~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/speex_codec.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: speex_codec.c 3664 2011-07-19 03:42:28Z nanang $ */
2
 
/*
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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
 
#include <pjmedia-codec/speex.h>
22
 
#include <pjmedia/codec.h>
23
 
#include <pjmedia/errno.h>
24
 
#include <pjmedia/endpoint.h>
25
 
#include <pjmedia/port.h>
26
 
#include <speex/speex.h>
27
 
#include <pj/assert.h>
28
 
#include <pj/log.h>
29
 
#include <pj/pool.h>
30
 
#include <pj/string.h>
31
 
#include <pj/os.h>
32
 
 
33
 
/*
34
 
 * Only build this file if PJMEDIA_HAS_SPEEX_CODEC != 0
35
 
 */
36
 
#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
37
 
 
38
 
 
39
 
#define THIS_FILE   "speex_codec.c"
40
 
 
41
 
/* Prototypes for Speex factory */
42
 
static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory,
43
 
                                   const pjmedia_codec_info *id );
44
 
static pj_status_t spx_default_attr( pjmedia_codec_factory *factory,
45
 
                                     const pjmedia_codec_info *id,
46
 
                                     pjmedia_codec_param *attr );
47
 
static pj_status_t spx_enum_codecs( pjmedia_codec_factory *factory,
48
 
                                    unsigned *count,
49
 
                                    pjmedia_codec_info codecs[]);
50
 
static pj_status_t spx_alloc_codec( pjmedia_codec_factory *factory,
51
 
                                    const pjmedia_codec_info *id,
52
 
                                    pjmedia_codec **p_codec);
53
 
static pj_status_t spx_dealloc_codec( pjmedia_codec_factory *factory,
54
 
                                      pjmedia_codec *codec );
55
 
 
56
 
/* Prototypes for Speex implementation. */
57
 
static pj_status_t  spx_codec_init( pjmedia_codec *codec,
58
 
                                    pj_pool_t *pool );
59
 
static pj_status_t  spx_codec_open( pjmedia_codec *codec,
60
 
                                    pjmedia_codec_param *attr );
61
 
static pj_status_t  spx_codec_close( pjmedia_codec *codec );
62
 
static pj_status_t  spx_codec_modify(pjmedia_codec *codec,
63
 
                                     const pjmedia_codec_param *attr );
64
 
static pj_status_t  spx_codec_parse( pjmedia_codec *codec,
65
 
                                     void *pkt,
66
 
                                     pj_size_t pkt_size,
67
 
                                     const pj_timestamp *ts,
68
 
                                     unsigned *frame_cnt,
69
 
                                     pjmedia_frame frames[]);
70
 
static pj_status_t  spx_codec_encode( pjmedia_codec *codec,
71
 
                                      const struct pjmedia_frame *input,
72
 
                                      unsigned output_buf_len,
73
 
                                      struct pjmedia_frame *output);
74
 
static pj_status_t  spx_codec_decode( pjmedia_codec *codec,
75
 
                                      const struct pjmedia_frame *input,
76
 
                                      unsigned output_buf_len,
77
 
                                      struct pjmedia_frame *output);
78
 
static pj_status_t  spx_codec_recover(pjmedia_codec *codec,
79
 
                                      unsigned output_buf_len,
80
 
                                      struct pjmedia_frame *output);
81
 
 
82
 
/* Definition for Speex codec operations. */
83
 
static pjmedia_codec_op spx_op =
84
 
{
85
 
    &spx_codec_init,
86
 
    &spx_codec_open,
87
 
    &spx_codec_close,
88
 
    &spx_codec_modify,
89
 
    &spx_codec_parse,
90
 
    &spx_codec_encode,
91
 
    &spx_codec_decode,
92
 
    &spx_codec_recover
93
 
};
94
 
 
95
 
/* Definition for Speex codec factory operations. */
96
 
static pjmedia_codec_factory_op spx_factory_op =
97
 
{
98
 
    &spx_test_alloc,
99
 
    &spx_default_attr,
100
 
    &spx_enum_codecs,
101
 
    &spx_alloc_codec,
102
 
    &spx_dealloc_codec,
103
 
    &pjmedia_codec_speex_deinit
104
 
};
105
 
 
106
 
/* Index to Speex parameter. */
107
 
enum
108
 
{
109
 
    PARAM_NB,   /* Index for narrowband parameter.      */
110
 
    PARAM_WB,   /* Index for wideband parameter.        */
111
 
    PARAM_UWB,  /* Index for ultra-wideband parameter   */
112
 
};
113
 
 
114
 
/* Speex default parameter */
115
 
struct speex_param
116
 
{
117
 
    int              enabled;           /* Is this mode enabled?            */
118
 
    const SpeexMode *mode;              /* Speex mode.                      */
119
 
    int              pt;                /* Payload type.                    */
120
 
    unsigned         clock_rate;        /* Default sampling rate to be used.*/
121
 
    int              quality;           /* Default encoder quality.         */
122
 
    int              complexity;        /* Default encoder complexity.      */
123
 
    int              samples_per_frame; /* Samples per frame.               */
124
 
    int              framesize;         /* Frame size for current mode.     */
125
 
    int              bitrate;           /* Bit rate for current mode.       */
126
 
    int              max_bitrate;       /* Max bit rate for current mode.   */
127
 
};
128
 
 
129
 
