summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/include/pjmedia/config.h10
-rw-r--r--pjmedia/include/pjmedia/sound.h22
-rw-r--r--pjmedia/src/pjmedia/dsound.c20
-rw-r--r--pjmedia/src/pjmedia/nullsound.c12
-rw-r--r--pjmedia/src/pjmedia/pasound.c35
-rw-r--r--pjmedia/src/pjmedia/rtcp_xr.c14
-rw-r--r--pjmedia/src/pjmedia/symbian_sound.cpp12
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c29
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) {