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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-codec/passthrough.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: passthrough.c 4082 2012-04-24 13:09:14Z bennylp $ */
 
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/passthrough.h>
 
21
#include <pjmedia-codec/amr_sdp_match.h>
 
22
#include <pjmedia/codec.h>
 
23
#include <pjmedia/errno.h>
 
24
#include <pjmedia/endpoint.h>
 
25
#include <pjmedia/port.h>
 
26
#include <pj/assert.h>
 
27
#include <pj/log.h>
 
28
#include <pj/math.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_PASSTHROUGH_CODECS != 0
 
35
 */
 
36
#if defined(PJMEDIA_HAS_PASSTHROUGH_CODECS) && PJMEDIA_HAS_PASSTHROUGH_CODECS!=0
 
37
 
 
38
#define THIS_FILE   "passthrough.c"
 
39
 
 
40
 
 
41
/* Prototypes for passthrough codecs factory */
 
42
static pj_status_t test_alloc( pjmedia_codec_factory *factory, 
 
43
                               const pjmedia_codec_info *id );
 
44
static pj_status_t default_attr( pjmedia_codec_factory *factory, 
 
45
                                 const pjmedia_codec_info *id, 
 
46
                                 pjmedia_codec_param *attr );
 
47
static pj_status_t enum_codecs( pjmedia_codec_factory *factory, 
 
48
                                unsigned *count, 
 
49
                                pjmedia_codec_info codecs[]);
 
50
static pj_status_t alloc_codec( pjmedia_codec_factory *factory, 
 
51
                                const pjmedia_codec_info *id, 
 
52
                                pjmedia_codec **p_codec);
 
53
static pj_status_t dealloc_codec( pjmedia_codec_factory *factory, 
 
54
                                  pjmedia_codec *codec );
 
55
 
 
56
/* Prototypes for passthrough codecs implementation. */
 
57
static pj_status_t codec_init( pjmedia_codec *codec, 
 
58
                               pj_pool_t *pool );
 
59
static pj_status_t codec_open( pjmedia_codec *codec, 
 
60
                               pjmedia_codec_param *attr );
 
61
static pj_status_t codec_close( pjmedia_codec *codec );
 
62
static pj_status_t codec_modify(pjmedia_codec *codec, 
 
63
                                const pjmedia_codec_param *attr );
 
64
static pj_status_t 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 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 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 codec_recover( pjmedia_codec *codec, 
 
79
                                  unsigned output_buf_len, 
 
80
                                  struct pjmedia_frame *output);
 
81
 
 
82
/* Definition for passthrough codecs operations. */
 
83
static pjmedia_codec_op codec_op = 
 
84
{
 
85
    &codec_init,
 
86
    &codec_open,
 
87
    &codec_close,
 
88
    &codec_modify,
 
89
    &codec_parse,
 
90
    &codec_encode,
 
91
    &codec_decode,
 
92
    &codec_recover
 
93
};
 
94
 
 
95
/* Definition for passthrough codecs factory operations. */
 
96
static pjmedia_codec_factory_op codec_factory_op =
 
97
{
 
98
    &test_alloc,
 
99
    &default_attr,
 
100
    &enum_codecs,
 
101
    &alloc_codec,
 
102
    &dealloc_codec,
 
103
    &pjmedia_codec_passthrough_deinit
 
104
};
 
105
 
 
106
/* Passthrough codecs factory */
 
107
static struct codec_factory {
 
108
    pjmedia_codec_factory    base;
 
109
    pjmedia_endpt           *endpt;
 
110
    pj_pool_t               *pool;
 
111
    pj_mutex_t              *mutex;
 
112
} codec_factory;
 
113
 
 
114
/* Passthrough codecs private data. */
 
115
typedef struct codec_private {
 
116
    pj_pool_t           *pool;              /**< Pool for each instance.    */
 
117
    int                  codec_idx;         /**< Codec index.               */
 
118
    void                *codec_setting;     /**< Specific codec setting.    */
 
119
    pj_uint16_t          avg_frame_size;    /**< Average of frame size.     */
 
120
    unsigned             samples_per_frame; /**< Samples per frame, for iLBC
 
121
                                                 this can be 240 or 160, can
 
122
                                                 only be known after codec is
 
123
                                                 opened.                    */
 
124
} codec_private_t;
 
125
 
 
126
 
 
127
 
 
128
/* CUSTOM CALLBACKS */
 
129
 
 
130
/* Parse frames from a packet. Default behaviour of frame parsing is 
 
131
 * just separating frames based on calculating frame length derived 
 
132
 * from bitrate. Implement this callback when the default behaviour is 
 
133
 * unapplicable.
 
134
 */
 
135
typedef pj_status_t (*parse_cb)(codec_private_t *codec_data, void *pkt, 
 
136
                                pj_size_t pkt_size, const pj_timestamp *ts,
 
137
                                unsigned *frame_cnt, pjmedia_frame frames[]);
 
138
 
 
139
/* Pack frames into a packet. Default behaviour of packing frames is 
 
140
 * just stacking the frames with octet aligned without adding any 
 
141
 * payload header. Implement this callback when the default behaviour is
 
142
 * unapplicable.
 
143
 */
 
