~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-codec/opencore_amr.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: opencore_amr.c 4348 2013-02-14 02:00:13Z ming $ */
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 */
82
 
static pj_status_t amr_test_alloc(pjmedia_codec_factory *factory, 
83
 
                                   const pjmedia_codec_info *id );
84
 
static pj_status_t amr_default_attr(pjmedia_codec_factory *factory, 
85
 
                                     const pjmedia_codec_info *id, 
86
 
                                     pjmedia_codec_param *attr );
87
 
static pj_status_t amr_enum_codecs(pjmedia_codec_factory *factory, 
88
 
                                    unsigned *count, 
89
 
                                    pjmedia_codec_info codecs[]);
90
 
static pj_status_t amr_alloc_codec(pjmedia_codec_factory *factory, 
91
 
                                    const pjmedia_codec_info *id, 
92
 
                                    pjmedia_codec **p_codec);
93
 
static pj_status_t amr_dealloc_codec(pjmedia_codec_factory *factory, 
94
 
                                      pjmedia_codec *codec );
95
 
 
96
 
/* Prototypes for AMR implementation. */
97
 
static pj_status_t  amr_codec_init(pjmedia_codec *codec, 
98
 
                                    pj_pool_t *pool );
99
 
static pj_status_t  amr_codec_open(pjmedia_codec *codec, 
100
 
                                    pjmedia_codec_param *attr );
101
 
static pj_status_t  amr_codec_close(pjmedia_codec *codec );
102
 
static pj_status_t  amr_codec_modify(pjmedia_codec *codec, 
103
 
                                      const pjmedia_codec_param *attr );
104
 
static 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[]);
110
 
static 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);
114
 
static 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);
118
 
static 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. */
125
 
static 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. */
138
 
static 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 */
150
 
static 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. */
160
 
struct 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. */
178
 
enum
179
 
{
180
 
    IDX_AMR_NB, /* Index for narrowband.    */
181
 
    IDX_AMR_WB  /* Index for wideband.      */
182
 
};
183
 
 
184
 
static 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
 
 
194
 
static const pj_uint16_t* amr_bitrates[2] =
195
 
    {pjmedia_codec_amrnb_bitrates, pjmedia_codec_amrwb_bitrates};
196
 
 
197
 
static 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
 
 */
207
 
PJ_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
 
 
261
 
on_error:
262
 
    pj_pool_release(amr_codec_factory.pool);
263
 
    amr_codec_factory.pool = NULL;
264
 
    return status;
265
 
}
266
 
 
267
 
PJ_DEF(pj_status_t)
268
 
pjmedia_codec_opencore_amr_init_default( pjmedia_endpt *endpt )
269
 
{
270
 
    return pjmedia_codec_opencore_amr_init(endpt, 0);
271
 
}
272
 
 
273
 
PJ_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
 
 */
283
 
PJ_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
 
 
313
 
PJ_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
 
 
327
 
static pj_status_t
328
 
amr_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
 
 
354
 
PJ_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
 
 
360
 
PJ_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
 
 */
369
 
static 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
 
 */
405
 
static 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 = 2;
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
 
 */
442
 
static 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
 
 */
478
 
static 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
 
 */
521
 
static 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
 
 */
543
 
static 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
 
 */
555
 
static 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
 
 */
682
 
static 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
 
 */
725
 
static 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
 
 */
763
 
static 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
 
 */
795
 
static 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
 
    int size;
812
 
 
813
 
    pj_assert(amr_data != NULL);
814
 
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
815
 
 
816
 
    nsamples = input->size >> 1;
817
 
    samples_per_frame = amr_data->clock_rate * FRAME_LENGTH_MS / 1000;
818
 
    PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0, 
819
 
                     PJMEDIA_CODEC_EPCMFRMINLEN);
820
 
 
821
 
    nframes = nsamples / samples_per_frame;
822
 
    PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET, 
823
 
                     PJMEDIA_CODEC_EFRMTOOSHORT);
824
 
 
825
 
    /* Encode the frames */
826
 
    speech = (pj_int16_t*)input->buf;
827
 
    bitstream = (unsigned char*)output->buf;
828
 
    while (nsamples >= samples_per_frame) {
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
 
#endif
835
 
        } else {
836
 
#ifdef USE_AMRWB
837
 
            size = E_IF_encode (amr_data->encoder, amr_data->enc_mode,
838
 
                                speech, bitstream, 0);
839
 
#endif
840
 
        }
