1
/* $Id: gsm.c 4537 2013-06-19 06:47:43Z riza $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
#include <pjmedia-codec/gsm.h>
21
#include <pjmedia/codec.h>
22
#include <pjmedia/errno.h>
23
#include <pjmedia/endpoint.h>
24
#include <pjmedia/plc.h>
25
#include <pjmedia/port.h>
26
#include <pjmedia/silencedet.h>
27
#include <pj/assert.h>
29
#include <pj/string.h>
33
* Only build this file if PJMEDIA_HAS_GSM_CODEC != 0
35
#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC != 0
37
#if defined(PJMEDIA_EXTERNAL_GSM_CODEC) && PJMEDIA_EXTERNAL_GSM_CODEC
38
# if PJMEDIA_EXTERNAL_GSM_GSM_H
40
# elif PJMEDIA_EXTERNAL_GSM_H
43
# error Please set the location of gsm.h
46
# include "../../third_party/gsm/inc/gsm.h"
49
/* We removed PLC in 0.6 (and re-enabled it again in 0.9!) */
50
#define PLC_DISABLED 0
53
/* Prototypes for GSM factory */
54
static pj_status_t gsm_test_alloc( pjmedia_codec_factory *factory,
55
const pjmedia_codec_info *id );
56
static pj_status_t gsm_default_attr( pjmedia_codec_factory *factory,
57
const pjmedia_codec_info *id,
58
pjmedia_codec_param *attr );
59
static pj_status_t gsm_enum_codecs( pjmedia_codec_factory *factory,
61
pjmedia_codec_info codecs[]);
62
static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory,
63
const pjmedia_codec_info *id,
64
pjmedia_codec **p_codec);
65
static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory,
66
pjmedia_codec *codec );
68
/* Prototypes for GSM implementation. */
69
static pj_status_t gsm_codec_init( pjmedia_codec *codec,
71
static pj_status_t gsm_codec_open( pjmedia_codec *codec,
72
pjmedia_codec_param *attr );
73
static pj_status_t gsm_codec_close( pjmedia_codec *codec );
74
static pj_status_t gsm_codec_modify(pjmedia_codec *codec,
75
const pjmedia_codec_param *attr );
76
static pj_status_t gsm_codec_parse( pjmedia_codec *codec,
79
const pj_timestamp *ts,
81
pjmedia_frame frames[]);
82
static pj_status_t gsm_codec_encode( pjmedia_codec *codec,
83
const struct pjmedia_frame *input,
84
unsigned output_buf_len,
85
struct pjmedia_frame *output);
86
static pj_status_t gsm_codec_decode( pjmedia_codec *codec,
87
const struct pjmedia_frame *input,
88
unsigned output_buf_len,
89
struct pjmedia_frame *output);
91
static pj_status_t gsm_codec_recover(pjmedia_codec *codec,
92
unsigned output_buf_len,
93
struct pjmedia_frame *output);
96
/* Definition for GSM codec operations. */
97
static pjmedia_codec_op gsm_op =
113
/* Definition for GSM codec factory operations. */
114
static pjmedia_codec_factory_op gsm_factory_op =
121
&pjmedia_codec_gsm_deinit
125
static struct gsm_codec_factory
127
pjmedia_codec_factory base;
128
pjmedia_endpt *endpt;
131
pjmedia_codec codec_list;
135
/* GSM codec private data. */
138
struct gsm_state *encoder;
139
struct gsm_state *decoder;
140
pj_bool_t plc_enabled;
144
pj_bool_t vad_enabled;
145
pjmedia_silence_det *vad;
146
pj_timestamp last_tx;
152
* Initialize and register GSM codec factory to pjmedia endpoint.
154
PJ_DEF(pj_status_t) pjmedia_codec_gsm_init( pjmedia_endpt *endpt )
156
pjmedia_codec_mgr *codec_mgr;
159
if (gsm_codec_factory.pool != NULL)
162
/* Create GSM codec factory. */
163
gsm_codec_factory.base.op = &gsm_factory_op;
164
gsm_codec_factory.base.factory_data = NULL;
165
gsm_codec_factory.endpt = endpt;
167
gsm_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "gsm", 4000,
169
if (!gsm_codec_factory.pool)
172
pj_list_init(&gsm_codec_factory.codec_list);
175
status = pj_mutex_create_simple(gsm_codec_factory.pool, "gsm",
176
&gsm_codec_factory.mutex);
177
if (status != PJ_SUCCESS)
180
/* Get the codec manager. */
181
codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
183
status = PJ_EINVALIDOP;
187
/* Register codec factory to endpoint. */
188
status = pjmedia_codec_mgr_register_factory(codec_mgr,
189
&gsm_codec_factory.base);
190
if (status != PJ_SUCCESS)
197
pj_pool_release(gsm_codec_factory.pool);
198
gsm_codec_factory.pool = NULL;
205
* Unregister GSM codec factory from pjmedia endpoint and deinitialize
206
* the GSM codec library.
208
PJ_DEF(pj_status_t) pjmedia_codec_gsm_deinit(void)
210
pjmedia_codec_mgr *codec_mgr;
213
if (gsm_codec_factory.pool == NULL)
216
/* We don't want to deinit if there's outstanding codec. */
217
/* This is silly, as we'll always have codec in the list if
218
we ever allocate a codec! A better behavior maybe is to
219
deallocate all codecs in the list.
220
pj_mutex_lock(gsm_codec_factory.mutex);
221
if (!pj_list_empty(&gsm_codec_factory.codec_list)) {
222
pj_mutex_unlock(gsm_codec_factory.mutex);
227
/* Get the codec manager. */
228
codec_mgr = pjmedia_endpt_get_codec_mgr(gsm_codec_factory.endpt);
230
pj_pool_release(gsm_codec_factory.pool);
231
gsm_codec_factory.pool = NULL;
232
return PJ_EINVALIDOP;
235
/* Unregister GSM codec factory. */
236
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
237
&gsm_codec_factory.base);
240
pj_mutex_destroy(gsm_codec_factory.mutex);
243
pj_pool_release(gsm_codec_factory.pool);
244
gsm_codec_factory.pool = NULL;
250
* Check if factory can allocate the specified codec.
252
static pj_status_t gsm_test_alloc( pjmedia_codec_factory *factory,
253
const pjmedia_codec_info *info )
255
PJ_UNUSED_ARG(factory);
257
/* Check payload type. */
258
if (info->pt != PJMEDIA_RTP_PT_GSM)
259
return PJMEDIA_CODEC_EUNSUP;
261
/* Ignore the rest, since it's static payload type. */
267
* Generate default attribute.
269
static pj_status_t gsm_default_attr (pjmedia_codec_factory *factory,
270
const pjmedia_codec_info *id,
271
pjmedia_codec_param *attr )
273
PJ_UNUSED_ARG(factory);
276
pj_bzero(attr, sizeof(pjmedia_codec_param));
277
attr->info.clock_rate = 8000;
278
attr->info.channel_cnt = 1;
279
attr->info.avg_bps = 13200;
280
attr->info.max_bps = 13200;
281
attr->info.pcm_bits_per_sample = 16;
282
attr->info.frm_ptime = 20;
283
attr->info.pt = PJMEDIA_RTP_PT_GSM;
285
attr->setting.frm_per_pkt = 1;
286
attr->setting.vad = 1;
288
attr->setting.plc = 1;
291
/* Default all other flag bits disabled. */
297
* Enum codecs supported by this factory (i.e. only GSM!).
299
static pj_status_t gsm_enum_codecs(pjmedia_codec_factory *factory,
301
pjmedia_codec_info codecs[])
303
PJ_UNUSED_ARG(factory);
304
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
306
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
307
codecs[0].encoding_name = pj_str("GSM");
308
codecs[0].pt = PJMEDIA_RTP_PT_GSM;
309
codecs[0].type = PJMEDIA_TYPE_AUDIO;
310
codecs[0].clock_rate = 8000;
311
codecs[0].channel_cnt = 1;
319
* Allocate a new GSM codec instance.
321
static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory,
322
const pjmedia_codec_info *id,
323
pjmedia_codec **p_codec)
325
pjmedia_codec *codec;
326
struct gsm_data *gsm_data;
329
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
330
PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
333
pj_mutex_lock(gsm_codec_factory.mutex);
335
/* Get free nodes, if any. */
336
if (!pj_list_empty(&gsm_codec_factory.codec_list)) {
337
codec = gsm_codec_factory.codec_list.next;
338
pj_list_erase(codec);
340
codec = PJ_POOL_ZALLOC_T(gsm_codec_factory.pool, pjmedia_codec);
341
PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
343
codec->factory = factory;
345
gsm_data = PJ_POOL_ZALLOC_T(gsm_codec_factory.pool, struct gsm_data);
346
codec->codec_data = gsm_data;
350
status = pjmedia_plc_create(gsm_codec_factory.pool, 8000,
351
160, 0, &gsm_data->plc);
352
if (status != PJ_SUCCESS) {
353
pj_mutex_unlock(gsm_codec_factory.mutex);
358
/* Create silence detector */
359
status = pjmedia_silence_det_create(gsm_codec_factory.pool,
362
if (status != PJ_SUCCESS) {
363
pj_mutex_unlock(gsm_codec_factory.mutex);
368
pj_mutex_unlock(gsm_codec_factory.mutex);
377
static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory,
378
pjmedia_codec *codec )
380
struct gsm_data *gsm_data;
383
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
384
PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
386
gsm_data = (struct gsm_data*) codec->codec_data;
388
/* Close codec, if it's not closed. */
389
gsm_codec_close(codec);
392
/* Clear left samples in the PLC, since codec+plc will be reused
395
for (i=0; i<2; ++i) {
396
pj_int16_t frame[160];
397
pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
398
pjmedia_plc_save(gsm_data->plc, frame);
404
/* Re-init silence_period */
405
pj_set_timestamp32(&gsm_data->last_tx, 0, 0);
407
/* Put in the free list. */
408
pj_mutex_lock(gsm_codec_factory.mutex);
409
pj_list_push_front(&gsm_codec_factory.codec_list, codec);
410
pj_mutex_unlock(gsm_codec_factory.mutex);
418
static pj_status_t gsm_codec_init( pjmedia_codec *codec,
421
PJ_UNUSED_ARG(codec);
429
static pj_status_t gsm_codec_open( pjmedia_codec *codec,
430
pjmedia_codec_param *attr )
432
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
434
pj_assert(gsm_data != NULL);
435
pj_assert(gsm_data->encoder == NULL && gsm_data->decoder == NULL);
437
gsm_data->encoder = gsm_create();
438
if (!gsm_data->encoder)
439
return PJMEDIA_CODEC_EFAILED;
441
gsm_data->decoder = gsm_create();
442
if (!gsm_data->decoder)
443
return PJMEDIA_CODEC_EFAILED;
445
gsm_data->vad_enabled = (attr->setting.vad != 0);
446
gsm_data->plc_enabled = (attr->setting.plc != 0);
454
static pj_status_t gsm_codec_close( pjmedia_codec *codec )
456
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
458
pj_assert(gsm_data != NULL);
460
if (gsm_data->encoder) {
461
gsm_destroy(gsm_data->encoder);
462
gsm_data->encoder = NULL;
464
if (gsm_data->decoder) {
465
gsm_destroy(gsm_data->decoder);
466
gsm_data->decoder = NULL;
474
* Modify codec settings.
476
static pj_status_t gsm_codec_modify(pjmedia_codec *codec,
477
const pjmedia_codec_param *attr )
479
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
481
pj_assert(gsm_data != NULL);
482
pj_assert(gsm_data->encoder != NULL && gsm_data->decoder != NULL);
484
gsm_data->vad_enabled = (attr->setting.vad != 0);
485
gsm_data->plc_enabled = (attr->setting.plc != 0);
492
* Get frames in the packet.
494
static pj_status_t gsm_codec_parse( pjmedia_codec *codec,
497
const pj_timestamp *ts,
499
pjmedia_frame frames[])
503
PJ_UNUSED_ARG(codec);
505
PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
507
while (pkt_size >= 33 && count < *frame_cnt) {
508
frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
509
frames[count].buf = pkt;
510
frames[count].size = 33;
511
frames[count].timestamp.u64 = ts->u64 + count * 160;
513
pkt = ((char*)pkt) + 33;
526
static pj_status_t gsm_codec_encode( pjmedia_codec *codec,
527
const struct pjmedia_frame *input,
528
unsigned output_buf_len,
529
struct pjmedia_frame *output)
531
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
535
pj_assert(gsm_data && input && output);
537
pcm_in = (pj_int16_t*)input->buf;
538
in_size = input->size;
540
PJ_ASSERT_RETURN(in_size % 320 == 0, PJMEDIA_CODEC_EPCMFRMINLEN);
541
PJ_ASSERT_RETURN(output_buf_len >= 33 * in_size/320,
542
PJMEDIA_CODEC_EFRMTOOSHORT);
545
if (gsm_data->vad_enabled) {
546
pj_bool_t is_silence;
547
pj_int32_t silence_duration;
549
silence_duration = pj_timestamp_diff32(&gsm_data->last_tx,
552
is_silence = pjmedia_silence_det_detect(gsm_data->vad,
553
(const pj_int16_t*) input->buf,
557
(PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
558
silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000))
560
output->type = PJMEDIA_FRAME_TYPE_NONE;
563
output->timestamp = input->timestamp;
566
gsm_data->last_tx = input->timestamp;
572
while (in_size >= 320) {
573
gsm_encode(gsm_data->encoder, pcm_in,
574
(unsigned char*)output->buf + output->size);
580
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
581
output->timestamp = input->timestamp;
589
static pj_status_t gsm_codec_decode( pjmedia_codec *codec,
590
const struct pjmedia_frame *input,
591
unsigned output_buf_len,
592
struct pjmedia_frame *output)
594
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
596
pj_assert(gsm_data != NULL);
597
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
599
if (output_buf_len < 320)
600
return PJMEDIA_CODEC_EPCMTOOSHORT;
602
if (input->size < 33)
603
return PJMEDIA_CODEC_EFRMTOOSHORT;
605
gsm_decode(gsm_data->decoder,
606
(unsigned char*)input->buf,
607
(short*)output->buf);
610
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
611
output->timestamp = input->timestamp;
614
if (gsm_data->plc_enabled)
615
pjmedia_plc_save( gsm_data->plc, (pj_int16_t*)output->buf);
624
* Recover lost frame.
626
static pj_status_t gsm_codec_recover(pjmedia_codec *codec,
627
unsigned output_buf_len,
628
struct pjmedia_frame *output)
630
struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
632
PJ_ASSERT_RETURN(gsm_data->plc_enabled, PJ_EINVALIDOP);
634
PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT);
636
pjmedia_plc_generate(gsm_data->plc, (pj_int16_t*)output->buf);
644
#endif /* PJMEDIA_HAS_GSM_CODEC */