~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjmedia/src/pjmedia-codec/gsm.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* 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: gsm.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
 
#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>
28
 
#include <pj/pool.h>
29
 
#include <pj/string.h>
30
 
#include <pj/os.h>
31
 
 
32
 
/*
33
 
 * Only build this file if PJMEDIA_HAS_GSM_CODEC != 0
34
 
 */
35
 
#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC != 0
36
 
 
37
 
#if defined(PJMEDIA_EXTERNAL_GSM_CODEC) && PJMEDIA_EXTERNAL_GSM_CODEC
38
 
# if PJMEDIA_EXTERNAL_GSM_GSM_H
39
 
#   include <gsm/gsm.h>
40
 
# elif PJMEDIA_EXTERNAL_GSM_H
41
 
#   include <gsm.h>
42
 
# else
43
 
#   error Please set the location of gsm.h
44
 
# endif
45
 
#else
46
 
#   include "../../third_party/gsm/inc/gsm.h"
47
 
#endif
48
 
 
49
 
/* We removed PLC in 0.6 (and re-enabled it again in 0.9!) */
50
 
#define PLC_DISABLED    0
51
 
 
52
 
 
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,
60
 
                                    unsigned *count,
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 );
67
 
 
68
 
/* Prototypes for GSM implementation. */
69
 
static pj_status_t  gsm_codec_init( pjmedia_codec *codec,
70
 
                                    pj_pool_t *pool );
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,
77
 
                                     void *pkt,
78
 
                                     pj_size_t pkt_size,
79
 
                                     const pj_timestamp *ts,
80
 
                                     unsigned *frame_cnt,
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);
90
 
#if !PLC_DISABLED
91
 
static pj_status_t  gsm_codec_recover(pjmedia_codec *codec,
92
 
                                      unsigned output_buf_len,
93
 
                                      struct pjmedia_frame *output);
94
 
#endif
95
 
 
96
 
/* Definition for GSM codec operations. */
97
 
static pjmedia_codec_op gsm_op =
98
 
{
99
 
    &gsm_codec_init,
100
 
    &gsm_codec_open,
101
 
    &gsm_codec_close,
102
 
    &gsm_codec_modify,
103
 
    &gsm_codec_parse,
104
 
    &gsm_codec_encode,
105
 
    &gsm_codec_decode,
106
 
#if !PLC_DISABLED
107
 
    &gsm_codec_recover
108
 
#else
109
 
    NULL
110
 
#endif
111
 
};
112
 
 
113
 
/* Definition for GSM codec factory operations. */
114
 
static pjmedia_codec_factory_op gsm_factory_op =
115
 
{
116
 
    &gsm_test_alloc,
117
 
    &gsm_default_attr,
118
 
    &gsm_enum_codecs,
119
 
    &gsm_alloc_codec,
120
 
    &gsm_dealloc_codec,
121
 
    &pjmedia_codec_gsm_deinit
122
 
};
123
 
 
124
 
/* GSM factory */
125
 
static struct gsm_codec_factory
126
 
{
127
 
    pjmedia_codec_factory    base;
128
 
    pjmedia_endpt           *endpt;
129
 
    pj_pool_t               *pool;
130
 
    pj_mutex_t              *mutex;
131
 
    pjmedia_codec            codec_list;
132
 
} gsm_codec_factory;
133
 
 
134
 
 
135
 
/* GSM codec private data. */
136
 
struct gsm_data
137
 
{
138
 
    struct gsm_state    *encoder;
139
 
    struct gsm_state    *decoder;
140
 
    pj_bool_t            plc_enabled;
141
 
#if !PLC_DISABLED
142
 
    pjmedia_plc         *plc;
143
 
#endif
144
 
    pj_bool_t            vad_enabled;
145
 
    pjmedia_silence_det *vad;
146
 
    pj_timestamp         last_tx;
147
 
};
148
 
 
149
 
 
150
 
 
151
 