841
 
        if (size == 0) {
842
 
            output->size = 0;
843
 
            output->buf = NULL;
844
 
            output->type = PJMEDIA_FRAME_TYPE_NONE;
845
 
            TRACE_((THIS_FILE, "AMR encode() failed"));
846
 
            return PJMEDIA_CODEC_EFAILED;
847
 
        }
848
 
        nsamples -= samples_per_frame;
849
 
        speech += samples_per_frame;
850
 
        bitstream += size;
851
 
        out_size += size;
852
 
        TRACE_((THIS_FILE, "AMR encode(): mode=%d, size=%d",
853
 
                amr_data->enc_mode, out_size));
854
 
    }
855
 
 
856
 
    /* Pack payload */
857
 
    p = (pj_uint8_t*)output->buf + output_buf_len - out_size;
858
 
    pj_memmove(p, output->buf, out_size);
859
 
    dtx_cnt = sid_cnt = 0;
860
 
    for (i = 0; i < nframes; ++i) {
861
 
        pjmedia_codec_amr_bit_info *info = (pjmedia_codec_amr_bit_info*)
862
 
                                           &frames[i].bit_info;
863
 
        info->frame_type = (pj_uint8_t)((*p >> 3) & 0x0F);
864
 
        info->good_quality = (pj_uint8_t)((*p >> 2) & 0x01);
865
 
        info->mode = (pj_int8_t)amr_data->enc_mode;
866
 
        info->start_bit = 0;
867
 
        frames[i].buf = p + 1;
868
 
        if (amr_data->enc_setting.amr_nb) {
869
 
            frames[i].size = (info->frame_type <= 8)?
870
 
                             pjmedia_codec_amrnb_framelen[info->frame_type] : 0;
871
 
        } else {
872
 
            frames[i].size = (info->frame_type <= 9)?
873
 
                             pjmedia_codec_amrwb_framelen[info->frame_type] : 0;
874
 
        }
875
 
        p += frames[i].size + 1;
876
 
 
877
 
        /* Count the number of SID and DTX frames */
878
 
        if (info->frame_type == 15) /* DTX*/
879
 
            ++dtx_cnt;
880
 
        else if (info->frame_type == 8) /* SID */
881
 
            ++sid_cnt;
882
 
    }
883
 
 
884
 
    /* VA generates DTX frames as DTX+SID frames switching quickly and it
885
 
     * seems that the SID frames occur too often (assuming the purpose is 
886
 
     * only for keeping NAT alive?). So let's modify the behavior a bit.
887
 
     * Only an SID frame will be sent every PJMEDIA_CODEC_MAX_SILENCE_PERIOD
888
 
     * milliseconds.
889
 
     */
890
 
    if (sid_cnt + dtx_cnt == nframes) {
891
 
        pj_int32_t dtx_duration;
892
 
 
893
 
        dtx_duration = pj_timestamp_diff32(&amr_data->last_tx, 
894
 
                                           &input->timestamp);
895
 
        if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
896
 
            dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*
897
 
                           amr_data->clock_rate/1000)
898
 
        {
899
 
            output->size = 0;
900
 
            output->type = PJMEDIA_FRAME_TYPE_NONE;
901
 
            output->timestamp = input->timestamp;
902
 
            return PJ_SUCCESS;
903
 
        }
904
 
    }
905
 
 
906
 
    payload_len = output_buf_len;
907
 
 
908
 
    status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting,
909
 
                                    output->buf, &payload_len);
910
 
    if (status != PJ_SUCCESS) {
911
 
        output->size = 0;
912
 
        output->buf = NULL;
913
 
        output->type = PJMEDIA_FRAME_TYPE_NONE;
914
 
        TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status));
915
 
        return status;
916
 
    }
917
 
 
918
 
    output->size = payload_len;
919
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
920
 
    output->timestamp = input->timestamp;
921
 
 
922
 
    amr_data->last_tx = input->timestamp;
923
 
 
924
 
    return PJ_SUCCESS;
925
 
}
926
 
 
927
 
 
928
 
/*
929
 
 * Decode frame.
930
 
 */
931
 
static pj_status_t amr_codec_decode( pjmedia_codec *codec, 
932
 
                                     const struct pjmedia_frame *input,
933
 
                                     unsigned output_buf_len, 
934
 
                                     struct pjmedia_frame *output)
