summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2015-02-11 05:15:29 +0000
committerNanang Izzuddin <nanang@teluu.com>2015-02-11 05:15:29 +0000
commit33ccbcef51df23a167a5411ca97e7cdd9b604652 (patch)
treecfad58562a8431fe9fa3c761cec05e924140afcf
parentdbae9140153559747dcb6b12c3fda2c139836733 (diff)
Close #1814: Add audio frame preview callbacks.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4982 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/sound_port.h32
-rw-r--r--pjmedia/src/pjmedia/sound_port.c27
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h25
-rw-r--r--pjsip/src/pjsua-lib/pjsua_aud.c19
4 files changed, 103 insertions, 0 deletions
diff --git a/pjmedia/include/pjmedia/sound_port.h b/pjmedia/include/pjmedia/sound_port.h
index 07d15c4a..b09cb7bd 100644
--- a/pjmedia/include/pjmedia/sound_port.h
+++ b/pjmedia/include/pjmedia/sound_port.h
@@ -96,6 +96,38 @@ typedef struct pjmedia_snd_port_param
*/
unsigned ec_options;
+ /**
+ * Arbitrary user data for playback and record preview callbacks below.
+ */
+ void *user_data;
+
+ /**
+ * Optional callback for audio frame preview right before queued to
+ * the speaker.
+ * Notes:
+ * - application MUST NOT block or perform long operation in the callback
+ * as the callback may be executed in sound device thread
+ * - when using software echo cancellation, application MUST NOT modify
+ * the audio data from within the callback, otherwise the echo canceller
+ * will not work properly.
+ * - the return value of the callback will be ignored
+ */
+ pjmedia_aud_play_cb on_play_frame;
+
+ /**
+ * Optional callback for audio frame preview recorded from the microphone
+ * before being processed by any media component such as software echo
+ * canceller.
+ * Notes:
+ * - application MUST NOT block or perform long operation in the callback
+ * as the callback may be executed in sound device thread
+ * - when using software echo cancellation, application MUST NOT modify
+ * the audio data from within the callback, otherwise the echo canceller
+ * will not work properly.
+ * - the return value of the callback will be ignored
+ */
+ pjmedia_aud_rec_cb on_rec_frame;
+
} pjmedia_snd_port_param;
/**
diff --git a/pjmedia/src/pjmedia/sound_port.c b/pjmedia/src/pjmedia/sound_port.c
index 73305d83..79525d8d 100644
--- a/pjmedia/src/pjmedia/sound_port.c
+++ b/pjmedia/src/pjmedia/sound_port.c
@@ -61,6 +61,11 @@ struct pjmedia_snd_port
pj_bool_t ec_suspended;
unsigned ec_suspend_count;
unsigned ec_suspend_limit;
+
+ /* audio frame preview callbacks */
+ void *user_data;
+ pjmedia_aud_play_cb on_play_frame;
+ pjmedia_aud_rec_cb on_rec_frame;
};
/*
@@ -100,6 +105,9 @@ static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
}
+ /* Invoke preview callback */
+ if (snd_port->on_play_frame)
+ (*snd_port->on_play_frame)(snd_port->user_data, frame);
return PJ_SUCCESS;
@@ -120,6 +128,10 @@ no_frame:
}
}
+ /* Invoke preview callback */
+ if (snd_port->on_play_frame)
+ (*snd_port->on_play_frame)(snd_port->user_data, frame);
+
return PJ_SUCCESS;
}
@@ -135,6 +147,10 @@ static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame)
pjmedia_clock_src_update(&snd_port->cap_clocksrc, &frame->timestamp);
+ /* Invoke preview callback */
+ if (snd_port->on_rec_frame)
+ (*snd_port->on_rec_frame)(snd_port->user_data, frame);
+
port = snd_port->port;
if (port == NULL)
return PJ_SUCCESS;
@@ -166,6 +182,10 @@ static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame)
pjmedia_port_get_frame(port, frame);
+ /* Invoke preview callback */
+ if (snd_port->on_play_frame)
+ (*snd_port->on_play_frame)(snd_port->user_data, frame);
+
return PJ_SUCCESS;
}
@@ -179,6 +199,10 @@ static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame)
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
pjmedia_port *port;
+ /* Invoke preview callback */
+ if (snd_port->on_rec_frame)
+ (*snd_port->on_rec_frame)(snd_port->user_data, frame);
+
port = snd_port->port;
if (port == NULL)
return PJ_SUCCESS;
@@ -464,6 +488,9 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
pj_memcpy(&snd_port->aud_param, &prm->base, sizeof(snd_port->aud_param));
snd_port->options = prm->options;
snd_port->prm_ec_options = prm->ec_options;
+ snd_port->user_data = prm->user_data;
+ snd_port->on_play_frame = prm->on_play_frame;
+ snd_port->on_rec_frame = prm->on_rec_frame;
ptime_usec = prm->base.samples_per_frame * 1000 / prm->base.channel_count /
prm->base.clock_rate * 1000;
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 31c5378b..6325b70a 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -5811,6 +5811,31 @@ struct pjsua_media_config
* Default: PJ_FALSE
*/
pj_bool_t no_rtcp_sdes_bye;
+
+ /**
+ * Optional callback for audio frame preview right before queued to
+ * the speaker.
+ * Notes:
+ * - application MUST NOT block or perform long operation in the callback
+ * as the callback may be executed in sound device thread
+ * - when using software echo cancellation, application MUST NOT modify
+ * the audio data from within the callback, otherwise the echo canceller
+ * will not work properly.
+ */
+ void (*on_aud_prev_play_frame)(pjmedia_frame *frame);
+
+ /**
+ * Optional callback for audio frame preview recorded from the microphone
+ * before being processed by any media component such as software echo
+ * canceller.
+ * Notes:
+ * - application MUST NOT block or perform long operation in the callback
+ * as the callback may be executed in sound device thread
+ * - when using software echo cancellation, application MUST NOT modify
+ * the audio data from within the callback, otherwise the echo canceller
+ * will not work properly.
+ */
+ void (*on_aud_prev_rec_frame)(pjmedia_frame *frame);
};
diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c
index 65c69979..921a5f61 100644
--- a/pjsip/src/pjsua-lib/pjsua_aud.c
+++ b/pjsip/src/pjsua-lib/pjsua_aud.c
@@ -1677,6 +1677,20 @@ static const char *get_fmt_name(pj_uint32_t id)
return name;
}
+static pj_status_t on_aud_prev_play_frame(void *user_data, pjmedia_frame *frame)
+{
+ PJ_UNUSED_ARG(user_data);
+ (*pjsua_var.media_cfg.on_aud_prev_play_frame)(frame);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t on_aud_prev_rec_frame(void *user_data, pjmedia_frame *frame)
+{
+ PJ_UNUSED_ARG(user_data);
+ (*pjsua_var.media_cfg.on_aud_prev_rec_frame)(frame);
+ return PJ_SUCCESS;
+}
+
/* Open sound device with the setting. */
static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
{
@@ -1704,6 +1718,11 @@ static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);
PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
+ /* Setup preview callbacks, if configured */
+ if (pjsua_var.media_cfg.on_aud_prev_play_frame)
+ param->on_play_frame = &on_aud_prev_play_frame;
+ if (pjsua_var.media_cfg.on_aud_prev_rec_frame)
+ param->on_rec_frame = &on_aud_prev_rec_frame;
PJ_LOG(4,(THIS_FILE, "Opening sound device %s@%d/%d/%dms",
get_fmt_name(param->base.ext_fmt.id),