/* Speex factory */
130
 
static struct spx_factory
131
 
{
132
 
    pjmedia_codec_factory    base;
133
 
    pjmedia_endpt           *endpt;
134
 
    pj_pool_t               *pool;
135
 
    pj_mutex_t              *mutex;
136
 
    pjmedia_codec            codec_list;
137
 
    struct speex_param       speex_param[3];
138
 
 
139
 
} spx_factory;
140
 
 
141
 
/* Speex codec private data. */
142
 
struct spx_private
143
 
{
144
 
    int                  param_id;          /**< Index to speex param.  */
145
 
 
146
 
    void                *enc;               /**< Encoder state.         */
147
 
    SpeexBits            enc_bits;          /**< Encoder bits.          */
148
 
    void                *dec;               /**< Decoder state.         */
149
 
    SpeexBits            dec_bits;          /**< Decoder bits.          */
150
 
};
151
 
 
152
 
 
153
 
/*
154
 
 * Get codec bitrate and frame size.
155
 
 */
156
 
static pj_status_t get_speex_info( struct speex_param *p )
157
 
{
158
 
    void *state;
159
 
    int tmp;
160
 
 
161
 
    /* Create temporary encoder */
162
 
    state = speex_encoder_init(p->mode);
163
 
    if (!state)
164
 
        return PJMEDIA_CODEC_EFAILED;
165
 
 
166
 
    /* Set the quality */
167
 
    if (p->quality != -1)
168
 
        speex_encoder_ctl(state, SPEEX_SET_QUALITY, &p->quality);
169
 
 
170
 
    /* Sampling rate. */
171
 
    speex_encoder_ctl(state, SPEEX_SET_SAMPLING_RATE, &p->clock_rate);
172
 
 
173
 
    /* VAD off to have max bitrate */
174
 
    tmp = 0;
175
 
    speex_encoder_ctl(state, SPEEX_SET_VAD, &tmp);
176
 
 
177
 
    /* Complexity. */
178
 
    if (p->complexity != -1)
179
 
        speex_encoder_ctl(state, SPEEX_SET_COMPLEXITY, &p->complexity);
180
 
 
181
 
    /* Now get the frame size */
182
 
    speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &p->samples_per_frame);
183
 
 
184
 
    /* Now get the average bitrate */
185
 
    speex_encoder_ctl(state, SPEEX_GET_BITRATE, &p->bitrate);
186
 
 
187
 
    /* Calculate framesize. */
188
 
    p->framesize = p->bitrate * 20 / 1000;
189
 
 
190
 
    /* Now get the maximum bitrate by using maximum quality (=10) */
191
 
    tmp = 10;
192
 
    speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);
193
 
    speex_encoder_ctl(state, SPEEX_GET_BITRATE, &p->max_bitrate);
194
 
 
195
 
    /* Destroy encoder. */
196
 
    speex_encoder_destroy(state);
197
 
 
198
 
    return PJ_SUCCESS;
199
 
}
200
 
 
201
 
/*
202
 
 * Initialize and register Speex codec factory to pjmedia endpoint.
203
 
 */
204
 
PJ_DEF(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt,
205
 
                                              unsigned options,
206
 
                                              int quality,
207
 
                                              int complexity )
208
 
{
209
 
    pjmedia_codec_mgr *codec_mgr;
210
 
    unsigned i;
211
 
    pj_status_t status;
212
 
 
213
 
    if (spx_factory.pool != NULL) {
214
 
        /* Already initialized. */
215
 
        return PJ_SUCCESS;
216
 
    }
217
 
 
218
 
    /* Get defaults */
219
 
    if (quality < 0) quality = PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY;
220
 
    if (complexity < 0) complexity = PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY;
221
 
 
222
 
    /* Validate quality & complexity */
223
 
    PJ_ASSERT_RETURN(quality >= 0 && quality <= 10, PJ_EINVAL);
224
 
    PJ_ASSERT_RETURN(complexity >= 1 && complexity <= 10, PJ_EINVAL);
225
 
 
226
 
    /* Create Speex codec factory. */
227
 
    spx_factory.base.op = &spx_factory_op;
228
 
    spx_factory.base.factory_data = NULL;
229
 
    spx_factory.endpt = endpt;
230
 
 
231
 
    spx_factory.pool = pjmedia_endpt_create_pool(endpt, "speex",
232
 
                                                       4000, 4000);
233
 
    if (!spx_factory.pool)
234
 
        return PJ_ENOMEM;
235
 
 
236
 
    pj_list_init(&spx_factory.codec_list);
237
 
 
238
 
    /* Create mutex. */
239
 
    status = pj_mutex_create_simple(spx_factory.pool, "speex",
240
 
                                    &spx_factory.mutex);
241
 
    if (status != PJ_SUCCESS)
242
 
        goto on_error;
243
 
 
244
 
    /* Initialize default Speex parameter. */
245
 
    spx_factory.speex_param[PARAM_NB].enabled =
246
 
        ((options & PJMEDIA_SPEEX_NO_NB) == 0);
247
 
    spx_factory.speex_param[PARAM_NB].pt = PJMEDIA_RTP_PT_SPEEX_NB;
248
 
    spx_factory.speex_param[PARAM_NB].mode = speex_lib_get_mode(SPEEX_MODEID_NB);
249
 
    spx_factory.speex_param[PARAM_NB].clock_rate = 8000;
250
 
    spx_factory.speex_param[PARAM_NB].quality = quality;
251
 
    spx_factory.speex_param[PARAM_NB].complexity = complexity;
252
 
 
253
 
    spx_factory.speex_param[PARAM_WB].enabled =
254
 
        ((options & PJMEDIA_SPEEX_NO_WB) == 0);
255
 
    spx_factory.speex_param[PARAM_WB].pt = PJMEDIA_RTP_PT_SPEEX_WB;
256
 
    spx_factory.speex_param[PARAM_WB].mode = speex_lib_get_mode(SPEEX_MODEID_WB);
257
 
    spx_factory.speex_param[PARAM_WB].clock_rate = 16000;
258
 
    spx_factory.speex_param[PARAM_WB].quality = quality;
259
 
    spx_factory.speex_param[PARAM_WB].complexity = complexity;
260
 
 
261
 
    spx_factory.speex_param[PARAM_UWB].enabled =
262
 
        ((options & PJMEDIA_SPEEX_NO_UWB) == 0);
263
 
    spx_factory.speex_param[PARAM_UWB].pt = PJMEDIA_RTP_PT_SPEEX_UWB;
264
 
    spx_factory.speex_param[PARAM_UWB].mode = speex_lib_get_mode(SPEEX_MODEID_UWB);
265
 
    spx_factory.speex_param[PARAM_UWB].clock_rate = 32000;
266
 
    spx_factory.speex_param[PARAM_UWB].quality = quality;
267
 
    spx_factory.speex_param[PARAM_UWB].complexity = complexity;
268
 
 
269
 
    /* Somehow quality <=4 is broken in linux. */
270
 
    if (quality <= 4 && quality >= 0) {
271
 
        PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb"));
272
 
        spx_factory.speex_param[PARAM_UWB].quality = 5;
273
 
    }
274
 
 
275
 
    /* Get codec framesize and avg bitrate for each mode. */
276
 
    for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) {
277
 
        status = get_speex_info(&spx_factory.speex_param[i]);
278
 
    }