144
typedef pj_status_t (*pack_cb)(codec_private_t *codec_data, 
 
145
                               const struct pjmedia_frame_ext *input,
 
146
                               unsigned output_buf_len, 
 
147
                               struct pjmedia_frame *output);
 
148
 
 
149
 
 
150
/* Custom callback implementations. */
 
151
static pj_status_t parse_amr( codec_private_t *codec_data, void *pkt, 
 
152
                              pj_size_t pkt_size, const pj_timestamp *ts,
 
153
                              unsigned *frame_cnt, pjmedia_frame frames[]);
 
154
static pj_status_t pack_amr ( codec_private_t *codec_data,
 
155
                              const struct pjmedia_frame_ext *input,
 
156
                              unsigned output_buf_len, 
 
157
                              struct pjmedia_frame *output);
 
158
 
 
159
 
 
160
/* Passthrough codec implementation descriptions. */
 
161
static struct codec_desc {
 
162
    int              enabled;           /* Is this codec enabled?           */
 
163
    const char      *name;              /* Codec name.                      */
 
164
    pj_uint8_t       pt;                /* Payload type.                    */
 
165
    pjmedia_format_id fmt_id;           /* Source format.                   */
 
166
    unsigned         clock_rate;        /* Codec's clock rate.              */
 
167
    unsigned         channel_count;     /* Codec's channel count.           */
 
168
    unsigned         samples_per_frame; /* Codec's samples count.           */
 
169
    unsigned         def_bitrate;       /* Default bitrate of this codec.   */
 
170
    unsigned         max_bitrate;       /* Maximum bitrate of this codec.   */
 
171
    pj_uint8_t       frm_per_pkt;       /* Default num of frames per packet.*/
 
172
    pj_uint8_t       vad;               /* VAD enabled/disabled.            */
 
173
    pj_uint8_t       plc;               /* PLC enabled/disabled.            */
 
174
    parse_cb         parse;             /* Callback to parse bitstream.     */
 
175
    pack_cb          pack;              /* Callback to pack bitstream.      */
 
176
    pjmedia_codec_fmtp dec_fmtp;        /* Decoder's fmtp params.           */
 
177
}
 
178
 
 
179
codec_desc[] = 
 
180
{
 
181
#   if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
182
    {1, "AMR",      PJMEDIA_RTP_PT_AMR,       PJMEDIA_FORMAT_AMR,
 
183
                    8000, 1, 160, 
 
184
                    7400, 12200, 2, 1, 1,
 
185
                    &parse_amr, &pack_amr
 
186
                    /*, {1, {{{"octet-align", 11}, {"1", 1}}} } */
 
187
    },
 
188
#   endif
 
189
 
 
190
#   if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
 
191
    {1, "G729",     PJMEDIA_RTP_PT_G729,      PJMEDIA_FORMAT_G729,
 
192
                    8000, 1,  80,
 
193
                    8000, 8000, 2, 1, 1
 
194
    },
 
195
#   endif
 
196
 
 
197
#   if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
 
198
    {1, "iLBC",     PJMEDIA_RTP_PT_ILBC,      PJMEDIA_FORMAT_ILBC,
 
199
                    8000, 1,  240,
 
200
                    13333, 15200, 1, 1, 1,
 
201
                    NULL, NULL,
 
202
                    {1, {{{"mode", 4}, {"30", 2}}} }
 
203
    },
 
204
#   endif
 
205
 
 
206
#   if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU
 
207
    {1, "PCMU",     PJMEDIA_RTP_PT_PCMU,      PJMEDIA_FORMAT_PCMU,
 
208
                    8000, 1,  80,
 
209
                    64000, 64000, 2, 1, 1
 
210
    },
 
211
#   endif
 
212
 
 
213
#   if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA
 
214
    {1, "PCMA",     PJMEDIA_RTP_PT_PCMA,      PJMEDIA_FORMAT_PCMA,
 
215
                    8000, 1,  80,
 
216
                    64000, 64000, 2, 1, 1
 
217
    },
 
218
#   endif
 
219
};
 
220
 
 
221
 
 
222
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
223
 
 
224
#include <pjmedia-codec/amr_helper.h>
 
225
 
 
226
typedef struct amr_settings_t {
 
227
    pjmedia_codec_amr_pack_setting enc_setting;
 
228
    pjmedia_codec_amr_pack_setting dec_setting;
 
229
    pj_int8_t enc_mode;
 
230
} amr_settings_t;
 
231
 
 
232
 
 
233
/* Pack AMR payload */
 
234
static pj_status_t pack_amr ( codec_private_t *codec_data,
 
235
                              const struct pjmedia_frame_ext *input,
 
236
                              unsigned output_buf_len, 
 
237
                              struct pjmedia_frame *output)
 
