blob: b8a2e58be5b31d8b9e247dbe44a5ede2e079db28 [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 Izzuddin23a00b72008-08-25 13:58:25 +0000379 unsigned i, dec_fmtp_mode = 0, enc_fmtp_mode = 0;
Benny Prijonoc5859882006-07-31 15:25:14 +0000380
381 pj_assert(ilbc_codec != NULL);
382 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
383 ilbc_codec->dec_ready == PJ_FALSE);
384
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000385 /* Get decoder mode */
386 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
387 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
388 {
389 dec_fmtp_mode = (unsigned)
390 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
391 break;
392 }
393 }
394
Benny Prijonoc5859882006-07-31 15:25:14 +0000395 /* Decoder mode must be set */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000396 PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
397 PJMEDIA_CODEC_EINMODE);
398
399 /* Get encoder mode */
400 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
401 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
402 {
403 enc_fmtp_mode = (unsigned)
404 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
405 break;
406 }
407 }
Benny Prijonoc5859882006-07-31 15:25:14 +0000408
409 /* The enc mode must be set in the attribute
410 * (from the mode parameter in fmtp attribute in the SDP
411 * received from remote)
412 */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000413 if (enc_fmtp_mode == 0)
414 enc_fmtp_mode = dec_fmtp_mode;
Benny Prijonoc5859882006-07-31 15:25:14 +0000415
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000416 PJ_ASSERT_RETURN(enc_fmtp_mode==20 ||
417 enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
Benny Prijonoc5859882006-07-31 15:25:14 +0000418
Benny Prijono6865a3f2006-12-30 02:46:57 +0000419 /* Update enc_ptime in the param */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000420 if (enc_fmtp_mode != dec_fmtp_mode) {
421 attr->info.enc_ptime = (pj_uint16_t)enc_fmtp_mode;
Benny Prijono6865a3f2006-12-30 02:46:57 +0000422 } else {
423 attr->info.enc_ptime = 0;
424 }
425
Benny Prijonoc5859882006-07-31 15:25:14 +0000426 /* Create enc */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000427 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
428 ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
Benny Prijonoc5859882006-07-31 15:25:14 +0000429 ilbc_codec->enc_ready = PJ_TRUE;
430
431 /* Create decoder */
432 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000433 dec_fmtp_mode,
Benny Prijonoc5859882006-07-31 15:25:14 +0000434 attr->setting.penh);
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000435 if (dec_fmtp_mode == 20)
Benny Prijonoc5859882006-07-31 15:25:14 +0000436 ilbc_codec->dec_frame_size = 38;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000437 else if (dec_fmtp_mode == 30)
Benny Prijonoc5859882006-07-31 15:25:14 +0000438 ilbc_codec->dec_frame_size = 50;
439 else {
440 pj_assert(!"Invalid iLBC mode");
441 ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
442 }
443 ilbc_codec->dec_ready = PJ_TRUE;
444
445 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000446 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000447
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000448 /* Create silence detector. */
449 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
450 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
451 ilbc_codec->enc_samples_per_frame,
452 &ilbc_codec->vad);
453 if (status != PJ_SUCCESS)
454 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000455
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000456 /* Init last_tx (not necessary because of zalloc, but better
457 * be safe in case someone remove zalloc later.
458 */
459 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
460
Benny Prijonoc5859882006-07-31 15:25:14 +0000461 PJ_LOG(5,(ilbc_codec->obj_name,
462 "iLBC codec opened, encoder mode=%d, decoder mode=%d",
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000463 enc_fmtp_mode, dec_fmtp_mode));
Benny Prijonoc5859882006-07-31 15:25:14 +0000464
465 return PJ_SUCCESS;
466}
467
468
469/*
470 * Close codec.
471 */
472static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
473{
474 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
475
476 PJ_UNUSED_ARG(codec);
477
478 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
479
480 return PJ_SUCCESS;
481}
482
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000483/*
484 * Modify codec settings.
485 */
486static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
487 const pjmedia_codec_param *attr )
488{
489 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
490
491 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
492 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
493
494 return PJ_SUCCESS;
495}
Benny Prijonoc5859882006-07-31 15:25:14 +0000496
497/*
498 * Get frames in the packet.
499 */
500static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
501 void *pkt,
502 pj_size_t pkt_size,
503 const pj_timestamp *ts,
504 unsigned *frame_cnt,
505 pjmedia_frame frames[])
506{
507 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
508 unsigned count;
509
510 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
511
512 count = 0;
513 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
514 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
515 frames[count].buf = pkt;
516 frames[count].size = ilbc_codec->dec_frame_size;
517 frames[count].timestamp.u64 = ts->u64 + count *
518 ilbc_codec->dec_samples_per_frame;
519
520 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
521 pkt_size -= ilbc_codec->dec_frame_size;
522
523 ++count;
524 }
525
526 *frame_cnt = count;
527 return PJ_SUCCESS;
528}
529
530/*
531 * Encode frame.
532 */
533static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
534 const struct pjmedia_frame *input,
535 unsigned output_buf_len,
536 struct pjmedia_frame *output)
537{
538 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000539 pj_int16_t *pcm_in;
540 unsigned nsamples;
Benny Prijonoc5859882006-07-31 15:25:14 +0000541
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000542 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000543
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000544 pcm_in = (pj_int16_t*)input->buf;
545 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000546
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000547 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
548 PJMEDIA_CODEC_EPCMFRMINLEN);
549 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
550 ilbc_codec->enc_samples_per_frame,
551 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000552
553 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000554 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000555 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000556 pj_int32_t silence_period;
557
558 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
559 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000560
561 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000562 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000563 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000564 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000565 if (is_silence &&
566 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonodd3d0022008-06-14 16:52:04 +0000567 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000568 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000569 output->type = PJMEDIA_FRAME_TYPE_NONE;
570 output->buf = NULL;
571 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000572 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000573 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000574 } else {
575 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000576 }
577 }
578
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000579 /* Encode */
580 output->size = 0;
581 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
582 unsigned i;
583
584 /* Convert to float */
585 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
586 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
587 }
588
589 iLBC_encode((unsigned char *)output->buf + output->size,
590 ilbc_codec->enc_block,
591 &ilbc_codec->enc);
592
593 output->size += ilbc_codec->enc.no_of_bytes;
594 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000595 }
596
Benny Prijonoc5859882006-07-31 15:25:14 +0000597 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000598 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000599
600 return PJ_SUCCESS;
601}
602
603/*
604 * Decode frame.
605 */
606static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
607 const struct pjmedia_frame *input,
608 unsigned output_buf_len,
609 struct pjmedia_frame *output)
610{
611 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
612 unsigned i;
613
614 pj_assert(ilbc_codec != NULL);
615 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
616
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000617 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000618 return PJMEDIA_CODEC_EPCMTOOSHORT;
619
620 if (input->size != ilbc_codec->dec_frame_size)
621 return PJMEDIA_CODEC_EFRMINLEN;
622
623 /* Decode to temporary buffer */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000624 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000625 &ilbc_codec->dec, 1);
626
627 /* Convert decodec samples from float to short */
628 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
629 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
630 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000631 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000632 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000633 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000634
635 return PJ_SUCCESS;
636}
637
638
639/*
640 * Recover lost frame.
641 */
642static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
643 unsigned output_buf_len,
644 struct pjmedia_frame *output)
645{
646 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
647 unsigned i;
648
649 pj_assert(ilbc_codec != NULL);
650 PJ_ASSERT_RETURN(output, PJ_EINVAL);
651
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000652 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000653 return PJMEDIA_CODEC_EPCMTOOSHORT;
654
655 /* Decode to temporary buffer */
656 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
657
658 /* Convert decodec samples from float to short */
659 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
660 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
661 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000662 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000663 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
664
665 return PJ_SUCCESS;
666}
667
668
669#endif /* PJMEDIA_HAS_ILBC_CODEC */
670