935
 
{
936
 
    struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
937
 
    pjmedia_frame input_;
938
 
    pjmedia_codec_amr_bit_info *info;
939
 
    unsigned out_size;
940
 
    /* AMR decoding buffer: AMR max frame size + 1 byte header. */
941
 
    unsigned char bitstream[61];
942
 
 
943
 
    pj_assert(amr_data != NULL);
944
 
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
945
 
 
946
 
    out_size = amr_data->clock_rate * FRAME_LENGTH_MS / 1000 * 2;
947
 
    if (output_buf_len < out_size)
948
 
        return PJMEDIA_CODEC_EPCMTOOSHORT;
949
 
 
950
 
    input_.buf = &bitstream[1];
951
 
    /* AMR max frame size */
952
 
    input_.size = (amr_data->dec_setting.amr_nb? 31: 60);
953
 
    pjmedia_codec_amr_predecode(input, &amr_data->dec_setting, &input_);
954
 
    info = (pjmedia_codec_amr_bit_info*)&input_.bit_info;
955
 
 
956
 
    /* VA AMR decoder requires frame info in the first byte. */
957
 
    bitstream[0] = (info->frame_type << 3) | (info->good_quality << 2);
958
 
 
959
 
    TRACE_((THIS_FILE, "AMR decode(): mode=%d, ft=%d, size=%d",
960
 
            info->mode, info->frame_type, input_.size));
961
 
 
962
 
    /* Decode */
963
 
    if (amr_data->dec_setting.amr_nb) {
964
 
#ifdef USE_AMRNB
965
 
        Decoder_Interface_Decode(amr_data->decoder, bitstream,
966
 
                                 (pj_int16_t*)output->buf, 0);
967
 
#endif
968
 
    } else {
969
 
#ifdef USE_AMRWB
970
 
        D_IF_decode(amr_data->decoder, bitstream,
971
 
                    (pj_int16_t*)output->buf, 0);
972
 
#endif
973
 
    }
974
 
 
975
 
    output->size = out_size;
976
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
977
 
    output->timestamp = input->timestamp;
978
 
 
979
 
#if USE_PJMEDIA_PLC
980
 
    if (amr_data->plc_enabled)
981
 
        pjmedia_plc_save(amr_data->plc, (pj_int16_t*)output->buf);
982
 
#endif
983
 
 
984
 
    return PJ_SUCCESS;
985
 
}
986
 
 
987
 
 
988
 
/*
989
 
 * Recover lost frame.
990
 
 */
991
 
#if USE_PJMEDIA_PLC
992
 
/*
993
 
 * Recover lost frame.
994
 
 */
995
 
static pj_status_t  amr_codec_recover( pjmedia_codec *codec,
996
 
                                       unsigned output_buf_len,
997
 
                                       struct pjmedia_frame *output)
998
 
{
999
 
    struct amr_data *amr_data = codec->codec_data;
1000
 
    unsigned out_size = amr_data->clock_rate * FRAME_LENGTH_MS / 1000 * 2;
1001
 
 
1002
 
    TRACE_((THIS_FILE, "amr_codec_recover"));
1003
 
 
1004
 
    PJ_ASSERT_RETURN(amr_data->plc_enabled, PJ_EINVALIDOP);
1005
 
 
1006
 
    PJ_ASSERT_RETURN(output_buf_len >= out_size,  PJMEDIA_CODEC_EPCMTOOSHORT);
1007
 
 
1008
 
    pjmedia_plc_generate(amr_data->plc, (pj_int16_t*)output->buf);
1009
 
 
1010
 
    output->size = out_size;
1011
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1012
 
    
1013
 
    return PJ_SUCCESS;
1014
 
}
1015
 
#endif
1016
 
 
1017
 
#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS
1018
 
#   if PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC
1019
 
#       ifdef USE_AMRNB
1020
 
#           pragma comment( lib, "libopencore-amrnb.a")
1021
 
#       endif
1022
 
#       ifdef USE_AMRWB
1023
 
#           pragma comment( lib, "libopencore-amrwb.a")
1024
 
#           pragma comment( lib, "libvo-amrwbenc.a")
1025
 
#       endif
1026
 
#   else
1027
 
#       error Unsupported OpenCORE AMR library, fix here
1028
 
#   endif
1029
 
#endif
1030
 
 
1031
 
#endif