blob: 650631674fa2f14a1b3a9100c8ff6e5a3b73e6c0 [file] [log] [blame]
Benny Prijonoc5859882006-07-31 15:25:14 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C)2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonoc5859882006-07-31 15:25:14 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-codec/ilbc.h>
20#include <pjmedia-codec/types.h>
21#include <pjmedia/codec.h>
22#include <pjmedia/errno.h>
23#include <pjmedia/endpoint.h>
24#include <pjmedia/plc.h>
25#include <pjmedia/port.h>
26#include <pjmedia/silencedet.h>
27#include <pj/assert.h>
28#include <pj/log.h>
29#include <pj/pool.h>
30#include <pj/string.h>
31#include <pj/os.h>
Benny Prijonof830c1b2007-04-07 12:47:34 +000032#include "../../third_party/ilbc/iLBC_encode.h"
33#include "../../third_party/ilbc/iLBC_decode.h"
Benny Prijonoc5859882006-07-31 15:25:14 +000034
35
36/*
37 * Only build this file if PJMEDIA_HAS_ILBC_CODEC != 0
38 */
39#if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC != 0
40
41
42#define THIS_FILE "ilbc.c"
43#define CLOCK_RATE 8000
44#define DEFAULT_MODE 30
45
46
47/* Prototypes for iLBC factory */
48static pj_status_t ilbc_test_alloc(pjmedia_codec_factory *factory,
49 const pjmedia_codec_info *id );
50static pj_status_t ilbc_default_attr(pjmedia_codec_factory *factory,
51 const pjmedia_codec_info *id,
52 pjmedia_codec_param *attr );
53static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
54 unsigned *count,
55 pjmedia_codec_info codecs[]);
56static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
57 const pjmedia_codec_info *id,
58 pjmedia_codec **p_codec);
59static pj_status_t ilbc_dealloc_codec(pjmedia_codec_factory *factory,
60 pjmedia_codec *codec );
61
62/* Prototypes for iLBC implementation. */
63static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
64 pj_pool_t *pool );
65static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000066 pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000067static pj_status_t ilbc_codec_close(pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000068static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
69 const pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000070static pj_status_t ilbc_codec_parse(pjmedia_codec *codec,
71 void *pkt,
72 pj_size_t pkt_size,
73 const pj_timestamp *ts,
74 unsigned *frame_cnt,
75 pjmedia_frame frames[]);
76static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
77 const struct pjmedia_frame *input,
78 unsigned output_buf_len,
79 struct pjmedia_frame *output);
80static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
81 const struct pjmedia_frame *input,
82 unsigned output_buf_len,
83 struct pjmedia_frame *output);
84static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
85 unsigned output_buf_len,
86 struct pjmedia_frame *output);
87
88/* Definition for iLBC codec operations. */
89static pjmedia_codec_op ilbc_op =
90{
91 &ilbc_codec_init,
92 &ilbc_codec_open,
93 &ilbc_codec_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +000094 &ilbc_codec_modify,
Benny Prijonoc5859882006-07-31 15:25:14 +000095 &ilbc_codec_parse,
96 &ilbc_codec_encode,
97 &ilbc_codec_decode,
98 &ilbc_codec_recover
99};
100
101/* Definition for iLBC codec factory operations. */
102static pjmedia_codec_factory_op ilbc_factory_op =
103{
104 &ilbc_test_alloc,
105 &ilbc_default_attr,
106 &ilbc_enum_codecs,
107 &ilbc_alloc_codec,
108 &ilbc_dealloc_codec
109};
110
111/* iLBC factory */
112static struct ilbc_factory
113{
114 pjmedia_codec_factory base;
115 pjmedia_endpt *endpt;
116
117 int mode;
118 int bps;
119} ilbc_factory;
120
121
122/* iLBC codec private data. */
123struct ilbc_codec
124{
125 pjmedia_codec base;
126 pj_pool_t *pool;
127 char obj_name[PJ_MAX_OBJ_NAME];
128 pjmedia_silence_det *vad;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000129 pj_bool_t vad_enabled;
Benny Prijonoc5859882006-07-31 15:25:14 +0000130 pj_bool_t plc_enabled;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000131 pj_timestamp last_tx;
Benny Prijonoc5859882006-07-31 15:25:14 +0000132
133 pj_bool_t enc_ready;
134 iLBC_Enc_Inst_t enc;
135 unsigned enc_frame_size;
136 unsigned enc_samples_per_frame;
137 float enc_block[BLOCKL_MAX];
138
139 pj_bool_t dec_ready;
140 iLBC_Dec_Inst_t dec;
141 unsigned dec_frame_size;
142 unsigned dec_samples_per_frame;
143 float dec_block[BLOCKL_MAX];
144};
145
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000146static pj_str_t STR_MODE = {"mode", 4};
Benny Prijonoc5859882006-07-31 15:25:14 +0000147
148/*
149 * Initialize and register iLBC codec factory to pjmedia endpoint.
150 */
151PJ_DEF(pj_status_t) pjmedia_codec_ilbc_init( pjmedia_endpt *endpt,
152 int mode )
153{
154 pjmedia_codec_mgr *codec_mgr;
155 pj_status_t status;
156
157 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
158 PJ_ASSERT_RETURN(mode==0 || mode==20 || mode==30, PJ_EINVAL);
159
160 /* Create iLBC codec factory. */
161 ilbc_factory.base.op = &ilbc_factory_op;
162 ilbc_factory.base.factory_data = NULL;
163 ilbc_factory.endpt = endpt;
164
165 if (mode == 0)
166 mode = DEFAULT_MODE;
167
168 ilbc_factory.mode = mode;
169
170 if (mode == 20) {
171 ilbc_factory.bps = 15200;
172 } else {
173 ilbc_factory.bps = 13333;
174 }
175
176 /* Get the codec manager. */
177 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
178 if (!codec_mgr)
179 return PJ_EINVALIDOP;
180
181 /* Register codec factory to endpoint. */
182 status = pjmedia_codec_mgr_register_factory(codec_mgr,
183 &ilbc_factory.base);
184 if (status != PJ_SUCCESS)
185 return status;
186
187
188 /* Done. */
189 return PJ_SUCCESS;
190}
191
192
193
194/*
195 * Unregister iLBC codec factory from pjmedia endpoint and deinitialize
196 * the iLBC codec library.
197 */
198PJ_DEF(pj_status_t) pjmedia_codec_ilbc_deinit(void)
199{
200 pjmedia_codec_mgr *codec_mgr;
201 pj_status_t status;
202
203
204 /* Get the codec manager. */
205 codec_mgr = pjmedia_endpt_get_codec_mgr(ilbc_factory.endpt);
206 if (!codec_mgr)
207 return PJ_EINVALIDOP;
208
209 /* Unregister iLBC codec factory. */
210 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
211 &ilbc_factory.base);
212
213 return status;
214}
215
216/*
217 * Check if factory can allocate the specified codec.
218 */
219static pj_status_t ilbc_test_alloc( pjmedia_codec_factory *factory,
220 const pjmedia_codec_info *info )
221{
222 const pj_str_t ilbc_tag = { "iLBC", 4};
223
224 PJ_UNUSED_ARG(factory);
225 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
226
227
228 /* Type MUST be audio. */
229 if (info->type != PJMEDIA_TYPE_AUDIO)
230 return PJMEDIA_CODEC_EUNSUP;
231
232 /* Check encoding name. */
233 if (pj_stricmp(&info->encoding_name, &ilbc_tag) != 0)
234 return PJMEDIA_CODEC_EUNSUP;
235
236 /* Check clock-rate */
237 if (info->clock_rate != CLOCK_RATE)
238 return PJMEDIA_CODEC_EUNSUP;
239
240 /* Channel count must be one */
241 if (info->channel_cnt != 1)
242 return PJMEDIA_CODEC_EUNSUP;
243
244 /* Yes, this should be iLBC! */
245 return PJ_SUCCESS;
246}
247
248
249/*
250 * Generate default attribute.
251 */
252static pj_status_t ilbc_default_attr (pjmedia_codec_factory *factory,
253 const pjmedia_codec_info *id,
254 pjmedia_codec_param *attr )
255{
256 PJ_UNUSED_ARG(factory);
257 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
258
259 PJ_UNUSED_ARG(id);
260 PJ_ASSERT_RETURN(pj_stricmp2(&id->encoding_name, "iLBC")==0, PJ_EINVAL);
261
262 pj_bzero(attr, sizeof(pjmedia_codec_param));
263
264 attr->info.clock_rate = CLOCK_RATE;
265 attr->info.channel_cnt = 1;
266 attr->info.avg_bps = ilbc_factory.bps;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000267 attr->info.max_bps = 15200;
Benny Prijonoc5859882006-07-31 15:25:14 +0000268 attr->info.pcm_bits_per_sample = 16;
269 attr->info.frm_ptime = (short)ilbc_factory.mode;
270 attr->info.pt = PJMEDIA_RTP_PT_ILBC;
271
272 attr->setting.frm_per_pkt = 1;
273 attr->setting.vad = 1;
274 attr->setting.plc = 1;
275 attr->setting.penh = 1;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000276 attr->setting.dec_fmtp.cnt = 1;
277 attr->setting.dec_fmtp.param[0].name = STR_MODE;
278 if (ilbc_factory.mode == 30)
279 attr->setting.dec_fmtp.param[0].val = pj_str("30");
280 else
281 attr->setting.dec_fmtp.param[0].val = pj_str("20");
Benny Prijonoc5859882006-07-31 15:25:14 +0000282
283 return PJ_SUCCESS;
284}
285
286/*
287 * Enum codecs supported by this factory (i.e. only iLBC!).
288 */
289static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
290 unsigned *count,
291 pjmedia_codec_info codecs[])
292{
293 PJ_UNUSED_ARG(factory);
294 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
295
296 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
297
298 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
299
300 codecs[0].encoding_name = pj_str("iLBC");
301 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
302 codecs[0].type = PJMEDIA_TYPE_AUDIO;
303 codecs[0].clock_rate = 8000;
304 codecs[0].channel_cnt = 1;
305
306 *count = 1;
307
308 return PJ_SUCCESS;
309}
310
311/*
312 * Allocate a new iLBC codec instance.
313 */
314static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
315 const pjmedia_codec_info *id,
316 pjmedia_codec **p_codec)
317{
318 pj_pool_t *pool;
319 struct ilbc_codec *codec;
320
321 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
322 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
323
324 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
325 2000, 2000);
326 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
327
Benny Prijonoa1e69682007-05-11 15:14:34 +0000328 codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
Benny Prijonoc5859882006-07-31 15:25:14 +0000329 codec->base.op = &ilbc_op;
330 codec->base.factory = factory;
331 codec->pool = pool;
332
333 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
334 "ilbc%p", codec);
335
336 *p_codec = &codec->base;
337 return PJ_SUCCESS;
338}
339
340
341/*
342 * Free codec.
343 */
344static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
345 pjmedia_codec *codec )
346{
347 struct ilbc_codec *ilbc_codec;
348
349 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
350 PJ_UNUSED_ARG(factory);
351 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
352
353 ilbc_codec = (struct ilbc_codec*) codec;
354 pj_pool_release(ilbc_codec->pool);
355
356 return PJ_SUCCESS;
357}
358
359/*
360 * Init codec.
361 */
362static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
363 pj_pool_t *pool )
364{
365 PJ_UNUSED_ARG(codec);
366 PJ_UNUSED_ARG(pool);
367 return PJ_SUCCESS;
368}
369
370/*
371 * Open codec.
372 */
373static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000374 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000375{
376 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000377 pj_status_t status;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000378 unsigned i, dec_fmtp_mode = 0, enc_fmtp_mode = 0;
Benny Prijonoc5859882006-07-31 15:25:14 +0000379
380 pj_assert(ilbc_codec != NULL);
381 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
382 ilbc_codec->dec_ready == PJ_FALSE);
383
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000384 /* Get decoder mode */
385 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
386 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
387 {
388 dec_fmtp_mode = (unsigned)
389 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
390 break;
391 }
392 }
393
Benny Prijonoc5859882006-07-31 15:25:14 +0000394 /* Decoder mode must be set */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000395 PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
396 PJMEDIA_CODEC_EINMODE);
397
398 /* Get encoder mode */
399 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
400 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
401 {
402 enc_fmtp_mode = (unsigned)
403 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
404 break;
405 }
406 }
Benny Prijonoc5859882006-07-31 15:25:14 +0000407
408 /* The enc mode must be set in the attribute
409 * (from the mode parameter in fmtp attribute in the SDP
410 * received from remote)
411 */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000412 if (enc_fmtp_mode == 0)
413 enc_fmtp_mode = dec_fmtp_mode;
Benny Prijonoc5859882006-07-31 15:25:14 +0000414
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000415 PJ_ASSERT_RETURN(enc_fmtp_mode==20 ||
416 enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
Benny Prijonoc5859882006-07-31 15:25:14 +0000417
Benny Prijono6865a3f2006-12-30 02:46:57 +0000418 /* Update enc_ptime in the param */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000419 if (enc_fmtp_mode != dec_fmtp_mode) {
420 attr->info.enc_ptime = (pj_uint16_t)enc_fmtp_mode;
Benny Prijono6865a3f2006-12-30 02:46:57 +0000421 } else {
422 attr->info.enc_ptime = 0;
423 }
424
Benny Prijonoc5859882006-07-31 15:25:14 +0000425 /* Create enc */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000426 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
427 ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
Benny Prijonoc5859882006-07-31 15:25:14 +0000428 ilbc_codec->enc_ready = PJ_TRUE;
429
430 /* Create decoder */
431 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000432 dec_fmtp_mode,
Benny Prijonoc5859882006-07-31 15:25:14 +0000433 attr->setting.penh);
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000434 if (dec_fmtp_mode == 20)
Benny Prijonoc5859882006-07-31 15:25:14 +0000435 ilbc_codec->dec_frame_size = 38;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000436 else if (dec_fmtp_mode == 30)
Benny Prijonoc5859882006-07-31 15:25:14 +0000437 ilbc_codec->dec_frame_size = 50;
438 else {
439 pj_assert(!"Invalid iLBC mode");
440 ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
441 }
442 ilbc_codec->dec_ready = PJ_TRUE;
443
444 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000445 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000446
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000447 /* Create silence detector. */
448 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
449 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
450 ilbc_codec->enc_samples_per_frame,
451 &ilbc_codec->vad);
452 if (status != PJ_SUCCESS)
453 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000454
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000455 /* Init last_tx (not necessary because of zalloc, but better
456 * be safe in case someone remove zalloc later.
457 */
458 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
459
Benny Prijonoc5859882006-07-31 15:25:14 +0000460 PJ_LOG(5,(ilbc_codec->obj_name,
461 "iLBC codec opened, encoder mode=%d, decoder mode=%d",
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000462 enc_fmtp_mode, dec_fmtp_mode));
Benny Prijonoc5859882006-07-31 15:25:14 +0000463
464 return PJ_SUCCESS;
465}
466
467
468/*
469 * Close codec.
470 */
471static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
472{
473 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
474
475 PJ_UNUSED_ARG(codec);
476
477 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
478
479 return PJ_SUCCESS;
480}
481
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000482/*
483 * Modify codec settings.
484 */
485static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
486 const pjmedia_codec_param *attr )
487{
488 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
489
490 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
491 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
492
493 return PJ_SUCCESS;
494}
Benny Prijonoc5859882006-07-31 15:25:14 +0000495
496/*
497 * Get frames in the packet.
498 */
499static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
500 void *pkt,
501 pj_size_t pkt_size,
502 const pj_timestamp *ts,
503 unsigned *frame_cnt,
504 pjmedia_frame frames[])
505{
506 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
507 unsigned count;
508
509 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
510
511 count = 0;
512 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
513 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
514 frames[count].buf = pkt;
515 frames[count].size = ilbc_codec->dec_frame_size;
516 frames[count].timestamp.u64 = ts->u64 + count *
517 ilbc_codec->dec_samples_per_frame;
518
519 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
520 pkt_size -= ilbc_codec->dec_frame_size;
521
522 ++count;
523 }
524
525 *frame_cnt = count;
526 return PJ_SUCCESS;
527}
528
529/*
530 * Encode frame.
531 */
532static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
533 const struct pjmedia_frame *input,
534 unsigned output_buf_len,
535 struct pjmedia_frame *output)
536{
537 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000538 pj_int16_t *pcm_in;
539 unsigned nsamples;
Benny Prijonoc5859882006-07-31 15:25:14 +0000540
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000541 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000542
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000543 pcm_in = (pj_int16_t*)input->buf;
544 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000545
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000546 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
547 PJMEDIA_CODEC_EPCMFRMINLEN);
548 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
549 ilbc_codec->enc_samples_per_frame,
550 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000551
552 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000553 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000554 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000555 pj_int32_t silence_period;
556
557 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
558 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000559
560 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000561 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000562 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000563 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000564 if (is_silence &&
565 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonodd3d0022008-06-14 16:52:04 +0000566 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000567 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000568 output->type = PJMEDIA_FRAME_TYPE_NONE;
569 output->buf = NULL;
570 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000571 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000572 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000573 } else {
574 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000575 }
576 }
577
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000578 /* Encode */
579 output->size = 0;
580 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
581 unsigned i;
582
583 /* Convert to float */
584 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
585 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
586 }
587
588 iLBC_encode((unsigned char *)output->buf + output->size,
589 ilbc_codec->enc_block,
590 &ilbc_codec->enc);
591
592 output->size += ilbc_codec->enc.no_of_bytes;
593 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000594 }
595
Benny Prijonoc5859882006-07-31 15:25:14 +0000596 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000597 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000598
599 return PJ_SUCCESS;
600}
601
602/*
603 * Decode frame.
604 */
605static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
606 const struct pjmedia_frame *input,
607 unsigned output_buf_len,
608 struct pjmedia_frame *output)
609{
610 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
611 unsigned i;
612
613 pj_assert(ilbc_codec != NULL);
614 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
615
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000616 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000617 return PJMEDIA_CODEC_EPCMTOOSHORT;
618
619 if (input->size != ilbc_codec->dec_frame_size)
620 return PJMEDIA_CODEC_EFRMINLEN;
621
622 /* Decode to temporary buffer */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000623 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000624 &ilbc_codec->dec, 1);
625
626 /* Convert decodec samples from float to short */
627 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
628 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
629 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000630 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000631 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000632 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000633
634 return PJ_SUCCESS;
635}
636
637
638/*
639 * Recover lost frame.
640 */
641static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
642 unsigned output_buf_len,
643 struct pjmedia_frame *output)
644{
645 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
646 unsigned i;
647
648 pj_assert(ilbc_codec != NULL);
649 PJ_ASSERT_RETURN(output, PJ_EINVAL);
650
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000651 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000652 return PJMEDIA_CODEC_EPCMTOOSHORT;
653
654 /* Decode to temporary buffer */
655 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
656
657 /* Convert decodec samples from float to short */
658 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
659 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
660 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000661 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000662 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
663
664 return PJ_SUCCESS;
665}
666
667
668#endif /* PJMEDIA_HAS_ILBC_CODEC */
669