1
/* $Id: g722.c 2760 2009-06-13 15:28:37Z nanang $ */
3
* Copyright (C) 2008-2009 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
* Additional permission under GNU GPL version 3 section 7:
22
* If you modify this program, or any covered work, by linking or
23
* combining it with the OpenSSL project's OpenSSL library (or a
24
* modified version of that library), containing parts covered by the
25
* terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
26
* grants you additional permission to convey the resulting work.
27
* Corresponding Source for a non-source form of such a combination
28
* shall include the source code for the parts of OpenSSL used as well
29
* as that of the covered work.
31
#include <pjmedia-codec/g722.h>
32
#include <pjmedia/codec.h>
33
#include <pjmedia/errno.h>
34
#include <pjmedia/endpoint.h>
35
#include <pjmedia/plc.h>
36
#include <pjmedia/port.h>
37
#include <pjmedia/silencedet.h>
38
#include <pj/assert.h>
41
#include <pj/string.h>
44
#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
46
#include "g722/g722_enc.h"
47
#include "g722/g722_dec.h"
49
#define THIS_FILE "g722.c"
53
#define SAMPLES_PER_FRAME (16000 * PTIME /1000)
54
#define FRAME_LEN (160)
55
#define PLC_DISABLED 0
63
# define TRACE_(expr) PJ_LOG(4,expr)
69
/* Prototypes for G722 factory */
70
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
71
const pjmedia_codec_info *id );
72
static pj_status_t g722_default_attr(pjmedia_codec_factory *factory,
73
const pjmedia_codec_info *id,
74
pjmedia_codec_param *attr );
75
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
77
pjmedia_codec_info codecs[]);
78
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
79
const pjmedia_codec_info *id,
80
pjmedia_codec **p_codec);
81
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
82
pjmedia_codec *codec );
84
/* Prototypes for G722 implementation. */
85
static pj_status_t g722_codec_init(pjmedia_codec *codec,
87
static pj_status_t g722_codec_open(pjmedia_codec *codec,
88
pjmedia_codec_param *attr );
89
static pj_status_t g722_codec_close(pjmedia_codec *codec );
90
static pj_status_t g722_codec_modify(pjmedia_codec *codec,
91
const pjmedia_codec_param *attr );
92
static pj_status_t g722_codec_parse(pjmedia_codec *codec,
95
const pj_timestamp *ts,
97
pjmedia_frame frames[]);
98
static pj_status_t g722_codec_encode(pjmedia_codec *codec,
99
const struct pjmedia_frame *input,
100
unsigned output_buf_len,
101
struct pjmedia_frame *output);
102
static pj_status_t g722_codec_decode(pjmedia_codec *codec,
103
const struct pjmedia_frame *input,
104
unsigned output_buf_len,
105
struct pjmedia_frame *output);
107
static pj_status_t g722_codec_recover(pjmedia_codec *codec,
108
unsigned output_buf_len,
109
struct pjmedia_frame *output);
112
/* Definition for G722 codec operations. */
113
static pjmedia_codec_op g722_op =
129
/* Definition for G722 codec factory operations. */
130
static pjmedia_codec_factory_op g722_factory_op =
140
static struct g722_codec_factory
142
pjmedia_codec_factory base;
143
pjmedia_endpt *endpt;
146
pjmedia_codec codec_list;
147
} g722_codec_factory;
150
/* G722 codec private data. */
155
pj_bool_t plc_enabled;
156
pj_bool_t vad_enabled;
157
pjmedia_silence_det *vad;
158
pj_timestamp last_tx;
167
* Initialize and register G722 codec factory to pjmedia endpoint.
169
PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
171
pjmedia_codec_mgr *codec_mgr;
174
if (g722_codec_factory.pool != NULL)
177
/* Create G722 codec factory. */
178
g722_codec_factory.base.op = &g722_factory_op;
179
g722_codec_factory.base.factory_data = NULL;
180
g722_codec_factory.endpt = endpt;
182
g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000,
184
if (!g722_codec_factory.pool)
187
pj_list_init(&g722_codec_factory.codec_list);
190
status = pj_mutex_create_simple(g722_codec_factory.pool, "g722",
191
&g722_codec_factory.mutex);
192
if (status != PJ_SUCCESS)
195
/* Get the codec manager. */
196
codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
198
status = PJ_EINVALIDOP;
202
/* Register codec factory to endpoint. */
203
status = pjmedia_codec_mgr_register_factory(codec_mgr,
204
&g722_codec_factory.base);
205
if (status != PJ_SUCCESS)
208
TRACE_((THIS_FILE, "G722 codec factory initialized"));
214
pj_pool_release(g722_codec_factory.pool);
215
g722_codec_factory.pool = NULL;
220
* Unregister G722 codec factory from pjmedia endpoint and deinitialize
221
* the G722 codec library.
223
PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
225
pjmedia_codec_mgr *codec_mgr;
228
if (g722_codec_factory.pool == NULL)
231
/* Get the codec manager. */
232
codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
234
pj_pool_release(g722_codec_factory.pool);
235
g722_codec_factory.pool = NULL;
236
return PJ_EINVALIDOP;
239
/* Unregister G722 codec factory. */
240
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
241
&g722_codec_factory.base);
244
pj_mutex_destroy(g722_codec_factory.mutex);
247
pj_pool_release(g722_codec_factory.pool);
248
g722_codec_factory.pool = NULL;
250
TRACE_((THIS_FILE, "G722 codec factory shutdown"));
255
* Check if factory can allocate the specified codec.
257
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
258
const pjmedia_codec_info *info )
260
PJ_UNUSED_ARG(factory);
262
/* Check payload type. */
263
if (info->pt != PJMEDIA_RTP_PT_G722)
264
return PJMEDIA_CODEC_EUNSUP;
266
/* Ignore the rest, since it's static payload type. */
272
* Generate default attribute.
274
static pj_status_t g722_default_attr( pjmedia_codec_factory *factory,
275
const pjmedia_codec_info *id,
276
pjmedia_codec_param *attr )
278
PJ_UNUSED_ARG(factory);
281
pj_bzero(attr, sizeof(pjmedia_codec_param));
282
attr->info.clock_rate = 16000;
283
attr->info.channel_cnt = 1;
284
attr->info.avg_bps = 64000;
285
attr->info.max_bps = 64000;
286
attr->info.pcm_bits_per_sample = 16;
287
attr->info.frm_ptime = PTIME;
288
attr->info.pt = PJMEDIA_RTP_PT_G722;
290
attr->setting.frm_per_pkt = 1;
291
attr->setting.vad = 1;
292
attr->setting.plc = 1;
294
/* Default all other flag bits disabled. */
300
* Enum codecs supported by this factory (i.e. only G722!).
302
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
304
pjmedia_codec_info codecs[])
306
PJ_UNUSED_ARG(factory);
307
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
309
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
310
codecs[0].encoding_name = pj_str("G722");
311
codecs[0].pt = PJMEDIA_RTP_PT_G722;
312
codecs[0].type = PJMEDIA_TYPE_AUDIO;
313
codecs[0].clock_rate = 16000;
314
codecs[0].channel_cnt = 1;
322
* Allocate a new G722 codec instance.
324
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
325
const pjmedia_codec_info *id,
326
pjmedia_codec **p_codec)
328
pjmedia_codec *codec;
329
struct g722_data *g722_data;
331
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
332
PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
334
pj_mutex_lock(g722_codec_factory.mutex);
336
/* Get free nodes, if any. */
337
if (!pj_list_empty(&g722_codec_factory.codec_list)) {
338
codec = g722_codec_factory.codec_list.next;
339
pj_list_erase(codec);
343
codec = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, pjmedia_codec);
344
PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
345
codec->op = &g722_op;
346
codec->factory = factory;
348
g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
349
codec->codec_data = g722_data;
353
status = pjmedia_plc_create(g722_codec_factory.pool, 16000,
354
SAMPLES_PER_FRAME, 0, &g722_data->plc);
355
if (status != PJ_SUCCESS) {
356
pj_mutex_unlock(g722_codec_factory.mutex);
361
/* Create silence detector */
362
status = pjmedia_silence_det_create(g722_codec_factory.pool,
363
16000, SAMPLES_PER_FRAME,
365
if (status != PJ_SUCCESS) {
366
pj_mutex_unlock(g722_codec_factory.mutex);
367
TRACE_((THIS_FILE, "Create silence detector failed (status = %d)",
374
pj_mutex_unlock(g722_codec_factory.mutex);
383
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
384
pjmedia_codec *codec )
386
struct g722_data *g722_data;
389
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
390
PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
392
g722_data = (struct g722_data*) codec->codec_data;
394
/* Close codec, if it's not closed. */
395
g722_codec_close(codec);
398
/* Clear left samples in the PLC, since codec+plc will be reused
401
for (i=0; i<2; ++i) {
402
pj_int16_t frame[SAMPLES_PER_FRAME];
403
pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
404
pjmedia_plc_save(g722_data->plc, frame);
410
/* Re-init silence_period */
411
pj_set_timestamp32(&g722_data->last_tx, 0, 0);
413
/* Put in the free list. */
414
pj_mutex_lock(g722_codec_factory.mutex);
415
pj_list_push_front(&g722_codec_factory.codec_list, codec);
416
pj_mutex_unlock(g722_codec_factory.mutex);
424
static pj_status_t g722_codec_init(pjmedia_codec *codec,
427
PJ_UNUSED_ARG(codec);
435
static pj_status_t g722_codec_open(pjmedia_codec *codec,
436
pjmedia_codec_param *attr )
438
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
441
PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
442
PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
444
status = g722_enc_init(&g722_data->encoder);
445
if (status != PJ_SUCCESS) {
446
TRACE_((THIS_FILE, "g722_enc_init() failed, status=%d", status));
447
pj_mutex_unlock(g722_codec_factory.mutex);
448
return PJMEDIA_CODEC_EFAILED;
451
status = g722_dec_init(&g722_data->decoder);
452
if (status != PJ_SUCCESS) {
453
TRACE_((THIS_FILE, "g722_dec_init() failed, status=%d", status));
454
pj_mutex_unlock(g722_codec_factory.mutex);
455
return PJMEDIA_CODEC_EFAILED;
458
g722_data->vad_enabled = (attr->setting.vad != 0);
459
g722_data->plc_enabled = (attr->setting.plc != 0);
461
TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
462
g722_data->vad_enabled, g722_data->plc_enabled));
469
static pj_status_t g722_codec_close( pjmedia_codec *codec )
471
/* The codec, encoder, and decoder will be reused, so there's
475
PJ_UNUSED_ARG(codec);
477
TRACE_((THIS_FILE, "G722 codec closed"));
483
* Modify codec settings.
485
static pj_status_t g722_codec_modify(pjmedia_codec *codec,
486
const pjmedia_codec_param *attr )
488
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
490
pj_assert(g722_data != NULL);
492
g722_data->vad_enabled = (attr->setting.vad != 0);
493
g722_data->plc_enabled = (attr->setting.plc != 0);
495
TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
496
g722_data->vad_enabled, g722_data->plc_enabled));
502
* Get frames in the packet.
504
static pj_status_t g722_codec_parse(pjmedia_codec *codec,
507
const pj_timestamp *ts,
509
pjmedia_frame frames[])
513
PJ_UNUSED_ARG(codec);
515
PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
517
TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
519
while (pkt_size >= FRAME_LEN && count < *frame_cnt) {
520
frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
521
frames[count].buf = pkt;
522
frames[count].size = FRAME_LEN;
523
frames[count].timestamp.u64 = ts->u64 + count * SAMPLES_PER_FRAME;
525
pkt = ((char*)pkt) + FRAME_LEN;
526
pkt_size -= FRAME_LEN;
531
TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
540
static pj_status_t g722_codec_encode(pjmedia_codec *codec,
541
const struct pjmedia_frame *input,
542
unsigned output_buf_len,
543
struct pjmedia_frame *output)
545
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
548
pj_assert(g722_data && input && output);
550
PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len,
551
PJMEDIA_CODEC_EFRMTOOSHORT);
554
if (g722_data->vad_enabled) {
555
pj_bool_t is_silence;
556
pj_int32_t silence_duration;
558
silence_duration = pj_timestamp_diff32(&g722_data->last_tx,
561
is_silence = pjmedia_silence_det_detect(g722_data->vad,
562
(const pj_int16_t*) input->buf,
566
(PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
567
silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000))
569
output->type = PJMEDIA_FRAME_TYPE_NONE;
572
output->timestamp = input->timestamp;
575
g722_data->last_tx = input->timestamp;
579
/* Encode to temporary buffer */
580
output->size = output_buf_len;
581
status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf,
582
(input->size >> 1), output->buf, &output->size);
583
if (status != PJ_SUCCESS) {
586
output->type = PJMEDIA_FRAME_TYPE_NONE;
587
TRACE_((THIS_FILE, "G722 encode() status: %d", status));
588
return PJMEDIA_CODEC_EFAILED;
591
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
592
output->timestamp = input->timestamp;
594
TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
601
static pj_status_t g722_codec_decode(pjmedia_codec *codec,
602
const struct pjmedia_frame *input,
603
unsigned output_buf_len,
604
struct pjmedia_frame *output)
606
struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
609
pj_assert(g722_data != NULL);
610
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
612
TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
614
input->buf, input->size, output->buf, output_buf_len));
616
if (output_buf_len < SAMPLES_PER_FRAME * 2) {
617
TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
618
return PJMEDIA_CODEC_EPCMTOOSHORT;
621
if (input->size != FRAME_LEN) {
622
TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
623
return PJMEDIA_CODEC_EFRMTOOSHORT;
628
output->size = SAMPLES_PER_FRAME;
629
status = g722_dec_decode(&g722_data->decoder, input->buf, input->size,
630
(pj_int16_t*)output->buf, &output->size);
631
if (status != PJ_SUCCESS) {
632
TRACE_((THIS_FILE, "G722 decode() status: %d", status));
633
return PJMEDIA_CODEC_EFAILED;
636
pj_assert(output->size == SAMPLES_PER_FRAME);
637
output->size = SAMPLES_PER_FRAME * 2;
638
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
639
output->timestamp = input->timestamp;
642
if (g722_data->plc_enabled)
643
pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
646
TRACE_((THIS_FILE, "G722 decode done"));
653
* Recover lost frame.
655
static pj_status_t g722_codec_recover(pjmedia_codec *codec,
656
unsigned output_buf_len,
657
struct pjmedia_frame *output)
659
struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
661
PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
663
PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
664
PJMEDIA_CODEC_EPCMTOOSHORT);
666
pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
668
output->size = SAMPLES_PER_FRAME * 2;
669
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
675
#endif // PJMEDIA_HAS_G722_CODEC