/*
152
 
 * Initialize and register GSM codec factory to pjmedia endpoint.
153
 
 */
154
 
PJ_DEF(pj_status_t) pjmedia_codec_gsm_init( pjmedia_endpt *endpt )
155
 
{
156
 
    pjmedia_codec_mgr *codec_mgr;
157
 
    pj_status_t status;
158
 
 
159
 
    if (gsm_codec_factory.pool != NULL)
160
 
        return PJ_SUCCESS;
161
 
 
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;
166
 
 
167
 
    gsm_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "gsm", 4000,
168
 
                                                       4000);
169
 
    if (!gsm_codec_factory.pool)
170
 
        return PJ_ENOMEM;
171
 
 
172
 
    pj_list_init(&gsm_codec_factory.codec_list);
173
 
 
174
 
    /* Create mutex. */
175
 
    status = pj_mutex_create_simple(gsm_codec_factory.pool, "gsm",
176
 
                                    &gsm_codec_factory.mutex);
177
 
    if (status != PJ_SUCCESS)
178
 
        goto on_error;
179
 
 
180
 
    /* Get the codec manager. */
181
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
182
 
    if (!codec_mgr) {
183
 
        status = PJ_EINVALIDOP;
184
 
        goto on_error;
185
 
    }
186
 
 
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)
191
 
        goto on_error;
192
 
 
193
 
    /* Done. */
194
 
    return PJ_SUCCESS;
195
 
 
196
 
on_error:
197
 
    pj_pool_release(gsm_codec_factory.pool);
198
 
    gsm_codec_factory.pool = NULL;
199
 
    return status;
200
 
}
201
 
 
202
 
 
203
 
 
204
 
/*
205
 
 * Unregister GSM codec factory from pjmedia endpoint and deinitialize
206
 
 * the GSM codec library.
207
 
 */
208
 
PJ_DEF(pj_status_t) pjmedia_codec_gsm_deinit(void)
209
 
{
210
 
    pjmedia_codec_mgr *codec_mgr;
211
 
    pj_status_t status;
212
 
 
213
 
    if (gsm_codec_factory.pool == NULL)
214
 
        return PJ_SUCCESS;
215
 
 
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);
223
 
        return PJ_EBUSY;
224
 
    }
225
 
    */
226
 
 
227
 
    /* Get the codec manager. */
228
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(gsm_codec_factory.endpt);
229
 
    if (!codec_mgr) {
230
 
        pj_pool_release(gsm_codec_factory.pool);
231
 
        gsm_codec_factory.pool = NULL;
232
 
        return PJ_EINVALIDOP;
233
 
    }
234
 
 
235
 
    /* Unregister GSM codec factory. */
236
 
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
237
 
                                                  &gsm_codec_factory.base);
238
 
 
239
 
    /* Destroy mutex. */
240
 
    pj_mutex_destroy(gsm_codec_factory.mutex);
241
 
 
242
 
    /* Destroy pool. */
243
 
    pj_pool_release(gsm_codec_factory.pool);
244
 
    gsm_codec_factory.pool = NULL;
245
 
 
246
 
    return status;
247
 
}
248
 
 
249
 
/*
250
 
 * Check if factory can allocate the specified codec.
251
 
 */
252
 
static pj_status_t gsm_test_alloc( pjmedia_codec_factory *factory,
253
 
                                   const pjmedia_codec_info *info )
254
 
{
255
 
    PJ_UNUSED_ARG(factory);
256
 
 
257
 
    /* Check payload type. */
258
 
    if (info->pt != PJMEDIA_RTP_PT_GSM)
259
 
        return PJMEDIA_CODEC_EUNSUP;
260
 
 
261
 
    /* Ignore the rest, since it's static payload type. */
262
 
 
263
 
    return PJ_SUCCESS;
264
 
}
265
 
 
266
 
/*
267
 
 * Generate default attribute.
268
 
 */
269
 
