blob: acddc14208b23e0255a170d8225144dcb75634e6 [file] [log] [blame]
Benny Prijono7ffd7752008-03-17 14:07:53 +00001/* $Id$ */
2/*
Nanang Izzuddina62ffc92011-05-05 06:14:19 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Benny Prijono844653c2008-12-23 17:27:53 +00004 * 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 */
Nanang Izzuddind8cc3e72011-02-18 09:34:28 +000041#define PTIME (10)
Benny Prijono7ffd7752008-03-17 14:07:53 +000042#define SAMPLES_PER_FRAME (16000 * PTIME /1000)
Nanang Izzuddind8cc3e72011-02-18 09:34:28 +000043#define FRAME_LEN (80)
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,
Benny Prijono35fc1eb2011-07-15 09:51:46 +0000125 &g722_dealloc_codec,
126 &pjmedia_codec_g722_deinit
Benny Prijono7ffd7752008-03-17 14:07:53 +0000127};
128
129/* G722 factory */
130static struct g722_codec_factory
131{
132 pjmedia_codec_factory base;
133 pjmedia_endpt *endpt;
134 pj_pool_t *pool;
135 pj_mutex_t *mutex;
136 pjmedia_codec codec_list;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000137 unsigned pcm_shift;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000138} g722_codec_factory;
139
140
141/* G722 codec private data. */
142struct g722_data
143{
144 g722_enc_t encoder;
145 g722_dec_t decoder;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000146 unsigned pcm_shift;
147 pj_int16_t pcm_clip_mask;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000148 pj_bool_t plc_enabled;
149 pj_bool_t vad_enabled;
150 pjmedia_silence_det *vad;
151 pj_timestamp last_tx;
152#if !PLC_DISABLED
153 pjmedia_plc *plc;
154#endif
155};
156
157
158
159/*
160 * Initialize and register G722 codec factory to pjmedia endpoint.
161 */
162PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
163{
164 pjmedia_codec_mgr *codec_mgr;
165 pj_status_t status;
166
167 if (g722_codec_factory.pool != NULL)
168 return PJ_SUCCESS;
169
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;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000174 g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000175
176 g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000,
177 1000);
178 if (!g722_codec_factory.pool)
179 return PJ_ENOMEM;
180
181 pj_list_init(&g722_codec_factory.codec_list);
182
183 /* Create mutex. */
184 status = pj_mutex_create_simple(g722_codec_factory.pool, "g722",
185 &g722_codec_factory.mutex);
186 if (status != PJ_SUCCESS)
187 goto on_error;
188
189 /* Get the codec manager. */
190 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
191 if (!codec_mgr) {
192 status = PJ_EINVALIDOP;
193 goto on_error;
194 }
195
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)
200 goto on_error;
201
202 TRACE_((THIS_FILE, "G722 codec factory initialized"));
203
204 /* Done. */
205 return PJ_SUCCESS;
206
207on_error:
208 pj_pool_release(g722_codec_factory.pool);
209 g722_codec_factory.pool = NULL;
210 return status;
211}
212
213/*
214 * Unregister G722 codec factory from pjmedia endpoint and deinitialize
215 * the G722 codec library.
216 */
217PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
218{
219 pjmedia_codec_mgr *codec_mgr;
220 pj_status_t status;
221
222 if (g722_codec_factory.pool == NULL)
223 return PJ_SUCCESS;
224
225 /* Get the codec manager. */
226 codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
227 if (!codec_mgr) {
228 pj_pool_release(g722_codec_factory.pool);
229 g722_codec_factory.pool = NULL;
230 return PJ_EINVALIDOP;
231 }
232
233 /* Unregister G722 codec factory. */
234 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
235 &g722_codec_factory.base);
236
237 /* Destroy mutex. */
238 pj_mutex_destroy(g722_codec_factory.mutex);
239
240 /* Destroy pool. */
241 pj_pool_release(g722_codec_factory.pool);
242 g722_codec_factory.pool = NULL;
243
244 TRACE_((THIS_FILE, "G722 codec factory shutdown"));
245 return status;
246}
247
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000248
249/*
250 * Set level adjustment.
251 */
252PJ_DEF(pj_status_t) pjmedia_codec_g722_set_pcm_shift(unsigned val)
253{
254 g722_codec_factory.pcm_shift = val;
255 return PJ_SUCCESS;
256}
257
258
Benny Prijono7ffd7752008-03-17 14:07:53 +0000259/*
260 * Check if factory can allocate the specified codec.
261 */
262static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
263 const pjmedia_codec_info *info )
264{
265 PJ_UNUSED_ARG(factory);
266
267 /* Check payload type. */
268 if (info->pt != PJMEDIA_RTP_PT_G722)
269 return PJMEDIA_CODEC_EUNSUP;
270
271 /* Ignore the rest, since it's static payload type. */
272
273 return PJ_SUCCESS;
274}
275
276/*
277 * Generate default attribute.
278 */
279static pj_status_t g722_default_attr( pjmedia_codec_factory *factory,
280 const pjmedia_codec_info *id,
281 pjmedia_codec_param *attr )
282{
283 PJ_UNUSED_ARG(factory);
284 PJ_UNUSED_ARG(id);
285
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;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000290 attr->info.max_bps = 64000;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000291 attr->info.pcm_bits_per_sample = 16;
292 attr->info.frm_ptime = PTIME;
293 attr->info.pt = PJMEDIA_RTP_PT_G722;
294
Nanang Izzuddind8cc3e72011-02-18 09:34:28 +0000295 attr->setting.frm_per_pkt = 2;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000296 attr->setting.vad = 1;
Nanang Izzuddinb8c1ebe2008-09-19 21:17:30 +0000297 attr->setting.plc = 1;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000298
299 /* Default all other flag bits disabled. */
300
301 return PJ_SUCCESS;
302}
303
304/*
305 * Enum codecs supported by this factory (i.e. only G722!).
306 */
307static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
308 unsigned *count,
309 pjmedia_codec_info codecs[])
310{
311 PJ_UNUSED_ARG(factory);
312 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
313
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;
320
321 *count = 1;
322
323 return PJ_SUCCESS;
324}
325
326/*
327 * Allocate a new G722 codec instance.
328 */
329static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
330 const pjmedia_codec_info *id,
331 pjmedia_codec **p_codec)
332{
333 pjmedia_codec *codec;
334 struct g722_data *g722_data;
335
336 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
337 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
338
339 pj_mutex_lock(g722_codec_factory.mutex);
340
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);
345 } else {
346 pj_status_t status;
347
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;
352
353 g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
354 codec->codec_data = g722_data;
355
356#if !PLC_DISABLED
357 /* Create PLC */
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);
362 return status;
363 }
364#endif
365
366 /* Create silence detector */
367 status = pjmedia_silence_det_create(g722_codec_factory.pool,
368 16000, SAMPLES_PER_FRAME,
369 &g722_data->vad);
370 if (status != PJ_SUCCESS) {
371 pj_mutex_unlock(g722_codec_factory.mutex);
372 TRACE_((THIS_FILE, "Create silence detector failed (status = %d)",
373 status));
374 return status;
375 }
376 }
377
378
379 pj_mutex_unlock(g722_codec_factory.mutex);
380
381 *p_codec = codec;
382 return PJ_SUCCESS;
383}
384
385/*
386 * Free codec.
387 */
388static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
389 pjmedia_codec *codec )
390{
391 struct g722_data *g722_data;
392 int i;
393
394 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
395 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
396
397 g722_data = (struct g722_data*) codec->codec_data;
398
399 /* Close codec, if it's not closed. */
400 g722_codec_close(codec);
401
402#if !PLC_DISABLED
403 /* Clear left samples in the PLC, since codec+plc will be reused
404 * next time.
405 */
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);
410 }
411#else
412 PJ_UNUSED_ARG(i);
413#endif
414
415 /* Re-init silence_period */
416 pj_set_timestamp32(&g722_data->last_tx, 0, 0);
417
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);
422
423 return PJ_SUCCESS;
424}
425
426/*
427 * Init codec.
428 */
429static pj_status_t g722_codec_init(pjmedia_codec *codec,
430 pj_pool_t *pool )
431{
432 PJ_UNUSED_ARG(codec);
433 PJ_UNUSED_ARG(pool);
434 return PJ_SUCCESS;
435}
436
437/*
438 * Open codec.
439 */
440static pj_status_t g722_codec_open(pjmedia_codec *codec,
441 pjmedia_codec_param *attr )
442{
443 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
444 pj_status_t status;
445
446 PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
447 PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
448
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;
454 }
455
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;
461 }
462
463 g722_data->vad_enabled = (attr->setting.vad != 0);
464 g722_data->plc_enabled = (attr->setting.plc != 0);
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000465 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);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000468
469 TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
470 g722_data->vad_enabled, g722_data->plc_enabled));
471 return PJ_SUCCESS;
472}
473
474/*
475 * Close codec.
476 */
477static pj_status_t g722_codec_close( pjmedia_codec *codec )
478{
479 /* The codec, encoder, and decoder will be reused, so there's
480 * nothing to do here
481 */
482
483 PJ_UNUSED_ARG(codec);
484
485 TRACE_((THIS_FILE, "G722 codec closed"));
486 return PJ_SUCCESS;
487}
488
489
490/*
491 * Modify codec settings.
492 */
493static pj_status_t g722_codec_modify(pjmedia_codec *codec,
494 const pjmedia_codec_param *attr )
495{
496 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
497
498 pj_assert(g722_data != NULL);
499
500 g722_data->vad_enabled = (attr->setting.vad != 0);
501 g722_data->plc_enabled = (attr->setting.plc != 0);
502
503 TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
504 g722_data->vad_enabled, g722_data->plc_enabled));
505 return PJ_SUCCESS;
506}
507
508
509/*
510 * Get frames in the packet.
511 */
512static pj_status_t g722_codec_parse(pjmedia_codec *codec,
513 void *pkt,
514 pj_size_t pkt_size,
515 const pj_timestamp *ts,
516 unsigned *frame_cnt,
517 pjmedia_frame frames[])
518{
519 unsigned count = 0;
520
521 PJ_UNUSED_ARG(codec);
522
523 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
524
525 TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
526
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;
532
533 pkt = ((char*)pkt) + FRAME_LEN;
534 pkt_size -= FRAME_LEN;
535
536 ++count;
537 }
538
539 TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
540
541 *frame_cnt = count;
542 return PJ_SUCCESS;
543}
544
545/*
546 * Encode frame.
547 */
548static 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)
552{
553 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
554 pj_status_t status;
555
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000556 pj_assert(g722_data && input && output);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000557
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000558 PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len,
559 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000560
561 /* Detect silence */
562 if (g722_data->vad_enabled) {
563 pj_bool_t is_silence;
564 pj_int32_t silence_duration;
565
566 silence_duration = pj_timestamp_diff32(&g722_data->last_tx,
567 &input->timestamp);
568
569 is_silence = pjmedia_silence_det_detect(g722_data->vad,
570 (const pj_int16_t*) input->buf,
571 (input->size >> 1),
572 NULL);
573 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +0000574 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
575 silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000))
Benny Prijono7ffd7752008-03-17 14:07:53 +0000576 {
577 output->type = PJMEDIA_FRAME_TYPE_NONE;
578 output->buf = NULL;
579 output->size = 0;
580 output->timestamp = input->timestamp;
581 return PJ_SUCCESS;
582 } else {
583 g722_data->last_tx = input->timestamp;
584 }
585 }
586
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000587 /* Adjust input signal level from 16-bit to 14-bit */
588 if (g722_data->pcm_shift) {
589 pj_int16_t *p, *end;
590
591 p = (pj_int16_t*)input->buf;
Nanang Izzuddin20c503a2010-08-05 10:41:48 +0000592 end = p + input->size/2;
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000593 while (p < end) {
594 *p++ >>= g722_data->pcm_shift;
595 }
596 }
597
Benny Prijono7ffd7752008-03-17 14:07:53 +0000598 /* Encode to temporary buffer */
Nanang Izzuddind4242972008-06-02 14:16:36 +0000599 output->size = output_buf_len;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000600 status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf,
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000601 (input->size >> 1), output->buf, &output->size);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000602 if (status != PJ_SUCCESS) {
603 output->size = 0;
604 output->buf = NULL;
605 output->type = PJMEDIA_FRAME_TYPE_NONE;
606 TRACE_((THIS_FILE, "G722 encode() status: %d", status));
607 return PJMEDIA_CODEC_EFAILED;
608 }
609
610 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000611 output->timestamp = input->timestamp;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000612
613 TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
614 return PJ_SUCCESS;
615}
616
617/*
618 * Decode frame.
619 */
620static 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)
624{
625 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
626 pj_status_t status;
627
628 pj_assert(g722_data != NULL);
629 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
630
631 TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
632 "outsize=%d",
633 input->buf, input->size, output->buf, output_buf_len));
634
635 if (output_buf_len < SAMPLES_PER_FRAME * 2) {
636 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
637 return PJMEDIA_CODEC_EPCMTOOSHORT;
638 }
639
640 if (input->size != FRAME_LEN) {
641 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
642 return PJMEDIA_CODEC_EFRMTOOSHORT;
643 }
644
645
646 /* Decode */
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;
653 }
654
655 pj_assert(output->size == SAMPLES_PER_FRAME);
Nanang Izzuddinc742f4e2010-06-11 13:38:42 +0000656
657 /* Adjust input signal level from 14-bit to 16-bit */
658 if (g722_data->pcm_shift) {
659 pj_int16_t *p, *end;
660
661 p = (pj_int16_t*)output->buf;
662 end = p + output->size;
663 while (p < end) {
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;
668 break;
669 }
670#endif
671 *p++ <<= g722_data->pcm_shift;
672 }
673 }
674
Benny Prijono7ffd7752008-03-17 14:07:53 +0000675 output->size = SAMPLES_PER_FRAME * 2;
676 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000677 output->timestamp = input->timestamp;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000678
679#if !PLC_DISABLED
680 if (g722_data->plc_enabled)
Benny Prijono20da7992008-12-18 16:48:43 +0000681 pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000682#endif
683
684 TRACE_((THIS_FILE, "G722 decode done"));
685 return PJ_SUCCESS;
686}
687
688
689#if !PLC_DISABLED
690/*
691 * Recover lost frame.
692 */
693static pj_status_t g722_codec_recover(pjmedia_codec *codec,
694 unsigned output_buf_len,
695 struct pjmedia_frame *output)
696{
Benny Prijono20da7992008-12-18 16:48:43 +0000697 struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000698
699 PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
700
701 PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
702 PJMEDIA_CODEC_EPCMTOOSHORT);
703
Benny Prijono20da7992008-12-18 16:48:43 +0000704 pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000705
706 output->size = SAMPLES_PER_FRAME * 2;
707 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
708
709 return PJ_SUCCESS;
710}
711#endif
712
713#endif // PJMEDIA_HAS_G722_CODEC
714