238
{
 
239
    enum {MAX_FRAMES_PER_PACKET = PJMEDIA_MAX_FRAME_DURATION_MS / 20};
 
240
 
 
241
    pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
 
242
    amr_settings_t* setting = (amr_settings_t*)codec_data->codec_setting;
 
243
    pjmedia_codec_amr_pack_setting *enc_setting = &setting->enc_setting;
 
244
    pj_uint8_t SID_FT;
 
245
    unsigned i;
 
246
 
 
247
    pj_assert(input->subframe_cnt <= MAX_FRAMES_PER_PACKET);
 
248
 
 
249
    SID_FT = (pj_uint8_t)(enc_setting->amr_nb? 8 : 9);
 
250
 
 
251
    /* Get frames */
 
252
    for (i = 0; i < input->subframe_cnt; ++i) {
 
253
        pjmedia_frame_ext_subframe *sf;
 
254
        pjmedia_codec_amr_bit_info *info;
 
255
        unsigned len;
 
256
        
 
257
        sf = pjmedia_frame_ext_get_subframe(input, i);
 
258
        len = (sf->bitlen + 7) >> 3;
 
259
        
 
260
        info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info;
 
261
        pj_bzero(info, sizeof(*info));
 
262
        
 
263
        if (len == 0) {
 
264
            /* DTX */
 
265
            info->frame_type = 15;
 
266
        } else {
 
267
            info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb, 
 
268
                                                           len);
 
269
        }
 
270
        info->good_quality = 1;
 
271
        info->mode = setting->enc_mode;
 
272
        if (info->frame_type == SID_FT)
 
273
            info->STI = (sf->data[4] >> 4) & 1;
 
274
 
 
275
        frames[i].buf = sf->data;
 
276
        frames[i].size = len;
 
277
    }
 
278
 
 
279
    output->size = output_buf_len;
 
280
 
 
281
    return pjmedia_codec_amr_pack(frames, input->subframe_cnt, enc_setting, 
 
282
                                  output->buf, &output->size);
 
283
}
 
284
 
 
285
 
 
286
/* Parse AMR payload into frames. */
 
287
static pj_status_t parse_amr(codec_private_t *codec_data, void *pkt, 
 
288
                             pj_size_t pkt_size, const pj_timestamp *ts,
 
289
                             unsigned *frame_cnt, pjmedia_frame frames[])
 
290
{
 
291
    amr_settings_t* s = (amr_settings_t*)codec_data->codec_setting;
 
292
    pjmedia_codec_amr_pack_setting *setting;
 
293
    pj_status_t status;
 
294
    pj_uint8_t cmr;
 
295
 
 
296
    setting = &s->dec_setting;
 
297
 
 
298
    status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, setting, frames, 
 
299
                                     frame_cnt, &cmr);
 
300
    if (status != PJ_SUCCESS)
 
301
        return status;
 
302
 
 
303
    // CMR is not supported for now. 
 
304
    /* Check Change Mode Request. */
 
305
    //if ((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) {
 
306
    //  s->enc_mode = cmr;
 
307
    //}
 
308
 
 
309
    return PJ_SUCCESS;
 
310
}
 
311
 
 
312
#endif /* PJMEDIA_HAS_PASSTROUGH_CODEC_AMR */
 
313
 
 
314
 
 
315
/*
 
316
 * Initialize and register passthrough codec factory to pjmedia endpoint.
 
317
 */
 
318
PJ_DEF(pj_status_t) pjmedia_codec_passthrough_init( pjmedia_endpt *endpt )
 
319
{
 
320
    pjmedia_codec_mgr *codec_mgr;
 
321
    pj_str_t codec_name;
 
322
    pj_status_t status;
 
323
 
 
324
    if (codec_factory.pool != NULL) {
 
325
        /* Already initialized. */
 
326
        return PJ_EEXISTS;
 
327
    }
 
328
 
 
329
    /* Create passthrough codec factory. */
 
330
    codec_factory.base.op = &codec_factory_op;
 
331
    codec_factory.base.factory_data = NULL;
 
332
    codec_factory.endpt = endpt;
 
333
 
 
334
    codec_factory.pool = pjmedia_endpt_create_pool(endpt, "Passthrough codecs",
 
335
                                                   4000, 4000);
 
336
    if (!codec_factory.pool)
 
337
        return PJ_ENOMEM;
 
338
 
 
339
    /* Create mutex. */
 
340
    status = pj_mutex_create_simple(codec_factory.pool, "Passthrough codecs",
 
341
                                    &codec_factory.mutex);
 
342
    if (status != PJ_SUCCESS)
 
343
        goto on_error;
 
344
 
 
345
    /* Get the codec manager. */
 
346
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
 
347
    if (!codec_mgr) {
 
348
        status = PJ_EINVALIDOP;
 
349
        goto on_error;
 
350
    }
 
351
 
 
352
    /* Register format match callback. */
 
353
#if PJMEDIA_HAS_PASSTROUGH_CODEC_AMR
 
354
    pj_cstr(&codec_name, "AMR");
 
355
    status = pjmedia_sdp_neg_register_fmt_match_cb(
 
356
                                        &codec_name,
 
357
                                        &pjmedia_codec_amr_match_sdp);
 
358
    if (status != PJ_SUCCESS)
 
359
        goto on_error;
 
360
#endif
 
361
 
 
362
    /* Suppress compile warning */
 
363
    PJ_UNUSED_ARG(codec_name);
 
364
 
 
365
    /* Register codec factory to endpoint. */
 
366
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
 
367
                                                &codec_factory.base);
 
368
    if (status != PJ_SUCCESS)
 
369
        goto on_error;
 
370
 
 
371
    /* Done. */
 
372
    return PJ_SUCCESS;
 
373
 
 
374
on_error:
 
375
    pj_pool_release(codec_factory.pool);
 
376
    codec_factory.pool = NULL;
 
377
    return status;
 
378
}
 