279
 
 
280
 
    /* Get the codec manager. */
281
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
282
 
    if (!codec_mgr) {
283
 
        status = PJ_EINVALIDOP;
284
 
        goto on_error;
285
 
    }
286
 
 
287
 
    /* Register codec factory to endpoint. */
288
 
    status = pjmedia_codec_mgr_register_factory(codec_mgr,
289
 
                                                &spx_factory.base);
290
 
    if (status != PJ_SUCCESS)
291
 
        goto on_error;
292
 
 
293
 
    /* Done. */
294
 
    return PJ_SUCCESS;
295
 
 
296
 
on_error:
297
 
    pj_pool_release(spx_factory.pool);
298
 
    spx_factory.pool = NULL;
299
 
    return status;
300
 
}
301
 
 
302
 
 
303
 
/*
304
 
 * Initialize with default settings.
305
 
 */
306
 
PJ_DEF(pj_status_t) pjmedia_codec_speex_init_default(pjmedia_endpt *endpt)
307
 
{
308
 
    return pjmedia_codec_speex_init(endpt, 0, -1, -1);
309
 
}
310
 
 
311
 
/*
312
 
 * Change the settings of Speex codec.
313
 
 */
314
 
PJ_DEF(pj_status_t) pjmedia_codec_speex_set_param(unsigned clock_rate,
315
 
                                                  int quality,
316
 
                                                  int complexity)
317
 
{
318
 
    unsigned i;
319
 
 
320
 
    /* Get defaults */
321
 
    if (quality < 0) quality = PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY;
322
 
    if (complexity < 0) complexity = PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY;
323
 
 
324
 
    /* Validate quality & complexity */
325
 
    PJ_ASSERT_RETURN(quality >= 0 && quality <= 10, PJ_EINVAL);
326
 
    PJ_ASSERT_RETURN(complexity >= 1 && complexity <= 10, PJ_EINVAL);
327
 
 
328
 
    /* Apply the settings */
329
 
    for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) {
330
 
        if (spx_factory.speex_param[i].clock_rate == clock_rate) {
331
 
            pj_status_t status;
332
 
 
333
 
            spx_factory.speex_param[i].quality = quality;
334
 
            spx_factory.speex_param[i].complexity = complexity;
335
 
 
336
 
            /* Somehow quality<=4 is broken in linux. */
337
 
            if (i == PARAM_UWB && quality <= 4 && quality >= 0) {
338
 
                PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb"));
339
 
                spx_factory.speex_param[PARAM_UWB].quality = 5;
340
 
            }
341
 
 
342
 
            status = get_speex_info(&spx_factory.speex_param[i]);
343
 
 
344
 
            return status;
345
 
        }
346
 
    }
347
 
 
348
 
    return PJ_EINVAL;
349
 
}
350
 
 
351
 
/*
352
 
 * Unregister Speex codec factory from pjmedia endpoint and deinitialize
353
 
 * the Speex codec library.
354
 
 */
355
 
PJ_DEF(pj_status_t) pjmedia_codec_speex_deinit(void)
356
 
