blob: 1c077dfaaae8d9854bece71d8a9763bb93400a19 [file] [log] [blame]
Benny Prijonoa837c302006-04-27 22:36:40 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C)2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonoa837c302006-04-27 22:36:40 +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/l16.h>
20#include <pjmedia/codec.h>
21#include <pjmedia/errno.h>
22#include <pjmedia/endpoint.h>
23#include <pj/assert.h>
24#include <pj/pool.h>
25#include <pj/sock.h>
26#include <pj/string.h>
27
28
29/*
30 * Only build this file if PJMEDIA_HAS_L16_CODEC != 0
31 */
32#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
33
34
35static const pj_str_t STR_L16 = { "L16", 3 };
36
37/* To keep frame size below 1400 MTU, set ptime to 10ms for
38 * sampling rate > 35 KHz
39 */
40#define GET_PTIME(clock_rate) ((pj_uint16_t)(clock_rate > 35000 ? 10 : 20))
41
42
43/* Prototypes for L16 factory */
44static pj_status_t l16_test_alloc( pjmedia_codec_factory *factory,
45 const pjmedia_codec_info *id );
46static pj_status_t l16_default_attr( pjmedia_codec_factory *factory,
47 const pjmedia_codec_info *id,
48 pjmedia_codec_param *attr );
49static pj_status_t l16_enum_codecs (pjmedia_codec_factory *factory,
50 unsigned *count,
51 pjmedia_codec_info codecs[]);
52static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory,
53 const pjmedia_codec_info *id,
54 pjmedia_codec **p_codec);
55static pj_status_t l16_dealloc_codec( pjmedia_codec_factory *factory,
56 pjmedia_codec *codec );
57
58/* Prototypes for L16 implementation. */
59static pj_status_t l16_init( pjmedia_codec *codec,
60 pj_pool_t *pool );
61static pj_status_t l16_open( pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000062 pjmedia_codec_param *attr );
Benny Prijonoa837c302006-04-27 22:36:40 +000063static pj_status_t l16_close( pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000064static pj_status_t l16_modify(pjmedia_codec *codec,
65 const pjmedia_codec_param *attr );
Benny Prijono8befd9f2006-05-13 22:46:23 +000066static pj_status_t l16_parse(pjmedia_codec *codec,
67 void *pkt,
68 pj_size_t pkt_size,
69 const pj_timestamp *ts,
70 unsigned *frame_cnt,
71 pjmedia_frame frames[]);
Benny Prijonoa837c302006-04-27 22:36:40 +000072static pj_status_t l16_encode( pjmedia_codec *codec,
73 const struct pjmedia_frame *input,
74 unsigned output_buf_len,
75 struct pjmedia_frame *output);
76static pj_status_t l16_decode( pjmedia_codec *codec,
77 const struct pjmedia_frame *input,
78 unsigned output_buf_len,
79 struct pjmedia_frame *output);
80
81/* Definition for L16 codec operations. */
82static pjmedia_codec_op l16_op =
83{
84 &l16_init,
85 &l16_open,
86 &l16_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +000087 &l16_modify,
Benny Prijono8befd9f2006-05-13 22:46:23 +000088 &l16_parse,
Benny Prijonoa837c302006-04-27 22:36:40 +000089 &l16_encode,
90 &l16_decode
91};
92
93/* Definition for L16 codec factory operations. */
94static pjmedia_codec_factory_op l16_factory_op =
95{
96 &l16_test_alloc,
97 &l16_default_attr,
98 &l16_enum_codecs,
99 &l16_alloc_codec,
100 &l16_dealloc_codec
101};
102
103/* L16 factory private data */
104static struct l16_factory
105{
106 pjmedia_codec_factory base;
107 pjmedia_endpt *endpt;
108 pj_pool_t *pool;
109 pj_mutex_t *mutex;
110 pjmedia_codec codec_list;
111} l16_factory;
112
113
114/* L16 codec private data. */
115struct l16_data
116{
117 unsigned frame_size; /* Frame size, in bytes */
118};
119
120
121
122PJ_DEF(pj_status_t) pjmedia_codec_l16_init(pjmedia_endpt *endpt,
123 unsigned options)
124{
125 pjmedia_codec_mgr *codec_mgr;
126 pj_status_t status;
127
128
129 PJ_UNUSED_ARG(options);
130
131
132 if (l16_factory.endpt != NULL) {
133 /* Already initialized. */
134 return PJ_SUCCESS;
135 }
136
137 /* Init factory */
138 l16_factory.base.op = &l16_factory_op;
139 l16_factory.base.factory_data = NULL;
140 l16_factory.endpt = endpt;
141
142 pj_list_init(&l16_factory.codec_list);
143
144 /* Create pool */
145 l16_factory.pool = pjmedia_endpt_create_pool(endpt, "l16", 4000, 4000);
146 if (!l16_factory.pool)
147 return PJ_ENOMEM;
148
149 /* Create mutex. */
150 status = pj_mutex_create_simple(l16_factory.pool, "l16",
151 &l16_factory.mutex);
152 if (status != PJ_SUCCESS)
153 goto on_error;
154
155 /* Get the codec manager. */
156 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
157 if (!codec_mgr) {
158 return PJ_EINVALIDOP;
159 }
160
161 /* Register codec factory to endpoint. */
162 status = pjmedia_codec_mgr_register_factory(codec_mgr,
163 &l16_factory.base);
164 if (status != PJ_SUCCESS)
165 return status;
166
167
168 return PJ_SUCCESS;
169
170on_error:
171 if (l16_factory.mutex) {
172 pj_mutex_destroy(l16_factory.mutex);
173 l16_factory.mutex = NULL;
174 }
175 if (l16_factory.pool) {
176 pj_pool_release(l16_factory.pool);
177 l16_factory.pool = NULL;
178 }
179 return status;
180}
181
182PJ_DEF(pj_status_t) pjmedia_codec_l16_deinit(void)
183{
184 pjmedia_codec_mgr *codec_mgr;
185 pj_status_t status;
186
187 if (l16_factory.endpt == NULL) {
188 /* Not registered. */
189 return PJ_SUCCESS;
190 }
191
192 /* Lock mutex. */
193 pj_mutex_lock(l16_factory.mutex);
194
195 /* Get the codec manager. */
196 codec_mgr = pjmedia_endpt_get_codec_mgr(l16_factory.endpt);
197 if (!codec_mgr) {
198 l16_factory.endpt = NULL;
199 pj_mutex_unlock(l16_factory.mutex);
200 return PJ_EINVALIDOP;
201 }
202
203 /* Unregister L16 codec factory. */
204 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
205 &l16_factory.base);
206 l16_factory.endpt = NULL;
207
208 /* Destroy mutex. */
209 pj_mutex_destroy(l16_factory.mutex);
210 l16_factory.mutex = NULL;
211
212
213 /* Release pool. */
214 pj_pool_release(l16_factory.pool);
215 l16_factory.pool = NULL;
216
217
218 return status;
219}
220
221static pj_status_t l16_test_alloc(pjmedia_codec_factory *factory,
222 const pjmedia_codec_info *id )
223{
224 PJ_UNUSED_ARG(factory);
225
226 if (pj_stricmp(&id->encoding_name, &STR_L16)==0) {
227 /* Match! */
228 return PJ_SUCCESS;
229 }
230
231 return -1;
232}
233
234static pj_status_t l16_default_attr( pjmedia_codec_factory *factory,
235 const pjmedia_codec_info *id,
236 pjmedia_codec_param *attr )
237{
238 PJ_UNUSED_ARG(factory);
239
Benny Prijonoac623b32006-07-03 15:19:31 +0000240 pj_bzero(attr, sizeof(pjmedia_codec_param));
Benny Prijono8befd9f2006-05-13 22:46:23 +0000241 attr->info.pt = (pj_uint8_t)id->pt;
242 attr->info.clock_rate = id->clock_rate;
243 attr->info.channel_cnt = id->channel_cnt;
244 attr->info.avg_bps = id->clock_rate * id->channel_cnt * 16;
Nanang Izzuddine4b4b7d2008-06-06 12:15:23 +0000245 attr->info.max_bps = attr->info.avg_bps;
Benny Prijono8befd9f2006-05-13 22:46:23 +0000246 attr->info.pcm_bits_per_sample = 16;
Benny Prijonoa837c302006-04-27 22:36:40 +0000247
248 /* To keep frame size below 1400 MTU, set ptime to 10ms for
249 * sampling rate > 35 KHz
250 */
Benny Prijono8befd9f2006-05-13 22:46:23 +0000251 attr->info.frm_ptime = GET_PTIME(id->clock_rate);
252
253 attr->setting.frm_per_pkt = 1;
Benny Prijonoa837c302006-04-27 22:36:40 +0000254
255 /* Default all flag bits disabled. */
256
257 return PJ_SUCCESS;
258}
259
260static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
261 unsigned *max_count,
262 pjmedia_codec_info codecs[])
263{
264 unsigned count = 0;
265
266 PJ_UNUSED_ARG(factory);
267
268 if (count < *max_count) {
269 /* Register 44100Hz 1 channel L16 codec */
270 codecs[count].type = PJMEDIA_TYPE_AUDIO;
271 codecs[count].pt = PJMEDIA_RTP_PT_L16_1;
272 codecs[count].encoding_name = STR_L16;
273 codecs[count].clock_rate = 44100;
274 codecs[count].channel_cnt = 1;
275 ++count;
276 }
277
278 if (count < *max_count) {
279 /* Register 44100Hz 2 channels L16 codec */
280 codecs[count].type = PJMEDIA_TYPE_AUDIO;
281 codecs[count].pt = PJMEDIA_RTP_PT_L16_2;
282 codecs[count].encoding_name = STR_L16;
283 codecs[count].clock_rate = 44100;
284 codecs[count].channel_cnt = 2;
285 ++count;
286 }
287
288 if (count < *max_count) {
289 /* 8KHz mono */
290 codecs[count].type = PJMEDIA_TYPE_AUDIO;
291 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_MONO;
292 codecs[count].encoding_name = STR_L16;
293 codecs[count].clock_rate = 8000;
294 codecs[count].channel_cnt = 1;
295 ++count;
296 }
297
298 if (count < *max_count) {
299 /* 8KHz stereo */
300 codecs[count].type = PJMEDIA_TYPE_AUDIO;
301 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_STEREO;
302 codecs[count].encoding_name = STR_L16;
303 codecs[count].clock_rate = 8000;
304 codecs[count].channel_cnt = 2;
305 ++count;
306 }
307
308 if (count < *max_count) {
309 /* 11025 Hz mono */
310 codecs[count].type = PJMEDIA_TYPE_AUDIO;
311 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_MONO;
312 codecs[count].encoding_name = STR_L16;
313 codecs[count].clock_rate = 11025;
314 codecs[count].channel_cnt = 1;
315 ++count;
316 }
317
318 if (count < *max_count) {
319 /* 11025 Hz stereo */
320 codecs[count].type = PJMEDIA_TYPE_AUDIO;
321 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_STEREO;
322 codecs[count].encoding_name = STR_L16;
323 codecs[count].clock_rate = 11025;
324 codecs[count].channel_cnt = 2;
325 ++count;
326 }
327
328 if (count < *max_count) {
329 /* 16000 Hz mono */
330 codecs[count].type = PJMEDIA_TYPE_AUDIO;
331 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_MONO;
332 codecs[count].encoding_name = STR_L16;
333 codecs[count].clock_rate = 16000;
334 codecs[count].channel_cnt = 1;
335 ++count;
336 }
337
338
339 if (count < *max_count) {
340 /* 16000 Hz stereo */
341 codecs[count].type = PJMEDIA_TYPE_AUDIO;
342 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_STEREO;
343 codecs[count].encoding_name = STR_L16;
344 codecs[count].clock_rate = 16000;
345 codecs[count].channel_cnt = 2;
346 ++count;
347 }
348
349 if (count < *max_count) {
350 /* 22050 Hz mono */
351 codecs[count].type = PJMEDIA_TYPE_AUDIO;
352 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_MONO;
353 codecs[count].encoding_name = STR_L16;
354 codecs[count].clock_rate = 22050;
355 codecs[count].channel_cnt = 1;
356 ++count;
357 }
358
359
360 if (count < *max_count) {
361 /* 22050 Hz stereo */
362 codecs[count].type = PJMEDIA_TYPE_AUDIO;
363 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_STEREO;
364 codecs[count].encoding_name = STR_L16;
365 codecs[count].clock_rate = 22050;
366 codecs[count].channel_cnt = 2;
367 ++count;
368 }
369
370 if (count < *max_count) {
371 /* 32000 Hz mono */
372 codecs[count].type = PJMEDIA_TYPE_AUDIO;
373 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_MONO;
374 codecs[count].encoding_name = STR_L16;
375 codecs[count].clock_rate = 32000;
376 codecs[count].channel_cnt = 1;
377 ++count;
378 }
379
380 if (count < *max_count) {
381 /* 32000 Hz stereo */
382 codecs[count].type = PJMEDIA_TYPE_AUDIO;
383 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_STEREO;
384 codecs[count].encoding_name = STR_L16;
385 codecs[count].clock_rate = 32000;
386 codecs[count].channel_cnt = 2;
387 ++count;
388 }
389
390 if (count < *max_count) {
391 /* 48KHz mono */
392 codecs[count].type = PJMEDIA_TYPE_AUDIO;
393 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
394 codecs[count].encoding_name = STR_L16;
395 codecs[count].clock_rate = 48000;
396 codecs[count].channel_cnt = 1;
397 ++count;
398 }
399
400 if (count < *max_count) {
401 /* 48KHz stereo */
402 codecs[count].type = PJMEDIA_TYPE_AUDIO;
403 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
404 codecs[count].encoding_name = STR_L16;
405 codecs[count].clock_rate = 48000;
406 codecs[count].channel_cnt = 2;
407 ++count;
408 }
409
410
411 *max_count = count;
412
413 return PJ_SUCCESS;
414}
415
416static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory,
417 const pjmedia_codec_info *id,
418 pjmedia_codec **p_codec)
419{
420 pjmedia_codec *codec = NULL;
421 struct l16_data *data;
422 unsigned ptime;
423
424 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
425
426 /* Lock mutex. */
427 pj_mutex_lock(l16_factory.mutex);
428
429 /* Allocate new codec if no more is available */
430 if (pj_list_empty(&l16_factory.codec_list)) {
431
Benny Prijonoa1e69682007-05-11 15:14:34 +0000432 codec = PJ_POOL_ALLOC_T(l16_factory.pool, pjmedia_codec);
Benny Prijonoa837c302006-04-27 22:36:40 +0000433 codec->codec_data = pj_pool_alloc(l16_factory.pool,
434 sizeof(struct l16_data));
435 codec->factory = factory;
436 codec->op = &l16_op;
437
438 } else {
439 codec = l16_factory.codec_list.next;
440 pj_list_erase(codec);
441 }
442
443 /* Init private data */
444 ptime = GET_PTIME(id->clock_rate);
Benny Prijonoa1e69682007-05-11 15:14:34 +0000445 data = (struct l16_data*) codec->codec_data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000446 data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
447
448 /* Zero the list, for error detection in l16_dealloc_codec */
449 codec->next = codec->prev = NULL;
450
451 *p_codec = codec;
452
453 /* Unlock mutex. */
454 pj_mutex_unlock(l16_factory.mutex);
455
456 return PJ_SUCCESS;
457}
458
459static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory,
460 pjmedia_codec *codec )
461{
462
463 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
464
465 /* Check that this node has not been deallocated before */
466 pj_assert (codec->next==NULL && codec->prev==NULL);
467 if (codec->next!=NULL || codec->prev!=NULL) {
468 return PJ_EINVALIDOP;
469 }
470
471 /* Lock mutex. */
472 pj_mutex_lock(l16_factory.mutex);
473
474 /* Insert at the back of the list */
475 pj_list_insert_before(&l16_factory.codec_list, codec);
476
477 /* Unlock mutex. */
478 pj_mutex_unlock(l16_factory.mutex);
479
480 return PJ_SUCCESS;
481}
482
483static pj_status_t l16_init( pjmedia_codec *codec, pj_pool_t *pool )
484{
485 /* There's nothing to do here really */
486 PJ_UNUSED_ARG(codec);
487 PJ_UNUSED_ARG(pool);
488
489 return PJ_SUCCESS;
490}
491
492static pj_status_t l16_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000493 pjmedia_codec_param *attr )
Benny Prijonoa837c302006-04-27 22:36:40 +0000494{
495 /* Nothing to do.. */
496 PJ_UNUSED_ARG(codec);
497 PJ_UNUSED_ARG(attr);
498 return PJ_SUCCESS;
499}
500
501static pj_status_t l16_close( pjmedia_codec *codec )
502{
503 PJ_UNUSED_ARG(codec);
504 /* Nothing to do */
505 return PJ_SUCCESS;
506}
507
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000508static pj_status_t l16_modify(pjmedia_codec *codec,
509 const pjmedia_codec_param *attr )
510{
511 /* Don't want to do anything. */
512 PJ_UNUSED_ARG(codec);
513 PJ_UNUSED_ARG(attr);
514 return PJ_EINVALIDOP;
515}
516
Benny Prijono8befd9f2006-05-13 22:46:23 +0000517static pj_status_t l16_parse( pjmedia_codec *codec,
518 void *pkt,
519 pj_size_t pkt_size,
520 const pj_timestamp *ts,
521 unsigned *frame_cnt,
522 pjmedia_frame frames[])
Benny Prijonoa837c302006-04-27 22:36:40 +0000523{
524 unsigned count = 0;
525 struct l16_data *data = (struct l16_data*) codec->codec_data;
526
527 PJ_UNUSED_ARG(codec);
528 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
529
530 while (pkt_size >= data->frame_size && count < *frame_cnt) {
Benny Prijono8befd9f2006-05-13 22:46:23 +0000531 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
532 frames[count].buf = pkt;
533 frames[count].size = data->frame_size;
534 frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size);
Benny Prijonoa837c302006-04-27 22:36:40 +0000535
536 pkt = ((char*)pkt) + data->frame_size;
537 pkt_size -= data->frame_size;
538
539 ++count;
540 }
541
542 *frame_cnt = count;
543 return PJ_SUCCESS;
544}
545
546static pj_status_t l16_encode(pjmedia_codec *codec,
547 const struct pjmedia_frame *input,
548 unsigned output_buf_len,
549 struct pjmedia_frame *output)
550{
551 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
552 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
553 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
554
555
556 PJ_UNUSED_ARG(codec);
557
558
559 /* Check output buffer length */
560 if (output_buf_len < input->size)
561 return PJMEDIA_CODEC_EFRMTOOSHORT;
562
563
564 /* Encode */
565#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
566 while (samp!=samp_end)
567 *samp_out++ = pj_htons(*samp++);
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000568#else
569 pjmedia_copy_samples(samp_out, samp, input->size >> 1);
Benny Prijonoa837c302006-04-27 22:36:40 +0000570#endif
571
572
573 /* Done */
574 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
575 output->size = input->size;
576
577 return PJ_SUCCESS;
578}
579
580static pj_status_t l16_decode(pjmedia_codec *codec,
581 const struct pjmedia_frame *input,
582 unsigned output_buf_len,
583 struct pjmedia_frame *output)
584{
585 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
586 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
587 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
588
589
590 PJ_UNUSED_ARG(codec);
591
592
593 /* Check output buffer length */
594 if (output_buf_len < input->size)
595 return PJMEDIA_CODEC_EPCMTOOSHORT;
596
597
598 /* Decode */
599#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
600 while (samp!=samp_end)
601 *samp_out++ = pj_htons(*samp++);
Nanang Izzuddin3aef5e12008-06-05 10:50:40 +0000602#else
603 pjmedia_copy_samples(samp_out, samp, input->size >> 1);
Benny Prijonoa837c302006-04-27 22:36:40 +0000604#endif
605
606
607 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
608 output->size = input->size;
609
610 return PJ_SUCCESS;
611}
612
613
614#endif /* PJMEDIA_HAS_L16_CODEC */
615
616