379
 
 
380
/*
 
381
 * Initialize and register passthrough codec factory to pjmedia endpoint.
 
382
 */
 
383
PJ_DEF(pj_status_t) pjmedia_codec_passthrough_init2( 
 
384
                      pjmedia_endpt *endpt,
 
385
                      const pjmedia_codec_passthrough_setting *setting)
 
386
{
 
387
    if (codec_factory.pool != NULL) {
 
388
        /* Already initialized. */
 
389
        return PJ_EEXISTS;
 
390
    }
 
391
 
 
392
    if (setting != NULL) {
 
393
        unsigned i;
 
394
 
 
395
        /* Enable/disable codecs based on the specified encoding formats */
 
396
        for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
397
            pj_bool_t enabled = PJ_FALSE;
 
398
            unsigned j;
 
399
 
 
400
            for (j = 0; j < setting->fmt_cnt && !enabled; ++j) {
 
401
                if ((pj_uint32_t)codec_desc[i].fmt_id == setting->fmts[j].id)
 
402
                    enabled = PJ_TRUE;
 
403
            }
 
404
 
 
405
            codec_desc[i].enabled = enabled;
 
406
        }
 
407
 
 
408
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
 
409
        /* Update iLBC codec description based on default mode setting. */
 
410
        for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
411
            if (codec_desc[i].enabled && 
 
412
                codec_desc[i].fmt_id == PJMEDIA_FORMAT_ILBC)
 
413
            {
 
414
                codec_desc[i].samples_per_frame = 
 
415
                                (setting->ilbc_mode == 20? 160 : 240);
 
416
                codec_desc[i].def_bitrate = 
 
417
                                (setting->ilbc_mode == 20? 15200 : 13333);
 
418
                pj_strset2(&codec_desc[i].dec_fmtp.param[0].val, 
 
419
                                (setting->ilbc_mode == 20? "20" : "30"));
 
420
                break;
 
421
            }
 
422
        }
 
423
#endif
 
424
    }
 
425
 
 
426
    return pjmedia_codec_passthrough_init(endpt);
 
427
}
 
428
 
 
429
/*
 
430
 * Unregister passthrough codecs factory from pjmedia endpoint.
 
431
 */
 
432
PJ_DEF(pj_status_t) pjmedia_codec_passthrough_deinit(void)
 
433
{
 
434
    pjmedia_codec_mgr *codec_mgr;
 
435
    unsigned i;
 
436
    pj_status_t status;
 
437
 
 
438
    if (codec_factory.pool == NULL) {
 
439
        /* Already deinitialized */
 
440
        return PJ_SUCCESS;
 
441
    }
 
442
 
 
443
    pj_mutex_lock(codec_factory.mutex);
 
444
 
 
445
    /* Get the codec manager. */
 
446
    codec_mgr = pjmedia_endpt_get_codec_mgr(codec_factory.endpt);
 
447
    if (!codec_mgr) {
 
448
        pj_pool_release(codec_factory.pool);
 
449
        codec_factory.pool = NULL;
 
450
        return PJ_EINVALIDOP;
 
451
    }
 
452
 
 
453
    /* Unregister passthrough codecs factory. */
 
454
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
 
455
                                                  &codec_factory.base);
 
456
    
 
457
    /* Destroy mutex. */
 
458
    pj_mutex_destroy(codec_factory.mutex);
 
459
 
 
460
    /* Destroy pool. */
 
461
    pj_pool_release(codec_factory.pool);
 
462
    codec_factory.pool = NULL;
 
463
 
 
464
    /* Re-enable all codecs in the codec_desc. */
 
465
    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
466
        codec_desc[i].enabled = PJ_TRUE;
 
467
    }
 
468
 
 
469
    return status;
 
470
}
 
471
 
 
472
/* 
 
473
 * Check if factory can allocate the specified codec. 
 
474
 */
 
475
static pj_status_t test_alloc( pjmedia_codec_factory *factory, 
 
476
                               const pjmedia_codec_info *info )
 
477
{
 
478
    unsigned i;
 
479
 
 
480
    PJ_UNUSED_ARG(factory);
 
481
 
 
482
    /* Type MUST be audio. */
 
483
    if (info->type != PJMEDIA_TYPE_AUDIO)
 
484
        return PJMEDIA_CODEC_EUNSUP;
 
485
 
 
486
    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
487
        pj_str_t name = pj_str((char*)codec_desc[i].name);
 
488
        if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
 
489
            (info->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
 
490
            (info->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
 
491
            (codec_desc[i].enabled))
 
492
        {
 
493
            return PJ_SUCCESS;
 
494
        }
 
495
    }
 
496
    
 
497
    /* Unsupported, or mode is disabled. */
 
498
    return PJMEDIA_CODEC_EUNSUP;
 
499
}
 
500
 
 
501
/*
 
502
 * Generate default attribute.
 
503
 */
 
504
static pj_status_t default_attr ( pjmedia_codec_factory *factory, 
 
505
                                  const pjmedia_codec_info *id, 
 
506
                                  pjmedia_codec_param *attr )
 
