blob: 4777b0bb888d8c9dff08b354912838acaf6b7128 [file] [log] [blame]
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjmedia-codec/ipp_codecs.h>
21#include <pjmedia/codec.h>
22#include <pjmedia/errno.h>
23#include <pjmedia/endpoint.h>
24#include <pjmedia/plc.h>
25#include <pjmedia/port.h>
26#include <pjmedia/silencedet.h>
27#include <pj/assert.h>
28#include <pj/log.h>
29#include <pj/pool.h>
30#include <pj/string.h>
31#include <pj/os.h>
32
Nanang Izzuddin23a00b72008-08-25 13:58:25 +000033
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000034/*
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000035 * Only build this file if PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000036 */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000037#if defined(PJMEDIA_HAS_INTEL_IPP) && PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000038
39#include <usc.h>
Benny Prijonoe1e6d512009-01-02 15:17:47 +000040#include <ippversion.h>
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000041
42#define THIS_FILE "ipp_codecs.c"
43
44/* Prototypes for IPP codecs factory */
45static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
46 const pjmedia_codec_info *id );
47static pj_status_t ipp_default_attr( pjmedia_codec_factory *factory,
48 const pjmedia_codec_info *id,
49 pjmedia_codec_param *attr );
50static pj_status_t ipp_enum_codecs( pjmedia_codec_factory *factory,
51 unsigned *count,
52 pjmedia_codec_info codecs[]);
53static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
54 const pjmedia_codec_info *id,
55 pjmedia_codec **p_codec);
56static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
57 pjmedia_codec *codec );
58
59/* Prototypes for IPP codecs implementation. */
60static pj_status_t ipp_codec_init( pjmedia_codec *codec,
61 pj_pool_t *pool );
62static pj_status_t ipp_codec_open( pjmedia_codec *codec,
63 pjmedia_codec_param *attr );
64static pj_status_t ipp_codec_close( pjmedia_codec *codec );
65static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
66 const pjmedia_codec_param *attr );
67static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
68 void *pkt,
69 pj_size_t pkt_size,
70 const pj_timestamp *ts,
71 unsigned *frame_cnt,
72 pjmedia_frame frames[]);
73static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
74 const struct pjmedia_frame *input,
75 unsigned output_buf_len,
76 struct pjmedia_frame *output);
77static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
78 const struct pjmedia_frame *input,
79 unsigned output_buf_len,
80 struct pjmedia_frame *output);
81static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
82 unsigned output_buf_len,
83 struct pjmedia_frame *output);
84
85/* Definition for IPP codecs operations. */
86static pjmedia_codec_op ipp_op =
87{
88 &ipp_codec_init,
89 &ipp_codec_open,
90 &ipp_codec_close,
91 &ipp_codec_modify,
92 &ipp_codec_parse,
93 &ipp_codec_encode,
94 &ipp_codec_decode,
95 &ipp_codec_recover
96};
97
98/* Definition for IPP codecs factory operations. */
99static pjmedia_codec_factory_op ipp_factory_op =
100{
101 &ipp_test_alloc,
102 &ipp_default_attr,
103 &ipp_enum_codecs,
104 &ipp_alloc_codec,
105 &ipp_dealloc_codec
106};
107
108/* IPP codecs factory */
109static struct ipp_factory {
110 pjmedia_codec_factory base;
111 pjmedia_endpt *endpt;
112 pj_pool_t *pool;
113 pj_mutex_t *mutex;
114} ipp_factory;
115
116/* IPP codecs private data. */
117typedef struct ipp_private {
118 int codec_idx; /**< Codec index. */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000119 void *codec_setting; /**< Specific codec setting. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000120 pj_pool_t *pool; /**< Pool for each instance. */
121
122 USC_Handle enc; /**< Encoder state. */
123 USC_Handle dec; /**< Decoder state. */
124 USC_CodecInfo *info; /**< Native codec info. */
125 pj_uint16_t frame_size; /**< Bitstream frame size. */
126
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000127 pj_bool_t plc_enabled; /**< PLC enabled flag. */
128 pjmedia_plc *plc; /**< PJMEDIA PLC engine, NULL if
129 codec has internal PLC. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000130
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000131 pj_bool_t vad_enabled; /**< VAD enabled flag. */
132 pjmedia_silence_det *vad; /**< PJMEDIA VAD engine, NULL if
133 codec has internal VAD. */
134 pj_timestamp last_tx; /**< Timestamp of last transmit.*/
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000135} ipp_private_t;
136
137
138/* USC codec implementations. */
139extern USC_Fxns USC_G729AFP_Fxns;
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000140extern USC_Fxns USC_G729I_Fxns;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000141extern USC_Fxns USC_G723_Fxns;
142extern USC_Fxns USC_G726_Fxns;
143extern USC_Fxns USC_G728_Fxns;
144extern USC_Fxns USC_G722_Fxns;
145extern USC_Fxns USC_GSMAMR_Fxns;
146extern USC_Fxns USC_AMRWB_Fxns;
147extern USC_Fxns USC_AMRWBE_Fxns;
148
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000149
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000150/* CUSTOM CALLBACKS */
151
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000152/* This callback is useful for translating RTP frame into USC frame, e.g:
153 * reassigning frame attributes, reorder bitstream. Default behaviour of
154 * the translation is just setting the USC frame buffer & its size as
155 * specified in RTP frame, setting USC frame frametype to 0, setting bitrate
156 * of USC frame to bitrate info of codec_data. Implement this callback when
157 * the default behaviour is unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000158 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000159typedef void (*predecode_cb)(ipp_private_t *codec_data,
160 const pjmedia_frame *rtp_frame,
161 USC_Bitstream *usc_frame);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000162
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000163/* Parse frames from a packet. Default behaviour of frame parsing is
164 * just separating frames based on calculating frame length derived
165 * from bitrate. Implement this callback when the default behaviour is
166 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000167 */
168typedef pj_status_t (*parse_cb)(ipp_private_t *codec_data, void *pkt,
169 pj_size_t pkt_size, const pj_timestamp *ts,
170 unsigned *frame_cnt, pjmedia_frame frames[]);
171
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000172/* Pack frames into a packet. Default behaviour of packing frames is
173 * just stacking the frames with octet aligned without adding any
174 * payload header. Implement this callback when the default behaviour is
175 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000176 */
177typedef pj_status_t (*pack_cb)(ipp_private_t *codec_data, void *pkt,
178 pj_size_t *pkt_size, pj_size_t max_pkt_size);
179
180
181
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000182/* Custom callback implementations. */
183static void predecode_g723( ipp_private_t *codec_data,
184 const pjmedia_frame *rtp_frame,
185 USC_Bitstream *usc_frame);
186static pj_status_t parse_g723( ipp_private_t *codec_data, void *pkt,
187 pj_size_t pkt_size, const pj_timestamp *ts,
188 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000189
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000190static void predecode_g729( ipp_private_t *codec_data,
191 const pjmedia_frame *rtp_frame,
192 USC_Bitstream *usc_frame);
193
194static void predecode_amr( ipp_private_t *codec_data,
195 const pjmedia_frame *rtp_frame,
196 USC_Bitstream *usc_frame);
197static pj_status_t parse_amr( ipp_private_t *codec_data, void *pkt,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000198 pj_size_t pkt_size, const pj_timestamp *ts,
199 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000200static pj_status_t pack_amr( ipp_private_t *codec_data, void *pkt,
201 pj_size_t *pkt_size, pj_size_t max_pkt_size);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000202
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000203static void predecode_g7221( ipp_private_t *codec_data,
204 const pjmedia_frame *rtp_frame,
205 USC_Bitstream *usc_frame);
206static pj_status_t pack_g7221( ipp_private_t *codec_data, void *pkt,
207 pj_size_t *pkt_size, pj_size_t max_pkt_size);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000208
209/* IPP codec implementation descriptions. */
210static struct ipp_codec {
211 int enabled; /* Is this codec enabled? */
212 const char *name; /* Codec name. */
213 pj_uint8_t pt; /* Payload type. */
214 USC_Fxns *fxns; /* USC callback functions. */
215 unsigned clock_rate; /* Codec's clock rate. */
216 unsigned channel_count; /* Codec's channel count. */
217 unsigned samples_per_frame; /* Codec's samples count. */
218
219 unsigned def_bitrate; /* Default bitrate of this codec. */
220 unsigned max_bitrate; /* Maximum bitrate of this codec. */
221 pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/
222 int has_native_vad; /* Codec has internal VAD? */
223 int has_native_plc; /* Codec has internal PLC? */
224
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000225 predecode_cb predecode; /* Callback to translate RTP frame
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000226 into USC frame. */
227 parse_cb parse; /* Callback to parse bitstream. */
228 pack_cb pack; /* Callback to pack bitstream. */
229
230 pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
231}
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000232
233ipp_codec[] =
234{
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000235# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Benny Prijono329d6382009-05-29 13:04:03 +0000236 /* AMR-NB SID seems to produce noise, so let's just disable its VAD. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000237 {1, "AMR", PJMEDIA_RTP_PT_AMR, &USC_GSMAMR_Fxns, 8000, 1, 160,
Benny Prijono329d6382009-05-29 13:04:03 +0000238 7400, 12200, 2, 0, 1,
239 &predecode_amr, &parse_amr, &pack_amr,
240 {1, {{{"octet-align", 11}, {"1", 1}}} }
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000241 },
242# endif
243
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000244# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMRWB
245 {1, "AMR-WB", PJMEDIA_RTP_PT_AMRWB, &USC_AMRWB_Fxns, 16000, 1, 320,
246 15850, 23850, 1, 1, 1,
Benny Prijono329d6382009-05-29 13:04:03 +0000247 &predecode_amr, &parse_amr, &pack_amr,
248 {1, {{{"octet-align", 11}, {"1", 1}}} }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000249 },
250# endif
251
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000252# if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000253# if defined(PJ_HAS_FLOATING_POINT) && (PJ_HAS_FLOATING_POINT != 0)
254 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729AFP_Fxns, 8000, 1, 80,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000255 8000, 11800, 2, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000256 &predecode_g729, NULL, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000257 },
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000258# else
259 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729I_Fxns, 8000, 1, 80,
260 8000, 11800, 2, 1, 1,
261 &predecode_g729, NULL, NULL
262 },
263# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000264# endif
265
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000266# if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000267 /* This is actually G.723.1 */
268 {1, "G723", PJMEDIA_RTP_PT_G723, &USC_G723_Fxns, 8000, 1, 240,
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000269 6300, 6300, 1, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000270 &predecode_g723, &parse_g723, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000271 },
272# endif
273
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000274# if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000275 {0, "G726-16", PJMEDIA_RTP_PT_G726_16, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000276 16000, 16000, 2, 0, 0,
277 NULL, NULL, NULL
278 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000279 {0, "G726-24", PJMEDIA_RTP_PT_G726_24, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000280 24000, 24000, 2, 0, 0,
281 NULL, NULL, NULL
282 },
283 {1, "G726-32", PJMEDIA_RTP_PT_G726_32, &USC_G726_Fxns, 8000, 1, 80,
284 32000, 32000, 2, 0, 0,
285 NULL, NULL, NULL
286 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000287 {0, "G726-40", PJMEDIA_RTP_PT_G726_40, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000288 40000, 40000, 2, 0, 0,
289 NULL, NULL, NULL
290 },
291# endif
292
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000293# if PJMEDIA_HAS_INTEL_IPP_CODEC_G728
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000294 {1, "G728", PJMEDIA_RTP_PT_G728, &USC_G728_Fxns, 8000, 1, 80,
295 16000, 16000, 2, 0, 1,
296 NULL, NULL, NULL
297 },
298# endif
299
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000300# if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000301 {0, "G7221", PJMEDIA_RTP_PT_G722_1_16, &USC_G722_Fxns, 16000, 1, 320,
302 16000, 16000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000303 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000304 {1, {{{"bitrate", 7}, {"16000", 5}}} }
305 },
306 {1, "G7221", PJMEDIA_RTP_PT_G722_1_24, &USC_G722_Fxns, 16000, 1, 320,
307 24000, 24000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000308 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000309 {1, {{{"bitrate", 7}, {"24000", 5}}} }
310 },
311 {1, "G7221", PJMEDIA_RTP_PT_G722_1_32, &USC_G722_Fxns, 16000, 1, 320,
312 32000, 32000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000313 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000314 {1, {{{"bitrate", 7}, {"32000", 5}}} }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000315 },
316# endif
317};
318
319
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000320#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
321
322static void predecode_g729( ipp_private_t *codec_data,
323 const pjmedia_frame *rtp_frame,
324 USC_Bitstream *usc_frame)
325{
326 switch (rtp_frame->size) {
327 case 2:
328 /* SID */
329 usc_frame->frametype = 1;
330 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
331 break;
332 case 8:
333 /* G729D */
334 usc_frame->frametype = 2;
335 usc_frame->bitrate = 6400;
336 break;
337 case 10:
338 /* G729 */
339 usc_frame->frametype = 3;
340 usc_frame->bitrate = 8000;
341 break;
342 case 15:
343 /* G729E */
344 usc_frame->frametype = 4;
345 usc_frame->bitrate = 11800;
346 break;
347 default:
348 usc_frame->frametype = 0;
349 usc_frame->bitrate = 0;
350 break;
351 }
352
353 usc_frame->pBuffer = rtp_frame->buf;
354 usc_frame->nbytes = rtp_frame->size;
355}
356
357#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G729 */
358
359
360#if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
361
362static void predecode_g723( ipp_private_t *codec_data,
363 const pjmedia_frame *rtp_frame,
364 USC_Bitstream *usc_frame)
365{
366 int i, HDR = 0;
367 pj_uint8_t *f = (pj_uint8_t*)rtp_frame->buf;
368
369 PJ_UNUSED_ARG(codec_data);
370
371 for (i = 0; i < 2; ++i){
372 int tmp;
373 tmp = (f[0] >> (i & 0x7)) & 1;
374 HDR += tmp << i ;
375 }
376
377 usc_frame->pBuffer = rtp_frame->buf;
378 usc_frame->nbytes = rtp_frame->size;
379 usc_frame->bitrate = HDR == 0? 6300 : 5300;
380 usc_frame->frametype = 0;
381}
382
383static pj_status_t parse_g723(ipp_private_t *codec_data, void *pkt,
384 pj_size_t pkt_size, const pj_timestamp *ts,
385 unsigned *frame_cnt, pjmedia_frame frames[])
386{
387 unsigned count = 0;
388 pj_uint8_t *f = (pj_uint8_t*)pkt;
389
390 while (pkt_size && count < *frame_cnt) {
391 int framesize, i, j;
392 int HDR = 0;
393
394 for (i = 0; i < 2; ++i){
395 j = (f[0] >> (i & 0x7)) & 1;
396 HDR += j << i ;
397 }
398
399 if (HDR == 0)
400 framesize = 24;
401 else if (HDR == 1)
402 framesize = 20;
403 else if (HDR == 2)
404 framesize = 4;
405 else if (HDR == 3)
406 framesize = 1;
407 else {
408 pj_assert(!"Unknown G723.1 frametype, packet may be corrupted!");
409 return PJMEDIA_CODEC_EINMODE;
410 }
411
412 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
413 frames[count].buf = f;
414 frames[count].size = framesize;
415 frames[count].timestamp.u64 = ts->u64 + count *
416 ipp_codec[codec_data->codec_idx].samples_per_frame;
417
418 f += framesize;
419 pkt_size -= framesize;
420
421 ++count;
422 }
423
424 *frame_cnt = count;
425 return PJ_SUCCESS;
426}
427
428#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1 */
429
430
431#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
432
433#include <pjmedia-codec/amr_helper.h>
434
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000435typedef struct amr_settings_t {
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000436 pjmedia_codec_amr_pack_setting enc_setting;
437 pjmedia_codec_amr_pack_setting dec_setting;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000438 pj_int8_t enc_mode;
439} amr_settings_t;
440
441
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000442/* Rearrange AMR bitstream and convert RTP frame into USC frame:
443 * - make the start_bit to be 0
444 * - if it is speech frame, reorder bitstream from sensitivity bits order
445 * to encoder bits order.
446 * - set the appropriate value of usc_frame.
447 */
448static void predecode_amr( ipp_private_t *codec_data,
449 const pjmedia_frame *rtp_frame,
450 USC_Bitstream *usc_frame)
451{
452 pjmedia_frame frame;
453 pjmedia_codec_amr_bit_info *info;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000454 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000455
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000456 setting = &((amr_settings_t*)codec_data->codec_setting)->dec_setting;
457
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000458 frame = *rtp_frame;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000459 pjmedia_codec_amr_predecode(rtp_frame, setting, &frame);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000460 info = (pjmedia_codec_amr_bit_info*) &frame.bit_info;
461
462 usc_frame->pBuffer = frame.buf;
463 usc_frame->nbytes = frame.size;
464 if (info->mode != -1) {
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000465 usc_frame->bitrate = setting->amr_nb?
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000466 pjmedia_codec_amrnb_bitrates[info->mode]:
467 pjmedia_codec_amrwb_bitrates[info->mode];
468 } else {
469 usc_frame->bitrate = 0;
470 }
471
472 if (frame.size > 5) {
473 /* Speech */
474 if (info->good_quality)
475 usc_frame->frametype = 0;
476 else
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000477 usc_frame->frametype = setting->amr_nb ? 5 : 6;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000478 } else if (frame.size == 5) {
479 /* SID */
480 if (info->good_quality) {
481 pj_bool_t STI;
482 STI = (((pj_uint8_t*)frame.buf)[35 >> 3] & 0x10) != 0;
483 usc_frame->frametype = STI? 2 : 1;
484 } else {
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000485 usc_frame->frametype = setting->amr_nb ? 6 : 7;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000486 }
487 } else {
488 /* no data */
489 usc_frame->frametype = 3;
490 }
491}
492
493/* Pack AMR payload */
494static pj_status_t pack_amr(ipp_private_t *codec_data, void *pkt,
495 pj_size_t *pkt_size, pj_size_t max_pkt_size)
496{
497 enum {MAX_FRAMES_PER_PACKET = 16};
498
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000499 pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
500 unsigned nframes = 0;
501 pjmedia_codec_amr_bit_info *info;
502 pj_uint8_t *r; /* Read cursor */
503 pj_uint8_t SID_FT;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000504 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000505
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000506 setting = &((amr_settings_t*)codec_data->codec_setting)->enc_setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000507
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000508 SID_FT = (pj_uint8_t)(setting->amr_nb? 8 : 9);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000509
510 /* Align pkt buf right */
511 r = (pj_uint8_t*)pkt + max_pkt_size - *pkt_size;
512 pj_memmove(r, pkt, *pkt_size);
513
514 /* Get frames */
515 for (;;) {
516 pj_bool_t eof;
517 pj_uint16_t info_;
518
519 info_ = *((pj_uint16_t*)r);
520 eof = ((info_ & 0x40) != 0);
521
522 info = (pjmedia_codec_amr_bit_info*) &frames[nframes].bit_info;
523 pj_bzero(info, sizeof(*info));
524 info->frame_type = (pj_uint8_t)(info_ & 0x0F);
525 info->good_quality = (pj_uint8_t)((info_ & 0x80) == 0);
526 info->mode = (pj_int8_t) ((info_ >> 8) & 0x0F);
527
528 frames[nframes].buf = r + 2;
529 frames[nframes].size = info->frame_type <= SID_FT ?
530 pjmedia_codec_amrnb_framelen[info->frame_type] :
531 0;
532
533 r += frames[nframes].size + 2;
534
535 /* Last frame */
536 if (++nframes >= MAX_FRAMES_PER_PACKET || eof)
537 break;
538 }
539
540 /* Pack */
541 *pkt_size = max_pkt_size;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000542 return pjmedia_codec_amr_pack(frames, nframes, setting, pkt, pkt_size);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000543}
544
545
546/* Parse AMR payload into frames. */
547static pj_status_t parse_amr(ipp_private_t *codec_data, void *pkt,
548 pj_size_t pkt_size, const pj_timestamp *ts,
549 unsigned *frame_cnt, pjmedia_frame frames[])
550{
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000551 amr_settings_t* s = (amr_settings_t*)codec_data->codec_setting;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000552 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000553 pj_status_t status;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000554 pj_uint8_t cmr;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000555
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000556 setting = &s->dec_setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000557
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000558 status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, setting, frames,
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000559 frame_cnt, &cmr);
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000560 if (status != PJ_SUCCESS)
561 return status;
562
563 /* Check Change Mode Request. */
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000564 if ((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) {
Benny Prijono329d6382009-05-29 13:04:03 +0000565 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
566
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000567 s->enc_mode = cmr;
Benny Prijono329d6382009-05-29 13:04:03 +0000568 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
569 pjmedia_codec_amrnb_bitrates[s->enc_mode] :
570 pjmedia_codec_amrwb_bitrates[s->enc_mode];
571 ippc->fxns->std.Control(&codec_data->info->params.modes,
572 codec_data->enc);
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000573 }
574
575 return PJ_SUCCESS;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000576}
577
578#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_AMR */
579
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000580
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000581#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
582
583static void predecode_g7221( ipp_private_t *codec_data,
584 const pjmedia_frame *rtp_frame,
585 USC_Bitstream *usc_frame)
586{
587 usc_frame->pBuffer = (char*)rtp_frame->buf;
588 usc_frame->nbytes = rtp_frame->size;
589 usc_frame->frametype = 0;
590 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
591
592#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
593 {
594 pj_uint16_t *p, *p_end;
595
596 p = (pj_uint16_t*)rtp_frame->buf;
597 p_end = p + rtp_frame->size/2;
598 while (p < p_end) {
599 *p = pj_ntohs(*p);
600 ++p;
601 }
602 }
603#endif
604}
605
606static pj_status_t pack_g7221( ipp_private_t *codec_data, void *pkt,
607 pj_size_t *pkt_size, pj_size_t max_pkt_size)
608{
609 PJ_UNUSED_ARG(codec_data);
610 PJ_UNUSED_ARG(max_pkt_size);
611
612#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
613 {
614 pj_uint16_t *p, *p_end;
615
616 p = (pj_uint16_t*)pkt;
617 p_end = p + *pkt_size/2;
618 while (p < p_end) {
619 *p = pj_htons(*p);
620 ++p;
621 }
622 }
623#else
624 PJ_UNUSED_ARG(pkt);
625 PJ_UNUSED_ARG(pkt_size);
626#endif
627
628 return PJ_SUCCESS;
629}
630
631#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1 */
632
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000633/*
634 * Initialize and register IPP codec factory to pjmedia endpoint.
635 */
636PJ_DEF(pj_status_t) pjmedia_codec_ipp_init( pjmedia_endpt *endpt )
637{
638 pjmedia_codec_mgr *codec_mgr;
639 pj_status_t status;
640
641 if (ipp_factory.pool != NULL) {
642 /* Already initialized. */
643 return PJ_SUCCESS;
644 }
645
646 /* Create IPP codec factory. */
647 ipp_factory.base.op = &ipp_factory_op;
648 ipp_factory.base.factory_data = NULL;
649 ipp_factory.endpt = endpt;
650
651 ipp_factory.pool = pjmedia_endpt_create_pool(endpt, "IPP codecs", 4000, 4000);
652 if (!ipp_factory.pool)
653 return PJ_ENOMEM;
654
655 /* Create mutex. */
656 status = pj_mutex_create_simple(ipp_factory.pool, "IPP codecs",
657 &ipp_factory.mutex);
658 if (status != PJ_SUCCESS)
659 goto on_error;
660
661 /* Get the codec manager. */
662 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
663 if (!codec_mgr) {
664 status = PJ_EINVALIDOP;
665 goto on_error;
666 }
667
668 /* Register codec factory to endpoint. */
669 status = pjmedia_codec_mgr_register_factory(codec_mgr,
670 &ipp_factory.base);
671 if (status != PJ_SUCCESS)
672 goto on_error;
673
674 /* Done. */
675 return PJ_SUCCESS;
676
677on_error:
678 pj_pool_release(ipp_factory.pool);
679 ipp_factory.pool = NULL;
680 return status;
681}
682
683/*
684 * Unregister IPP codecs factory from pjmedia endpoint.
685 */
686PJ_DEF(pj_status_t) pjmedia_codec_ipp_deinit(void)
687{
688 pjmedia_codec_mgr *codec_mgr;
689 pj_status_t status;
690
691 if (ipp_factory.pool == NULL) {
692 /* Already deinitialized */
693 return PJ_SUCCESS;
694 }
695
696 pj_mutex_lock(ipp_factory.mutex);
697
698 /* Get the codec manager. */
699 codec_mgr = pjmedia_endpt_get_codec_mgr(ipp_factory.endpt);
700 if (!codec_mgr) {
701 pj_pool_release(ipp_factory.pool);
702 ipp_factory.pool = NULL;
703 return PJ_EINVALIDOP;
704 }
705
706 /* Unregister IPP codecs factory. */
707 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
708 &ipp_factory.base);
709
710 /* Destroy mutex. */
711 pj_mutex_destroy(ipp_factory.mutex);
712
713 /* Destroy pool. */
714 pj_pool_release(ipp_factory.pool);
715 ipp_factory.pool = NULL;
716
717 return status;
718}
719
720/*
721 * Check if factory can allocate the specified codec.
722 */
723static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
724 const pjmedia_codec_info *info )
725{
726 unsigned i;
727
728 PJ_UNUSED_ARG(factory);
729
730 /* Type MUST be audio. */
731 if (info->type != PJMEDIA_TYPE_AUDIO)
732 return PJMEDIA_CODEC_EUNSUP;
733
734 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
735 pj_str_t name = pj_str((char*)ipp_codec[i].name);
736 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
737 (info->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
738 (info->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
739 (ipp_codec[i].enabled))
740 {
741 return PJ_SUCCESS;
742 }
743 }
744
745 /* Unsupported, or mode is disabled. */
746 return PJMEDIA_CODEC_EUNSUP;
747}
748
749/*
750 * Generate default attribute.
751 */
752static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
753 const pjmedia_codec_info *id,
754 pjmedia_codec_param *attr )
755{
756 unsigned i;
757
758 PJ_ASSERT_RETURN(factory==&ipp_factory.base, PJ_EINVAL);
759
760 pj_bzero(attr, sizeof(pjmedia_codec_param));
761
762 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
763 pj_str_t name = pj_str((char*)ipp_codec[i].name);
764 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
765 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000766 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
767 (id->pt == (unsigned)ipp_codec[i].pt))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000768 {
769 attr->info.pt = (pj_uint8_t)id->pt;
770 attr->info.channel_cnt = ipp_codec[i].channel_count;
771 attr->info.clock_rate = ipp_codec[i].clock_rate;
772 attr->info.avg_bps = ipp_codec[i].def_bitrate;
773 attr->info.max_bps = ipp_codec[i].max_bitrate;
774 attr->info.pcm_bits_per_sample = 16;
775 attr->info.frm_ptime = (pj_uint16_t)
776 (ipp_codec[i].samples_per_frame * 1000 /
777 ipp_codec[i].channel_count /
778 ipp_codec[i].clock_rate);
779 attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
780
781 /* Default flags. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000782 attr->setting.plc = 1;
783 attr->setting.penh= 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000784 attr->setting.vad = 1;
785 attr->setting.cng = attr->setting.vad;
786 attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
787
788 if (attr->setting.vad == 0) {
789#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
790 if (id->pt == PJMEDIA_RTP_PT_G729) {
791 /* Signal G729 Annex B is being disabled */
792 attr->setting.dec_fmtp.cnt = 1;
793 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
794 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
795 }
796#endif
797 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000798
799 return PJ_SUCCESS;
800 }
801 }
802
803 return PJMEDIA_CODEC_EUNSUP;
804}
805
806/*
807 * Enum codecs supported by this factory.
808 */
809static pj_status_t ipp_enum_codecs(pjmedia_codec_factory *factory,
810 unsigned *count,
811 pjmedia_codec_info codecs[])
812{
813 unsigned max;
814 unsigned i;
815
816 PJ_UNUSED_ARG(factory);
817 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
818
819 max = *count;
820
821 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(ipp_codec) && *count < max; ++i)
822 {
823 if (!ipp_codec[i].enabled)
824 continue;
825
826 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
827 codecs[*count].encoding_name = pj_str((char*)ipp_codec[i].name);
828 codecs[*count].pt = ipp_codec[i].pt;
829 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
830 codecs[*count].clock_rate = ipp_codec[i].clock_rate;
831 codecs[*count].channel_cnt = ipp_codec[i].channel_count;
832
833 ++*count;
834 }
835
836 return PJ_SUCCESS;
837}
838
839/*
840 * Allocate a new codec instance.
841 */
842static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
843 const pjmedia_codec_info *id,
844 pjmedia_codec **p_codec)
845{
846 ipp_private_t *codec_data;
847 pjmedia_codec *codec;
848 int idx;
849 pj_pool_t *pool;
850 unsigned i;
851
852 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
853 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
854
855 pj_mutex_lock(ipp_factory.mutex);
856
857 /* Find codec's index */
858 idx = -1;
859 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
860 pj_str_t name = pj_str((char*)ipp_codec[i].name);
861 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
862 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
863 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
864 (ipp_codec[i].enabled))
865 {
866 idx = i;
867 break;
868 }
869 }
870 if (idx == -1) {
871 *p_codec = NULL;
872 return PJMEDIA_CODEC_EFAILED;
873 }
874
875 /* Create pool for codec instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000876 pool = pjmedia_endpt_create_pool(ipp_factory.endpt, "IPPcodec", 512, 512);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000877 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
878 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
879 codec->op = &ipp_op;
880 codec->factory = factory;
881 codec->codec_data = PJ_POOL_ZALLOC_T(pool, ipp_private_t);
882 codec_data = (ipp_private_t*) codec->codec_data;
883
884 /* Create PLC if codec has no internal PLC */
885 if (!ipp_codec[idx].has_native_plc) {
886 pj_status_t status;
887 status = pjmedia_plc_create(pool, ipp_codec[idx].clock_rate,
888 ipp_codec[idx].samples_per_frame, 0,
889 &codec_data->plc);
890 if (status != PJ_SUCCESS) {
891 pj_pool_release(pool);
892 pj_mutex_unlock(ipp_factory.mutex);
893 return status;
894 }
895 }
896
897 /* Create silence detector if codec has no internal VAD */
898 if (!ipp_codec[idx].has_native_vad) {
899 pj_status_t status;
900 status = pjmedia_silence_det_create(pool,
901 ipp_codec[idx].clock_rate,
902 ipp_codec[idx].samples_per_frame,
903 &codec_data->vad);
904 if (status != PJ_SUCCESS) {
905 pj_pool_release(pool);
906 pj_mutex_unlock(ipp_factory.mutex);
907 return status;
908 }
909 }
910
911 codec_data->pool = pool;
912 codec_data->codec_idx = idx;
913
914 pj_mutex_unlock(ipp_factory.mutex);
915
916 *p_codec = codec;
917 return PJ_SUCCESS;
918}
919
920/*
921 * Free codec.
922 */
923static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
924 pjmedia_codec *codec )
925{
926 ipp_private_t *codec_data;
927
928 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
929 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
930
931 /* Close codec, if it's not closed. */
932 codec_data = (ipp_private_t*) codec->codec_data;
933 if (codec_data->enc != NULL || codec_data->dec != NULL) {
934 ipp_codec_close(codec);
935 }
936
937 pj_pool_release(codec_data->pool);
938
939 return PJ_SUCCESS;
940}
941
942/*
943 * Init codec.
944 */
945static pj_status_t ipp_codec_init( pjmedia_codec *codec,
946 pj_pool_t *pool )
947{
948 PJ_UNUSED_ARG(codec);
949 PJ_UNUSED_ARG(pool);
950 return PJ_SUCCESS;
951}
952
953/*
954 * Open codec.
955 */
956static pj_status_t ipp_codec_open( pjmedia_codec *codec,
957 pjmedia_codec_param *attr )
958{
959 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000960 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000961 int info_size;
962 pj_pool_t *pool;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000963 int i, j;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000964 USC_MemBank *membanks;
965 int nb_membanks;
966
967 pool = codec_data->pool;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000968
969 /* Get the codec info size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000970 if (USC_NoError != ippc->fxns->std.GetInfoSize(&info_size)) {
971 PJ_LOG(1,(THIS_FILE, "Error getting codec info size"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000972 goto on_error;
973 }
974 /* Get the codec info */
975 codec_data->info = pj_pool_zalloc(pool, info_size);
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000976 if (USC_NoError != ippc->fxns->std.GetInfo((USC_Handle)NULL,
977 codec_data->info))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000978 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000979 PJ_LOG(1,(THIS_FILE, "Error getting codec info"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000980 goto on_error;
981 }
982
983 /* PREPARING THE ENCODER */
984
985 /* Setting the encoder params */
986 codec_data->info->params.direction = USC_ENCODE;
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000987 codec_data->info->params.modes.vad = attr->setting.vad &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000988 ippc->has_native_vad;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000989 codec_data->info->params.modes.bitrate = attr->info.avg_bps;
990 codec_data->info->params.law = 0; /* Linear PCM input */
991
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000992#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
993 if (ippc->pt == PJMEDIA_RTP_PT_G729) {
994 /* Check if G729 Annex B is signaled to be disabled */
995 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
996 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
997 {
998 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
999 codec_data->info->params.modes.vad = 0;
1000 break;
1001 }
1002 }
1003 }
1004#endif
1005
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001006 /* Get number of memory blocks needed by the encoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001007 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1008 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001009 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001010 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001011 goto on_error;
1012 }
1013
1014 /* Allocate memory blocks table */
1015 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1016 sizeof(USC_MemBank) * nb_membanks);
1017 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001018 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1019 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001020 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001021 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001022 goto on_error;
1023 }
1024
1025 /* Allocate memory for each block */
1026 for (i = 0; i < nb_membanks; i++) {
1027 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1028 }
1029
1030 /* Create encoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001031 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1032 membanks,
1033 &codec_data->enc))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001034 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001035 PJ_LOG(1,(THIS_FILE, "Error initializing encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001036 goto on_error;
1037 }
1038
1039 /* PREPARING THE DECODER */
1040
1041 /* Setting the decoder params */
1042 codec_data->info->params.direction = USC_DECODE;
1043
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001044 /* Not sure if VAD affects decoder, just try to be safe */
Benny Prijono329d6382009-05-29 13:04:03 +00001045 //codec_data->info->params.modes.vad = ippc->has_native_vad;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001046
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001047 /* Get number of memory blocks needed by the decoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001048 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1049 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001050 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001051 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001052 goto on_error;
1053 }
1054
1055 /* Allocate memory blocks table */
1056 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1057 sizeof(USC_MemBank) * nb_membanks);
1058 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001059 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1060 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001061 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001062 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001063 goto on_error;
1064 }
1065
1066 /* Allocate memory for each block */
1067 for (i = 0; i < nb_membanks; i++) {
1068 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1069 }
1070
1071 /* Create decoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001072 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1073 membanks, &codec_data->dec))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001074 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001075 PJ_LOG(1,(THIS_FILE, "Error initializing decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001076 goto on_error;
1077 }
1078
1079 /* Update codec info */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001080 ippc->fxns->std.GetInfo((USC_Handle)codec_data->enc, codec_data->info);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001081
1082 /* Get bitstream size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001083 i = codec_data->info->params.modes.bitrate * ippc->samples_per_frame;
1084 j = ippc->clock_rate << 3;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001085 codec_data->frame_size = (pj_uint16_t)(i / j);
1086 if (i % j) ++codec_data->frame_size;
1087
1088 codec_data->vad_enabled = (attr->setting.vad != 0);
1089 codec_data->plc_enabled = (attr->setting.plc != 0);
1090
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001091#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
1092 /* Init AMR settings */
1093 if (ippc->pt == PJMEDIA_RTP_PT_AMR || ippc->pt == PJMEDIA_RTP_PT_AMRWB) {
1094 amr_settings_t *s;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001095 pj_uint8_t octet_align = 0;
Benny Prijono329d6382009-05-29 13:04:03 +00001096 pj_int8_t enc_mode = -1;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001097
Benny Prijono329d6382009-05-29 13:04:03 +00001098 /* Check AMR specific attributes */
1099
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001100 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
Benny Prijono329d6382009-05-29 13:04:03 +00001101 /* octet-align, one of the parameters that must have same value
1102 * in offer & answer (RFC 4867 Section 8.3.1). Just check fmtp
1103 * in the decoder side, since it's value is guaranteed to fulfil
1104 * above requirement (by SDP negotiator).
1105 */
1106 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
1107
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001108 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
1109 &STR_FMTP_OCTET_ALIGN) == 0)
1110 {
1111 octet_align=(pj_uint8_t)
Benny Prijono329d6382009-05-29 13:04:03 +00001112 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
1113 break;
1114 }
1115 }
1116 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
1117 /* mode-set */
1118 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
1119
1120 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
1121 &STR_FMTP_MODE_SET) == 0)
1122 {
1123 pj_int8_t tmp;
1124
1125 /* Just get the first value. */
1126 tmp = (pj_int8_t)
1127 pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
1128
1129 if ((ippc->pt == PJMEDIA_RTP_PT_AMR && tmp > 0 && tmp < 8) ||
1130 (ippc->pt == PJMEDIA_RTP_PT_AMRWB && tmp > 0 && tmp < 9))
1131 {
1132 enc_mode = tmp;
1133 PJ_LOG(4,(THIS_FILE, "Remote specifies AMR mode-set attr, "
1134 "selected: %d", enc_mode));
1135 }
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001136 break;
1137 }
1138 }
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001139
Benny Prijono329d6382009-05-29 13:04:03 +00001140 /* Initialize AMR specific settings */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001141 s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
1142 codec_data->codec_setting = s;
1143
Benny Prijono6b6fce12009-03-17 10:13:30 +00001144 s->enc_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001145 s->enc_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001146 s->enc_setting.reorder = PJ_TRUE;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001147 s->enc_setting.cmr = 15;
Benny Prijono329d6382009-05-29 13:04:03 +00001148
Benny Prijono6b6fce12009-03-17 10:13:30 +00001149 s->dec_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001150 s->dec_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001151 s->dec_setting.reorder = PJ_TRUE;
Benny Prijono329d6382009-05-29 13:04:03 +00001152
1153 s->enc_mode = pjmedia_codec_amr_get_mode(
1154 codec_data->info->params.modes.bitrate);
1155 if (s->enc_mode < 0)
1156 goto on_error;
1157
1158 if (enc_mode != -1) {
1159 s->enc_mode = enc_mode;
1160
1161 /* Apply requested encoder bitrate */
1162 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
1163 pjmedia_codec_amrnb_bitrates[s->enc_mode] :
1164 pjmedia_codec_amrwb_bitrates[s->enc_mode];
1165 ippc->fxns->std.Control(&codec_data->info->params.modes,
1166 codec_data->enc);
1167 }
1168
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001169 }
1170#endif
1171
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001172 return PJ_SUCCESS;
1173
1174on_error:
1175 return PJMEDIA_CODEC_EFAILED;
1176}
1177
1178/*
1179 * Close codec.
1180 */
1181static pj_status_t ipp_codec_close( pjmedia_codec *codec )
1182{
1183 PJ_UNUSED_ARG(codec);
1184
1185 return PJ_SUCCESS;
1186}
1187
1188
1189/*
1190 * Modify codec settings.
1191 */
1192static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
1193 const pjmedia_codec_param *attr )
1194{
1195 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001196 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001197
1198 codec_data->vad_enabled = (attr->setting.vad != 0);
1199 codec_data->plc_enabled = (attr->setting.plc != 0);
1200
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001201 if (ippc->has_native_vad) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001202 USC_Modes modes;
1203
1204 modes = codec_data->info->params.modes;
1205 modes.vad = codec_data->vad_enabled;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001206 ippc->fxns->std.Control(&modes, codec_data->enc);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001207 }
1208
1209 return PJ_SUCCESS;
1210}
1211
1212/*
1213 * Get frames in the packet.
1214 */
1215static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
1216 void *pkt,
1217 pj_size_t pkt_size,
1218 const pj_timestamp *ts,
1219 unsigned *frame_cnt,
1220 pjmedia_frame frames[])
1221{
1222 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001223 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001224 unsigned count = 0;
1225
1226 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
1227
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001228 if (ippc->parse != NULL) {
1229 return ippc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001230 }
1231
1232 while (pkt_size >= codec_data->frame_size && count < *frame_cnt) {
1233 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1234 frames[count].buf = pkt;
1235 frames[count].size = codec_data->frame_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001236 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001237
1238 pkt = ((char*)pkt) + codec_data->frame_size;
1239 pkt_size -= codec_data->frame_size;
1240
1241 ++count;
1242 }
1243
1244 if (pkt_size && count < *frame_cnt) {
1245 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1246 frames[count].buf = pkt;
1247 frames[count].size = pkt_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001248 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001249 ++count;
1250 }
1251
1252 *frame_cnt = count;
1253 return PJ_SUCCESS;
1254}
1255
1256/*
1257 * Encode frames.
1258 */
1259static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
1260 const struct pjmedia_frame *input,
1261 unsigned output_buf_len,
1262 struct pjmedia_frame *output)
1263{
1264 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001265 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001266 unsigned samples_per_frame;
1267 unsigned nsamples;
1268 pj_size_t tx = 0;
1269 pj_int16_t *pcm_in = (pj_int16_t*)input->buf;
Benny Prijonob1339242008-08-21 20:58:55 +00001270 pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001271 pj_uint8_t pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001272
1273 /* Invoke external VAD if codec has no internal VAD */
1274 if (codec_data->vad && codec_data->vad_enabled) {
1275 pj_bool_t is_silence;
1276 pj_int32_t silence_duration;
1277
1278 silence_duration = pj_timestamp_diff32(&codec_data->last_tx,
1279 &input->timestamp);
1280
1281 is_silence = pjmedia_silence_det_detect(codec_data->vad,
1282 (const pj_int16_t*) input->buf,
1283 (input->size >> 1),
1284 NULL);
1285 if (is_silence &&
1286 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001287 silence_duration < (PJMEDIA_CODEC_MAX_SILENCE_PERIOD *
1288 (int)ippc->clock_rate / 1000))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001289 {
1290 output->type = PJMEDIA_FRAME_TYPE_NONE;
1291 output->buf = NULL;
1292 output->size = 0;
1293 output->timestamp = input->timestamp;
1294 return PJ_SUCCESS;
1295 } else {
1296 codec_data->last_tx = input->timestamp;
1297 }
1298 }
1299
1300 nsamples = input->size >> 1;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001301 samples_per_frame = ippc->samples_per_frame;
1302 pt = ippc->pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001303
1304 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
1305 PJMEDIA_CODEC_EPCMFRMINLEN);
1306
1307 /* Encode the frames */
1308 while (nsamples >= samples_per_frame) {
1309 USC_PCMStream in;
1310 USC_Bitstream out;
1311
1312 in.bitrate = codec_data->info->params.modes.bitrate;
1313 in.nbytes = samples_per_frame << 1;
1314 in.pBuffer = (char*)pcm_in;
1315 in.pcmType.bitPerSample = codec_data->info->params.pcmType.bitPerSample;
1316 in.pcmType.nChannels = codec_data->info->params.pcmType.nChannels;
1317 in.pcmType.sample_frequency = codec_data->info->params.pcmType.sample_frequency;
1318
Benny Prijonob1339242008-08-21 20:58:55 +00001319 out.pBuffer = (char*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001320
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001321#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001322 /* For AMR: reserve two octets for AMR frame info */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001323 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001324 out.pBuffer += 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001325 }
1326#endif
1327
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001328 if (USC_NoError != ippc->fxns->Encode(codec_data->enc, &in, &out)) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001329 break;
1330 }
1331
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001332#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001333 /* For AMR: put info (frametype, degraded, last frame, mode) in the
1334 * first two octets for payload packing.
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001335 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001336 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001337 pj_uint16_t *info = (pj_uint16_t*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001338
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001339 /* Two octets for AMR frame info, 0=LSB:
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001340 * bit 0-3 : frame type
1341 * bit 6 : last frame flag
1342 * bit 7 : quality flag
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001343 * bit 8-11 : mode
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001344 */
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001345 out.nbytes += 2;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001346 if (out.frametype == 0 || out.frametype == 4 ||
1347 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 5) ||
1348 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 6))
1349 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001350 /* Speech frame type */
1351 *info = (char)pjmedia_codec_amr_get_mode(out.bitrate);
1352 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001353 if (out.frametype == 5 || out.frametype == 6)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001354 *info |= 0x80;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001355 } else if (out.frametype == 1 || out.frametype == 2 ||
1356 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 6) ||
1357 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 7))
1358 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001359 /* SID frame type */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001360 *info = (pj_uint8_t)(pt == PJMEDIA_RTP_PT_AMRWB? 9 : 8);
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001361 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001362 if (out.frametype == 6 || out.frametype == 7)
1363 *info |= 0x80;
1364 } else {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001365 /* Untransmited */
1366 *info = 15;
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001367 out.nbytes = 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001368 }
1369
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001370 /* Mode */
1371 *info |= (char)pjmedia_codec_amr_get_mode(out.bitrate) << 8;
1372
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001373 /* Last frame flag */
1374 if (nsamples == samples_per_frame)
1375 *info |= 0x40;
1376 }
Nanang Izzuddin7dd32682008-08-19 11:23:33 +00001377#endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001378
1379 pcm_in += samples_per_frame;
1380 nsamples -= samples_per_frame;
1381 tx += out.nbytes;
1382 bits_out += out.nbytes;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001383
1384#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddine3a6fca2008-08-27 13:15:25 +00001385 if (pt == PJMEDIA_RTP_PT_G729) {
1386 if (out.frametype == 1) {
1387 /* SID */
1388 break;
1389 } else if (out.frametype == 0) {
1390 /* Untransmitted */
1391 tx -= out.nbytes;
1392 break;
1393 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001394 }
1395#endif
1396
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001397 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001398
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001399 if (ippc->pack != NULL) {
1400 ippc->pack(codec_data, output->buf, &tx, output_buf_len);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001401 }
1402
1403 /* Check if we don't need to transmit the frame (DTX) */
1404 if (tx == 0) {
1405 output->buf = NULL;
1406 output->size = 0;
1407 output->timestamp.u64 = input->timestamp.u64;
1408 output->type = PJMEDIA_FRAME_TYPE_NONE;
1409 return PJ_SUCCESS;
1410 }
1411
1412 output->size = tx;
1413 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1414 output->timestamp = input->timestamp;
1415
1416 return PJ_SUCCESS;
1417}
1418
1419/*
1420 * Decode frame.
1421 */
1422static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
1423 const struct pjmedia_frame *input,
1424 unsigned output_buf_len,
1425 struct pjmedia_frame *output)
1426{
1427 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001428 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001429 unsigned samples_per_frame;
1430 USC_PCMStream out;
1431 USC_Bitstream in;
1432 pj_uint8_t pt;
1433
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001434 pt = ippc->pt;
1435 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001436
1437 PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
1438 PJMEDIA_CODEC_EPCMTOOSHORT);
1439
1440 if (input->type == PJMEDIA_FRAME_TYPE_AUDIO) {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001441 if (ippc->predecode) {
1442 ippc->predecode(codec_data, input, &in);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001443 } else {
1444 /* Most IPP codecs have frametype==0 for speech frame */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001445 in.pBuffer = (char*)input->buf;
1446 in.nbytes = input->size;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001447 in.frametype = 0;
1448 in.bitrate = codec_data->info->params.modes.bitrate;
1449 }
1450
1451 out.pBuffer = output->buf;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001452 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001453
1454 if (input->type != PJMEDIA_FRAME_TYPE_AUDIO ||
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001455 USC_NoError != ippc->fxns->Decode(codec_data->dec, &in, &out))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001456 {
1457 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1458 output->size = samples_per_frame << 1;
1459 output->timestamp.u64 = input->timestamp.u64;
1460 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1461 return PJ_SUCCESS;
1462 }
1463
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001464#if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001465 /* For G.726: amplify decoding result (USC G.726 encoder deamplified it) */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001466 if (pt == PJMEDIA_RTP_PT_G726_16 || pt == PJMEDIA_RTP_PT_G726_24 ||
1467 pt == PJMEDIA_RTP_PT_G726_32 || pt == PJMEDIA_RTP_PT_G726_40)
1468 {
1469 unsigned i;
1470 pj_int16_t *s = (pj_int16_t*)output->buf;
1471
1472 for (i = 0; i < samples_per_frame; ++i)
1473 s[i] <<= 2;
1474 }
1475#endif
1476
1477 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1478 output->size = samples_per_frame << 1;
1479 output->timestamp.u64 = input->timestamp.u64;
1480
1481 /* Invoke external PLC if codec has no internal PLC */
1482 if (codec_data->plc && codec_data->plc_enabled)
1483 pjmedia_plc_save(codec_data->plc, (pj_int16_t*)output->buf);
1484
1485 return PJ_SUCCESS;
1486}
1487
1488/*
1489 * Recover lost frame.
1490 */
1491static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
1492 unsigned output_buf_len,
1493 struct pjmedia_frame *output)
1494{
1495 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001496 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001497 unsigned samples_per_frame;
1498
1499 PJ_UNUSED_ARG(output_buf_len);
1500
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001501 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001502
1503 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1504 output->size = samples_per_frame << 1;
1505
1506 if (codec_data->plc_enabled) {
1507 if (codec_data->plc) {
1508 pjmedia_plc_generate(codec_data->plc, (pj_int16_t*)output->buf);
1509 } else {
1510 USC_PCMStream out;
1511 out.pBuffer = output->buf;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001512 ippc->fxns->Decode(codec_data->dec, NULL, &out);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001513 }
1514 } else {
1515 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1516 }
1517
1518 return PJ_SUCCESS;
1519}
1520
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001521
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001522#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_IPP_LIBS
1523# pragma comment( lib, "ippcore.lib")
1524# pragma comment( lib, "ipps.lib")
1525# pragma comment( lib, "ippsc.lib")
1526# pragma comment( lib, "ippsr.lib")
Benny Prijonoc543e9e2009-01-03 12:19:53 +00001527//# pragma comment( lib, "ippcorel.lib")
1528//# pragma comment( lib, "ippsemerged.lib")
1529//# pragma comment( lib, "ippsmerged.lib")
1530//# pragma comment( lib, "ippscemerged.lib")
1531//# pragma comment( lib, "ippscmerged.lib")
1532//# pragma comment( lib, "ippsremerged.lib")
1533//# pragma comment( lib, "ippsrmerged.lib")
Benny Prijonoe1e6d512009-01-02 15:17:47 +00001534# if defined(IPP_VERSION_MAJOR) && IPP_VERSION_MAJOR>=6
1535# pragma comment( lib, "speech.lib")
1536# else
1537# pragma comment( lib, "usc.lib")
1538# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001539#endif
1540
1541
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001542#endif /* PJMEDIA_HAS_INTEL_IPP */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001543