{
357
 
    pjmedia_codec_mgr *codec_mgr;
358
 
    pj_status_t status;
359
 
 
360
 
    if (spx_factory.pool == NULL) {
361
 
        /* Already deinitialized */
362
 
        return PJ_SUCCESS;
363
 
    }
364
 
 
365
 
    pj_mutex_lock(spx_factory.mutex);
366
 
 
367
 
    /* We don't want to deinit if there's outstanding codec. */
368
 
    /* This is silly, as we'll always have codec in the list if
369
 
       we ever allocate a codec! A better behavior maybe is to
370
 
       deallocate all codecs in the list.
371
 
    if (!pj_list_empty(&spx_factory.codec_list)) {
372
 
        pj_mutex_unlock(spx_factory.mutex);
373
 
        return PJ_EBUSY;
374
 
    }
375
 
    */
376
 
 
377
 
    /* Get the codec manager. */
378
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(spx_factory.endpt);
379
 
    if (!codec_mgr) {
380
 
        pj_pool_release(spx_factory.pool);
381
 
        spx_factory.pool = NULL;
382
 
        return PJ_EINVALIDOP;
383
 
    }
384
 
 
385
 
    /* Unregister Speex codec factory. */
386
 
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
387
 
                                                  &spx_factory.base);
388
 
 
389
 
    /* Destroy mutex. */
390
 
    pj_mutex_destroy(spx_factory.mutex);
391
 
 
392
 
    /* Destroy pool. */
393
 
    pj_pool_release(spx_factory.pool);
394
 
    spx_factory.pool = NULL;
395
 
 
396
 
    return status;
397
 
}
398
 
 
399
 
/*
400
 
 * Check if factory can allocate the specified codec.
401
 
 */
402
 
static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory,
403
 
                                   const pjmedia_codec_info *info )
404
 
{
405
 
    const pj_str_t speex_tag = { "speex", 5};
406
 
    unsigned i;
407
 
 
408
 
    PJ_UNUSED_ARG(factory);
409
 
 
410
 
    /* Type MUST be audio. */
411
 
    if (info->type != PJMEDIA_TYPE_AUDIO)
412
 
        return PJMEDIA_CODEC_EUNSUP;
413
 
 
414
 
    /* Check encoding name. */
415
 
    if (pj_stricmp(&info->encoding_name, &speex_tag) != 0)
416
 
        return PJMEDIA_CODEC_EUNSUP;
417
 
 
418
 
    /* Check clock-rate */
419
 
    for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) {
420
 
        if (info->clock_rate == spx_factory.speex_param[i].clock_rate) {
421
 
            /* Okay, let's Speex! */
422
 
            return PJ_SUCCESS;
423
 
        }
424
 
    }
425
 
 
426
 
 
427
 
    /* Unsupported, or mode is disabled. */
428
 
    return PJMEDIA_CODEC_EUNSUP;
429
 
}
430
 
 
431
 
/*
432
 
 * Generate default attribute.
433
 
 */
434
 
static pj_status_t spx_default_attr (pjmedia_codec_factory *factory,
435
 
                                      const pjmedia_codec_info *id,
436
 
                                      pjmedia_codec_param *attr )
437
 
{
438
 
 
439
 
    PJ_ASSERT_RETURN(factory==&spx_factory.base, PJ_EINVAL);
440
 
 
441
 
    pj_bzero(attr, sizeof(pjmedia_codec_param));
442
 
    attr->info.pt = (pj_uint8_t)id->pt;
443
 
    attr->info.channel_cnt = 1;
444
 
 
445
 
    if (id->clock_rate <= 8000) {
446
 
        attr->info.clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate;
447
 
        attr->info.avg_bps = spx_factory.speex_param[PARAM_NB].bitrate;
448
 
        attr->info.max_bps = spx_factory.speex_param[PARAM_NB].max_bitrate;
449
 
 
450
 
    } else if (id->clock_rate <= 16000) {
451
 
        attr->info.clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate;
452
 
        attr->info.avg_bps = spx_factory.speex_param[PARAM_WB].bitrate;
453
 
        attr->info.max_bps = spx_factory.speex_param[PARAM_WB].max_bitrate;
454
 
 
455
 
    } else {
456
 
        /* Wow.. somebody is doing ultra-wideband. Cool...! */
457
 
        attr->info.clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate;
458
 
        attr->info.avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate;
459
 
        attr->info.max_bps = spx_factory.speex_param[PARAM_UWB].max_bitrate;
460
 
    }
461
 
 
462
 
    attr->info.pcm_bits_per_sample = 16;
463
 
    attr->info.frm_ptime = 20;
464
 
    attr->info.pt = (pj_uint8_t)id->pt;
465
 
 
466
 
    attr->setting.frm_per_pkt = 1;
467
 
 
468
 
    /* Default flags. */
469
 
    attr->setting.cng = 1;
470
 
    attr->setting.plc = 1;
471
 
    attr->setting.penh =1 ;
472
 
    attr->setting.vad = 1;
473
 
 
474
 
    return PJ_SUCCESS;
475
 
}
476
 
 
477
 
/*
478
 
 * Enum codecs supported by this factory (i.e. only Speex!).
479
 
 */
480
 
static pj_status_t spx_enum_codecs(pjmedia_codec_factory *factory,
481
 
                                    unsigned *count,
482
 
                                    pjmedia_codec_info codecs[])
483
 
