blob: df45604533c5c61ddc2464e02723146893aa0bdf [file] [log] [blame]
Benny Prijonoa837c302006-04-27 22:36:40 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 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;
245 attr->info.pcm_bits_per_sample = 16;
Benny Prijonoa837c302006-04-27 22:36:40 +0000246
247 /* To keep frame size below 1400 MTU, set ptime to 10ms for
248 * sampling rate > 35 KHz
249 */
Benny Prijono8befd9f2006-05-13 22:46:23 +0000250 attr->info.frm_ptime = GET_PTIME(id->clock_rate);
251
252 attr->setting.frm_per_pkt = 1;
Benny Prijonoa837c302006-04-27 22:36:40 +0000253
254 /* Default all flag bits disabled. */
255
256 return PJ_SUCCESS;
257}
258
259static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
260 unsigned *max_count,
261 pjmedia_codec_info codecs[])
262{
263 unsigned count = 0;
264
265 PJ_UNUSED_ARG(factory);
266
267 if (count < *max_count) {
268 /* Register 44100Hz 1 channel L16 codec */
269 codecs[count].type = PJMEDIA_TYPE_AUDIO;
270 codecs[count].pt = PJMEDIA_RTP_PT_L16_1;
271 codecs[count].encoding_name = STR_L16;
272 codecs[count].clock_rate = 44100;
273 codecs[count].channel_cnt = 1;
274 ++count;
275 }
276
277 if (count < *max_count) {
278 /* Register 44100Hz 2 channels L16 codec */
279 codecs[count].type = PJMEDIA_TYPE_AUDIO;
280 codecs[count].pt = PJMEDIA_RTP_PT_L16_2;
281 codecs[count].encoding_name = STR_L16;
282 codecs[count].clock_rate = 44100;
283 codecs[count].channel_cnt = 2;
284 ++count;
285 }
286
287 if (count < *max_count) {
288 /* 8KHz mono */
289 codecs[count].type = PJMEDIA_TYPE_AUDIO;
290 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_MONO;
291 codecs[count].encoding_name = STR_L16;
292 codecs[count].clock_rate = 8000;
293 codecs[count].channel_cnt = 1;
294 ++count;
295 }
296
297 if (count < *max_count) {
298 /* 8KHz stereo */
299 codecs[count].type = PJMEDIA_TYPE_AUDIO;
300 codecs[count].pt = PJMEDIA_RTP_PT_L16_8KHZ_STEREO;
301 codecs[count].encoding_name = STR_L16;
302 codecs[count].clock_rate = 8000;
303 codecs[count].channel_cnt = 2;
304 ++count;
305 }
306
307 if (count < *max_count) {
308 /* 11025 Hz mono */
309 codecs[count].type = PJMEDIA_TYPE_AUDIO;
310 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_MONO;
311 codecs[count].encoding_name = STR_L16;
312 codecs[count].clock_rate = 11025;
313 codecs[count].channel_cnt = 1;
314 ++count;
315 }
316
317 if (count < *max_count) {
318 /* 11025 Hz stereo */
319 codecs[count].type = PJMEDIA_TYPE_AUDIO;
320 codecs[count].pt = PJMEDIA_RTP_PT_L16_11KHZ_STEREO;
321 codecs[count].encoding_name = STR_L16;
322 codecs[count].clock_rate = 11025;
323 codecs[count].channel_cnt = 2;
324 ++count;
325 }
326
327 if (count < *max_count) {
328 /* 16000 Hz mono */
329 codecs[count].type = PJMEDIA_TYPE_AUDIO;
330 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_MONO;
331 codecs[count].encoding_name = STR_L16;
332 codecs[count].clock_rate = 16000;
333 codecs[count].channel_cnt = 1;
334 ++count;
335 }
336
337
338 if (count < *max_count) {
339 /* 16000 Hz stereo */
340 codecs[count].type = PJMEDIA_TYPE_AUDIO;
341 codecs[count].pt = PJMEDIA_RTP_PT_L16_16KHZ_STEREO;
342 codecs[count].encoding_name = STR_L16;
343 codecs[count].clock_rate = 16000;
344 codecs[count].channel_cnt = 2;
345 ++count;
346 }
347
348 if (count < *max_count) {
349 /* 22050 Hz mono */
350 codecs[count].type = PJMEDIA_TYPE_AUDIO;
351 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_MONO;
352 codecs[count].encoding_name = STR_L16;
353 codecs[count].clock_rate = 22050;
354 codecs[count].channel_cnt = 1;
355 ++count;
356 }
357
358
359 if (count < *max_count) {
360 /* 22050 Hz stereo */
361 codecs[count].type = PJMEDIA_TYPE_AUDIO;
362 codecs[count].pt = PJMEDIA_RTP_PT_L16_22KHZ_STEREO;
363 codecs[count].encoding_name = STR_L16;
364 codecs[count].clock_rate = 22050;
365 codecs[count].channel_cnt = 2;
366 ++count;
367 }
368
369 if (count < *max_count) {
370 /* 32000 Hz mono */
371 codecs[count].type = PJMEDIA_TYPE_AUDIO;
372 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_MONO;
373 codecs[count].encoding_name = STR_L16;
374 codecs[count].clock_rate = 32000;
375 codecs[count].channel_cnt = 1;
376 ++count;
377 }
378
379 if (count < *max_count) {
380 /* 32000 Hz stereo */
381 codecs[count].type = PJMEDIA_TYPE_AUDIO;
382 codecs[count].pt = PJMEDIA_RTP_PT_L16_32KHZ_STEREO;
383 codecs[count].encoding_name = STR_L16;
384 codecs[count].clock_rate = 32000;
385 codecs[count].channel_cnt = 2;
386 ++count;
387 }
388
389 if (count < *max_count) {
390 /* 48KHz mono */
391 codecs[count].type = PJMEDIA_TYPE_AUDIO;
392 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
393 codecs[count].encoding_name = STR_L16;
394 codecs[count].clock_rate = 48000;
395 codecs[count].channel_cnt = 1;
396 ++count;
397 }
398
399 if (count < *max_count) {
400 /* 48KHz stereo */
401 codecs[count].type = PJMEDIA_TYPE_AUDIO;
402 codecs[count].pt = PJMEDIA_RTP_PT_L16_48KHZ_MONO;
403 codecs[count].encoding_name = STR_L16;
404 codecs[count].clock_rate = 48000;
405 codecs[count].channel_cnt = 2;
406 ++count;
407 }
408
409
410 *max_count = count;
411
412 return PJ_SUCCESS;
413}
414
415static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory,
416 const pjmedia_codec_info *id,
417 pjmedia_codec **p_codec)
418{
419 pjmedia_codec *codec = NULL;
420 struct l16_data *data;
421 unsigned ptime;
422
423 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
424
425 /* Lock mutex. */
426 pj_mutex_lock(l16_factory.mutex);
427
428 /* Allocate new codec if no more is available */
429 if (pj_list_empty(&l16_factory.codec_list)) {
430
Benny Prijonoa1e69682007-05-11 15:14:34 +0000431 codec = PJ_POOL_ALLOC_T(l16_factory.pool, pjmedia_codec);
Benny Prijonoa837c302006-04-27 22:36:40 +0000432 codec->codec_data = pj_pool_alloc(l16_factory.pool,
433 sizeof(struct l16_data));
434 codec->factory = factory;
435 codec->op = &l16_op;
436
437 } else {
438 codec = l16_factory.codec_list.next;
439 pj_list_erase(codec);
440 }
441
442 /* Init private data */
443 ptime = GET_PTIME(id->clock_rate);
Benny Prijonoa1e69682007-05-11 15:14:34 +0000444 data = (struct l16_data*) codec->codec_data;
Benny Prijonoa837c302006-04-27 22:36:40 +0000445 data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
446
447 /* Zero the list, for error detection in l16_dealloc_codec */
448 codec->next = codec->prev = NULL;
449
450 *p_codec = codec;
451
452 /* Unlock mutex. */
453 pj_mutex_unlock(l16_factory.mutex);
454
455 return PJ_SUCCESS;
456}
457
458static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory,
459 pjmedia_codec *codec )
460{
461
462 PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);
463
464 /* Check that this node has not been deallocated before */
465 pj_assert (codec->next==NULL && codec->prev==NULL);
466 if (codec->next!=NULL || codec->prev!=NULL) {
467 return PJ_EINVALIDOP;
468 }
469
470 /* Lock mutex. */
471 pj_mutex_lock(l16_factory.mutex);
472
473 /* Insert at the back of the list */
474 pj_list_insert_before(&l16_factory.codec_list, codec);
475
476 /* Unlock mutex. */
477 pj_mutex_unlock(l16_factory.mutex);
478
479 return PJ_SUCCESS;
480}
481
482static pj_status_t l16_init( pjmedia_codec *codec, pj_pool_t *pool )
483{
484 /* There's nothing to do here really */
485 PJ_UNUSED_ARG(codec);
486 PJ_UNUSED_ARG(pool);
487
488 return PJ_SUCCESS;
489}
490
491static pj_status_t l16_open(pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000492 pjmedia_codec_param *attr )
Benny Prijonoa837c302006-04-27 22:36:40 +0000493{
494 /* Nothing to do.. */
495 PJ_UNUSED_ARG(codec);
496 PJ_UNUSED_ARG(attr);
497 return PJ_SUCCESS;
498}
499
500static pj_status_t l16_close( pjmedia_codec *codec )
501{
502 PJ_UNUSED_ARG(codec);
503 /* Nothing to do */
504 return PJ_SUCCESS;
505}
506
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000507static pj_status_t l16_modify(pjmedia_codec *codec,
508 const pjmedia_codec_param *attr )
509{
510 /* Don't want to do anything. */
511 PJ_UNUSED_ARG(codec);
512 PJ_UNUSED_ARG(attr);
513 return PJ_EINVALIDOP;
514}
515
Benny Prijono8befd9f2006-05-13 22:46:23 +0000516static pj_status_t l16_parse( pjmedia_codec *codec,
517 void *pkt,
518 pj_size_t pkt_size,
519 const pj_timestamp *ts,
520 unsigned *frame_cnt,
521 pjmedia_frame frames[])
Benny Prijonoa837c302006-04-27 22:36:40 +0000522{
523 unsigned count = 0;
524 struct l16_data *data = (struct l16_data*) codec->codec_data;
525
526 PJ_UNUSED_ARG(codec);
527 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
528
529 while (pkt_size >= data->frame_size && count < *frame_cnt) {
Benny Prijono8befd9f2006-05-13 22:46:23 +0000530 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
531 frames[count].buf = pkt;
532 frames[count].size = data->frame_size;
533 frames[count].timestamp.u64 = ts->u64 + (count * data->frame_size);
Benny Prijonoa837c302006-04-27 22:36:40 +0000534
535 pkt = ((char*)pkt) + data->frame_size;
536 pkt_size -= data->frame_size;
537
538 ++count;
539 }
540
541 *frame_cnt = count;
542 return PJ_SUCCESS;
543}
544
545static pj_status_t l16_encode(pjmedia_codec *codec,
546 const struct pjmedia_frame *input,
547 unsigned output_buf_len,
548 struct pjmedia_frame *output)
549{
550 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
551 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
552 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
553
554
555 PJ_UNUSED_ARG(codec);
556
557
558 /* Check output buffer length */
559 if (output_buf_len < input->size)
560 return PJMEDIA_CODEC_EFRMTOOSHORT;
561
562
563 /* Encode */
564#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
565 while (samp!=samp_end)
566 *samp_out++ = pj_htons(*samp++);
567#endif
568
569
570 /* Done */
571 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
572 output->size = input->size;
573
574 return PJ_SUCCESS;
575}
576
577static pj_status_t l16_decode(pjmedia_codec *codec,
578 const struct pjmedia_frame *input,
579 unsigned output_buf_len,
580 struct pjmedia_frame *output)
581{
582 const pj_int16_t *samp = (const pj_int16_t*) input->buf;
583 const pj_int16_t *samp_end = samp + input->size/sizeof(pj_int16_t);
584 pj_int16_t *samp_out = (pj_int16_t*) output->buf;
585
586
587 PJ_UNUSED_ARG(codec);
588
589
590 /* Check output buffer length */
591 if (output_buf_len < input->size)
592 return PJMEDIA_CODEC_EPCMTOOSHORT;
593
594
595 /* Decode */
596#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
597 while (samp!=samp_end)
598 *samp_out++ = pj_htons(*samp++);
599#endif
600
601
602 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
603 output->size = input->size;
604
605 return PJ_SUCCESS;
606}
607
608
609#endif /* PJMEDIA_HAS_L16_CODEC */
610
611