blob: 9449fa6127363d354c394fa470bc8f3cd7ac73a6 [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;
136} g722_codec_factory;
137
138
139/* G722 codec private data. */
140struct g722_data
141{
142 g722_enc_t encoder;
143 g722_dec_t decoder;
144 pj_bool_t plc_enabled;
145 pj_bool_t vad_enabled;
146 pjmedia_silence_det *vad;
147 pj_timestamp last_tx;
148#if !PLC_DISABLED
149 pjmedia_plc *plc;
150#endif
151};
152
153
154
155/*
156 * Initialize and register G722 codec factory to pjmedia endpoint.
157 */
158PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
159{
160 pjmedia_codec_mgr *codec_mgr;
161 pj_status_t status;
162
163 if (g722_codec_factory.pool != NULL)
164 return PJ_SUCCESS;
165
166 /* Create G722 codec factory. */
167 g722_codec_factory.base.op = &g722_factory_op;
168 g722_codec_factory.base.factory_data = NULL;
169 g722_codec_factory.endpt = endpt;
170
171 g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000,
172 1000);
173 if (!g722_codec_factory.pool)
174 return PJ_ENOMEM;
175
176 pj_list_init(&g722_codec_factory.codec_list);
177
178 /* Create mutex. */
179 status = pj_mutex_create_simple(g722_codec_factory.pool, "g722",
180 &g722_codec_factory.mutex);
181 if (status != PJ_SUCCESS)
182 goto on_error;
183
184 /* Get the codec manager. */
185 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
186 if (!codec_mgr) {
187 status = PJ_EINVALIDOP;
188 goto on_error;
189 }
190
191 /* Register codec factory to endpoint. */
192 status = pjmedia_codec_mgr_register_factory(codec_mgr,
193 &g722_codec_factory.base);
194 if (status != PJ_SUCCESS)
195 goto on_error;
196
197 TRACE_((THIS_FILE, "G722 codec factory initialized"));
198
199 /* Done. */
200 return PJ_SUCCESS;
201
202on_error:
203 pj_pool_release(g722_codec_factory.pool);
204 g722_codec_factory.pool = NULL;
205 return status;
206}
207
208/*
209 * Unregister G722 codec factory from pjmedia endpoint and deinitialize
210 * the G722 codec library.
211 */
212PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
213{
214 pjmedia_codec_mgr *codec_mgr;
215 pj_status_t status;
216
217 if (g722_codec_factory.pool == NULL)
218 return PJ_SUCCESS;
219
220 /* Get the codec manager. */
221 codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
222 if (!codec_mgr) {
223 pj_pool_release(g722_codec_factory.pool);
224 g722_codec_factory.pool = NULL;
225 return PJ_EINVALIDOP;
226 }
227
228 /* Unregister G722 codec factory. */
229 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
230 &g722_codec_factory.base);
231
232 /* Destroy mutex. */
233 pj_mutex_destroy(g722_codec_factory.mutex);
234
235 /* Destroy pool. */
236 pj_pool_release(g722_codec_factory.pool);
237 g722_codec_factory.pool = NULL;
238
239 TRACE_((THIS_FILE, "G722 codec factory shutdown"));
240 return status;
241}
242
243/*
244 * Check if factory can allocate the specified codec.
245 */
246static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory,
247 const pjmedia_codec_info *info )
248{
249 PJ_UNUSED_ARG(factory);
250
251 /* Check payload type. */
252 if (info->pt != PJMEDIA_RTP_PT_G722)
253 return PJMEDIA_CODEC_EUNSUP;
254
255 /* Ignore the rest, since it's static payload type. */
256
257 return PJ_SUCCESS;
258}
259
260/*
261 * Generate default attribute.
262 */
263static pj_status_t g722_default_attr( pjmedia_codec_factory *factory,
264 const pjmedia_codec_info *id,
265 pjmedia_codec_param *attr )
266{
267 PJ_UNUSED_ARG(factory);
268 PJ_UNUSED_ARG(id);
269
270 pj_bzero(attr, sizeof(pjmedia_codec_param));
271 attr->info.clock_rate = 16000;
272 attr->info.channel_cnt = 1;
273 attr->info.avg_bps = 64000;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000274 attr->info.max_bps = 64000;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000275 attr->info.pcm_bits_per_sample = 16;
276 attr->info.frm_ptime = PTIME;
277 attr->info.pt = PJMEDIA_RTP_PT_G722;
278
279 attr->setting.frm_per_pkt = 1;
280 attr->setting.vad = 1;
Nanang Izzuddinb8c1ebe2008-09-19 21:17:30 +0000281 attr->setting.plc = 1;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000282
283 /* Default all other flag bits disabled. */
284
285 return PJ_SUCCESS;
286}
287
288/*
289 * Enum codecs supported by this factory (i.e. only G722!).
290 */
291static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory,
292 unsigned *count,
293 pjmedia_codec_info codecs[])
294{
295 PJ_UNUSED_ARG(factory);
296 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
297
298 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
299 codecs[0].encoding_name = pj_str("G722");
300 codecs[0].pt = PJMEDIA_RTP_PT_G722;
301 codecs[0].type = PJMEDIA_TYPE_AUDIO;
302 codecs[0].clock_rate = 16000;
303 codecs[0].channel_cnt = 1;
304
305 *count = 1;
306
307 return PJ_SUCCESS;
308}
309
310/*
311 * Allocate a new G722 codec instance.
312 */
313static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory,
314 const pjmedia_codec_info *id,
315 pjmedia_codec **p_codec)
316{
317 pjmedia_codec *codec;
318 struct g722_data *g722_data;
319
320 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
321 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
322
323 pj_mutex_lock(g722_codec_factory.mutex);
324
325 /* Get free nodes, if any. */
326 if (!pj_list_empty(&g722_codec_factory.codec_list)) {
327 codec = g722_codec_factory.codec_list.next;
328 pj_list_erase(codec);
329 } else {
330 pj_status_t status;
331
332 codec = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, pjmedia_codec);
333 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
334 codec->op = &g722_op;
335 codec->factory = factory;
336
337 g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
338 codec->codec_data = g722_data;
339
340#if !PLC_DISABLED
341 /* Create PLC */
342 status = pjmedia_plc_create(g722_codec_factory.pool, 16000,
343 SAMPLES_PER_FRAME, 0, &g722_data->plc);
344 if (status != PJ_SUCCESS) {
345 pj_mutex_unlock(g722_codec_factory.mutex);
346 return status;
347 }
348#endif
349
350 /* Create silence detector */
351 status = pjmedia_silence_det_create(g722_codec_factory.pool,
352 16000, SAMPLES_PER_FRAME,
353 &g722_data->vad);
354 if (status != PJ_SUCCESS) {
355 pj_mutex_unlock(g722_codec_factory.mutex);
356 TRACE_((THIS_FILE, "Create silence detector failed (status = %d)",
357 status));
358 return status;
359 }
360 }
361
362
363 pj_mutex_unlock(g722_codec_factory.mutex);
364
365 *p_codec = codec;
366 return PJ_SUCCESS;
367}
368
369/*
370 * Free codec.
371 */
372static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory,
373 pjmedia_codec *codec )
374{
375 struct g722_data *g722_data;
376 int i;
377
378 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
379 PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
380
381 g722_data = (struct g722_data*) codec->codec_data;
382
383 /* Close codec, if it's not closed. */
384 g722_codec_close(codec);
385
386#if !PLC_DISABLED
387 /* Clear left samples in the PLC, since codec+plc will be reused
388 * next time.
389 */
390 for (i=0; i<2; ++i) {
391 pj_int16_t frame[SAMPLES_PER_FRAME];
392 pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
393 pjmedia_plc_save(g722_data->plc, frame);
394 }
395#else
396 PJ_UNUSED_ARG(i);
397#endif
398
399 /* Re-init silence_period */
400 pj_set_timestamp32(&g722_data->last_tx, 0, 0);
401
402 /* Put in the free list. */
403 pj_mutex_lock(g722_codec_factory.mutex);
404 pj_list_push_front(&g722_codec_factory.codec_list, codec);
405 pj_mutex_unlock(g722_codec_factory.mutex);
406
407 return PJ_SUCCESS;
408}
409
410/*
411 * Init codec.
412 */
413static pj_status_t g722_codec_init(pjmedia_codec *codec,
414 pj_pool_t *pool )
415{
416 PJ_UNUSED_ARG(codec);
417 PJ_UNUSED_ARG(pool);
418 return PJ_SUCCESS;
419}
420
421/*
422 * Open codec.
423 */
424static pj_status_t g722_codec_open(pjmedia_codec *codec,
425 pjmedia_codec_param *attr )
426{
427 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
428 pj_status_t status;
429
430 PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
431 PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
432
433 status = g722_enc_init(&g722_data->encoder);
434 if (status != PJ_SUCCESS) {
435 TRACE_((THIS_FILE, "g722_enc_init() failed, status=%d", status));
436 pj_mutex_unlock(g722_codec_factory.mutex);
437 return PJMEDIA_CODEC_EFAILED;
438 }
439
440 status = g722_dec_init(&g722_data->decoder);
441 if (status != PJ_SUCCESS) {
442 TRACE_((THIS_FILE, "g722_dec_init() failed, status=%d", status));
443 pj_mutex_unlock(g722_codec_factory.mutex);
444 return PJMEDIA_CODEC_EFAILED;
445 }
446
447 g722_data->vad_enabled = (attr->setting.vad != 0);
448 g722_data->plc_enabled = (attr->setting.plc != 0);
449
450 TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
451 g722_data->vad_enabled, g722_data->plc_enabled));
452 return PJ_SUCCESS;
453}
454
455/*
456 * Close codec.
457 */
458static pj_status_t g722_codec_close( pjmedia_codec *codec )
459{
460 /* The codec, encoder, and decoder will be reused, so there's
461 * nothing to do here
462 */
463
464 PJ_UNUSED_ARG(codec);
465
466 TRACE_((THIS_FILE, "G722 codec closed"));
467 return PJ_SUCCESS;
468}
469
470
471/*
472 * Modify codec settings.
473 */
474static pj_status_t g722_codec_modify(pjmedia_codec *codec,
475 const pjmedia_codec_param *attr )
476{
477 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
478
479 pj_assert(g722_data != NULL);
480
481 g722_data->vad_enabled = (attr->setting.vad != 0);
482 g722_data->plc_enabled = (attr->setting.plc != 0);
483
484 TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
485 g722_data->vad_enabled, g722_data->plc_enabled));
486 return PJ_SUCCESS;
487}
488
489
490/*
491 * Get frames in the packet.
492 */
493static pj_status_t g722_codec_parse(pjmedia_codec *codec,
494 void *pkt,
495 pj_size_t pkt_size,
496 const pj_timestamp *ts,
497 unsigned *frame_cnt,
498 pjmedia_frame frames[])
499{
500 unsigned count = 0;
501
502 PJ_UNUSED_ARG(codec);
503
504 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
505
506 TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
507
508 while (pkt_size >= FRAME_LEN && count < *frame_cnt) {
509 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
510 frames[count].buf = pkt;
511 frames[count].size = FRAME_LEN;
512 frames[count].timestamp.u64 = ts->u64 + count * SAMPLES_PER_FRAME;
513
514 pkt = ((char*)pkt) + FRAME_LEN;
515 pkt_size -= FRAME_LEN;
516
517 ++count;
518 }
519
520 TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
521
522 *frame_cnt = count;
523 return PJ_SUCCESS;
524}
525
526/*
527 * Encode frame.
528 */
529static pj_status_t g722_codec_encode(pjmedia_codec *codec,
530 const struct pjmedia_frame *input,
531 unsigned output_buf_len,
532 struct pjmedia_frame *output)
533{
534 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
535 pj_status_t status;
536
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000537 pj_assert(g722_data && input && output);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000538
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000539 PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len,
540 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000541
542 /* Detect silence */
543 if (g722_data->vad_enabled) {
544 pj_bool_t is_silence;
545 pj_int32_t silence_duration;
546
547 silence_duration = pj_timestamp_diff32(&g722_data->last_tx,
548 &input->timestamp);
549
550 is_silence = pjmedia_silence_det_detect(g722_data->vad,
551 (const pj_int16_t*) input->buf,
552 (input->size >> 1),
553 NULL);
554 if (is_silence &&
555 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonodd3d0022008-06-14 16:52:04 +0000556 silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000)
Benny Prijono7ffd7752008-03-17 14:07:53 +0000557 {
558 output->type = PJMEDIA_FRAME_TYPE_NONE;
559 output->buf = NULL;
560 output->size = 0;
561 output->timestamp = input->timestamp;
562 return PJ_SUCCESS;
563 } else {
564 g722_data->last_tx = input->timestamp;
565 }
566 }
567
568 /* Encode to temporary buffer */
Nanang Izzuddind4242972008-06-02 14:16:36 +0000569 output->size = output_buf_len;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000570 status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf,
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000571 (input->size >> 1), output->buf, &output->size);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000572 if (status != PJ_SUCCESS) {
573 output->size = 0;
574 output->buf = NULL;
575 output->type = PJMEDIA_FRAME_TYPE_NONE;
576 TRACE_((THIS_FILE, "G722 encode() status: %d", status));
577 return PJMEDIA_CODEC_EFAILED;
578 }
579
580 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
581
582 TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
583 return PJ_SUCCESS;
584}
585
586/*
587 * Decode frame.
588 */
589static pj_status_t g722_codec_decode(pjmedia_codec *codec,
590 const struct pjmedia_frame *input,
591 unsigned output_buf_len,
592 struct pjmedia_frame *output)
593{
594 struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
595 pj_status_t status;
596
597 pj_assert(g722_data != NULL);
598 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
599
600 TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
601 "outsize=%d",
602 input->buf, input->size, output->buf, output_buf_len));
603
604 if (output_buf_len < SAMPLES_PER_FRAME * 2) {
605 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
606 return PJMEDIA_CODEC_EPCMTOOSHORT;
607 }
608
609 if (input->size != FRAME_LEN) {
610 TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
611 return PJMEDIA_CODEC_EFRMTOOSHORT;
612 }
613
614
615 /* Decode */
616 output->size = SAMPLES_PER_FRAME;
617 status = g722_dec_decode(&g722_data->decoder, input->buf, input->size,
618 (pj_int16_t*)output->buf, &output->size);
619 if (status != PJ_SUCCESS) {
620 TRACE_((THIS_FILE, "G722 decode() status: %d", status));
621 return PJMEDIA_CODEC_EFAILED;
622 }
623
624 pj_assert(output->size == SAMPLES_PER_FRAME);
625 output->size = SAMPLES_PER_FRAME * 2;
626 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
627
628#if !PLC_DISABLED
629 if (g722_data->plc_enabled)
Benny Prijono20da7992008-12-18 16:48:43 +0000630 pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000631#endif
632
633 TRACE_((THIS_FILE, "G722 decode done"));
634 return PJ_SUCCESS;
635}
636
637
638#if !PLC_DISABLED
639/*
640 * Recover lost frame.
641 */
642static pj_status_t g722_codec_recover(pjmedia_codec *codec,
643 unsigned output_buf_len,
644 struct pjmedia_frame *output)
645{
Benny Prijono20da7992008-12-18 16:48:43 +0000646 struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
Benny Prijono7ffd7752008-03-17 14:07:53 +0000647
648 PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
649
650 PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2,
651 PJMEDIA_CODEC_EPCMTOOSHORT);
652
Benny Prijono20da7992008-12-18 16:48:43 +0000653 pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
Benny Prijono7ffd7752008-03-17 14:07:53 +0000654
655 output->size = SAMPLES_PER_FRAME * 2;
656 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
657
658 return PJ_SUCCESS;
659}
660#endif
661
662#endif // PJMEDIA_HAS_G722_CODEC
663