blob: a21b6889eef40274719cb810dea942f0c91022bc [file] [log] [blame]
Benny Prijonoc5859882006-07-31 15:25:14 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
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>
32#include "ilbc/iLBC_encode.h"
33#include "ilbc/iLBC_decode.h"
34
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;
131
132 pj_bool_t enc_ready;
133 iLBC_Enc_Inst_t enc;
134 unsigned enc_frame_size;
135 unsigned enc_samples_per_frame;
136 float enc_block[BLOCKL_MAX];
137
138 pj_bool_t dec_ready;
139 iLBC_Dec_Inst_t dec;
140 unsigned dec_frame_size;
141 unsigned dec_samples_per_frame;
142 float dec_block[BLOCKL_MAX];
143};
144
145
146
147/*
148 * Initialize and register iLBC codec factory to pjmedia endpoint.
149 */
150PJ_DEF(pj_status_t) pjmedia_codec_ilbc_init( pjmedia_endpt *endpt,
151 int mode )
152{
153 pjmedia_codec_mgr *codec_mgr;
154 pj_status_t status;
155
156 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
157 PJ_ASSERT_RETURN(mode==0 || mode==20 || mode==30, PJ_EINVAL);
158
159 /* Create iLBC codec factory. */
160 ilbc_factory.base.op = &ilbc_factory_op;
161 ilbc_factory.base.factory_data = NULL;
162 ilbc_factory.endpt = endpt;
163
164 if (mode == 0)
165 mode = DEFAULT_MODE;
166
167 ilbc_factory.mode = mode;
168
169 if (mode == 20) {
170 ilbc_factory.bps = 15200;
171 } else {
172 ilbc_factory.bps = 13333;
173 }
174
175 /* Get the codec manager. */
176 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
177 if (!codec_mgr)
178 return PJ_EINVALIDOP;
179
180 /* Register codec factory to endpoint. */
181 status = pjmedia_codec_mgr_register_factory(codec_mgr,
182 &ilbc_factory.base);
183 if (status != PJ_SUCCESS)
184 return status;
185
186
187 /* Done. */
188 return PJ_SUCCESS;
189}
190
191
192
193/*
194 * Unregister iLBC codec factory from pjmedia endpoint and deinitialize
195 * the iLBC codec library.
196 */
197PJ_DEF(pj_status_t) pjmedia_codec_ilbc_deinit(void)
198{
199 pjmedia_codec_mgr *codec_mgr;
200 pj_status_t status;
201
202
203 /* Get the codec manager. */
204 codec_mgr = pjmedia_endpt_get_codec_mgr(ilbc_factory.endpt);
205 if (!codec_mgr)
206 return PJ_EINVALIDOP;
207
208 /* Unregister iLBC codec factory. */
209 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
210 &ilbc_factory.base);
211
212 return status;
213}
214
215/*
216 * Check if factory can allocate the specified codec.
217 */
218static pj_status_t ilbc_test_alloc( pjmedia_codec_factory *factory,
219 const pjmedia_codec_info *info )
220{
221 const pj_str_t ilbc_tag = { "iLBC", 4};
222
223 PJ_UNUSED_ARG(factory);
224 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
225
226
227 /* Type MUST be audio. */
228 if (info->type != PJMEDIA_TYPE_AUDIO)
229 return PJMEDIA_CODEC_EUNSUP;
230
231 /* Check encoding name. */
232 if (pj_stricmp(&info->encoding_name, &ilbc_tag) != 0)
233 return PJMEDIA_CODEC_EUNSUP;
234
235 /* Check clock-rate */
236 if (info->clock_rate != CLOCK_RATE)
237 return PJMEDIA_CODEC_EUNSUP;
238
239 /* Channel count must be one */
240 if (info->channel_cnt != 1)
241 return PJMEDIA_CODEC_EUNSUP;
242
243 /* Yes, this should be iLBC! */
244 return PJ_SUCCESS;
245}
246
247
248/*
249 * Generate default attribute.
250 */
251static pj_status_t ilbc_default_attr (pjmedia_codec_factory *factory,
252 const pjmedia_codec_info *id,
253 pjmedia_codec_param *attr )
254{
255 PJ_UNUSED_ARG(factory);
256 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
257
258 PJ_UNUSED_ARG(id);
259 PJ_ASSERT_RETURN(pj_stricmp2(&id->encoding_name, "iLBC")==0, PJ_EINVAL);
260
261 pj_bzero(attr, sizeof(pjmedia_codec_param));
262
263 attr->info.clock_rate = CLOCK_RATE;
264 attr->info.channel_cnt = 1;
265 attr->info.avg_bps = ilbc_factory.bps;
266 attr->info.pcm_bits_per_sample = 16;
267 attr->info.frm_ptime = (short)ilbc_factory.mode;
268 attr->info.pt = PJMEDIA_RTP_PT_ILBC;
269
270 attr->setting.frm_per_pkt = 1;
271 attr->setting.vad = 1;
272 attr->setting.plc = 1;
273 attr->setting.penh = 1;
274 attr->setting.dec_fmtp_mode = (pj_uint8_t)ilbc_factory.mode;
275
276 return PJ_SUCCESS;
277}
278
279/*
280 * Enum codecs supported by this factory (i.e. only iLBC!).
281 */
282static pj_status_t ilbc_enum_codecs(pjmedia_codec_factory *factory,
283 unsigned *count,
284 pjmedia_codec_info codecs[])
285{
286 PJ_UNUSED_ARG(factory);
287 PJ_ASSERT_RETURN(factory==&ilbc_factory.base, PJ_EINVAL);
288
289 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
290
291 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
292
293 codecs[0].encoding_name = pj_str("iLBC");
294 codecs[0].pt = PJMEDIA_RTP_PT_ILBC;
295 codecs[0].type = PJMEDIA_TYPE_AUDIO;
296 codecs[0].clock_rate = 8000;
297 codecs[0].channel_cnt = 1;
298
299 *count = 1;
300
301 return PJ_SUCCESS;
302}
303
304/*
305 * Allocate a new iLBC codec instance.
306 */
307static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory,
308 const pjmedia_codec_info *id,
309 pjmedia_codec **p_codec)
310{
311 pj_pool_t *pool;
312 struct ilbc_codec *codec;
313
314 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
315 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
316
317 pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
318 2000, 2000);
319 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
320
321 codec = pj_pool_zalloc(pool, sizeof(struct ilbc_codec));
322 codec->base.op = &ilbc_op;
323 codec->base.factory = factory;
324 codec->pool = pool;
325
326 pj_ansi_snprintf(codec->obj_name, sizeof(codec->obj_name),
327 "ilbc%p", codec);
328
329 *p_codec = &codec->base;
330 return PJ_SUCCESS;
331}
332
333
334/*
335 * Free codec.
336 */
337static pj_status_t ilbc_dealloc_codec( pjmedia_codec_factory *factory,
338 pjmedia_codec *codec )
339{
340 struct ilbc_codec *ilbc_codec;
341
342 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
343 PJ_UNUSED_ARG(factory);
344 PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);
345
346 ilbc_codec = (struct ilbc_codec*) codec;
347 pj_pool_release(ilbc_codec->pool);
348
349 return PJ_SUCCESS;
350}
351
352/*
353 * Init codec.
354 */
355static pj_status_t ilbc_codec_init(pjmedia_codec *codec,
356 pj_pool_t *pool )
357{
358 PJ_UNUSED_ARG(codec);
359 PJ_UNUSED_ARG(pool);
360 return PJ_SUCCESS;
361}
362
363/*
364 * Open codec.
365 */
366static pj_status_t ilbc_codec_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000367 pjmedia_codec_param *attr )
Benny Prijonoc5859882006-07-31 15:25:14 +0000368{
369 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000370 pj_status_t status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000371
372 pj_assert(ilbc_codec != NULL);
373 pj_assert(ilbc_codec->enc_ready == PJ_FALSE &&
374 ilbc_codec->dec_ready == PJ_FALSE);
375
376 /* Decoder mode must be set */
377 PJ_ASSERT_RETURN(attr->setting.dec_fmtp_mode==20 ||
378 attr->setting.dec_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
379
380 /* The enc mode must be set in the attribute
381 * (from the mode parameter in fmtp attribute in the SDP
382 * received from remote)
383 */
384 if (attr->setting.enc_fmtp_mode == 0)
385 attr->setting.enc_fmtp_mode = attr->setting.dec_fmtp_mode;
386
387 PJ_ASSERT_RETURN(attr->setting.enc_fmtp_mode==20 ||
388 attr->setting.enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
389
Benny Prijono6865a3f2006-12-30 02:46:57 +0000390 /* Update enc_ptime in the param */
391 if (attr->setting.enc_fmtp_mode != attr->setting.dec_fmtp_mode) {
392 attr->info.enc_ptime = attr->setting.enc_fmtp_mode;
393 } else {
394 attr->info.enc_ptime = 0;
395 }
396
Benny Prijonoc5859882006-07-31 15:25:14 +0000397 /* Create enc */
398 ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc,
399 attr->setting.enc_fmtp_mode);
400 ilbc_codec->enc_samples_per_frame = CLOCK_RATE*attr->setting.enc_fmtp_mode/
401 1000;
402 ilbc_codec->enc_ready = PJ_TRUE;
403
404 /* Create decoder */
405 ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec,
406 attr->setting.dec_fmtp_mode,
407 attr->setting.penh);
408 if (attr->setting.dec_fmtp_mode == 20)
409 ilbc_codec->dec_frame_size = 38;
Benny Prijono1d9b9a42006-09-25 13:40:12 +0000410 else if (attr->setting.dec_fmtp_mode == 30)
Benny Prijonoc5859882006-07-31 15:25:14 +0000411 ilbc_codec->dec_frame_size = 50;
412 else {
413 pj_assert(!"Invalid iLBC mode");
414 ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
415 }
416 ilbc_codec->dec_ready = PJ_TRUE;
417
418 /* Save plc flags */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000419 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
Benny Prijonoc5859882006-07-31 15:25:14 +0000420
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000421 /* Create silence detector. */
422 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
423 status = pjmedia_silence_det_create(ilbc_codec->pool, CLOCK_RATE,
424 ilbc_codec->enc_samples_per_frame,
425 &ilbc_codec->vad);
426 if (status != PJ_SUCCESS)
427 return status;
Benny Prijonoc5859882006-07-31 15:25:14 +0000428
429 PJ_LOG(5,(ilbc_codec->obj_name,
430 "iLBC codec opened, encoder mode=%d, decoder mode=%d",
431 attr->setting.enc_fmtp_mode, attr->setting.dec_fmtp_mode));
432
433 return PJ_SUCCESS;
434}
435
436
437/*
438 * Close codec.
439 */
440static pj_status_t ilbc_codec_close( pjmedia_codec *codec )
441{
442 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
443
444 PJ_UNUSED_ARG(codec);
445
446 PJ_LOG(5,(ilbc_codec->obj_name, "iLBC codec closed"));
447
448 return PJ_SUCCESS;
449}
450
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000451/*
452 * Modify codec settings.
453 */
454static pj_status_t ilbc_codec_modify(pjmedia_codec *codec,
455 const pjmedia_codec_param *attr )
456{
457 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
458
459 ilbc_codec->plc_enabled = (attr->setting.plc != 0);
460 ilbc_codec->vad_enabled = (attr->setting.vad != 0);
461
462 return PJ_SUCCESS;
463}
Benny Prijonoc5859882006-07-31 15:25:14 +0000464
465/*
466 * Get frames in the packet.
467 */
468static pj_status_t ilbc_codec_parse( pjmedia_codec *codec,
469 void *pkt,
470 pj_size_t pkt_size,
471 const pj_timestamp *ts,
472 unsigned *frame_cnt,
473 pjmedia_frame frames[])
474{
475 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
476 unsigned count;
477
478 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
479
480 count = 0;
481 while (pkt_size >= ilbc_codec->dec_frame_size && count < *frame_cnt) {
482 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
483 frames[count].buf = pkt;
484 frames[count].size = ilbc_codec->dec_frame_size;
485 frames[count].timestamp.u64 = ts->u64 + count *
486 ilbc_codec->dec_samples_per_frame;
487
488 pkt = ((char*)pkt) + ilbc_codec->dec_frame_size;
489 pkt_size -= ilbc_codec->dec_frame_size;
490
491 ++count;
492 }
493
494 *frame_cnt = count;
495 return PJ_SUCCESS;
496}
497
498/*
499 * Encode frame.
500 */
501static pj_status_t ilbc_codec_encode(pjmedia_codec *codec,
502 const struct pjmedia_frame *input,
503 unsigned output_buf_len,
504 struct pjmedia_frame *output)
505{
506 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
507 unsigned i;
508
509 pj_assert(ilbc_codec != NULL);
510 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
511
512 if (output_buf_len < ilbc_codec->enc_frame_size)
513 return PJMEDIA_CODEC_EFRMTOOSHORT;
514
515 if (input->size != ilbc_codec->enc_samples_per_frame * 2)
516 return PJMEDIA_CODEC_EPCMFRMINLEN;
517
518 /* Detect silence */
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000519 if (ilbc_codec->vad_enabled) {
Benny Prijonoc5859882006-07-31 15:25:14 +0000520 pj_bool_t is_silence;
521
522 is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,
523 input->buf,
524 input->size / 2,
525 NULL);
526 if (is_silence) {
527 output->type = PJMEDIA_FRAME_TYPE_NONE;
528 output->buf = NULL;
529 output->size = 0;
530 output->timestamp.u64 = input->timestamp.u64;
531 return PJ_SUCCESS;
532 }
533 }
534
535 /* Convert to float */
536 for (i=0; i<ilbc_codec->enc_samples_per_frame; ++i) {
537 ilbc_codec->enc_block[i] = (float) (((pj_int16_t*)input->buf)[i]);
538 }
539
540 /* Encode */
541 iLBC_encode((unsigned char *)output->buf,
542 ilbc_codec->enc_block,
543 &ilbc_codec->enc);
544
545 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
546 output->size = ilbc_codec->enc.no_of_bytes;
547 output->timestamp.u64 = input->timestamp.u64;
548
549 return PJ_SUCCESS;
550}
551
552/*
553 * Decode frame.
554 */
555static pj_status_t ilbc_codec_decode(pjmedia_codec *codec,
556 const struct pjmedia_frame *input,
557 unsigned output_buf_len,
558 struct pjmedia_frame *output)
559{
560 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
561 unsigned i;
562
563 pj_assert(ilbc_codec != NULL);
564 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
565
566 if (output_buf_len < ilbc_codec->dec_samples_per_frame*2)
567 return PJMEDIA_CODEC_EPCMTOOSHORT;
568
569 if (input->size != ilbc_codec->dec_frame_size)
570 return PJMEDIA_CODEC_EFRMINLEN;
571
572 /* Decode to temporary buffer */
573 iLBC_decode(ilbc_codec->dec_block, input->buf,
574 &ilbc_codec->dec, 1);
575
576 /* Convert decodec samples from float to short */
577 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
578 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
579 }
580 output->size = ilbc_codec->dec_samples_per_frame * 2;
581 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
582 output->timestamp.u64 = input->timestamp.u64;
583
584 return PJ_SUCCESS;
585}
586
587
588/*
589 * Recover lost frame.
590 */
591static pj_status_t ilbc_codec_recover(pjmedia_codec *codec,
592 unsigned output_buf_len,
593 struct pjmedia_frame *output)
594{
595 struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
596 unsigned i;
597
598 pj_assert(ilbc_codec != NULL);
599 PJ_ASSERT_RETURN(output, PJ_EINVAL);
600
601 if (output_buf_len < ilbc_codec->dec_samples_per_frame*2)
602 return PJMEDIA_CODEC_EPCMTOOSHORT;
603
604 /* Decode to temporary buffer */
605 iLBC_decode(ilbc_codec->dec_block, NULL, &ilbc_codec->dec, 0);
606
607 /* Convert decodec samples from float to short */
608 for (i=0; i<ilbc_codec->dec_samples_per_frame; ++i) {
609 ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i];
610 }
611 output->size = ilbc_codec->dec_samples_per_frame * 2;
612 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
613
614 return PJ_SUCCESS;
615}
616
617
618#endif /* PJMEDIA_HAS_ILBC_CODEC */
619