blob: c2f9f9a4362af0cd14df286800adaeaa0b23f796 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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/passthrough.h>
21#include <pjmedia-codec/amr_sdp_match.h>
22#include <pjmedia/codec.h>
23#include <pjmedia/errno.h>
24#include <pjmedia/endpoint.h>
25#include <pjmedia/port.h>
26#include <pj/assert.h>
27#include <pj/log.h>
28#include <pj/math.h>
29#include <pj/pool.h>
30#include <pj/string.h>
31#include <pj/os.h>
32
33/*
34 * Only build this file if PJMEDIA_HAS_PASSTHROUGH_CODECS != 0
35 */
36#if defined(PJMEDIA_HAS_PASSTHROUGH_CODECS) && PJMEDIA_HAS_PASSTHROUGH_CODECS!=0
37
38#define THIS_FILE "passthrough.c"
39
40
41/* Prototypes for passthrough codecs factory */
42static pj_status_t test_alloc( pjmedia_codec_factory *factory,
43 const pjmedia_codec_info *id );
44static pj_status_t default_attr( pjmedia_codec_factory *factory,
45 const pjmedia_codec_info *id,
46 pjmedia_codec_param *attr );
47static pj_status_t enum_codecs( pjmedia_codec_factory *factory,
48 unsigned *count,
49 pjmedia_codec_info codecs[]);
50static pj_status_t alloc_codec( pjmedia_codec_factory *factory,
51 const pjmedia_codec_info *id,
52 pjmedia_codec **p_codec);
53static pj_status_t dealloc_codec( pjmedia_codec_factory *factory,
54 pjmedia_codec *codec );
55
56/* Prototypes for passthrough codecs implementation. */
57static pj_status_t codec_init( pjmedia_codec *codec,
58 pj_pool_t *pool );
59static pj_status_t codec_open( pjmedia_codec *codec,
60 pjmedia_codec_param *attr );
61static pj_status_t codec_close( pjmedia_codec *codec );
62static pj_status_t codec_modify(pjmedia_codec *codec,
63 const pjmedia_codec_param *attr );
64static pj_status_t codec_parse( pjmedia_codec *codec,
65 void *pkt,
66 pj_size_t pkt_size,
67 const pj_timestamp *ts,
68 unsigned *frame_cnt,
69 pjmedia_frame frames[]);
70static pj_status_t codec_encode( pjmedia_codec *codec,
71 const struct pjmedia_frame *input,
72 unsigned output_buf_len,
73 struct pjmedia_frame *output);
74static pj_status_t codec_decode( pjmedia_codec *codec,
75 const struct pjmedia_frame *input,
76 unsigned output_buf_len,
77 struct pjmedia_frame *output);
78static pj_status_t codec_recover( pjmedia_codec *codec,
79 unsigned output_buf_len,
80 struct pjmedia_frame *output);
81
82/* Definition for passthrough codecs operations. */
83static pjmedia_codec_op codec_op =
84{
85 &codec_init,
86 &codec_open,
87 &codec_close,
88 &codec_modify,
89 &codec_parse,
90 &codec_encode,
91 &codec_decode,
92 &codec_recover
93};
94
95/* Definition for passthrough codecs factory operations. */
96static pjmedia_codec_factory_op codec_factory_op =
97{
98 &test_alloc,
99 &default_attr,
100 &enum_codecs,
101 &alloc_codec,
102 &dealloc_codec,
103 &pjmedia_codec_passthrough_deinit
104};
105
106/* Passthrough codecs factory */
107static struct codec_factory {
108 pjmedia_codec_factory base;
109 pjmedia_endpt *endpt;
110 pj_pool_t *pool;
111 pj_mutex_t *mutex;
112} codec_factory;
113
114/* Passthrough codecs private data. */
115typedef struct codec_private {
116 pj_pool_t *pool; /**< Pool for each instance. */
117 int codec_idx; /**< Codec index. */
118 void *codec_setting; /**< Specific codec setting. */
119 pj_uint16_t avg_frame_size; /**< Average of frame size. */
120 unsigned samples_per_frame; /**< Samples per frame, for iLBC
121 this can be 240 or 160, can
122 only be known after codec is
123 opened. */
124} codec_private_t;
125
126
127
128/* CUSTOM CALLBACKS */
129
130/* Parse frames from a packet. Default behaviour of frame parsing is
131 * just separating frames based on calculating frame length derived
132 * from bitrate. Implement this callback when the default behaviour is
133 * unapplicable.
134 */
135typedef pj_status_t (*parse_cb)(codec_private_t *codec_data, void *pkt,
136 pj_size_t pkt_size, const pj_timestamp *ts,
137 unsigned *frame_cnt, pjmedia_frame frames[]);
138
139/* Pack frames into a packet. Default behaviour of packing frames is
140 * just stacking the frames with octet aligned without adding any
141 * payload header. Implement this callback when the default behaviour is
142 * unapplicable.
143 */
144typedef pj_status_t (*pack_cb)(codec_private_t *codec_data,
145 const struct pjmedia_frame_ext *input,
146 unsigned output_buf_len,
147 struct pjmedia_frame *output);
148
149
150/* Custom callback implementations. */
151static pj_status_t parse_amr( codec_private_t *codec_data, void *pkt,
152 pj_size_t pkt_size, const pj_timestamp *ts,
153 unsigned *frame_cnt, pjmedia_frame frames[]);
154static pj_status_t pack_amr ( codec_private_t *codec_data,
155 const struct pjmedia_frame_ext *input,
156 unsigned output_buf_len,
157 struct pjmedia_frame *output);
158
159
160/* Passthrough codec implementation descriptions. */
161static struct codec_desc {
162 int enabled; /* Is this codec enabled? */
163 const char *name; /* Codec name. */
164 pj_uint8_t pt; /* Payload type. */
165 pjmedia_format_id fmt_id; /* Source format. */
166 unsigned clock_rate; /* Codec's clock rate. */
167 unsigned channel_count; /* Codec's channel count. */
168 unsigned samples_per_frame; /* Codec's samples count. */
169 unsigned def_bitrate; /* Default bitrate of this codec. */
170 unsigned max_bitrate; /* Maximum bitrate of this codec. */
171 pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/
172 pj_uint8_t vad; /* VAD enabled/disabled. */
173 pj_uint8_t plc; /* PLC enabled/disabled. */
174 parse_cb parse; /* Callback to parse bitstream. */
175 pack_cb pack; /* Callback to pack bitstream. */
176 pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
177}
178
179codec_desc[] =
180{
181# if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
182 {1, "AMR", PJMEDIA_RTP_PT_AMR, PJMEDIA_FORMAT_AMR,
183 8000, 1, 160,
184 7400, 12200, 2, 1, 1,
185 &parse_amr, &pack_amr
186 /*, {1, {{{"octet-align", 11}, {"1", 1}}} } */
187 },
188# endif
189
190# if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
191 {1, "G729", PJMEDIA_RTP_PT_G729, PJMEDIA_FORMAT_G729,
192 8000, 1, 80,
193 8000, 8000, 2, 1, 1
194 },
195# endif
196
197# if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
198 {1, "iLBC", PJMEDIA_RTP_PT_ILBC, PJMEDIA_FORMAT_ILBC,
199 8000, 1, 240,
200 13333, 15200, 1, 1, 1,
201 NULL, NULL,
202 {1, {{{"mode", 4}, {"30", 2}}} }
203 },
204# endif
205
206# if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU
207 {1, "PCMU", PJMEDIA_RTP_PT_PCMU, PJMEDIA_FORMAT_PCMU,
208 8000, 1, 80,
209 64000, 64000, 2, 1, 1
210 },
211# endif
212
213# if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA
214 {1, "PCMA", PJMEDIA_RTP_PT_PCMA, PJMEDIA_FORMAT_PCMA,
215 8000, 1, 80,
216 64000, 64000, 2, 1, 1
217 },
218# endif
219};
220
221
222#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
223
224#include <pjmedia-codec/amr_helper.h>
225
226typedef struct amr_settings_t {
227 pjmedia_codec_amr_pack_setting enc_setting;
228 pjmedia_codec_amr_pack_setting dec_setting;
229 pj_int8_t enc_mode;
230} amr_settings_t;
231
232
233/* Pack AMR payload */
234static pj_status_t pack_amr ( codec_private_t *codec_data,
235 const struct pjmedia_frame_ext *input,
236 unsigned output_buf_len,
237 struct pjmedia_frame *output)
238{
239 enum {MAX_FRAMES_PER_PACKET = PJMEDIA_MAX_FRAME_DURATION_MS / 20};
240
241 pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
242 amr_settings_t* setting = (amr_settings_t*)codec_data->codec_setting;
243 pjmedia_codec_amr_pack_setting *enc_setting = &setting->enc_setting;
244 pj_uint8_t SID_FT;
245 unsigned i;
246
247 pj_assert(input->subframe_cnt <= MAX_FRAMES_PER_PACKET);
248
249 SID_FT = (pj_uint8_t)(enc_setting->amr_nb? 8 : 9);
250
251 /* Get frames */
252 for (i = 0; i < input->subframe_cnt; ++i) {
253 pjmedia_frame_ext_subframe *sf;
254 pjmedia_codec_amr_bit_info *info;
255 unsigned len;
256
257 sf = pjmedia_frame_ext_get_subframe(input, i);
258 len = (sf->bitlen + 7) >> 3;
259
260 info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info;
261 pj_bzero(info, sizeof(*info));
262
263 if (len == 0) {
264 /* DTX */
265 info->frame_type = 15;
266 } else {
267 info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb,
268 len);
269 }
270 info->good_quality = 1;
271 info->mode = setting->enc_mode;
272 if (info->frame_type == SID_FT)
273 info->STI = (sf->data[4] >> 4) & 1;
274
275 frames[i].buf = sf->data;
276 frames[i].size = len;
277 }
278
279 output->size = output_buf_len;
280
281 return pjmedia_codec_amr_pack(frames, input->subframe_cnt, enc_setting,
282 output->buf, &output->size);
283}
284
285
286/* Parse AMR payload into frames. */
287static pj_status_t parse_amr(codec_private_t *codec_data, void *pkt,
288 pj_size_t pkt_size, const pj_timestamp *ts,
289 unsigned *frame_cnt, pjmedia_frame frames[])
290{
291 amr_settings_t* s = (amr_settings_t*)codec_data->codec_setting;
292 pjmedia_codec_amr_pack_setting *setting;
293 pj_status_t status;
294 pj_uint8_t cmr;
295
296 setting = &s->dec_setting;
297
298 status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, setting, frames,
299 frame_cnt, &cmr);
300 if (status != PJ_SUCCESS)
301 return status;
302
303 // CMR is not supported for now.
304 /* Check Change Mode Request. */
305 //if ((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) {
306 // s->enc_mode = cmr;
307 //}
308
309 return PJ_SUCCESS;
310}
311
312#endif /* PJMEDIA_HAS_PASSTROUGH_CODEC_AMR */
313
314
315/*
316 * Initialize and register passthrough codec factory to pjmedia endpoint.
317 */
318PJ_DEF(pj_status_t) pjmedia_codec_passthrough_init( pjmedia_endpt *endpt )
319{
320 pjmedia_codec_mgr *codec_mgr;
321 pj_str_t codec_name;
322 pj_status_t status;
323
324 if (codec_factory.pool != NULL) {
325 /* Already initialized. */
326 return PJ_EEXISTS;
327 }
328
329 /* Create passthrough codec factory. */
330 codec_factory.base.op = &codec_factory_op;
331 codec_factory.base.factory_data = NULL;
332 codec_factory.endpt = endpt;
333
334 codec_factory.pool = pjmedia_endpt_create_pool(endpt, "Passthrough codecs",
335 4000, 4000);
336 if (!codec_factory.pool)
337 return PJ_ENOMEM;
338
339 /* Create mutex. */
340 status = pj_mutex_create_simple(codec_factory.pool, "Passthrough codecs",
341 &codec_factory.mutex);
342 if (status != PJ_SUCCESS)
343 goto on_error;
344
345 /* Get the codec manager. */
346 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
347 if (!codec_mgr) {
348 status = PJ_EINVALIDOP;
349 goto on_error;
350 }
351
352 /* Register format match callback. */
353#if PJMEDIA_HAS_PASSTROUGH_CODEC_AMR
354 pj_cstr(&codec_name, "AMR");
355 status = pjmedia_sdp_neg_register_fmt_match_cb(
356 &codec_name,
357 &pjmedia_codec_amr_match_sdp);
358 if (status != PJ_SUCCESS)
359 goto on_error;
360#endif
361
362 /* Suppress compile warning */
363 PJ_UNUSED_ARG(codec_name);
364
365 /* Register codec factory to endpoint. */
366 status = pjmedia_codec_mgr_register_factory(codec_mgr,
367 &codec_factory.base);
368 if (status != PJ_SUCCESS)
369 goto on_error;
370
371 /* Done. */
372 return PJ_SUCCESS;
373
374on_error:
375 pj_pool_release(codec_factory.pool);
376 codec_factory.pool = NULL;
377 return status;
378}
379
380/*
381 * Initialize and register passthrough codec factory to pjmedia endpoint.
382 */
383PJ_DEF(pj_status_t) pjmedia_codec_passthrough_init2(
384 pjmedia_endpt *endpt,
385 const pjmedia_codec_passthrough_setting *setting)
386{
387 if (codec_factory.pool != NULL) {
388 /* Already initialized. */
389 return PJ_EEXISTS;
390 }
391
392 if (setting != NULL) {
393 unsigned i;
394
395 /* Enable/disable codecs based on the specified encoding formats */
396 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
397 pj_bool_t enabled = PJ_FALSE;
398 unsigned j;
399
400 for (j = 0; j < setting->fmt_cnt && !enabled; ++j) {
401 if ((pj_uint32_t)codec_desc[i].fmt_id == setting->fmts[j].id)
402 enabled = PJ_TRUE;
403 }
404
405 codec_desc[i].enabled = enabled;
406 }
407
408#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
409 /* Update iLBC codec description based on default mode setting. */
410 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
411 if (codec_desc[i].enabled &&
412 codec_desc[i].fmt_id == PJMEDIA_FORMAT_ILBC)
413 {
414 codec_desc[i].samples_per_frame =
415 (setting->ilbc_mode == 20? 160 : 240);
416 codec_desc[i].def_bitrate =
417 (setting->ilbc_mode == 20? 15200 : 13333);
418 pj_strset2(&codec_desc[i].dec_fmtp.param[0].val,
419 (setting->ilbc_mode == 20? "20" : "30"));
420 break;
421 }
422 }
423#endif
424 }
425
426 return pjmedia_codec_passthrough_init(endpt);
427}
428
429/*
430 * Unregister passthrough codecs factory from pjmedia endpoint.
431 */
432PJ_DEF(pj_status_t) pjmedia_codec_passthrough_deinit(void)
433{
434 pjmedia_codec_mgr *codec_mgr;
435 unsigned i;
436 pj_status_t status;
437
438 if (codec_factory.pool == NULL) {
439 /* Already deinitialized */
440 return PJ_SUCCESS;
441 }
442
443 pj_mutex_lock(codec_factory.mutex);
444
445 /* Get the codec manager. */
446 codec_mgr = pjmedia_endpt_get_codec_mgr(codec_factory.endpt);
447 if (!codec_mgr) {
448 pj_pool_release(codec_factory.pool);
449 codec_factory.pool = NULL;
450 return PJ_EINVALIDOP;
451 }
452
453 /* Unregister passthrough codecs factory. */
454 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
455 &codec_factory.base);
456
457 /* Destroy mutex. */
458 pj_mutex_destroy(codec_factory.mutex);
459
460 /* Destroy pool. */
461 pj_pool_release(codec_factory.pool);
462 codec_factory.pool = NULL;
463
464 /* Re-enable all codecs in the codec_desc. */
465 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
466 codec_desc[i].enabled = PJ_TRUE;
467 }
468
469 return status;
470}
471
472/*
473 * Check if factory can allocate the specified codec.
474 */
475static pj_status_t test_alloc( pjmedia_codec_factory *factory,
476 const pjmedia_codec_info *info )
477{
478 unsigned i;
479
480 PJ_UNUSED_ARG(factory);
481
482 /* Type MUST be audio. */
483 if (info->type != PJMEDIA_TYPE_AUDIO)
484 return PJMEDIA_CODEC_EUNSUP;
485
486 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
487 pj_str_t name = pj_str((char*)codec_desc[i].name);
488 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
489 (info->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
490 (info->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
491 (codec_desc[i].enabled))
492 {
493 return PJ_SUCCESS;
494 }
495 }
496
497 /* Unsupported, or mode is disabled. */
498 return PJMEDIA_CODEC_EUNSUP;
499}
500
501/*
502 * Generate default attribute.
503 */
504static pj_status_t default_attr ( pjmedia_codec_factory *factory,
505 const pjmedia_codec_info *id,
506 pjmedia_codec_param *attr )
507{
508 unsigned i;
509
510 PJ_ASSERT_RETURN(factory==&codec_factory.base, PJ_EINVAL);
511
512 pj_bzero(attr, sizeof(pjmedia_codec_param));
513
514 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
515 pj_str_t name = pj_str((char*)codec_desc[i].name);
516 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
517 (id->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
518 (id->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
519 (id->pt == (unsigned)codec_desc[i].pt))
520 {
521 attr->info.pt = (pj_uint8_t)id->pt;
522 attr->info.channel_cnt = codec_desc[i].channel_count;
523 attr->info.clock_rate = codec_desc[i].clock_rate;
524 attr->info.avg_bps = codec_desc[i].def_bitrate;
525 attr->info.max_bps = codec_desc[i].max_bitrate;
526 attr->info.pcm_bits_per_sample = 16;
527 attr->info.frm_ptime = (pj_uint16_t)
528 (codec_desc[i].samples_per_frame * 1000 /
529 codec_desc[i].channel_count /
530 codec_desc[i].clock_rate);
531 attr->info.fmt_id = codec_desc[i].fmt_id;
532
533 /* Default flags. */
534 attr->setting.frm_per_pkt = codec_desc[i].frm_per_pkt;
535 attr->setting.plc = codec_desc[i].plc;
536 attr->setting.penh= 0;
537 attr->setting.vad = codec_desc[i].vad;
538 attr->setting.cng = attr->setting.vad;
539 attr->setting.dec_fmtp = codec_desc[i].dec_fmtp;
540
541 if (attr->setting.vad == 0) {
542#if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
543 if (id->pt == PJMEDIA_RTP_PT_G729) {
544 /* Signal G729 Annex B is being disabled */
545 attr->setting.dec_fmtp.cnt = 1;
546 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
547 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
548 }
549#endif
550 }
551
552 return PJ_SUCCESS;
553 }
554 }
555
556 return PJMEDIA_CODEC_EUNSUP;
557}
558
559/*
560 * Enum codecs supported by this factory.
561 */
562static pj_status_t enum_codecs( pjmedia_codec_factory *factory,
563 unsigned *count,
564 pjmedia_codec_info codecs[])
565{
566 unsigned max;
567 unsigned i;
568
569 PJ_UNUSED_ARG(factory);
570 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
571
572 max = *count;
573
574 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(codec_desc) && *count < max; ++i)
575 {
576 if (!codec_desc[i].enabled)
577 continue;
578
579 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
580 codecs[*count].encoding_name = pj_str((char*)codec_desc[i].name);
581 codecs[*count].pt = codec_desc[i].pt;
582 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
583 codecs[*count].clock_rate = codec_desc[i].clock_rate;
584 codecs[*count].channel_cnt = codec_desc[i].channel_count;
585
586 ++*count;
587 }
588
589 return PJ_SUCCESS;
590}
591
592/*
593 * Allocate a new codec instance.
594 */
595static pj_status_t alloc_codec( pjmedia_codec_factory *factory,
596 const pjmedia_codec_info *id,
597 pjmedia_codec **p_codec)
598{
599 codec_private_t *codec_data;
600 pjmedia_codec *codec;
601 int idx;
602 pj_pool_t *pool;
603 unsigned i;
604
605 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
606 PJ_ASSERT_RETURN(factory == &codec_factory.base, PJ_EINVAL);
607
608 pj_mutex_lock(codec_factory.mutex);
609
610 /* Find codec's index */
611 idx = -1;
612 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
613 pj_str_t name = pj_str((char*)codec_desc[i].name);
614 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
615 (id->clock_rate == (unsigned)codec_desc[i].clock_rate) &&
616 (id->channel_cnt == (unsigned)codec_desc[i].channel_count) &&
617 (codec_desc[i].enabled))
618 {
619 idx = i;
620 break;
621 }
622 }
623 if (idx == -1) {
624 *p_codec = NULL;
625 return PJMEDIA_CODEC_EUNSUP;
626 }
627
628 /* Create pool for codec instance */
629 pool = pjmedia_endpt_create_pool(codec_factory.endpt, "passthroughcodec",
630 512, 512);
631 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
632 codec->op = &codec_op;
633 codec->factory = factory;
634 codec->codec_data = PJ_POOL_ZALLOC_T(pool, codec_private_t);
635 codec_data = (codec_private_t*) codec->codec_data;
636 codec_data->pool = pool;
637 codec_data->codec_idx = idx;
638
639 pj_mutex_unlock(codec_factory.mutex);
640
641 *p_codec = codec;
642 return PJ_SUCCESS;
643}
644
645/*
646 * Free codec.
647 */
648static pj_status_t dealloc_codec( pjmedia_codec_factory *factory,
649 pjmedia_codec *codec )
650{
651 codec_private_t *codec_data;
652
653 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
654 PJ_ASSERT_RETURN(factory == &codec_factory.base, PJ_EINVAL);
655
656 /* Close codec, if it's not closed. */
657 codec_data = (codec_private_t*) codec->codec_data;
658 codec_close(codec);
659
660 pj_pool_release(codec_data->pool);
661
662 return PJ_SUCCESS;
663}
664
665/*
666 * Init codec.
667 */
668static pj_status_t codec_init( pjmedia_codec *codec,
669 pj_pool_t *pool )
670{
671 PJ_UNUSED_ARG(codec);
672 PJ_UNUSED_ARG(pool);
673 return PJ_SUCCESS;
674}
675
676/*
677 * Open codec.
678 */
679static pj_status_t codec_open( pjmedia_codec *codec,
680 pjmedia_codec_param *attr )
681{
682 codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
683 struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
684 pj_pool_t *pool;
685 int i, j;
686
687 pool = codec_data->pool;
688
689 /* Cache samples per frame value */
690 codec_data->samples_per_frame = desc->samples_per_frame;
691
692 /* Calculate bitstream size */
693 i = attr->info.avg_bps * codec_data->samples_per_frame;
694 j = desc->clock_rate << 3;
695 codec_data->avg_frame_size = (pj_uint16_t)(i / j);
696 if (i % j) ++codec_data->avg_frame_size;
697
698#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
699 /* Init AMR settings */
700 if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) {
701 amr_settings_t *s;
702 pj_uint8_t octet_align = 0;
703 pj_int8_t enc_mode;
704
705 enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
706 pj_assert(enc_mode >= 0 && enc_mode <= 8);
707
708 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
709 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
710
711 /* Fetch octet-align setting. It should be fine to fetch only
712 * the decoder, since encoder & decoder must use the same setting
713 * (RFC 4867 section 8.3.1).
714 */
715 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
716 &STR_FMTP_OCTET_ALIGN) == 0)
717 {
718 octet_align=(pj_uint8_t)
719 (pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
720 break;
721 }
722 }
723
724 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
725 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
726
727 /* mode-set, encoding mode is chosen based on local default mode
728 * setting:
729 * - if local default mode is included in the mode-set, use it
730 * - otherwise, find the closest mode to local default mode;
731 * if there are two closest modes, prefer to use the higher
732 * one, e.g: local default mode is 4, the mode-set param
733 * contains '2,3,5,6', then 5 will be chosen.
734 */
735 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
736 &STR_FMTP_MODE_SET) == 0)
737 {
738 const char *p;
739 pj_size_t l;
740 pj_int8_t diff = 99;
741
742 p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
743 l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
744
745 while (l--) {
746 if ((desc->pt==PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') ||
747 (desc->pt==PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8'))
748 {
749 pj_int8_t tmp = (pj_int8_t)(*p - '0' - enc_mode);
750
751 if (PJ_ABS(diff) > PJ_ABS(tmp) ||
752 (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
753 {
754 diff = tmp;
755 if (diff == 0) break;
756 }
757 }
758 ++p;
759 }
760
761 if (diff == 99)
762 return PJMEDIA_CODEC_EFAILED;
763
764 enc_mode = (pj_int8_t)(enc_mode + diff);
765
766 break;
767 }
768 }
769
770 s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
771 codec_data->codec_setting = s;
772
773 s->enc_mode = enc_mode;
774 if (s->enc_mode < 0)
775 return PJMEDIA_CODEC_EINMODE;
776
777 s->enc_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
778 s->enc_setting.octet_aligned = octet_align;
779 s->enc_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
780 doesn't do sensitivity bits
781 reordering */
782 s->enc_setting.cmr = 15;
783
784 s->dec_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
785 s->dec_setting.octet_aligned = octet_align;
786 s->dec_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
787 doesn't do sensitivity bits
788 reordering */
789
790 /* Return back bitrate info to application */
791 attr->info.avg_bps = s->enc_setting.amr_nb?
792 pjmedia_codec_amrnb_bitrates[s->enc_mode]:
793 pjmedia_codec_amrwb_bitrates[s->enc_mode];
794 }
795#endif
796
797#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
798 /* Init iLBC settings */
799 if (desc->pt == PJMEDIA_RTP_PT_ILBC)
800 {
801 enum { DEFAULT_MODE = 30 };
802 static pj_str_t STR_MODE = {"mode", 4};
803 pj_uint16_t dec_fmtp_mode = DEFAULT_MODE,
804 enc_fmtp_mode = DEFAULT_MODE;
805
806 /* Get decoder mode */
807 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
808 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
809 {
810 dec_fmtp_mode = (pj_uint16_t)
811 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
812 break;
813 }
814 }
815
816 /* Decoder mode must be set */
817 PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30,
818 PJMEDIA_CODEC_EINMODE);
819
820 /* Get encoder mode */
821 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
822 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
823 {
824 enc_fmtp_mode = (pj_uint16_t)
825 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
826 break;
827 }
828 }
829
830 PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30,
831 PJMEDIA_CODEC_EINMODE);
832
833 /* Both sides of a bi-directional session MUST use the same "mode" value.
834 * In this point, possible values are only 20 or 30, so when encoder and
835 * decoder modes are not same, just use the default mode, it is 30.
836 */
837 if (enc_fmtp_mode != dec_fmtp_mode) {
838 enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
839 PJ_LOG(4,(pool->obj_name,
840 "Normalized iLBC encoder and decoder modes to %d",
841 DEFAULT_MODE));
842 }
843
844 /* Update some attributes based on negotiated mode. */
845 attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
846 attr->info.frm_ptime = dec_fmtp_mode;
847
848 /* Override average frame size */
849 codec_data->avg_frame_size = (dec_fmtp_mode == 30? 50 : 38);
850
851 /* Override samples per frame */
852 codec_data->samples_per_frame = (dec_fmtp_mode == 30? 240 : 160);
853 }
854#endif
855
856 return PJ_SUCCESS;
857}
858
859/*
860 * Close codec.
861 */
862static pj_status_t codec_close( pjmedia_codec *codec )
863{
864 PJ_UNUSED_ARG(codec);
865
866 return PJ_SUCCESS;
867}
868
869
870/*
871 * Modify codec settings.
872 */
873static pj_status_t codec_modify( pjmedia_codec *codec,
874 const pjmedia_codec_param *attr )
875{
876 /* Not supported yet. */
877 PJ_UNUSED_ARG(codec);
878 PJ_UNUSED_ARG(attr);
879
880 return PJ_ENOTSUP;
881}
882
883/*
884 * Get frames in the packet.
885 */
886static pj_status_t codec_parse( pjmedia_codec *codec,
887 void *pkt,
888 pj_size_t pkt_size,
889 const pj_timestamp *ts,
890 unsigned *frame_cnt,
891 pjmedia_frame frames[])
892{
893 codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
894 struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
895 unsigned count = 0;
896
897 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
898
899 if (desc->parse != NULL) {
900 return desc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
901 }
902
903 while (pkt_size >= codec_data->avg_frame_size && count < *frame_cnt) {
904 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
905 frames[count].buf = pkt;
906 frames[count].size = codec_data->avg_frame_size;
907 frames[count].timestamp.u64 = ts->u64 +
908 count * codec_data->samples_per_frame;
909
910 pkt = (pj_uint8_t*)pkt + codec_data->avg_frame_size;
911 pkt_size -= codec_data->avg_frame_size;
912
913 ++count;
914 }
915
916 if (pkt_size && count < *frame_cnt) {
917 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
918 frames[count].buf = pkt;
919 frames[count].size = pkt_size;
920 frames[count].timestamp.u64 = ts->u64 +
921 count * codec_data->samples_per_frame;
922 ++count;
923 }
924
925 *frame_cnt = count;
926 return PJ_SUCCESS;
927}
928
929/*
930 * Encode frames.
931 */
932static pj_status_t codec_encode( pjmedia_codec *codec,
933 const struct pjmedia_frame *input,
934 unsigned output_buf_len,
935 struct pjmedia_frame *output)
936{
937 codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
938 struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
939 const pjmedia_frame_ext *input_ = (const pjmedia_frame_ext*) input;
940
941 pj_assert(input && input->type == PJMEDIA_FRAME_TYPE_EXTENDED);
942
943 if (desc->pack != NULL) {
944 desc->pack(codec_data, input_, output_buf_len, output);
945 } else {
946 if (input_->subframe_cnt == 0) {
947 /* DTX */
948 output->buf = NULL;
949 output->size = 0;
950 output->type = PJMEDIA_FRAME_TYPE_NONE;
951 } else {
952 unsigned i;
953 pj_uint8_t *p = output->buf;
954
955 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
956 output->size = 0;
957
958 for (i = 0; i < input_->subframe_cnt; ++i) {
959 pjmedia_frame_ext_subframe *sf;
960 unsigned sf_len;
961
962 sf = pjmedia_frame_ext_get_subframe(input_, i);
963 pj_assert(sf);
964
965 sf_len = (sf->bitlen + 7) >> 3;
966
967 pj_memcpy(p, sf->data, sf_len);
968 p += sf_len;
969 output->size += sf_len;
970
971 /* If there is SID or DTX frame, break the loop. */
972 if (desc->pt == PJMEDIA_RTP_PT_G729 &&
973 sf_len < codec_data->avg_frame_size)
974 {
975 break;
976 }
977
978 }
979 }
980 }
981
982 output->timestamp = input->timestamp;
983
984 return PJ_SUCCESS;
985}
986
987/*
988 * Decode frame.
989 */
990static pj_status_t codec_decode( pjmedia_codec *codec,
991 const struct pjmedia_frame *input,
992 unsigned output_buf_len,
993 struct pjmedia_frame *output)
994{
995 codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
996#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
997 struct codec_desc *desc = &codec_desc[codec_data->codec_idx];
998#endif
999 pjmedia_frame_ext *output_ = (pjmedia_frame_ext*) output;
1000
1001 pj_assert(input);
1002 PJ_UNUSED_ARG(output_buf_len);
1003
1004#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
1005 /* Need to rearrange the AMR bitstream, since the bitstream may not be
1006 * started from bit 0 or may need to be reordered from sensitivity order
1007 * into encoder bits order.
1008 */
1009 if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) {
1010 pjmedia_frame input_;
1011 pjmedia_codec_amr_pack_setting *setting;
1012
1013 setting = &((amr_settings_t*)codec_data->codec_setting)->dec_setting;
1014
1015 input_ = *input;
1016 pjmedia_codec_amr_predecode(input, setting, &input_);
1017
1018 pjmedia_frame_ext_append_subframe(output_, input_.buf,
1019 (pj_uint16_t)(input_.size << 3),
1020 (pj_uint16_t)codec_data->samples_per_frame);
1021 output->timestamp = input->timestamp;
1022
1023 return PJ_SUCCESS;
1024 }
1025#endif
1026
1027 pjmedia_frame_ext_append_subframe(output_, input->buf,
1028 (pj_uint16_t)(input->size << 3),
1029 (pj_uint16_t)codec_data->samples_per_frame);
1030 output->timestamp = input->timestamp;
1031
1032 return PJ_SUCCESS;
1033}
1034
1035/*
1036 * Recover lost frame.
1037 */
1038static pj_status_t codec_recover( pjmedia_codec *codec,
1039 unsigned output_buf_len,
1040 struct pjmedia_frame *output)
1041{
1042 codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
1043 pjmedia_frame_ext *output_ = (pjmedia_frame_ext*) output;
1044
1045 PJ_UNUSED_ARG(output_buf_len);
1046
1047 pjmedia_frame_ext_append_subframe(output_, NULL, 0,
1048 (pj_uint16_t)codec_data->samples_per_frame);
1049
1050 return PJ_SUCCESS;
1051}
1052
1053#endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */
1054