~ubuntu-branches/ubuntu/maverick/sflphone/maverick

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/pjmedia/src/pjmedia-codec/g722.c

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-06-03 15:59:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100603155946-ybe8d8o8zx8lp0m8
Tags: upstream-0.9.8.3
ImportĀ upstreamĀ versionĀ 0.9.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: g722.c 2760 2009-06-13 15:28:37Z nanang $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2009 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
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify this program, or any covered work, by linking or
 
23
 *  combining it with the OpenSSL project's OpenSSL library (or a
 
24
 *  modified version of that library), containing parts covered by the
 
25
 *  terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
 
26
 *  grants you additional permission to convey the resulting work.
 
27
 *  Corresponding Source for a non-source form of such a combination
 
28
 *  shall include the source code for the parts of OpenSSL used as well
 
29
 *  as that of the covered work.
 
30
 */
 
31
#include <pjmedia-codec/g722.h>
 
32
#include <pjmedia/codec.h>
 
33
#include <pjmedia/errno.h>
 
34
#include <pjmedia/endpoint.h>
 
35
#include <pjmedia/plc.h>
 
36
#include <pjmedia/port.h>
 
37
#include <pjmedia/silencedet.h>
 
38
#include <pj/assert.h>
 
39
#include <pj/log.h>
 
40
#include <pj/pool.h>
 
41
#include <pj/string.h>
 
42
#include <pj/os.h>
 
43
 
 
44
#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
 
45
 
 
46
#include "g722/g722_enc.h"
 
47
#include "g722/g722_dec.h"
 
48
 
 
49
#define THIS_FILE   "g722.c"
 
50
 
 
51
/* Defines */
 
52
#define PTIME                   (20)
 
53
#define SAMPLES_PER_FRAME       (16000 * PTIME /1000)
 
54
#define FRAME_LEN               (160)
 
55
#define PLC_DISABLED            0
 
56
 
 
57
/* Tracing */
 
58
#ifndef PJ_TRACE
 
59
#   define PJ_TRACE     0       
 
60
#endif
 
61
 
 
62
#if PJ_TRACE 
 
63
#   define TRACE_(expr) PJ_LOG(4,expr)
 
64
#else
 
65
#   define TRACE_(expr)
 
66
#endif
 
67
 
 
68
 
 
69
/* Prototypes for G722 factory */
 
70
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory, 
 
71
                                   const pjmedia_codec_info *id );
 
72
static pj_status_t g722_default_attr(pjmedia_codec_factory *factory, 
 
73
                                     const pjmedia_codec_info *id, 
 
74
                                     pjmedia_codec_param *attr );
 
75
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory, 
 
76
                                    unsigned *count, 
 
77
                                    pjmedia_codec_info codecs[]);
 
78
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory, 
 
79
                                    const pjmedia_codec_info *id, 
 
80
                                    pjmedia_codec **p_codec);
 
81
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory, 
 
82
                                      pjmedia_codec *codec );
 
83
 
 
84
/* Prototypes for G722 implementation. */
 
85
static pj_status_t  g722_codec_init(pjmedia_codec *codec, 
 
86
                                    pj_pool_t *pool );
 
87
static pj_status_t  g722_codec_open(pjmedia_codec *codec, 
 
88
                                    pjmedia_codec_param *attr );
 
89
static pj_status_t  g722_codec_close(pjmedia_codec *codec );
 
90
static pj_status_t  g722_codec_modify(pjmedia_codec *codec, 
 
91
                                      const pjmedia_codec_param *attr );
 
92
static pj_status_t  g722_codec_parse(pjmedia_codec *codec,
 
93
                                     void *pkt,
 
94
                                     pj_size_t pkt_size,
 
95
                                     const pj_timestamp *ts,
 
96
                                     unsigned *frame_cnt,
 
97
                                     pjmedia_frame frames[]);
 
98
static pj_status_t  g722_codec_encode(pjmedia_codec *codec, 
 
99
                                      const struct pjmedia_frame *input,
 
100
                                      unsigned output_buf_len, 
 
101
                                      struct pjmedia_frame *output);
 