507
{
 
508
    unsigned i;
 
509
 
 
510
    PJ_ASSERT_RETURN(factory==&codec_factory.base, PJ_EINVAL);
 
511
 
 
512
    pj_bzero(attr, sizeof(pjmedia_codec_param));
 
513
 
 
514
    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
515
        pj_str_t name = pj_str((char*)codec_desc[i].name);
 
516
        if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
 
517
            (id->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
 
518
            (id->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
 
519
            (id->pt == (unsigned)codec_desc[i].pt))
 
520
        {
 
521
            attr->info.pt = (pj_uint8_t)id->pt;
 
522
            attr->info.channel_cnt = codec_desc[i].channel_count;
 
523
            attr->info.clock_rate = codec_desc[i].clock_rate;
 
524
            attr->info.avg_bps = codec_desc[i].def_bitrate;
 
525
            attr->info.max_bps = codec_desc[i].max_bitrate;
 
526
            attr->info.pcm_bits_per_sample = 16;
 
527
            attr->info.frm_ptime =  (pj_uint16_t)
 
528
                                    (codec_desc[i].samples_per_frame * 1000 / 
 
529
                                    codec_desc[i].channel_count / 
 
530
                                    codec_desc[i].clock_rate);
 
531
            attr->info.fmt_id = codec_desc[i].fmt_id;
 
532
 
 
533
            /* Default flags. */
 
534
            attr->setting.frm_per_pkt = codec_desc[i].frm_per_pkt;
 
535
            attr->setting.plc = codec_desc[i].plc;
 
536
            attr->setting.penh= 0;
 
537
            attr->setting.vad = codec_desc[i].vad;
 
538
            attr->setting.cng = attr->setting.vad;
 
539
            attr->setting.dec_fmtp = codec_desc[i].dec_fmtp;
 
540
 
 
541
            if (attr->setting.vad == 0) {
 
542
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
 
543
                if (id->pt == PJMEDIA_RTP_PT_G729) {
 
544
                    /* Signal G729 Annex B is being disabled */
 
545
                    attr->setting.dec_fmtp.cnt = 1;
 
546
                    pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
 
547
                    pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
 
548
                }
 
549
#endif
 
550
            }
 
551
 
 
552
            return PJ_SUCCESS;
 
553
        }
 
554
    }
 
555
 
 
556
    return PJMEDIA_CODEC_EUNSUP;
 
557
}
 
558
 
 
559
/*
 
560
 * Enum codecs supported by this factory.
 
561
 */
 
562
static pj_status_t enum_codecs( pjmedia_codec_factory *factory, 
 
563
                                unsigned *count, 
 
564
                                pjmedia_codec_info codecs[])
 
565
{
 
566
    unsigned max;
 
567
    unsigned i;
 
568
 
 
569
    PJ_UNUSED_ARG(factory);
 
570
    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
 
571
 
 
572
    max = *count;
 
573
    
 
574
    for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(codec_desc) && *count < max; ++i) 
 
575
    {
 
576
        if (!codec_desc[i].enabled)
 
577
            continue;
 
578
 
 
579
        pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
 
580
        codecs[*count].encoding_name = pj_str((char*)codec_desc[i].name);
 
581
        codecs[*count].pt = codec_desc[i].pt;
 
582
        codecs[*count].type = PJMEDIA_TYPE_AUDIO;
 
583
        codecs[*count].clock_rate = codec_desc[i].clock_rate;
 
584
        codecs[*count].channel_cnt = codec_desc[i].channel_count;
 
585
 
 
586
        ++*count;
 
587
    }
 
588
 
 
589
    return PJ_SUCCESS;
 
590
}
 
591
 
 
592
/*
 
593
 * Allocate a new codec instance.
 
594
 */
 
595
static pj_status_t alloc_codec( pjmedia_codec_factory *factory, 
 
596
                                const pjmedia_codec_info *id,
 
597
                                pjmedia_codec **p_codec)
 
598
{
 
599
    codec_private_t *codec_data;
 
600
    pjmedia_codec *codec;
 
601
    int idx;
 
602
    pj_pool_t *pool;
 
603
    unsigned i;
 
604
 
 
605
    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
 
606
    PJ_ASSERT_RETURN(factory == &codec_factory.base, PJ_EINVAL);
 
607
 
 
608
    pj_mutex_lock(codec_factory.mutex);
 
609
 
 
610
    /* Find codec's index */
 
611
    idx = -1;
 
612
    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
 
613
        pj_str_t name = pj_str((char*)codec_desc[i].name);
 
614
        if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
 
615
            (id->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
 
616
            (id->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
 
617
            (codec_desc[i].enabled))
 
618
        {
 
619
            idx = i;
 
620
            break;
 
621
        }
 
622
    }
 
623
    if (idx == -1) {
 
624
        *p_codec = NULL;
 
625
        return PJMEDIA_CODEC_EUNSUP;
 
626
    }
 
627
 
 
628
    /* Create pool for codec instance */
 
629
    pool = pjmedia_endpt_create_pool(codec_factory.endpt, "passthroughcodec",
 
630
                                     512, 512);
 
631
    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
 
632
    codec->op = &codec_op;
 
633
    codec->factory = factory;
 
634
    codec->codec_data = PJ_POOL_ZALLOC_T(pool, codec_private_t);
 
635
    codec_data = (codec_private_t*) codec->codec_data;
 
636
    codec_data->pool = pool;
 
637
    codec_data->codec_idx = idx;
 
638
 
 
639
    pj_mutex_unlock(codec_factory.mutex);
 
640
 
 
641
    *p_codec = codec;
 
642
    return PJ_SUCCESS;
 
643
}
 
