From b4ff87018aef719a1427c47da854d0108b9ed6c4 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sat, 13 May 2006 22:46:23 +0000 Subject: Another major modifications in PJMEDIA: - handle multiple frames in one packet - split stream creation into two steps to allow customization - PLC framework and implementation with G.711 and speex - stream returns NO_FRAME correctly. - added ptime argument in pjsua git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@438 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia-codec/gsm.c | 45 ++++++------ pjmedia/src/pjmedia-codec/l16.c | 45 ++++++------ pjmedia/src/pjmedia-codec/speex/ltp.c | 2 +- pjmedia/src/pjmedia-codec/speex_codec.c | 122 +++++++++++++++++++++----------- 4 files changed, 133 insertions(+), 81 deletions(-) (limited to 'pjmedia/src/pjmedia-codec') diff --git a/pjmedia/src/pjmedia-codec/gsm.c b/pjmedia/src/pjmedia-codec/gsm.c index ebb6d1be..8689960f 100644 --- a/pjmedia/src/pjmedia-codec/gsm.c +++ b/pjmedia/src/pjmedia-codec/gsm.c @@ -54,11 +54,12 @@ static pj_status_t gsm_codec_init( pjmedia_codec *codec, static pj_status_t gsm_codec_open( pjmedia_codec *codec, pjmedia_codec_param *attr ); static pj_status_t gsm_codec_close( pjmedia_codec *codec ); -static pj_status_t gsm_codec_get_frames( pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]); +static pj_status_t gsm_codec_parse( pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]); static pj_status_t gsm_codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, @@ -74,7 +75,7 @@ static pjmedia_codec_op gsm_op = &gsm_codec_init, &gsm_codec_open, &gsm_codec_close, - &gsm_codec_get_frames, + &gsm_codec_parse, &gsm_codec_encode, &gsm_codec_decode }; @@ -230,12 +231,14 @@ static pj_status_t gsm_default_attr (pjmedia_codec_factory *factory, PJ_UNUSED_ARG(id); pj_memset(attr, 0, sizeof(pjmedia_codec_param)); - attr->clock_rate = 8000; - attr->channel_cnt = 1; - attr->avg_bps = 13200; - attr->pcm_bits_per_sample = 16; - attr->ptime = 20; - attr->pt = PJMEDIA_RTP_PT_GSM; + attr->info.clock_rate = 8000; + attr->info.channel_cnt = 1; + attr->info.avg_bps = 13200; + attr->info.pcm_bits_per_sample = 16; + attr->info.frm_ptime = 20; + attr->info.pt = PJMEDIA_RTP_PT_GSM; + + attr->setting.frm_per_pkt = 1; /* Default all flag bits disabled. */ @@ -386,11 +389,12 @@ static pj_status_t gsm_codec_close( pjmedia_codec *codec ) /* * Get frames in the packet. */ -static pj_status_t gsm_codec_get_frames( pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]) +static pj_status_t gsm_codec_parse( pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]) { unsigned count = 0; @@ -399,9 +403,10 @@ static pj_status_t gsm_codec_get_frames( pjmedia_codec *codec, PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL); while (pkt_size >= 33 && count < *frame_cnt) { - frames[0].type = PJMEDIA_FRAME_TYPE_AUDIO; - frames[0].buf = pkt; - frames[0].size = 33; + frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; + frames[count].buf = pkt; + frames[count].size = 33; + frames[count].timestamp.u64 = ts->u64 + count * 160; pkt = ((char*)pkt) + 33; pkt_size -= 33; diff --git a/pjmedia/src/pjmedia-codec/l16.c b/pjmedia/src/pjmedia-codec/l16.c index 594aefc3..47e4c070 100644 --- a/pjmedia/src/pjmedia-codec/l16.c +++ b/pjmedia/src/pjmedia-codec/l16.c @@ -61,11 +61,12 @@ static pj_status_t l16_init( pjmedia_codec *codec, static pj_status_t l16_open( pjmedia_codec *codec, pjmedia_codec_param *attr ); static pj_status_t l16_close( pjmedia_codec *codec ); -static pj_status_t l16_get_frames(pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]); +static pj_status_t l16_parse(pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]); static pj_status_t l16_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, @@ -81,7 +82,7 @@ static pjmedia_codec_op l16_op = &l16_init, &l16_open, &l16_close, - &l16_get_frames, + &l16_parse, &l16_encode, &l16_decode }; @@ -234,16 +235,18 @@ static pj_status_t l16_default_attr( pjmedia_codec_factory *factory, PJ_UNUSED_ARG(factory); pj_memset(attr, 0, sizeof(pjmedia_codec_param)); - attr->pt = id->pt; - attr->clock_rate = id->clock_rate; - attr->channel_cnt = id->channel_cnt; - attr->avg_bps = id->clock_rate * id->channel_cnt * 16; - attr->pcm_bits_per_sample = 16; + attr->info.pt = (pj_uint8_t)id->pt; + attr->info.clock_rate = id->clock_rate; + attr->info.channel_cnt = id->channel_cnt; + attr->info.avg_bps = id->clock_rate * id->channel_cnt * 16; + attr->info.pcm_bits_per_sample = 16; /* To keep frame size below 1400 MTU, set ptime to 10ms for * sampling rate > 35 KHz */ - attr->ptime = GET_PTIME(id->clock_rate); + attr->info.frm_ptime = GET_PTIME(id->clock_rate); + + attr->setting.frm_per_pkt = 1; /* Default all flag bits disabled. */ @@ -498,11 +501,12 @@ static pj_status_t l16_close( pjmedia_codec *codec ) return PJ_SUCCESS; } -static pj_status_t l16_get_frames( pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]) +static pj_status_t l16_parse( pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]) { unsigned count = 0; struct l16_data *data = (struct l16_data*) codec->codec_data; @@ -511,9 +515,10 @@ static pj_status_t l16_get_frames( pjmedia_codec *codec, PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL); while (pkt_size >= data->frame_size && count < *frame_cnt) { - frames[0].type = PJMEDIA_FRAME_TYPE_AUDIO; - frames[0].buf = pkt; - frames[0].size = data->frame_size; + frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; + frames[count].buf = pkt; + frames[count].size = data->frame_size; + frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size); pkt = ((char*)pkt) + data->frame_size; pkt_size -= data->frame_size; diff --git a/pjmedia/src/pjmedia-codec/speex/ltp.c b/pjmedia/src/pjmedia-codec/speex/ltp.c index 94189c34..8620dd47 100644 --- a/pjmedia/src/pjmedia-codec/speex/ltp.c +++ b/pjmedia/src/pjmedia-codec/speex/ltp.c @@ -176,7 +176,7 @@ void open_loop_nbest_pitch(spx_sig_t *sw, int start, int end, int len, int *pitc VARDECL(spx_word32_t *corr); VARDECL(spx_word32_t *energy); VARDECL(spx_word32_t *score); - VARDECL(spx_word16_t *swn2); + /*VARDECL(spx_word16_t *swn2);*/ spx_word16_t *swn; ALLOC(best_score, N, spx_word32_t); diff --git a/pjmedia/src/pjmedia-codec/speex_codec.c b/pjmedia/src/pjmedia-codec/speex_codec.c index 280cfbdd..1bf161b6 100644 --- a/pjmedia/src/pjmedia-codec/speex_codec.c +++ b/pjmedia/src/pjmedia-codec/speex_codec.c @@ -61,11 +61,12 @@ static pj_status_t spx_codec_init( pjmedia_codec *codec, static pj_status_t spx_codec_open( pjmedia_codec *codec, pjmedia_codec_param *attr ); static pj_status_t spx_codec_close( pjmedia_codec *codec ); -static pj_status_t spx_codec_get_frames( pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]); +static pj_status_t spx_codec_parse( pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]); static pj_status_t spx_codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, @@ -74,6 +75,9 @@ static pj_status_t spx_codec_decode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output); +static pj_status_t spx_codec_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output); /* Definition for Speex codec operations. */ static pjmedia_codec_op spx_op = @@ -81,9 +85,10 @@ static pjmedia_codec_op spx_op = &spx_codec_init, &spx_codec_open, &spx_codec_close, - &spx_codec_get_frames, + &spx_codec_parse, &spx_codec_encode, - &spx_codec_decode + &spx_codec_decode, + &spx_codec_recover }; /* Definition for Speex codec factory operations. */ @@ -377,36 +382,38 @@ static pj_status_t spx_default_attr (pjmedia_codec_factory *factory, PJ_ASSERT_RETURN(factory==&spx_factory.base, PJ_EINVAL); pj_memset(attr, 0, sizeof(pjmedia_codec_param)); - attr->pt = id->pt; - attr->channel_cnt = 1; + attr->info.pt = (pj_uint8_t)id->pt; + attr->info.channel_cnt = 1; if (id->clock_rate <= 8000) { - attr->clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate; - attr->avg_bps = spx_factory.speex_param[PARAM_NB].bitrate; + attr->info.clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate; + attr->info.avg_bps = spx_factory.speex_param[PARAM_NB].bitrate; } else if (id->clock_rate <= 16000) { - attr->clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate; - attr->avg_bps = spx_factory.speex_param[PARAM_WB].bitrate; + attr->info.clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate; + attr->info.avg_bps = spx_factory.speex_param[PARAM_WB].bitrate; } else { /* Wow.. somebody is doing ultra-wideband. Cool...! */ - attr->clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate; - attr->avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate; + attr->info.clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate; + attr->info.avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate; } - attr->pcm_bits_per_sample = 16; - attr->ptime = 20; - attr->pt = id->pt; + attr->info.pcm_bits_per_sample = 16; + attr->info.frm_ptime = 20; + attr->info.pt = (pj_uint8_t)id->pt; + + attr->setting.frm_per_pkt = 1; /* Default flags. */ - attr->cng = 1; - attr->concl = 1; - attr->hpf = 1; - attr->lpf =1 ; - attr->penh =1 ; + attr->setting.cng = 1; + attr->setting.plc = 1; + attr->setting.hpf = 1; + attr->setting.lpf =1 ; + attr->setting.penh =1 ; /* Default, set VAD off as it caused voice chip off */ - attr->vad = 0; + attr->setting.vad = 0; return PJ_SUCCESS; } @@ -559,12 +566,12 @@ static pj_status_t spx_codec_open( pjmedia_codec *codec, } /* Sampling rate. */ - tmp = attr->clock_rate; + tmp = attr->info.clock_rate; speex_encoder_ctl(spx->enc, SPEEX_SET_SAMPLING_RATE, &spx_factory.speex_param[id].clock_rate); /* VAD */ - tmp = attr->vad; + tmp = attr->setting.vad; speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp); /* Complexity */ @@ -588,7 +595,7 @@ static pj_status_t spx_codec_open( pjmedia_codec *codec, &spx_factory.speex_param[id].clock_rate); /* PENH */ - tmp = attr->penh; + tmp = attr->setting.penh; speex_decoder_ctl(spx->dec, SPEEX_SET_ENH, &tmp); return PJ_SUCCESS; @@ -624,38 +631,43 @@ static pj_status_t spx_codec_close( pjmedia_codec *codec ) /* * Get frames in the packet. */ -static pj_status_t spx_codec_get_frames( pjmedia_codec *codec, - void *pkt, - pj_size_t pkt_size, - unsigned *frame_cnt, - pjmedia_frame frames[]) +static pj_status_t spx_codec_parse( pjmedia_codec *codec, + void *pkt, + pj_size_t pkt_size, + const pj_timestamp *ts, + unsigned *frame_cnt, + pjmedia_frame frames[]) { struct spx_private *spx; - unsigned speex_frame_size; + unsigned frame_size, samples_per_frame; unsigned count; spx = (struct spx_private*) codec->codec_data; - speex_frame_size = spx_factory.speex_param[spx->param_id].framesize; + 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 >= speex_frame_size && count < *frame_cnt) { + while (pkt_size >= frame_size && count < *frame_cnt) { frames[count].buf = pkt; - frames[count].size = speex_frame_size; + frames[count].size = frame_size; frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; - frames[count].timestamp.u64 = 0; + frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; - pkt_size -= speex_frame_size; + pkt_size -= frame_size; ++count; - pkt = ((char*)pkt) + speex_frame_size; + pkt = ((char*)pkt) + frame_size; } + /* 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 = 0; + frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; ++count; } @@ -764,5 +776,35 @@ static pj_status_t spx_codec_decode( pjmedia_codec *codec, return PJ_SUCCESS; } +/* + * Recover lost frame. + */ +static pj_status_t spx_codec_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output) +{ + struct spx_private *spx; + float tmp[642]; /* 20ms at 32KHz + 2 */ + pj_int16_t *dst_buf; + unsigned i, count; + + spx = (struct spx_private*) codec->codec_data; + + count = spx_factory.speex_param[spx->param_id].clock_rate * 20 / 1000; + pj_assert((count <= output_buf_len/2) && count <= PJ_ARRAY_SIZE(tmp)); + + /* Recover packet loss */ + speex_decode(spx->dec, NULL, tmp); + + /* Copy from float to short samples. */ + dst_buf = output->buf; + for (i=0; isize = count * 2; + + return PJ_SUCCESS; +} + #endif /* PJMEDIA_HAS_SPEEX_CODEC */ -- cgit v1.2.3