102
static pj_status_t  g722_codec_decode(pjmedia_codec *codec, 
 
103
                                      const struct pjmedia_frame *input,
 
104
                                      unsigned output_buf_len, 
 
105
                                      struct pjmedia_frame *output);
 
106
#if !PLC_DISABLED
 
107
static pj_status_t  g722_codec_recover(pjmedia_codec *codec,
 
108
                                      unsigned output_buf_len,
 
109
                                      struct pjmedia_frame *output);
 
110
#endif
 
111
 
 
112
/* Definition for G722 codec operations. */
 
113
static pjmedia_codec_op g722_op = 
 
114
{
 
115
    &g722_codec_init,
 
116
    &g722_codec_open,
 
117
    &g722_codec_close,
 
118
    &g722_codec_modify,
 
119
    &g722_codec_parse,
 
120
    &g722_codec_encode,
 
121
    &g722_codec_decode,
 
122
#if !PLC_DISABLED
 
123
    &g722_codec_recover
 
124
#else
 
125
    NULL
 
126
#endif
 
127
};
 
128
 
 
129
/* Definition for G722 codec factory operations. */
 
130
static pjmedia_codec_factory_op g722_factory_op =
 
131
{
 
132
    &g722_test_alloc,
 
133
    &g722_default_attr,
 
134
    &g722_enum_codecs,
 
135
    &g722_alloc_codec,
 
136
    &g722_dealloc_codec
 
137
};
 
138
 
 
139
/* G722 factory */
 
140
static struct g722_codec_factory
 
141
{
 
142
    pjmedia_codec_factory    base;
 
143
    pjmedia_endpt           *endpt;
 
144
    pj_pool_t               *pool;
 
145
    pj_mutex_t              *mutex;
 
146
    pjmedia_codec            codec_list;
 
147
} g722_codec_factory;
 
148
 
 
149
 
 
150
/* G722 codec private data. */
 
151
struct g722_data
 
152
{
 
153
    g722_enc_t           encoder;
 
154
    g722_dec_t           decoder;
 
155
    pj_bool_t            plc_enabled;
 
156
    pj_bool_t            vad_enabled;
 
157
    pjmedia_silence_det *vad;
 
158
    pj_timestamp         last_tx;
 
159
#if !PLC_DISABLED
 
160
    pjmedia_plc         *plc;
 
161
#endif
 
162
};
 
163
 
 
164
 
 
165
 
 
166
/*
 
167
 * Initialize and register G722 codec factory to pjmedia endpoint.
 
168
 */
 
169
PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
 
170
{
 
171
    pjmedia_codec_mgr *codec_mgr;
 
172
    pj_status_t status;
 
173
 
 
174
    if (g722_codec_factory.pool != NULL)
 
175
        return PJ_SUCCESS;
 
176
 
 
177
    /* Create G722 codec factory. */
 
178
    g722_codec_factory.base.op = &g722_factory_op;
 
179
    g722_codec_factory.base.factory_data = NULL;
 
180
    g722_codec_factory.endpt = endpt;
 
181
 
 
182
    g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000, 
 
183
                                                        1000);
 
184
    if (!g722_codec_factory.pool)
 
185
        return PJ_ENOMEM;
 
186
 
 
187
    pj_list_init(&g722_codec_factory.codec_list);
 
188
 
 
189
    /* Create mutex. */
 
190
    status = pj_mutex_create_simple(g722_codec_factory.pool, "g722", 
 
191
                                    &g722_codec_factory.mutex);
 
192
    if (status != PJ_SUCCESS)
 
193
        goto on_error;
 
194
 
 
195
    /* Get the codec manager. */
 
196
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
 
197
    if (!codec_mgr) {
 
198
        status = PJ_EINVALIDOP;
 
199
        goto on_error;
 
200
    }
 
201
 
 
202
    /* Register codec factory to endpoint. */
 
203
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
 
204
                                                &g722_codec_factory.base);
 
