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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjmedia/src/pjmedia-codec/opencore_amrnb.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_amrnb.c 3939 2012-01-10 05:38:40Z nanang $ */
2
 
/*
3
 
 * Copyright (C) 2011 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-NB codec implementation with OpenCORE AMRNB 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
 
 
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>
46
 
 
47
 
#define THIS_FILE "opencore_amrnb.c"
48
 
 
49
 
/* Tracing */
50
 
#define PJ_TRACE    0
51
 
 
52
 
#if PJ_TRACE
53
 
#   define TRACE_(expr) PJ_LOG(4,expr)
54
 
#else
55
 
#   define TRACE_(expr)
56
 
#endif
57
 
 
58
 
/* Use PJMEDIA PLC */
59
 
#define USE_PJMEDIA_PLC     1
60
 
 
61
 
 
62
 
 
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,
70
 
                                    unsigned *count,
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 );
77
 
 
78
 
/* Prototypes for AMR-NB implementation. */
79
 
static pj_status_t  amr_codec_init(pjmedia_codec *codec,
80
 
                                    pj_pool_t *pool );
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,
87
 
                                     void *pkt,
88
 
                                     pj_size_t pkt_size,
89
 
                                     const pj_timestamp *ts,
90
 
                                     unsigned *frame_cnt,
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);
103
 
 
104
 
 
105
 
 
106
 
/* Definition for AMR-NB codec operations. */
107
 
static pjmedia_codec_op amr_op =
108
 
{
109
 
    &amr_codec_init,
110
 
    &amr_codec_open,
111
 
    &amr_codec_close,
112
 
    &amr_codec_modify,
113
 
    &amr_codec_parse,
114
 
    &amr_codec_encode,
115
 
    &amr_codec_decode,
116
 
    &amr_codec_recover
117
 
};
118
 
 
119
 
/* Definition for AMR-NB codec factory operations. */
120
 
static pjmedia_codec_factory_op amr_factory_op =
121
 
{
122
 
    &amr_test_alloc,
123
 
    &amr_default_attr,
124
 
    &amr_enum_codecs,
125
 
    &amr_alloc_codec,
126
 
    &amr_dealloc_codec,
127
 
    &pjmedia_codec_opencore_amrnb_deinit
128
 
};
129
 
 
130
 
 
131
 
/* AMR-NB factory */
132
 
static struct amr_codec_factory
133
 
{
134
 
    pjmedia_codec_factory    base;
135
 
    pjmedia_endpt           *endpt;
136
 
    pj_pool_t               *pool;
137
 
} amr_codec_factory;
138
 
 
139
 
 
140
 
/* AMR-NB codec private data. */
141
 
struct amr_data
142
 
{
143
 
    pj_pool_t           *pool;
144
 
    void                *encoder;
145
 
    void                *decoder;
146
 
    pj_bool_t            plc_enabled;
147
 
    pj_bool_t            vad_enabled;
148
 
    int                  enc_mode;
149
 
    pjmedia_codec_amr_pack_setting enc_setting;
150
 
    pjmedia_codec_amr_pack_setting dec_setting;
151
 
#if USE_PJMEDIA_PLC
152
 
    pjmedia_plc         *plc;
153
 
#endif
154
 
    pj_timestamp         last_tx;
155
 
};
156
 
 
157
 
static pjmedia_codec_amrnb_config def_config =
158
 
{
159
 
    PJ_FALSE,       /* octet align      */
160
 
    5900            /* bitrate          */
161
 
};
162
 
 
163
 
 
164
 
 
165
 
/*
166
 
 * Initialize and register AMR-NB codec factory to pjmedia endpoint.
167
 
 */
168
 
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_init( pjmedia_endpt *endpt )
169
 
{
170
 
    pjmedia_codec_mgr *codec_mgr;
171
 
    pj_str_t codec_name;
172
 
    pj_status_t status;
173
 
 
174
 
    if (amr_codec_factory.pool != NULL)
175
 
        return PJ_SUCCESS;
176
 
 
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;
181
 
 
182
 
    amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amrnb", 1000,
183
 
                                                       1000);
