blob: b8ef74bd6ea7243dd5e16723a91cce1ae84df53c [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 Prijonoc5859882006-07-31 15:25:14 +000033
Sauw Mingb83b3f32010-04-13 14:29:56 +000034#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
35 #include <AudioToolbox/AudioToolbox.h>
36 #define iLBC_Enc_Inst_t AudioConverterRef
37 #define iLBC_Dec_Inst_t AudioConverterRef
38 #define BLOCKL_MAX 1
39#else
40 #include "../../third_party/ilbc/iLBC_encode.h"
41 #include "../../third_party/ilbc/iLBC_decode.h"
42#endif
Benny Prijonoc5859882006-07-31 15:25:14 +000043
44/*
45 * Only build this file if PJMEDIA_HAS_ILBC_CODEC != 0
46 */
47#if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC != 0
48
49
50#define THIS_FILE "ilbc.c"
51#define CLOCK_RATE 8000
52#define DEFAULT_MODE 30
53
54
55/* Prototypes for iLBC factory */
56static pj_status_t ilbc_test_alloc(pjmedia_codec_factory *factory,
57 const pjmedia_codec_info *id );
58static pj_status_t ilbc_default_attr(pjmedia_codec_factory *factory,
59 const pjmedia_codec_info *id,
60 pjmedia_codec_param *attr );
61static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
62 unsigned *count,
63 pjmedia_codec_info codecs[]);
64static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
65 const pjmedia_codec_info *id,
66 pjmedia_codec **p_codec);
67static pj_status_t ilbc_dealloc_codec(pjmedia_codec_factory *factory,
68 pjmedia_codec *codec );
69
70/* Prototypes for iLBC implementation. */
71static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
72 pj_pool_t *pool );
73static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000074 pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000075static pj_status_t ilbc_codec_close(pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000076static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
77 const pjmedia_codec_param *attr );
Benny Prijonoc5859882006-07-31 15:25:14 +000078static pj_status_t ilbc_codec_parse(pjmedia_codec *codec,
79 void *pkt,
80 pj_size_t pkt_size,
81 const pj_timestamp *ts,
82 unsigned *frame_cnt,
83 pjmedia_frame frames[]);
84static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
85 const struct pjmedia_frame *input,
86 unsigned output_buf_len,
87 struct pjmedia_frame *output);
88static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
89 const struct pjmedia_frame *input,
90 unsigned output_buf_len,
91 struct pjmedia_frame *output);
92static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
93 unsigned output_buf_len,
94 struct pjmedia_frame *output);
95
96/* Definition for iLBC codec operations. */
97static pjmedia_codec_op ilbc_op =
98{
99 &ilbc_codec_init,
100 &ilbc_codec_open,
101 &ilbc_codec_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000102 &ilbc_codec_modify,
Benny Prijonoc5859882006-07-31 15:25:14 +0000103 &ilbc_codec_parse,
104 &ilbc_codec_encode,
105 &ilbc_codec_decode,
106 &ilbc_codec_recover
107};
108
109/* Definition for iLBC codec factory operations. */
110static pjmedia_codec_factory_op ilbc_factory_op =
111{
112 &ilbc_test_alloc,
113 &ilbc_default_attr,
114 &ilbc_enum_codecs,
115 &ilbc_alloc_codec,
116 &ilbc_dealloc_codec
117};
118
119/* iLBC factory */
120static struct ilbc_factory
121{
122 pjmedia_codec_factory base;
123 pjmedia_endpt *endpt;
124
125 int mode;
126 int bps;
127} ilbc_factory;
128
129
130/* iLBC codec private data. */
131struct ilbc_codec
132{
133 pjmedia_codec base;
134 pj_pool_t *pool;
135 char obj_name[PJ_MAX_OBJ_NAME];
136 pjmedia_silence_det *vad;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000137 pj_bool_t vad_enabled;
Benny Prijonoc5859882006-07-31 15:25:14 +0000138 pj_bool_t plc_enabled;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000139 pj_timestamp last_tx;
Benny Prijonoc5859882006-07-31 15:25:14 +0000140
Sauw Mingb83b3f32010-04-13 14:29:56 +0000141
Benny Prijonoc5859882006-07-31 15:25:14 +0000142 pj_bool_t enc_ready;
143 iLBC_Enc_Inst_t enc;
144 unsigned enc_frame_size;
145 unsigned enc_samples_per_frame;
146 float enc_block[BLOCKL_MAX];
147
148 pj_bool_t dec_ready;
149 iLBC_Dec_Inst_t dec;
150 unsigned dec_frame_size;
151 unsigned dec_samples_per_frame;
152 float dec_block[BLOCKL_MAX];
Sauw Mingb83b3f32010-04-13 14:29:56 +0000153
154#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
155 unsigned enc_total_packets;
156 char *enc_buffer;
157 unsigned enc_buffer_offset;
158
159 unsigned dec_total_packets;
160 char *dec_buffer;
161 unsigned dec_buffer_offset;
162#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000163};
164
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000165static pj_str_t STR_MODE = {"mode", 4};
Benny Prijonoc5859882006-07-31 15:25:14 +0000166
167/*
168 * Initialize and register iLBC codec factory to pjmedia endpoint.
169 */
170PJ_DEF(pj_status_t) pjmedia_codec_ilbc_init( pjmedia_endpt *endpt,
171 int mode )
172{
173 pjmedia_codec_mgr *codec_mgr;
174 pj_status_t status;
175
176 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
177 PJ_ASSERT_RETURN(mode==0 || mode==20 || mode==30, PJ_EINVAL);
178
179 /* Create iLBC codec factory. */
180 ilbc_factory.base.op = &ilbc_factory_op;
181 ilbc_factory.base.factory_data = NULL;
182 ilbc_factory.endpt = endpt;
183
184 if (mode == 0)
185 mode = DEFAULT_MODE;
186
187 ilbc_factory.mode = mode;
188
189 if (mode == 20) {
190 ilbc_factory.bps = 15200;
191 } else {
192 ilbc_factory.bps = 13333;
193 }
194
195 /* Get the codec manager. */
196 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
197 if (!codec_mgr)
198 return PJ_EINVALIDOP;
199
200 /* Register codec factory to endpoint. */
201 status = pjmedia_codec_mgr_register_factory(codec_mgr,
202 &ilbc_factory.base);
203 if (status != PJ_SUCCESS)
204 return status;
205
206
207 /* Done. */
208 return PJ_SUCCESS;
209}
210
211
212
213/*
214 * Unregister iLBC codec factory from pjmedia endpoint and deinitialize
215 * the iLBC codec library.
216 */
217PJ_DEF(pj_status_t) pjmedia_codec_ilbc_deinit(void)
218{
219 pjmedia_codec_mgr *codec_mgr;
220 pj_status_t status;
221
222
223 /* Get the codec manager. */
224 codec_mgr = pjmedia_endpt_get_codec_mgr(ilbc_factory.endpt);
225 if (!codec_mgr)
226 return PJ_EINVALIDOP;
227
228 /* Unregister iLBC codec factory. */
229 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
230 &ilbc_factory.base);
231
232 return status;
233}
234
235/*
236 * Check if factory can allocate the specified codec.
237 */
238static pj_status_t ilbc_test_alloc( pjmedia_codec_factory *factory,
239 const pjmedia_codec_info *info )
240{
241 const pj_str_t ilbc_tag = { "iLBC", 4};
242
243 PJ_UNUSED_ARG(factory);
244 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
245
246
247 /* Type MUST be audio. */
248 if (info->type != PJMEDIA_TYPE_AUDIO)
249 return PJMEDIA_CODEC_EUNSUP;
250
251 /* Check encoding name. */
252 if (pj_stricmp(&info->encoding_name, &ilbc_tag) != 0)
253 return PJMEDIA_CODEC_EUNSUP;
254
255 /* Check clock-rate */
256 if (info->clock_rate != CLOCK_RATE)
257 return PJMEDIA_CODEC_EUNSUP;
258
259 /* Channel count must be one */
260 if (info->channel_cnt != 1)
261 return PJMEDIA_CODEC_EUNSUP;
262
263 /* Yes, this should be iLBC! */
264 return PJ_SUCCESS;
265}
266
267
268/*
269 * Generate default attribute.
270 */
271static pj_status_t ilbc_default_attr (pjmedia_codec_factory *factory,
272 const pjmedia_codec_info *id,
273 pjmedia_codec_param *attr )
274{
275 PJ_UNUSED_ARG(factory);
276 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
277
278 PJ_UNUSED_ARG(id);
279 PJ_ASSERT_RETURN(pj_stricmp2(&id->encoding_name, "iLBC")==0, PJ_EINVAL);
280
281 pj_bzero(attr, sizeof(pjmedia_codec_param));
282
283 attr->info.clock_rate = CLOCK_RATE;
284 attr->info.channel_cnt = 1;
285 attr->info.avg_bps = ilbc_factory.bps;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000286 attr->info.max_bps = 15200;
Benny Prijonoc5859882006-07-31 15:25:14 +0000287 attr->info.pcm_bits_per_sample = 16;
288 attr->info.frm_ptime = (short)ilbc_factory.mode;
289 attr->info.pt = PJMEDIA_RTP_PT_ILBC;
290
291 attr->setting.frm_per_pkt = 1;
292 attr->setting.vad = 1;
293 attr->setting.plc = 1;
294 attr->setting.penh = 1;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000295 attr->setting.dec_fmtp.cnt = 1;
296 attr->setting.dec_fmtp.param[0].name = STR_MODE;
297 if (ilbc_factory.mode == 30)
298 attr->setting.dec_fmtp.param[0].val = pj_str("30");
299 else
300 attr->setting.dec_fmtp.param[0].val = pj_str("20");
Benny Prijonoc5859882006-07-31 15:25:14 +0000301
302 return PJ_SUCCESS;
303}
304
305/*
306 * Enum codecs supported by this factory (i.e. only iLBC!).
307 */
308static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
309 unsigned *count,
310 pjmedia_codec_info codecs[])
311{
312 PJ_UNUSED_ARG(factory);
313 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
314
315 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
316
317 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
318
319 codecs[0].encoding_name = pj_str("iLBC");
320 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
321 codecs[0].type = PJMEDIA_TYPE_AUDIO;
322 codecs[0].clock_rate = 8000;
323 codecs[0].channel_cnt = 1;
324
325 *count = 1;
326
327 return PJ_SUCCESS;
328}
329
330/*
331 * Allocate a new iLBC codec instance.
332 */
333static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
334 const pjmedia_codec_info *id,
335 pjmedia_codec **p_codec)
336{
337 pj_pool_t *pool;
338 struct ilbc_codec *codec;
339
340 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
341 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
342
343 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
344 2000, 2000);
345 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
346
Benny Prijonoa1e69682007-05-11 15:14:34 +0000347 codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
Benny Prijonoc5859882006-07-31 15:25:14 +0000348 codec->base.op = &ilbc_op;
349 codec->base.factory = factory;
350 codec->pool = pool;
351
352 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
353 "ilbc%p", codec);
354
355 *p_codec = &codec->base;
356 return PJ_SUCCESS;
357}
358
359
360/*
361 * Free codec.
362 */
363static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
364 pjmedia_codec *codec )
365{
366 struct ilbc_codec *ilbc_codec;
367
368 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
369 PJ_UNUSED_ARG(factory);
370 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
371
372 ilbc_codec = (struct ilbc_codec*) codec;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000373
374#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
375 if (ilbc_codec->enc) {
376 AudioConverterDispose(ilbc_codec->enc);
377 ilbc_codec->enc = NULL;
378 }
379 if (ilbc_codec->dec) {
380 AudioConverterDispose(ilbc_codec->dec);
381 ilbc_codec->dec = NULL;
382 }
383#endif
384
Benny Prijonoc5859882006-07-31 15:25:14 +0000385 pj_pool_release(ilbc_codec->pool);
386
387 return PJ_SUCCESS;
388}
389
390/*
391 * Init codec.
392 */
393static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
394 pj_pool_t *pool )
395{
396 PJ_UNUSED_ARG(codec);
397 PJ_UNUSED_ARG(pool);
398 return PJ_SUCCESS;
399}
400
401/*
402 * Open codec.
403 */
404static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000405 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000406{
407 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000408 pj_status_t status;
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000409 unsigned i;
410 pj_uint16_t dec_fmtp_mode = DEFAULT_MODE,
411 enc_fmtp_mode = DEFAULT_MODE;
Benny Prijonoc5859882006-07-31 15:25:14 +0000412
Sauw Mingb83b3f32010-04-13 14:29:56 +0000413#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
414 AudioStreamBasicDescription srcFormat, dstFormat;
415 UInt32 size;
416
417 srcFormat.mSampleRate = attr->info.clock_rate;
418 srcFormat.mFormatID = kAudioFormatLinearPCM;
419 srcFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
420 | kLinearPCMFormatFlagIsPacked;
421 srcFormat.mBitsPerChannel = attr->info.pcm_bits_per_sample;
422 srcFormat.mChannelsPerFrame = attr->info.channel_cnt;
423 srcFormat.mBytesPerFrame = srcFormat.mChannelsPerFrame
424 * srcFormat.mBitsPerChannel >> 3;
425 srcFormat.mFramesPerPacket = 1;
426 srcFormat.mBytesPerPacket = srcFormat.mBytesPerFrame *
427 srcFormat.mFramesPerPacket;
428
429 memset(&dstFormat, 0, sizeof(dstFormat));
430 dstFormat.mSampleRate = attr->info.clock_rate;
431 dstFormat.mFormatID = kAudioFormatiLBC;
432 dstFormat.mChannelsPerFrame = attr->info.channel_cnt;
433#endif
434
Benny Prijonoc5859882006-07-31 15:25:14 +0000435 pj_assert(ilbc_codec != NULL);
436 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
437 ilbc_codec->dec_ready == PJ_FALSE);
438
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000439 /* Get decoder mode */
440 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
441 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
442 {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000443 dec_fmtp_mode = (pj_uint16_t)
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000444 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
445 break;
446 }
447 }
448
Benny Prijonoc5859882006-07-31 15:25:14 +0000449 /* Decoder mode must be set */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000450 PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
451 PJMEDIA_CODEC_EINMODE);
452
453 /* Get encoder mode */
454 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
455 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
456 {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000457 enc_fmtp_mode = (pj_uint16_t)
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000458 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
459 break;
460 }
461 }
Benny Prijonoc5859882006-07-31 15:25:14 +0000462
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000463 PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30,
464 PJMEDIA_CODEC_EINMODE);
465
466 /* Both sides of a bi-directional session MUST use the same "mode" value.
467 * In this point, possible values are only 20 or 30, so when encoder and
468 * decoder modes are not same, just use the default mode, it is 30.
Benny Prijonoc5859882006-07-31 15:25:14 +0000469 */
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000470 if (enc_fmtp_mode != dec_fmtp_mode) {
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000471 enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
472 PJ_LOG(4,(ilbc_codec->obj_name,
473 "Normalized iLBC encoder and decoder modes to %d",
474 DEFAULT_MODE));
Benny Prijono6865a3f2006-12-30 02:46:57 +0000475 }
476
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000477 /* Update some attributes based on negotiated mode. */
478 attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
479 attr->info.frm_ptime = dec_fmtp_mode;
480
481 /* Create encoder */
Sauw Mingb83b3f32010-04-13 14:29:56 +0000482#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
483 dstFormat.mFramesPerPacket = CLOCK_RATE * enc_fmtp_mode / 1000;
484 dstFormat.mBytesPerPacket = (enc_fmtp_mode == 20? 38 : 50);
485
486 /* Use AudioFormat API to fill out the rest of the description */
487 size = sizeof(dstFormat);
488 AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
489 0, NULL, &size, &dstFormat);
490
491 if (AudioConverterNew(&srcFormat, &dstFormat, &ilbc_codec->enc) != noErr)
492 return PJMEDIA_CODEC_EFAILED;
493 ilbc_codec->enc_frame_size = (enc_fmtp_mode == 20? 38 : 50);
494#else
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000495 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
Sauw Mingb83b3f32010-04-13 14:29:56 +0000496#endif
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000497 ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
Benny Prijonoc5859882006-07-31 15:25:14 +0000498 ilbc_codec->enc_ready = PJ_TRUE;
499
500 /* Create decoder */
Sauw Mingb83b3f32010-04-13 14:29:56 +0000501#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
502 if (AudioConverterNew(&dstFormat, &srcFormat, &ilbc_codec->dec) != noErr)
503 return PJMEDIA_CODEC_EFAILED;
504 ilbc_codec->dec_samples_per_frame = CLOCK_RATE * dec_fmtp_mode / 1000;
505#else
Benny Prijonoc5859882006-07-31 15:25:14 +0000506 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000507 dec_fmtp_mode,
Benny Prijonoc5859882006-07-31 15:25:14 +0000508 attr->setting.penh);
Sauw Mingb83b3f32010-04-13 14:29:56 +0000509#endif
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000510 ilbc_codec->dec_frame_size = (dec_fmtp_mode == 20? 38 : 50);
Benny Prijonoc5859882006-07-31 15:25:14 +0000511 ilbc_codec->dec_ready = PJ_TRUE;
512
513 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000514 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000515
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000516 /* Create silence detector. */
517 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
518 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
519 ilbc_codec->enc_samples_per_frame,
520 &ilbc_codec->vad);
521 if (status != PJ_SUCCESS)
522 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000523
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000524 /* Init last_tx (not necessary because of zalloc, but better
525 * be safe in case someone remove zalloc later.
526 */
527 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
528
Benny Prijonoc5859882006-07-31 15:25:14 +0000529 PJ_LOG(5,(ilbc_codec->obj_name,
Nanang Izzuddin873f3e42009-07-15 17:55:16 +0000530 "iLBC codec opened, mode=%d", dec_fmtp_mode));
Benny Prijonoc5859882006-07-31 15:25:14 +0000531
532 return PJ_SUCCESS;
533}
534
535
536/*
537 * Close codec.
538 */
539static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
540{
541 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
542
543 PJ_UNUSED_ARG(codec);
544
545 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
546
547 return PJ_SUCCESS;
548}
549
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000550/*
551 * Modify codec settings.
552 */
553static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
554 const pjmedia_codec_param *attr )
555{
556 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
557
558 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
559 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
560
561 return PJ_SUCCESS;
562}
Benny Prijonoc5859882006-07-31 15:25:14 +0000563
564/*
565 * Get frames in the packet.
566 */
567static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
568 void *pkt,
569 pj_size_t pkt_size,
570 const pj_timestamp *ts,
571 unsigned *frame_cnt,
572 pjmedia_frame frames[])
573{
574 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
575 unsigned count;
576
577 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
578
579 count = 0;
580 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
581 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
582 frames[count].buf = pkt;
583 frames[count].size = ilbc_codec->dec_frame_size;
584 frames[count].timestamp.u64 = ts->u64 + count *
Sauw Mingb83b3f32010-04-13 14:29:56 +0000585 ilbc_codec->dec_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000586
587 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
588 pkt_size -= ilbc_codec->dec_frame_size;
589
590 ++count;
591 }
592
593 *frame_cnt = count;
594 return PJ_SUCCESS;
595}
596
Sauw Mingb83b3f32010-04-13 14:29:56 +0000597#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
598static OSStatus encodeDataProc (
599 AudioConverterRef inAudioConverter,
600 UInt32 *ioNumberDataPackets,
601 AudioBufferList *ioData,
602 AudioStreamPacketDescription **outDataPacketDescription,
603 void *inUserData
604)
605{
606 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)inUserData;
607
608 /* Initialize in case of failure */
609 ioData->mBuffers[0].mData = NULL;
610 ioData->mBuffers[0].mDataByteSize = 0;
611
612 if (ilbc_codec->enc_total_packets < *ioNumberDataPackets) {
613 *ioNumberDataPackets = ilbc_codec->enc_total_packets;
614 }
615
616 if (*ioNumberDataPackets) {
617 ioData->mBuffers[0].mData = ilbc_codec->enc_buffer +
618 ilbc_codec->enc_buffer_offset;
619 ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets *
620 ilbc_codec->enc_samples_per_frame
621 << 1;
622 ilbc_codec->enc_buffer_offset += ioData->mBuffers[0].mDataByteSize;
623 }
624
625 ilbc_codec->enc_total_packets -= *ioNumberDataPackets;
626 return noErr;
627}
628
629static OSStatus decodeDataProc (
630 AudioConverterRef inAudioConverter,
631 UInt32 *ioNumberDataPackets,
632 AudioBufferList *ioData,
633 AudioStreamPacketDescription **outDataPacketDescription,
634 void *inUserData
635)
636{
637 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)inUserData;
638
639 /* Initialize in case of failure */
640 ioData->mBuffers[0].mData = NULL;
641 ioData->mBuffers[0].mDataByteSize = 0;
642
643 if (ilbc_codec->dec_total_packets < *ioNumberDataPackets) {
644 *ioNumberDataPackets = ilbc_codec->dec_total_packets;
645 }
646
647 if (*ioNumberDataPackets) {
648 ioData->mBuffers[0].mData = ilbc_codec->dec_buffer +
649 ilbc_codec->dec_buffer_offset;
650 ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets *
651 ilbc_codec->dec_frame_size;
652 ilbc_codec->dec_buffer_offset += ioData->mBuffers[0].mDataByteSize;
653 }
654
655 ilbc_codec->dec_total_packets -= *ioNumberDataPackets;
656 return noErr;
657}
658#endif
659
Benny Prijonoc5859882006-07-31 15:25:14 +0000660/*
661 * Encode frame.
662 */
663static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
664 const struct pjmedia_frame *input,
665 unsigned output_buf_len,
666 struct pjmedia_frame *output)
667{
668 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000669 pj_int16_t *pcm_in;
670 unsigned nsamples;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000671#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
672 UInt32 npackets;
673 OSStatus err;
674 AudioBufferList theABL;
675#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000676
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000677 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000678
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000679 pcm_in = (pj_int16_t*)input->buf;
680 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000681
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000682 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
683 PJMEDIA_CODEC_EPCMFRMINLEN);
684 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
685 ilbc_codec->enc_samples_per_frame,
686 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000687
688 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000689 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000690 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000691 pj_int32_t silence_period;
692
693 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
694 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000695
696 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000697 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000698 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000699 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000700 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +0000701 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
702 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000))
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000703 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000704 output->type = PJMEDIA_FRAME_TYPE_NONE;
705 output->buf = NULL;
706 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000707 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000708 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000709 } else {
710 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000711 }
712 }
713
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000714 /* Encode */
715 output->size = 0;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000716#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
717 npackets = nsamples / ilbc_codec->enc_samples_per_frame;
718
719 theABL.mNumberBuffers = 1;
720 theABL.mBuffers[0].mNumberChannels = 1;
721 theABL.mBuffers[0].mDataByteSize = output_buf_len;
722 theABL.mBuffers[0].mData = output->buf;
723
724 ilbc_codec->enc_total_packets = npackets;
725 ilbc_codec->enc_buffer = (char *)input->buf;
726 ilbc_codec->enc_buffer_offset = 0;
727
728 err = AudioConverterFillComplexBuffer(ilbc_codec->enc, encodeDataProc,
729 ilbc_codec, &npackets,
730 &theABL, NULL);
731 if (err == noErr) {
732 output->size = npackets * ilbc_codec->enc_frame_size;
733 }
734#else
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000735 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
736 unsigned i;
737
738 /* Convert to float */
739 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
740 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
741 }
742
743 iLBC_encode((unsigned char *)output->buf + output->size,
744 ilbc_codec->enc_block,
745 &ilbc_codec->enc);
746
747 output->size += ilbc_codec->enc.no_of_bytes;
748 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000749 }
Sauw Mingb83b3f32010-04-13 14:29:56 +0000750#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000751
Benny Prijonoc5859882006-07-31 15:25:14 +0000752 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000753 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000754
755 return PJ_SUCCESS;
756}
757
758/*
759 * Decode frame.
760 */
761static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
762 const struct pjmedia_frame *input,
763 unsigned output_buf_len,
764 struct pjmedia_frame *output)
765{
766 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000767#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
768 UInt32 npackets;
769 OSStatus err;
770 AudioBufferList theABL;
771#else
Benny Prijonoc5859882006-07-31 15:25:14 +0000772 unsigned i;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000773#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000774
775 pj_assert(ilbc_codec != NULL);
776 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
777
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000778 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000779 return PJMEDIA_CODEC_EPCMTOOSHORT;
780
781 if (input->size != ilbc_codec->dec_frame_size)
782 return PJMEDIA_CODEC_EFRMINLEN;
783
784 /* Decode to temporary buffer */
Sauw Mingb83b3f32010-04-13 14:29:56 +0000785#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
786 npackets = input->size / ilbc_codec->dec_frame_size *
787 ilbc_codec->dec_samples_per_frame;
788
789 theABL.mNumberBuffers = 1;
790 theABL.mBuffers[0].mNumberChannels = 1;
791 theABL.mBuffers[0].mDataByteSize = output_buf_len;
792 theABL.mBuffers[0].mData = output->buf;
793
794 ilbc_codec->dec_total_packets = npackets;
795 ilbc_codec->dec_buffer = (char *)input->buf;
796 ilbc_codec->dec_buffer_offset = 0;
797
798 err = AudioConverterFillComplexBuffer(ilbc_codec->dec, decodeDataProc,
799 ilbc_codec, &npackets,
800 &theABL, NULL);
801 if (err == noErr) {
802 output->size = npackets * (ilbc_codec->dec_samples_per_frame << 1);
803 }
804#else
Benny Prijonoa1e69682007-05-11 15:14:34 +0000805 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000806 &ilbc_codec->dec, 1);
807
808 /* Convert decodec samples from float to short */
809 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
810 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
811 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000812 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Sauw Mingb83b3f32010-04-13 14:29:56 +0000813#endif
814
Benny Prijonoc5859882006-07-31 15:25:14 +0000815 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000816 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000817
818 return PJ_SUCCESS;
819}
820
821
822/*
823 * Recover lost frame.
824 */
825static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
826 unsigned output_buf_len,
827 struct pjmedia_frame *output)
828{
829 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000830#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
831 UInt32 npackets;
832 OSStatus err;
833 AudioBufferList theABL;
834#else
Benny Prijonoc5859882006-07-31 15:25:14 +0000835 unsigned i;
Sauw Mingb83b3f32010-04-13 14:29:56 +0000836#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000837
838 pj_assert(ilbc_codec != NULL);
839 PJ_ASSERT_RETURN(output, PJ_EINVAL);
840
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000841 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000842 return PJMEDIA_CODEC_EPCMTOOSHORT;
843
844 /* Decode to temporary buffer */
Sauw Mingb83b3f32010-04-13 14:29:56 +0000845#ifdef PJMEDIA_ILBC_CODEC_USE_COREAUDIO
846 npackets = 1;
847
848 theABL.mNumberBuffers = 1;
849 theABL.mBuffers[0].mNumberChannels = 1;
850 theABL.mBuffers[0].mDataByteSize = output_buf_len;
851 theABL.mBuffers[0].mData = output->buf;
852
853 ilbc_codec->dec_total_packets = npackets;
854 ilbc_codec->dec_buffer_offset = 0;
855 if (ilbc_codec->dec_buffer) {
856 err = AudioConverterFillComplexBuffer(ilbc_codec->dec, decodeDataProc,
857 ilbc_codec, &npackets,
858 &theABL, NULL);
859 if (err == noErr) {
860 output->size = npackets *
861 (ilbc_codec->dec_samples_per_frame << 1);
862 }
863 } else {
864 output->size = npackets * (ilbc_codec->dec_samples_per_frame << 1);
865 pj_bzero(output->buf, output->size);
866 }
867#else
Benny Prijonoc5859882006-07-31 15:25:14 +0000868 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
869
870 /* Convert decodec samples from float to short */
871 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
872 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
873 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000874 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Sauw Mingb83b3f32010-04-13 14:29:56 +0000875#endif
Benny Prijonoc5859882006-07-31 15:25:14 +0000876 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
877
878 return PJ_SUCCESS;
879}
880
881
882#endif /* PJMEDIA_HAS_ILBC_CODEC */