205
    if (status != PJ_SUCCESS)
 
206
        goto on_error;
 
207
 
 
208
    TRACE_((THIS_FILE, "G722 codec factory initialized"));
 
209
    
 
210
    /* Done. */
 
211
    return PJ_SUCCESS;
 
212
 
 
213
on_error:
 
214
    pj_pool_release(g722_codec_factory.pool);
 
215
    g722_codec_factory.pool = NULL;
 
216
    return status;
 
217
}
 
218
 
 
219
/*
 
220
 * Unregister G722 codec factory from pjmedia endpoint and deinitialize
 
221
 * the G722 codec library.
 
222
 */
 
223
PJ_DEF(pj_status_t) pjmedia_codec_g722_deinit(void)
 
224
{
 
225
    pjmedia_codec_mgr *codec_mgr;
 
226
    pj_status_t status;
 
227
 
 
228
    if (g722_codec_factory.pool == NULL)
 
229
        return PJ_SUCCESS;
 
230
 
 
231
    /* Get the codec manager. */
 
232
    codec_mgr = pjmedia_endpt_get_codec_mgr(g722_codec_factory.endpt);
 
233
    if (!codec_mgr) {
 
234
        pj_pool_release(g722_codec_factory.pool);
 
235
        g722_codec_factory.pool = NULL;
 
236
        return PJ_EINVALIDOP;
 
237
    }
 
238
 
 
239
    /* Unregister G722 codec factory. */
 
240
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
 
241
                                                  &g722_codec_factory.base);
 
242
    
 
243
    /* Destroy mutex. */
 
244
    pj_mutex_destroy(g722_codec_factory.mutex);
 
245
 
 
246
    /* Destroy pool. */
 
247
    pj_pool_release(g722_codec_factory.pool);
 
248
    g722_codec_factory.pool = NULL;
 
249
    
 
250
    TRACE_((THIS_FILE, "G722 codec factory shutdown"));
 
251
    return status;
 
252
}
 
253
 
 
254
/* 
 
255
 * Check if factory can allocate the specified codec. 
 
256
 */
 
257
static pj_status_t g722_test_alloc(pjmedia_codec_factory *factory, 
 
258
                                   const pjmedia_codec_info *info )
 
259
{
 
260
    PJ_UNUSED_ARG(factory);
 
261
 
 
262
    /* Check payload type. */
 
263
    if (info->pt != PJMEDIA_RTP_PT_G722)
 
264
        return PJMEDIA_CODEC_EUNSUP;
 
265
 
 
266
    /* Ignore the rest, since it's static payload type. */
 
267
 
 
268
    return PJ_SUCCESS;
 
269
}
 
270
 
 
271
/*
 
272
 * Generate default attribute.
 
273
 */
 
274
static pj_status_t g722_default_attr( pjmedia_codec_factory *factory, 
 
275
                                      const pjmedia_codec_info *id, 
 
276
                                      pjmedia_codec_param *attr )
 
277
{
 
278
    PJ_UNUSED_ARG(factory);
 
279
    PJ_UNUSED_ARG(id);
 
280
 
 
281
    pj_bzero(attr, sizeof(pjmedia_codec_param));
 
282
    attr->info.clock_rate = 16000;
 
283
    attr->info.channel_cnt = 1;
 
284
    attr->info.avg_bps = 64000;
 
285
    attr->info.max_bps = 64000;
 
286
    attr->info.pcm_bits_per_sample = 16;
 
287
    attr->info.frm_ptime = PTIME;
 
288
    attr->info.pt = PJMEDIA_RTP_PT_G722;
 
289
 
 
290
    attr->setting.frm_per_pkt = 1;
 
291
    attr->setting.vad = 1;
 
292
    attr->setting.plc = 1;
 
293
 
 
294
    /* Default all other flag bits disabled. */
 
295
 
 
296
    return PJ_SUCCESS;
 
297
}
 
298
 
 
299
/*
 
300
 * Enum codecs supported by this factory (i.e. only G722!).
 
301
 */
 