184
 
    if (!amr_codec_factory.pool)
185
 
        return PJ_ENOMEM;
186
 
 
187
 
    /* Get the codec manager. */
188
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
189
 
    if (!codec_mgr) {
190
 
        status = PJ_EINVALIDOP;
191
 
        goto on_error;
192
 
    }
193
 
 
194
 
    /* Register format match callback. */
195
 
    pj_cstr(&codec_name, "AMR");
196
 
    status = pjmedia_sdp_neg_register_fmt_match_cb(
197
 
                                        &codec_name,
198
 
                                        &pjmedia_codec_amr_match_sdp);
199
 
    if (status != PJ_SUCCESS)
200
 
        goto on_error;
201
 
 
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)
206
 
        goto on_error;
207
 
 
208
 
    /* Done. */
209
 
    return PJ_SUCCESS;
210
 
 
211
 
on_error:
212
 
    pj_pool_release(amr_codec_factory.pool);
213
 
    amr_codec_factory.pool = NULL;
214
 
    return status;
215
 
}
216
 
 
217
 
 
218
 
/*
219
 
 * Unregister AMR-NB codec factory from pjmedia endpoint and deinitialize
220
 
 * the AMR-NB codec library.
221
 
 */
222
 
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_deinit(void)
223
 
{
224
 
    pjmedia_codec_mgr *codec_mgr;
225
 
    pj_status_t status;
226
 
 
227
 
    if (amr_codec_factory.pool == NULL)
228
 
        return PJ_SUCCESS;
229
 
 
230
 
    /* Get the codec manager. */
231
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(amr_codec_factory.endpt);
232
 
    if (!codec_mgr) {
233
 
        pj_pool_release(amr_codec_factory.pool);
234
 
        amr_codec_factory.pool = NULL;
235
 
        return PJ_EINVALIDOP;
236
 
    }
237
 
 
238
 
    /* Unregister AMR-NB codec factory. */
239
 
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
240
 
                                                  &amr_codec_factory.base);
241
 
 
242
 
    /* Destroy pool. */
243
 
    pj_pool_release(amr_codec_factory.pool);
244
 
    amr_codec_factory.pool = NULL;
245
 
 
246
 
    return status;
247
 
}
248
 
 
249
 
 
250
 
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_set_config(
251
 
                            const pjmedia_codec_amrnb_config *config)
252
 
{
253
 
    unsigned nbitrates;
254
 
 
255
 
 
256
 
    def_config = *config;
257
 
 
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];
264
 
    else
265
 
    {
266
 
        unsigned i;
267
 
 
268
 
        for (i = 0; i < nbitrates; ++i) {
269
 
            if (def_config.bitrate <= pjmedia_codec_amrnb_bitrates[i])
270
 
                break;
271
 
        }
272
 
        def_config.bitrate = pjmedia_codec_amrnb_bitrates[i];
273
 
    }
274
 
 
275
 
    return PJ_SUCCESS;
276
 
}
277
 
 
278
 
/*
279
 
 * Check if factory can allocate the specified codec.
280
 
 */
281
 
static pj_status_t amr_test_alloc( pjmedia_codec_factory *factory,
282
 
                                   const pjmedia_codec_info *info )
283
 
{
284
 
    PJ_UNUSED_ARG(factory);
285
 
 
286
 
    /* Check payload type. */
287
 
    if (info->pt != PJMEDIA_RTP_PT_AMR)
288
 
        return PJMEDIA_CODEC_EUNSUP;
289
 
 
290
 
    /* Ignore the rest, since it's static payload type. */
291
 
 
292
 
    return PJ_SUCCESS;
293
 
}
294
 
 
295
 
/*
296
 
 * Generate default attribute.
297
 
 */
298
 
