From 5f1ff63b18fbf86eaa27798a35ae8979e3a01b11 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Thu, 5 Jun 2008 10:50:40 +0000 Subject: Ticket #473: - fixed issue on Speex multiple frames (encoding: encoded bits concatenation & decoding: frames parsing) - updated pjmedia stream & codecs on encoding multiple frames - introduced bit_info in pjmedia_frame and jitter buffer git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1983 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/codec.h | 2 +- pjmedia/include/pjmedia/jbuf.h | 10 +- pjmedia/include/pjmedia/port.h | 13 +- pjmedia/src/pjmedia-codec/g722.c | 12 +- pjmedia/src/pjmedia-codec/gsm.c | 26 ++-- pjmedia/src/pjmedia-codec/ilbc.c | 42 ++++--- pjmedia/src/pjmedia-codec/l16.c | 4 + pjmedia/src/pjmedia-codec/speex_codec.c | 215 +++++++++++++++++++++++++------- pjmedia/src/pjmedia/jbuf.c | 37 ++++-- pjmedia/src/pjmedia/stream.c | 69 ++-------- 10 files changed, 275 insertions(+), 155 deletions(-) diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h index e64f8f08..1a7e0bc0 100644 --- a/pjmedia/include/pjmedia/codec.h +++ b/pjmedia/include/pjmedia/codec.h @@ -375,7 +375,7 @@ typedef struct pjmedia_codec_op /** * Instruct the codec to encode the specified input frame. The input - * PCM samples MUST have ptime that is exactly equal to base frame + * PCM samples MUST have ptime that is multiplication of base frame * ptime (i.e. the value of info.frm_ptime in #pjmedia_codec_param). * * @param codec The codec instance. diff --git a/pjmedia/include/pjmedia/jbuf.h b/pjmedia/include/pjmedia/jbuf.h index 229f3f05..bef94490 100644 --- a/pjmedia/include/pjmedia/jbuf.h +++ b/pjmedia/include/pjmedia/jbuf.h @@ -219,12 +219,16 @@ PJ_DECL(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb, * @param frame Pointer to frame buffer to be stored in the jitter * buffer. * @param size The frame size. + * @param bit_info Bit precise info of the frame, e.g: a frame may not + * exactly start and end at the octet boundary, so this + * field may be used for specifying start & end bit offset. * @param frame_seq The frame sequence number. * @param discarded Flag whether the frame is discarded by jitter buffer. */ PJ_DECL(void) pjmedia_jbuf_put_frame2( pjmedia_jbuf *jb, const void *frame, pj_size_t size, + pj_uint32_t bit_info, int frame_seq, pj_bool_t *discarded); @@ -267,11 +271,15 @@ PJ_DECL(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, * @param size Pointer to receive frame size. * @param p_frm_type Pointer to receive frame type. * @see pjmedia_jbuf_get_frame(). + * @param bit_info Bit precise info of the frame, e.g: a frame may not + * exactly start and end at the octet boundary, so this + * field may be used for specifying start & end bit offset. */ PJ_DECL(void) pjmedia_jbuf_get_frame2(pjmedia_jbuf *jb, void *frame, pj_size_t *size, - char *p_frm_type); + char *p_frm_type, + pj_uint32_t *bit_info); /** diff --git a/pjmedia/include/pjmedia/port.h b/pjmedia/include/pjmedia/port.h index 58b6e0f7..3edea1dc 100644 --- a/pjmedia/include/pjmedia/port.h +++ b/pjmedia/include/pjmedia/port.h @@ -298,10 +298,15 @@ typedef enum pjmedia_frame_type */ struct pjmedia_frame { - pjmedia_frame_type type; /**< Frame type. */ - void *buf; /**< Pointer to buffer. */ - pj_size_t size; /**< Frame size in bytes. */ - pj_timestamp timestamp; /**< Frame timestamp. */ + pjmedia_frame_type type; /**< Frame type. */ + void *buf; /**< Pointer to buffer. */ + pj_size_t size; /**< Frame size in bytes. */ + pj_timestamp timestamp; /**< Frame timestamp. */ + pj_uint32_t bit_info; /**< Bit info of the frame, sample case: + a frame may not exactly start and end + at the octet boundary, so this field + may be used for specifying start & + end bit offset. */ }; diff --git a/pjmedia/src/pjmedia-codec/g722.c b/pjmedia/src/pjmedia-codec/g722.c index 4a89b182..aa54c177 100644 --- a/pjmedia/src/pjmedia-codec/g722.c +++ b/pjmedia/src/pjmedia-codec/g722.c @@ -532,14 +532,10 @@ static pj_status_t g722_codec_encode(pjmedia_codec *codec, struct g722_data *g722_data = (struct g722_data*) codec->codec_data; pj_status_t status; - pj_assert(g722_data != NULL); - PJ_ASSERT_RETURN(input && output, PJ_EINVAL); - - if (output_buf_len < FRAME_LEN) - return PJMEDIA_CODEC_EFRMTOOSHORT; + pj_assert(g722_data && input && output); - PJ_ASSERT_RETURN(input->size/2 == SAMPLES_PER_FRAME, - PJMEDIA_CODEC_EPCMFRMINLEN); + PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len, + PJMEDIA_CODEC_EFRMTOOSHORT); /* Detect silence */ if (g722_data->vad_enabled) { @@ -570,7 +566,7 @@ static pj_status_t g722_codec_encode(pjmedia_codec *codec, /* Encode to temporary buffer */ output->size = output_buf_len; status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf, - SAMPLES_PER_FRAME, output->buf, &output->size); + (input->size >> 1), output->buf, &output->size); if (status != PJ_SUCCESS) { output->size = 0; output->buf = NULL; diff --git a/pjmedia/src/pjmedia-codec/gsm.c b/pjmedia/src/pjmedia-codec/gsm.c index 8bc33bb4..555901f8 100644 --- a/pjmedia/src/pjmedia-codec/gsm.c +++ b/pjmedia/src/pjmedia-codec/gsm.c @@ -515,14 +515,17 @@ static pj_status_t gsm_codec_encode( pjmedia_codec *codec, struct pjmedia_frame *output) { struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data; + pj_int16_t *pcm_in; + unsigned in_size; - pj_assert(gsm_data != NULL); - PJ_ASSERT_RETURN(input && output, PJ_EINVAL); - - if (output_buf_len < 33) - return PJMEDIA_CODEC_EFRMTOOSHORT; + pj_assert(gsm_data && input && output); + + pcm_in = (pj_int16_t*)input->buf; + in_size = input->size; - PJ_ASSERT_RETURN(input->size==320, PJMEDIA_CODEC_EPCMFRMINLEN); + PJ_ASSERT_RETURN(in_size % 320 == 0, PJMEDIA_CODEC_EPCMFRMINLEN); + PJ_ASSERT_RETURN(output_buf_len >= 33 * in_size/320, + PJMEDIA_CODEC_EFRMTOOSHORT); /* Detect silence */ if (gsm_data->vad_enabled) { @@ -551,10 +554,15 @@ static pj_status_t gsm_codec_encode( pjmedia_codec *codec, } /* Encode */ - gsm_encode(gsm_data->encoder, (short*)input->buf, - (unsigned char*)output->buf); + output->size = 0; + while (in_size >= 320) { + gsm_encode(gsm_data->encoder, pcm_in, + (unsigned char*)output->buf + output->size); + pcm_in += 160; + output->size += 33; + in_size -= 320; + } - output->size = 33; output->type = PJMEDIA_FRAME_TYPE_AUDIO; return PJ_SUCCESS; diff --git a/pjmedia/src/pjmedia-codec/ilbc.c b/pjmedia/src/pjmedia-codec/ilbc.c index 7819867f..2134e77b 100644 --- a/pjmedia/src/pjmedia-codec/ilbc.c +++ b/pjmedia/src/pjmedia-codec/ilbc.c @@ -510,16 +510,19 @@ static pj_status_t ilbc_codec_encode(pjmedia_codec *codec, struct pjmedia_frame *output) { struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec; - unsigned i; + pj_int16_t *pcm_in; + unsigned nsamples; - pj_assert(ilbc_codec != NULL); - PJ_ASSERT_RETURN(input && output, PJ_EINVAL); + pj_assert(ilbc_codec && input && output); - if (output_buf_len < ilbc_codec->enc_frame_size) - return PJMEDIA_CODEC_EFRMTOOSHORT; + pcm_in = (pj_int16_t*)input->buf; + nsamples = input->size >> 1; - if (input->size != (ilbc_codec->enc_samples_per_frame << 1)) - return PJMEDIA_CODEC_EPCMFRMINLEN; + PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0, + PJMEDIA_CODEC_EPCMFRMINLEN); + PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples / + ilbc_codec->enc_samples_per_frame, + PJMEDIA_CODEC_EFRMTOOSHORT); /* Detect silence */ if (ilbc_codec->vad_enabled) { @@ -547,18 +550,25 @@ static pj_status_t ilbc_codec_encode(pjmedia_codec *codec, } } - /* Convert to float */ - for (i=0; ienc_samples_per_frame; ++i) { - ilbc_codec->enc_block[i] = (float) (((pj_int16_t*)input->buf)[i]); - } - /* Encode */ - iLBC_encode((unsigned char *)output->buf, - ilbc_codec->enc_block, - &ilbc_codec->enc); + output->size = 0; + while (nsamples >= ilbc_codec->enc_samples_per_frame) { + unsigned i; + + /* Convert to float */ + for (i=0; ienc_samples_per_frame; ++i) { + ilbc_codec->enc_block[i] = (float) (*pcm_in++); + } + + iLBC_encode((unsigned char *)output->buf + output->size, + ilbc_codec->enc_block, + &ilbc_codec->enc); + + output->size += ilbc_codec->enc.no_of_bytes; + nsamples -= ilbc_codec->enc_samples_per_frame; + } output->type = PJMEDIA_FRAME_TYPE_AUDIO; - output->size = ilbc_codec->enc.no_of_bytes; output->timestamp = input->timestamp; return PJ_SUCCESS; diff --git a/pjmedia/src/pjmedia-codec/l16.c b/pjmedia/src/pjmedia-codec/l16.c index df456045..0ccc9309 100644 --- a/pjmedia/src/pjmedia-codec/l16.c +++ b/pjmedia/src/pjmedia-codec/l16.c @@ -564,6 +564,8 @@ static pj_status_t l16_encode(pjmedia_codec *codec, #if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 while (samp!=samp_end) *samp_out++ = pj_htons(*samp++); +#else + pjmedia_copy_samples(samp_out, samp, input->size >> 1); #endif @@ -596,6 +598,8 @@ static pj_status_t l16_decode(pjmedia_codec *codec, #if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 while (samp!=samp_end) *samp_out++ = pj_htons(*samp++); +#else + pjmedia_copy_samples(samp_out, samp, input->size >> 1); #endif diff --git a/pjmedia/src/pjmedia-codec/speex_codec.c b/pjmedia/src/pjmedia-codec/speex_codec.c index dc2c7400..05d6b67b 100644 --- a/pjmedia/src/pjmedia-codec/speex_codec.c +++ b/pjmedia/src/pjmedia-codec/speex_codec.c @@ -160,9 +160,9 @@ static pj_status_t get_speex_info( struct speex_param *p ) if (!state) return PJMEDIA_CODEC_EFAILED; - /* Set the quality */ - if (p->quality != -1) - speex_encoder_ctl(state, SPEEX_SET_QUALITY, &p->quality); + /* We have to get maximum bitrate, so let's set maximum quality */ + tmp = 10; + speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp); /* Sampling rate. */ speex_encoder_ctl(state, SPEEX_SET_SAMPLING_RATE, &p->clock_rate); @@ -595,9 +595,6 @@ static pj_status_t spx_codec_open( pjmedia_codec *codec, spx = (struct spx_private*) codec->codec_data; id = spx->param_id; - /* Only supports one frame per packet */ - PJ_ASSERT_RETURN(attr->setting.frm_per_pkt==1, PJ_EINVAL); - /* * Create and initialize encoder. */ @@ -687,9 +684,6 @@ static pj_status_t spx_codec_modify(pjmedia_codec *codec, spx = (struct spx_private*) codec->codec_data; - /* Only supports one frame per packet */ - PJ_ASSERT_RETURN(attr->setting.frm_per_pkt==1, PJ_EINVAL); - /* VAD */ tmp = (attr->setting.vad != 0); speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp); @@ -702,6 +696,119 @@ static pj_status_t spx_codec_modify(pjmedia_codec *codec, return PJ_SUCCESS; } +#if 0 +# define TRACE__(args) PJ_LOG(5,args) +#else +# define TRACE__(args) +#endif + +#undef THIS_FUNC +#define THIS_FUNC "speex_get_next_frame" + +#define NB_SUBMODES 16 +#define NB_SUBMODE_BITS 4 + +#define SB_SUBMODES 8 +#define SB_SUBMODE_BITS 3 + +/* This function will iterate frames & submodes in the Speex bits. + * Returns 0 if a frame found, otherwise returns -1. + */ +int speex_get_next_frame(SpeexBits *bits) +{ + static const int inband_skip_table[NB_SUBMODES] = + {1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 }; + static const int wb_skip_table[SB_SUBMODES] = + {SB_SUBMODE_BITS+1, 36, 112, 192, 352, -1, -1, -1}; + + unsigned submode; + unsigned nb_count = 0; + + while (speex_bits_remaining(bits) >= 5) { + unsigned wb_count = 0; + unsigned bit_ptr = bits->bitPtr; + unsigned char_ptr = bits->charPtr; + + /* WB frame */ + while ((speex_bits_remaining(bits) >= 4) + && speex_bits_unpack_unsigned(bits, 1)) + { + int advance; + + submode = speex_bits_unpack_unsigned(bits, 3); + advance = wb_skip_table[submode]; + if (advance < 0) { + TRACE__((THIS_FUNC, "Invalid mode encountered. " + "The stream is corrupted.")); + return -1; + } + TRACE__((THIS_FUNC, "WB layer skipped: %d bits", advance)); + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + + bit_ptr = bits->bitPtr; + char_ptr = bits->charPtr; + + /* Consecutive subband frames may not exceed 2 frames */ + if (++wb_count > 2) + return -1; + } + + /* End of bits, return the frame */ + if (speex_bits_remaining(bits) < 4) { + TRACE__((THIS_FUNC, "End of stream")); + return 0; + } + + /* Stop iteration, return the frame */ + if (nb_count > 0) { + bits->bitPtr = bit_ptr; + bits->charPtr = char_ptr; + return 0; + } + + /* Get control bits */ + submode = speex_bits_unpack_unsigned(bits, 4); + TRACE__((THIS_FUNC, "Control bits: %d at %d", + submode, bits->charPtr*8+bits->bitPtr)); + + if (submode == 15) { + TRACE__((THIS_FUNC, "Found submode: terminator")); + return 0; + } else if (submode == 14) { + /* in-band signal; next 4 bits contain signal id */ + submode = speex_bits_unpack_unsigned(bits, 4); + TRACE__((THIS_FUNC, "Found submode: in-band %d bits", + inband_skip_table[submode])); + speex_bits_advance(bits, inband_skip_table[submode]); + } else if (submode == 13) { + /* user in-band; next 5 bits contain msg len */ + submode = speex_bits_unpack_unsigned(bits, 5); + TRACE__((THIS_FUNC, "Found submode: user-band %d bytes", submode)); + speex_bits_advance(bits, submode * 8); + } else if (submode > 8) { + TRACE__((THIS_FUNC, "Unknown sub-mode %d", submode)); + return 0; + } else { + /* NB frame */ + unsigned int advance = submode; + speex_mode_query(&speex_nb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance); + if (advance < 0) { + TRACE__((THIS_FUNC, "Invalid mode encountered. " + "The stream is corrupted.")); + return -1; + } + TRACE__((THIS_FUNC, "Submode %d: %d bits", submode, advance)); + advance -= (NB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + + ++nb_count; + } + } + + return 0; +} + /* * Get frames in the packet. @@ -713,45 +820,42 @@ static pj_status_t spx_codec_parse( pjmedia_codec *codec, unsigned *frame_cnt, pjmedia_frame frames[]) { - struct spx_private *spx; - unsigned frame_size, samples_per_frame; - unsigned count; - - spx = (struct spx_private*) codec->codec_data; - - frame_size = spx_factory.speex_param[spx->param_id].framesize; - samples_per_frame = spx_factory.speex_param[spx->param_id].samples_per_frame; - - /* Don't really know how to do this... */ - count = 0; - while (pkt_size >= frame_size && count < *frame_cnt) { - frames[count].buf = pkt; - frames[count].size = frame_size; + struct spx_private *spx = (struct spx_private*) codec->codec_data; + unsigned samples_per_frame; + unsigned count = 0; + int char_ptr = 0; + int bit_ptr = 0; + + samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; + + /* Copy the data into the speex bit-stream */ + speex_bits_read_from(&spx->dec_bits, (char*)pkt, pkt_size); + + while (speex_get_next_frame(&spx->dec_bits) == 0 && + spx->dec_bits.charPtr != char_ptr) + { + frames[count].buf = (char*)pkt + char_ptr; + /* Bit info contains start bit offset of the frame */ + frames[count].bit_info = bit_ptr; frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; + frames[count].size = spx->dec_bits.charPtr - char_ptr; + if (spx->dec_bits.bitPtr) + ++frames[count].size; - pkt_size -= frame_size; - ++count; - pkt = ((char*)pkt) + frame_size; - } + bit_ptr = spx->dec_bits.bitPtr; + char_ptr = spx->dec_bits.charPtr; - /* Just in case speex has silence frame which size is less than normal - * frame size... - */ - if (pkt_size && count < *frame_cnt) { - frames[count].buf = pkt; - frames[count].size = pkt_size; - frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; - frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; ++count; } *frame_cnt = count; + return PJ_SUCCESS; } /* - * Encode frame. + * Encode frames. */ static pj_status_t spx_codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, @@ -759,8 +863,10 @@ static pj_status_t spx_codec_encode( pjmedia_codec *codec, struct pjmedia_frame *output) { struct spx_private *spx; - unsigned sz; - int tx; + unsigned samples_per_frame; + int tx = 0; + spx_int16_t *pcm_in = (spx_int16_t*)input->buf; + unsigned nsamples; spx = (struct spx_private*) codec->codec_data; @@ -772,12 +878,21 @@ static pj_status_t spx_codec_encode( pjmedia_codec *codec, return PJ_SUCCESS; } + nsamples = input->size >> 1; + samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; + + PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0, + PJMEDIA_CODEC_EPCMFRMINLEN); + /* Flush all the bits in the struct so we can encode a new frame */ speex_bits_reset(&spx->enc_bits); - /* Encode the frame */ - tx = speex_encode_int(spx->enc, (spx_int16_t*)input->buf, - &spx->enc_bits); + /* Encode the frames */ + while (nsamples >= samples_per_frame) { + tx += speex_encode_int(spx->enc, pcm_in, &spx->enc_bits); + pcm_in += samples_per_frame; + nsamples -= samples_per_frame; + } /* Check if we need not to transmit the frame (DTX) */ if (tx == 0) { @@ -789,8 +904,7 @@ static pj_status_t spx_codec_encode( pjmedia_codec *codec, } /* Check size. */ - sz = speex_bits_nbytes(&spx->enc_bits); - pj_assert(sz <= output_buf_len); + pj_assert(speex_bits_nbytes(&spx->enc_bits) <= (int)output_buf_len); /* Copy the bits to an array of char that can be written */ output->size = speex_bits_write(&spx->enc_bits, @@ -810,14 +924,17 @@ static pj_status_t spx_codec_decode( pjmedia_codec *codec, struct pjmedia_frame *output) { struct spx_private *spx; + unsigned samples_per_frame; spx = (struct spx_private*) codec->codec_data; + samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; - PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT); + PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1, + PJMEDIA_CODEC_EPCMTOOSHORT); if (input->type != PJMEDIA_FRAME_TYPE_AUDIO) { - pjmedia_zero_samples((pj_int16_t*)output->buf, 160); - output->size = 320; + pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame); + output->size = samples_per_frame << 1; output->timestamp.u64 = input->timestamp.u64; output->type = PJMEDIA_FRAME_TYPE_AUDIO; return PJ_SUCCESS; @@ -825,15 +942,17 @@ static pj_status_t spx_codec_decode( pjmedia_codec *codec, /* Copy the data into the bit-stream struct */ speex_bits_read_from(&spx->dec_bits, (char*)input->buf, input->size); + + /* Set Speex dec_bits pointer to the start bit of the frame */ + speex_bits_advance(&spx->dec_bits, input->bit_info); /* Decode the data */ speex_decode_int(spx->dec, &spx->dec_bits, (spx_int16_t*)output->buf); output->type = PJMEDIA_FRAME_TYPE_AUDIO; - output->size = 320; + output->size = samples_per_frame << 1; output->timestamp.u64 = input->timestamp.u64; - return PJ_SUCCESS; } diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c index e3aa86e7..b8361913 100644 --- a/pjmedia/src/pjmedia/jbuf.c +++ b/pjmedia/src/pjmedia/jbuf.c @@ -38,6 +38,7 @@ typedef struct jb_framelist_t char *flist_buffer; int *flist_frame_type; pj_size_t *flist_content_len; + pj_uint32_t *flist_bit_info; unsigned flist_frame_size; unsigned flist_max_count; unsigned flist_empty; @@ -108,6 +109,10 @@ static pj_status_t jb_framelist_init( pj_pool_t *pool, pj_pool_zalloc(pool, sizeof(framelist->flist_content_len[0]) * framelist->flist_max_count); + framelist->flist_bit_info = (pj_uint32_t*) + pj_pool_zalloc(pool, sizeof(framelist->flist_bit_info[0]) * + framelist->flist_max_count); + framelist->flist_empty = 1; return PJ_SUCCESS; @@ -134,7 +139,8 @@ static unsigned jb_framelist_size(jb_framelist_t *framelist) static pj_bool_t jb_framelist_get(jb_framelist_t *framelist, void *frame, pj_size_t *size, - pjmedia_jb_frame_type *p_type) + pjmedia_jb_frame_type *p_type, + pj_uint32_t *bit_info) { if (!framelist->flist_empty) { pj_memcpy(frame, @@ -143,7 +149,10 @@ static pj_bool_t jb_framelist_get(jb_framelist_t *framelist, framelist->flist_frame_size); *p_type = (pjmedia_jb_frame_type) framelist->flist_frame_type[framelist->flist_head]; - *size = framelist->flist_content_len[framelist->flist_head]; + if (size) + *size = framelist->flist_content_len[framelist->flist_head]; + if (bit_info) + *bit_info = framelist->flist_bit_info[framelist->flist_head]; pj_bzero(framelist->flist_buffer + framelist->flist_head * framelist->flist_frame_size, @@ -221,7 +230,8 @@ static void jb_framelist_remove_head( jb_framelist_t *framelist, static pj_bool_t jb_framelist_put_at(jb_framelist_t *framelist, unsigned index, const void *frame, - unsigned frame_size) + unsigned frame_size, + pj_uint32_t bit_info) { unsigned where; @@ -263,6 +273,7 @@ static pj_bool_t jb_framelist_put_at(jb_framelist_t *framelist, framelist->flist_frame_type[where] = PJMEDIA_JB_NORMAL_FRAME; framelist->flist_content_len[where] = frame_size; + framelist->flist_bit_info[where] = bit_info; return PJ_TRUE; } @@ -478,12 +489,13 @@ PJ_DEF(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb, pj_size_t frame_size, int frame_seq) { - pjmedia_jbuf_put_frame2(jb, frame, frame_size, frame_seq, NULL); + pjmedia_jbuf_put_frame2(jb, frame, frame_size, 0, frame_seq, NULL); } PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb, const void *frame, pj_size_t frame_size, + pj_uint32_t bit_info, int frame_seq, pj_bool_t *discarded) { @@ -508,8 +520,8 @@ PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb, min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size); if (seq_diff > 0) { - while (jb_framelist_put_at(&jb->jb_framelist, - frame_seq,frame,min_frame_size) == PJ_FALSE) + while (jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, + min_frame_size, bit_info) == PJ_FALSE) { jb_framelist_remove_head(&jb->jb_framelist, PJ_MAX(jb->jb_max_count/4,1) ); @@ -525,7 +537,7 @@ PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb, { pj_bool_t res; res = jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame, - min_frame_size); + min_frame_size, bit_info); if (discarded) *discarded = !res; } @@ -538,9 +550,7 @@ PJ_DEF(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, void *frame, char *p_frame_type) { - pj_size_t size; - - pjmedia_jbuf_get_frame2(jb, frame, &size, p_frame_type); + pjmedia_jbuf_get_frame2(jb, frame, NULL, p_frame_type, NULL); } /* @@ -549,7 +559,8 @@ PJ_DEF(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, PJ_DEF(void) pjmedia_jbuf_get_frame2(pjmedia_jbuf *jb, void *frame, pj_size_t *size, - char *p_frame_type) + char *p_frame_type, + pj_uint32_t *bit_info) { pjmedia_jb_frame_type ftype; @@ -581,7 +592,9 @@ PJ_DEF(void) pjmedia_jbuf_get_frame2(pjmedia_jbuf *jb, #endif /* Retrieve a frame from frame list */ - if (jb_framelist_get(&jb->jb_framelist,frame,size,&ftype) == PJ_FALSE) { + if (jb_framelist_get(&jb->jb_framelist,frame,size,&ftype,bit_info) == + PJ_FALSE) + { /* Can't return frame because jitter buffer is empty! */ pj_bzero(frame, jb->jb_frame_size); *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME; diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index 2122033b..c5d632d3 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -229,10 +229,11 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) { char frame_type; pj_size_t frame_size; + pj_uint32_t bit_info; /* Get frame from jitter buffer. */ pjmedia_jbuf_get_frame2(stream->jb, channel->out_pkt, &frame_size, - &frame_type); + &frame_type, &bit_info); if (frame_type == PJMEDIA_JB_MISSING_FRAME) { @@ -364,6 +365,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) /* Decode */ frame_in.buf = channel->out_pkt; frame_in.size = frame_size; + frame_in.bit_info = bit_info; frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO; /* ignored */ frame_out.buf = p_out_samp + samples_count; @@ -677,60 +679,15 @@ static pj_status_t put_frame_imp( pjmedia_port *port, } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE && frame->buf != NULL) { - unsigned ts, codec_samples_per_frame; - - /* Repeatedly call encode if there are multiple frames to be - * sent. - */ - codec_samples_per_frame = stream->codec_param.info.enc_ptime * - stream->codec_param.info.clock_rate / - 1000; - if (codec_samples_per_frame == 0) { - codec_samples_per_frame = stream->codec_param.info.frm_ptime * - stream->codec_param.info.clock_rate / - 1000; - } - - for (ts=0; tscodec_param.info.pcm_bits_per_sample/8; - - /* Split original PCM input frame into base frame size */ - tmp_in_frame.timestamp.u64 = frame->timestamp.u64 + ts; - tmp_in_frame.buf = ((char*)frame->buf) + ts * bytes_per_sample; - tmp_in_frame.size = codec_samples_per_frame * bytes_per_sample; - tmp_in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; - - /* Set output frame position */ - tmp_out_frame.buf = ((char*)frame_out.buf) + frame_out.size; - - max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr) - - frame_out.size; - - /* Encode! */ - status = stream->codec->op->encode( stream->codec, &tmp_in_frame, - max_size, &tmp_out_frame); - if (status != PJ_SUCCESS) { - LOGERR_((stream->port.info.name.ptr, - "Codec encode() error", status)); - return status; - } - - /* tmp_out_frame.size may be zero for silence frame. */ - frame_out.size += tmp_out_frame.size; - - /* Stop processing next PCM frame when encode() returns either - * CNG frame or NULL frame. - */ - if (tmp_out_frame.type!=PJMEDIA_FRAME_TYPE_AUDIO || - tmp_out_frame.size==0) - { - break; - } - + /* Encode! */ + status = stream->codec->op->encode( stream->codec, frame, + channel->out_pkt_size - + sizeof(pjmedia_rtp_hdr), + &frame_out); + if (status != PJ_SUCCESS) { + LOGERR_((stream->port.info.name.ptr, + "Codec encode() error", status)); + return status; } /* Encapsulate. */ @@ -1217,7 +1174,7 @@ static void on_rx_rtp( void *data, ext_seq = (unsigned)(frames[i].timestamp.u64 / ts_span); pjmedia_jbuf_put_frame2(stream->jb, frames[i].buf, frames[i].size, - ext_seq, &discarded); + frames[i].bit_info, ext_seq, &discarded); if (discarded) pkt_discarded = PJ_TRUE; } -- cgit v1.2.3