302
static pj_status_t g722_enum_codecs(pjmedia_codec_factory *factory, 
 
303
                                    unsigned *count, 
 
304
                                    pjmedia_codec_info codecs[])
 
305
{
 
306
    PJ_UNUSED_ARG(factory);
 
307
    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
 
308
 
 
309
    pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
 
310
    codecs[0].encoding_name = pj_str("G722");
 
311
    codecs[0].pt = PJMEDIA_RTP_PT_G722;
 
312
    codecs[0].type = PJMEDIA_TYPE_AUDIO;
 
313
    codecs[0].clock_rate = 16000;
 
314
    codecs[0].channel_cnt = 1;
 
315
 
 
316
    *count = 1;
 
317
 
 
318
    return PJ_SUCCESS;
 
319
}
 
320
 
 
321
/*
 
322
 * Allocate a new G722 codec instance.
 
323
 */
 
324
static pj_status_t g722_alloc_codec(pjmedia_codec_factory *factory, 
 
325
                                    const pjmedia_codec_info *id,
 
326
                                    pjmedia_codec **p_codec)
 
327
{
 
328
    pjmedia_codec *codec;
 
329
    struct g722_data *g722_data;
 
330
 
 
331
    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
 
332
    PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
 
333
 
 
334
    pj_mutex_lock(g722_codec_factory.mutex);
 
335
 
 
336
    /* Get free nodes, if any. */
 
337
    if (!pj_list_empty(&g722_codec_factory.codec_list)) {
 
338
        codec = g722_codec_factory.codec_list.next;
 
339
        pj_list_erase(codec);
 
340
    } else {
 
341
        pj_status_t status;
 
342
 
 
343
        codec = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, pjmedia_codec);
 
344
        PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
 
345
        codec->op = &g722_op;
 
346
        codec->factory = factory;
 
347
 
 
348
        g722_data = PJ_POOL_ZALLOC_T(g722_codec_factory.pool, struct g722_data);
 
349
        codec->codec_data = g722_data;
 
350
 
 
351
#if !PLC_DISABLED
 
352
        /* Create PLC */
 
353
        status = pjmedia_plc_create(g722_codec_factory.pool, 16000, 
 
354
                                    SAMPLES_PER_FRAME, 0, &g722_data->plc);
 
355
        if (status != PJ_SUCCESS) {
 
356
            pj_mutex_unlock(g722_codec_factory.mutex);
 
357
            return status;
 
358
        }
 
359
#endif
 
360
 
 
361
        /* Create silence detector */
 
362
        status = pjmedia_silence_det_create(g722_codec_factory.pool,
 
363
                                            16000, SAMPLES_PER_FRAME,
 
364
                                            &g722_data->vad);
 
365
        if (status != PJ_SUCCESS) {
 
366
            pj_mutex_unlock(g722_codec_factory.mutex);
 
367
            TRACE_((THIS_FILE, "Create silence detector failed (status = %d)", 
 
368
                               status));
 
369
            return status;
 
370
        }
 
371
    }
 
372
 
 
373
 
 
374
    pj_mutex_unlock(g722_codec_factory.mutex);
 
375
 
 
376
    *p_codec = codec;
 
377
    return PJ_SUCCESS;
 
378
}
 
379
 
 
380
/*
 
381
 * Free codec.
 
382
 */
 
383
static pj_status_t g722_dealloc_codec(pjmedia_codec_factory *factory, 
 
384
                                      pjmedia_codec *codec )
 