static pj_status_t amr_default_attr( pjmedia_codec_factory *factory,
299
 
                                     const pjmedia_codec_info *id,
300
 
                                     pjmedia_codec_param *attr )
301
 
{
302
 
    PJ_UNUSED_ARG(factory);
303
 
    PJ_UNUSED_ARG(id);
304
 
 
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;
313
 
 
314
 
    attr->setting.frm_per_pkt = 2;
315
 
    attr->setting.vad = 1;
316
 
    attr->setting.plc = 1;
317
 
 
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");
322
 
    }
323
 
 
324
 
    /* Default all other flag bits disabled. */
325
 
 
326
 
    return PJ_SUCCESS;
327
 
}
328
 
 
329
 
 
330
 
/*
331
 
 * Enum codecs supported by this factory (i.e. only AMR-NB!).
332
 
 */
333
 
static pj_status_t amr_enum_codecs( pjmedia_codec_factory *factory,
334
 
                                    unsigned *count,
335
 
                                    pjmedia_codec_info codecs[])
336
 
{
337
 
    PJ_UNUSED_ARG(factory);
338
 
    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
339
 
 
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;
346
 
 
347
 
    *count = 1;
348
 
 
349
 
    return PJ_SUCCESS;
350
 
}
351
 
 
352
 
 
353
 
/*
354
 
 * Allocate a new AMR-NB codec instance.
355
 
 */
356
 
static pj_status_t amr_alloc_codec( pjmedia_codec_factory *factory,
357
 
                                    const pjmedia_codec_info *id,
358
 
                                    pjmedia_codec **p_codec)
359
 
{
360
 
    pj_pool_t *pool;
361
 
    pjmedia_codec *codec;
362
 
    struct amr_data *amr_data;
363
 
    pj_status_t status;
364
 
 
365
 
    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
366
 
    PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
367
 
 
368
 
    pool = pjmedia_endpt_create_pool(amr_codec_factory.endpt, "amrnb-inst",
369
 
                                     512, 512);
370
 
 
371
 
    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
372
 
    PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
373
 
    codec->op = &amr_op;
374
 
    codec->factory = factory;
375
 
 
376
 
    amr_data = PJ_POOL_ZALLOC_T(pool, struct amr_data);
377
 
    codec->codec_data = amr_data;
378
 
    amr_data->pool = pool;
379
 
 
380
 
#if USE_PJMEDIA_PLC
381
 
    /* Create PLC */
382
 
    status = pjmedia_plc_create(pool, 8000, 160, 0, &amr_data->plc);
383
 
    if (status != PJ_SUCCESS) {
384
 
        return status;
385
 
    }
386
 
#else
387
 
    PJ_UNUSED_ARG(status);
388
 
#endif
389
 
    *p_codec = codec;
390
 
    return PJ_SUCCESS;
391
 
}
392
 
 
393
 
 
394
 
/*
395
 
 * Free codec.
396
 
 */
397
 
static pj_status_t amr_dealloc_codec( pjmedia_codec_factory *factory,
398
 
                                      pjmedia_codec *codec )
399
 
{
400
 
    struct amr_data *amr_data;
401
 
 
402
 
    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
403
 
    PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
404
 
 
405
 
    amr_data = (struct amr_data*) codec->codec_data;
406
 
 
407
 
    /* Close codec, if it's not closed. */
408
 
    amr_codec_close(codec);
409
 
 
410
 
    pj_pool_release(amr_data->pool);
411
 
    amr_data = NULL;
412
 
 
413
 
    return PJ_SUCCESS;
414
 
}
415
 
 
416
 
/*
417
 
 * Init codec.
418
 
 */
419
 
static pj_status_t amr_codec_init( pjmedia_codec *codec,
420
 
                                   pj_pool_t *pool )
421
 
{
422
 
    PJ_UNUSED_ARG(codec);
423
 
    PJ_UNUSED_ARG(pool);
424
 
    return PJ_SUCCESS;
425
 
}
426
 
 
427
 
 
428
 