{
484
 
    unsigned max;
485
 
    int i;  /* Must be signed */
486
 
 
487
 
    PJ_UNUSED_ARG(factory);
488
 
    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
489
 
 
490
 
    max = *count;
491
 
    *count = 0;
492
 
 
493
 
    /*
494
 
     * We return three codecs here, and in this order:
495
 
     *  - ultra-wideband, wideband, and narrowband.
496
 
     */
497
 
    for (i=PJ_ARRAY_SIZE(spx_factory.speex_param)-1; i>=0 && *count<max; --i) {
498
 
 
499
 
        if (!spx_factory.speex_param[i].enabled)
500
 
            continue;
501
 
 
502
 
        pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
503
 
        codecs[*count].encoding_name = pj_str("speex");
504
 
        codecs[*count].pt = spx_factory.speex_param[i].pt;
505
 
        codecs[*count].type = PJMEDIA_TYPE_AUDIO;
506
 
        codecs[*count].clock_rate = spx_factory.speex_param[i].clock_rate;
507
 
        codecs[*count].channel_cnt = 1;
508
 
 
509
 
        ++*count;
510
 
    }
511
 
 
512
 
    return PJ_SUCCESS;
513
 
}
514
 
 
515
 
/*
516
 
 * Allocate a new Speex codec instance.
517
 
 */
518
 
static pj_status_t spx_alloc_codec( pjmedia_codec_factory *factory,
519
 
                                    const pjmedia_codec_info *id,
520
 
                                    pjmedia_codec **p_codec)
521
 
{
522
 
    pjmedia_codec *codec;
523
 
    struct spx_private *spx;
524
 
 
525
 
    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
526
 
    PJ_ASSERT_RETURN(factory == &spx_factory.base, PJ_EINVAL);
527
 
 
528
 
 
529
 
    pj_mutex_lock(spx_factory.mutex);
530
 
 
531
 
    /* Get free nodes, if any. */
532
 
    if (!pj_list_empty(&spx_factory.codec_list)) {
533
 
        codec = spx_factory.codec_list.next;
534
 
        pj_list_erase(codec);
535
 
    } else {
536
 
        codec = PJ_POOL_ZALLOC_T(spx_factory.pool, pjmedia_codec);
537
 
        PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
538
 
        codec->op = &spx_op;
539
 
        codec->factory = factory;
540
 
        codec->codec_data = pj_pool_alloc(spx_factory.pool,
541
 
                                          sizeof(struct spx_private));
542
 
    }
543
 
 
544
 
    pj_mutex_unlock(spx_factory.mutex);
545
 
 
546
 
    spx = (struct spx_private*) codec->codec_data;
547
 
    spx->enc = NULL;
548
 
    spx->dec = NULL;
549
 
 
550
 
    if (id->clock_rate <= 8000)
551
 
        spx->param_id = PARAM_NB;
552
 
    else if (id->clock_rate <= 16000)
553
 
        spx->param_id = PARAM_WB;
554
 
    else
555
 
        spx->param_id = PARAM_UWB;
556
 
 
557
 
    *p_codec = codec;
558
 
    return PJ_SUCCESS;
559
 
}
560
 
 
561
 
/*
562
 
 * Free codec.
563
 
 */
564
 
static pj_status_t spx_dealloc_codec( pjmedia_codec_factory *factory,
565
 
                                      pjmedia_codec *codec )
566
 
{
567
 
    struct spx_private *spx;
568
 
 
569
 
    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
570
 
    PJ_ASSERT_RETURN(factory == &spx_factory.base, PJ_EINVAL);
571
 
 
572
 
    /* Close codec, if it's not closed. */
573
 
    spx = (struct spx_private*) codec->codec_data;
574
 
    if (spx->enc != NULL || spx->dec != NULL) {
575
 
        spx_codec_close(codec);
576
 
    }
577
 
 
578
 
    /* Put in the free list. */
579
 
    pj_mutex_lock(spx_factory.mutex);
580
 
    pj_list_push_front(&spx_factory.codec_list, codec);
581
 
    pj_mutex_unlock(spx_factory.mutex);
582
 
 
583
 
    return PJ_SUCCESS;
584
 
}
585
 
 
586
 
/*
587
 
 * Init codec.
588
 
 */
589
 
static pj_status_t spx_codec_init( pjmedia_codec *codec,
590
 
                                   pj_pool_t *pool )
591
 
{
592
 
    PJ_UNUSED_ARG(codec);
593
 
    PJ_UNUSED_ARG(pool);
594
 
    return PJ_SUCCESS;
595
 
}
596
 
 
597
 
/*
598
 
 * Open codec.
599
 
 */
600
 
static pj_status_t spx_codec_open( pjmedia_codec *codec,
601
 
                                   pjmedia_codec_param *attr )
602
 
{
603
 
    struct spx_private *spx;
604
 
    int id, tmp;
605
 
 
606
 
    spx = (struct spx_private*) codec->codec_data;
607
 
    id = spx->param_id;
608
 
 
609
 
    /*
610
 
     * Create and initialize encoder.
611
 
     */
612
 
    spx->enc = speex_encoder_init(spx_factory.speex_param[id].mode);
613
 
    if (!spx->enc)
614
 
        return PJMEDIA_CODEC_EFAILED;
615
 
    speex_bits_init(&spx->enc_bits);
616
 
 
617
 
    /* Set the quality*/
618
 
    if (spx_factory.speex_param[id].quality != -1) {
619
 
        speex_encoder_ctl(spx->enc, SPEEX_SET_QUALITY,
620
 
                          &spx_factory.speex_param[id].quality);
621
 
    }
622
 
 
623
 
    /* Sampling rate. */
624
 
    tmp = attr->info.clock_rate;
625
 
    speex_encoder_ctl(spx->enc, SPEEX_SET_SAMPLING_RATE,
626
 
                      &spx_factory.speex_param[id].clock_rate);
627
 
 
628
 
    /* VAD */
629
 
    tmp = (attr->setting.vad != 0);
630
 
    speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp);