385
{
 
386
    struct g722_data *g722_data;
 
387
    int i;
 
388
 
 
389
    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
 
390
    PJ_ASSERT_RETURN(factory == &g722_codec_factory.base, PJ_EINVAL);
 
391
 
 
392
    g722_data = (struct g722_data*) codec->codec_data;
 
393
 
 
394
    /* Close codec, if it's not closed. */
 
395
    g722_codec_close(codec);
 
396
 
 
397
#if !PLC_DISABLED
 
398
    /* Clear left samples in the PLC, since codec+plc will be reused
 
399
     * next time.
 
400
     */
 
401
    for (i=0; i<2; ++i) {
 
402
        pj_int16_t frame[SAMPLES_PER_FRAME];
 
403
        pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
 
404
        pjmedia_plc_save(g722_data->plc, frame);
 
405
    }
 
406
#else
 
407
    PJ_UNUSED_ARG(i);
 
408
#endif
 
409
 
 
410
    /* Re-init silence_period */
 
411
    pj_set_timestamp32(&g722_data->last_tx, 0, 0);
 
412
 
 
413
    /* Put in the free list. */
 
414
    pj_mutex_lock(g722_codec_factory.mutex);
 
415
    pj_list_push_front(&g722_codec_factory.codec_list, codec);
 
416
    pj_mutex_unlock(g722_codec_factory.mutex);
 
417
 
 
418
    return PJ_SUCCESS;
 
419
}
 
420
 
 
421
/*
 
422
 * Init codec.
 
423
 */
 
424
static pj_status_t g722_codec_init(pjmedia_codec *codec, 
 
425
                                   pj_pool_t *pool )
 
426
{
 
427
    PJ_UNUSED_ARG(codec);
 
428
    PJ_UNUSED_ARG(pool);
 
429
    return PJ_SUCCESS;
 
430
}
 
431
 
 
432
/*
 
433
 * Open codec.
 
434
 */
 
435
static pj_status_t g722_codec_open(pjmedia_codec *codec, 
 
436
                                   pjmedia_codec_param *attr )
 
437
{
 
438
    struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
 
439
    pj_status_t status;
 
440
 
 
441
    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
 
442
    PJ_ASSERT_RETURN(g722_data != NULL, PJ_EINVALIDOP);
 
443
 
 
444
    status = g722_enc_init(&g722_data->encoder);
 
445
    if (status != PJ_SUCCESS) {
 
446
        TRACE_((THIS_FILE, "g722_enc_init() failed, status=%d", status));
 
447
        pj_mutex_unlock(g722_codec_factory.mutex);
 
448
        return PJMEDIA_CODEC_EFAILED;
 
449
    }
 
450
 
 
451
    status = g722_dec_init(&g722_data->decoder);
 
452
    if (status != PJ_SUCCESS) {
 
453
        TRACE_((THIS_FILE, "g722_dec_init() failed, status=%d", status));
 
454
        pj_mutex_unlock(g722_codec_factory.mutex);
 
455
        return PJMEDIA_CODEC_EFAILED;
 
456
    }
 
457
 
 
458
    g722_data->vad_enabled = (attr->setting.vad != 0);
 
459
    g722_data->plc_enabled = (attr->setting.plc != 0);
 
460
 
 
461
    TRACE_((THIS_FILE, "G722 codec opened: vad=%d, plc=%d",
 
462
                        g722_data->vad_enabled, g722_data->plc_enabled));
 
463
    return PJ_SUCCESS;
 
464
}
 
465
 
 
466
/*
 
467
 * Close codec.
 
468
 */
 
469
static pj_status_t g722_codec_close( pjmedia_codec *codec )
 
470
{
 
471
    /* The codec, encoder, and decoder will be reused, so there's
 
472
     * nothing to do here
 
473
     */
 
474
 
 
475
    PJ_UNUSED_ARG(codec);
 
476
    
 
477
    TRACE_((THIS_FILE, "G722 codec closed"));
 
478
    return PJ_SUCCESS;
 
479
}
 
480
 
 
481
 
 
482
/*
 
483
 * Modify codec settings.
 
484
 */
 
485
static pj_status_t  g722_codec_modify(pjmedia_codec *codec, 
 
486
                                     const pjmedia_codec_param *attr )
 