/*
429
 
 * Open codec.
430
 
 */
431
 
static pj_status_t amr_codec_open( pjmedia_codec *codec,
432
 
                                   pjmedia_codec_param *attr )
433
 
{
434
 
    struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
435
 
    pjmedia_codec_amr_pack_setting *setting;
436
 
    unsigned i;
437
 
    pj_uint8_t octet_align = 0;
438
 
    pj_int8_t enc_mode;
439
 
    const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
440
 
 
441
 
    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
442
 
    PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
443
 
 
444
 
    enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
445
 
    pj_assert(enc_mode >= 0 && enc_mode <= 7);
446
 
 
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)
451
 
        {
452
 
            octet_align = (pj_uint8_t)
453
 
                          (pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
454
 
            break;
455
 
        }
456
 
    }
457
 
 
458
 
    /* Check mode-set */
459
 
    for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
460
 
        const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
461
 
 
462
 
        if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
463
 
                       &STR_FMTP_MODE_SET) == 0)
464
 
        {
465
 
            const char *p;
466
 
            pj_size_t l;
467
 
            pj_int8_t diff = 99;
468
 
 
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.
475
 
             */
476
 
            p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
477
 
            l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
478
 
            while (l--) {
479
 
                if (*p>='0' && *p<='7') {
480
 
                    pj_int8_t tmp = *p - '0' - enc_mode;
481
 
 
482
 
                    if (PJ_ABS(diff) > PJ_ABS(tmp) ||
483
 
                        (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
484
 
                    {
485
 
                        diff = tmp;
486
 
                        if (diff == 0) break;
487
 
                    }
488
 
                }
489
 
                ++p;
490
 
            }
491
 
            PJ_ASSERT_RETURN(diff != 99, PJMEDIA_CODEC_EFAILED);
492
 
 
493
 
            enc_mode = enc_mode + diff;
494
 
 
495
 
            break;
496
 
        }
497
 
    }
498
 
 
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;
502
 
 
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;
508
 
    }
509
 
    setting = &amr_data->enc_setting;
510
 
    pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
511
 
    setting->amr_nb = 1;
512
 
    setting->reorder = 0;
513
 
    setting->octet_aligned = octet_align;
514
 
    setting->cmr = 15;
515
 
 
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;
521
 
    }
522
 
    setting = &amr_data->dec_setting;
523
 
    pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
524
 
    setting->amr_nb = 1;
525
 
    setting->reorder = 0;
526
 
    setting->octet_aligned = octet_align;
527
 
 
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]));
531
 
    return PJ_SUCCESS;
532
 
}
533
 
 
534
 
 
535
 
/*
536
 
 * Close codec.
537
 
 */
538
 
static pj_status_t amr_codec_close( pjmedia_codec *codec )
539
 
{
540
 
    struct amr_data *amr_data;
541
 
 
542
 
    PJ_ASSERT_RETURN(codec, PJ_EINVAL);
543
 
 
544
 
    amr_data = (struct amr_data*) codec->codec_data;
545
 
    PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
546
 
 
547
 
    if (amr_data->encoder) {
548
 
        Encoder_Interface_exit(amr_data->encoder);
549
 
        amr_data->encoder = NULL;
550
 
    }
551
 
 
552
 
    if (amr_data->decoder) {
553
 
        Decoder_Interface_exit(amr_data->decoder);
554
 
        amr_data->decoder = NULL;
555
 
    }
556
 
 
557
 
    TRACE_((THIS_FILE, "AMR-NB codec closed"));
558
 
    return PJ_SUCCESS;
559
 
}
560
 
 
561
 
 
562
 
/*
563
 
 * Modify codec settings.
564
 
 */
565
 
static pj_status_t amr_codec_modify( pjmedia_codec *codec,
566
 
                                     const pjmedia_codec_param *attr )
567
 
