blob: 1c7fd1fe6eab6f7358a98bd0da17cba4fb40c18b [file] [log] [blame]
Benny Prijonoc5859882006-07-31 15:25:14 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonoc5859882006-07-31 15:25:14 +00005 *
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/ilbc.h>
21#include <pjmedia-codec/types.h>
22#include <pjmedia/codec.h>
23#include <pjmedia/errno.h>
24#include <pjmedia/endpoint.h>
25#include <pjmedia/plc.h>
26#include <pjmedia/port.h>
27#include <pjmedia/silencedet.h>
28#include <pj/assert.h>
29#include <pj/log.h>
30#include <pj/pool.h>
31#include <pj/string.h>
32#include <pj/os.h>
Benny Prijonof830c1b2007-04-07 12:47:34 +000033#include "../../third_party/ilbc/iLBC_encode.h"
34#include "../../third_party/ilbc/iLBC_decode.h"
Benny Prijonoc5859882006-07-31 15:25:14 +000035
36
37/*
38 * Only build this file if PJMEDIA_HAS_ILBC_CODEC != 0
39 */
40#if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC != 0
41
42
43#define THIS_FILE "ilbc.c"
44#define CLOCK_RATE 8000
45#define DEFAULT_MODE 30
46
47
48/* Prototypes for iLBC factory */
49static pj_status_t ilbc_test_alloc(pjmedia_codec_factory *factory,
50 const pjmedia_codec_info *id );
51static pj_status_t ilbc_default_attr(pjmedia_codec_factory *factory,
52 const pjmedia_codec_info *id,
53 pjmedia_codec_param *attr );
54static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
55 unsigned *count,
56 pjmedia_codec_info codecs[]);
57static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
58 const pjmedia_codec_info *id,
59 pjmedia_codec **p_codec);
60static pj_status_t ilbc_dealloc_codec(pjmedia_codec_factory *factory,
61 pjmedia_codec *codec );
62
63/* Prototypes for iLBC implementation. */
64static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
65 pj_pool_t *pool );
66static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000067 pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000068static pj_status_t ilbc_codec_close(pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000069static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
70 const pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000071static pj_status_t ilbc_codec_parse(pjmedia_codec *codec,
72 void *pkt,
73 pj_size_t pkt_size,
74 const pj_timestamp *ts,
75 unsigned *frame_cnt,
76 pjmedia_frame frames[]);
77static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
78 const struct pjmedia_frame *input,
79 unsigned output_buf_len,
80 struct pjmedia_frame *output);
81static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
82 const struct pjmedia_frame *input,
83 unsigned output_buf_len,
84 struct pjmedia_frame *output);
85static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
86 unsigned output_buf_len,
87 struct pjmedia_frame *output);
88
89/* Definition for iLBC codec operations. */
90static pjmedia_codec_op ilbc_op =
91{
92 &ilbc_codec_init,
93 &ilbc_codec_open,
94 &ilbc_codec_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +000095 &ilbc_codec_modify,
Benny Prijonoc5859882006-07-31 15:25:14 +000096 &ilbc_codec_parse,
97 &ilbc_codec_encode,
98 &ilbc_codec_decode,
99 &ilbc_codec_recover
100};
101
102/* Definition for iLBC codec factory operations. */
103static pjmedia_codec_factory_op ilbc_factory_op =
104{
105 &ilbc_test_alloc,
106 &ilbc_default_attr,
107 &ilbc_enum_codecs,
108 &ilbc_alloc_codec,
109 &ilbc_dealloc_codec
110};
111
112/* iLBC factory */
113static struct ilbc_factory
114{
115 pjmedia_codec_factory base;
116 pjmedia_endpt *endpt;
117
118 int mode;
119 int bps;
120} ilbc_factory;
121
122
123/* iLBC codec private data. */
124struct ilbc_codec
125{
126 pjmedia_codec base;
127 pj_pool_t *pool;
128 char obj_name[PJ_MAX_OBJ_NAME];
129 pjmedia_silence_det *vad;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000130 pj_bool_t vad_enabled;
Benny Prijonoc5859882006-07-31 15:25:14 +0000131 pj_bool_t plc_enabled;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000132 pj_timestamp last_tx;
Benny Prijonoc5859882006-07-31 15:25:14 +0000133
134 pj_bool_t enc_ready;
135 iLBC_Enc_Inst_t enc;
136 unsigned enc_frame_size;
137 unsigned enc_samples_per_frame;
138 float enc_block[BLOCKL_MAX];
139
140 pj_bool_t dec_ready;
141 iLBC_Dec_Inst_t dec;
142 unsigned dec_frame_size;
143 unsigned dec_samples_per_frame;
144 float dec_block[BLOCKL_MAX];
145};
146
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000147static pj_str_t STR_MODE = {"mode", 4};
Benny Prijonoc5859882006-07-31 15:25:14 +0000148
149/*
150 * Initialize and register iLBC codec factory to pjmedia endpoint.
151 */
152PJ_DEF(pj_status_t) pjmedia_codec_ilbc_init( pjmedia_endpt *endpt,
153 int mode )
154{
155 pjmedia_codec_mgr *codec_mgr;
156 pj_status_t status;
157
158 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
159 PJ_ASSERT_RETURN(mode==0 || mode==20 || mode==30, PJ_EINVAL);
160
161 /* Create iLBC codec factory. */
162 ilbc_factory.base.op = &ilbc_factory_op;
163 ilbc_factory.base.factory_data = NULL;
164 ilbc_factory.endpt = endpt;
165
166 if (mode == 0)
167 mode = DEFAULT_MODE;
168
169 ilbc_factory.mode = mode;
170
171 if (mode == 20) {
172 ilbc_factory.bps = 15200;
173 } else {
174 ilbc_factory.bps = 13333;
175 }
176
177 /* Get the codec manager. */
178 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
179 if (!codec_mgr)
180 return PJ_EINVALIDOP;
181
182 /* Register codec factory to endpoint. */
183 status = pjmedia_codec_mgr_register_factory(codec_mgr,
184 &ilbc_factory.base);
185 if (status != PJ_SUCCESS)
186 return status;
187
188
189 /* Done. */
190 return PJ_SUCCESS;
191}
192
193
194
195/*
196 * Unregister iLBC codec factory from pjmedia endpoint and deinitialize
197 * the iLBC codec library.
198 */
199PJ_DEF(pj_status_t) pjmedia_codec_ilbc_deinit(void)
200{
201 pjmedia_codec_mgr *codec_mgr;
202 pj_status_t status;
203
204
205 /* Get the codec manager. */
206 codec_mgr = pjmedia_endpt_get_codec_mgr(ilbc_factory.endpt);
207 if (!codec_mgr)
208 return PJ_EINVALIDOP;
209
210 /* Unregister iLBC codec factory. */
211 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
212 &ilbc_factory.base);
213
214 return status;
215}
216
217/*
218 * Check if factory can allocate the specified codec.
219 */
220static pj_status_t ilbc_test_alloc( pjmedia_codec_factory *factory,
221 const pjmedia_codec_info *info )
222{
223 const pj_str_t ilbc_tag = { "iLBC", 4};
224
225 PJ_UNUSED_ARG(factory);
226 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
227
228
229 /* Type MUST be audio. */
230 if (info->type != PJMEDIA_TYPE_AUDIO)
231 return PJMEDIA_CODEC_EUNSUP;
232
233 /* Check encoding name. */
234 if (pj_stricmp(&info->encoding_name, &ilbc_tag) != 0)
235 return PJMEDIA_CODEC_EUNSUP;
236
237 /* Check clock-rate */
238 if (info->clock_rate != CLOCK_RATE)
239 return PJMEDIA_CODEC_EUNSUP;
240
241 /* Channel count must be one */
242 if (info->channel_cnt != 1)
243 return PJMEDIA_CODEC_EUNSUP;
244
245 /* Yes, this should be iLBC! */
246 return PJ_SUCCESS;
247}
248
249
250/*
251 * Generate default attribute.
252 */
253static pj_status_t ilbc_default_attr (pjmedia_codec_factory *factory,
254 const pjmedia_codec_info *id,
255 pjmedia_codec_param *attr )
256{
257 PJ_UNUSED_ARG(factory);
258 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
259
260 PJ_UNUSED_ARG(id);
261 PJ_ASSERT_RETURN(pj_stricmp2(&id->encoding_name, "iLBC")==0, PJ_EINVAL);
262
263 pj_bzero(attr, sizeof(pjmedia_codec_param));
264
265 attr->info.clock_rate = CLOCK_RATE;
266 attr->info.channel_cnt = 1;
267 attr->info.avg_bps = ilbc_factory.bps;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000268 attr->info.max_bps = 15200;
Benny Prijonoc5859882006-07-31 15:25:14 +0000269 attr->info.pcm_bits_per_sample = 16;
270 attr->info.frm_ptime = (short)ilbc_factory.mode;
271 attr->info.pt = PJMEDIA_RTP_PT_ILBC;
272
273 attr->setting.frm_per_pkt = 1;
274 attr->setting.vad = 1;
275 attr->setting.plc = 1;
276 attr->setting.penh = 1;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000277 attr->setting.dec_fmtp.cnt = 1;
278 attr->setting.dec_fmtp.param[0].name = STR_MODE;
279 if (ilbc_factory.mode == 30)
280 attr->setting.dec_fmtp.param[0].val = pj_str("30");
281 else
282 attr->setting.dec_fmtp.param[0].val = pj_str("20");
Benny Prijonoc5859882006-07-31 15:25:14 +0000283
284 return PJ_SUCCESS;
285}
286
287/*
288 * Enum codecs supported by this factory (i.e. only iLBC!).
289 */
290static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
291 unsigned *count,
292 pjmedia_codec_info codecs[])
293{
294 PJ_UNUSED_ARG(factory);
295 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
296
297 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
298
299 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
300
301 codecs[0].encoding_name = pj_str("iLBC");
302 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
303 codecs[0].type = PJMEDIA_TYPE_AUDIO;
304 codecs[0].clock_rate = 8000;
305 codecs[0].channel_cnt = 1;
306
307 *count = 1;
308
309 return PJ_SUCCESS;
310}
311
312/*
313 * Allocate a new iLBC codec instance.
314 */
315static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
316 const pjmedia_codec_info *id,
317 pjmedia_codec **p_codec)
318{
319 pj_pool_t *pool;
320 struct ilbc_codec *codec;
321
322 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
323 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
324
325 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
326 2000, 2000);
327 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
328
Benny Prijonoa1e69682007-05-11 15:14:34 +0000329 codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
Benny Prijonoc5859882006-07-31 15:25:14 +0000330 codec->base.op = &ilbc_op;
331 codec->base.factory = factory;
332 codec->pool = pool;
333
334 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
335 "ilbc%p", codec);
336
337 *p_codec = &codec->base;
338 return PJ_SUCCESS;
339}
340
341
342/*
343 * Free codec.
344 */
345static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
346 pjmedia_codec *codec )
347{
348 struct ilbc_codec *ilbc_codec;
349
350 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
351 PJ_UNUSED_ARG(factory);
352 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
353
354 ilbc_codec = (struct ilbc_codec*) codec;
355 pj_pool_release(ilbc_codec->pool);
356
357 return PJ_SUCCESS;
358}
359
360/*
361 * Init codec.
362 */
363static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
364 pj_pool_t *pool )
365{
366 PJ_UNUSED_ARG(codec);
367 PJ_UNUSED_ARG(pool);
368 return PJ_SUCCESS;
369}
370
371/*
372 * Open codec.
373 */
374static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000375 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000376{
377 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000378 pj_status_t status;
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000379 unsigned i;
380 pj_uint16_t dec_fmtp_mode = DEFAULT_MODE,
381 enc_fmtp_mode = DEFAULT_MODE;
Benny Prijonoc5859882006-07-31 15:25:14 +0000382
383 pj_assert(ilbc_codec != NULL);
384 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
385 ilbc_codec->dec_ready == PJ_FALSE);
386
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000387 /* Get decoder mode */
388 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
389 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
390 {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000391 dec_fmtp_mode = (pj_uint16_t)
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000392 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
393 break;
394 }
395 }
396
Benny Prijonoc5859882006-07-31 15:25:14 +0000397 /* Decoder mode must be set */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000398 PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
399 PJMEDIA_CODEC_EINMODE);
400
401 /* Get encoder mode */
402 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
403 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
404 {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000405 enc_fmtp_mode = (pj_uint16_t)
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000406 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
407 break;
408 }
409 }
Benny Prijonoc5859882006-07-31 15:25:14 +0000410
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000411 PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30,
412 PJMEDIA_CODEC_EINMODE);
413
414 /* Both sides of a bi-directional session MUST use the same "mode" value.
415 * In this point, possible values are only 20 or 30, so when encoder and
416 * decoder modes are not same, just use the default mode, it is 30.
Benny Prijonoc5859882006-07-31 15:25:14 +0000417 */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000418 if (enc_fmtp_mode != dec_fmtp_mode) {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000419 enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
420 PJ_LOG(4,(ilbc_codec->obj_name,
421 "Normalized iLBC encoder and decoder modes to %d",
422 DEFAULT_MODE));
Benny Prijono6865a3f2006-12-30 02:46:57 +0000423 }
424
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000425 /* Update some attributes based on negotiated mode. */
426 attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
427 attr->info.frm_ptime = dec_fmtp_mode;
428
429 /* Create encoder */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000430 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
431 ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
Benny Prijonoc5859882006-07-31 15:25:14 +0000432 ilbc_codec->enc_ready = PJ_TRUE;
433
434 /* Create decoder */
435 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000436 dec_fmtp_mode,
Benny Prijonoc5859882006-07-31 15:25:14 +0000437 attr->setting.penh);
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000438 ilbc_codec->dec_frame_size = (dec_fmtp_mode == 20? 38 : 50);
Benny Prijonoc5859882006-07-31 15:25:14 +0000439 ilbc_codec->dec_ready = PJ_TRUE;
440
441 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000442 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000443
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000444 /* Create silence detector. */
445 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
446 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
447 ilbc_codec->enc_samples_per_frame,
448 &ilbc_codec->vad);
449 if (status != PJ_SUCCESS)
450 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000451
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000452 /* Init last_tx (not necessary because of zalloc, but better
453 * be safe in case someone remove zalloc later.
454 */
455 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
456
Benny Prijonoc5859882006-07-31 15:25:14 +0000457 PJ_LOG(5,(ilbc_codec->obj_name,
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000458 "iLBC codec opened, mode=%d", dec_fmtp_mode));
Benny Prijonoc5859882006-07-31 15:25:14 +0000459
460 return PJ_SUCCESS;
461}
462
463
464/*
465 * Close codec.
466 */
467static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
468{
469 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
470
471 PJ_UNUSED_ARG(codec);
472
473 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
474
475 return PJ_SUCCESS;
476}
477
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000478/*
479 * Modify codec settings.
480 */
481static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
482 const pjmedia_codec_param *attr )
483{
484 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
485
486 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
487 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
488
489 return PJ_SUCCESS;
490}
Benny Prijonoc5859882006-07-31 15:25:14 +0000491
492/*
493 * Get frames in the packet.
494 */
495static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
496 void *pkt,
497 pj_size_t pkt_size,
498 const pj_timestamp *ts,
499 unsigned *frame_cnt,
500 pjmedia_frame frames[])
501{
502 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
503 unsigned count;
504
505 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
506
507 count = 0;
508 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
509 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
510 frames[count].buf = pkt;
511 frames[count].size = ilbc_codec->dec_frame_size;
512 frames[count].timestamp.u64 = ts->u64 + count *
513 ilbc_codec->dec_samples_per_frame;
514
515 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
516 pkt_size -= ilbc_codec->dec_frame_size;
517
518 ++count;
519 }
520
521 *frame_cnt = count;
522 return PJ_SUCCESS;
523}
524
525/*
526 * Encode frame.
527 */
528static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
529 const struct pjmedia_frame *input,
530 unsigned output_buf_len,
531 struct pjmedia_frame *output)
532{
533 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000534 pj_int16_t *pcm_in;
535 unsigned nsamples;
Benny Prijonoc5859882006-07-31 15:25:14 +0000536
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000537 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000538
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000539 pcm_in = (pj_int16_t*)input->buf;
540 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000541
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000542 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
543 PJMEDIA_CODEC_EPCMFRMINLEN);
544 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
545 ilbc_codec->enc_samples_per_frame,
546 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000547
548 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000549 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000550 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000551 pj_int32_t silence_period;
552
553 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
554 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000555
556 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000557 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000558 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000559 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000560 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +0000561 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
562 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000))
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000563 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000564 output->type = PJMEDIA_FRAME_TYPE_NONE;
565 output->buf = NULL;
566 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000567 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000568 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000569 } else {
570 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000571 }
572 }
573
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000574 /* Encode */
575 output->size = 0;
576 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
577 unsigned i;
578
579 /* Convert to float */
580 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
581 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
582 }
583
584 iLBC_encode((unsigned char *)output->buf + output->size,
585 ilbc_codec->enc_block,
586 &ilbc_codec->enc);
587
588 output->size += ilbc_codec->enc.no_of_bytes;
589 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000590 }
591
Benny Prijonoc5859882006-07-31 15:25:14 +0000592 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000593 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000594
595 return PJ_SUCCESS;
596}
597
598/*
599 * Decode frame.
600 */
601static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
602 const struct pjmedia_frame *input,
603 unsigned output_buf_len,
604 struct pjmedia_frame *output)
605{
606 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
607 unsigned i;
608
609 pj_assert(ilbc_codec != NULL);
610 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
611
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000612 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000613 return PJMEDIA_CODEC_EPCMTOOSHORT;
614
615 if (input->size != ilbc_codec->dec_frame_size)
616 return PJMEDIA_CODEC_EFRMINLEN;
617
618 /* Decode to temporary buffer */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000619 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000620 &ilbc_codec->dec, 1);
621
622 /* Convert decodec samples from float to short */
623 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
624 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
625 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000626 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000627 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000628 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000629
630 return PJ_SUCCESS;
631}
632
633
634/*
635 * Recover lost frame.
636 */
637static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
638 unsigned output_buf_len,
639 struct pjmedia_frame *output)
640{
641 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
642 unsigned i;
643
644 pj_assert(ilbc_codec != NULL);
645 PJ_ASSERT_RETURN(output, PJ_EINVAL);
646
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000647 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000648 return PJMEDIA_CODEC_EPCMTOOSHORT;
649
650 /* Decode to temporary buffer */
651 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
652
653 /* Convert decodec samples from float to short */
654 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
655 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
656 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000657 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000658 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
659
660 return PJ_SUCCESS;
661}
662
663
664#endif /* PJMEDIA_HAS_ILBC_CODEC */
665