static pj_status_t gsm_default_attr (pjmedia_codec_factory *factory,
270
 
                                      const pjmedia_codec_info *id,
271
 
                                      pjmedia_codec_param *attr )
272
 
{
273
 
    PJ_UNUSED_ARG(factory);
274
 
    PJ_UNUSED_ARG(id);
275
 
 
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;
284
 
 
285
 
    attr->setting.frm_per_pkt = 1;
286
 
    attr->setting.vad = 1;
287
 
#if !PLC_DISABLED
288
 
    attr->setting.plc = 1;
289
 
#endif
290
 
 
291
 
    /* Default all other flag bits disabled. */
292
 
 
293
 
    return PJ_SUCCESS;
294
 
}
295
 
 
296
 
/*
297
 
 * Enum codecs supported by this factory (i.e. only GSM!).
298
 
 */
299
 
static pj_status_t gsm_enum_codecs(pjmedia_codec_factory *factory,
300
 
                                    unsigned *count,
301
 
                                    pjmedia_codec_info codecs[])
302
 
{
303
 
    PJ_UNUSED_ARG(factory);
304
 
    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
305
 
 
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;
312
 
 
313
 
    *count = 1;
314
 
 
315
 
    return PJ_SUCCESS;
316
 
}
317
 
 
318
 
/*
319
 
 * Allocate a new GSM codec instance.
320
 
 */
321
 
static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory,
322
 
                                    const pjmedia_codec_info *id,
323
 
                                    pjmedia_codec **p_codec)
324
 
{
325
 
    pjmedia_codec *codec;
326
 
    struct gsm_data *gsm_data;
327
 
    pj_status_t status;
328
 
 
329
 
    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
330
 
    PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
331
 
 
332
 
 
333
 
    pj_mutex_lock(gsm_codec_factory.mutex);
334
 
 
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);
339
 
    } else {
340
 
        codec = PJ_POOL_ZALLOC_T(gsm_codec_factory.pool, pjmedia_codec);
341
 
        PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
342
 
        codec->op = &gsm_op;
343
 
        codec->factory = factory;
344
 
 
345
 
        gsm_data = PJ_POOL_ZALLOC_T(gsm_codec_factory.pool, struct gsm_data);
346
 
        codec->codec_data = gsm_data;
347
 
 
348
 
#if !PLC_DISABLED
349
 
        /* Create PLC */
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);
354
 
            return status;
355
 
        }
356
 
#endif
357
 
 
358
 
        /* Create silence detector */
359
 
        status = pjmedia_silence_det_create(gsm_codec_factory.pool,
360
 
                                            8000, 160,
361
 
                                            &gsm_data->vad);
362
 
        if (status != PJ_SUCCESS) {
363
 
            pj_mutex_unlock(gsm_codec_factory.mutex);
364
 
            return status;
365
 
        }
366
 
    }
367
 
 
368
 
    pj_mutex_unlock(gsm_codec_factory.mutex);
369
 
 
370
 
    *p_codec = codec;
371
 
    return PJ_SUCCESS;
372
 
}
373
 
 
374
 
/*
375
 
 * Free codec.
376
 
 */
377
 
static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory,
378
 
                                      pjmedia_codec *codec )
379
 
{
380
 
    struct gsm_data *gsm_data;
381
 
    int i;
382
 
 
383
 
    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
384
 
    PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
385
 
 
386
 
    gsm_data = (struct gsm_data*) codec->codec_data;
387
 
 
388
 
    /* Close codec, if it's not closed. */
389
 
    gsm_codec_close(codec);
390
 
 
391
 
#if !PLC_DISABLED
392
 
    /* Clear left samples in the PLC, since codec+plc will be reused
393
 
     * next time.
394
 
     */
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);
399
 
    }
400
 
#else
401
 
    PJ_UNUSED_ARG(i);
402
 
#endif
403
 
 
404
 
    /* Re-init silence_period */
405
 
    pj_set_timestamp32(&gsm_data->last_tx, 0, 0);