487
{
 
488
    struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
 
489
 
 
490
    pj_assert(g722_data != NULL);
 
491
 
 
492
    g722_data->vad_enabled = (attr->setting.vad != 0);
 
493
    g722_data->plc_enabled = (attr->setting.plc != 0);
 
494
 
 
495
    TRACE_((THIS_FILE, "G722 codec modified: vad=%d, plc=%d",
 
496
                        g722_data->vad_enabled, g722_data->plc_enabled));
 
497
    return PJ_SUCCESS;
 
498
}
 
499
 
 
500
 
 
501
/*
 
502
 * Get frames in the packet.
 
503
 */
 
504
static pj_status_t  g722_codec_parse(pjmedia_codec *codec,
 
505
                                     void *pkt,
 
506
                                     pj_size_t pkt_size,
 
507
                                     const pj_timestamp *ts,
 
508
                                     unsigned *frame_cnt,
 
509
                                     pjmedia_frame frames[])
 
510
{
 
511
    unsigned count = 0;
 
512
 
 
513
    PJ_UNUSED_ARG(codec);
 
514
 
 
515
    PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
 
516
 
 
517
    TRACE_((THIS_FILE, "G722 parse(): input len=%d", pkt_size));
 
518
 
 
519
    while (pkt_size >= FRAME_LEN && count < *frame_cnt) {
 
520
        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
 
521
        frames[count].buf = pkt;
 
522
        frames[count].size = FRAME_LEN;
 
523
        frames[count].timestamp.u64 = ts->u64 + count * SAMPLES_PER_FRAME;
 
524
 
 
525
        pkt = ((char*)pkt) + FRAME_LEN;
 
526
        pkt_size -= FRAME_LEN;
 
527
 
 
528
        ++count;
 
529
    }
 
530
 
 
531
    TRACE_((THIS_FILE, "G722 parse(): got %d frames", count));
 
532
 
 
533
    *frame_cnt = count;
 
534
    return PJ_SUCCESS;
 
535
}
 
536
 
 
537
/*
 
538
 * Encode frame.
 
539
 */
 
540
static pj_status_t g722_codec_encode(pjmedia_codec *codec, 
 
541
                                     const struct pjmedia_frame *input,
 
542
                                     unsigned output_buf_len, 
 
543
                                     struct pjmedia_frame *output)
 
544
{
 
545
    struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
 
546
    pj_status_t status;
 
547
 
 
548
    pj_assert(g722_data && input && output);
 
549
 
 
550
    PJ_ASSERT_RETURN((input->size >> 2) <= output_buf_len, 
 
551
                     PJMEDIA_CODEC_EFRMTOOSHORT);
 
552
 
 
553
    /* Detect silence */
 
554
    if (g722_data->vad_enabled) {
 
555
        pj_bool_t is_silence;
 
556
        pj_int32_t silence_duration;
 
557
 
 
558
        silence_duration = pj_timestamp_diff32(&g722_data->last_tx, 
 
559
                                               &input->timestamp);
 
560
 
 
561
        is_silence = pjmedia_silence_det_detect(g722_data->vad, 
 
562
                                                (const pj_int16_t*) input->buf,
 
563
                                                (input->size >> 1),
 
564
                                                NULL);
 
565
        if (is_silence &&
 
566
            (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
 
567
             silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*16000/1000))
 
568
        {
 
569
            output->type = PJMEDIA_FRAME_TYPE_NONE;
 
570
            output->buf = NULL;
 
571
            output->size = 0;
 
572
            output->timestamp = input->timestamp;
 
573
            return PJ_SUCCESS;
 
574
        } else {
 
575
            g722_data->last_tx = input->timestamp;
 
576
        }
 
577
    }
 
578
 
 
579
    /* Encode to temporary buffer */
 
580
    output->size = output_buf_len;
 
581
    status = g722_enc_encode(&g722_data->encoder, (pj_int16_t*)input->buf, 
 
582
                             (input->size >> 1), output->buf, &output->size);
 
583
    if (status != PJ_SUCCESS) {
 
584
        output->size = 0;
 
585
        output->buf = NULL;
 
586
        output->type = PJMEDIA_FRAME_TYPE_NONE;
 
587
        TRACE_((THIS_FILE, "G722 encode() status: %d", status));
 
588
        return PJMEDIA_CODEC_EFAILED;
 
589
    }
 
590
 
 
591
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
592
    output->timestamp = input->timestamp;
 
593
    
 
594
    TRACE_((THIS_FILE, "G722 encode(): size=%d", output->size));
 
595
    return PJ_SUCCESS;
 
596
}
 
