blob: 5b43a61bb095b981fd848680ef144d71c8c66cdc [file] [log] [blame]
Benny Prijono7ffd7752008-03-17 14:07:53 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono7ffd7752008-03-17 14:07:53 +00005 *
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.
10 *
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.
15 *
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
19 */
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>
28#include <pj/log.h>
29#include <pj/pool.h>
30#include <pj/string.h>
31#include <pj/os.h>
32
33#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
34
35#include "g722/g722_enc.h"
36#include "g722/g722_dec.h"
37
38#define THIS_FILE "g722.c"
39
40/* Defines */
41#define PTIME (20)
42#define SAMPLES_PER_FRAME (16000 * PTIME /1000)
43#define FRAME_LEN (160)
Nanang Izzuddin49a979b2008-09-19 21:10:14 +000044#define PLC_DISABLED 0
Benny Prijono7ffd7752008-03-17 14:07:53 +000045
46/* Tracing */
47#ifndef PJ_TRACE
48# define PJ_TRACE 0
49#endif
50
51#if PJ_TRACE
52# define TRACE_(expr) PJ_LOG(4,expr)
53#else
54# define TRACE_(expr)
55#endif
56
57
58/* Prototypes for G722 factory */
59static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
60 const pjmedia_codec_info *id );
61static pj_status_t g722_default_attr(pjmedia_codec_factory *factory,
62 const pjmedia_codec_info *id,
63 pjmedia_codec_param *attr );
64static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
65 unsigned *count,
66 pjmedia_codec_info codecs[]);
67static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
68 const pjmedia_codec_info *id,
69 pjmedia_codec **p_codec);
70static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
71 pjmedia_codec *codec );
72
73/* Prototypes for G722 implementation. */
74static pj_status_t g722_codec_init(pjmedia_codec *codec,
75 pj_pool_t *pool );
76static pj_status_t g722_codec_open(pjmedia_codec *codec,
77 pjmedia_codec_param *attr );
78static pj_status_t g722_codec_close(pjmedia_codec *codec );
79static pj_status_t g722_codec_modify(pjmedia_codec *codec,
80 const pjmedia_codec_param *attr );
81static pj_status_t g722_codec_parse(pjmedia_codec *codec,
82 void *pkt,
83 pj_size_t pkt_size,
84 const pj_timestamp *ts,
85 unsigned *frame_cnt,
86 pjmedia_frame frames[]);
87static 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);
91static 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);
95#if !PLC_DISABLED
96static pj_status_t g722_codec_recover(pjmedia_codec *codec,
97 unsigned output_buf_len,
98 struct pjmedia_frame *output);
99#endif
100
101/* Definition for G722 codec operations. */
102static pjmedia_codec_op g722_op =
103{
104 &g722_codec_init,
105 &g722_codec_open,
106 &g722_codec_close,
107 &g722_codec_modify,
108 &g722_codec_parse,
109 &g722_codec_encode,
110 &g722_codec_decode,
111#if !PLC_DISABLED
112 &g722_codec_recover
113#else
114 NULL
115#endif
116};
117
118/* Definition for G722 codec factory operations. */
119static pjmedia_codec_factory_op g722_factory_op =
120{
121 &g722_test_alloc,
122 &g722_default_attr,
123 &g722_enum_codecs,
124 &g722_alloc_codec,
125 &g722_dealloc_codec
126};
127
128/* G722 factory */
129static struct g722_codec_factory
130{
131 pjmedia_codec_factory base;
132 pjmedia_endpt *endpt;
133 pj_pool_t *pool;
134 pj_mutex_t *mutex;
135 pjmedia_codec codec_list;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000136 unsigned pcm_shift;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000137} g722_codec_factory;
138
139
140/* G722 codec private data. */
141struct g722_data
142{
143 g722_enc_t encoder;
144 g722_dec_t decoder;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000145 unsigned pcm_shift;
146 pj_int16_t pcm_clip_mask;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000147 pj_bool_t plc_enabled;
148 pj_bool_t vad_enabled;
149 pjmedia_silence_det *vad;
150 pj_timestamp last_tx;
151#if !PLC_DISABLED
152 pjmedia_plc *plc;
153#endif
154};
155
156
157
158/*
159 * Initialize and register G722 codec factory to pjmedia endpoint.
160 */
161PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
162{
163 pjmedia_codec_mgr *codec_mgr;
164 pj_status_t status;
165
166 if (g722_codec_factory.pool != NULL)
167 return PJ_SUCCESS;
168
169 /* Create G722 codec factory. */
170 g722_codec_factory.base.op = &g722_factory_op;
171 g722_codec_factory.base.factory_data = NULL;
172 g722_codec_factory.endpt = endpt;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000173 g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000174
175 g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000,
176 1000);
177 if (!g722_codec_factory.pool)
178 return PJ_ENOMEM;
179
180 pj_list_init(&g722_codec_factory.codec_list);
181
182 /* Create mutex. */
183 status = pj_mutex_create_simple(g722_codec_factory.pool, "g722",
184 &g722_codec_factory.mutex);
185 if (status != PJ_SUCCESS)
186 goto on_error;
187
188 /* Get the codec manager. */
189 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
190 if (!codec_mgr) {
191 status = PJ_EINVALIDOP;
192 goto on_error;
193 }
194
195 /* Register codec factory to endpoint. */
196 status = pjmedia_codec_mgr_register_factory(codec_mgr,
197 &g722_codec_factory.base);
198 if (status != PJ_SUCCESS)
199 goto on_error;
200
201 TRACE_((THIS_FILE, "G722 codec factory initialized"));
202
203 /* Done. */
204 return PJ_SUCCESS;
205
206on_error:
207 pj_pool_release(g722_codec_factory.pool);
208 g722_codec_factory.pool = NULL;
209 return status;
210}
211
212/*
213 * Unregister G722 codec factory from pjmedia endpoint and deinitialize
214 * the G722 codec library.
215 */
216PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
217{
218 pjmedia_codec_mgr *codec_mgr;
219 pj_status_t status;
220
221 if (g722_codec_factory.pool == NULL)
222 return PJ_SUCCESS;
223
224 /* Get the codec manager. */
225 codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
226 if (!codec_mgr) {
227 pj_pool_release(g722_codec_factory.pool);
228 g722_codec_factory.pool = NULL;
229 return PJ_EINVALIDOP;
230 }
231
232 /* Unregister G722 codec factory. */
233 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
234 &g722_codec_factory.base);
235
236 /* Destroy mutex. */
237 pj_mutex_destroy(g722_codec_factory.mutex);
238
239 /* Destroy pool. */
240 pj_pool_release(g722_codec_factory.pool);
241 g722_codec_factory.pool = NULL;
242
243 TRACE_((THIS_FILE, "G722 codec factory shutdown"));
244 return status;
245}
246
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000247
248/*
249 * Set level adjustment.
250 */
251PJ_DEF(pj_status_t) pjmedia_codec_g722_set_pcm_shift(unsigned val)
252{
253 g722_codec_factory.pcm_shift = val;
254 return PJ_SUCCESS;
255}
256
257
Benny Prijono7ffd7752008-03-17 14:07:53 +0000258/*
259 * Check if factory can allocate the specified codec.
260 */
261static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
262 const pjmedia_codec_info *info )
263{
264 PJ_UNUSED_ARG(factory);
265
266 /* Check payload type. */
267 if (info->pt != PJMEDIA_RTP_PT_G722)
268 return PJMEDIA_CODEC_EUNSUP;
269
270 /* Ignore the rest, since it's static payload type. */
271
272 return PJ_SUCCESS;
273}
274
275/*
276 * Generate default attribute.
277 */
278static pj_status_t g722_default_attr( pjmedia_codec_factory *factory,
279 const pjmedia_codec_info *id,
280 pjmedia_codec_param *attr )
281{
282 PJ_UNUSED_ARG(factory);
283 PJ_UNUSED_ARG(id);
284
285 pj_bzero(attr, sizeof(pjmedia_codec_param));
286 attr->info.clock_rate = 16000;
287 attr->info.channel_cnt = 1;
288 attr->info.avg_bps = 64000;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000289 attr->info.max_bps = 64000;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000290 attr->info.pcm_bits_per_sample = 16;
291 attr->info.frm_ptime = PTIME;
292 attr->info.pt = PJMEDIA_RTP_PT_G722;
293
294 attr->setting.frm_per_pkt = 1;
295 attr->setting.vad = 1;
Nanang Izzuddinb8c1ebe2008-09-19 21:17:30 +0000296 attr->setting.plc = 1;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000297
298 /* Default all other flag bits disabled. */
299
300 return PJ_SUCCESS;
301}
302
303/*
304 * Enum codecs supported by this factory (i.e. only G722!).
305 */
306static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
307 unsigned *count,
308 pjmedia_codec_info codecs[])
309{
310 PJ_UNUSED_ARG(factory);
311 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
312
313 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
314 codecs[0].encoding_name = pj_str("G722");
315 codecs[0].pt = PJMEDIA_RTP_PT_G722;
316 codecs[0].type = PJMEDIA_TYPE_AUDIO;
317 codecs[0].clock_rate = 16000;
318 codecs[0].channel_cnt = 1;
319
320 *count = 1;
321
322 return PJ_SUCCESS;
323}
324
325/*
326 * Allocate a new G722 codec instance.
327 */
328static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
329 const pjmedia_codec_info *id,
330 pjmedia_codec **p_codec)
331{
332 pjmedia_codec *codec;
333 struct g722_data *g722_data;
334
335 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
336 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
337
338 pj_mutex_lock(g722_codec_factory.mutex);
339
340 /* Get free nodes, if any. */
341 if (!pj_list_empty(&g722_codec_factory.codec_list)) {
342 codec = g722_codec_factory.codec_list.next;
343 pj_list_erase(codec);
344 } else {
345 pj_status_t status;
346
347 codec = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, pjmedia_codec);
348 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
349 codec->op = &g722_op;
350 codec->factory = factory;
351
352 g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
353 codec->codec_data = g722_data;
354
355#if !PLC_DISABLED
356 /* Create PLC */
357 status = pjmedia_plc_create(g722_codec_factory.pool, 16000,
358 SAMPLES_PER_FRAME, 0, &g722_data->plc);
359 if (status != PJ_SUCCESS) {
360 pj_mutex_unlock(g722_codec_factory.mutex);
361 return status;
362 }
363#endif
364
365 /* Create silence detector */
366 status = pjmedia_silence_det_create(g722_codec_factory.pool,
367 16000, SAMPLES_PER_FRAME,
368 &g722_data->vad);
369 if (status != PJ_SUCCESS) {
370 pj_mutex_unlock(g722_codec_factory.mutex);
371 TRACE_((THIS_FILE, "Create silence detector failed (status = %d)",
372 status));
373 return status;
374 }
375 }
376
377
378 pj_mutex_unlock(g722_codec_factory.mutex);
379
380 *p_codec = codec;
381 return PJ_SUCCESS;
382}
383
384/*
385 * Free codec.
386 */
387static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
388 pjmedia_codec *codec )
389{
390 struct g722_data *g722_data;
391 int i;
392
393 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
394 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
395
396 g722_data = (struct g722_data*) codec->codec_data;
397
398 /* Close codec, if it's not closed. */
399 g722_codec_close(codec);
400
401#if !PLC_DISABLED
402 /* Clear left samples in the PLC, since codec+plc will be reused
403 * next time.
404 */
405 for (i=0; i<2; ++i) {
406 pj_int16_t frame[SAMPLES_PER_FRAME];
407 pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
408 pjmedia_plc_save(g722_data->plc, frame);
409 }
410#else
411 PJ_UNUSED_ARG(i);
412#endif
413
414 /* Re-init silence_period */
415 pj_set_timestamp32(&g722_data->last_tx, 0, 0);
416
417 /* Put in the free list. */
418 pj_mutex_lock(g722_codec_factory.mutex);
419 pj_list_push_front(&g722_codec_factory.codec_list, codec);
420 pj_mutex_unlock(g722_codec_factory.mutex);
421
422 return PJ_SUCCESS;
423}
424
425/*
426 * Init codec.
427 */
428static pj_status_t g722_codec_init(pjmedia_codec *codec,
429 pj_pool_t *pool )
430{
431 PJ_UNUSED_ARG(codec);
432 PJ_UNUSED_ARG(pool);
433 return PJ_SUCCESS;
434}
435
436/*
437 * Open codec.
438 */
439static pj_status_t g722_codec_open(pjmedia_codec *codec,
440 pjmedia_codec_param *attr )
441{
442 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
443 pj_status_t status;
444
445 PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
446 PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
447
448 status = g722_enc_init(&g722_data->encoder);
449 if (status != PJ_SUCCESS) {
450 TRACE_((THIS_FILE, "g722_enc_init() failed, status=%d", status));
451 pj_mutex_unlock(g722_codec_factory.mutex);
452 return PJMEDIA_CODEC_EFAILED;
453 }
454
455 status = g722_dec_init(&g722_data->decoder);
456 if (status != PJ_SUCCESS) {
457 TRACE_((THIS_FILE, "g722_dec_init() failed, status=%d", status));
458 pj_mutex_unlock(g722_codec_factory.mutex);
459 return PJMEDIA_CODEC_EFAILED;
460 }
461
462 g722_data->vad_enabled = (attr->setting.vad != 0);
463 g722_data->plc_enabled = (attr->setting.plc != 0);
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000464 g722_data->pcm_shift = g722_codec_factory.pcm_shift;
465 g722_data->pcm_clip_mask = (pj_int16_t)(1<<g722_codec_factory.pcm_shift)-1;
466 g722_data->pcm_clip_mask <<= (16-g722_codec_factory.pcm_shift);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000467
468 TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
469 g722_data->vad_enabled, g722_data->plc_enabled));
470 return PJ_SUCCESS;
471}
472
473/*
474 * Close codec.
475 */
476static pj_status_t g722_codec_close( pjmedia_codec *codec )
477{
478 /* The codec, encoder, and decoder will be reused, so there's
479 * nothing to do here
480 */
481
482 PJ_UNUSED_ARG(codec);
483
484 TRACE_((THIS_FILE, "G722 codec closed"));
485 return PJ_SUCCESS;
486}
487
488
489/*
490 * Modify codec settings.
491 */
492static pj_status_t g722_codec_modify(pjmedia_codec *codec,
493 const pjmedia_codec_param *attr )
494{
495 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
496
497 pj_assert(g722_data != NULL);
498
499 g722_data->vad_enabled = (attr->setting.vad != 0);
500 g722_data->plc_enabled = (attr->setting.plc != 0);
501
502 TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
503 g722_data->vad_enabled, g722_data->plc_enabled));
504 return PJ_SUCCESS;
505}
506
507
508/*
509 * Get frames in the packet.
510 */
511static pj_status_t g722_codec_parse(pjmedia_codec *codec,
512 void *pkt,
513 pj_size_t pkt_size,
514 const pj_timestamp *ts,
515 unsigned *frame_cnt,
516 pjmedia_frame frames[])
517{
518 unsigned count = 0;
519
520 PJ_UNUSED_ARG(codec);
521
522 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
523
524 TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
525
526 while (pkt_size >= FRAME_LEN && count < *frame_cnt) {
527 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
528 frames[count].buf = pkt;
529 frames[count].size = FRAME_LEN;
530 frames[count].timestamp.u64 = ts->u64 + count * SAMPLES_PER_FRAME;
531
532 pkt = ((char*)pkt) + FRAME_LEN;
533 pkt_size -= FRAME_LEN;
534
535 ++count;
536 }
537
538 TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
539
540 *frame_cnt = count;
541 return PJ_SUCCESS;
542}
543
544/*
545 * Encode frame.
546 */
547static pj_status_t g722_codec_encode(pjmedia_codec *codec,
548 const struct pjmedia_frame *input,
549 unsigned output_buf_len,
550 struct pjmedia_frame *output)
551{
552 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
553 pj_status_t status;
554
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000555 pj_assert(g722_data && input && output);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000556
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000557 PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len,
558 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000559
560 /* Detect silence */
561 if (g722_data->vad_enabled) {
562 pj_bool_t is_silence;
563 pj_int32_t silence_duration;
564
565 silence_duration = pj_timestamp_diff32(&g722_data->last_tx,
566 &input->timestamp);
567
568 is_silence = pjmedia_silence_det_detect(g722_data->vad,
569 (const pj_int16_t*) input->buf,
570 (input->size >> 1),
571 NULL);
572 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +0000573 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
574 silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000))
Benny Prijono7ffd7752008-03-17 14:07:53 +0000575 {
576 output->type = PJMEDIA_FRAME_TYPE_NONE;
577 output->buf = NULL;
578 output->size = 0;
579 output->timestamp = input->timestamp;
580 return PJ_SUCCESS;
581 } else {
582 g722_data->last_tx = input->timestamp;
583 }
584 }
585
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000586 /* Adjust input signal level from 16-bit to 14-bit */
587 if (g722_data->pcm_shift) {
588 pj_int16_t *p, *end;
589
590 p = (pj_int16_t*)input->buf;
Nanang Izzuddin20c503a2010-08-05 10:41:48 +0000591 end = p + input->size/2;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000592 while (p < end) {
593 *p++ >>= g722_data->pcm_shift;
594 }
595 }
596
Benny Prijono7ffd7752008-03-17 14:07:53 +0000597 /* Encode to temporary buffer */
Nanang Izzuddind4242972008-06-02 14:16:36 +0000598 output->size = output_buf_len;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000599 status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf,
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000600 (input->size >> 1), output->buf, &output->size);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000601 if (status != PJ_SUCCESS) {
602 output->size = 0;
603 output->buf = NULL;
604 output->type = PJMEDIA_FRAME_TYPE_NONE;
605 TRACE_((THIS_FILE, "G722 encode() status: %d", status));
606 return PJMEDIA_CODEC_EFAILED;
607 }
608
609 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000610 output->timestamp = input->timestamp;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000611
612 TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
613 return PJ_SUCCESS;
614}
615
616/*
617 * Decode frame.
618 */
619static pj_status_t g722_codec_decode(pjmedia_codec *codec,
620 const struct pjmedia_frame *input,
621 unsigned output_buf_len,
622 struct pjmedia_frame *output)
623{
624 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
625 pj_status_t status;
626
627 pj_assert(g722_data != NULL);
628 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
629
630 TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
631 "outsize=%d",
632 input->buf, input->size, output->buf, output_buf_len));
633
634 if (output_buf_len < SAMPLES_PER_FRAME * 2) {
635 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
636 return PJMEDIA_CODEC_EPCMTOOSHORT;
637 }
638
639 if (input->size != FRAME_LEN) {
640 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
641 return PJMEDIA_CODEC_EFRMTOOSHORT;
642 }
643
644
645 /* Decode */
646 output->size = SAMPLES_PER_FRAME;
647 status = g722_dec_decode(&g722_data->decoder, input->buf, input->size,
648 (pj_int16_t*)output->buf, &output->size);
649 if (status != PJ_SUCCESS) {
650 TRACE_((THIS_FILE, "G722 decode() status: %d", status));
651 return PJMEDIA_CODEC_EFAILED;
652 }
653
654 pj_assert(output->size == SAMPLES_PER_FRAME);
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000655
656 /* Adjust input signal level from 14-bit to 16-bit */
657 if (g722_data->pcm_shift) {
658 pj_int16_t *p, *end;
659
660 p = (pj_int16_t*)output->buf;
661 end = p + output->size;
662 while (p < end) {
663#if PJMEDIA_G722_STOP_PCM_SHIFT_ON_CLIPPING
664 /* If there is clipping, stop the PCM shifting */
665 if (*p & g722_data->pcm_clip_mask) {
666 g722_data->pcm_shift = 0;
667 break;
668 }
669#endif
670 *p++ <<= g722_data->pcm_shift;
671 }
672 }
673
Benny Prijono7ffd7752008-03-17 14:07:53 +0000674 output->size = SAMPLES_PER_FRAME * 2;
675 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000676 output->timestamp = input->timestamp;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000677
678#if !PLC_DISABLED
679 if (g722_data->plc_enabled)
Benny Prijono20da7992008-12-18 16:48:43 +0000680 pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000681#endif
682
683 TRACE_((THIS_FILE, "G722 decode done"));
684 return PJ_SUCCESS;
685}
686
687
688#if !PLC_DISABLED
689/*
690 * Recover lost frame.
691 */
692static pj_status_t g722_codec_recover(pjmedia_codec *codec,
693 unsigned output_buf_len,
694 struct pjmedia_frame *output)
695{
Benny Prijono20da7992008-12-18 16:48:43 +0000696 struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000697
698 PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
699
700 PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
701 PJMEDIA_CODEC_EPCMTOOSHORT);
702
Benny Prijono20da7992008-12-18 16:48:43 +0000703 pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000704
705 output->size = SAMPLES_PER_FRAME * 2;
706 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
707
708 return PJ_SUCCESS;
709}
710#endif
711
712#endif // PJMEDIA_HAS_G722_CODEC
713