{
568
 
    struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
569
 
    pj_bool_t prev_vad_state;
570
 
 
571
 
    pj_assert(amr_data != NULL);
572
 
    pj_assert(amr_data->encoder != NULL && amr_data->decoder != NULL);
573
 
 
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);
577
 
 
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;
587
 
        }
588
 
    }
589
 
 
590
 
    TRACE_((THIS_FILE, "AMR-NB codec modified: vad=%d, plc=%d",
591
 
                        amr_data->vad_enabled, amr_data->plc_enabled));
592
 
    return PJ_SUCCESS;
593
 
}
594
 
 
595
 
 
596
 
/*
597
 
 * Get frames in the packet.
598
 
 */
599
 
static pj_status_t amr_codec_parse( pjmedia_codec *codec,
600
 
                                    void *pkt,
601
 
                                    pj_size_t pkt_size,
602
 
                                    const pj_timestamp *ts,
603
 
                                    unsigned *frame_cnt,
604
 
                                    pjmedia_frame frames[])
605
 
{
606
 
    struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
607
 
    pj_uint8_t cmr;
608
 
    pj_status_t status;
609
 
 
610
 
    status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, &amr_data->dec_setting,
611
 
                                     frames, frame_cnt, &cmr);
612
 
    if (status != PJ_SUCCESS)
613
 
        return status;
614
 
 
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)",
619
 
                            amr_data->enc_mode,
620
 
                            pjmedia_codec_amrnb_bitrates[amr_data->enc_mode]));
621
 
    }
622
 
 
623
 
    return PJ_SUCCESS;
624
 
}
625
 
 
626
 
 
627
 
/*
628
 
 * Encode frame.
629
 
 */
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)
634
 
{
635
 
    struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
636
 
    unsigned char *bitstream;
637
 
    pj_int16_t *speech;
638
 
    unsigned nsamples, samples_per_frame;
639
 
    enum {MAX_FRAMES_PER_PACKET = 16};
640
 
    pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
641
 
    pj_uint8_t *p;
642
 
    unsigned i, out_size = 0, nframes = 0;
643
 
    pj_size_t payload_len;
644
 
    unsigned dtx_cnt, sid_cnt;
645
 
    pj_status_t status;
646
 
    int size;
647
 
 
648
 
    pj_assert(amr_data != NULL);
649
 
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
650
 
 
651
 
    nsamples = input->size >> 1;
652
 
    samples_per_frame = 160;
653
 
    PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
654
 
                     PJMEDIA_CODEC_EPCMFRMINLEN);
655
 
 
656
 
    nframes = nsamples / samples_per_frame;
657
 
    PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET,
658
 
                     PJMEDIA_CODEC_EFRMTOOSHORT);
659
 
 
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);
666
 
        if (size == 0) {
667
 
            output->size = 0;
668
 
            output->buf = NULL;
669
 
            output->type = PJMEDIA_FRAME_TYPE_NONE;
670
 
            TRACE_((THIS_FILE, "AMR-NB encode() failed"));
671
 
            return PJMEDIA_CODEC_EFAILED;
672
 
        }
673
 
        nsamples -= 160;
674
 
        speech += samples_per_frame;
675
 
        bitstream += size;
676
 
        out_size += size;
677
 
        TRACE_((THIS_FILE, "AMR-NB encode(): mode=%d, size=%d",
678
 
                amr_data->enc_mode, out_size));
679
 
    }
680
 
 
681
 
    /* Pack payload */
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*)
687
 
                                           &frames[i].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;
691
 
        info->start_bit = 0;
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;
696
 
 
697
 
        /* Count the number of SID and DTX frames */
698
 
        if (info->frame_type == 15) /* DTX*/
699
 
            ++dtx_cnt;
700
 
        else if (info->frame_type == 8) /* SID */
701
 
            ++sid_cnt;
702
 
    }
703
 
 
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
708
 
     * milliseconds.
709
 
     */