631
 
    speex_encoder_ctl(spx->enc, SPEEX_SET_DTX, &tmp);
632
 
 
633
 
    /* Complexity */
634
 
    if (spx_factory.speex_param[id].complexity != -1) {
635
 
        speex_encoder_ctl(spx->enc, SPEEX_SET_COMPLEXITY,
636
 
                          &spx_factory.speex_param[id].complexity);
637
 
    }
638
 
 
639
 
    /*
640
 
     * Create and initialize decoder.
641
 
     */
642
 
    spx->dec = speex_decoder_init(spx_factory.speex_param[id].mode);
643
 
    if (!spx->dec) {
644
 
        spx_codec_close(codec);
645
 
        return PJMEDIA_CODEC_EFAILED;
646
 
    }
647
 
    speex_bits_init(&spx->dec_bits);
648
 
 
649
 
    /* Sampling rate. */
650
 
    speex_decoder_ctl(spx->dec, SPEEX_SET_SAMPLING_RATE,
651
 
                      &spx_factory.speex_param[id].clock_rate);
652
 
 
653
 
    /* PENH */
654
 
    tmp = attr->setting.penh;
655
 
    speex_decoder_ctl(spx->dec, SPEEX_SET_ENH, &tmp);
656
 
 
657
 
    return PJ_SUCCESS;
658
 
}
659
 
 
660
 
/*
661
 
 * Close codec.
662
 
 */
663
 
static pj_status_t spx_codec_close( pjmedia_codec *codec )
664
 
{
665
 
    struct spx_private *spx;
666
 
 
667
 
    spx = (struct spx_private*) codec->codec_data;
668
 
 
669
 
    /* Destroy encoder*/
670
 
    if (spx->enc) {
671
 
        speex_encoder_destroy( spx->enc );
672
 
        spx->enc = NULL;
673
 
        speex_bits_destroy( &spx->enc_bits );
674
 
    }
675
 
 
676
 
    /* Destroy decoder */
677
 
    if (spx->dec) {
678
 
        speex_decoder_destroy( spx->dec);
679
 
        spx->dec = NULL;
680
 
        speex_bits_destroy( &spx->dec_bits );
681
 
    }
682
 
 
683
 
    return PJ_SUCCESS;
684
 
}
685
 
 
686
 
 
687
 
/*
688
 
 * Modify codec settings.
689
 
 */
690
 
static pj_status_t  spx_codec_modify(pjmedia_codec *codec,
691
 
                                     const pjmedia_codec_param *attr )
692
 
{
693
 
    struct spx_private *spx;
694
 
    int tmp;
695
 
 
696
 
    spx = (struct spx_private*) codec->codec_data;
697
 
 
698
 
    /* VAD */
699
 
    tmp = (attr->setting.vad != 0);
700
 
    speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp);
701
 
    speex_encoder_ctl(spx->enc, SPEEX_SET_DTX, &tmp);
702
 
 
703
 
    /* PENH */
704
 
    tmp = attr->setting.penh;
705
 
    speex_decoder_ctl(spx->dec, SPEEX_SET_ENH, &tmp);
706
 
 
707
 
    return PJ_SUCCESS;
708
 
}
709
 
 
710
 
#if 0
711
 
#  define TRACE__(args)     PJ_LOG(5,args)
712
 
#else
713
 
#  define TRACE__(args)
714
 
#endif
715
 
 
716
 
#undef THIS_FUNC
717
 
#define THIS_FUNC "speex_get_next_frame"
718
 
 
719
 
#define NB_SUBMODES 16
720
 
#define NB_SUBMODE_BITS 4
721
 
 
722
 
#define SB_SUBMODES 8
723
 
#define SB_SUBMODE_BITS 3
724
 
 
725
 
/* This function will iterate frames & submodes in the Speex bits.
726
 
 * Returns 0 if a frame found, otherwise returns -1.
727
 
 */
728
 
int speex_get_next_frame(SpeexBits *bits)
729
 