644
 
 
645
/*
 
646
 * Free codec.
 
647
 */
 
648
static pj_status_t dealloc_codec( pjmedia_codec_factory *factory, 
 
649
                                  pjmedia_codec *codec )
 
650
{
 
651
    codec_private_t *codec_data;
 
652
 
 
653
    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
 
654
    PJ_ASSERT_RETURN(factory == &codec_factory.base, PJ_EINVAL);
 
655
 
 
656
    /* Close codec, if it's not closed. */
 
657
    codec_data = (codec_private_t*) codec->codec_data;
 
658
    codec_close(codec);
 
659
 
 
660
    pj_pool_release(codec_data->pool);
 
661
 
 
662
    return PJ_SUCCESS;
 
663
}
 
664
 
 
665
/*
 
666
 * Init codec.
 
667
 */
 
668
static pj_status_t codec_init( pjmedia_codec *codec, 
 
669
                               pj_pool_t *pool )
 
670
{
 
671
    PJ_UNUSED_ARG(codec);
 
672
    PJ_UNUSED_ARG(pool);
 
673
    return PJ_SUCCESS;
 
674
}
 
675
 
 
676
/*
 
677
 * Open codec.
 
678
 */
 
679
static pj_status_t codec_open( pjmedia_codec *codec, 
 
680
                               pjmedia_codec_param *attr )
 
681
{
 
682
    codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
 
683
    struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
 
684
    pj_pool_t *pool;
 
685
    int i, j;
 
686
 
 
687
    pool = codec_data->pool;
 
688
 
 
689
    /* Cache samples per frame value */
 
690
    codec_data->samples_per_frame = desc->samples_per_frame;
 
691
 
 
692
    /* Calculate bitstream size */
 
693
    i = attr->info.avg_bps * codec_data->samples_per_frame;
 
694
    j = desc->clock_rate << 3;
 
695
    codec_data->avg_frame_size = (pj_uint16_t)(i / j);
 
696
    if (i % j) ++codec_data->avg_frame_size;
 
697
 
 
698
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
699
    /* Init AMR settings */
 
700
    if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) {
 
701
        amr_settings_t *s;
 
702
        pj_uint8_t octet_align = 0;
 
703
        pj_int8_t enc_mode;
 
704
        
 
705
        enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
 
706
        pj_assert(enc_mode >= 0 && enc_mode <= 8);
 
707
 
 
708
        for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
 
709
            const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
 
710
            
 
711
            /* Fetch octet-align setting. It should be fine to fetch only 
 
712
             * the decoder, since encoder & decoder must use the same setting 
 
713
             * (RFC 4867 section 8.3.1).
 
714
             */
 
715
            if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, 
 
716
                           &STR_FMTP_OCTET_ALIGN) == 0)
 
717
            {
 
718
                octet_align=(pj_uint8_t)
 
719
                            (pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
 
720
                break;
 
721
            }
 
722
        }
 
723
 
 
724
        for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
 
725
            const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
 
726
 
 
727
            /* mode-set, encoding mode is chosen based on local default mode 
 
728
             * setting:
 
729
             * - if local default mode is included in the mode-set, use it
 
730
             * - otherwise, find the closest mode to local default mode;
 
731
             *   if there are two closest modes, prefer to use the higher
 
732
             *   one, e.g: local default mode is 4, the mode-set param
 
733
             *   contains '2,3,5,6', then 5 will be chosen.
 
734
             */
 
735
            if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, 
 
736
                           &STR_FMTP_MODE_SET) == 0)
 
737
            {
 
738
                const char *p;
 
739
                pj_size_t l;
 
740
                pj_int8_t diff = 99;
 
741
                
 
742
                p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
 
743
                l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
 
744
 
 
745
                while (l--) {
 
746
                    if ((desc->pt==PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') ||
 
747
                        (desc->pt==PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8'))
 
748
                    {
 
749
                        pj_int8_t tmp = (pj_int8_t)(*p - '0' - enc_mode);
 
750
 
 
751
                        if (PJ_ABS(diff) > PJ_ABS(tmp) || 
 
752
                            (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
 
753
                        {
 
754
                            diff = tmp;
 
755
                            if (diff == 0) break;
 
756
                        }
 
757
                    }
 
758
                    ++p;
 
759
                }
 
760
 
 
761
                if (diff == 99)
 
762
                    return PJMEDIA_CODEC_EFAILED;
 
763
 
 
764
                enc_mode = (pj_int8_t)(enc_mode + diff);
 
765
 
 
766
                break;
 
767
            }
 
768
        }
 
769
 
 
770
        s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
 
771
        codec_data->codec_setting = s;
 
772
 
 
773
        s->enc_mode = enc_mode;
 
774
        if (s->enc_mode < 0)
 
775
            return PJMEDIA_CODEC_EINMODE;
 
776
 
 
777
        s->enc_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
 
778
        s->enc_setting.octet_aligned = octet_align;
 
779
        s->enc_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
 
780
                                              doesn't do sensitivity bits 
 
781
                                              reordering */
 
782
        s->enc_setting.cmr = 15;
 
783
        
 
784
        s->dec_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
 
785
        s->dec_setting.octet_aligned = octet_align;
 
786
        s->dec_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
 
787
                                              doesn't do sensitivity bits 
 
788
                                              reordering */
 
789
        
 
790
        /* Return back bitrate info to application */
 
791
        attr->info.avg_bps = s->enc_setting.amr_nb?
 
792
                             pjmedia_codec_amrnb_bitrates[s->enc_mode]:
 
793
                             pjmedia_codec_amrwb_bitrates[s->enc_mode];
 
794
    }
 
795
#endif
 
796
 
 
797
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
 
798
    /* Init iLBC settings */
 
799
    if (desc->pt == PJMEDIA_RTP_PT_ILBC)
 
800
    {
 
801
        enum { DEFAULT_MODE = 30 };
 
802
        static pj_str_t STR_MODE = {"mode", 4};
 
803
        pj_uint16_t dec_fmtp_mode = DEFAULT_MODE, 
 
804
                    enc_fmtp_mode = DEFAULT_MODE;
 
805
 
 
806
        /* Get decoder mode */
 
807
        for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
 
808
            if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
 
809
            {
 
810
                dec_fmtp_mode = (pj_uint16_t)
 
811
                                pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
 
812
                break;
 
813
            }
 
814
        }
 
815
 
 
816
        /* Decoder mode must be set */
 
817
        PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30, 
 
818
                         PJMEDIA_CODEC_EINMODE);
 
819
 
 
820
        /* Get encoder mode */
 
821
        for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
 
822
            if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
 
823
            {
 
824
                enc_fmtp_mode = (pj_uint16_t)
 
825
                                pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
 
826
                break;
 
827
            }
 
828
        }
 
829
 
 
830
        PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30, 
 
831
                         PJMEDIA_CODEC_EINMODE);
 
