blob: 57e42c5fca678d2a8b729c0eb07a708c501f3f1c [file] [log] [blame]
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2008 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/ipp_codecs.h>
20#include <pjmedia/codec.h>
21#include <pjmedia/errno.h>
22#include <pjmedia/endpoint.h>
23#include <pjmedia/plc.h>
24#include <pjmedia/port.h>
25#include <pjmedia/silencedet.h>
26#include <pj/assert.h>
27#include <pj/log.h>
28#include <pj/pool.h>
29#include <pj/string.h>
30#include <pj/os.h>
31
Nanang Izzuddin23a00b72008-08-25 13:58:25 +000032
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000033/*
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000034 * Only build this file if PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000035 */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000036#if defined(PJMEDIA_HAS_INTEL_IPP) && PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000037
38#include <usc.h>
39
40#define THIS_FILE "ipp_codecs.c"
41
42/* Prototypes for IPP codecs factory */
43static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
44 const pjmedia_codec_info *id );
45static pj_status_t ipp_default_attr( pjmedia_codec_factory *factory,
46 const pjmedia_codec_info *id,
47 pjmedia_codec_param *attr );
48static pj_status_t ipp_enum_codecs( pjmedia_codec_factory *factory,
49 unsigned *count,
50 pjmedia_codec_info codecs[]);
51static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
52 const pjmedia_codec_info *id,
53 pjmedia_codec **p_codec);
54static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
55 pjmedia_codec *codec );
56
57/* Prototypes for IPP codecs implementation. */
58static pj_status_t ipp_codec_init( pjmedia_codec *codec,
59 pj_pool_t *pool );
60static pj_status_t ipp_codec_open( pjmedia_codec *codec,
61 pjmedia_codec_param *attr );
62static pj_status_t ipp_codec_close( pjmedia_codec *codec );
63static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
64 const pjmedia_codec_param *attr );
65static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
66 void *pkt,
67 pj_size_t pkt_size,
68 const pj_timestamp *ts,
69 unsigned *frame_cnt,
70 pjmedia_frame frames[]);
71static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
72 const struct pjmedia_frame *input,
73 unsigned output_buf_len,
74 struct pjmedia_frame *output);
75static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
76 const struct pjmedia_frame *input,
77 unsigned output_buf_len,
78 struct pjmedia_frame *output);
79static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
80 unsigned output_buf_len,
81 struct pjmedia_frame *output);
82
83/* Definition for IPP codecs operations. */
84static pjmedia_codec_op ipp_op =
85{
86 &ipp_codec_init,
87 &ipp_codec_open,
88 &ipp_codec_close,
89 &ipp_codec_modify,
90 &ipp_codec_parse,
91 &ipp_codec_encode,
92 &ipp_codec_decode,
93 &ipp_codec_recover
94};
95
96/* Definition for IPP codecs factory operations. */
97static pjmedia_codec_factory_op ipp_factory_op =
98{
99 &ipp_test_alloc,
100 &ipp_default_attr,
101 &ipp_enum_codecs,
102 &ipp_alloc_codec,
103 &ipp_dealloc_codec
104};
105
106/* IPP codecs factory */
107static struct ipp_factory {
108 pjmedia_codec_factory base;
109 pjmedia_endpt *endpt;
110 pj_pool_t *pool;
111 pj_mutex_t *mutex;
112} ipp_factory;
113
114/* IPP codecs private data. */
115typedef struct ipp_private {
116 int codec_idx; /**< Codec index. */
117 pj_pool_t *pool; /**< Pool for each instance. */
118
119 USC_Handle enc; /**< Encoder state. */
120 USC_Handle dec; /**< Decoder state. */
121 USC_CodecInfo *info; /**< Native codec info. */
122 pj_uint16_t frame_size; /**< Bitstream frame size. */
123
124 pj_bool_t plc_enabled;
125 pjmedia_plc *plc;
126
127 pj_bool_t vad_enabled;
128 pjmedia_silence_det *vad;
129 pj_timestamp last_tx;
130} ipp_private_t;
131
132
133/* USC codec implementations. */
134extern USC_Fxns USC_G729AFP_Fxns;
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000135extern USC_Fxns USC_G729I_Fxns;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000136extern USC_Fxns USC_G723_Fxns;
137extern USC_Fxns USC_G726_Fxns;
138extern USC_Fxns USC_G728_Fxns;
139extern USC_Fxns USC_G722_Fxns;
140extern USC_Fxns USC_GSMAMR_Fxns;
141extern USC_Fxns USC_AMRWB_Fxns;
142extern USC_Fxns USC_AMRWBE_Fxns;
143
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000144
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000145/* CUSTOM CALLBACKS */
146
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000147/* This callback is useful for translating RTP frame into USC frame, e.g:
148 * reassigning frame attributes, reorder bitstream. Default behaviour of
149 * the translation is just setting the USC frame buffer & its size as
150 * specified in RTP frame, setting USC frame frametype to 0, setting bitrate
151 * of USC frame to bitrate info of codec_data. Implement this callback when
152 * the default behaviour is unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000153 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000154typedef void (*predecode_cb)(ipp_private_t *codec_data,
155 const pjmedia_frame *rtp_frame,
156 USC_Bitstream *usc_frame);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000157
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000158/* Parse frames from a packet. Default behaviour of frame parsing is
159 * just separating frames based on calculating frame length derived
160 * from bitrate. Implement this callback when the default behaviour is
161 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000162 */
163typedef pj_status_t (*parse_cb)(ipp_private_t *codec_data, void *pkt,
164 pj_size_t pkt_size, const pj_timestamp *ts,
165 unsigned *frame_cnt, pjmedia_frame frames[]);
166
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000167/* Pack frames into a packet. Default behaviour of packing frames is
168 * just stacking the frames with octet aligned without adding any
169 * payload header. Implement this callback when the default behaviour is
170 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000171 */
172typedef pj_status_t (*pack_cb)(ipp_private_t *codec_data, void *pkt,
173 pj_size_t *pkt_size, pj_size_t max_pkt_size);
174
175
176
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000177/* Custom callback implementations. */
178static void predecode_g723( ipp_private_t *codec_data,
179 const pjmedia_frame *rtp_frame,
180 USC_Bitstream *usc_frame);
181static pj_status_t parse_g723( ipp_private_t *codec_data, void *pkt,
182 pj_size_t pkt_size, const pj_timestamp *ts,
183 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000184
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000185static void predecode_g729( ipp_private_t *codec_data,
186 const pjmedia_frame *rtp_frame,
187 USC_Bitstream *usc_frame);
188
189static void predecode_amr( ipp_private_t *codec_data,
190 const pjmedia_frame *rtp_frame,
191 USC_Bitstream *usc_frame);
192static pj_status_t parse_amr( ipp_private_t *codec_data, void *pkt,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000193 pj_size_t pkt_size, const pj_timestamp *ts,
194 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000195static pj_status_t pack_amr( ipp_private_t *codec_data, void *pkt,
196 pj_size_t *pkt_size, pj_size_t max_pkt_size);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000197
198
199/* IPP codec implementation descriptions. */
200static struct ipp_codec {
201 int enabled; /* Is this codec enabled? */
202 const char *name; /* Codec name. */
203 pj_uint8_t pt; /* Payload type. */
204 USC_Fxns *fxns; /* USC callback functions. */
205 unsigned clock_rate; /* Codec's clock rate. */
206 unsigned channel_count; /* Codec's channel count. */
207 unsigned samples_per_frame; /* Codec's samples count. */
208
209 unsigned def_bitrate; /* Default bitrate of this codec. */
210 unsigned max_bitrate; /* Maximum bitrate of this codec. */
211 pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/
212 int has_native_vad; /* Codec has internal VAD? */
213 int has_native_plc; /* Codec has internal PLC? */
214
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000215 predecode_cb predecode; /* Callback to translate RTP frame
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000216 into USC frame. */
217 parse_cb parse; /* Callback to parse bitstream. */
218 pack_cb pack; /* Callback to pack bitstream. */
219
220 pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
221}
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000222
223ipp_codec[] =
224{
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000225# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000226 {1, "AMR", PJMEDIA_RTP_PT_AMR, &USC_GSMAMR_Fxns, 8000, 1, 160,
227 5900, 12200, 4, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000228 &predecode_amr, &parse_amr, &pack_amr
229 },
230# endif
231
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000232# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMRWB
233 {1, "AMR-WB", PJMEDIA_RTP_PT_AMRWB, &USC_AMRWB_Fxns, 16000, 1, 320,
234 15850, 23850, 1, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000235 &predecode_amr, &parse_amr, &pack_amr
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000236 },
237# endif
238
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000239# if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000240# if defined(PJ_HAS_FLOATING_POINT) && (PJ_HAS_FLOATING_POINT != 0)
241 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729AFP_Fxns, 8000, 1, 80,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000242 8000, 11800, 2, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000243 &predecode_g729, NULL, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000244 },
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000245# else
246 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729I_Fxns, 8000, 1, 80,
247 8000, 11800, 2, 1, 1,
248 &predecode_g729, NULL, NULL
249 },
250# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000251# endif
252
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000253# if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000254 /* This is actually G.723.1 */
255 {1, "G723", PJMEDIA_RTP_PT_G723, &USC_G723_Fxns, 8000, 1, 240,
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000256 6300, 6300, 1, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000257 &predecode_g723, &parse_g723, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000258 },
259# endif
260
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000261# if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000262 {0, "G726-16", PJMEDIA_RTP_PT_G726_16, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000263 16000, 16000, 2, 0, 0,
264 NULL, NULL, NULL
265 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000266 {0, "G726-24", PJMEDIA_RTP_PT_G726_24, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000267 24000, 24000, 2, 0, 0,
268 NULL, NULL, NULL
269 },
270 {1, "G726-32", PJMEDIA_RTP_PT_G726_32, &USC_G726_Fxns, 8000, 1, 80,
271 32000, 32000, 2, 0, 0,
272 NULL, NULL, NULL
273 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000274 {0, "G726-40", PJMEDIA_RTP_PT_G726_40, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000275 40000, 40000, 2, 0, 0,
276 NULL, NULL, NULL
277 },
278# endif
279
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000280# if PJMEDIA_HAS_INTEL_IPP_CODEC_G728
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000281 {1, "G728", PJMEDIA_RTP_PT_G728, &USC_G728_Fxns, 8000, 1, 80,
282 16000, 16000, 2, 0, 1,
283 NULL, NULL, NULL
284 },
285# endif
286
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000287# if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000288 {0, "G7221", PJMEDIA_RTP_PT_G722_1_16, &USC_G722_Fxns, 16000, 1, 320,
289 16000, 16000, 1, 0, 1,
290 NULL, NULL, NULL,
291 {1, {{{"bitrate", 7}, {"16000", 5}}} }
292 },
293 {1, "G7221", PJMEDIA_RTP_PT_G722_1_24, &USC_G722_Fxns, 16000, 1, 320,
294 24000, 24000, 1, 0, 1,
295 NULL, NULL, NULL,
296 {1, {{{"bitrate", 7}, {"24000", 5}}} }
297 },
298 {1, "G7221", PJMEDIA_RTP_PT_G722_1_32, &USC_G722_Fxns, 16000, 1, 320,
299 32000, 32000, 1, 0, 1,
300 NULL, NULL, NULL,
301 {1, {{{"bitrate", 7}, {"32000", 5}}} }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000302 },
303# endif
304};
305
306
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000307#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
308
309static void predecode_g729( ipp_private_t *codec_data,
310 const pjmedia_frame *rtp_frame,
311 USC_Bitstream *usc_frame)
312{
313 switch (rtp_frame->size) {
314 case 2:
315 /* SID */
316 usc_frame->frametype = 1;
317 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
318 break;
319 case 8:
320 /* G729D */
321 usc_frame->frametype = 2;
322 usc_frame->bitrate = 6400;
323 break;
324 case 10:
325 /* G729 */
326 usc_frame->frametype = 3;
327 usc_frame->bitrate = 8000;
328 break;
329 case 15:
330 /* G729E */
331 usc_frame->frametype = 4;
332 usc_frame->bitrate = 11800;
333 break;
334 default:
335 usc_frame->frametype = 0;
336 usc_frame->bitrate = 0;
337 break;
338 }
339
340 usc_frame->pBuffer = rtp_frame->buf;
341 usc_frame->nbytes = rtp_frame->size;
342}
343
344#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G729 */
345
346
347#if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
348
349static void predecode_g723( ipp_private_t *codec_data,
350 const pjmedia_frame *rtp_frame,
351 USC_Bitstream *usc_frame)
352{
353 int i, HDR = 0;
354 pj_uint8_t *f = (pj_uint8_t*)rtp_frame->buf;
355
356 PJ_UNUSED_ARG(codec_data);
357
358 for (i = 0; i < 2; ++i){
359 int tmp;
360 tmp = (f[0] >> (i & 0x7)) & 1;
361 HDR += tmp << i ;
362 }
363
364 usc_frame->pBuffer = rtp_frame->buf;
365 usc_frame->nbytes = rtp_frame->size;
366 usc_frame->bitrate = HDR == 0? 6300 : 5300;
367 usc_frame->frametype = 0;
368}
369
370static pj_status_t parse_g723(ipp_private_t *codec_data, void *pkt,
371 pj_size_t pkt_size, const pj_timestamp *ts,
372 unsigned *frame_cnt, pjmedia_frame frames[])
373{
374 unsigned count = 0;
375 pj_uint8_t *f = (pj_uint8_t*)pkt;
376
377 while (pkt_size && count < *frame_cnt) {
378 int framesize, i, j;
379 int HDR = 0;
380
381 for (i = 0; i < 2; ++i){
382 j = (f[0] >> (i & 0x7)) & 1;
383 HDR += j << i ;
384 }
385
386 if (HDR == 0)
387 framesize = 24;
388 else if (HDR == 1)
389 framesize = 20;
390 else if (HDR == 2)
391 framesize = 4;
392 else if (HDR == 3)
393 framesize = 1;
394 else {
395 pj_assert(!"Unknown G723.1 frametype, packet may be corrupted!");
396 return PJMEDIA_CODEC_EINMODE;
397 }
398
399 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
400 frames[count].buf = f;
401 frames[count].size = framesize;
402 frames[count].timestamp.u64 = ts->u64 + count *
403 ipp_codec[codec_data->codec_idx].samples_per_frame;
404
405 f += framesize;
406 pkt_size -= framesize;
407
408 ++count;
409 }
410
411 *frame_cnt = count;
412 return PJ_SUCCESS;
413}
414
415#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1 */
416
417
418#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
419
420#include <pjmedia-codec/amr_helper.h>
421
422/* Rearrange AMR bitstream and convert RTP frame into USC frame:
423 * - make the start_bit to be 0
424 * - if it is speech frame, reorder bitstream from sensitivity bits order
425 * to encoder bits order.
426 * - set the appropriate value of usc_frame.
427 */
428static void predecode_amr( ipp_private_t *codec_data,
429 const pjmedia_frame *rtp_frame,
430 USC_Bitstream *usc_frame)
431{
432 pjmedia_frame frame;
433 pjmedia_codec_amr_bit_info *info;
434 pj_bool_t amr_nb;
435
436 amr_nb = (ipp_codec[codec_data->codec_idx].pt == PJMEDIA_RTP_PT_AMR);
437 frame = *rtp_frame;
438 pjmedia_codec_amr_reorder_sens_to_enc(amr_nb, rtp_frame, &frame);
439 info = (pjmedia_codec_amr_bit_info*) &frame.bit_info;
440
441 usc_frame->pBuffer = frame.buf;
442 usc_frame->nbytes = frame.size;
443 if (info->mode != -1) {
444 usc_frame->bitrate = amr_nb?
445 pjmedia_codec_amrnb_bitrates[info->mode]:
446 pjmedia_codec_amrwb_bitrates[info->mode];
447 } else {
448 usc_frame->bitrate = 0;
449 }
450
451 if (frame.size > 5) {
452 /* Speech */
453 if (info->good_quality)
454 usc_frame->frametype = 0;
455 else
456 usc_frame->frametype = amr_nb ? 5 : 6;
457 } else if (frame.size == 5) {
458 /* SID */
459 if (info->good_quality) {
460 pj_bool_t STI;
461 STI = (((pj_uint8_t*)frame.buf)[35 >> 3] & 0x10) != 0;
462 usc_frame->frametype = STI? 2 : 1;
463 } else {
464 usc_frame->frametype = amr_nb ? 6 : 7;
465 }
466 } else {
467 /* no data */
468 usc_frame->frametype = 3;
469 }
470}
471
472/* Pack AMR payload */
473static pj_status_t pack_amr(ipp_private_t *codec_data, void *pkt,
474 pj_size_t *pkt_size, pj_size_t max_pkt_size)
475{
476 enum {MAX_FRAMES_PER_PACKET = 16};
477
478 pjmedia_codec_amr_settings setting;
479 pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
480 unsigned nframes = 0;
481 pjmedia_codec_amr_bit_info *info;
482 pj_uint8_t *r; /* Read cursor */
483 pj_uint8_t SID_FT;
484
485 setting.amr_nb = ipp_codec[codec_data->codec_idx].pt == PJMEDIA_RTP_PT_AMR;
486 setting.CMR = 15; /* not requesting any mode */
487 setting.octet_aligned = 0;
488
489 SID_FT = (pj_uint8_t)(setting.amr_nb? 8 : 9);
490
491 /* Align pkt buf right */
492 r = (pj_uint8_t*)pkt + max_pkt_size - *pkt_size;
493 pj_memmove(r, pkt, *pkt_size);
494
495 /* Get frames */
496 for (;;) {
497 pj_bool_t eof;
498 pj_uint16_t info_;
499
500 info_ = *((pj_uint16_t*)r);
501 eof = ((info_ & 0x40) != 0);
502
503 info = (pjmedia_codec_amr_bit_info*) &frames[nframes].bit_info;
504 pj_bzero(info, sizeof(*info));
505 info->frame_type = (pj_uint8_t)(info_ & 0x0F);
506 info->good_quality = (pj_uint8_t)((info_ & 0x80) == 0);
507 info->mode = (pj_int8_t) ((info_ >> 8) & 0x0F);
508
509 frames[nframes].buf = r + 2;
510 frames[nframes].size = info->frame_type <= SID_FT ?
511 pjmedia_codec_amrnb_framelen[info->frame_type] :
512 0;
513
514 r += frames[nframes].size + 2;
515
516 /* Last frame */
517 if (++nframes >= MAX_FRAMES_PER_PACKET || eof)
518 break;
519 }
520
521 /* Pack */
522 *pkt_size = max_pkt_size;
523 return pjmedia_codec_amr_pack(frames, nframes, &setting, pkt, pkt_size);
524}
525
526
527/* Parse AMR payload into frames. */
528static pj_status_t parse_amr(ipp_private_t *codec_data, void *pkt,
529 pj_size_t pkt_size, const pj_timestamp *ts,
530 unsigned *frame_cnt, pjmedia_frame frames[])
531{
532 pjmedia_codec_amr_settings setting;
533 pj_uint8_t CMR;
534
535 setting.amr_nb = ipp_codec[codec_data->codec_idx].pt == PJMEDIA_RTP_PT_AMR;
536 setting.octet_aligned = 0;
537
538 return pjmedia_codec_amr_parse(pkt, pkt_size, ts, &setting, frames,
539 frame_cnt, &CMR);
540}
541
542#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_AMR */
543
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000544
545/*
546 * Initialize and register IPP codec factory to pjmedia endpoint.
547 */
548PJ_DEF(pj_status_t) pjmedia_codec_ipp_init( pjmedia_endpt *endpt )
549{
550 pjmedia_codec_mgr *codec_mgr;
551 pj_status_t status;
552
553 if (ipp_factory.pool != NULL) {
554 /* Already initialized. */
555 return PJ_SUCCESS;
556 }
557
558 /* Create IPP codec factory. */
559 ipp_factory.base.op = &ipp_factory_op;
560 ipp_factory.base.factory_data = NULL;
561 ipp_factory.endpt = endpt;
562
563 ipp_factory.pool = pjmedia_endpt_create_pool(endpt, "IPP codecs", 4000, 4000);
564 if (!ipp_factory.pool)
565 return PJ_ENOMEM;
566
567 /* Create mutex. */
568 status = pj_mutex_create_simple(ipp_factory.pool, "IPP codecs",
569 &ipp_factory.mutex);
570 if (status != PJ_SUCCESS)
571 goto on_error;
572
573 /* Get the codec manager. */
574 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
575 if (!codec_mgr) {
576 status = PJ_EINVALIDOP;
577 goto on_error;
578 }
579
580 /* Register codec factory to endpoint. */
581 status = pjmedia_codec_mgr_register_factory(codec_mgr,
582 &ipp_factory.base);
583 if (status != PJ_SUCCESS)
584 goto on_error;
585
586 /* Done. */
587 return PJ_SUCCESS;
588
589on_error:
590 pj_pool_release(ipp_factory.pool);
591 ipp_factory.pool = NULL;
592 return status;
593}
594
595/*
596 * Unregister IPP codecs factory from pjmedia endpoint.
597 */
598PJ_DEF(pj_status_t) pjmedia_codec_ipp_deinit(void)
599{
600 pjmedia_codec_mgr *codec_mgr;
601 pj_status_t status;
602
603 if (ipp_factory.pool == NULL) {
604 /* Already deinitialized */
605 return PJ_SUCCESS;
606 }
607
608 pj_mutex_lock(ipp_factory.mutex);
609
610 /* Get the codec manager. */
611 codec_mgr = pjmedia_endpt_get_codec_mgr(ipp_factory.endpt);
612 if (!codec_mgr) {
613 pj_pool_release(ipp_factory.pool);
614 ipp_factory.pool = NULL;
615 return PJ_EINVALIDOP;
616 }
617
618 /* Unregister IPP codecs factory. */
619 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
620 &ipp_factory.base);
621
622 /* Destroy mutex. */
623 pj_mutex_destroy(ipp_factory.mutex);
624
625 /* Destroy pool. */
626 pj_pool_release(ipp_factory.pool);
627 ipp_factory.pool = NULL;
628
629 return status;
630}
631
632/*
633 * Check if factory can allocate the specified codec.
634 */
635static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
636 const pjmedia_codec_info *info )
637{
638 unsigned i;
639
640 PJ_UNUSED_ARG(factory);
641
642 /* Type MUST be audio. */
643 if (info->type != PJMEDIA_TYPE_AUDIO)
644 return PJMEDIA_CODEC_EUNSUP;
645
646 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
647 pj_str_t name = pj_str((char*)ipp_codec[i].name);
648 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
649 (info->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
650 (info->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
651 (ipp_codec[i].enabled))
652 {
653 return PJ_SUCCESS;
654 }
655 }
656
657 /* Unsupported, or mode is disabled. */
658 return PJMEDIA_CODEC_EUNSUP;
659}
660
661/*
662 * Generate default attribute.
663 */
664static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
665 const pjmedia_codec_info *id,
666 pjmedia_codec_param *attr )
667{
668 unsigned i;
669
670 PJ_ASSERT_RETURN(factory==&ipp_factory.base, PJ_EINVAL);
671
672 pj_bzero(attr, sizeof(pjmedia_codec_param));
673
674 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
675 pj_str_t name = pj_str((char*)ipp_codec[i].name);
676 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
677 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000678 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
679 (id->pt == (unsigned)ipp_codec[i].pt))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000680 {
681 attr->info.pt = (pj_uint8_t)id->pt;
682 attr->info.channel_cnt = ipp_codec[i].channel_count;
683 attr->info.clock_rate = ipp_codec[i].clock_rate;
684 attr->info.avg_bps = ipp_codec[i].def_bitrate;
685 attr->info.max_bps = ipp_codec[i].max_bitrate;
686 attr->info.pcm_bits_per_sample = 16;
687 attr->info.frm_ptime = (pj_uint16_t)
688 (ipp_codec[i].samples_per_frame * 1000 /
689 ipp_codec[i].channel_count /
690 ipp_codec[i].clock_rate);
691 attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
692
693 /* Default flags. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000694 attr->setting.plc = 1;
695 attr->setting.penh= 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000696 attr->setting.vad = 1;
697 attr->setting.cng = attr->setting.vad;
698 attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
699
700 if (attr->setting.vad == 0) {
701#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
702 if (id->pt == PJMEDIA_RTP_PT_G729) {
703 /* Signal G729 Annex B is being disabled */
704 attr->setting.dec_fmtp.cnt = 1;
705 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
706 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
707 }
708#endif
709 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000710
711 return PJ_SUCCESS;
712 }
713 }
714
715 return PJMEDIA_CODEC_EUNSUP;
716}
717
718/*
719 * Enum codecs supported by this factory.
720 */
721static pj_status_t ipp_enum_codecs(pjmedia_codec_factory *factory,
722 unsigned *count,
723 pjmedia_codec_info codecs[])
724{
725 unsigned max;
726 unsigned i;
727
728 PJ_UNUSED_ARG(factory);
729 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
730
731 max = *count;
732
733 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(ipp_codec) && *count < max; ++i)
734 {
735 if (!ipp_codec[i].enabled)
736 continue;
737
738 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
739 codecs[*count].encoding_name = pj_str((char*)ipp_codec[i].name);
740 codecs[*count].pt = ipp_codec[i].pt;
741 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
742 codecs[*count].clock_rate = ipp_codec[i].clock_rate;
743 codecs[*count].channel_cnt = ipp_codec[i].channel_count;
744
745 ++*count;
746 }
747
748 return PJ_SUCCESS;
749}
750
751/*
752 * Allocate a new codec instance.
753 */
754static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
755 const pjmedia_codec_info *id,
756 pjmedia_codec **p_codec)
757{
758 ipp_private_t *codec_data;
759 pjmedia_codec *codec;
760 int idx;
761 pj_pool_t *pool;
762 unsigned i;
763
764 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
765 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
766
767 pj_mutex_lock(ipp_factory.mutex);
768
769 /* Find codec's index */
770 idx = -1;
771 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
772 pj_str_t name = pj_str((char*)ipp_codec[i].name);
773 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
774 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
775 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
776 (ipp_codec[i].enabled))
777 {
778 idx = i;
779 break;
780 }
781 }
782 if (idx == -1) {
783 *p_codec = NULL;
784 return PJMEDIA_CODEC_EFAILED;
785 }
786
787 /* Create pool for codec instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000788 pool = pjmedia_endpt_create_pool(ipp_factory.endpt, "IPPcodec", 512, 512);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000789 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
790 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
791 codec->op = &ipp_op;
792 codec->factory = factory;
793 codec->codec_data = PJ_POOL_ZALLOC_T(pool, ipp_private_t);
794 codec_data = (ipp_private_t*) codec->codec_data;
795
796 /* Create PLC if codec has no internal PLC */
797 if (!ipp_codec[idx].has_native_plc) {
798 pj_status_t status;
799 status = pjmedia_plc_create(pool, ipp_codec[idx].clock_rate,
800 ipp_codec[idx].samples_per_frame, 0,
801 &codec_data->plc);
802 if (status != PJ_SUCCESS) {
803 pj_pool_release(pool);
804 pj_mutex_unlock(ipp_factory.mutex);
805 return status;
806 }
807 }
808
809 /* Create silence detector if codec has no internal VAD */
810 if (!ipp_codec[idx].has_native_vad) {
811 pj_status_t status;
812 status = pjmedia_silence_det_create(pool,
813 ipp_codec[idx].clock_rate,
814 ipp_codec[idx].samples_per_frame,
815 &codec_data->vad);
816 if (status != PJ_SUCCESS) {
817 pj_pool_release(pool);
818 pj_mutex_unlock(ipp_factory.mutex);
819 return status;
820 }
821 }
822
823 codec_data->pool = pool;
824 codec_data->codec_idx = idx;
825
826 pj_mutex_unlock(ipp_factory.mutex);
827
828 *p_codec = codec;
829 return PJ_SUCCESS;
830}
831
832/*
833 * Free codec.
834 */
835static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
836 pjmedia_codec *codec )
837{
838 ipp_private_t *codec_data;
839
840 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
841 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
842
843 /* Close codec, if it's not closed. */
844 codec_data = (ipp_private_t*) codec->codec_data;
845 if (codec_data->enc != NULL || codec_data->dec != NULL) {
846 ipp_codec_close(codec);
847 }
848
849 pj_pool_release(codec_data->pool);
850
851 return PJ_SUCCESS;
852}
853
854/*
855 * Init codec.
856 */
857static pj_status_t ipp_codec_init( pjmedia_codec *codec,
858 pj_pool_t *pool )
859{
860 PJ_UNUSED_ARG(codec);
861 PJ_UNUSED_ARG(pool);
862 return PJ_SUCCESS;
863}
864
865/*
866 * Open codec.
867 */
868static pj_status_t ipp_codec_open( pjmedia_codec *codec,
869 pjmedia_codec_param *attr )
870{
871 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000872 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000873 int info_size;
874 pj_pool_t *pool;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000875 int i, j;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000876 USC_MemBank *membanks;
877 int nb_membanks;
878
879 pool = codec_data->pool;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000880
881 /* Get the codec info size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000882 if (USC_NoError != ippc->fxns->std.GetInfoSize(&info_size)) {
883 PJ_LOG(1,(THIS_FILE, "Error getting codec info size"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000884 goto on_error;
885 }
886 /* Get the codec info */
887 codec_data->info = pj_pool_zalloc(pool, info_size);
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000888 if (USC_NoError != ippc->fxns->std.GetInfo((USC_Handle)NULL,
889 codec_data->info))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000890 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000891 PJ_LOG(1,(THIS_FILE, "Error getting codec info"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000892 goto on_error;
893 }
894
895 /* PREPARING THE ENCODER */
896
897 /* Setting the encoder params */
898 codec_data->info->params.direction = USC_ENCODE;
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000899 codec_data->info->params.modes.vad = attr->setting.vad &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000900 ippc->has_native_vad;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000901 codec_data->info->params.modes.bitrate = attr->info.avg_bps;
902 codec_data->info->params.law = 0; /* Linear PCM input */
903
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000904#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
905 if (ippc->pt == PJMEDIA_RTP_PT_G729) {
906 /* Check if G729 Annex B is signaled to be disabled */
907 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
908 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
909 {
910 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
911 codec_data->info->params.modes.vad = 0;
912 break;
913 }
914 }
915 }
916#endif
917
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000918 /* Get number of memory blocks needed by the encoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000919 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
920 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000921 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000922 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000923 goto on_error;
924 }
925
926 /* Allocate memory blocks table */
927 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
928 sizeof(USC_MemBank) * nb_membanks);
929 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000930 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
931 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000932 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000933 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000934 goto on_error;
935 }
936
937 /* Allocate memory for each block */
938 for (i = 0; i < nb_membanks; i++) {
939 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
940 }
941
942 /* Create encoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000943 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
944 membanks,
945 &codec_data->enc))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000946 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000947 PJ_LOG(1,(THIS_FILE, "Error initializing encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000948 goto on_error;
949 }
950
951 /* PREPARING THE DECODER */
952
953 /* Setting the decoder params */
954 codec_data->info->params.direction = USC_DECODE;
955
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000956 /* Not sure if VAD affects decoder, just try to be safe */
957 codec_data->info->params.modes.vad = ippc->has_native_vad;
958
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000959 /* Get number of memory blocks needed by the decoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000960 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
961 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000962 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000963 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000964 goto on_error;
965 }
966
967 /* Allocate memory blocks table */
968 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
969 sizeof(USC_MemBank) * nb_membanks);
970 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000971 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
972 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000973 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000974 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000975 goto on_error;
976 }
977
978 /* Allocate memory for each block */
979 for (i = 0; i < nb_membanks; i++) {
980 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
981 }
982
983 /* Create decoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000984 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
985 membanks, &codec_data->dec))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000986 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000987 PJ_LOG(1,(THIS_FILE, "Error initializing decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000988 goto on_error;
989 }
990
991 /* Update codec info */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000992 ippc->fxns->std.GetInfo((USC_Handle)codec_data->enc, codec_data->info);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000993
994 /* Get bitstream size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000995 i = codec_data->info->params.modes.bitrate * ippc->samples_per_frame;
996 j = ippc->clock_rate << 3;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000997 codec_data->frame_size = (pj_uint16_t)(i / j);
998 if (i % j) ++codec_data->frame_size;
999
1000 codec_data->vad_enabled = (attr->setting.vad != 0);
1001 codec_data->plc_enabled = (attr->setting.plc != 0);
1002
1003 return PJ_SUCCESS;
1004
1005on_error:
1006 return PJMEDIA_CODEC_EFAILED;
1007}
1008
1009/*
1010 * Close codec.
1011 */
1012static pj_status_t ipp_codec_close( pjmedia_codec *codec )
1013{
1014 PJ_UNUSED_ARG(codec);
1015
1016 return PJ_SUCCESS;
1017}
1018
1019
1020/*
1021 * Modify codec settings.
1022 */
1023static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
1024 const pjmedia_codec_param *attr )
1025{
1026 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001027 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001028
1029 codec_data->vad_enabled = (attr->setting.vad != 0);
1030 codec_data->plc_enabled = (attr->setting.plc != 0);
1031
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001032 if (ippc->has_native_vad) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001033 USC_Modes modes;
1034
1035 modes = codec_data->info->params.modes;
1036 modes.vad = codec_data->vad_enabled;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001037 ippc->fxns->std.Control(&modes, codec_data->enc);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001038 }
1039
1040 return PJ_SUCCESS;
1041}
1042
1043/*
1044 * Get frames in the packet.
1045 */
1046static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
1047 void *pkt,
1048 pj_size_t pkt_size,
1049 const pj_timestamp *ts,
1050 unsigned *frame_cnt,
1051 pjmedia_frame frames[])
1052{
1053 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001054 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001055 unsigned count = 0;
1056
1057 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
1058
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001059 if (ippc->parse != NULL) {
1060 return ippc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001061 }
1062
1063 while (pkt_size >= codec_data->frame_size && count < *frame_cnt) {
1064 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1065 frames[count].buf = pkt;
1066 frames[count].size = codec_data->frame_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001067 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001068
1069 pkt = ((char*)pkt) + codec_data->frame_size;
1070 pkt_size -= codec_data->frame_size;
1071
1072 ++count;
1073 }
1074
1075 if (pkt_size && count < *frame_cnt) {
1076 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1077 frames[count].buf = pkt;
1078 frames[count].size = pkt_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001079 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001080 ++count;
1081 }
1082
1083 *frame_cnt = count;
1084 return PJ_SUCCESS;
1085}
1086
1087/*
1088 * Encode frames.
1089 */
1090static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
1091 const struct pjmedia_frame *input,
1092 unsigned output_buf_len,
1093 struct pjmedia_frame *output)
1094{
1095 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001096 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001097 unsigned samples_per_frame;
1098 unsigned nsamples;
1099 pj_size_t tx = 0;
1100 pj_int16_t *pcm_in = (pj_int16_t*)input->buf;
Benny Prijonob1339242008-08-21 20:58:55 +00001101 pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001102 pj_uint8_t pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001103
1104 /* Invoke external VAD if codec has no internal VAD */
1105 if (codec_data->vad && codec_data->vad_enabled) {
1106 pj_bool_t is_silence;
1107 pj_int32_t silence_duration;
1108
1109 silence_duration = pj_timestamp_diff32(&codec_data->last_tx,
1110 &input->timestamp);
1111
1112 is_silence = pjmedia_silence_det_detect(codec_data->vad,
1113 (const pj_int16_t*) input->buf,
1114 (input->size >> 1),
1115 NULL);
1116 if (is_silence &&
1117 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001118 silence_duration < (PJMEDIA_CODEC_MAX_SILENCE_PERIOD *
1119 (int)ippc->clock_rate / 1000))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001120 {
1121 output->type = PJMEDIA_FRAME_TYPE_NONE;
1122 output->buf = NULL;
1123 output->size = 0;
1124 output->timestamp = input->timestamp;
1125 return PJ_SUCCESS;
1126 } else {
1127 codec_data->last_tx = input->timestamp;
1128 }
1129 }
1130
1131 nsamples = input->size >> 1;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001132 samples_per_frame = ippc->samples_per_frame;
1133 pt = ippc->pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001134
1135 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
1136 PJMEDIA_CODEC_EPCMFRMINLEN);
1137
1138 /* Encode the frames */
1139 while (nsamples >= samples_per_frame) {
1140 USC_PCMStream in;
1141 USC_Bitstream out;
1142
1143 in.bitrate = codec_data->info->params.modes.bitrate;
1144 in.nbytes = samples_per_frame << 1;
1145 in.pBuffer = (char*)pcm_in;
1146 in.pcmType.bitPerSample = codec_data->info->params.pcmType.bitPerSample;
1147 in.pcmType.nChannels = codec_data->info->params.pcmType.nChannels;
1148 in.pcmType.sample_frequency = codec_data->info->params.pcmType.sample_frequency;
1149
Benny Prijonob1339242008-08-21 20:58:55 +00001150 out.pBuffer = (char*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001151
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001152#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001153 /* For AMR: reserve two octets for AMR frame info */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001154 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001155 out.pBuffer += 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001156 }
1157#endif
1158
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001159 if (USC_NoError != ippc->fxns->Encode(codec_data->enc, &in, &out)) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001160 break;
1161 }
1162
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001163#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
1164 /* For AMR: put info (frametype, degraded, last frame) in the
1165 * first byte
1166 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001167 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001168 pj_uint16_t *info = (pj_uint16_t*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001169
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001170 /* Two octets for AMR frame info, 0=LSB:
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001171 * bit 0-3 : frame type
1172 * bit 6 : last frame flag
1173 * bit 7 : quality flag
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001174 * bit 8-11 : mode
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001175 */
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001176 out.nbytes += 2;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001177 if (out.frametype == 0 || out.frametype == 4 ||
1178 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 5) ||
1179 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 6))
1180 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001181 /* Speech frame type */
1182 *info = (char)pjmedia_codec_amr_get_mode(out.bitrate);
1183 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001184 if (out.frametype == 5 || out.frametype == 6)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001185 *info |= 0x80;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001186 } else if (out.frametype == 1 || out.frametype == 2 ||
1187 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 6) ||
1188 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 7))
1189 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001190 /* SID frame type */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001191 *info = (pj_uint8_t)(pt == PJMEDIA_RTP_PT_AMRWB? 9 : 8);
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001192 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001193 if (out.frametype == 6 || out.frametype == 7)
1194 *info |= 0x80;
1195 } else {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001196 /* Untransmited */
1197 *info = 15;
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001198 out.nbytes = 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001199 }
1200
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001201 /* Mode */
1202 *info |= (char)pjmedia_codec_amr_get_mode(out.bitrate) << 8;
1203
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001204 /* Last frame flag */
1205 if (nsamples == samples_per_frame)
1206 *info |= 0x40;
1207 }
Nanang Izzuddin7dd32682008-08-19 11:23:33 +00001208#endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001209
1210 pcm_in += samples_per_frame;
1211 nsamples -= samples_per_frame;
1212 tx += out.nbytes;
1213 bits_out += out.nbytes;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001214
1215#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddine3a6fca2008-08-27 13:15:25 +00001216 if (pt == PJMEDIA_RTP_PT_G729) {
1217 if (out.frametype == 1) {
1218 /* SID */
1219 break;
1220 } else if (out.frametype == 0) {
1221 /* Untransmitted */
1222 tx -= out.nbytes;
1223 break;
1224 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001225 }
1226#endif
1227
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001228 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001229
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001230 if (ippc->pack != NULL) {
1231 ippc->pack(codec_data, output->buf, &tx, output_buf_len);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001232 }
1233
1234 /* Check if we don't need to transmit the frame (DTX) */
1235 if (tx == 0) {
1236 output->buf = NULL;
1237 output->size = 0;
1238 output->timestamp.u64 = input->timestamp.u64;
1239 output->type = PJMEDIA_FRAME_TYPE_NONE;
1240 return PJ_SUCCESS;
1241 }
1242
1243 output->size = tx;
1244 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1245 output->timestamp = input->timestamp;
1246
1247 return PJ_SUCCESS;
1248}
1249
1250/*
1251 * Decode frame.
1252 */
1253static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
1254 const struct pjmedia_frame *input,
1255 unsigned output_buf_len,
1256 struct pjmedia_frame *output)
1257{
1258 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001259 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001260 unsigned samples_per_frame;
1261 USC_PCMStream out;
1262 USC_Bitstream in;
1263 pj_uint8_t pt;
1264
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001265 pt = ippc->pt;
1266 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001267
1268 PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
1269 PJMEDIA_CODEC_EPCMTOOSHORT);
1270
1271 if (input->type == PJMEDIA_FRAME_TYPE_AUDIO) {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001272 if (ippc->predecode) {
1273 ippc->predecode(codec_data, input, &in);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001274 } else {
1275 /* Most IPP codecs have frametype==0 for speech frame */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001276 in.pBuffer = (char*)input->buf;
1277 in.nbytes = input->size;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001278 in.frametype = 0;
1279 in.bitrate = codec_data->info->params.modes.bitrate;
1280 }
1281
1282 out.pBuffer = output->buf;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001283 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001284
1285 if (input->type != PJMEDIA_FRAME_TYPE_AUDIO ||
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001286 USC_NoError != ippc->fxns->Decode(codec_data->dec, &in, &out))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001287 {
1288 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1289 output->size = samples_per_frame << 1;
1290 output->timestamp.u64 = input->timestamp.u64;
1291 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1292 return PJ_SUCCESS;
1293 }
1294
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001295#if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001296 /* For G.726: amplify decoding result (USC G.726 encoder deamplified it) */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001297 if (pt == PJMEDIA_RTP_PT_G726_16 || pt == PJMEDIA_RTP_PT_G726_24 ||
1298 pt == PJMEDIA_RTP_PT_G726_32 || pt == PJMEDIA_RTP_PT_G726_40)
1299 {
1300 unsigned i;
1301 pj_int16_t *s = (pj_int16_t*)output->buf;
1302
1303 for (i = 0; i < samples_per_frame; ++i)
1304 s[i] <<= 2;
1305 }
1306#endif
1307
1308 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1309 output->size = samples_per_frame << 1;
1310 output->timestamp.u64 = input->timestamp.u64;
1311
1312 /* Invoke external PLC if codec has no internal PLC */
1313 if (codec_data->plc && codec_data->plc_enabled)
1314 pjmedia_plc_save(codec_data->plc, (pj_int16_t*)output->buf);
1315
1316 return PJ_SUCCESS;
1317}
1318
1319/*
1320 * Recover lost frame.
1321 */
1322static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
1323 unsigned output_buf_len,
1324 struct pjmedia_frame *output)
1325{
1326 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001327 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001328 unsigned samples_per_frame;
1329
1330 PJ_UNUSED_ARG(output_buf_len);
1331
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001332 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001333
1334 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1335 output->size = samples_per_frame << 1;
1336
1337 if (codec_data->plc_enabled) {
1338 if (codec_data->plc) {
1339 pjmedia_plc_generate(codec_data->plc, (pj_int16_t*)output->buf);
1340 } else {
1341 USC_PCMStream out;
1342 out.pBuffer = output->buf;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001343 ippc->fxns->Decode(codec_data->dec, NULL, &out);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001344 }
1345 } else {
1346 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1347 }
1348
1349 return PJ_SUCCESS;
1350}
1351
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001352
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001353#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_IPP_LIBS
1354# pragma comment( lib, "ippcore.lib")
1355# pragma comment( lib, "ipps.lib")
1356# pragma comment( lib, "ippsc.lib")
1357# pragma comment( lib, "ippsr.lib")
1358# pragma comment( lib, "usc.lib")
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001359#endif
1360
1361
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001362#endif /* PJMEDIA_HAS_INTEL_IPP */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001363