{
730
 
    static const int inband_skip_table[NB_SUBMODES] =
731
 
       {1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 };
732
 
    static const int wb_skip_table[SB_SUBMODES] =
733
 
       {SB_SUBMODE_BITS+1, 36, 112, 192, 352, -1, -1, -1};
734
 
 
735
 
    unsigned submode;
736
 
    unsigned nb_count = 0;
737
 
 
738
 
    while (speex_bits_remaining(bits) >= 5) {
739
 
        unsigned wb_count = 0;
740
 
        unsigned bit_ptr = bits->bitPtr;
741
 
        unsigned char_ptr = bits->charPtr;
742
 
 
743
 
        /* WB frame */
744
 
        while ((speex_bits_remaining(bits) >= 4)
745
 
            && speex_bits_unpack_unsigned(bits, 1))
746
 
        {
747
 
            int advance;
748
 
 
749
 
            submode = speex_bits_unpack_unsigned(bits, 3);
750
 
            advance = wb_skip_table[submode];
751
 
            if (advance < 0) {
752
 
                TRACE__((THIS_FUNC, "Invalid mode encountered. "
753
 
                         "The stream is corrupted."));
754
 
                return -1;
755
 
            }
756
 
            TRACE__((THIS_FUNC, "WB layer skipped: %d bits", advance));
757
 
            advance -= (SB_SUBMODE_BITS+1);
758
 
            speex_bits_advance(bits, advance);
759
 
 
760
 
            bit_ptr = bits->bitPtr;
761
 
            char_ptr = bits->charPtr;
762
 
 
763
 
            /* Consecutive subband frames may not exceed 2 frames */
764
 
            if (++wb_count > 2)
765
 
                return -1;
766
 
        }
767
 
 
768
 
        /* End of bits, return the frame */
769
 
        if (speex_bits_remaining(bits) < 4) {
770
 
            TRACE__((THIS_FUNC, "End of stream"));
771
 
            return 0;
772
 
        }
773
 
 
774
 
        /* Stop iteration, return the frame */
775
 
        if (nb_count > 0) {
776
 
            bits->bitPtr = bit_ptr;
777
 
            bits->charPtr = char_ptr;
778
 
            return 0;
779
 
        }
780
 
 
781
 
        /* Get control bits */
782
 
        submode = speex_bits_unpack_unsigned(bits, 4);
783
 
        TRACE__((THIS_FUNC, "Control bits: %d at %d",
784
 
                 submode, bits->charPtr*8+bits->bitPtr));
785
 
 
786
 
        if (submode == 15) {
787
 
            TRACE__((THIS_FUNC, "Found submode: terminator"));
788
 
            return -1;
789
 
        } else if (submode == 14) {
790
 
            /* in-band signal; next 4 bits contain signal id */
791
 
            submode = speex_bits_unpack_unsigned(bits, 4);
792
 
            TRACE__((THIS_FUNC, "Found submode: in-band %d bits",
793
 
                     inband_skip_table[submode]));
794
 
            speex_bits_advance(bits, inband_skip_table[submode]);
795
 
        } else if (submode == 13) {
796
 
            /* user in-band; next 5 bits contain msg len */
797
 
            submode = speex_bits_unpack_unsigned(bits, 5);
798
 
            TRACE__((THIS_FUNC, "Found submode: user-band %d bytes", submode));
799
 
            speex_bits_advance(bits, submode * 8);
800
 
        } else if (submode > 8) {
801
 
            TRACE__((THIS_FUNC, "Unknown sub-mode %d", submode));
802
 
            return -1;
803
 
        } else {
804
 
            /* NB frame */
805
 
            unsigned int advance = submode;
806
 
            speex_mode_query(&speex_nb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);
807
 
            if (advance < 0) {
808
 
                TRACE__((THIS_FUNC, "Invalid mode encountered. "
809
 
                         "The stream is corrupted."));
810
 
                return -1;
811
 
            }
812
 
            TRACE__((THIS_FUNC, "Submode %d: %d bits", submode, advance));
813
 
            advance -= (NB_SUBMODE_BITS+1);
814
 
            speex_bits_advance(bits, advance);
815
 
 
816
 
            ++nb_count;
817
 
        }
818
 
    }
819
 
 
820
 
    return 0;
821
 
}
822
 
 
823
 
 
824
 
/*
825
 
 * Get frames in the packet.
826
 
 */
827
 
static pj_status_t  spx_codec_parse( pjmedia_codec *codec,
828
 
                                     void *pkt,
829
 
                                     pj_size_t pkt_size,
830
 
                                     const pj_timestamp *ts,
831
 
                                     unsigned *frame_cnt,
832
 
                                     pjmedia_frame frames[])
833
 
{
834
 
    struct spx_private *spx = (struct spx_private*) codec->codec_data;
835
 
    unsigned samples_per_frame;
836
 
    unsigned count = 0;
837
 
    int char_ptr = 0;
838
 
    int bit_ptr = 0;
839
 
 
840
 
    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame;
841
 
 
842
 
    /* Copy the data into the speex bit-stream */
843
 
    speex_bits_read_from(&spx->dec_bits, (char*)pkt, pkt_size);
844
 
 
845
 
    while (speex_get_next_frame(&spx->dec_bits) == 0 &&
846
 
           spx->dec_bits.charPtr != char_ptr)
847
 
    {
848
 
        frames[count].buf = (char*)pkt + char_ptr;
849
 
        /* Bit info contains start bit offset of the frame */
850
 
        frames[count].bit_info = bit_ptr;
851
 
        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
852
 
        frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame;
853
 
        frames[count].size = spx->dec_bits.charPtr - char_ptr;
854
 
        if (spx->dec_bits.bitPtr)
855
 
            ++frames[count].size;
856
 
 
857
 
        bit_ptr = spx->dec_bits.bitPtr;
858
 
        char_ptr = spx->dec_bits.charPtr;
859
 
 
860
 
        ++count;
861
 
    }
862
 
 
863
 
    *frame_cnt = count;
864
 
 
865
 
    return PJ_SUCCESS;
866
 
}
867
 
 
868
 
/*
869
 
 * Encode frames.
870
 
 */
871
 
