blob: 92b783104b92d9d07790c9ac32fe5a68936a3f13 [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;
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;
276 attr->setting.dec_fmtp_mode = (pj_uint8_t)ilbc_factory.mode;
277
278 return PJ_SUCCESS;
279}
280
281/*
282 * Enum codecs supported by this factory (i.e. only iLBC!).
283 */
284static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
285 unsigned *count,
286 pjmedia_codec_info codecs[])
287{
288 PJ_UNUSED_ARG(factory);
289 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
290
291 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
292
293 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
294
295 codecs[0].encoding_name = pj_str("iLBC");
296 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
297 codecs[0].type = PJMEDIA_TYPE_AUDIO;
298 codecs[0].clock_rate = 8000;
299 codecs[0].channel_cnt = 1;
300
301 *count = 1;
302
303 return PJ_SUCCESS;
304}
305
306/*
307 * Allocate a new iLBC codec instance.
308 */
309static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
310 const pjmedia_codec_info *id,
311 pjmedia_codec **p_codec)
312{
313 pj_pool_t *pool;
314 struct ilbc_codec *codec;
315
316 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
317 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
318
319 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
320 2000, 2000);
321 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
322
Benny Prijonoa1e69682007-05-11 15:14:34 +0000323 codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
Benny Prijonoc5859882006-07-31 15:25:14 +0000324 codec->base.op = &ilbc_op;
325 codec->base.factory = factory;
326 codec->pool = pool;
327
328 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
329 "ilbc%p", codec);
330
331 *p_codec = &codec->base;
332 return PJ_SUCCESS;
333}
334
335
336/*
337 * Free codec.
338 */
339static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
340 pjmedia_codec *codec )
341{
342 struct ilbc_codec *ilbc_codec;
343
344 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
345 PJ_UNUSED_ARG(factory);
346 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
347
348 ilbc_codec = (struct ilbc_codec*) codec;
349 pj_pool_release(ilbc_codec->pool);
350
351 return PJ_SUCCESS;
352}
353
354/*
355 * Init codec.
356 */
357static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
358 pj_pool_t *pool )
359{
360 PJ_UNUSED_ARG(codec);
361 PJ_UNUSED_ARG(pool);
362 return PJ_SUCCESS;
363}
364
365/*
366 * Open codec.
367 */
368static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000369 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000370{
371 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000372 pj_status_t status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000373
374 pj_assert(ilbc_codec != NULL);
375 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
376 ilbc_codec->dec_ready == PJ_FALSE);
377
378 /* Decoder mode must be set */
379 PJ_ASSERT_RETURN(attr->setting.dec_fmtp_mode==20 ||
380 attr->setting.dec_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
381
382 /* The enc mode must be set in the attribute
383 * (from the mode parameter in fmtp attribute in the SDP
384 * received from remote)
385 */
386 if (attr->setting.enc_fmtp_mode == 0)
387 attr->setting.enc_fmtp_mode = attr->setting.dec_fmtp_mode;
388
389 PJ_ASSERT_RETURN(attr->setting.enc_fmtp_mode==20 ||
390 attr->setting.enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
391
Benny Prijono6865a3f2006-12-30 02:46:57 +0000392 /* Update enc_ptime in the param */
393 if (attr->setting.enc_fmtp_mode != attr->setting.dec_fmtp_mode) {
394 attr->info.enc_ptime = attr->setting.enc_fmtp_mode;
395 } else {
396 attr->info.enc_ptime = 0;
397 }
398
Benny Prijonoc5859882006-07-31 15:25:14 +0000399 /* Create enc */
400 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc,
401 attr->setting.enc_fmtp_mode);
402 ilbc_codec->enc_samples_per_frame = CLOCK_RATE*attr->setting.enc_fmtp_mode/
403 1000;
404 ilbc_codec->enc_ready = PJ_TRUE;
405
406 /* Create decoder */
407 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
408 attr->setting.dec_fmtp_mode,
409 attr->setting.penh);
410 if (attr->setting.dec_fmtp_mode == 20)
411 ilbc_codec->dec_frame_size = 38;
Benny Prijono1d9b9a42006-09-25 13:40:12 +0000412 else if (attr->setting.dec_fmtp_mode == 30)
Benny Prijonoc5859882006-07-31 15:25:14 +0000413 ilbc_codec->dec_frame_size = 50;
414 else {
415 pj_assert(!"Invalid iLBC mode");
416 ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
417 }
418 ilbc_codec->dec_ready = PJ_TRUE;
419
420 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000421 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000422
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000423 /* Create silence detector. */
424 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
425 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
426 ilbc_codec->enc_samples_per_frame,
427 &ilbc_codec->vad);
428 if (status != PJ_SUCCESS)
429 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000430
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000431 /* Init last_tx (not necessary because of zalloc, but better
432 * be safe in case someone remove zalloc later.
433 */
434 pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0);
435
Benny Prijonoc5859882006-07-31 15:25:14 +0000436 PJ_LOG(5,(ilbc_codec->obj_name,
437 "iLBC codec opened, encoder mode=%d, decoder mode=%d",
438 attr->setting.enc_fmtp_mode, attr->setting.dec_fmtp_mode));
439
440 return PJ_SUCCESS;
441}
442
443
444/*
445 * Close codec.
446 */
447static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
448{
449 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
450
451 PJ_UNUSED_ARG(codec);
452
453 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
454
455 return PJ_SUCCESS;
456}
457
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000458/*
459 * Modify codec settings.
460 */
461static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
462 const pjmedia_codec_param *attr )
463{
464 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
465
466 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
467 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
468
469 return PJ_SUCCESS;
470}
Benny Prijonoc5859882006-07-31 15:25:14 +0000471
472/*
473 * Get frames in the packet.
474 */
475static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
476 void *pkt,
477 pj_size_t pkt_size,
478 const pj_timestamp *ts,
479 unsigned *frame_cnt,
480 pjmedia_frame frames[])
481{
482 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
483 unsigned count;
484
485 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
486
487 count = 0;
488 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
489 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
490 frames[count].buf = pkt;
491 frames[count].size = ilbc_codec->dec_frame_size;
492 frames[count].timestamp.u64 = ts->u64 + count *
493 ilbc_codec->dec_samples_per_frame;
494
495 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
496 pkt_size -= ilbc_codec->dec_frame_size;
497
498 ++count;
499 }
500
501 *frame_cnt = count;
502 return PJ_SUCCESS;
503}
504
505/*
506 * Encode frame.
507 */
508static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
509 const struct pjmedia_frame *input,
510 unsigned output_buf_len,
511 struct pjmedia_frame *output)
512{
513 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000514 pj_int16_t *pcm_in;
515 unsigned nsamples;
Benny Prijonoc5859882006-07-31 15:25:14 +0000516
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000517 pj_assert(ilbc_codec && input && output);
Benny Prijonoc5859882006-07-31 15:25:14 +0000518
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000519 pcm_in = (pj_int16_t*)input->buf;
520 nsamples = input->size >> 1;
Benny Prijonoc5859882006-07-31 15:25:14 +0000521
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000522 PJ_ASSERT_RETURN(nsamples % ilbc_codec->enc_samples_per_frame == 0,
523 PJMEDIA_CODEC_EPCMFRMINLEN);
524 PJ_ASSERT_RETURN(output_buf_len >= ilbc_codec->enc_frame_size * nsamples /
525 ilbc_codec->enc_samples_per_frame,
526 PJMEDIA_CODEC_EFRMTOOSHORT);
Benny Prijonoc5859882006-07-31 15:25:14 +0000527
528 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000529 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000530 pj_bool_t is_silence;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000531 pj_int32_t silence_period;
532
533 silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx,
534 &input->timestamp);
Benny Prijonoc5859882006-07-31 15:25:14 +0000535
536 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
Benny Prijonoa1e69682007-05-11 15:14:34 +0000537 (const pj_int16_t*)input->buf,
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000538 (input->size >> 1),
Benny Prijonoc5859882006-07-31 15:25:14 +0000539 NULL);
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000540 if (is_silence &&
541 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonodd3d0022008-06-14 16:52:04 +0000542 silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000543 {
Benny Prijonoc5859882006-07-31 15:25:14 +0000544 output->type = PJMEDIA_FRAME_TYPE_NONE;
545 output->buf = NULL;
546 output->size = 0;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000547 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000548 return PJ_SUCCESS;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000549 } else {
550 ilbc_codec->last_tx = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000551 }
552 }
553
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000554 /* Encode */
555 output->size = 0;
556 while (nsamples >= ilbc_codec->enc_samples_per_frame) {
557 unsigned i;
558
559 /* Convert to float */
560 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
561 ilbc_codec->enc_block[i] = (float) (*pcm_in++);
562 }
563
564 iLBC_encode((unsigned char *)output->buf + output->size,
565 ilbc_codec->enc_block,
566 &ilbc_codec->enc);
567
568 output->size += ilbc_codec->enc.no_of_bytes;
569 nsamples -= ilbc_codec->enc_samples_per_frame;
Benny Prijonoc5859882006-07-31 15:25:14 +0000570 }
571
Benny Prijonoc5859882006-07-31 15:25:14 +0000572 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000573 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000574
575 return PJ_SUCCESS;
576}
577
578/*
579 * Decode frame.
580 */
581static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
582 const struct pjmedia_frame *input,
583 unsigned output_buf_len,
584 struct pjmedia_frame *output)
585{
586 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
587 unsigned i;
588
589 pj_assert(ilbc_codec != NULL);
590 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
591
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000592 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000593 return PJMEDIA_CODEC_EPCMTOOSHORT;
594
595 if (input->size != ilbc_codec->dec_frame_size)
596 return PJMEDIA_CODEC_EFRMINLEN;
597
598 /* Decode to temporary buffer */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000599 iLBC_decode(ilbc_codec->dec_block, (unsigned char*) input->buf,
Benny Prijonoc5859882006-07-31 15:25:14 +0000600 &ilbc_codec->dec, 1);
601
602 /* Convert decodec samples from float to short */
603 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
604 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
605 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000606 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000607 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000608 output->timestamp = input->timestamp;
Benny Prijonoc5859882006-07-31 15:25:14 +0000609
610 return PJ_SUCCESS;
611}
612
613
614/*
615 * Recover lost frame.
616 */
617static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
618 unsigned output_buf_len,
619 struct pjmedia_frame *output)
620{
621 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
622 unsigned i;
623
624 pj_assert(ilbc_codec != NULL);
625 PJ_ASSERT_RETURN(output, PJ_EINVAL);
626
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000627 if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1))
Benny Prijonoc5859882006-07-31 15:25:14 +0000628 return PJMEDIA_CODEC_EPCMTOOSHORT;
629
630 /* Decode to temporary buffer */
631 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
632
633 /* Convert decodec samples from float to short */
634 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
635 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
636 }
Benny Prijonoc6c0ed02007-01-20 05:18:14 +0000637 output->size = (ilbc_codec->dec_samples_per_frame << 1);
Benny Prijonoc5859882006-07-31 15:25:14 +0000638 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
639
640 return PJ_SUCCESS;
641}
642
643
644#endif /* PJMEDIA_HAS_ILBC_CODEC */
645