1
/* $Id: g722.c 3664 2011-07-19 03:42:28Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#include <pjmedia-codec/g722.h>
21
#include <pjmedia/codec.h>
22
#include <pjmedia/errno.h>
23
#include <pjmedia/endpoint.h>
24
#include <pjmedia/plc.h>
25
#include <pjmedia/port.h>
26
#include <pjmedia/silencedet.h>
27
#include <pj/assert.h>
30
#include <pj/string.h>
33
#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
35
#include "g722/g722_enc.h"
36
#include "g722/g722_dec.h"
38
#define THIS_FILE "g722.c"
42
#define SAMPLES_PER_FRAME (16000 * PTIME /1000)
43
#define FRAME_LEN (80)
44
#define PLC_DISABLED 0
52
# define TRACE_(expr) PJ_LOG(4,expr)
58
/* Prototypes for G722 factory */
59
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
60
const pjmedia_codec_info *id );
61
static pj_status_t g722_default_attr(pjmedia_codec_factory *factory,
62
const pjmedia_codec_info *id,
63
pjmedia_codec_param *attr );
64
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
66
pjmedia_codec_info codecs[]);
67
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
68
const pjmedia_codec_info *id,
69
pjmedia_codec **p_codec);
70
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
71
pjmedia_codec *codec );
73
/* Prototypes for G722 implementation. */
74
static pj_status_t g722_codec_init(pjmedia_codec *codec,
76
static pj_status_t g722_codec_open(pjmedia_codec *codec,
77
pjmedia_codec_param *attr );
78
static pj_status_t g722_codec_close(pjmedia_codec *codec );
79
static pj_status_t g722_codec_modify(pjmedia_codec *codec,
80
const pjmedia_codec_param *attr );
81
static pj_status_t g722_codec_parse(pjmedia_codec *codec,
84
const pj_timestamp *ts,
86
pjmedia_frame frames[]);
87
static pj_status_t g722_codec_encode(pjmedia_codec *codec,
88
const struct pjmedia_frame *input,
89
unsigned output_buf_len,
90
struct pjmedia_frame *output);
91
static pj_status_t g722_codec_decode(pjmedia_codec *codec,
92
const struct pjmedia_frame *input,
93
unsigned output_buf_len,
94
struct pjmedia_frame *output);
96
static pj_status_t g722_codec_recover(pjmedia_codec *codec,
97
unsigned output_buf_len,
98
struct pjmedia_frame *output);
101
/* Definition for G722 codec operations. */
102
static pjmedia_codec_op g722_op =
118
/* Definition for G722 codec factory operations. */
119
static pjmedia_codec_factory_op g722_factory_op =
126
&pjmedia_codec_g722_deinit
130
static struct g722_codec_factory
132
pjmedia_codec_factory base;
133
pjmedia_endpt *endpt;
136
pjmedia_codec codec_list;
138
} g722_codec_factory;
141
/* G722 codec private data. */
147
pj_int16_t pcm_clip_mask;
148
pj_bool_t plc_enabled;
149
pj_bool_t vad_enabled;
150
pjmedia_silence_det *vad;
151
pj_timestamp last_tx;
160
* Initialize and register G722 codec factory to pjmedia endpoint.
162
PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
164
pjmedia_codec_mgr *codec_mgr;
167
if (g722_codec_factory.pool != NULL)
170
/* Create G722 codec factory. */
171
g722_codec_factory.base.op = &g722_factory_op;
172
g722_codec_factory.base.factory_data = NULL;
173
g722_codec_factory.endpt = endpt;
174
g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT;
176
g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000,
178
if (!g722_codec_factory.pool)
181
pj_list_init(&g722_codec_factory.codec_list);
184
status = pj_mutex_create_simple(g722_codec_factory.pool, "g722",
185
&g722_codec_factory.mutex);
186
if (status != PJ_SUCCESS)
189
/* Get the codec manager. */
190
codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
192
status = PJ_EINVALIDOP;
196
/* Register codec factory to endpoint. */
197
status = pjmedia_codec_mgr_register_factory(codec_mgr,
198
&g722_codec_factory.base);
199
if (status != PJ_SUCCESS)
202
TRACE_((THIS_FILE, "G722 codec factory initialized"));
208
pj_pool_release(g722_codec_factory.pool);
209
g722_codec_factory.pool = NULL;
214
* Unregister G722 codec factory from pjmedia endpoint and deinitialize
215
* the G722 codec library.
217
PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
219
pjmedia_codec_mgr *codec_mgr;
222
if (g722_codec_factory.pool == NULL)
225
/* Get the codec manager. */
226
codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
228
pj_pool_release(g722_codec_factory.pool);
229
g722_codec_factory.pool = NULL;
230
return PJ_EINVALIDOP;
233
/* Unregister G722 codec factory. */
234
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
235
&g722_codec_factory.base);
238
pj_mutex_destroy(g722_codec_factory.mutex);
241
pj_pool_release(g722_codec_factory.pool);
242
g722_codec_factory.pool = NULL;
244
TRACE_((THIS_FILE, "G722 codec factory shutdown"));
250
* Set level adjustment.
252
PJ_DEF(pj_status_t) pjmedia_codec_g722_set_pcm_shift(unsigned val)
254
g722_codec_factory.pcm_shift = val;
260
* Check if factory can allocate the specified codec.
262
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
263
const pjmedia_codec_info *info )
265
PJ_UNUSED_ARG(factory);
267
/* Check payload type. */
268
if (info->pt != PJMEDIA_RTP_PT_G722)
269
return PJMEDIA_CODEC_EUNSUP;
271
/* Ignore the rest, since it's static payload type. */
277
* Generate default attribute.
279
static pj_status_t g722_default_attr( pjmedia_codec_factory *factory,
280
const pjmedia_codec_info *id,
281
pjmedia_codec_param *attr )
283
PJ_UNUSED_ARG(factory);
286
pj_bzero(attr, sizeof(pjmedia_codec_param));
287
attr->info.clock_rate = 16000;
288
attr->info.channel_cnt = 1;
289
attr->info.avg_bps = 64000;
290
attr->info.max_bps = 64000;
291
attr->info.pcm_bits_per_sample = 16;
292
attr->info.frm_ptime = PTIME;
293
attr->info.pt = PJMEDIA_RTP_PT_G722;
295
attr->setting.frm_per_pkt = 2;
296
attr->setting.vad = 1;
297
attr->setting.plc = 1;
299
/* Default all other flag bits disabled. */
305
* Enum codecs supported by this factory (i.e. only G722!).
307
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
309
pjmedia_codec_info codecs[])
311
PJ_UNUSED_ARG(factory);
312
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
314
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
315
codecs[0].encoding_name = pj_str("G722");
316
codecs[0].pt = PJMEDIA_RTP_PT_G722;
317
codecs[0].type = PJMEDIA_TYPE_AUDIO;
318
codecs[0].clock_rate = 16000;
319
codecs[0].channel_cnt = 1;
327
* Allocate a new G722 codec instance.
329
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
330
const pjmedia_codec_info *id,
331
pjmedia_codec **p_codec)
333
pjmedia_codec *codec;
334
struct g722_data *g722_data;
336
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
337
PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
339
pj_mutex_lock(g722_codec_factory.mutex);
341
/* Get free nodes, if any. */
342
if (!pj_list_empty(&g722_codec_factory.codec_list)) {
343
codec = g722_codec_factory.codec_list.next;
344
pj_list_erase(codec);
348
codec = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, pjmedia_codec);
349
PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
350
codec->op = &g722_op;
351
codec->factory = factory;
353
g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
354
codec->codec_data = g722_data;
358
status = pjmedia_plc_create(g722_codec_factory.pool, 16000,
359
SAMPLES_PER_FRAME, 0, &g722_data->plc);
360
if (status != PJ_SUCCESS) {
361
pj_mutex_unlock(g722_codec_factory.mutex);
366
/* Create silence detector */
367
status = pjmedia_silence_det_create(g722_codec_factory.pool,
368
16000, SAMPLES_PER_FRAME,
370
if (status != PJ_SUCCESS) {
371
pj_mutex_unlock(g722_codec_factory.mutex);
372
TRACE_((THIS_FILE, "Create silence detector failed (status = %d)",
379
pj_mutex_unlock(g722_codec_factory.mutex);
388
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
389
pjmedia_codec *codec )
391
struct g722_data *g722_data;
394
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
395
PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
397
g722_data = (struct g722_data*) codec->codec_data;
399
/* Close codec, if it's not closed. */
400
g722_codec_close(codec);
403
/* Clear left samples in the PLC, since codec+plc will be reused
406
for (i=0; i<2; ++i) {
407
pj_int16_t frame[SAMPLES_PER_FRAME];
408
pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
409
pjmedia_plc_save(g722_data->plc, frame);
415
/* Re-init silence_period */
416
pj_set_timestamp32(&g722_data->last_tx, 0, 0);
418
/* Put in the free list. */
419
pj_mutex_lock(g722_codec_factory.mutex);
420
pj_list_push_front(&g722_codec_factory.codec_list, codec);
421
pj_mutex_unlock(g722_codec_factory.mutex);
429
static pj_status_t g722_codec_init(pjmedia_codec *codec,
432
PJ_UNUSED_ARG(codec);
440
static pj_status_t g722_codec_open(pjmedia_codec *codec,
441
pjmedia_codec_param *attr )
443
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
446
PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
447
PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
449
status = g722_enc_init(&g722_data->encoder);
450
if (status != PJ_SUCCESS) {
451
TRACE_((THIS_FILE, "g722_enc_init() failed, status=%d", status));
452
pj_mutex_unlock(g722_codec_factory.mutex);
453
return PJMEDIA_CODEC_EFAILED;
456
status = g722_dec_init(&g722_data->decoder);
457
if (status != PJ_SUCCESS) {
458
TRACE_((THIS_FILE, "g722_dec_init() failed, status=%d", status));
459
pj_mutex_unlock(g722_codec_factory.mutex);
460
return PJMEDIA_CODEC_EFAILED;
463
g722_data->vad_enabled = (attr->setting.vad != 0);
464
g722_data->plc_enabled = (attr->setting.plc != 0);
465
g722_data->pcm_shift = g722_codec_factory.pcm_shift;
466
g722_data->pcm_clip_mask = (pj_int16_t)(1<<g722_codec_factory.pcm_shift)-1;
467
g722_data->pcm_clip_mask <<= (16-g722_codec_factory.pcm_shift);
469
TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
470
g722_data->vad_enabled, g722_data->plc_enabled));
477
static pj_status_t g722_codec_close( pjmedia_codec *codec )
479
/* The codec, encoder, and decoder will be reused, so there's
483
PJ_UNUSED_ARG(codec);
485
TRACE_((THIS_FILE, "G722 codec closed"));
491
* Modify codec settings.
493
static pj_status_t g722_codec_modify(pjmedia_codec *codec,
494
const pjmedia_codec_param *attr )
496
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
498
pj_assert(g722_data != NULL);
500
g722_data->vad_enabled = (attr->setting.vad != 0);
501
g722_data->plc_enabled = (attr->setting.plc != 0);
503
TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
504
g722_data->vad_enabled, g722_data->plc_enabled));
510
* Get frames in the packet.
512
static pj_status_t g722_codec_parse(pjmedia_codec *codec,
515
const pj_timestamp *ts,
517
pjmedia_frame frames[])
521
PJ_UNUSED_ARG(codec);
523
PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
525
TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
527
while (pkt_size >= FRAME_LEN && count < *frame_cnt) {
528
frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
529
frames[count].buf = pkt;
530
frames[count].size = FRAME_LEN;
531
frames[count].timestamp.u64 = ts->u64 + count * SAMPLES_PER_FRAME;
533
pkt = ((char*)pkt) + FRAME_LEN;
534
pkt_size -= FRAME_LEN;
539
TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
548
static pj_status_t g722_codec_encode(pjmedia_codec *codec,
549
const struct pjmedia_frame *input,
550
unsigned output_buf_len,
551
struct pjmedia_frame *output)
553
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
556
pj_assert(g722_data && input && output);
558
PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len,
559
PJMEDIA_CODEC_EFRMTOOSHORT);
562
if (g722_data->vad_enabled) {
563
pj_bool_t is_silence;
564
pj_int32_t silence_duration;
566
silence_duration = pj_timestamp_diff32(&g722_data->last_tx,
569
is_silence = pjmedia_silence_det_detect(g722_data->vad,
570
(const pj_int16_t*) input->buf,
574
(PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
575
silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000))
577
output->type = PJMEDIA_FRAME_TYPE_NONE;
580
output->timestamp = input->timestamp;
583
g722_data->last_tx = input->timestamp;
587
/* Adjust input signal level from 16-bit to 14-bit */
588
if (g722_data->pcm_shift) {
591
p = (pj_int16_t*)input->buf;
592
end = p + input->size/2;
594
*p++ >>= g722_data->pcm_shift;
598
/* Encode to temporary buffer */
599
output->size = output_buf_len;
600
status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf,
601
(input->size >> 1), output->buf, &output->size);
602
if (status != PJ_SUCCESS) {
605
output->type = PJMEDIA_FRAME_TYPE_NONE;
606
TRACE_((THIS_FILE, "G722 encode() status: %d", status));
607
return PJMEDIA_CODEC_EFAILED;
610
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
611
output->timestamp = input->timestamp;
613
TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
620
static pj_status_t g722_codec_decode(pjmedia_codec *codec,
621
const struct pjmedia_frame *input,
622
unsigned output_buf_len,
623
struct pjmedia_frame *output)
625
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
628
pj_assert(g722_data != NULL);
629
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
631
TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
633
input->buf, input->size, output->buf, output_buf_len));
635
if (output_buf_len < SAMPLES_PER_FRAME * 2) {
636
TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
637
return PJMEDIA_CODEC_EPCMTOOSHORT;
640
if (input->size != FRAME_LEN) {
641
TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
642
return PJMEDIA_CODEC_EFRMTOOSHORT;
647
output->size = SAMPLES_PER_FRAME;
648
status = g722_dec_decode(&g722_data->decoder, input->buf, input->size,
649
(pj_int16_t*)output->buf, &output->size);
650
if (status != PJ_SUCCESS) {
651
TRACE_((THIS_FILE, "G722 decode() status: %d", status));
652
return PJMEDIA_CODEC_EFAILED;
655
pj_assert(output->size == SAMPLES_PER_FRAME);
657
/* Adjust input signal level from 14-bit to 16-bit */
658
if (g722_data->pcm_shift) {
661
p = (pj_int16_t*)output->buf;
662
end = p + output->size;
664
#if PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING
665
/* If there is clipping, stop the PCM shifting */
666
if (*p & g722_data->pcm_clip_mask) {
667
g722_data->pcm_shift = 0;
671
*p++ <<= g722_data->pcm_shift;
675
output->size = SAMPLES_PER_FRAME * 2;
676
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
677
output->timestamp = input->timestamp;
680
if (g722_data->plc_enabled)
681
pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
684
TRACE_((THIS_FILE, "G722 decode done"));
691
* Recover lost frame.
693
static pj_status_t g722_codec_recover(pjmedia_codec *codec,
694
unsigned output_buf_len,
695
struct pjmedia_frame *output)
697
struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
699
PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
701
PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
702
PJMEDIA_CODEC_EPCMTOOSHORT);
704
pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
706
output->size = SAMPLES_PER_FRAME * 2;
707
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
713
#endif // PJMEDIA_HAS_G722_CODEC