blob: 1704d2c9951e7be1ce56e238fd8ae314156706b9 [file] [log] [blame]
Benny Prijonoa837c302006-04-27 22:36:40 +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 Prijonoa837c302006-04-27 22:36:40 +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/l16.h>
21#include <pjmedia/codec.h>
22#include <pjmedia/errno.h>
23#include <pjmedia/endpoint.h>
Nanang Izzuddin16b504c2008-08-26 20:09:03 +000024#include <pjmedia/plc.h>
25#include <pjmedia/silencedet.h>
Benny Prijonoa837c302006-04-27 22:36:40 +000026#include <pj/assert.h>
27#include <pj/pool.h>
28#include <pj/sock.h>
29#include <pj/string.h>
30
31
32/*
33 * Only build this file if PJMEDIA_HAS_L16_CODEC != 0
34 */
35#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
36
Nanang Izzuddin16b504c2008-08-26 20:09:03 +000037#define PLC_DISABLED 0
38
Benny Prijonoa837c302006-04-27 22:36:40 +000039
40static const pj_str_t STR_L16 = { "L16", 3 };
41
42/* To keep frame size below 1400 MTU, set ptime to 10ms for
43 * sampling rate > 35 KHz
44 */
45#define GET_PTIME(clock_rate) ((pj_uint16_t)(clock_rate > 35000 ? 10 : 20))
46
47
48/* Prototypes for L16 factory */
49static pj_status_t l16_test_alloc( pjmedia_codec_factory *factory,
50 const pjmedia_codec_info *id );
51static pj_status_t l16_default_attr( pjmedia_codec_factory *factory,
52 const pjmedia_codec_info *id,
53 pjmedia_codec_param *attr );
54static pj_status_t l16_enum_codecs (pjmedia_codec_factory *factory,
55 unsigned *count,
56 pjmedia_codec_info codecs[]);
57static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory,
58 const pjmedia_codec_info *id,
59 pjmedia_codec **p_codec);
60static pj_status_t l16_dealloc_codec( pjmedia_codec_factory *factory,
61 pjmedia_codec *codec );
62
63/* Prototypes for L16 implementation. */
64static pj_status_t l16_init( pjmedia_codec *codec,
65 pj_pool_t *pool );
66static pj_status_t l16_open( pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000067 pjmedia_codec_param *attr );
Benny Prijonoa837c302006-04-27 22:36:40 +000068static pj_status_t l16_close( pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000069static pj_status_t l16_modify(pjmedia_codec *codec,
70 const pjmedia_codec_param *attr );
Benny Prijono8befd9f2006-05-13 22:46:23 +000071static pj_status_t l16_parse(pjmedia_codec *codec,
72 void *pkt,
73 pj_size_t pkt_size,
74 const pj_timestamp *ts,
75 unsigned *frame_cnt,
76 pjmedia_frame frames[]);
Benny Prijonoa837c302006-04-27 22:36:40 +000077static pj_status_t l16_encode( pjmedia_codec *codec,
78 const struct pjmedia_frame *input,
79 unsigned output_buf_len,
80 struct pjmedia_frame *output);
81static pj_status_t l16_decode( pjmedia_codec *codec,
82 const struct pjmedia_frame *input,
83 unsigned output_buf_len,
84 struct pjmedia_frame *output);
Nanang Izzuddin16b504c2008-08-26 20:09:03 +000085#if !PLC_DISABLED
86static pj_status_t l16_recover(pjmedia_codec *codec,
87 unsigned output_buf_len,
88 struct pjmedia_frame *output);
89#endif
Benny Prijonoa837c302006-04-27 22:36:40 +000090
91/* Definition for L16 codec operations. */
92static pjmedia_codec_op l16_op =
93{
94 &l16_init,
95 &l16_open,
96 &l16_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +000097 &l16_modify,
Benny Prijono8befd9f2006-05-13 22:46:23 +000098 &l16_parse,
Benny Prijonoa837c302006-04-27 22:36:40 +000099 &l16_encode,
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000100 &l16_decode,
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000101#if !PLC_DISABLED
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000102 &l16_recover
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000103#else
104 NULL
105#endif
Benny Prijonoa837c302006-04-27 22:36:40 +0000106};
107
108/* Definition for L16 codec factory operations. */
109static pjmedia_codec_factory_op l16_factory_op =
110{
111 &l16_test_alloc,
112 &l16_default_attr,
113 &l16_enum_codecs,
114 &l16_alloc_codec,
115 &l16_dealloc_codec
116};
117
118/* L16 factory private data */
119static struct l16_factory
120{
121 pjmedia_codec_factory base;
122 pjmedia_endpt *endpt;
123 pj_pool_t *pool;
124 pj_mutex_t *mutex;
Benny Prijonoa837c302006-04-27 22:36:40 +0000125} l16_factory;
126
127
128/* L16 codec private data. */
129struct l16_data
130{
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000131 pj_pool_t *pool;
132 unsigned frame_size; /* Frame size, in bytes */
133 unsigned clock_rate; /* Clock rate */
134
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000135#if !PLC_DISABLED
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000136 pj_bool_t plc_enabled;
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000137 pjmedia_plc *plc;
138#endif
139 pj_bool_t vad_enabled;
140 pjmedia_silence_det *vad;
141 pj_timestamp last_tx;
Benny Prijonoa837c302006-04-27 22:36:40 +0000142};
143
144
145
146PJ_DEF(pj_status_t) pjmedia_codec_l16_init(pjmedia_endpt *endpt,
147 unsigned options)
148{
149 pjmedia_codec_mgr *codec_mgr;
150 pj_status_t status;
151
152
153 PJ_UNUSED_ARG(options);
154
155
156 if (l16_factory.endpt != NULL) {
157 /* Already initialized. */
158 return PJ_SUCCESS;
159 }
160
161 /* Init factory */
162 l16_factory.base.op = &l16_factory_op;
163 l16_factory.base.factory_data = NULL;
164 l16_factory.endpt = endpt;
165
Benny Prijonoa837c302006-04-27 22:36:40 +0000166 /* Create pool */
167 l16_factory.pool = pjmedia_endpt_create_pool(endpt, "l16", 4000, 4000);
168 if (!l16_factory.pool)
169 return PJ_ENOMEM;
170
171 /* Create mutex. */
172 status = pj_mutex_create_simple(l16_factory.pool, "l16",
173 &l16_factory.mutex);
174 if (status != PJ_SUCCESS)
175 goto on_error;
176
177 /* Get the codec manager. */
178 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
179 if (!codec_mgr) {
180 return PJ_EINVALIDOP;
181 }
182
183 /* Register codec factory to endpoint. */
184 status = pjmedia_codec_mgr_register_factory(codec_mgr,
185 &l16_factory.base);
186 if (status != PJ_SUCCESS)
187 return status;
188
189
190 return PJ_SUCCESS;
191
192on_error:
193 if (l16_factory.mutex) {
194 pj_mutex_destroy(l16_factory.mutex);
195 l16_factory.mutex = NULL;
196 }
197 if (l16_factory.pool) {
198 pj_pool_release(l16_factory.pool);
199 l16_factory.pool = NULL;
200 }
201 return status;
202}
203
204PJ_DEF(pj_status_t) pjmedia_codec_l16_deinit(void)
205{
206 pjmedia_codec_mgr *codec_mgr;
207 pj_status_t status;
208
209 if (l16_factory.endpt == NULL) {
210 /* Not registered. */
211 return PJ_SUCCESS;
212 }
213
214 /* Lock mutex. */
215 pj_mutex_lock(l16_factory.mutex);
216
217 /* Get the codec manager. */
218 codec_mgr = pjmedia_endpt_get_codec_mgr(l16_factory.endpt);
219 if (!codec_mgr) {
220 l16_factory.endpt = NULL;
221 pj_mutex_unlock(l16_factory.mutex);
222 return PJ_EINVALIDOP;
223 }
224
225 /* Unregister L16 codec factory. */
226 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
227 &l16_factory.base);
228 l16_factory.endpt = NULL;
229
230 /* Destroy mutex. */
231 pj_mutex_destroy(l16_factory.mutex);
232 l16_factory.mutex = NULL;
233
234
235 /* Release pool. */
236 pj_pool_release(l16_factory.pool);
237 l16_factory.pool = NULL;
238
239
240 return status;
241}
242
243static pj_status_t l16_test_alloc(pjmedia_codec_factory *factory,
244 const pjmedia_codec_info *id )
245{
246 PJ_UNUSED_ARG(factory);
247
248 if (pj_stricmp(&id->encoding_name, &STR_L16)==0) {
249 /* Match! */
250 return PJ_SUCCESS;
251 }
252
253 return -1;
254}
255
256static pj_status_t l16_default_attr( pjmedia_codec_factory *factory,
257 const pjmedia_codec_info *id,
258 pjmedia_codec_param *attr )
259{
260 PJ_UNUSED_ARG(factory);
261
Benny Prijonoac623b32006-07-03 15:19:31 +0000262 pj_bzero(attr, sizeof(pjmedia_codec_param));
Benny Prijono8befd9f2006-05-13 22:46:23 +0000263 attr->info.pt = (pj_uint8_t)id->pt;
264 attr->info.clock_rate = id->clock_rate;
265 attr->info.channel_cnt = id->channel_cnt;
266 attr->info.avg_bps = id->clock_rate * id->channel_cnt * 16;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000267 attr->info.max_bps = attr->info.avg_bps;
Benny Prijono8befd9f2006-05-13 22:46:23 +0000268 attr->info.pcm_bits_per_sample = 16;
Benny Prijonoa837c302006-04-27 22:36:40 +0000269
270 /* To keep frame size below 1400 MTU, set ptime to 10ms for
271 * sampling rate > 35 KHz
272 */
Benny Prijono8befd9f2006-05-13 22:46:23 +0000273 attr->info.frm_ptime = GET_PTIME(id->clock_rate);
274
275 attr->setting.frm_per_pkt = 1;
Benny Prijonoa837c302006-04-27 22:36:40 +0000276
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000277 attr->setting.vad = 1;
278#if !PLC_DISABLED
279 attr->setting.plc = 1;
280#endif
Benny Prijonoa837c302006-04-27 22:36:40 +0000281
282 return PJ_SUCCESS;
283}
284
285static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
286 unsigned *max_count,
287 pjmedia_codec_info codecs[])
288{
289 unsigned count = 0;
290
291 PJ_UNUSED_ARG(factory);
292
293 if (count < *max_count) {
294 /* Register 44100Hz 1 channel L16 codec */
295 codecs[count].type = PJMEDIA_TYPE_AUDIO;
296 codecs[count].pt = PJMEDIA_RTP_PT_L16_1;
297 codecs[count].encoding_name = STR_L16;
298 codecs[count].clock_rate = 44100;
299 codecs[count].channel_cnt = 1;
300 ++count;
301 }
302
303 if (count < *max_count) {
304 /* Register 44100Hz 2 channels L16 codec */
305 codecs[count].type = PJMEDIA_TYPE_AUDIO;
306 codecs[count].pt = PJMEDIA_RTP_PT_L16_2;
307 codecs[count].encoding_name = STR_L16;
308 codecs[count].clock_rate = 44100;
309 codecs[count].channel_cnt = 2;
310 ++count;
311 }
312
313 if (count < *max_count) {
314 /* 8KHz mono */
315 codecs[count].type = PJMEDIA_TYPE_AUDIO;
316 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_MONO;
317 codecs[count].encoding_name = STR_L16;
318 codecs[count].clock_rate = 8000;
319 codecs[count].channel_cnt = 1;
320 ++count;
321 }
322
323 if (count < *max_count) {
324 /* 8KHz stereo */
325 codecs[count].type = PJMEDIA_TYPE_AUDIO;
326 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_STEREO;
327 codecs[count].encoding_name = STR_L16;
328 codecs[count].clock_rate = 8000;
329 codecs[count].channel_cnt = 2;
330 ++count;
331 }
332
Nanang Izzuddin57b88572009-04-01 12:05:34 +0000333// disable some L16 modes
334#if 0
Benny Prijonoa837c302006-04-27 22:36:40 +0000335 if (count < *max_count) {
336 /* 11025 Hz mono */
337 codecs[count].type = PJMEDIA_TYPE_AUDIO;
338 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_MONO;
339 codecs[count].encoding_name = STR_L16;
340 codecs[count].clock_rate = 11025;
341 codecs[count].channel_cnt = 1;
342 ++count;
343 }
344
345 if (count < *max_count) {
346 /* 11025 Hz stereo */
347 codecs[count].type = PJMEDIA_TYPE_AUDIO;
348 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_STEREO;
349 codecs[count].encoding_name = STR_L16;
350 codecs[count].clock_rate = 11025;
351 codecs[count].channel_cnt = 2;
352 ++count;
353 }
Nanang Izzuddin57b88572009-04-01 12:05:34 +0000354#endif
Benny Prijonoa837c302006-04-27 22:36:40 +0000355
356 if (count < *max_count) {
357 /* 16000 Hz mono */
358 codecs[count].type = PJMEDIA_TYPE_AUDIO;
359 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_MONO;
360 codecs[count].encoding_name = STR_L16;
361 codecs[count].clock_rate = 16000;
362 codecs[count].channel_cnt = 1;
363 ++count;
364 }
365
366
367 if (count < *max_count) {
368 /* 16000 Hz stereo */
369 codecs[count].type = PJMEDIA_TYPE_AUDIO;
370 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_STEREO;
371 codecs[count].encoding_name = STR_L16;
372 codecs[count].clock_rate = 16000;
373 codecs[count].channel_cnt = 2;
374 ++count;
375 }
376
Nanang Izzuddin57b88572009-04-01 12:05:34 +0000377// disable some L16 modes
378#if 0
Benny Prijonoa837c302006-04-27 22:36:40 +0000379 if (count < *max_count) {
380 /* 22050 Hz mono */
381 codecs[count].type = PJMEDIA_TYPE_AUDIO;
382 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_MONO;
383 codecs[count].encoding_name = STR_L16;
384 codecs[count].clock_rate = 22050;
385 codecs[count].channel_cnt = 1;
386 ++count;
387 }
388
389
390 if (count < *max_count) {
391 /* 22050 Hz stereo */
392 codecs[count].type = PJMEDIA_TYPE_AUDIO;
393 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_STEREO;
394 codecs[count].encoding_name = STR_L16;
395 codecs[count].clock_rate = 22050;
396 codecs[count].channel_cnt = 2;
397 ++count;
398 }
399
400 if (count < *max_count) {
401 /* 32000 Hz mono */
402 codecs[count].type = PJMEDIA_TYPE_AUDIO;
403 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_MONO;
404 codecs[count].encoding_name = STR_L16;
405 codecs[count].clock_rate = 32000;
406 codecs[count].channel_cnt = 1;
407 ++count;
408 }
409
410 if (count < *max_count) {
411 /* 32000 Hz stereo */
412 codecs[count].type = PJMEDIA_TYPE_AUDIO;
413 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_STEREO;
414 codecs[count].encoding_name = STR_L16;
415 codecs[count].clock_rate = 32000;
416 codecs[count].channel_cnt = 2;
417 ++count;
418 }
419
420 if (count < *max_count) {
421 /* 48KHz mono */
422 codecs[count].type = PJMEDIA_TYPE_AUDIO;
423 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
424 codecs[count].encoding_name = STR_L16;
425 codecs[count].clock_rate = 48000;
426 codecs[count].channel_cnt = 1;
427 ++count;
428 }
429
430 if (count < *max_count) {
431 /* 48KHz stereo */
432 codecs[count].type = PJMEDIA_TYPE_AUDIO;
Benny Prijono275539b2009-03-13 09:33:02 +0000433 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_STEREO;
Benny Prijonoa837c302006-04-27 22:36:40 +0000434 codecs[count].encoding_name = STR_L16;
435 codecs[count].clock_rate = 48000;
436 codecs[count].channel_cnt = 2;
437 ++count;
438 }
Nanang Izzuddin1c701732010-04-26 13:57:28 +0000439#endif
Benny Prijonoa837c302006-04-27 22:36:40 +0000440
441
442 *max_count = count;
443
444 return PJ_SUCCESS;
445}
446
447static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory,
448 const pjmedia_codec_info *id,
449 pjmedia_codec **p_codec)
450{
451 pjmedia_codec *codec = NULL;
452 struct l16_data *data;
453 unsigned ptime;
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000454 pj_pool_t *pool;
455
456 pj_status_t status;
Benny Prijonoa837c302006-04-27 22:36:40 +0000457
458 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
459
460 /* Lock mutex. */
461 pj_mutex_lock(l16_factory.mutex);
462
Benny Prijonoa837c302006-04-27 22:36:40 +0000463
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000464 pool = pjmedia_endpt_create_pool(l16_factory.endpt, "l16", 4000, 4000);
465 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
466 codec->codec_data = pj_pool_alloc(pool, sizeof(struct l16_data));
467 codec->factory = factory;
468 codec->op = &l16_op;
Benny Prijonoa837c302006-04-27 22:36:40 +0000469
470 /* Init private data */
471 ptime = GET_PTIME(id->clock_rate);
Benny Prijonoa1e69682007-05-11 15:14:34 +0000472 data = (struct l16_data*) codec->codec_data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000473 data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000474 data->clock_rate = id->clock_rate;
475 data->pool = pool;
Benny Prijonoa837c302006-04-27 22:36:40 +0000476
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000477#if !PLC_DISABLED
478 /* Create PLC */
479 status = pjmedia_plc_create(pool, id->clock_rate,
480 data->frame_size >> 1, 0,
481 &data->plc);
482 if (status != PJ_SUCCESS) {
483 pj_mutex_unlock(l16_factory.mutex);
484 return status;
485 }
486#endif
487
488 /* Create silence detector */
489 status = pjmedia_silence_det_create(pool, id->clock_rate,
490 data->frame_size >> 1,
491 &data->vad);
492 if (status != PJ_SUCCESS) {
493 pj_mutex_unlock(l16_factory.mutex);
494 return status;
495 }
Benny Prijonoa837c302006-04-27 22:36:40 +0000496
497 *p_codec = codec;
498
499 /* Unlock mutex. */
500 pj_mutex_unlock(l16_factory.mutex);
501
502 return PJ_SUCCESS;
503}
504
505static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory,
506 pjmedia_codec *codec )
507{
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000508 struct l16_data *data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000509
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000510 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
511 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
Benny Prijonoa837c302006-04-27 22:36:40 +0000512
513 /* Lock mutex. */
514 pj_mutex_lock(l16_factory.mutex);
515
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000516 /* Just release codec data pool */
517 data = (struct l16_data*) codec->codec_data;
518 pj_assert(data);
519 pj_pool_release(data->pool);
Benny Prijonoa837c302006-04-27 22:36:40 +0000520
521 /* Unlock mutex. */
522 pj_mutex_unlock(l16_factory.mutex);
523
524 return PJ_SUCCESS;
525}
526
527static pj_status_t l16_init( pjmedia_codec *codec, pj_pool_t *pool )
528{
529 /* There's nothing to do here really */
530 PJ_UNUSED_ARG(codec);
531 PJ_UNUSED_ARG(pool);
532
533 return PJ_SUCCESS;
534}
535
536static pj_status_t l16_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000537 pjmedia_codec_param *attr )
Benny Prijonoa837c302006-04-27 22:36:40 +0000538{
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000539 struct l16_data *data = NULL;
540
541 PJ_ASSERT_RETURN(codec && codec->codec_data && attr, PJ_EINVAL);
542
543 data = (struct l16_data*) codec->codec_data;
544
545 data->vad_enabled = (attr->setting.vad != 0);
546#if !PLC_DISABLED
547 data->plc_enabled = (attr->setting.plc != 0);
548#endif
549
Benny Prijonoa837c302006-04-27 22:36:40 +0000550 return PJ_SUCCESS;
551}
552
553static pj_status_t l16_close( pjmedia_codec *codec )
554{
555 PJ_UNUSED_ARG(codec);
556 /* Nothing to do */
557 return PJ_SUCCESS;
558}
559
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000560static pj_status_t l16_modify(pjmedia_codec *codec,
561 const pjmedia_codec_param *attr )
562{
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000563 struct l16_data *data = (struct l16_data*) codec->codec_data;
564
565 pj_assert(data != NULL);
566
567 data->vad_enabled = (attr->setting.vad != 0);
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000568#if !PLC_DISABLED
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000569 data->plc_enabled = (attr->setting.plc != 0);
Nanang Izzuddin3405e2a2009-02-13 15:33:03 +0000570#endif
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000571
572 return PJ_SUCCESS;
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000573}
574
Benny Prijono8befd9f2006-05-13 22:46:23 +0000575static pj_status_t l16_parse( pjmedia_codec *codec,
576 void *pkt,
577 pj_size_t pkt_size,
578 const pj_timestamp *ts,
579 unsigned *frame_cnt,
580 pjmedia_frame frames[])
Benny Prijonoa837c302006-04-27 22:36:40 +0000581{
582 unsigned count = 0;
583 struct l16_data *data = (struct l16_data*) codec->codec_data;
584
585 PJ_UNUSED_ARG(codec);
586 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
587
588 while (pkt_size >= data->frame_size && count < *frame_cnt) {
Benny Prijono8befd9f2006-05-13 22:46:23 +0000589 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
590 frames[count].buf = pkt;
591 frames[count].size = data->frame_size;
592 frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size);
Benny Prijonoa837c302006-04-27 22:36:40 +0000593
594 pkt = ((char*)pkt) + data->frame_size;
595 pkt_size -= data->frame_size;
596
597 ++count;
598 }
599
600 *frame_cnt = count;
601 return PJ_SUCCESS;
602}
603
604static pj_status_t l16_encode(pjmedia_codec *codec,
605 const struct pjmedia_frame *input,
606 unsigned output_buf_len,
607 struct pjmedia_frame *output)
608{
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000609 struct l16_data *data = (struct l16_data*) codec->codec_data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000610 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
611 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
612 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
613
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000614 pj_assert(data && input && output);
Benny Prijonoa837c302006-04-27 22:36:40 +0000615
616 /* Check output buffer length */
617 if (output_buf_len < input->size)
618 return PJMEDIA_CODEC_EFRMTOOSHORT;
619
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000620 /* Detect silence */
621 if (data->vad_enabled) {
622 pj_bool_t is_silence;
623 pj_int32_t silence_duration;
624
625 silence_duration = pj_timestamp_diff32(&data->last_tx,
626 &input->timestamp);
627
628 is_silence = pjmedia_silence_det_detect(data->vad,
629 (const pj_int16_t*) input->buf,
630 (input->size >> 1),
631 NULL);
632 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +0000633 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
634 silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*
635 (int)data->clock_rate/1000))
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000636 {
637 output->type = PJMEDIA_FRAME_TYPE_NONE;
638 output->buf = NULL;
639 output->size = 0;
640 output->timestamp = input->timestamp;
641 return PJ_SUCCESS;
642 } else {
643 data->last_tx = input->timestamp;
644 }
645 }
Benny Prijonoa837c302006-04-27 22:36:40 +0000646
647 /* Encode */
648#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
649 while (samp!=samp_end)
650 *samp_out++ = pj_htons(*samp++);
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000651#else
652 pjmedia_copy_samples(samp_out, samp, input->size >> 1);
Benny Prijonoa837c302006-04-27 22:36:40 +0000653#endif
654
655
656 /* Done */
657 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
658 output->size = input->size;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000659 output->timestamp = input->timestamp;
Benny Prijonoa837c302006-04-27 22:36:40 +0000660
661 return PJ_SUCCESS;
662}
663
664static pj_status_t l16_decode(pjmedia_codec *codec,
665 const struct pjmedia_frame *input,
666 unsigned output_buf_len,
667 struct pjmedia_frame *output)
668{
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000669 struct l16_data *l16_data = (struct l16_data*) codec->codec_data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000670 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
671 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
672 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
673
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000674 pj_assert(l16_data != NULL);
675 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
Benny Prijonoa837c302006-04-27 22:36:40 +0000676
677
678 /* Check output buffer length */
679 if (output_buf_len < input->size)
680 return PJMEDIA_CODEC_EPCMTOOSHORT;
681
682
683 /* Decode */
684#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
685 while (samp!=samp_end)
686 *samp_out++ = pj_htons(*samp++);
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000687#else
688 pjmedia_copy_samples(samp_out, samp, input->size >> 1);
Benny Prijonoa837c302006-04-27 22:36:40 +0000689#endif
690
691
692 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
693 output->size = input->size;
Nanang Izzuddin5fe03142009-06-02 18:01:49 +0000694 output->timestamp = input->timestamp;
Benny Prijonoa837c302006-04-27 22:36:40 +0000695
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000696#if !PLC_DISABLED
697 if (l16_data->plc_enabled)
698 pjmedia_plc_save( l16_data->plc, (pj_int16_t*)output->buf);
699#endif
700
Benny Prijonoa837c302006-04-27 22:36:40 +0000701 return PJ_SUCCESS;
702}
703
Nanang Izzuddin16b504c2008-08-26 20:09:03 +0000704#if !PLC_DISABLED
705/*
706 * Recover lost frame.
707 */
708static pj_status_t l16_recover(pjmedia_codec *codec,
709 unsigned output_buf_len,
710 struct pjmedia_frame *output)
711{
712 struct l16_data *data = (struct l16_data*) codec->codec_data;
713
714 PJ_ASSERT_RETURN(data->plc_enabled, PJ_EINVALIDOP);
715
716 PJ_ASSERT_RETURN(output_buf_len >= data->frame_size,
717 PJMEDIA_CODEC_EPCMTOOSHORT);
718
719 pjmedia_plc_generate(data->plc, (pj_int16_t*)output->buf);
720 output->size = data->frame_size;
721
722 return PJ_SUCCESS;
723}
724#endif
Benny Prijonoa837c302006-04-27 22:36:40 +0000725
726#endif /* PJMEDIA_HAS_L16_CODEC */
727
728