832
 
 
833
        /* Both sides of a bi-directional session MUST use the same "mode" value.
 
834
         * In this point, possible values are only 20 or 30, so when encoder and
 
835
         * decoder modes are not same, just use the default mode, it is 30.
 
836
         */
 
837
        if (enc_fmtp_mode != dec_fmtp_mode) {
 
838
            enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
 
839
            PJ_LOG(4,(pool->obj_name, 
 
840
                      "Normalized iLBC encoder and decoder modes to %d", 
 
841
                      DEFAULT_MODE));
 
842
        }
 
843
 
 
844
        /* Update some attributes based on negotiated mode. */
 
845
        attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
 
846
        attr->info.frm_ptime = dec_fmtp_mode;
 
847
 
 
848
        /* Override average frame size */
 
849
        codec_data->avg_frame_size = (dec_fmtp_mode == 30? 50 : 38);
 
850
 
 
851
        /* Override samples per frame */
 
852
        codec_data->samples_per_frame = (dec_fmtp_mode == 30? 240 : 160);
 
853
    }
 
854
#endif
 
855
 
 
856
    return PJ_SUCCESS;
 
857
}
 
858
 
 
859
/*
 
860
 * Close codec.
 
861
 */
 
862
static pj_status_t codec_close( pjmedia_codec *codec )
 
863
{
 
864
    PJ_UNUSED_ARG(codec);
 
865
 
 
866
    return PJ_SUCCESS;
 
867
}
 
868
 
 
869
 
 
870
/*
 
871
 * Modify codec settings.
 
872
 */
 
873
static pj_status_t codec_modify( pjmedia_codec *codec, 
 
874
                                 const pjmedia_codec_param *attr )
 
875
{
 
876
    /* Not supported yet. */
 
877
    PJ_UNUSED_ARG(codec);
 
878
    PJ_UNUSED_ARG(attr);
 
879
 
 
880
    return PJ_ENOTSUP;
 
881
}
 
882
 
 
883
/*
 
884
 * Get frames in the packet.
 
885
 */
 
886
static pj_status_t codec_parse( pjmedia_codec *codec,
 
887
                                void *pkt,
 
888
                                pj_size_t pkt_size,
 
889
                                const pj_timestamp *ts,
 
890
                                unsigned *frame_cnt,
 
891
                                pjmedia_frame frames[])
 
892
{
 
893
    codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
 
894
    struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
 
895
    unsigned count = 0;
 
896
 
 
897
    PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
 
898
 
 
899
    if (desc->parse != NULL) {
 
900
        return desc->parse(codec_data, pkt,  pkt_size, ts, frame_cnt, frames);
 
901
    }
 
902
 
 
903
    while (pkt_size >= codec_data->avg_frame_size && count < *frame_cnt) {
 
904
        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
 
905
        frames[count].buf = pkt;
 
906
        frames[count].size = codec_data->avg_frame_size;
 
907
        frames[count].timestamp.u64 = ts->u64 + 
 
908
                                      count * codec_data->samples_per_frame;
 
909
 
 
910
        pkt = (pj_uint8_t*)pkt + codec_data->avg_frame_size;
 
911
        pkt_size -= codec_data->avg_frame_size;
 
912
 
 
913
        ++count;
 
914
    }
 
915
 
 
916
    if (pkt_size && count < *frame_cnt) {
 
917
        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
 
918
        frames[count].buf = pkt;
 
919
        frames[count].size = pkt_size;
 
920
        frames[count].timestamp.u64 = ts->u64 + 
 
921
                                       count * codec_data->samples_per_frame;
 
922
        ++count;
 
923
    }
 
924
 
 
925
    *frame_cnt = count;
 
926
    return PJ_SUCCESS;
 
927
}
 
