diff options
-rw-r--r-- | pjmedia/include/pjmedia/config.h | 10 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/sound.h | 22 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/dsound.c | 20 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/nullsound.c | 12 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/pasound.c | 35 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/rtcp_xr.c | 14 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/symbian_sound.cpp | 12 | ||||
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 29 |
8 files changed, 129 insertions, 25 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h index f9015815..5eebe4cb 100644 --- a/pjmedia/include/pjmedia/config.h +++ b/pjmedia/include/pjmedia/config.h @@ -83,10 +83,14 @@ /** - * Specify PortAudio maximum buffering latency, in milliseconds. + * Specify sound device latency default, in milisecond. */ -#ifndef PJMEDIA_PASOUND_MAX_LATENCY -# define PJMEDIA_PASOUND_MAX_LATENCY 100 +#ifndef PJMEDIA_SND_DEFAULT_REC_LATENCY +# define PJMEDIA_SND_DEFAULT_REC_LATENCY 10 +#endif + +#ifndef PJMEDIA_SND_DEFAULT_PLAY_LATENCY +# define PJMEDIA_SND_DEFAULT_PLAY_LATENCY 100 #endif diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h index 91d1cb8f..ca9ccee4 100644 --- a/pjmedia/include/pjmedia/sound.h +++ b/pjmedia/include/pjmedia/sound.h @@ -154,6 +154,28 @@ PJ_DECL(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index); /** + * Set sound device latency, this function must be called before sound device + * opened, or otherwise default latency setting will be used, @see + * PJMEDIA_SND_DEFAULT_REC_LATENCY & PJMEDIA_SND_DEFAULT_PLAY_LATENCY. + * + * Choosing latency value is not straightforward, it should accomodate both + * minimum latency and stability. Lower latency tends to cause sound device + * less reliable (producing audio dropouts) on CPU load disturbance. Moreover, + * the best latency setting may vary based on many aspects, e.g: sound card, + * CPU, OS, kernel, etc. + * + * @param input_latency The latency of input device, in ms, set to 0 + * for default PJMEDIA_SND_DEFAULT_REC_LATENCY. + * @param output_latency The latency of output device, in ms, set to 0 + * for default PJMEDIA_SND_DEFAULT_PLAY_LATENCY. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, + unsigned output_latency); + + +/** * Create sound stream for both capturing audio and audio playback, from the * same device. This is the recommended way to create simultaneous recorder * and player streams (instead of creating separate capture and playback diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c index dc51d975..ea673bf0 100644 --- a/pjmedia/src/pjmedia/dsound.c +++ b/pjmedia/src/pjmedia/dsound.c @@ -59,6 +59,10 @@ static unsigned dev_count; static struct dsound_dev_info dev_info[MAX_HARDWARE]; static int snd_init_count; +/* Latency settings */ +static unsigned snd_input_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY; +static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; + /* Individual DirectSound capture/playback stream descriptor */ struct dsound_stream @@ -986,5 +990,21 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream) } +/* + * Set sound latency. + */ +PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, + unsigned output_latency) +{ + PJ_TODO(APPLY_LATENCY_SETTINGS_ON_DSOUND); + + snd_input_latency = (input_latency == 0)? + PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency; + snd_output_latency = (output_latency == 0)? + PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency; + + return PJ_SUCCESS; +} + #endif /* PJMEDIA_SOUND_IMPLEMENTATION */ diff --git a/pjmedia/src/pjmedia/nullsound.c b/pjmedia/src/pjmedia/nullsound.c index f0c065ee..1c2fff83 100644 --- a/pjmedia/src/pjmedia/nullsound.c +++ b/pjmedia/src/pjmedia/nullsound.c @@ -181,4 +181,16 @@ PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream) return PJ_SUCCESS; } +/* + * Set sound latency. + */ +PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, + unsigned output_latency) +{ + /* Nothing to do */ + PJ_UNUSED_ARG(input_latency); + PJ_UNUSED_ARG(output_latency); + return PJ_SUCCESS; +} + #endif /* PJMEDIA_SOUND_IMPLEMENTATION */ diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c index bbc142cd..f5c04498 100644 --- a/pjmedia/src/pjmedia/pasound.c +++ b/pjmedia/src/pjmedia/pasound.c @@ -28,10 +28,12 @@ #define THIS_FILE "pasound.c" -#define MAX_LATENCY (PJMEDIA_PASOUND_MAX_LATENCY / 1000.0) - static int snd_init_count; +/* Latency settings */ +static unsigned snd_input_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY; +static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; + static struct snd_mgr { pj_pool_factory *factory; @@ -561,9 +563,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index, inputParam.channelCount = channel_count; inputParam.hostApiSpecificStreamInfo = NULL; inputParam.sampleFormat = sampleFormat; - inputParam.suggestedLatency = paDevInfo->defaultLowInputLatency; - if (inputParam.suggestedLatency > MAX_LATENCY) - inputParam.suggestedLatency = MAX_LATENCY; + inputParam.suggestedLatency = snd_input_latency / 1000.0; paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi); @@ -663,9 +663,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index, outputParam.channelCount = channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; - outputParam.suggestedLatency = paDevInfo->defaultLowOutputLatency; - if (outputParam.suggestedLatency > MAX_LATENCY) - outputParam.suggestedLatency = MAX_LATENCY; + outputParam.suggestedLatency = snd_output_latency / 1000.0; paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi); @@ -794,9 +792,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, inputParam.channelCount = channel_count; inputParam.hostApiSpecificStreamInfo = NULL; inputParam.sampleFormat = sampleFormat; - inputParam.suggestedLatency = paRecDevInfo->defaultLowInputLatency; - if (inputParam.suggestedLatency > MAX_LATENCY) - inputParam.suggestedLatency = MAX_LATENCY; + inputParam.suggestedLatency = snd_input_latency / 1000.0; paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi); @@ -805,9 +801,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id, outputParam.channelCount = channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; - outputParam.suggestedLatency = paPlayDevInfo->defaultLowOutputLatency; - if (outputParam.suggestedLatency > MAX_LATENCY) - outputParam.suggestedLatency = MAX_LATENCY; + outputParam.suggestedLatency = snd_output_latency / 1000.0; paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi); @@ -1012,5 +1006,18 @@ PJ_DEF(pj_status_t) pjmedia_snd_deinit(void) } } +/* + * Set sound latency. + */ +PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, + unsigned output_latency) +{ + snd_input_latency = (input_latency == 0)? + PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency; + snd_output_latency = (output_latency == 0)? + PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency; + + return PJ_SUCCESS; +} #endif /* PJMEDIA_SOUND_IMPLEMENTATION */ diff --git a/pjmedia/src/pjmedia/rtcp_xr.c b/pjmedia/src/pjmedia/rtcp_xr.c index 8b109a28..d99c4bb0 100644 --- a/pjmedia/src/pjmedia/rtcp_xr.c +++ b/pjmedia/src/pjmedia/rtcp_xr.c @@ -326,15 +326,13 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp_xr( pjmedia_rtcp_xr_session *sess, * Since it is difficult to get the exact value of EXTRA, estimation * is taken to be totally around 30ms + sound device latency. */ - est_extra_delay = 30 + -#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND - PJMEDIA_PASOUND_MAX_LATENCY -#elif PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_NULL_SOUND - 0 -#else - (PJMEDIA_SOUND_BUFFER_COUNT * 15) + est_extra_delay = 30; + +#if PJMEDIA_SOUND_IMPLEMENTATION!=PJMEDIA_SOUND_NULL_SOUND + est_extra_delay += PJMEDIA_SND_DEFAULT_REC_LATENCY + + PJMEDIA_SND_DEFAULT_PLAY_LATENCY; #endif - ; + sess->stat.rx.voip_mtc.end_sys_delay = (pj_uint16_t) (sess->stat.rx.voip_mtc.rnd_trip_delay / 2 + sess->stat.rx.voip_mtc.jb_nom + diff --git a/pjmedia/src/pjmedia/symbian_sound.cpp b/pjmedia/src/pjmedia/symbian_sound.cpp index 031d10cc..8c09be2c 100644 --- a/pjmedia/src/pjmedia/symbian_sound.cpp +++ b/pjmedia/src/pjmedia/symbian_sound.cpp @@ -927,3 +927,15 @@ PJ_DEF(pj_status_t) pjmedia_snd_deinit(void) return PJ_SUCCESS; } + +/* + * Set sound latency. + */ +PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, + unsigned output_latency) +{ + /* Nothing to do */ + PJ_UNUSED_ARG(input_latency); + PJ_UNUSED_ARG(output_latency); + return PJ_SUCCESS; +} diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 3c92b988..b8affe61 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -85,6 +85,7 @@ static struct app_config speaker_level; int capture_dev, playback_dev; + unsigned capture_lat, playback_lat; } app_config; @@ -194,6 +195,8 @@ static void usage(void) puts (" --ilbc-mode=MODE Set iLBC codec mode (20 or 30, default is 20)"); puts (" --capture-dev=id Audio capture device ID (default=-1)"); puts (" --playback-dev=id Audio playback device ID (default=-1)"); + puts (" --capture-lat=N Audio capture latency, in ms (default=10)"); + puts (" --playback-lat=N Audio playback latency, in ms (default=100)"); puts (""); puts ("Media Transport Options:"); @@ -252,6 +255,8 @@ static void default_config(struct app_config *cfg) cfg->mic_level = cfg->speaker_level = 1.0; cfg->capture_dev = PJSUA_INVALID_ID; cfg->playback_dev = PJSUA_INVALID_ID; + cfg->capture_lat = PJMEDIA_SND_DEFAULT_REC_LATENCY; + cfg->playback_lat = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i) pjsua_acc_config_default(&cfg->acc_cfg[i]); @@ -413,6 +418,7 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT, OPT_TLS_NEG_TIMEOUT, OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV, + OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC }; struct pj_getopt_option long_options[] = { @@ -499,6 +505,8 @@ static pj_status_t parse_args(int argc, char *argv[], { "tls-neg-timeout", 1, 0, OPT_TLS_NEG_TIMEOUT}, { "capture-dev", 1, 0, OPT_CAPTURE_DEV}, { "playback-dev", 1, 0, OPT_PLAYBACK_DEV}, + { "capture-lat", 1, 0, OPT_CAPTURE_LAT}, + { "playback-lat", 1, 0, OPT_PLAYBACK_LAT}, { NULL, 0, 0, 0} }; pj_status_t status; @@ -1077,6 +1085,14 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->playback_dev = atoi(pj_optarg); break; + case OPT_CAPTURE_LAT: + cfg->capture_lat = atoi(pj_optarg); + break; + + case OPT_PLAYBACK_LAT: + cfg->playback_lat = atoi(pj_optarg); + break; + default: PJ_LOG(1,(THIS_FILE, "Argument \"%s\" is not valid. Use --help to see help", @@ -1474,6 +1490,16 @@ static int write_settings(const struct app_config *config, pj_strcat2(&cfg, line); } + /* Sound device latency */ + if (config->capture_lat != PJMEDIA_SND_DEFAULT_REC_LATENCY) { + pj_ansi_sprintf(line, "--capture-lat %d\n", config->capture_lat); + pj_strcat2(&cfg, line); + } + if (config->playback_dev != PJMEDIA_SND_DEFAULT_PLAY_LATENCY) { + pj_ansi_sprintf(line, "--playback-lat %d\n", config->playback_lat); + pj_strcat2(&cfg, line); + } + /* Media clock rate. */ if (config->media_cfg.clock_rate != PJSUA_DEFAULT_CLOCK_RATE) { pj_ansi_sprintf(line, "--clock-rate %d\n", @@ -3713,6 +3739,9 @@ pj_status_t app_init(int argc, char *argv[]) if (status != PJ_SUCCESS) goto on_error; + /* Set sound device latency */ + pjmedia_snd_set_latency(app_config.capture_lat, app_config.playback_lat); + /* Use null sound device? */ #ifndef STEREO_DEMO if (app_config.null_audio) { |