summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-09-27 22:49:55 +0000
committerBenny Prijono <bennylp@teluu.com>2006-09-27 22:49:55 +0000
commitf91822a157bb753d4e83d553cb3aa3e4186a33b5 (patch)
tree89e2aaddc8103bdca2997af3db1ca5ba3d242396 /pjmedia
parenta018c05e4ebb1b8814c001185fcb61e54499f7d2 (diff)
Added pjmedia_snd_stream_get_info() function.
** NOTE SOUND DEVICE IMPLEMENTORS: YOU'LL NEED TO IMPLEMENT THIS FUNCTION TOO *** git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@744 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia/sound.h31
-rw-r--r--pjmedia/src/pjmedia/dsound.c32
-rw-r--r--pjmedia/src/pjmedia/pasound.c94
-rw-r--r--pjmedia/src/pjmedia/sound_port.c20
4 files changed, 158 insertions, 19 deletions
diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h
index ecff739a..39c71b92 100644
--- a/pjmedia/include/pjmedia/sound.h
+++ b/pjmedia/include/pjmedia/sound.h
@@ -75,6 +75,24 @@ typedef struct pjmedia_snd_dev_info
} pjmedia_snd_dev_info;
/**
+ * Stream information, can be retrieved from a live stream by calling
+ * #pjmedia_snd_stream_get_info().
+ */
+typedef struct pjmedia_snd_stream_info
+{
+ pjmedia_dir dir; /**< Stream direction. */
+ int play_id; /**< Playback dev id, or -1 for rec only*/
+ int rec_id; /**< Capture dev id, or -1 for play only*/
+ unsigned clock_rate; /**< Actual clock rate. */
+ unsigned channel_count; /**< Number of channels. */
+ unsigned samples_per_frame; /**< Samples per frame. */
+ unsigned bits_per_sample; /**< Bits per sample. */
+ unsigned rec_latency; /**< Record latency, in samples. */
+ unsigned play_latency; /**< Playback latency, in samples. */
+} pjmedia_snd_stream_info;
+
+
+/**
* This callback is called by player stream when it needs additional data
* to be played by the device. Application must fill in the whole of output
* buffer with sound samples.
@@ -232,6 +250,19 @@ PJ_DECL(pj_status_t) pjmedia_snd_open_player( int index,
/**
+ * Get information about live stream.
+ *
+ * @param strm The stream to be queried.
+ * @param i Pointer to stream information to be filled up with
+ * information about the stream.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
+ pjmedia_snd_stream_info *pi);
+
+
+/**
* Start the stream.
*
* @param stream The recorder or player stream.
diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c
index cf8e1600..04cbc215 100644
--- a/pjmedia/src/pjmedia/dsound.c
+++ b/pjmedia/src/pjmedia/dsound.c
@@ -89,6 +89,8 @@ struct dsound_stream
struct pjmedia_snd_stream
{
pjmedia_dir dir; /**< Sound direction. */
+ int play_id; /**< Playback dev id. */
+ int rec_id; /**< Recording dev id. */
pj_pool_t *pool; /**< Memory pool. */
pjmedia_snd_rec_cb rec_cb; /**< Capture callback. */
@@ -101,6 +103,8 @@ struct pjmedia_snd_stream
void *buffer; /**< Temp. frame buffer. */
unsigned clock_rate; /**< Clock rate. */
unsigned samples_per_frame; /**< Samples per frame. */
+ unsigned bits_per_sample; /**< Bits per sample. */
+ unsigned channel_count; /**< Channel count. */
pj_thread_t *thread; /**< Thread handle. */
pj_bool_t thread_quit_flag; /**< Quit signal to thread */
@@ -719,12 +723,16 @@ static pj_status_t open_stream( pjmedia_dir dir,
strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream));
strm->dir = dir;
+ strm->play_id = play_id;
+ strm->rec_id = rec_id;
strm->pool = pool;
strm->rec_cb = rec_cb;
strm->play_cb = play_cb;
strm->user_data = user_data;
strm->clock_rate = clock_rate;
strm->samples_per_frame = samples_per_frame;
+ strm->bits_per_sample = bits_per_sample;
+ strm->channel_count = channel_count;
strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
if (!strm->buffer) {
pj_pool_release(pool);
@@ -827,6 +835,30 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
}
/*
+ * Get stream info.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
+ pjmedia_snd_stream_info *pi)
+{
+
+ PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+ pj_bzero(pi, sizeof(*pi));
+ pi->dir = strm->dir;
+ pi->play_id = strm->play_id;
+ pi->rec_id = strm->rec_id;
+ pi->clock_rate = strm->clock_rate;
+ pi->channel_count = strm->channel_count;
+ pi->samples_per_frame = strm->samples_per_frame;
+ pi->bits_per_sample = strm->bits_per_sample;
+ pi->rec_latency = 0;
+ pi->play_latency = 0;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
* Start stream.
*/
PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c
index 527c0a02..9e8a92b1 100644
--- a/pjmedia/src/pjmedia/pasound.c
+++ b/pjmedia/src/pjmedia/pasound.c
@@ -18,6 +18,7 @@
*/
#include <pjmedia/sound.h>
#include <pjmedia/errno.h>
+#include <pj/assert.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/string.h>
@@ -42,8 +43,11 @@ struct pjmedia_snd_stream
pj_pool_t *pool;
pj_str_t name;
pjmedia_dir dir;
+ int play_id;
+ int rec_id;
int bytes_per_sample;
pj_uint32_t samples_per_sec;
+ unsigned samples_per_frame;
int channel_count;
PaStream *stream;
@@ -241,7 +245,8 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
int sampleFormat;
const PaDeviceInfo *paDevInfo = NULL;
const PaHostApiInfo *paHostApiInfo = NULL;
- unsigned paFrames;
+ unsigned paFrames, paRate, paLatency;
+ const PaStreamInfo *paSI;
PaError err;
if (index <= 0) {
@@ -280,8 +285,11 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
stream->dir = PJMEDIA_DIR_CAPTURE;
+ stream->rec_id = index;
+ stream->play_id = -1;
stream->user_data = user_data;
stream->samples_per_sec = clock_rate;
+ stream->samples_per_frame = samples_per_frame;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
@@ -306,13 +314,17 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
- PJ_LOG(5,(THIS_FILE, "%s opening device %s (%s) for recording, sample "
+ paSI = Pa_GetStreamInfo(stream->stream);
+ paRate = (unsigned)paSI->sampleRate;
+ paLatency = (unsigned)(paSI->inputLatency * 1000);
+
+ PJ_LOG(5,(THIS_FILE, "Opened device %s (%s) for recording, sample "
"rate=%d, ch=%d, "
- "bits=%d, %d samples per frame",
- (err==0 ? "Success" : "Error"),
+ "bits=%d, %d samples per frame, latency=%d ms",
paDevInfo->name, paHostApiInfo->name,
- clock_rate, channel_count,
- bits_per_sample, samples_per_frame));
+ paSI->sampleRate, channel_count,
+ bits_per_sample, samples_per_frame,
+ paLatency));
*p_snd_strm = stream;
return PJ_SUCCESS;
@@ -334,7 +346,8 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
int sampleFormat;
const PaDeviceInfo *paDevInfo = NULL;
const PaHostApiInfo *paHostApiInfo = NULL;
- unsigned paFrames;
+ const PaStreamInfo *paSI;
+ unsigned paFrames, paRate, paLatency;
PaError err;
if (index <= 0) {
@@ -373,8 +386,11 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
stream->dir = stream->dir = PJMEDIA_DIR_PLAYBACK;
+ stream->play_id = index;
+ stream->rec_id = -1;
stream->user_data = user_data;
stream->samples_per_sec = clock_rate;
+ stream->samples_per_frame = samples_per_frame;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->play_cb = play_cb;
@@ -399,13 +415,16 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
- PJ_LOG(5,(THIS_FILE, "%s opening device %d: %s(%s) for playing, sample rate=%d"
+ paSI = Pa_GetStreamInfo(stream->stream);
+ paRate = (unsigned)(paSI->sampleRate);
+ paLatency = (unsigned)(paSI->outputLatency * 1000);
+
+ PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d"
", ch=%d, "
- "bits=%d, %d samples per frame",
- (err==0 ? "Success" : "Error"),
+ "bits=%d, %d samples per frame, latency=%d ms",
index, paDevInfo->name, paHostApiInfo->name,
- clock_rate, channel_count,
- bits_per_sample, samples_per_frame));
+ paRate, channel_count,
+ bits_per_sample, samples_per_frame, paLatency));
*p_snd_strm = stream;
@@ -436,7 +455,8 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
const PaDeviceInfo *paPlayDevInfo = NULL;
const PaHostApiInfo *paRecHostApiInfo = NULL;
const PaHostApiInfo *paPlayHostApiInfo = NULL;
- unsigned paFrames;
+ const PaStreamInfo *paSI;
+ unsigned paFrames, paRate, paInputLatency, paOutputLatency;
PaError err;
if (rec_id <= 0) {
@@ -494,8 +514,11 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name);
stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+ stream->play_id = play_id;
+ stream->rec_id = rec_id;
stream->user_data = user_data;
stream->samples_per_sec = clock_rate;
+ stream->samples_per_frame = samples_per_frame;
stream->bytes_per_sample = bits_per_sample / 8;
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
@@ -530,14 +553,20 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
}
- PJ_LOG(5,(THIS_FILE, "%s opening device %s(%s)/%s(%s) for recording and "
+ paSI = Pa_GetStreamInfo(stream->stream);
+ paRate = (unsigned)(paSI->sampleRate);
+ paInputLatency = (unsigned)(paSI->inputLatency * 1000);
+ paOutputLatency = (unsigned)(paSI->outputLatency * 1000);
+
+ PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and "
"playback, sample rate=%d, ch=%d, "
- "bits=%d, %d samples per frame",
- (err==0 ? "Success" : "Error"),
+ "bits=%d, %d samples per frame, input latency=%d ms, "
+ "output latency=%d ms",
paRecDevInfo->name, paRecHostApiInfo->name,
paPlayDevInfo->name, paPlayHostApiInfo->name,
- clock_rate, channel_count,
- bits_per_sample, samples_per_frame));
+ paRate, channel_count,
+ bits_per_sample, samples_per_frame,
+ paInputLatency, paOutputLatency));
*p_snd_strm = stream;
@@ -545,6 +574,35 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
return PJ_SUCCESS;
}
+
+/*
+ * Get stream info.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
+ pjmedia_snd_stream_info *pi)
+{
+ const PaStreamInfo *paSI;
+
+ PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+ PJ_ASSERT_RETURN(strm->stream, PJ_EINVALIDOP);
+
+ paSI = Pa_GetStreamInfo(strm->stream);
+
+ pj_bzero(pi, sizeof(*pi));
+ pi->dir = strm->dir;
+ pi->play_id = strm->play_id;
+ pi->rec_id = strm->rec_id;
+ pi->clock_rate = (unsigned)(paSI->sampleRate);
+ pi->channel_count = strm->channel_count;
+ pi->samples_per_frame = strm->samples_per_frame;
+ pi->bits_per_sample = strm->bytes_per_sample * 8;
+ pi->rec_latency = (unsigned)(paSI->inputLatency * paSI->sampleRate);
+ pi->play_latency = (unsigned)(paSI->outputLatency * paSI->sampleRate);
+
+ return PJ_SUCCESS;
+}
+
+
/*
* Start stream.
*/
diff --git a/pjmedia/src/pjmedia/sound_port.c b/pjmedia/src/pjmedia/sound_port.c
index 170091c5..02478e06 100644
--- a/pjmedia/src/pjmedia/sound_port.c
+++ b/pjmedia/src/pjmedia/sound_port.c
@@ -124,6 +124,7 @@ static pj_status_t play_cb(/* in */ void *user_data,
if (snd_port->ec_state) {
if (snd_port->ec_suspended) {
snd_port->ec_suspended = PJ_FALSE;
+ //pjmedia_echo_state_reset(snd_port->ec_state);
PJ_LOG(4,(THIS_FILE, "EC activated"));
}
snd_port->ec_suspend_count = 0;
@@ -141,6 +142,10 @@ no_frame:
snd_port->ec_suspended = PJ_TRUE;
PJ_LOG(4,(THIS_FILE, "EC suspended because of inactivity"));
}
+ if (snd_port->ec_state) {
+ /* To maintain correct delay in EC */
+ pjmedia_echo_playback(snd_port->ec_state, output);
+ }
}
/* Apply PLC */
@@ -353,7 +358,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create( pj_pool_t *pool,
}
/*
- * Create sound recorder port.
+ * Create sound recorder AEC.
*/
PJ_DEF(pj_status_t) pjmedia_snd_port_create_rec( pj_pool_t *pool,
int dev_id,
@@ -456,6 +461,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
unsigned tail_ms,
unsigned options)
{
+ pjmedia_snd_stream_info si;
pj_status_t status;
/* Sound must be opened in full-duplex mode */
@@ -463,6 +469,10 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK,
PJ_EINVALIDOP);
+ /* Sound port must have 16bits per sample */
+ PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16,
+ PJ_EINVALIDOP);
+
/* Destroy AEC */
if (snd_port->ec_state) {
pjmedia_echo_destroy(snd_port->ec_state);
@@ -472,6 +482,14 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
snd_port->aec_tail_len = tail_ms;
if (tail_ms != 0) {
+ unsigned delay_ms;
+
+ status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si);
+ if (status != PJ_SUCCESS)
+ si.rec_latency = si.play_latency = 0;
+
+ delay_ms = (si.rec_latency + si.play_latency) * 1000 /
+ snd_port->clock_rate;
status = pjmedia_echo_create(pool, snd_port->clock_rate,
snd_port->samples_per_frame,
tail_ms, options, &snd_port->ec_state);