406
 
 
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);
411
 
 
412
 
    return PJ_SUCCESS;
413
 
}
414
 
 
415
 
/*
416
 
 * Init codec.
417
 
 */
418
 
static pj_status_t gsm_codec_init( pjmedia_codec *codec,
419
 
                                   pj_pool_t *pool )
420
 
{
421
 
    PJ_UNUSED_ARG(codec);
422
 
    PJ_UNUSED_ARG(pool);
423
 
    return PJ_SUCCESS;
424
 
}
425
 
 
426
 
/*
427
 
 * Open codec.
428
 
 */
429
 
static pj_status_t gsm_codec_open( pjmedia_codec *codec,
430
 
                                   pjmedia_codec_param *attr )
431
 
{
432
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
433
 
 
434
 
    pj_assert(gsm_data != NULL);
435
 
    pj_assert(gsm_data->encoder == NULL && gsm_data->decoder == NULL);
436
 
 
437
 
    gsm_data->encoder = gsm_create();
438
 
    if (!gsm_data->encoder)
439
 
        return PJMEDIA_CODEC_EFAILED;
440
 
 
441
 
    gsm_data->decoder = gsm_create();
442
 
    if (!gsm_data->decoder)
443
 
        return PJMEDIA_CODEC_EFAILED;
444
 
 
445
 
    gsm_data->vad_enabled = (attr->setting.vad != 0);
446
 
    gsm_data->plc_enabled = (attr->setting.plc != 0);
447
 
 
448
 
    return PJ_SUCCESS;
449
 
}
450
 
 
451
 
/*
452
 
 * Close codec.
453
 
 */
454
 
static pj_status_t gsm_codec_close( pjmedia_codec *codec )
455
 
{
456
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
457
 
 
458
 
    pj_assert(gsm_data != NULL);
459
 
 
460
 
    if (gsm_data->encoder) {
461
 
        gsm_destroy(gsm_data->encoder);
462
 
        gsm_data->encoder = NULL;
463
 
    }
464
 
    if (gsm_data->decoder) {
465
 
        gsm_destroy(gsm_data->decoder);
466
 
        gsm_data->decoder = NULL;
467
 
    }
468
 
 
469
 
    return PJ_SUCCESS;
470
 
}
471
 
 
472
 
 
473
 
/*
474
 
 * Modify codec settings.
475
 
 */
476
 
static pj_status_t  gsm_codec_modify(pjmedia_codec *codec,
477
 
                                     const pjmedia_codec_param *attr )
478
 
{
479
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
480
 
 
481
 
    pj_assert(gsm_data != NULL);
482
 
    pj_assert(gsm_data->encoder != NULL && gsm_data->decoder != NULL);
483
 
 
484
 
    gsm_data->vad_enabled = (attr->setting.vad != 0);
485
 
    gsm_data->plc_enabled = (attr->setting.plc != 0);
486
 
 
487
 
    return PJ_SUCCESS;
488
 
}
489
 
 
490
 
 
491
 
/*
492
 
 * Get frames in the packet.
493
 
 */
494
 
static pj_status_t  gsm_codec_parse( pjmedia_codec *codec,
495
 
                                     void *pkt,
496
 
                                     pj_size_t pkt_size,
497
 
                                     const pj_timestamp *ts,
498
 
                                     unsigned *frame_cnt,
499
 
                                     pjmedia_frame frames[])
500
 
{
501
 
    unsigned count = 0;
502
 
 
503
 
    PJ_UNUSED_ARG(codec);
504
 
 
505
 
    PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
506
 
 
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;
512
 
 
513
 
        pkt = ((char*)pkt) + 33;
514
 
        pkt_size -= 33;
515
 
 
516
 
        ++count;
517
 
    }
518
 
 
519
 
    *frame_cnt = count;
520
 
    return PJ_SUCCESS;
521
 
}
522
 
 
523
 
/*
524
 
 * Encode frame.
525
 
 */
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)
530
 
