~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): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

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