summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2008-04-10 09:53:16 +0000
committerBenny Prijono <bennylp@teluu.com>2008-04-10 09:53:16 +0000
commitaf4378a7caa56289dc6526ed94d254eb7727d366 (patch)
treef997455e8e8d0e1e670853bfeab57ef2dc44fc49 /pjmedia
parentdf25592dcb2fccb8180fb9e4a10a6989e97c5dd1 (diff)
Ticket #523: Handle incomplete audio frame from sound device (e.g. OSS)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1918 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/src/pjmedia/pasound.c147
1 files changed, 132 insertions, 15 deletions
diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c
index e355749f..ea285c0a 100644
--- a/pjmedia/src/pjmedia/pasound.c
+++ b/pjmedia/src/pjmedia/pasound.c
@@ -77,6 +77,21 @@ struct pjmedia_snd_stream
//pj_bool_t play_thread_initialized;
pj_thread_desc play_thread_desc;
pj_thread_t *play_thread;
+
+ /* Sometime the record callback does not return framesize as configured
+ * (e.g: in OSS), while this module must guarantee returning framesize
+ * as configured in the creation settings. In this case, we need a buffer
+ * for the recorded samples.
+ */
+ pj_int16_t *rec_buf;
+ unsigned rec_buf_size;
+
+ /* Sometime the player callback does not request framesize as configured
+ * (e.g: in Linux OSS) while sound device will always get samples from
+ * the other component as many as configured samples_per_frame.
+ */
+ pj_int16_t *play_buf;
+ unsigned play_buf_size;
};
@@ -88,9 +103,8 @@ static int PaRecorderCallback(const void *input,
void *userData )
{
pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
- pj_status_t status;
-
- pj_assert(frameCount * stream->channel_count == stream->samples_per_frame);
+ pj_status_t status = 0;
+ unsigned nsamples;
PJ_UNUSED_ARG(output);
PJ_UNUSED_ARG(timeInfo);
@@ -118,11 +132,56 @@ static int PaRecorderCallback(const void *input,
stream->rec_timestamp += frameCount;
- status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp,
- (void*)input,
- frameCount * stream->bytes_per_sample *
- stream->channel_count);
-
+ /* Calculate number of samples we've got */
+ nsamples = frameCount * stream->channel_count + stream->rec_buf_size;
+
+ if (nsamples >= stream->samples_per_frame)
+ {
+ /* If buffer is not empty, combine the buffer with the just incoming
+ * samples, then call put_frame.
+ */
+ if (stream->rec_buf_size) {
+ unsigned chunk_size = 0;
+
+ chunk_size = stream->samples_per_frame - stream->rec_buf_size;
+ pjmedia_copy_samples(stream->rec_buf + stream->rec_buf_size,
+ (pj_int16_t*)input, chunk_size);
+ status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp,
+ (void*) stream->rec_buf,
+ stream->samples_per_frame *
+ stream->bytes_per_sample);
+
+ input = (pj_int16_t*) input + chunk_size;
+ nsamples -= stream->samples_per_frame;
+ stream->rec_buf_size = 0;
+ }
+
+ /* Give all frames we have */
+ while (nsamples >= stream->samples_per_frame && status == 0) {
+ status = (*stream->rec_cb)(stream->user_data, stream->rec_timestamp,
+ (void*) input,
+ stream->samples_per_frame *
+ stream->bytes_per_sample);
+ input = (pj_int16_t*) input + stream->samples_per_frame;
+ nsamples -= stream->samples_per_frame;
+ }
+
+ /* Store the remaining samples into the buffer */
+ if (nsamples && status == 0) {
+ stream->rec_buf_size = nsamples;
+ pjmedia_copy_samples((pj_int16_t*)stream->rec_buf,
+ (pj_int16_t*)input, nsamples);
+ }
+
+ } else {
+ /* Not enough samples, let's just store them in the buffer */
+ pjmedia_copy_samples((pj_int16_t*)(stream->rec_buf +
+ stream->rec_buf_size),
+ (pj_int16_t*)input,
+ frameCount * stream->channel_count);
+ stream->rec_buf_size += frameCount * stream->channel_count;
+ }
+
if (status==0)
return paContinue;
@@ -139,11 +198,8 @@ static int PaPlayerCallback( const void *input,
void *userData )
{
pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
- pj_status_t status;
- unsigned size = frameCount * stream->bytes_per_sample *
- stream->channel_count;
-
- pj_assert(frameCount * stream->channel_count == stream->samples_per_frame);
+ pj_status_t status = 0;
+ unsigned nsamples_req = frameCount * stream->channel_count;
PJ_UNUSED_ARG(input);
PJ_UNUSED_ARG(timeInfo);
@@ -171,8 +227,53 @@ static int PaPlayerCallback( const void *input,
stream->play_timestamp += frameCount;
- status = (*stream->play_cb)(stream->user_data, stream->play_timestamp,
- output, size);
+ /* Check if any buffered samples */
+ if (stream->play_buf_size) {
+ /* samples buffered >= requested by sound device */
+ if (stream->play_buf_size >= nsamples_req) {
+ pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+ nsamples_req);
+ stream->play_buf_size -= nsamples_req;
+ pjmedia_move_samples(stream->play_buf,
+ stream->play_buf + nsamples_req,
+ stream->play_buf_size);
+ nsamples_req = 0;
+
+ return paContinue;
+ }
+
+ /* samples buffered < requested by sound device */
+ pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+ stream->play_buf_size);
+ nsamples_req -= stream->play_buf_size;
+ output = (pj_int16_t*)output + stream->play_buf_size;
+ stream->play_buf_size = 0;
+ }
+
+ /* Fill output buffer as requested */
+ while (nsamples_req && status == 0) {
+ if (nsamples_req >= stream->samples_per_frame) {
+ status = (*stream->play_cb)(stream->user_data,
+ stream->play_timestamp,
+ output,
+ stream->samples_per_frame *
+ stream->bytes_per_sample);
+ nsamples_req -= stream->samples_per_frame;
+ output = (pj_int16_t*)output + stream->samples_per_frame;
+ } else {
+ status = (*stream->play_cb)(stream->user_data,
+ stream->play_timestamp,
+ stream->play_buf,
+ stream->samples_per_frame *
+ stream->bytes_per_sample);
+ pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+ nsamples_req);
+ stream->play_buf_size = stream->samples_per_frame - nsamples_req;
+ pjmedia_move_samples(stream->play_buf, stream->play_buf+nsamples_req,
+ stream->play_buf_size);
+ nsamples_req = 0;
+ }
+ }
if (status==0)
return paContinue;
@@ -449,6 +550,10 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
stream->channel_count = channel_count;
stream->rec_cb = rec_cb;
+ stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool,
+ stream->samples_per_frame * stream->bytes_per_sample);
+ stream->rec_buf_size = 0;
+
pj_bzero(&inputParam, sizeof(inputParam));
inputParam.device = index;
inputParam.channelCount = channel_count;
@@ -547,6 +652,10 @@ PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
stream->channel_count = channel_count;
stream->play_cb = play_cb;
+ stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool,
+ stream->samples_per_frame * stream->bytes_per_sample);
+ stream->play_buf_size = 0;
+
pj_bzero(&outputParam, sizeof(outputParam));
outputParam.device = index;
outputParam.channelCount = channel_count;
@@ -670,6 +779,14 @@ PJ_DEF(pj_status_t) pjmedia_snd_open( int rec_id,
stream->rec_cb = rec_cb;
stream->play_cb = play_cb;
+ stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool,
+ stream->samples_per_frame * stream->bytes_per_sample);
+ stream->rec_buf_size = 0;
+
+ stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool,
+ stream->samples_per_frame * stream->bytes_per_sample);
+ stream->play_buf_size = 0;
+
pj_bzero(&inputParam, sizeof(inputParam));
inputParam.device = rec_id;
inputParam.channelCount = channel_count;