{
531
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
532
 
    pj_int16_t *pcm_in;
533
 
    unsigned in_size;
534
 
 
535
 
    pj_assert(gsm_data && input && output);
536
 
 
537
 
    pcm_in = (pj_int16_t*)input->buf;
538
 
    in_size = input->size;
539
 
 
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);
543
 
 
544
 
    /* Detect silence */
545
 
    if (gsm_data->vad_enabled) {
546
 
        pj_bool_t is_silence;
547
 
        pj_int32_t silence_duration;
548
 
 
549
 
        silence_duration = pj_timestamp_diff32(&gsm_data->last_tx,
550
 
                                               &input->timestamp);
551
 
 
552
 
        is_silence = pjmedia_silence_det_detect(gsm_data->vad,
553
 
                                                (const pj_int16_t*) input->buf,
554
 
                                                (input->size >> 1),
555
 
                                                NULL);
556
 
        if (is_silence &&
557
 
            (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
558
 
             silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000))
559
 
        {
560
 
            output->type = PJMEDIA_FRAME_TYPE_NONE;
561
 
            output->buf = NULL;
562
 
            output->size = 0;
563
 
            output->timestamp = input->timestamp;
564
 
            return PJ_SUCCESS;
565
 
        } else {
566
 
            gsm_data->last_tx = input->timestamp;
567
 
        }
568
 
    }
569
 
 
570
 
    /* Encode */
571
 
    output->size = 0;
572
 
    while (in_size >= 320) {
573
 
        gsm_encode(gsm_data->encoder, pcm_in,
574
 
                   (unsigned char*)output->buf + output->size);
575
 
        pcm_in += 160;
576
 
        output->size += 33;
577
 
        in_size -= 320;
578
 
    }
579
 
 
580
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
581
 
    output->timestamp = input->timestamp;
582
 
 
583
 
    return PJ_SUCCESS;
584
 
}
585
 
 
586
 
/*
587
 
 * Decode frame.
588
 
 */
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)
593
 
{
594
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
595
 
 
596
 
    pj_assert(gsm_data != NULL);
597
 
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
598
 
 
599
 
    if (output_buf_len < 320)
600
 
        return PJMEDIA_CODEC_EPCMTOOSHORT;
601
 
 
602
 
    if (input->size < 33)
603
 
        return PJMEDIA_CODEC_EFRMTOOSHORT;
604
 
 
605
 
    gsm_decode(gsm_data->decoder,
606
 
               (unsigned char*)input->buf,
607
 
               (short*)output->buf);
608
 
 
609
 
    output->size = 320;
610
 
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
611
 
    output->timestamp = input->timestamp;
612
 
 
613
 
#if !PLC_DISABLED
614
 
    if (gsm_data->plc_enabled)
615
 
        pjmedia_plc_save( gsm_data->plc, (pj_int16_t*)output->buf);
616
 
#endif
617
 
 
618
 
    return PJ_SUCCESS;
619
 
}
620
 
 
621
 
 
622
 
#if !PLC_DISABLED
623
 
/*
624
 
 * Recover lost frame.
625
 
 */
626
 
static pj_status_t  gsm_codec_recover(pjmedia_codec *codec,
627
 
                                      unsigned output_buf_len,
628
 
                                      struct pjmedia_frame *output)
629
 
{
630
 
    struct gsm_data *gsm_data = (struct gsm_data*) codec->codec_data;
631
 
 
632
 
    PJ_ASSERT_RETURN(gsm_data->plc_enabled, PJ_EINVALIDOP);
633
 
 
634
 
    PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT);
635
 
 
636
 
    pjmedia_plc_generate(gsm_data->plc, (pj_int16_t*)output->buf);
637
 
    output->size = 320;
638
 
 
639
 
    return PJ_SUCCESS;
640
 
}
641
 
#endif
642
 
 
643
 
 
644
 
#endif  /* PJMEDIA_HAS_GSM_CODEC */