static pj_status_t spx_codec_encode( pjmedia_codec *codec,
872
 
                                     const struct pjmedia_frame *input,
873
 
                                     unsigned output_buf_len,
874
 
                                     struct pjmedia_frame *output)
875
 
{
876
 
    struct spx_private *spx;
877
 
    unsigned samples_per_frame;
878
 
    int tx = 0;
879
 
    spx_int16_t *pcm_in = (spx_int16_t*)input->buf;
880
 
    unsigned nsamples;
881
 
 
882
 
    spx = (struct spx_private*) codec->codec_data;
883
 
 
884
 
    if (input->type != PJMEDIA_FRAME_TYPE_AUDIO) {
885
 
        output->size = 0;
886
 
        output->buf = NULL;
887
 
        output->timestamp = input->timestamp;
888
 
        output->type = input->type;
889
 
        return PJ_SUCCESS;
890
 
    }
891
 
 
892
 
    nsamples = input->size >> 1;
893
 
    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame;
894
 
 
895
 
    PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
896
 
                     PJMEDIA_CODEC_EPCMFRMINLEN);
897
 
 
898
 
    /* Flush all the bits in the struct so we can encode a new frame */
899
 
    speex_bits_reset(&spx->enc_bits);
900
 
 
901
 
    /* Encode the frames */
902
 
    while (nsamples >= samples_per_frame) {
903
 
        tx += speex_encode_int(spx->enc, pcm_in, &spx->enc_bits);
904
 
        pcm_in += samples_per_frame;
905
 
        nsamples -= samples_per_frame;
906
 
    }
907
 
 
908
 
    /* Check if we need not to transmit the frame (DTX) */
909
 
    if (tx == 0) {
910
 
        output->buf = NULL;
911
 
        output->size = 0;
912
 
        output->timestamp.u64 = input->timestamp.u64;
913
 
        output->type = PJMEDIA_FRAME_TYPE_NONE;
914
 
        return PJ_SUCCESS;
915
 
    }
916
 
 
917
 
    /* Check size. */
918
 
    pj_assert(speex_bits_nbytes(&spx->enc_bits) <= (int)output_buf_len);
919
 
 
920
 
    /* Copy the bits to an array of char that can be written */
921
 
    output->size = speex_bits_write(&spx->enc_bits,
922
 
                                    (char*)output->buf, output_buf_len);
923
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
924
 
    output->timestamp = input->timestamp;
925
 
 
926
 
    return PJ_SUCCESS;
927
 
}
928
 
 
929
 
/*
930
 
 * Decode frame.
931
 
 */
932
 
static pj_status_t spx_codec_decode( pjmedia_codec *codec,
933
 
                                     const struct pjmedia_frame *input,
934
 
                                     unsigned output_buf_len,
935
 
                                     struct pjmedia_frame *output)
936
 
{
937
 
    struct spx_private *spx;
938
 
    unsigned samples_per_frame;
939
 
 
940
 
    spx = (struct spx_private*) codec->codec_data;
941
 
    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame;
942
 
 
943
 
    PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
944
 
                     PJMEDIA_CODEC_EPCMTOOSHORT);
945
 
 
946
 
    if (input->type != PJMEDIA_FRAME_TYPE_AUDIO) {
947
 
        pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
948
 
        output->size = samples_per_frame << 1;
949
 
        output->timestamp.u64 = input->timestamp.u64;
950
 
        output->type = PJMEDIA_FRAME_TYPE_AUDIO;
951
 
        return PJ_SUCCESS;
952
 
    }
953
 
 
954
 
    /* Copy the data into the bit-stream struct */
955
 
    speex_bits_read_from(&spx->dec_bits, (char*)input->buf, input->size);
956
 
 
957
 
    /* Set Speex dec_bits pointer to the start bit of the frame */
958
 
    speex_bits_advance(&spx->dec_bits, input->bit_info);
959
 
 
960
 
    /* Decode the data */
961
 
    speex_decode_int(spx->dec, &spx->dec_bits, (spx_int16_t*)output->buf);
962
 
 
963
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
964
 
    output->size = samples_per_frame << 1;
965
 
    output->timestamp.u64 = input->timestamp.u64;
966
 
 
967
 
    return PJ_SUCCESS;
968
 
}
969
 
 
970
 
/*
971
 
 * Recover lost frame.
972
 
 */
973
 
static pj_status_t  spx_codec_recover(pjmedia_codec *codec,
974
 
                                      unsigned output_buf_len,
975
 
                                      struct pjmedia_frame *output)
976
 
{
977
 
    struct spx_private *spx;
978
 
    unsigned count;
979
 
 
980
 
    /* output_buf_len is unreferenced when building in Release mode */
981
 
    PJ_UNUSED_ARG(output_buf_len);
982
 
 
983
 
    spx = (struct spx_private*) codec->codec_data;
984
 
 
985
 
    count = spx_factory.speex_param[spx->param_id].clock_rate * 20 / 1000;
986
 
    pj_assert(count <= output_buf_len/2);
987
 
 
988
 
    /* Recover packet loss */
989
 
    speex_decode_int(spx->dec, NULL, (spx_int16_t*) output->buf);
990
 
 
991
 
    output->size = count * 2;
992
 
 
993
 
    return PJ_SUCCESS;
994
 
}
995
 
 
996
 
 
997
 
#endif  /* PJMEDIA_HAS_SPEEX_CODEC */