blob: ab9b509a512a40e6c7fe88f4e4d6ef998c57c4ac [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
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 */
42static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory,
43 const pjmedia_codec_info *id );
44static pj_status_t spx_default_attr( pjmedia_codec_factory *factory,
45 const pjmedia_codec_info *id,
46 pjmedia_codec_param *attr );
47static pj_status_t spx_enum_codecs( pjmedia_codec_factory *factory,
48 unsigned *count,
49 pjmedia_codec_info codecs[]);
50static pj_status_t spx_alloc_codec( pjmedia_codec_factory *factory,
51 const pjmedia_codec_info *id,
52 pjmedia_codec **p_codec);
53static pj_status_t spx_dealloc_codec( pjmedia_codec_factory *factory,
54 pjmedia_codec *codec );
55
56/* Prototypes for Speex implementation. */
57static pj_status_t spx_codec_init( pjmedia_codec *codec,
58 pj_pool_t *pool );
59static pj_status_t spx_codec_open( pjmedia_codec *codec,
60 pjmedia_codec_param *attr );
61static pj_status_t spx_codec_close( pjmedia_codec *codec );
62static pj_status_t spx_codec_modify(pjmedia_codec *codec,
63 const pjmedia_codec_param *attr );
64static 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[]);
70static 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);
74static 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);
78static 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. */
83static 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. */
96static 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. */
107enum
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 */
115struct 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 */
130static 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. */
142struct 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 */
156static 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 */
204PJ_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
296on_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 */
306PJ_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 */
314PJ_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 */
355PJ_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 */
402static 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 */
434static 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 */
480static 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 */
518static 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 */
564static 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 */
589static 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 */
600static 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 */
663static 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 */
690static 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 */
728int 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 */
827static 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, (int)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 */
871static 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 pj_size_t 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 */
932static 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, (int)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 */
973static 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 */