597
 
 
598
/*
 
599
 * Decode frame.
 
600
 */
 
601
static pj_status_t g722_codec_decode(pjmedia_codec *codec, 
 
602
                                     const struct pjmedia_frame *input,
 
603
                                     unsigned output_buf_len, 
 
604
                                     struct pjmedia_frame *output)
 
605
{
 
606
    struct g722_data *g722_data = (struct g722_data*) codec->codec_data;
 
607
    pj_status_t status;
 
608
 
 
609
    pj_assert(g722_data != NULL);
 
610
    PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
 
611
 
 
612
    TRACE_((THIS_FILE, "G722 decode(): inbuf=%p, insize=%d, outbuf=%p,"
 
613
                       "outsize=%d",
 
614
                       input->buf, input->size, output->buf, output_buf_len));
 
615
    
 
616
    if (output_buf_len < SAMPLES_PER_FRAME * 2) {
 
617
        TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EPCMTOOSHORT"));
 
618
        return PJMEDIA_CODEC_EPCMTOOSHORT;
 
619
    }
 
620
 
 
621
    if (input->size != FRAME_LEN) {
 
622
        TRACE_((THIS_FILE, "G722 decode() ERROR: PJMEDIA_CODEC_EFRMTOOSHORT"));
 
623
        return PJMEDIA_CODEC_EFRMTOOSHORT;
 
624
    }
 
625
 
 
626
 
 
627
    /* Decode */
 
628
    output->size = SAMPLES_PER_FRAME;
 
629
    status = g722_dec_decode(&g722_data->decoder, input->buf, input->size,
 
630
                             (pj_int16_t*)output->buf, &output->size);
 
631
    if (status != PJ_SUCCESS) {
 
632
        TRACE_((THIS_FILE, "G722 decode() status: %d", status));
 
633
        return PJMEDIA_CODEC_EFAILED;
 
634
    }
 
635
 
 
636
    pj_assert(output->size == SAMPLES_PER_FRAME);
 
637
    output->size = SAMPLES_PER_FRAME * 2;
 
638
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
639
    output->timestamp = input->timestamp;
 
640
 
 
641
#if !PLC_DISABLED
 
642
    if (g722_data->plc_enabled)
 
643
        pjmedia_plc_save(g722_data->plc, (pj_int16_t*)output->buf);
 
644
#endif
 
645
 
 
646
    TRACE_((THIS_FILE, "G722 decode done"));
 
647
    return PJ_SUCCESS;
 
648
}
 
649
 
 
650
 
 
651
#if !PLC_DISABLED
 
652
/*
 
653
 * Recover lost frame.
 
654
 */
 
655
static pj_status_t  g722_codec_recover(pjmedia_codec *codec,
 
656
                                       unsigned output_buf_len,
 
657
                                       struct pjmedia_frame *output)
 
658
{
 
659
    struct g722_data *g722_data = (struct g722_data*)codec->codec_data;
 
660
 
 
661
    PJ_ASSERT_RETURN(g722_data->plc_enabled, PJ_EINVALIDOP);
 
662
 
 
663
    PJ_ASSERT_RETURN(output_buf_len >= SAMPLES_PER_FRAME * 2, 
 
664
                     PJMEDIA_CODEC_EPCMTOOSHORT);
 
665
 
 
666
    pjmedia_plc_generate(g722_data->plc, (pj_int16_t*)output->buf);
 
667
 
 
668
    output->size = SAMPLES_PER_FRAME * 2;
 
669
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
670
    
 
671
    return PJ_SUCCESS;
 
672
}
 
673
#endif
 
674
 
 
675
#endif // PJMEDIA_HAS_G722_CODEC
 
676