summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia-codec
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-05-13 22:46:23 +0000
committerBenny Prijono <bennylp@teluu.com>2006-05-13 22:46:23 +0000
commitb4ff87018aef719a1427c47da854d0108b9ed6c4 (patch)
treef117b651f2daeea1824eca14945668df7d4898a3 /pjmedia/src/pjmedia-codec
parent19d4fb0b0f2d39538018f16323c4b6a52c07903d (diff)
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
Diffstat (limited to 'pjmedia/src/pjmedia-codec')
-rw-r--r--pjmedia/src/pjmedia-codec/gsm.c45
-rw-r--r--pjmedia/src/pjmedia-codec/l16.c45
-rw-r--r--pjmedia/src/pjmedia-codec/speex/ltp.c2
-rw-r--r--pjmedia/src/pjmedia-codec/speex_codec.c122
4 files changed, 133 insertions, 81 deletions
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; i<count; ++i) {
+ dst_buf[i] = (pj_int16_t)tmp[i];
+ }
+ output->size = count * 2;
+
+ return PJ_SUCCESS;
+}
+
#endif /* PJMEDIA_HAS_SPEEX_CODEC */