1
/* $Id: opencore_amrnb.c 3939 2012-01-10 05:38:40Z nanang $ */
3
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2011 Dan Arrhenius <dan@keystream.se>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
* AMR-NB codec implementation with OpenCORE AMRNB library
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>
35
#include <pj/string.h>
39
#if defined(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC) && \
40
(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC != 0)
42
#include <opencore-amrnb/interf_enc.h>
43
#include <opencore-amrnb/interf_dec.h>
44
#include <pjmedia-codec/amr_helper.h>
45
#include <pjmedia-codec/opencore_amrnb.h>
47
#define THIS_FILE "opencore_amrnb.c"
53
# define TRACE_(expr) PJ_LOG(4,expr)
59
#define USE_PJMEDIA_PLC 1
63
/* Prototypes for AMR-NB factory */
64
static pj_status_t amr_test_alloc(pjmedia_codec_factory *factory,
65
const pjmedia_codec_info *id );
66
static pj_status_t amr_default_attr(pjmedia_codec_factory *factory,
67
const pjmedia_codec_info *id,
68
pjmedia_codec_param *attr );
69
static pj_status_t amr_enum_codecs(pjmedia_codec_factory *factory,
71
pjmedia_codec_info codecs[]);
72
static pj_status_t amr_alloc_codec(pjmedia_codec_factory *factory,
73
const pjmedia_codec_info *id,
74
pjmedia_codec **p_codec);
75
static pj_status_t amr_dealloc_codec(pjmedia_codec_factory *factory,
76
pjmedia_codec *codec );
78
/* Prototypes for AMR-NB implementation. */
79
static pj_status_t amr_codec_init(pjmedia_codec *codec,
81
static pj_status_t amr_codec_open(pjmedia_codec *codec,
82
pjmedia_codec_param *attr );
83
static pj_status_t amr_codec_close(pjmedia_codec *codec );
84
static pj_status_t amr_codec_modify(pjmedia_codec *codec,
85
const pjmedia_codec_param *attr );
86
static pj_status_t amr_codec_parse(pjmedia_codec *codec,
89
const pj_timestamp *ts,
91
pjmedia_frame frames[]);
92
static pj_status_t amr_codec_encode(pjmedia_codec *codec,
93
const struct pjmedia_frame *input,
94
unsigned output_buf_len,
95
struct pjmedia_frame *output);
96
static pj_status_t amr_codec_decode(pjmedia_codec *codec,
97
const struct pjmedia_frame *input,
98
unsigned output_buf_len,
99
struct pjmedia_frame *output);
100
static pj_status_t amr_codec_recover(pjmedia_codec *codec,
101
unsigned output_buf_len,
102
struct pjmedia_frame *output);
106
/* Definition for AMR-NB codec operations. */
107
static pjmedia_codec_op amr_op =
119
/* Definition for AMR-NB codec factory operations. */
120
static pjmedia_codec_factory_op amr_factory_op =
127
&pjmedia_codec_opencore_amrnb_deinit
132
static struct amr_codec_factory
134
pjmedia_codec_factory base;
135
pjmedia_endpt *endpt;
140
/* AMR-NB codec private data. */
146
pj_bool_t plc_enabled;
147
pj_bool_t vad_enabled;
149
pjmedia_codec_amr_pack_setting enc_setting;
150
pjmedia_codec_amr_pack_setting dec_setting;
154
pj_timestamp last_tx;
157
static pjmedia_codec_amrnb_config def_config =
159
PJ_FALSE, /* octet align */
166
* Initialize and register AMR-NB codec factory to pjmedia endpoint.
168
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_init( pjmedia_endpt *endpt )
170
pjmedia_codec_mgr *codec_mgr;
174
if (amr_codec_factory.pool != NULL)
177
/* Create AMR-NB codec factory. */
178
amr_codec_factory.base.op = &amr_factory_op;
179
amr_codec_factory.base.factory_data = NULL;
180
amr_codec_factory.endpt = endpt;
182
amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amrnb", 1000,
184
if (!amr_codec_factory.pool)
187
/* Get the codec manager. */
188
codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
190
status = PJ_EINVALIDOP;
194
/* Register format match callback. */
195
pj_cstr(&codec_name, "AMR");
196
status = pjmedia_sdp_neg_register_fmt_match_cb(
198
&pjmedia_codec_amr_match_sdp);
199
if (status != PJ_SUCCESS)
202
/* Register codec factory to endpoint. */
203
status = pjmedia_codec_mgr_register_factory(codec_mgr,
204
&amr_codec_factory.base);
205
if (status != PJ_SUCCESS)
212
pj_pool_release(amr_codec_factory.pool);
213
amr_codec_factory.pool = NULL;
219
* Unregister AMR-NB codec factory from pjmedia endpoint and deinitialize
220
* the AMR-NB codec library.
222
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_deinit(void)
224
pjmedia_codec_mgr *codec_mgr;
227
if (amr_codec_factory.pool == NULL)
230
/* Get the codec manager. */
231
codec_mgr = pjmedia_endpt_get_codec_mgr(amr_codec_factory.endpt);
233
pj_pool_release(amr_codec_factory.pool);
234
amr_codec_factory.pool = NULL;
235
return PJ_EINVALIDOP;
238
/* Unregister AMR-NB codec factory. */
239
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
240
&amr_codec_factory.base);
243
pj_pool_release(amr_codec_factory.pool);
244
amr_codec_factory.pool = NULL;
250
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_set_config(
251
const pjmedia_codec_amrnb_config *config)
256
def_config = *config;
258
/* Normalize bitrate. */
259
nbitrates = PJ_ARRAY_SIZE(pjmedia_codec_amrnb_bitrates);
260
if (def_config.bitrate < pjmedia_codec_amrnb_bitrates[0])
261
def_config.bitrate = pjmedia_codec_amrnb_bitrates[0];
262
else if (def_config.bitrate > pjmedia_codec_amrnb_bitrates[nbitrates-1])
263
def_config.bitrate = pjmedia_codec_amrnb_bitrates[nbitrates-1];
268
for (i = 0; i < nbitrates; ++i) {
269
if (def_config.bitrate <= pjmedia_codec_amrnb_bitrates[i])
272
def_config.bitrate = pjmedia_codec_amrnb_bitrates[i];
279
* Check if factory can allocate the specified codec.
281
static pj_status_t amr_test_alloc( pjmedia_codec_factory *factory,
282
const pjmedia_codec_info *info )
284
PJ_UNUSED_ARG(factory);
286
/* Check payload type. */
287
if (info->pt != PJMEDIA_RTP_PT_AMR)
288
return PJMEDIA_CODEC_EUNSUP;
290
/* Ignore the rest, since it's static payload type. */
296
* Generate default attribute.
298
static pj_status_t amr_default_attr( pjmedia_codec_factory *factory,
299
const pjmedia_codec_info *id,
300
pjmedia_codec_param *attr )
302
PJ_UNUSED_ARG(factory);
305
pj_bzero(attr, sizeof(pjmedia_codec_param));
306
attr->info.clock_rate = 8000;
307
attr->info.channel_cnt = 1;
308
attr->info.avg_bps = def_config.bitrate;
309
attr->info.max_bps = pjmedia_codec_amrnb_bitrates[7];
310
attr->info.pcm_bits_per_sample = 16;
311
attr->info.frm_ptime = 20;
312
attr->info.pt = PJMEDIA_RTP_PT_AMR;
314
attr->setting.frm_per_pkt = 2;
315
attr->setting.vad = 1;
316
attr->setting.plc = 1;
318
if (def_config.octet_align) {
319
attr->setting.dec_fmtp.cnt = 1;
320
attr->setting.dec_fmtp.param[0].name = pj_str("octet-align");
321
attr->setting.dec_fmtp.param[0].val = pj_str("1");
324
/* Default all other flag bits disabled. */
331
* Enum codecs supported by this factory (i.e. only AMR-NB!).
333
static pj_status_t amr_enum_codecs( pjmedia_codec_factory *factory,
335
pjmedia_codec_info codecs[])
337
PJ_UNUSED_ARG(factory);
338
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
340
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
341
codecs[0].encoding_name = pj_str("AMR");
342
codecs[0].pt = PJMEDIA_RTP_PT_AMR;
343
codecs[0].type = PJMEDIA_TYPE_AUDIO;
344
codecs[0].clock_rate = 8000;
345
codecs[0].channel_cnt = 1;
354
* Allocate a new AMR-NB codec instance.
356
static pj_status_t amr_alloc_codec( pjmedia_codec_factory *factory,
357
const pjmedia_codec_info *id,
358
pjmedia_codec **p_codec)
361
pjmedia_codec *codec;
362
struct amr_data *amr_data;
365
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
366
PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
368
pool = pjmedia_endpt_create_pool(amr_codec_factory.endpt, "amrnb-inst",
371
codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
372
PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
374
codec->factory = factory;
376
amr_data = PJ_POOL_ZALLOC_T(pool, struct amr_data);
377
codec->codec_data = amr_data;
378
amr_data->pool = pool;
382
status = pjmedia_plc_create(pool, 8000, 160, 0, &amr_data->plc);
383
if (status != PJ_SUCCESS) {
387
PJ_UNUSED_ARG(status);
397
static pj_status_t amr_dealloc_codec( pjmedia_codec_factory *factory,
398
pjmedia_codec *codec )
400
struct amr_data *amr_data;
402
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
403
PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
405
amr_data = (struct amr_data*) codec->codec_data;
407
/* Close codec, if it's not closed. */
408
amr_codec_close(codec);
410
pj_pool_release(amr_data->pool);
419
static pj_status_t amr_codec_init( pjmedia_codec *codec,
422
PJ_UNUSED_ARG(codec);
431
static pj_status_t amr_codec_open( pjmedia_codec *codec,
432
pjmedia_codec_param *attr )
434
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
435
pjmedia_codec_amr_pack_setting *setting;
437
pj_uint8_t octet_align = 0;
439
const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
441
PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
442
PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
444
enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
445
pj_assert(enc_mode >= 0 && enc_mode <= 7);
447
/* Check octet-align */
448
for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
449
if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
450
&STR_FMTP_OCTET_ALIGN) == 0)
452
octet_align = (pj_uint8_t)
453
(pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
459
for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
460
const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
462
if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
463
&STR_FMTP_MODE_SET) == 0)
469
/* Encoding mode is chosen based on local default mode setting:
470
* - if local default mode is included in the mode-set, use it
471
* - otherwise, find the closest mode to local default mode;
472
* if there are two closest modes, prefer to use the higher
473
* one, e.g: local default mode is 4, the mode-set param
474
* contains '2,3,5,6', then 5 will be chosen.
476
p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
477
l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
479
if (*p>='0' && *p<='7') {
480
pj_int8_t tmp = *p - '0' - enc_mode;
482
if (PJ_ABS(diff) > PJ_ABS(tmp) ||
483
(PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
486
if (diff == 0) break;
491
PJ_ASSERT_RETURN(diff != 99, PJMEDIA_CODEC_EFAILED);
493
enc_mode = enc_mode + diff;
499
amr_data->vad_enabled = (attr->setting.vad != 0);
500
amr_data->plc_enabled = (attr->setting.plc != 0);
501
amr_data->enc_mode = enc_mode;
503
amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
504
if (amr_data->encoder == NULL) {
505
TRACE_((THIS_FILE, "Encoder_Interface_init() failed"));
506
amr_codec_close(codec);
507
return PJMEDIA_CODEC_EFAILED;
509
setting = &amr_data->enc_setting;
510
pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
512
setting->reorder = 0;
513
setting->octet_aligned = octet_align;
516
amr_data->decoder = Decoder_Interface_init();
517
if (amr_data->decoder == NULL) {
518
TRACE_((THIS_FILE, "Decoder_Interface_init() failed"));
519
amr_codec_close(codec);
520
return PJMEDIA_CODEC_EFAILED;
522
setting = &amr_data->dec_setting;
523
pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
525
setting->reorder = 0;
526
setting->octet_aligned = octet_align;
528
TRACE_((THIS_FILE, "AMR-NB codec allocated: vad=%d, plc=%d, bitrate=%d",
529
amr_data->vad_enabled, amr_data->plc_enabled,
530
pjmedia_codec_amrnb_bitrates[amr_data->enc_mode]));
538
static pj_status_t amr_codec_close( pjmedia_codec *codec )
540
struct amr_data *amr_data;
542
PJ_ASSERT_RETURN(codec, PJ_EINVAL);
544
amr_data = (struct amr_data*) codec->codec_data;
545
PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
547
if (amr_data->encoder) {
548
Encoder_Interface_exit(amr_data->encoder);
549
amr_data->encoder = NULL;
552
if (amr_data->decoder) {
553
Decoder_Interface_exit(amr_data->decoder);
554
amr_data->decoder = NULL;
557
TRACE_((THIS_FILE, "AMR-NB codec closed"));
563
* Modify codec settings.
565
static pj_status_t amr_codec_modify( pjmedia_codec *codec,
566
const pjmedia_codec_param *attr )
568
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
569
pj_bool_t prev_vad_state;
571
pj_assert(amr_data != NULL);
572
pj_assert(amr_data->encoder != NULL && amr_data->decoder != NULL);
574
prev_vad_state = amr_data->vad_enabled;
575
amr_data->vad_enabled = (attr->setting.vad != 0);
576
amr_data->plc_enabled = (attr->setting.plc != 0);
578
if (prev_vad_state != amr_data->vad_enabled) {
579
/* Reinit AMR encoder to update VAD setting */
580
TRACE_((THIS_FILE, "Reiniting AMR encoder to update VAD setting."));
581
Encoder_Interface_exit(amr_data->encoder);
582
amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
583
if (amr_data->encoder == NULL) {
584
TRACE_((THIS_FILE, "Encoder_Interface_init() failed"));
585
amr_codec_close(codec);
586
return PJMEDIA_CODEC_EFAILED;
590
TRACE_((THIS_FILE, "AMR-NB codec modified: vad=%d, plc=%d",
591
amr_data->vad_enabled, amr_data->plc_enabled));
597
* Get frames in the packet.
599
static pj_status_t amr_codec_parse( pjmedia_codec *codec,
602
const pj_timestamp *ts,
604
pjmedia_frame frames[])
606
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
610
status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, &amr_data->dec_setting,
611
frames, frame_cnt, &cmr);
612
if (status != PJ_SUCCESS)
615
/* Check for Change Mode Request. */
616
if (cmr <= 7 && amr_data->enc_mode != cmr) {
617
amr_data->enc_mode = cmr;
618
TRACE_((THIS_FILE, "AMR-NB encoder switched mode to %d (%dbps)",
620
pjmedia_codec_amrnb_bitrates[amr_data->enc_mode]));
630
static pj_status_t amr_codec_encode( pjmedia_codec *codec,
631
const struct pjmedia_frame *input,
632
unsigned output_buf_len,
633
struct pjmedia_frame *output)
635
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
636
unsigned char *bitstream;
638
unsigned nsamples, samples_per_frame;
639
enum {MAX_FRAMES_PER_PACKET = 16};
640
pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
642
unsigned i, out_size = 0, nframes = 0;
643
pj_size_t payload_len;
644
unsigned dtx_cnt, sid_cnt;
648
pj_assert(amr_data != NULL);
649
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
651
nsamples = input->size >> 1;
652
samples_per_frame = 160;
653
PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
654
PJMEDIA_CODEC_EPCMFRMINLEN);
656
nframes = nsamples / samples_per_frame;
657
PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET,
658
PJMEDIA_CODEC_EFRMTOOSHORT);
660
/* Encode the frames */
661
speech = (pj_int16_t*)input->buf;
662
bitstream = (unsigned char*)output->buf;
663
while (nsamples >= samples_per_frame) {
664
size = Encoder_Interface_Encode (amr_data->encoder, amr_data->enc_mode,
665
speech, bitstream, 0);
669
output->type = PJMEDIA_FRAME_TYPE_NONE;
670
TRACE_((THIS_FILE, "AMR-NB encode() failed"));
671
return PJMEDIA_CODEC_EFAILED;
674
speech += samples_per_frame;
677
TRACE_((THIS_FILE, "AMR-NB encode(): mode=%d, size=%d",
678
amr_data->enc_mode, out_size));
682
p = (pj_uint8_t*)output->buf + output_buf_len - out_size;
683
pj_memmove(p, output->buf, out_size);
684
dtx_cnt = sid_cnt = 0;
685
for (i = 0; i < nframes; ++i) {
686
pjmedia_codec_amr_bit_info *info = (pjmedia_codec_amr_bit_info*)
688
info->frame_type = (pj_uint8_t)((*p >> 3) & 0x0F);
689
info->good_quality = (pj_uint8_t)((*p >> 2) & 0x01);
690
info->mode = (pj_int8_t)amr_data->enc_mode;
692
frames[i].buf = p + 1;
693
frames[i].size = (info->frame_type <= 8)?
694
pjmedia_codec_amrnb_framelen[info->frame_type] : 0;
695
p += frames[i].size + 1;
697
/* Count the number of SID and DTX frames */
698
if (info->frame_type == 15) /* DTX*/
700
else if (info->frame_type == 8) /* SID */
704
/* VA generates DTX frames as DTX+SID frames switching quickly and it
705
* seems that the SID frames occur too often (assuming the purpose is
706
* only for keeping NAT alive?). So let's modify the behavior a bit.
707
* Only an SID frame will be sent every PJMEDIA_CODEC_MAX_SILENCE_PERIOD
710
if (sid_cnt + dtx_cnt == nframes) {
711
pj_int32_t dtx_duration;
713
dtx_duration = pj_timestamp_diff32(&amr_data->last_tx,
715
if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
716
dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
719
output->type = PJMEDIA_FRAME_TYPE_NONE;
720
output->timestamp = input->timestamp;
725
payload_len = output_buf_len;
727
status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting,
728
output->buf, &payload_len);
729
if (status != PJ_SUCCESS) {
732
output->type = PJMEDIA_FRAME_TYPE_NONE;
733
TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status));
737
output->size = payload_len;
738
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
739
output->timestamp = input->timestamp;
741
amr_data->last_tx = input->timestamp;
750
static pj_status_t amr_codec_decode( pjmedia_codec *codec,
751
const struct pjmedia_frame *input,
752
unsigned output_buf_len,
753
struct pjmedia_frame *output)
755
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
756
pjmedia_frame input_;
757
pjmedia_codec_amr_bit_info *info;
758
/* VA AMR-NB decoding buffer: AMR-NB max frame size + 1 byte header. */
759
unsigned char bitstream[32];
761
pj_assert(amr_data != NULL);
762
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
764
if (output_buf_len < 320)
765
return PJMEDIA_CODEC_EPCMTOOSHORT;
767
input_.buf = &bitstream[1];
768
input_.size = 31; /* AMR-NB max frame size */
769
pjmedia_codec_amr_predecode(input, &amr_data->dec_setting, &input_);
770
info = (pjmedia_codec_amr_bit_info*)&input_.bit_info;
772
/* VA AMRNB decoder requires frame info in the first byte. */
773
bitstream[0] = (info->frame_type << 3) | (info->good_quality << 2);
775
TRACE_((THIS_FILE, "AMR-NB decode(): mode=%d, ft=%d, size=%d",
776
info->mode, info->frame_type, input_.size));
779
Decoder_Interface_Decode(amr_data->decoder, bitstream,
780
(pj_int16_t*)output->buf, 0);
783
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
784
output->timestamp = input->timestamp;
787
if (amr_data->plc_enabled)
788
pjmedia_plc_save(amr_data->plc, (pj_int16_t*)output->buf);
796
* Recover lost frame.
800
* Recover lost frame.
802
static pj_status_t amr_codec_recover( pjmedia_codec *codec,
803
unsigned output_buf_len,
804
struct pjmedia_frame *output)
806
struct amr_data *amr_data = codec->codec_data;
808
TRACE_((THIS_FILE, "amr_codec_recover"));
810
PJ_ASSERT_RETURN(amr_data->plc_enabled, PJ_EINVALIDOP);
812
PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT);
814
pjmedia_plc_generate(amr_data->plc, (pj_int16_t*)output->buf);
817
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
823
#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS
824
# if PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC
825
# pragma comment( lib, "libopencore-amrnb.a")
827
# error Unsupported OpenCORE AMR library, fix here