928
 
 
929
/*
 
930
 * Encode frames.
 
931
 */
 
932
static pj_status_t codec_encode( pjmedia_codec *codec, 
 
933
                                 const struct pjmedia_frame *input,
 
934
                                 unsigned output_buf_len, 
 
935
                                 struct pjmedia_frame *output)
 
936
{
 
937
    codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
 
938
    struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
 
939
    const pjmedia_frame_ext *input_ = (const pjmedia_frame_ext*) input;
 
940
 
 
941
    pj_assert(input && input->type == PJMEDIA_FRAME_TYPE_EXTENDED);
 
942
 
 
943
    if (desc->pack != NULL) {
 
944
        desc->pack(codec_data, input_, output_buf_len, output);
 
945
    } else {
 
946
        if (input_->subframe_cnt == 0) {
 
947
            /* DTX */
 
948
            output->buf = NULL;
 
949
            output->size = 0;
 
950
            output->type = PJMEDIA_FRAME_TYPE_NONE;
 
951
        } else {
 
952
            unsigned i;
 
953
            pj_uint8_t *p = output->buf;
 
954
 
 
955
            output->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
956
            output->size = 0;
 
957
            
 
958
            for (i = 0; i < input_->subframe_cnt; ++i) {
 
959
                pjmedia_frame_ext_subframe *sf;
 
960
                unsigned sf_len;
 
961
 
 
962
                sf = pjmedia_frame_ext_get_subframe(input_, i);
 
963
                pj_assert(sf);
 
964
 
 
965
                sf_len = (sf->bitlen + 7) >> 3;
 
966
 
 
967
                pj_memcpy(p, sf->data, sf_len);
 
968
                p += sf_len;
 
969
                output->size += sf_len;
 
970
 
 
971
                /* If there is SID or DTX frame, break the loop. */
 
972
                if (desc->pt == PJMEDIA_RTP_PT_G729 && 
 
973
                    sf_len < codec_data->avg_frame_size)
 
974
                {
 
975
                    break;
 
976
                }
 
977
                
 
978
            }
 
979
        }
 
980
    }
 
981
 
 
982
    output->timestamp = input->timestamp;
 
983
 
 
984
    return PJ_SUCCESS;
 
985
}
 
986
 
 
987
/*
 
988
 * Decode frame.
 
989
 */
 
990
static pj_status_t codec_decode( pjmedia_codec *codec, 
 
991
                                 const struct pjmedia_frame *input,
 
992
                                 unsigned output_buf_len, 
 
993
                                 struct pjmedia_frame *output)
 
994
{
 
995
    codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
 
996
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
997
    struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
 
998
#endif
 
999
    pjmedia_frame_ext *output_ = (pjmedia_frame_ext*) output;
 
1000
 
 
1001
    pj_assert(input);
 
1002
    PJ_UNUSED_ARG(output_buf_len);
 
1003
 
 
1004
#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
1005
    /* Need to rearrange the AMR bitstream, since the bitstream may not be 
 
1006
     * started from bit 0 or may need to be reordered from sensitivity order 
 
1007
     * into encoder bits order.
 
1008
     */
 
1009
    if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) {
 
1010
        pjmedia_frame input_;
 
1011
        pjmedia_codec_amr_pack_setting *setting;
 
1012
 
 
1013
        setting = &((amr_settings_t*)codec_data->codec_setting)->dec_setting;
 
1014
 
 
1015
        input_ = *input;
 
1016
        pjmedia_codec_amr_predecode(input, setting, &input_);
 
1017
        
 
1018
        pjmedia_frame_ext_append_subframe(output_, input_.buf, 
 
1019
                                          (pj_uint16_t)(input_.size << 3),
 
1020
                                          (pj_uint16_t)codec_data->samples_per_frame);
 
1021
        output->timestamp = input->timestamp;
 
1022
        
 
1023
        return PJ_SUCCESS;
 
1024
    }
 
1025
#endif
 
1026
    
 
1027
    pjmedia_frame_ext_append_subframe(output_, input->buf, 
 
1028
                                      (pj_uint16_t)(input->size << 3),
 
1029
                                      (pj_uint16_t)codec_data->samples_per_frame);
 
1030
    output->timestamp = input->timestamp;
 
1031
 
 
1032
    return PJ_SUCCESS;
 
1033
}
 
1034
 
 
1035
/* 
 
1036
 * Recover lost frame.
 
1037
 */
 
1038
static pj_status_t codec_recover( pjmedia_codec *codec, 
 
1039
                                  unsigned output_buf_len, 
 
1040
                                  struct pjmedia_frame *output)
 
1041
{
 
1042
    codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
 
1043
    pjmedia_frame_ext *output_ = (pjmedia_frame_ext*) output;
 
1044
 
 
1045
    PJ_UNUSED_ARG(output_buf_len);
 
1046
 
 
1047
    pjmedia_frame_ext_append_subframe(output_, NULL, 0,
 
1048
                                      (pj_uint16_t)codec_data->samples_per_frame);
 
1049
 
 
1050
    return PJ_SUCCESS;
 
1051
}
 
1052
 
 
1053
#endif  /* PJMEDIA_HAS_PASSTHROUGH_CODECS */
 
1054