blob: 2134e77b756aa02af5ad085f7f9fe10df831bb33 [file] [log] [blame]
Benny Prijonoc5859882006-07-31 15:25:14 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 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
146
147
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;
267 attr->info.pcm_bits_per_sample = 16;
268 attr->info.frm_ptime = (short)ilbc_factory.mode;
269 attr->info.pt = PJMEDIA_RTP_PT_ILBC;
270
271 attr->setting.frm_per_pkt = 1;
272 attr->setting.vad = 1;
273 attr->setting.plc = 1;
274 attr->setting.penh = 1;
275 attr->setting.dec_fmtp_mode = (pj_uint8_t)ilbc_factory.mode;
276
277 return PJ_SUCCESS;
278}
279
280/*
281 * Enum codecs supported by this factory (i.e. only iLBC!).
282 */
283static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
284 unsigned *count,
285 pjmedia_codec_info codecs[])
286{
287 PJ_UNUSED_ARG(factory);
288 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
289
290 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
291
292 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
293
294 codecs[0].encoding_name = pj_str("iLBC");
295 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
296 codecs[0].type = PJMEDIA_TYPE_AUDIO;
297 codecs[0].clock_rate = 8000;
298 codecs[0].channel_cnt = 1;
299
300 *count = 1;
301
302 return PJ_SUCCESS;
303}
304
305/*
306 * Allocate a new iLBC codec instance.
307 */
308static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
309 const pjmedia_codec_info *id,
310 pjmedia_codec **p_codec)
311{
312 pj_pool_t *pool;
313 struct ilbc_codec *codec;
314
315 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
316 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
317
318 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
319 2000, 2000);
320 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
321
Benny Prijonoa1e69682007-05-11 15:14:34 +0000322 codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
Benny Prijonoc5859882006-07-31 15:25:14 +0000323 codec->base.op = &ilbc_op;
324 codec->base.factory = factory;
325 codec->pool = pool;
326
327 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
328 "ilbc%p", codec);
329
330 *p_codec = &codec->base;
331 return PJ_SUCCESS;
332}
333
334
335/*
336 * Free codec.
337 */
338static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
339 pjmedia_codec *codec )
340{
341 struct ilbc_codec *ilbc_codec;
342
343 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
344 PJ_UNUSED_ARG(factory);
345 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
346
347 ilbc_codec = (struct ilbc_codec*) codec;
348 pj_pool_release(ilbc_codec->pool);
349
350 return PJ_SUCCESS;
351}
352
353/*
354 * Init codec.
355 */
356static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
357 pj_pool_t *pool )
358{
359 PJ_UNUSED_ARG(codec);
360 PJ_UNUSED_ARG(pool);
361 return PJ_SUCCESS;
362}
363
364/*
365 * Open codec.
366 */
367static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000368 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000369{
370 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000371 pj_status_t status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000372
373 pj_assert(ilbc_codec != NULL);
374 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
375 ilbc_codec->dec_ready == PJ_FALSE);
376
377 /* Decoder mode must be set */
378 PJ_ASSERT_RETURN(attr->setting.dec_fmtp_mode==20 ||
379 attr->setting.dec_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
380
381 /* The enc mode must be set in the attribute
382 * (from the mode parameter in fmtp attribute in the SDP
383 * received from remote)
384 */
385 if (attr->setting.enc_fmtp_mode == 0)
386 attr->setting.enc_fmtp_mode = attr->setting.dec_fmtp_mode;
387
388 PJ_ASSERT_RETURN(attr->setting.enc_fmtp_mode==20 ||
389 attr->setting.enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
390
Benny Prijono6865a3f2006-12-30 02:46:57 +0000391 /* Update enc_ptime in the param */
392 if (attr->setting.enc_fmtp_mode != attr->setting.dec_fmtp_mode) {
393 attr->info.enc_ptime = attr->setting.enc_fmtp_mode;
394 } else {
395 attr->info.enc_ptime = 0;
396 }
397
Benny Prijonoc5859882006-07-31 15:25:14 +0000398 /* Create enc */
399 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc,
400 attr->setting.enc_fmtp_mode);
401 ilbc_codec->enc_samples_per_frame = CLOCK_RATE*attr->setting.enc_fmtp_mode/
402 1000;
403 ilbc_codec->enc_ready = PJ_TRUE;
404
405 /* Create decoder */
406 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
407 attr->setting.dec_fmtp_mode,
408 attr->setting.penh);
409 if (attr->setting.dec_fmtp_mode == 20)
410 ilbc_codec->dec_frame_size = 38;
Benny Prijono1d9b9a42006-09-25 13:40:12 +0000411 else if (attr->setting.dec_fmtp_mode == 30)
Benny Prijonoc5859882006-07-31 15:25:14 +0000412 ilbc_codec->dec_frame_size = 50;
413 else {
414 pj_assert(!"Invalid iLBC mode");
415 ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
416 }
417 ilbc_codec->dec_ready = PJ_TRUE;
418
419 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000420 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000421
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000422 /* Create silence detector. */
423 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
424 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
425 ilbc_codec->enc_samples_per_frame,
426 &ilbc_codec->vad);
427 if (status != PJ_SUCCESS)
428 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000429
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000430 /* Init last_tx (not necessary because of zalloc, but better
431 * be safe in case someone remove zalloc later.
432 */
433 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
434
Benny Prijonoc5859882006-07-31 15:25:14 +0000435 PJ_LOG(5,(ilbc_codec->obj_name,
436 "iLBC codec opened, encoder mode=%d, decoder mode=%d",
437 attr->setting.enc_fmtp_mode, attr->setting.dec_fmtp_mode));
438
439 return PJ_SUCCESS;
440}
441
442
443/*
444 * Close codec.
445 */
446static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
447{
448 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
449
450 PJ_UNUSED_ARG(codec);
451
452 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
453
454 return PJ_SUCCESS;
455}
456
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000457/*
458 * Modify codec settings.
459 */
460static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
461 const pjmedia_codec_param *attr )
462{
463 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
464
465 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
466 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
467
468 return PJ_SUCCESS;
469}
Benny Prijonoc5859882006-07-31 15:25:14 +0000470
471/*
472 * Get frames in the packet.
473 */
474static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
475 void *pkt,
476 pj_size_t pkt_size,
477 const pj_timestamp *ts,
478 unsigned *frame_cnt,
479 pjmedia_frame frames[])
480{
481 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
482 unsigned count;
483
484 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
485
486 count = 0;
487 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
488 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
489 frames[count].buf = pkt;
490 frames[count].size = ilbc_codec->dec_frame_size;
491 frames[count].timestamp.u64 = ts->u64 + count *
492 ilbc_codec->dec_samples_per_frame;
493
494 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
495 pkt_size -= ilbc_codec->dec_frame_size;
496
497 ++count;
498 }
499
500 *frame_cnt = count;
501 return PJ_SUCCESS;
502}
503
504/*
505 * Encode frame.
506 */
507static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
508 const struct pjmedia_frame *input,
509 unsigned output_buf_len,
510 struct pjmedia_frame *output)
511{
512 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000513 pj_int16_t *pcm_in;
514 unsigned nsamples;
Benny Prijonoc5859882006-07-31 15:25:14 +0000515
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000516 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000517
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000518 pcm_in = (pj_int16_t*)input->buf;
519 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000520
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000521 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
522 PJMEDIA_CODEC_EPCMFRMINLEN);
523 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
524 ilbc_codec->enc_samples_per_frame,
525 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000526
527 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000528 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000529 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000530 pj_int32_t silence_period;
531
532 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
533 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000534
535 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000536 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000537 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000538 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000539 if (is_silence &&
540 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
541 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)
542 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000543 output->type = PJMEDIA_FRAME_TYPE_NONE;
544 output->buf = NULL;
545 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000546 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000547 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000548 } else {
549 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000550 }
551 }
552
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000553 /* Encode */
554 output->size = 0;
555 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
556 unsigned i;
557
558 /* Convert to float */
559 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
560 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
561 }
562
563 iLBC_encode((unsigned char *)output->buf + output->size,
564 ilbc_codec->enc_block,
565 &ilbc_codec->enc);
566
567 output->size += ilbc_codec->enc.no_of_bytes;
568 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000569 }
570
Benny Prijonoc5859882006-07-31 15:25:14 +0000571 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000572 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000573
574 return PJ_SUCCESS;
575}
576
577/*
578 * Decode frame.
579 */
580static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
581 const struct pjmedia_frame *input,
582 unsigned output_buf_len,
583 struct pjmedia_frame *output)
584{
585 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
586 unsigned i;
587
588 pj_assert(ilbc_codec != NULL);
589 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
590
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000591 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000592 return PJMEDIA_CODEC_EPCMTOOSHORT;
593
594 if (input->size != ilbc_codec->dec_frame_size)
595 return PJMEDIA_CODEC_EFRMINLEN;
596
597 /* Decode to temporary buffer */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000598 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000599 &ilbc_codec->dec, 1);
600
601 /* Convert decodec samples from float to short */
602 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
603 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
604 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000605 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000606 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000607 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000608
609 return PJ_SUCCESS;
610}
611
612
613/*
614 * Recover lost frame.
615 */
616static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
617 unsigned output_buf_len,
618 struct pjmedia_frame *output)
619{
620 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
621 unsigned i;
622
623 pj_assert(ilbc_codec != NULL);
624 PJ_ASSERT_RETURN(output, PJ_EINVAL);
625
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000626 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000627 return PJMEDIA_CODEC_EPCMTOOSHORT;
628
629 /* Decode to temporary buffer */
630 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
631
632 /* Convert decodec samples from float to short */
633 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
634 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
635 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000636 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000637 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
638
639 return PJ_SUCCESS;
640}
641
642
643#endif /* PJMEDIA_HAS_ILBC_CODEC */
644