blob: 99ad54ef8eb8ce0a23a47286227c738130efe96f [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2011-2013 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2011 Dan Arrhenius <dan@keystream.se>
5 *
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
21/*
22 * AMR codec implementation with OpenCORE AMR library
23 */
24#include <pjmedia-codec/g722.h>
25#include <pjmedia-codec/amr_sdp_match.h>
26#include <pjmedia/codec.h>
27#include <pjmedia/errno.h>
28#include <pjmedia/endpoint.h>
29#include <pjmedia/plc.h>
30#include <pjmedia/port.h>
31#include <pjmedia/silencedet.h>
32#include <pj/assert.h>
33#include <pj/log.h>
34#include <pj/pool.h>
35#include <pj/string.h>
36#include <pj/os.h>
37#include <pj/math.h>
38
39#if defined(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC) && \
40 (PJMEDIA_HAS_OPENCORE_AMRNB_CODEC != 0)
41#define USE_AMRNB
42#endif
43
44#if defined(PJMEDIA_HAS_OPENCORE_AMRWB_CODEC) && \
45 (PJMEDIA_HAS_OPENCORE_AMRWB_CODEC != 0)
46#define USE_AMRWB
47#endif
48
49#if defined(USE_AMRNB) || defined(USE_AMRWB)
50
51#ifdef USE_AMRNB
52#include <opencore-amrnb/interf_enc.h>
53#include <opencore-amrnb/interf_dec.h>
54#endif
55
56#ifdef USE_AMRWB
57#include <vo-amrwbenc/enc_if.h>
58#include <opencore-amrwb/dec_if.h>
59#endif
60
61#include <pjmedia-codec/amr_helper.h>
62#include <pjmedia-codec/opencore_amr.h>
63
64#define THIS_FILE "opencore_amr.c"
65
66/* Tracing */
67#define PJ_TRACE 0
68
69#if PJ_TRACE
70# define TRACE_(expr) PJ_LOG(4,expr)
71#else
72# define TRACE_(expr)
73#endif
74
75/* Use PJMEDIA PLC */
76#define USE_PJMEDIA_PLC 1
77
78#define FRAME_LENGTH_MS 20
79
80
81/* Prototypes for AMR factory */
82static pj_status_t amr_test_alloc(pjmedia_codec_factory *factory,
83 const pjmedia_codec_info *id );
84static pj_status_t amr_default_attr(pjmedia_codec_factory *factory,
85 const pjmedia_codec_info *id,
86 pjmedia_codec_param *attr );
87static pj_status_t amr_enum_codecs(pjmedia_codec_factory *factory,
88 unsigned *count,
89 pjmedia_codec_info codecs[]);
90static pj_status_t amr_alloc_codec(pjmedia_codec_factory *factory,
91 const pjmedia_codec_info *id,
92 pjmedia_codec **p_codec);
93static pj_status_t amr_dealloc_codec(pjmedia_codec_factory *factory,
94 pjmedia_codec *codec );
95
96/* Prototypes for AMR implementation. */
97static pj_status_t amr_codec_init(pjmedia_codec *codec,
98 pj_pool_t *pool );
99static pj_status_t amr_codec_open(pjmedia_codec *codec,
100 pjmedia_codec_param *attr );
101static pj_status_t amr_codec_close(pjmedia_codec *codec );
102static pj_status_t amr_codec_modify(pjmedia_codec *codec,
103 const pjmedia_codec_param *attr );
104static pj_status_t amr_codec_parse(pjmedia_codec *codec,
105 void *pkt,
106 pj_size_t pkt_size,
107 const pj_timestamp *ts,
108 unsigned *frame_cnt,
109 pjmedia_frame frames[]);
110static pj_status_t amr_codec_encode(pjmedia_codec *codec,
111 const struct pjmedia_frame *input,
112 unsigned output_buf_len,
113 struct pjmedia_frame *output);
114static pj_status_t amr_codec_decode(pjmedia_codec *codec,
115 const struct pjmedia_frame *input,
116 unsigned output_buf_len,
117 struct pjmedia_frame *output);
118static pj_status_t amr_codec_recover(pjmedia_codec *codec,
119 unsigned output_buf_len,
120 struct pjmedia_frame *output);
121
122
123
124/* Definition for AMR codec operations. */
125static pjmedia_codec_op amr_op =
126{
127 &amr_codec_init,
128 &amr_codec_open,
129 &amr_codec_close,
130 &amr_codec_modify,
131 &amr_codec_parse,
132 &amr_codec_encode,
133 &amr_codec_decode,
134 &amr_codec_recover
135};
136
137/* Definition for AMR codec factory operations. */
138static pjmedia_codec_factory_op amr_factory_op =
139{
140 &amr_test_alloc,
141 &amr_default_attr,
142 &amr_enum_codecs,
143 &amr_alloc_codec,
144 &amr_dealloc_codec,
145 &pjmedia_codec_opencore_amr_deinit
146};
147
148
149/* AMR factory */
150static struct amr_codec_factory
151{
152 pjmedia_codec_factory base;
153 pjmedia_endpt *endpt;
154 pj_pool_t *pool;
155 pj_bool_t init[2];
156} amr_codec_factory;
157
158
159/* AMR codec private data. */
160struct amr_data
161{
162 pj_pool_t *pool;
163 unsigned clock_rate;
164 void *encoder;
165 void *decoder;
166 pj_bool_t plc_enabled;
167 pj_bool_t vad_enabled;
168 int enc_mode;
169 pjmedia_codec_amr_pack_setting enc_setting;
170 pjmedia_codec_amr_pack_setting dec_setting;
171#if USE_PJMEDIA_PLC
172 pjmedia_plc *plc;
173#endif
174 pj_timestamp last_tx;
175};
176
177/* Index for AMR tables. */
178enum
179{
180 IDX_AMR_NB, /* Index for narrowband. */
181 IDX_AMR_WB /* Index for wideband. */
182};
183
184static pjmedia_codec_amr_config def_config[2] =
185{{ /* AMR-NB */
186 PJ_FALSE, /* octet align */
187 5900 /* bitrate */
188 },
189 { /* AMR-WB */
190 PJ_FALSE, /* octet align */
191 12650 /* bitrate */
192 }};
193
194static const pj_uint16_t* amr_bitrates[2] =
195 {pjmedia_codec_amrnb_bitrates, pjmedia_codec_amrwb_bitrates};
196
197static const unsigned amr_bitrates_size[2] =
198{
199 PJ_ARRAY_SIZE(pjmedia_codec_amrnb_bitrates),
200 PJ_ARRAY_SIZE(pjmedia_codec_amrwb_bitrates)
201};
202
203
204/*
205 * Initialize and register AMR codec factory to pjmedia endpoint.
206 */
207PJ_DEF(pj_status_t) pjmedia_codec_opencore_amr_init( pjmedia_endpt *endpt,
208 unsigned options)
209{
210 pjmedia_codec_mgr *codec_mgr;
211 pj_str_t codec_name;
212 pj_status_t status;
213
214 if (amr_codec_factory.pool != NULL)
215 return PJ_SUCCESS;
216
217 /* Create AMR codec factory. */
218 amr_codec_factory.base.op = &amr_factory_op;
219 amr_codec_factory.base.factory_data = NULL;
220 amr_codec_factory.endpt = endpt;
221#ifdef USE_AMRNB
222 amr_codec_factory.init[IDX_AMR_NB] = ((options & PJMEDIA_AMR_NO_NB) == 0);
223#else
224 amr_codec_factory.init[IDX_AMR_NB] = PJ_FALSE;
225#endif
226#ifdef USE_AMRWB
227 amr_codec_factory.init[IDX_AMR_WB] = ((options & PJMEDIA_AMR_NO_WB) == 0);
228#else
229 amr_codec_factory.init[IDX_AMR_WB] = PJ_FALSE;
230#endif
231
232 amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amr", 1000,
233 1000);
234 if (!amr_codec_factory.pool)
235 return PJ_ENOMEM;
236
237 /* Get the codec manager. */
238 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
239 if (!codec_mgr) {
240 status = PJ_EINVALIDOP;
241 goto on_error;
242 }
243
244 /* Register format match callback. */
245 pj_cstr(&codec_name, "AMR");
246 status = pjmedia_sdp_neg_register_fmt_match_cb(
247 &codec_name,
248 &pjmedia_codec_amr_match_sdp);
249 if (status != PJ_SUCCESS)
250 goto on_error;
251
252 /* Register codec factory to endpoint. */
253 status = pjmedia_codec_mgr_register_factory(codec_mgr,
254 &amr_codec_factory.base);
255 if (status != PJ_SUCCESS)
256 goto on_error;
257
258 /* Done. */
259 return PJ_SUCCESS;
260
261on_error:
262 pj_pool_release(amr_codec_factory.pool);
263 amr_codec_factory.pool = NULL;
264 return status;
265}
266
267PJ_DEF(pj_status_t)
268pjmedia_codec_opencore_amr_init_default( pjmedia_endpt *endpt )
269{
270 return pjmedia_codec_opencore_amr_init(endpt, 0);
271}
272
273PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_init( pjmedia_endpt *endpt )
274{
275 return pjmedia_codec_opencore_amr_init(endpt, PJMEDIA_AMR_NO_WB);
276}
277
278
279/*
280 * Unregister AMR codec factory from pjmedia endpoint and deinitialize
281 * the AMR codec library.
282 */
283PJ_DEF(pj_status_t) pjmedia_codec_opencore_amr_deinit(void)
284{
285 pjmedia_codec_mgr *codec_mgr;
286 pj_status_t status;
287
288 amr_codec_factory.init[IDX_AMR_NB] = PJ_FALSE;
289 amr_codec_factory.init[IDX_AMR_WB] = PJ_FALSE;
290
291 if (amr_codec_factory.pool == NULL)
292 return PJ_SUCCESS;
293
294 /* Get the codec manager. */
295 codec_mgr = pjmedia_endpt_get_codec_mgr(amr_codec_factory.endpt);
296 if (!codec_mgr) {
297 pj_pool_release(amr_codec_factory.pool);
298 amr_codec_factory.pool = NULL;
299 return PJ_EINVALIDOP;
300 }
301
302 /* Unregister AMR codec factory. */
303 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
304 &amr_codec_factory.base);
305
306 /* Destroy pool. */
307 pj_pool_release(amr_codec_factory.pool);
308 amr_codec_factory.pool = NULL;
309
310 return status;
311}
312
313PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_deinit(void)
314{
315 if (amr_codec_factory.init[IDX_AMR_NB] &&
316 amr_codec_factory.init[IDX_AMR_WB])
317 {
318 PJ_LOG(4, (THIS_FILE, "Should call "
319 "pjmedia_codec_opencore_amr_deinit() instead"));
320
321 return PJ_EINVALIDOP;
322 }
323
324 return pjmedia_codec_opencore_amr_deinit();
325}
326
327static pj_status_t
328amr_set_config(unsigned idx, const pjmedia_codec_amr_config *config)
329{
330 unsigned nbitrates;
331
332 def_config[idx] = *config;
333
334 /* Normalize bitrate. */
335 nbitrates = amr_bitrates_size[idx];
336 if (def_config[idx].bitrate < amr_bitrates[idx][0]) {
337 def_config[idx].bitrate = amr_bitrates[idx][0];
338 } else if (def_config[idx].bitrate > amr_bitrates[idx][nbitrates-1]) {
339 def_config[idx].bitrate = amr_bitrates[idx][nbitrates-1];
340 } else
341 {
342 unsigned i;
343
344 for (i = 0; i < nbitrates; ++i) {
345 if (def_config[idx].bitrate <= amr_bitrates[idx][i])
346 break;
347 }
348 def_config[idx].bitrate = amr_bitrates[idx][i];
349 }
350
351 return PJ_SUCCESS;
352}
353
354PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_set_config(
355 const pjmedia_codec_amrnb_config *config)
356{
357 return amr_set_config(IDX_AMR_NB, (const pjmedia_codec_amr_config *)config);
358}
359
360PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrwb_set_config(
361 const pjmedia_codec_amrwb_config *config)
362{
363 return amr_set_config(IDX_AMR_WB, (const pjmedia_codec_amr_config *)config);
364}
365
366/*
367 * Check if factory can allocate the specified codec.
368 */
369static pj_status_t amr_test_alloc( pjmedia_codec_factory *factory,
370 const pjmedia_codec_info *info )
371{
372 const pj_str_t amr_tag = { "AMR", 3};
373 const pj_str_t amrwb_tag = { "AMR-WB", 6};
374 PJ_UNUSED_ARG(factory);
375
376 /* Type MUST be audio. */
377 if (info->type != PJMEDIA_TYPE_AUDIO)
378 return PJMEDIA_CODEC_EUNSUP;
379
380 /* Check payload type. */
381 if (info->pt != PJMEDIA_RTP_PT_AMR && info->pt != PJMEDIA_RTP_PT_AMRWB)
382 return PJMEDIA_CODEC_EUNSUP;
383
384 /* Check encoding name. */
385 if (pj_stricmp(&info->encoding_name, &amr_tag) != 0 &&
386 pj_stricmp(&info->encoding_name, &amrwb_tag) != 0)
387 {
388 return PJMEDIA_CODEC_EUNSUP;
389 }
390
391 /* Check clock-rate */
392 if ((info->clock_rate == 8000 && amr_codec_factory.init[IDX_AMR_NB]) ||
393 (info->clock_rate == 16000 && amr_codec_factory.init[IDX_AMR_WB]))
394 {
395 return PJ_SUCCESS;
396 }
397
398 /* Unsupported or disabled. */
399 return PJMEDIA_CODEC_EUNSUP;
400}
401
402/*
403 * Generate default attribute.
404 */
405static pj_status_t amr_default_attr( pjmedia_codec_factory *factory,
406 const pjmedia_codec_info *id,
407 pjmedia_codec_param *attr )
408{
409 unsigned idx;
410
411 PJ_UNUSED_ARG(factory);
412
413 idx = (id->clock_rate <= 8000? IDX_AMR_NB: IDX_AMR_WB);
414 pj_bzero(attr, sizeof(pjmedia_codec_param));
415 attr->info.clock_rate = (id->clock_rate <= 8000? 8000: 16000);
416 attr->info.channel_cnt = 1;
417 attr->info.avg_bps = def_config[idx].bitrate;
418 attr->info.max_bps = amr_bitrates[idx][amr_bitrates_size[idx]-1];
419 attr->info.pcm_bits_per_sample = 16;
420 attr->info.frm_ptime = 20;
421 attr->info.pt = (pj_uint8_t)id->pt;
422
423 attr->setting.frm_per_pkt = 1;
424 attr->setting.vad = 1;
425 attr->setting.plc = 1;
426
427 if (def_config[idx].octet_align) {
428 attr->setting.dec_fmtp.cnt = 1;
429 attr->setting.dec_fmtp.param[0].name = pj_str("octet-align");
430 attr->setting.dec_fmtp.param[0].val = pj_str("1");
431 }
432
433 /* Default all other flag bits disabled. */
434
435 return PJ_SUCCESS;
436}
437
438
439/*
440 * Enum codecs supported by this factory (i.e. AMR-NB and AMR-WB).
441 */
442static pj_status_t amr_enum_codecs( pjmedia_codec_factory *factory,
443 unsigned *count,
444 pjmedia_codec_info codecs[])
445{
446 PJ_UNUSED_ARG(factory);
447 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
448
449 *count = 0;
450
451 if (amr_codec_factory.init[IDX_AMR_NB]) {
452 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
453 codecs[*count].encoding_name = pj_str("AMR");
454 codecs[*count].pt = PJMEDIA_RTP_PT_AMR;
455 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
456 codecs[*count].clock_rate = 8000;
457 codecs[*count].channel_cnt = 1;
458 (*count)++;
459 }
460
461 if (amr_codec_factory.init[IDX_AMR_WB]) {
462 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
463 codecs[*count].encoding_name = pj_str("AMR-WB");
464 codecs[*count].pt = PJMEDIA_RTP_PT_AMRWB;
465 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
466 codecs[*count].clock_rate = 16000;
467 codecs[*count].channel_cnt = 1;
468 (*count)++;
469 }
470
471 return PJ_SUCCESS;
472}
473
474
475/*
476 * Allocate a new AMR codec instance.
477 */
478static pj_status_t amr_alloc_codec( pjmedia_codec_factory *factory,
479 const pjmedia_codec_info *id,
480 pjmedia_codec **p_codec)
481{
482 pj_pool_t *pool;
483 pjmedia_codec *codec;
484 struct amr_data *amr_data;
485 pj_status_t status;
486
487 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
488 PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
489
490 pool = pjmedia_endpt_create_pool(amr_codec_factory.endpt, "amr-inst",
491 512, 512);
492
493 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
494 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
495 codec->op = &amr_op;
496 codec->factory = factory;
497
498 amr_data = PJ_POOL_ZALLOC_T(pool, struct amr_data);
499 codec->codec_data = amr_data;
500 amr_data->pool = pool;
501
502#if USE_PJMEDIA_PLC
503 /* Create PLC */
504 status = pjmedia_plc_create(pool, id->clock_rate,
505 id->clock_rate * FRAME_LENGTH_MS / 1000, 0,
506 &amr_data->plc);
507 if (status != PJ_SUCCESS) {
508 return status;
509 }
510#else
511 PJ_UNUSED_ARG(status);
512#endif
513 *p_codec = codec;
514 return PJ_SUCCESS;
515}
516
517
518/*
519 * Free codec.
520 */
521static pj_status_t amr_dealloc_codec( pjmedia_codec_factory *factory,
522 pjmedia_codec *codec )
523{
524 struct amr_data *amr_data;
525
526 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
527 PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
528
529 amr_data = (struct amr_data*) codec->codec_data;
530
531 /* Close codec, if it's not closed. */
532 amr_codec_close(codec);
533
534 pj_pool_release(amr_data->pool);
535 amr_data = NULL;
536
537 return PJ_SUCCESS;
538}
539
540/*
541 * Init codec.
542 */
543static pj_status_t amr_codec_init( pjmedia_codec *codec,
544 pj_pool_t *pool )
545{
546 PJ_UNUSED_ARG(codec);
547 PJ_UNUSED_ARG(pool);
548 return PJ_SUCCESS;
549}
550
551
552/*
553 * Open codec.
554 */
555static pj_status_t amr_codec_open( pjmedia_codec *codec,
556 pjmedia_codec_param *attr )
557{
558 struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
559 pjmedia_codec_amr_pack_setting *setting;
560 unsigned i;
561 pj_uint8_t octet_align = 0;
562 pj_int8_t enc_mode;
563 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
564 unsigned idx;
565
566 PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
567 PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
568
569 idx = (attr->info.clock_rate <= 8000? IDX_AMR_NB: IDX_AMR_WB);
570 enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
571 pj_assert(enc_mode >= 0 && enc_mode < amr_bitrates_size[idx]);
572
573 /* Check octet-align */
574 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
575 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
576 &STR_FMTP_OCTET_ALIGN) == 0)
577 {
578 octet_align = (pj_uint8_t)
579 (pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
580 break;
581 }
582 }
583
584 /* Check mode-set */
585 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
586 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
587
588 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
589 &STR_FMTP_MODE_SET) == 0)
590 {
591 const char *p;
592 pj_size_t l;
593 pj_int8_t diff = 99;
594
595 /* Encoding mode is chosen based on local default mode setting:
596 * - if local default mode is included in the mode-set, use it
597 * - otherwise, find the closest mode to local default mode;
598 * if there are two closest modes, prefer to use the higher
599 * one, e.g: local default mode is 4, the mode-set param
600 * contains '2,3,5,6', then 5 will be chosen.
601 */
602 p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
603 l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
604 while (l--) {
605 if (*p>='0' && *p<=('0'+amr_bitrates_size[idx]-1)) {
606 pj_int8_t tmp = *p - '0' - enc_mode;
607
608 if (PJ_ABS(diff) > PJ_ABS(tmp) ||
609 (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
610 {
611 diff = tmp;
612 if (diff == 0) break;
613 }
614 }
615 ++p;
616 }
617 PJ_ASSERT_RETURN(diff != 99, PJMEDIA_CODEC_EFAILED);
618
619 enc_mode = enc_mode + diff;
620
621 break;
622 }
623 }
624
625 amr_data->clock_rate = attr->info.clock_rate;
626 amr_data->vad_enabled = (attr->setting.vad != 0);
627 amr_data->plc_enabled = (attr->setting.plc != 0);
628 amr_data->enc_mode = enc_mode;
629
630 if (idx == IDX_AMR_NB) {
631#ifdef USE_AMRNB
632 amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
633#endif
634 } else {
635#ifdef USE_AMRWB
636 amr_data->encoder = E_IF_init();
637#endif
638 }
639 if (amr_data->encoder == NULL) {
640 TRACE_((THIS_FILE, "Encoder initialization failed"));
641 amr_codec_close(codec);
642 return PJMEDIA_CODEC_EFAILED;
643 }
644 setting = &amr_data->enc_setting;
645 pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
646 setting->amr_nb = (idx == IDX_AMR_NB? 1: 0);
647 setting->reorder = 0;
648 setting->octet_aligned = octet_align;
649 setting->cmr = 15;
650
651 if (idx == IDX_AMR_NB) {
652#ifdef USE_AMRNB
653 amr_data->decoder = Decoder_Interface_init();
654#endif
655 } else {
656#ifdef USE_AMRWB
657 amr_data->decoder = D_IF_init();
658#endif
659 }
660 if (amr_data->decoder == NULL) {
661 TRACE_((THIS_FILE, "Decoder initialization failed"));
662 amr_codec_close(codec);
663 return PJMEDIA_CODEC_EFAILED;
664 }
665 setting = &amr_data->dec_setting;
666 pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
667 setting->amr_nb = (idx == IDX_AMR_NB? 1: 0);
668 setting->reorder = 0;
669 setting->octet_aligned = octet_align;
670
671 TRACE_((THIS_FILE, "AMR codec allocated: clockrate=%d vad=%d, plc=%d,"
672 " bitrate=%d", amr_data->clock_rate,
673 amr_data->vad_enabled, amr_data->plc_enabled,
674 amr_bitrates[idx][amr_data->enc_mode]));
675 return PJ_SUCCESS;
676}
677
678
679/*
680 * Close codec.
681 */
682static pj_status_t amr_codec_close( pjmedia_codec *codec )
683{
684 struct amr_data *amr_data;
685
686 PJ_ASSERT_RETURN(codec, PJ_EINVAL);
687
688 amr_data = (struct amr_data*) codec->codec_data;
689 PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
690
691 if (amr_data->encoder) {
692 if (amr_data->enc_setting.amr_nb) {
693#ifdef USE_AMRNB
694 Encoder_Interface_exit(amr_data->encoder);
695#endif
696 } else {
697#ifdef USE_AMRWB
698 E_IF_exit(amr_data->encoder);
699#endif
700 }
701 amr_data->encoder = NULL;
702 }
703
704 if (amr_data->decoder) {
705 if (amr_data->dec_setting.amr_nb) {
706#ifdef USE_AMRNB
707 Decoder_Interface_exit(amr_data->decoder);
708#endif
709 } else {
710#ifdef USE_AMRWB
711 D_IF_exit(amr_data->decoder);
712#endif
713 }
714 amr_data->decoder = NULL;
715 }
716
717 TRACE_((THIS_FILE, "AMR codec closed"));
718 return PJ_SUCCESS;
719}
720
721
722/*
723 * Modify codec settings.
724 */
725static pj_status_t amr_codec_modify( pjmedia_codec *codec,
726 const pjmedia_codec_param *attr )
727{
728 struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
729 pj_bool_t prev_vad_state;
730
731 pj_assert(amr_data != NULL);
732 pj_assert(amr_data->encoder != NULL && amr_data->decoder != NULL);
733
734 prev_vad_state = amr_data->vad_enabled;
735 amr_data->vad_enabled = (attr->setting.vad != 0);
736 amr_data->plc_enabled = (attr->setting.plc != 0);
737
738 if (amr_data->enc_setting.amr_nb &&
739 prev_vad_state != amr_data->vad_enabled)
740 {
741 /* Reinit AMR encoder to update VAD setting */
742 TRACE_((THIS_FILE, "Reiniting AMR encoder to update VAD setting."));
743#ifdef USE_AMRNB
744 Encoder_Interface_exit(amr_data->encoder);
745 amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
746#endif
747 if (amr_data->encoder == NULL) {
748 TRACE_((THIS_FILE, "Encoder_Interface_init() failed"));
749 amr_codec_close(codec);
750 return PJMEDIA_CODEC_EFAILED;
751 }
752 }
753
754 TRACE_((THIS_FILE, "AMR codec modified: vad=%d, plc=%d",
755 amr_data->vad_enabled, amr_data->plc_enabled));
756 return PJ_SUCCESS;
757}
758
759
760/*
761 * Get frames in the packet.
762 */
763static pj_status_t amr_codec_parse( pjmedia_codec *codec,
764 void *pkt,
765 pj_size_t pkt_size,
766 const pj_timestamp *ts,
767 unsigned *frame_cnt,
768 pjmedia_frame frames[])
769{
770 struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
771 pj_uint8_t cmr;
772 pj_status_t status;
773 unsigned idx = (amr_data->enc_setting.amr_nb? 0: 1);
774
775 status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, &amr_data->dec_setting,
776 frames, frame_cnt, &cmr);
777 if (status != PJ_SUCCESS)
778 return status;
779
780 /* Check for Change Mode Request. */
781 if (cmr < amr_bitrates_size[idx] && amr_data->enc_mode != cmr) {
782 amr_data->enc_mode = cmr;
783 TRACE_((THIS_FILE, "AMR encoder switched mode to %d (%dbps)",
784 amr_data->enc_mode,
785 amr_bitrates[idx][amr_data->enc_mode]));
786 }
787
788 return PJ_SUCCESS;
789}
790
791
792/*
793 * Encode frame.
794 */
795static pj_status_t amr_codec_encode( pjmedia_codec *codec,
796 const struct pjmedia_frame *input,
797 unsigned output_buf_len,
798 struct pjmedia_frame *output)
799{
800 struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
801 unsigned char *bitstream;
802 pj_int16_t *speech;
803 unsigned nsamples, samples_per_frame;
804 enum {MAX_FRAMES_PER_PACKET = 16};
805 pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
806 pj_uint8_t *p;
807 unsigned i, out_size = 0, nframes = 0;
808 pj_size_t payload_len;
809 unsigned dtx_cnt, sid_cnt;
810 pj_status_t status;
811
812 pj_assert(amr_data != NULL);
813 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
814
815 nsamples = input->size >> 1;
816 samples_per_frame = amr_data->clock_rate * FRAME_LENGTH_MS / 1000;
817 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
818 PJMEDIA_CODEC_EPCMFRMINLEN);
819
820 nframes = nsamples / samples_per_frame;
821 PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET,
822 PJMEDIA_CODEC_EFRMTOOSHORT);
823
824 /* Encode the frames */
825 speech = (pj_int16_t*)input->buf;
826 bitstream = (unsigned char*)output->buf;
827 while (nsamples >= samples_per_frame) {
828 int size;
829 if (amr_data->enc_setting.amr_nb) {
830#ifdef USE_AMRNB
831 size = Encoder_Interface_Encode (amr_data->encoder,
832 amr_data->enc_mode,
833 speech, bitstream, 0);
834#else
835 size = 0;
836#endif
837 } else {
838#ifdef USE_AMRWB
839 size = E_IF_encode (amr_data->encoder, amr_data->enc_mode,
840 speech, bitstream, 0);
841#else
842 size = 0;
843#endif
844 }
845 if (size == 0) {
846 output->size = 0;
847 output->buf = NULL;
848 output->type = PJMEDIA_FRAME_TYPE_NONE;
849 TRACE_((THIS_FILE, "AMR encode() failed"));
850 return PJMEDIA_CODEC_EFAILED;
851 }
852 nsamples -= samples_per_frame;
853 speech += samples_per_frame;
854 bitstream += size;
855 out_size += size;
856 TRACE_((THIS_FILE, "AMR encode(): mode=%d, size=%d",
857 amr_data->enc_mode, out_size));
858 }
859
860 /* Pack payload */
861 p = (pj_uint8_t*)output->buf + output_buf_len - out_size;
862 pj_memmove(p, output->buf, out_size);
863 dtx_cnt = sid_cnt = 0;
864 for (i = 0; i < nframes; ++i) {
865 pjmedia_codec_amr_bit_info *info = (pjmedia_codec_amr_bit_info*)
866 &frames[i].bit_info;
867 info->frame_type = (pj_uint8_t)((*p >> 3) & 0x0F);
868 info->good_quality = (pj_uint8_t)((*p >> 2) & 0x01);
869 info->mode = (pj_int8_t)amr_data->enc_mode;
870 info->start_bit = 0;
871 frames[i].buf = p + 1;
872 if (amr_data->enc_setting.amr_nb) {
873 frames[i].size = (info->frame_type <= 8)?
874 pjmedia_codec_amrnb_framelen[info->frame_type] : 0;
875 } else {
876 frames[i].size = (info->frame_type <= 9)?
877 pjmedia_codec_amrwb_framelen[info->frame_type] : 0;
878 }
879 p += frames[i].size + 1;
880
881 /* Count the number of SID and DTX frames */
882 if (info->frame_type == 15) /* DTX*/
883 ++dtx_cnt;
884 else if (info->frame_type == 8) /* SID */
885 ++sid_cnt;
886 }
887
888 /* VA generates DTX frames as DTX+SID frames switching quickly and it
889 * seems that the SID frames occur too often (assuming the purpose is
890 * only for keeping NAT alive?). So let's modify the behavior a bit.
891 * Only an SID frame will be sent every PJMEDIA_CODEC_MAX_SILENCE_PERIOD
892 * milliseconds.
893 */
894 if (sid_cnt + dtx_cnt == nframes) {
895 pj_int32_t dtx_duration;
896
897 dtx_duration = pj_timestamp_diff32(&amr_data->last_tx,
898 &input->timestamp);
899 if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
900 dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*
901 amr_data->clock_rate/1000)
902 {
903 output->size = 0;
904 output->type = PJMEDIA_FRAME_TYPE_NONE;
905 output->timestamp = input->timestamp;
906 return PJ_SUCCESS;
907 }
908 }
909
910 payload_len = output_buf_len;
911
912 status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting,
913 output->buf, &payload_len);
914 if (status != PJ_SUCCESS) {
915 output->size = 0;
916 output->buf = NULL;
917 output->type = PJMEDIA_FRAME_TYPE_NONE;
918 TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status));
919 return status;
920 }
921
922 output->size = payload_len;
923 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
924 output->timestamp = input->timestamp;
925
926 amr_data->last_tx = input->timestamp;
927
928 return PJ_SUCCESS;
929}
930
931
932/*
933 * Decode frame.
934 */
935static pj_status_t amr_codec_decode( pjmedia_codec *codec,
936 const struct pjmedia_frame *input,
937 unsigned output_buf_len,
938 struct pjmedia_frame *output)
939{
940 struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
941 pjmedia_frame input_;
942 pjmedia_codec_amr_bit_info *info;
943 unsigned out_size;
944 /* AMR decoding buffer: AMR max frame size + 1 byte header. */
945 unsigned char bitstream[61];
946
947 pj_assert(amr_data != NULL);
948 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
949
950 out_size = amr_data->clock_rate * FRAME_LENGTH_MS / 1000 * 2;
951 if (output_buf_len < out_size)
952 return PJMEDIA_CODEC_EPCMTOOSHORT;
953
954 input_.buf = &bitstream[1];
955 /* AMR max frame size */
956 input_.size = (amr_data->dec_setting.amr_nb? 31: 60);
957 pjmedia_codec_amr_predecode(input, &amr_data->dec_setting, &input_);
958 info = (pjmedia_codec_amr_bit_info*)&input_.bit_info;
959
960 /* VA AMR decoder requires frame info in the first byte. */
961 bitstream[0] = (info->frame_type << 3) | (info->good_quality << 2);
962
963 TRACE_((THIS_FILE, "AMR decode(): mode=%d, ft=%d, size=%d",
964 info->mode, info->frame_type, input_.size));
965
966 /* Decode */
967 if (amr_data->dec_setting.amr_nb) {
968#ifdef USE_AMRNB
969 Decoder_Interface_Decode(amr_data->decoder, bitstream,
970 (pj_int16_t*)output->buf, 0);
971#endif
972 } else {
973#ifdef USE_AMRWB
974 D_IF_decode(amr_data->decoder, bitstream,
975 (pj_int16_t*)output->buf, 0);
976#endif
977 }
978
979 output->size = out_size;
980 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
981 output->timestamp = input->timestamp;
982
983#if USE_PJMEDIA_PLC
984 if (amr_data->plc_enabled)
985 pjmedia_plc_save(amr_data->plc, (pj_int16_t*)output->buf);
986#endif
987
988 return PJ_SUCCESS;
989}
990
991
992/*
993 * Recover lost frame.
994 */
995#if USE_PJMEDIA_PLC
996/*
997 * Recover lost frame.
998 */
999static pj_status_t amr_codec_recover( pjmedia_codec *codec,
1000 unsigned output_buf_len,
1001 struct pjmedia_frame *output)
1002{
1003 struct amr_data *amr_data = codec->codec_data;
1004 unsigned out_size = amr_data->clock_rate * FRAME_LENGTH_MS / 1000 * 2;
1005
1006 TRACE_((THIS_FILE, "amr_codec_recover"));
1007
1008 PJ_ASSERT_RETURN(amr_data->plc_enabled, PJ_EINVALIDOP);
1009
1010 PJ_ASSERT_RETURN(output_buf_len >= out_size, PJMEDIA_CODEC_EPCMTOOSHORT);
1011
1012 pjmedia_plc_generate(amr_data->plc, (pj_int16_t*)output->buf);
1013
1014 output->size = out_size;
1015 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1016
1017 return PJ_SUCCESS;
1018}
1019#endif
1020
1021#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS
1022# if PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC
1023# ifdef USE_AMRNB
1024# pragma comment( lib, "libopencore-amrnb.a")
1025# endif
1026# ifdef USE_AMRWB
1027# pragma comment( lib, "libopencore-amrwb.a")
1028# pragma comment( lib, "libvo-amrwbenc.a")
1029# endif
1030# else
1031# error Unsupported OpenCORE AMR library, fix here
1032# endif
1033#endif
1034
1035#endif