710
 
    if (sid_cnt + dtx_cnt == nframes) {
711
 
        pj_int32_t dtx_duration;
712
 
 
713
 
        dtx_duration = pj_timestamp_diff32(&amr_data->last_tx,
714
 
                                           &input->timestamp);
715
 
        if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
716
 
            dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
717
 
        {
718
 
            output->size = 0;
719
 
            output->type = PJMEDIA_FRAME_TYPE_NONE;
720
 
            output->timestamp = input->timestamp;
721
 
            return PJ_SUCCESS;
722
 
        }
723
 
    }
724
 
 
725
 
    payload_len = output_buf_len;
726
 
 
727
 
    status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting,
728
 
                                    output->buf, &payload_len);
729
 
    if (status != PJ_SUCCESS) {
730
 
        output->size = 0;
731
 
        output->buf = NULL;
732
 
        output->type = PJMEDIA_FRAME_TYPE_NONE;
733
 
        TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status));
734
 
        return status;
735
 
    }
736
 
 
737
 
    output->size = payload_len;
738
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
739
 
    output->timestamp = input->timestamp;
740
 
 
741
 
    amr_data->last_tx = input->timestamp;
742
 
 
743
 
    return PJ_SUCCESS;
744
 
}
745
 
 
746
 
 
747
 
/*
748
 
 * Decode frame.
749
 
 */
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)
754
 
{
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];
760
 
 
761
 
    pj_assert(amr_data != NULL);
762
 
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
763
 
 
764
 
    if (output_buf_len < 320)
765
 
        return PJMEDIA_CODEC_EPCMTOOSHORT;
766
 
 
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;
771
 
 
772
 
    /* VA AMRNB decoder requires frame info in the first byte. */
773
 
    bitstream[0] = (info->frame_type << 3) | (info->good_quality << 2);
774
 
 
775
 
    TRACE_((THIS_FILE, "AMR-NB decode(): mode=%d, ft=%d, size=%d",
776
 
            info->mode, info->frame_type, input_.size));
777
 
 
778
 
    /* Decode */
779
 
    Decoder_Interface_Decode(amr_data->decoder, bitstream,
780
 
                             (pj_int16_t*)output->buf, 0);
781
 
 
782
 
    output->size = 320;
783
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
784
 
    output->timestamp = input->timestamp;
785
 
 
786
 
#if USE_PJMEDIA_PLC
787
 
    if (amr_data->plc_enabled)
788
 
        pjmedia_plc_save(amr_data->plc, (pj_int16_t*)output->buf);
789
 
#endif
790
 
 
791
 
    return PJ_SUCCESS;
792
 
}
793
 
 
794
 
 
795
 
/*
796
 
 * Recover lost frame.
797
 
 */
798
 
#if USE_PJMEDIA_PLC
799
 
/*
800
 
 * Recover lost frame.
801
 
 */
802
 
static pj_status_t  amr_codec_recover( pjmedia_codec *codec,
803
 
                                       unsigned output_buf_len,
804
 
                                       struct pjmedia_frame *output)
805
 
{
806
 
    struct amr_data *amr_data = codec->codec_data;
807
 
 
808
 
    TRACE_((THIS_FILE, "amr_codec_recover"));
809
 
 
810
 
    PJ_ASSERT_RETURN(amr_data->plc_enabled, PJ_EINVALIDOP);
811
 
 
812
 
    PJ_ASSERT_RETURN(output_buf_len >= 320,  PJMEDIA_CODEC_EPCMTOOSHORT);
813
 
 
814
 
    pjmedia_plc_generate(amr_data->plc, (pj_int16_t*)output->buf);
815
 
 
816
 
    output->size = 320;
817
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
818
 
 
819
 
    return PJ_SUCCESS;
820
 
}
821
 
#endif
822
 
 
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")
826
 
#  else
827
 
#   error Unsupported OpenCORE AMR library, fix here
828
 
#  endif
829
 
#endif
830
 
 
831
 
#endif