📄 g711.c
字号:
pj_status_t status;
PJ_ASSERT_RETURN(factory==&g711_factory.base, PJ_EINVAL);
/* Lock mutex. */
pj_mutex_lock(g711_factory.mutex);
/* Allocate new codec if no more is available */
if (pj_list_empty(&g711_factory.codec_list)) {
struct g711_private *codec_priv;
codec = PJ_POOL_ALLOC_T(g711_factory.pool, pjmedia_codec);
codec_priv = PJ_POOL_ZALLOC_T(g711_factory.pool, struct g711_private);
if (!codec || !codec_priv) {
pj_mutex_unlock(g711_factory.mutex);
return PJ_ENOMEM;
}
/* Set the payload type */
codec_priv->pt = id->pt;
#if !PLC_DISABLED
/* Create PLC, always with 10ms ptime */
status = pjmedia_plc_create(g711_factory.pool, 8000, 80,
0, &codec_priv->plc);
if (status != PJ_SUCCESS) {
pj_mutex_unlock(g711_factory.mutex);
return status;
}
#endif
/* Create VAD */
status = pjmedia_silence_det_create(g711_factory.pool,
8000, 80,
&codec_priv->vad);
if (status != PJ_SUCCESS) {
pj_mutex_unlock(g711_factory.mutex);
return status;
}
codec->factory = factory;
codec->op = &g711_op;
codec->codec_data = codec_priv;
} else {
codec = g711_factory.codec_list.next;
pj_list_erase(codec);
}
/* Zero the list, for error detection in g711_dealloc_codec */
codec->next = codec->prev = NULL;
*p_codec = codec;
/* Unlock mutex. */
pj_mutex_unlock(g711_factory.mutex);
return PJ_SUCCESS;
}
static pj_status_t g711_dealloc_codec(pjmedia_codec_factory *factory,
pjmedia_codec *codec )
{
struct g711_private *priv = (struct g711_private*) codec->codec_data;
int i = 0;
PJ_ASSERT_RETURN(factory==&g711_factory.base, PJ_EINVAL);
/* Check that this node has not been deallocated before */
pj_assert (codec->next==NULL && codec->prev==NULL);
if (codec->next!=NULL || codec->prev!=NULL) {
return PJ_EINVALIDOP;
}
#if !PLC_DISABLED
/* Clear left samples in the PLC, since codec+plc will be reused
* next time.
*/
for (i=0; i<2; ++i) {
pj_int16_t frame[SAMPLES_PER_FRAME];
pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
pjmedia_plc_save(priv->plc, frame);
}
#else
PJ_UNUSED_ARG(i);
PJ_UNUSED_ARG(priv);
#endif
/* Lock mutex. */
pj_mutex_lock(g711_factory.mutex);
/* Insert at the back of the list */
pj_list_insert_before(&g711_factory.codec_list, codec);
/* Unlock mutex. */
pj_mutex_unlock(g711_factory.mutex);
return PJ_SUCCESS;
}
static pj_status_t g711_init( pjmedia_codec *codec, pj_pool_t *pool )
{
/* There's nothing to do here really */
PJ_UNUSED_ARG(codec);
PJ_UNUSED_ARG(pool);
return PJ_SUCCESS;
}
static pj_status_t g711_open(pjmedia_codec *codec,
pjmedia_codec_param *attr )
{
struct g711_private *priv = (struct g711_private*) codec->codec_data;
priv->pt = attr->info.pt;
#if !PLC_DISABLED
priv->plc_enabled = (attr->setting.plc != 0);
#endif
priv->vad_enabled = (attr->setting.vad != 0);
return PJ_SUCCESS;
}
static pj_status_t g711_close( pjmedia_codec *codec )
{
PJ_UNUSED_ARG(codec);
/* Nothing to do */
return PJ_SUCCESS;
}
static pj_status_t g711_modify(pjmedia_codec *codec,
const pjmedia_codec_param *attr )
{
struct g711_private *priv = (struct g711_private*) codec->codec_data;
if (attr->info.pt != priv->pt)
return PJMEDIA_EINVALIDPT;
#if !PLC_DISABLED
priv->plc_enabled = (attr->setting.plc != 0);
#endif
priv->vad_enabled = (attr->setting.vad != 0);
return PJ_SUCCESS;
}
static pj_status_t g711_parse( pjmedia_codec *codec,
void *pkt,
pj_size_t pkt_size,
const pj_timestamp *ts,
unsigned *frame_cnt,
pjmedia_frame frames[])
{
unsigned count = 0;
PJ_UNUSED_ARG(codec);
PJ_ASSERT_RETURN(ts && frame_cnt && frames, PJ_EINVAL);
while (pkt_size >= FRAME_SIZE && count < *frame_cnt) {
frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
frames[count].buf = pkt;
frames[count].size = FRAME_SIZE;
frames[count].timestamp.u64 = ts->u64 + SAMPLES_PER_FRAME * count;
pkt = ((char*)pkt) + FRAME_SIZE;
pkt_size -= FRAME_SIZE;
++count;
}
*frame_cnt = count;
return PJ_SUCCESS;
}
static pj_status_t g711_encode(pjmedia_codec *codec,
const struct pjmedia_frame *input,
unsigned output_buf_len,
struct pjmedia_frame *output)
{
pj_int16_t *samples = (pj_int16_t*) input->buf;
struct g711_private *priv = (struct g711_private*) codec->codec_data;
/* Check output buffer length */
if (output_buf_len < (input->size >> 1))
return PJMEDIA_CODEC_EFRMTOOSHORT;
/* Detect silence if VAD is enabled */
if (priv->vad_enabled) {
pj_bool_t is_silence;
pj_int32_t silence_period;
silence_period = pj_timestamp_diff32(&priv->last_tx,
&input->timestamp);
is_silence = pjmedia_silence_det_detect(priv->vad,
(const pj_int16_t*) input->buf,
(input->size >> 1), NULL);
if (is_silence &&
PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
{
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->buf = NULL;
output->size = 0;
output->timestamp = input->timestamp;
return PJ_SUCCESS;
} else {
priv->last_tx = input->timestamp;
}
}
/* Encode */
if (priv->pt == PJMEDIA_RTP_PT_PCMA) {
unsigned i, n;
pj_uint8_t *dst = (pj_uint8_t*) output->buf;
n = (input->size >> 1);
for (i=0; i!=n; ++i, ++dst) {
*dst = pjmedia_linear2alaw(samples[i]);
}
} else if (priv->pt == PJMEDIA_RTP_PT_PCMU) {
unsigned i, n;
pj_uint8_t *dst = (pj_uint8_t*) output->buf;
n = (input->size >> 1);
for (i=0; i!=n; ++i, ++dst) {
*dst = pjmedia_linear2ulaw(samples[i]);
}
} else {
return PJMEDIA_EINVALIDPT;
}
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
output->size = (input->size >> 1);
return PJ_SUCCESS;
}
static pj_status_t g711_decode(pjmedia_codec *codec,
const struct pjmedia_frame *input,
unsigned output_buf_len,
struct pjmedia_frame *output)
{
struct g711_private *priv = (struct g711_private*) codec->codec_data;
/* Check output buffer length */
PJ_ASSERT_RETURN(output_buf_len >= (input->size << 1),
PJMEDIA_CODEC_EPCMTOOSHORT);
/* Input buffer MUST have exactly 80 bytes long */
PJ_ASSERT_RETURN(input->size == FRAME_SIZE,
PJMEDIA_CODEC_EFRMINLEN);
/* Decode */
if (priv->pt == PJMEDIA_RTP_PT_PCMA) {
unsigned i;
pj_uint8_t *src = (pj_uint8_t*) input->buf;
pj_uint16_t *dst = (pj_uint16_t*) output->buf;
for (i=0; i!=input->size; ++i) {
*dst++ = (pj_uint16_t) pjmedia_alaw2linear(*src++);
}
} else if (priv->pt == PJMEDIA_RTP_PT_PCMU) {
unsigned i;
pj_uint8_t *src = (pj_uint8_t*) input->buf;
pj_uint16_t *dst = (pj_uint16_t*) output->buf;
for (i=0; i!=input->size; ++i) {
*dst++ = (pj_uint16_t) pjmedia_ulaw2linear(*src++);
}
} else {
return PJMEDIA_EINVALIDPT;
}
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
output->size = (input->size << 1);
#if !PLC_DISABLED
if (priv->plc_enabled)
pjmedia_plc_save( priv->plc, output->buf);
#endif
return PJ_SUCCESS;
}
#if !PLC_DISABLED
static pj_status_t g711_recover( pjmedia_codec *codec,
unsigned output_buf_len,
struct pjmedia_frame *output)
{
struct g711_private *priv = codec->codec_data;
if (!priv->plc_enabled)
return PJ_EINVALIDOP;
PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
PJMEDIA_CODEC_EPCMTOOSHORT);
pjmedia_plc_generate(priv->plc, output->buf);
output->size = SAMPLES_PER_FRAME * 2;
return PJ_SUCCESS;
}
#endif
#endif /* PJMEDIA_HAS_G711_CODEC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -