blob: 3dfb9e8027bb94507edf8919afd7a671b1bdd4ce [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 Izzuddin18a9ef12009-06-02 12:38:15 +0000573
574 PJ_LOG(4,(THIS_FILE, "AMR%s switched encoding mode to: %d (%dbps)",
575 (s->enc_setting.amr_nb?"":"-WB"),
576 s->enc_mode,
577 codec_data->info->params.modes.bitrate));
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000578 }
579
580 return PJ_SUCCESS;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000581}
582
583#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_AMR */
584
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000585
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000586#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
587
588static void predecode_g7221( ipp_private_t *codec_data,
589 const pjmedia_frame *rtp_frame,
590 USC_Bitstream *usc_frame)
591{
592 usc_frame->pBuffer = (char*)rtp_frame->buf;
593 usc_frame->nbytes = rtp_frame->size;
594 usc_frame->frametype = 0;
595 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
596
597#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
598 {
599 pj_uint16_t *p, *p_end;
600
601 p = (pj_uint16_t*)rtp_frame->buf;
602 p_end = p + rtp_frame->size/2;
603 while (p < p_end) {
604 *p = pj_ntohs(*p);
605 ++p;
606 }
607 }
608#endif
609}
610
611static pj_status_t pack_g7221( ipp_private_t *codec_data, void *pkt,
612 pj_size_t *pkt_size, pj_size_t max_pkt_size)
613{
614 PJ_UNUSED_ARG(codec_data);
615 PJ_UNUSED_ARG(max_pkt_size);
616
617#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
618 {
619 pj_uint16_t *p, *p_end;
620
621 p = (pj_uint16_t*)pkt;
622 p_end = p + *pkt_size/2;
623 while (p < p_end) {
624 *p = pj_htons(*p);
625 ++p;
626 }
627 }
628#else
629 PJ_UNUSED_ARG(pkt);
630 PJ_UNUSED_ARG(pkt_size);
631#endif
632
633 return PJ_SUCCESS;
634}
635
636#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1 */
637
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000638/*
639 * Initialize and register IPP codec factory to pjmedia endpoint.
640 */
641PJ_DEF(pj_status_t) pjmedia_codec_ipp_init( pjmedia_endpt *endpt )
642{
643 pjmedia_codec_mgr *codec_mgr;
644 pj_status_t status;
645
646 if (ipp_factory.pool != NULL) {
647 /* Already initialized. */
648 return PJ_SUCCESS;
649 }
650
651 /* Create IPP codec factory. */
652 ipp_factory.base.op = &ipp_factory_op;
653 ipp_factory.base.factory_data = NULL;
654 ipp_factory.endpt = endpt;
655
656 ipp_factory.pool = pjmedia_endpt_create_pool(endpt, "IPP codecs", 4000, 4000);
657 if (!ipp_factory.pool)
658 return PJ_ENOMEM;
659
660 /* Create mutex. */
661 status = pj_mutex_create_simple(ipp_factory.pool, "IPP codecs",
662 &ipp_factory.mutex);
663 if (status != PJ_SUCCESS)
664 goto on_error;
665
666 /* Get the codec manager. */
667 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
668 if (!codec_mgr) {
669 status = PJ_EINVALIDOP;
670 goto on_error;
671 }
672
673 /* Register codec factory to endpoint. */
674 status = pjmedia_codec_mgr_register_factory(codec_mgr,
675 &ipp_factory.base);
676 if (status != PJ_SUCCESS)
677 goto on_error;
678
679 /* Done. */
680 return PJ_SUCCESS;
681
682on_error:
683 pj_pool_release(ipp_factory.pool);
684 ipp_factory.pool = NULL;
685 return status;
686}
687
688/*
689 * Unregister IPP codecs factory from pjmedia endpoint.
690 */
691PJ_DEF(pj_status_t) pjmedia_codec_ipp_deinit(void)
692{
693 pjmedia_codec_mgr *codec_mgr;
694 pj_status_t status;
695
696 if (ipp_factory.pool == NULL) {
697 /* Already deinitialized */
698 return PJ_SUCCESS;
699 }
700
701 pj_mutex_lock(ipp_factory.mutex);
702
703 /* Get the codec manager. */
704 codec_mgr = pjmedia_endpt_get_codec_mgr(ipp_factory.endpt);
705 if (!codec_mgr) {
706 pj_pool_release(ipp_factory.pool);
707 ipp_factory.pool = NULL;
708 return PJ_EINVALIDOP;
709 }
710
711 /* Unregister IPP codecs factory. */
712 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
713 &ipp_factory.base);
714
715 /* Destroy mutex. */
716 pj_mutex_destroy(ipp_factory.mutex);
717
718 /* Destroy pool. */
719 pj_pool_release(ipp_factory.pool);
720 ipp_factory.pool = NULL;
721
722 return status;
723}
724
725/*
726 * Check if factory can allocate the specified codec.
727 */
728static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
729 const pjmedia_codec_info *info )
730{
731 unsigned i;
732
733 PJ_UNUSED_ARG(factory);
734
735 /* Type MUST be audio. */
736 if (info->type != PJMEDIA_TYPE_AUDIO)
737 return PJMEDIA_CODEC_EUNSUP;
738
739 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
740 pj_str_t name = pj_str((char*)ipp_codec[i].name);
741 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
742 (info->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
743 (info->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
744 (ipp_codec[i].enabled))
745 {
746 return PJ_SUCCESS;
747 }
748 }
749
750 /* Unsupported, or mode is disabled. */
751 return PJMEDIA_CODEC_EUNSUP;
752}
753
754/*
755 * Generate default attribute.
756 */
757static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
758 const pjmedia_codec_info *id,
759 pjmedia_codec_param *attr )
760{
761 unsigned i;
762
763 PJ_ASSERT_RETURN(factory==&ipp_factory.base, PJ_EINVAL);
764
765 pj_bzero(attr, sizeof(pjmedia_codec_param));
766
767 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
768 pj_str_t name = pj_str((char*)ipp_codec[i].name);
769 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
770 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000771 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
772 (id->pt == (unsigned)ipp_codec[i].pt))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000773 {
774 attr->info.pt = (pj_uint8_t)id->pt;
775 attr->info.channel_cnt = ipp_codec[i].channel_count;
776 attr->info.clock_rate = ipp_codec[i].clock_rate;
777 attr->info.avg_bps = ipp_codec[i].def_bitrate;
778 attr->info.max_bps = ipp_codec[i].max_bitrate;
779 attr->info.pcm_bits_per_sample = 16;
780 attr->info.frm_ptime = (pj_uint16_t)
781 (ipp_codec[i].samples_per_frame * 1000 /
782 ipp_codec[i].channel_count /
783 ipp_codec[i].clock_rate);
784 attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
785
786 /* Default flags. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000787 attr->setting.plc = 1;
788 attr->setting.penh= 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000789 attr->setting.vad = 1;
790 attr->setting.cng = attr->setting.vad;
791 attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
792
793 if (attr->setting.vad == 0) {
794#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
795 if (id->pt == PJMEDIA_RTP_PT_G729) {
796 /* Signal G729 Annex B is being disabled */
797 attr->setting.dec_fmtp.cnt = 1;
798 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
799 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
800 }
801#endif
802 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000803
804 return PJ_SUCCESS;
805 }
806 }
807
808 return PJMEDIA_CODEC_EUNSUP;
809}
810
811/*
812 * Enum codecs supported by this factory.
813 */
814static pj_status_t ipp_enum_codecs(pjmedia_codec_factory *factory,
815 unsigned *count,
816 pjmedia_codec_info codecs[])
817{
818 unsigned max;
819 unsigned i;
820
821 PJ_UNUSED_ARG(factory);
822 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
823
824 max = *count;
825
826 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(ipp_codec) && *count < max; ++i)
827 {
828 if (!ipp_codec[i].enabled)
829 continue;
830
831 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
832 codecs[*count].encoding_name = pj_str((char*)ipp_codec[i].name);
833 codecs[*count].pt = ipp_codec[i].pt;
834 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
835 codecs[*count].clock_rate = ipp_codec[i].clock_rate;
836 codecs[*count].channel_cnt = ipp_codec[i].channel_count;
837
838 ++*count;
839 }
840
841 return PJ_SUCCESS;
842}
843
844/*
845 * Allocate a new codec instance.
846 */
847static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
848 const pjmedia_codec_info *id,
849 pjmedia_codec **p_codec)
850{
851 ipp_private_t *codec_data;
852 pjmedia_codec *codec;
853 int idx;
854 pj_pool_t *pool;
855 unsigned i;
856
857 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
858 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
859
860 pj_mutex_lock(ipp_factory.mutex);
861
862 /* Find codec's index */
863 idx = -1;
864 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
865 pj_str_t name = pj_str((char*)ipp_codec[i].name);
866 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
867 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
868 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
869 (ipp_codec[i].enabled))
870 {
871 idx = i;
872 break;
873 }
874 }
875 if (idx == -1) {
876 *p_codec = NULL;
877 return PJMEDIA_CODEC_EFAILED;
878 }
879
880 /* Create pool for codec instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000881 pool = pjmedia_endpt_create_pool(ipp_factory.endpt, "IPPcodec", 512, 512);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000882 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
883 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
884 codec->op = &ipp_op;
885 codec->factory = factory;
886 codec->codec_data = PJ_POOL_ZALLOC_T(pool, ipp_private_t);
887 codec_data = (ipp_private_t*) codec->codec_data;
888
889 /* Create PLC if codec has no internal PLC */
890 if (!ipp_codec[idx].has_native_plc) {
891 pj_status_t status;
892 status = pjmedia_plc_create(pool, ipp_codec[idx].clock_rate,
893 ipp_codec[idx].samples_per_frame, 0,
894 &codec_data->plc);
895 if (status != PJ_SUCCESS) {
896 pj_pool_release(pool);
897 pj_mutex_unlock(ipp_factory.mutex);
898 return status;
899 }
900 }
901
902 /* Create silence detector if codec has no internal VAD */
903 if (!ipp_codec[idx].has_native_vad) {
904 pj_status_t status;
905 status = pjmedia_silence_det_create(pool,
906 ipp_codec[idx].clock_rate,
907 ipp_codec[idx].samples_per_frame,
908 &codec_data->vad);
909 if (status != PJ_SUCCESS) {
910 pj_pool_release(pool);
911 pj_mutex_unlock(ipp_factory.mutex);
912 return status;
913 }
914 }
915
916 codec_data->pool = pool;
917 codec_data->codec_idx = idx;
918
919 pj_mutex_unlock(ipp_factory.mutex);
920
921 *p_codec = codec;
922 return PJ_SUCCESS;
923}
924
925/*
926 * Free codec.
927 */
928static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
929 pjmedia_codec *codec )
930{
931 ipp_private_t *codec_data;
932
933 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
934 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
935
936 /* Close codec, if it's not closed. */
937 codec_data = (ipp_private_t*) codec->codec_data;
938 if (codec_data->enc != NULL || codec_data->dec != NULL) {
939 ipp_codec_close(codec);
940 }
941
942 pj_pool_release(codec_data->pool);
943
944 return PJ_SUCCESS;
945}
946
947/*
948 * Init codec.
949 */
950static pj_status_t ipp_codec_init( pjmedia_codec *codec,
951 pj_pool_t *pool )
952{
953 PJ_UNUSED_ARG(codec);
954 PJ_UNUSED_ARG(pool);
955 return PJ_SUCCESS;
956}
957
958/*
959 * Open codec.
960 */
961static pj_status_t ipp_codec_open( pjmedia_codec *codec,
962 pjmedia_codec_param *attr )
963{
964 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000965 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000966 int info_size;
967 pj_pool_t *pool;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000968 int i, j;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000969 USC_MemBank *membanks;
970 int nb_membanks;
971
972 pool = codec_data->pool;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000973
974 /* Get the codec info size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000975 if (USC_NoError != ippc->fxns->std.GetInfoSize(&info_size)) {
976 PJ_LOG(1,(THIS_FILE, "Error getting codec info size"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000977 goto on_error;
978 }
979 /* Get the codec info */
980 codec_data->info = pj_pool_zalloc(pool, info_size);
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000981 if (USC_NoError != ippc->fxns->std.GetInfo((USC_Handle)NULL,
982 codec_data->info))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000983 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000984 PJ_LOG(1,(THIS_FILE, "Error getting codec info"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000985 goto on_error;
986 }
987
988 /* PREPARING THE ENCODER */
989
990 /* Setting the encoder params */
991 codec_data->info->params.direction = USC_ENCODE;
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000992 codec_data->info->params.modes.vad = attr->setting.vad &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000993 ippc->has_native_vad;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000994 codec_data->info->params.modes.bitrate = attr->info.avg_bps;
995 codec_data->info->params.law = 0; /* Linear PCM input */
996
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000997#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
998 if (ippc->pt == PJMEDIA_RTP_PT_G729) {
999 /* Check if G729 Annex B is signaled to be disabled */
1000 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
1001 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
1002 {
1003 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
1004 codec_data->info->params.modes.vad = 0;
1005 break;
1006 }
1007 }
1008 }
1009#endif
1010
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001011 /* Get number of memory blocks needed by the encoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001012 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1013 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001014 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001015 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001016 goto on_error;
1017 }
1018
1019 /* Allocate memory blocks table */
1020 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1021 sizeof(USC_MemBank) * nb_membanks);
1022 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001023 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1024 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001025 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001026 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001027 goto on_error;
1028 }
1029
1030 /* Allocate memory for each block */
1031 for (i = 0; i < nb_membanks; i++) {
1032 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1033 }
1034
1035 /* Create encoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001036 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1037 membanks,
1038 &codec_data->enc))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001039 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001040 PJ_LOG(1,(THIS_FILE, "Error initializing encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001041 goto on_error;
1042 }
1043
1044 /* PREPARING THE DECODER */
1045
1046 /* Setting the decoder params */
1047 codec_data->info->params.direction = USC_DECODE;
1048
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001049 /* Not sure if VAD affects decoder, just try to be safe */
Benny Prijono329d6382009-05-29 13:04:03 +00001050 //codec_data->info->params.modes.vad = ippc->has_native_vad;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001051
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001052 /* Get number of memory blocks needed by the decoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001053 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1054 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001055 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001056 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001057 goto on_error;
1058 }
1059
1060 /* Allocate memory blocks table */
1061 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1062 sizeof(USC_MemBank) * nb_membanks);
1063 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001064 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1065 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001066 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001067 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001068 goto on_error;
1069 }
1070
1071 /* Allocate memory for each block */
1072 for (i = 0; i < nb_membanks; i++) {
1073 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1074 }
1075
1076 /* Create decoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001077 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1078 membanks, &codec_data->dec))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001079 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001080 PJ_LOG(1,(THIS_FILE, "Error initializing decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001081 goto on_error;
1082 }
1083
1084 /* Update codec info */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001085 ippc->fxns->std.GetInfo((USC_Handle)codec_data->enc, codec_data->info);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001086
1087 /* Get bitstream size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001088 i = codec_data->info->params.modes.bitrate * ippc->samples_per_frame;
1089 j = ippc->clock_rate << 3;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001090 codec_data->frame_size = (pj_uint16_t)(i / j);
1091 if (i % j) ++codec_data->frame_size;
1092
1093 codec_data->vad_enabled = (attr->setting.vad != 0);
1094 codec_data->plc_enabled = (attr->setting.plc != 0);
1095
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001096#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
1097 /* Init AMR settings */
1098 if (ippc->pt == PJMEDIA_RTP_PT_AMR || ippc->pt == PJMEDIA_RTP_PT_AMRWB) {
1099 amr_settings_t *s;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001100 pj_uint8_t octet_align = 0;
Benny Prijono329d6382009-05-29 13:04:03 +00001101 pj_int8_t enc_mode = -1;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001102
Benny Prijono329d6382009-05-29 13:04:03 +00001103 /* Check AMR specific attributes */
1104
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001105 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
Benny Prijono329d6382009-05-29 13:04:03 +00001106 /* octet-align, one of the parameters that must have same value
1107 * in offer & answer (RFC 4867 Section 8.3.1). Just check fmtp
1108 * in the decoder side, since it's value is guaranteed to fulfil
1109 * above requirement (by SDP negotiator).
1110 */
1111 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
1112
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001113 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
1114 &STR_FMTP_OCTET_ALIGN) == 0)
1115 {
1116 octet_align=(pj_uint8_t)
Benny Prijono329d6382009-05-29 13:04:03 +00001117 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
1118 break;
1119 }
1120 }
1121 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
1122 /* mode-set */
1123 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
1124
1125 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
1126 &STR_FMTP_MODE_SET) == 0)
1127 {
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001128 const char *p;
1129 pj_size_t l;
Benny Prijono329d6382009-05-29 13:04:03 +00001130
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001131 /* Get the highest value, for better quality. */
1132 p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
1133 l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
Benny Prijono329d6382009-05-29 13:04:03 +00001134
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001135 while (l--) {
1136 if ((ippc->pt == PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') ||
1137 (ippc->pt == PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8'))
1138 {
1139 pj_int8_t tmp = *p - '0';
1140 if (enc_mode < tmp)
1141 enc_mode = tmp;
1142 }
1143 ++p;
Benny Prijono329d6382009-05-29 13:04:03 +00001144 }
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001145 break;
1146 }
1147 }
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001148
Benny Prijono329d6382009-05-29 13:04:03 +00001149 /* Initialize AMR specific settings */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001150 s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
1151 codec_data->codec_setting = s;
1152
Benny Prijono6b6fce12009-03-17 10:13:30 +00001153 s->enc_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001154 s->enc_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001155 s->enc_setting.reorder = PJ_TRUE;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001156 s->enc_setting.cmr = 15;
Benny Prijono329d6382009-05-29 13:04:03 +00001157
Benny Prijono6b6fce12009-03-17 10:13:30 +00001158 s->dec_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001159 s->dec_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001160 s->dec_setting.reorder = PJ_TRUE;
Benny Prijono329d6382009-05-29 13:04:03 +00001161
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001162 if (enc_mode != -1) {
1163 s->enc_mode = enc_mode;
1164 } else {
1165 s->enc_mode = pjmedia_codec_amr_get_mode(
Benny Prijono329d6382009-05-29 13:04:03 +00001166 codec_data->info->params.modes.bitrate);
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001167 }
1168
Benny Prijono329d6382009-05-29 13:04:03 +00001169 if (s->enc_mode < 0)
1170 goto on_error;
1171
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001172 /* Apply requested encoder bitrate */
1173 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
1174 pjmedia_codec_amrnb_bitrates[s->enc_mode]:
1175 pjmedia_codec_amrwb_bitrates[s->enc_mode];
1176 ippc->fxns->std.Control(&codec_data->info->params.modes,
1177 codec_data->enc);
Benny Prijono329d6382009-05-29 13:04:03 +00001178
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001179 PJ_LOG(4,(THIS_FILE, "AMR%s encoding mode: %d (%dbps)",
1180 (s->enc_setting.amr_nb?"":"-WB"),
1181 s->enc_mode,
1182 codec_data->info->params.modes.bitrate));
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001183 }
1184#endif
1185
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001186 return PJ_SUCCESS;
1187
1188on_error:
1189 return PJMEDIA_CODEC_EFAILED;
1190}
1191
1192/*
1193 * Close codec.
1194 */
1195static pj_status_t ipp_codec_close( pjmedia_codec *codec )
1196{
1197 PJ_UNUSED_ARG(codec);
1198
1199 return PJ_SUCCESS;
1200}
1201
1202
1203/*
1204 * Modify codec settings.
1205 */
1206static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
1207 const pjmedia_codec_param *attr )
1208{
1209 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001210 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001211
1212 codec_data->vad_enabled = (attr->setting.vad != 0);
1213 codec_data->plc_enabled = (attr->setting.plc != 0);
1214
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001215 if (ippc->has_native_vad) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001216 USC_Modes modes;
1217
1218 modes = codec_data->info->params.modes;
1219 modes.vad = codec_data->vad_enabled;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001220 ippc->fxns->std.Control(&modes, codec_data->enc);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001221 }
1222
1223 return PJ_SUCCESS;
1224}
1225
1226/*
1227 * Get frames in the packet.
1228 */
1229static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
1230 void *pkt,
1231 pj_size_t pkt_size,
1232 const pj_timestamp *ts,
1233 unsigned *frame_cnt,
1234 pjmedia_frame frames[])
1235{
1236 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001237 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001238 unsigned count = 0;
1239
1240 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
1241
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001242 if (ippc->parse != NULL) {
1243 return ippc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001244 }
1245
1246 while (pkt_size >= codec_data->frame_size && count < *frame_cnt) {
1247 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1248 frames[count].buf = pkt;
1249 frames[count].size = codec_data->frame_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001250 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001251
1252 pkt = ((char*)pkt) + codec_data->frame_size;
1253 pkt_size -= codec_data->frame_size;
1254
1255 ++count;
1256 }
1257
1258 if (pkt_size && count < *frame_cnt) {
1259 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1260 frames[count].buf = pkt;
1261 frames[count].size = pkt_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001262 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001263 ++count;
1264 }
1265
1266 *frame_cnt = count;
1267 return PJ_SUCCESS;
1268}
1269
1270/*
1271 * Encode frames.
1272 */
1273static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
1274 const struct pjmedia_frame *input,
1275 unsigned output_buf_len,
1276 struct pjmedia_frame *output)
1277{
1278 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001279 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001280 unsigned samples_per_frame;
1281 unsigned nsamples;
1282 pj_size_t tx = 0;
1283 pj_int16_t *pcm_in = (pj_int16_t*)input->buf;
Benny Prijonob1339242008-08-21 20:58:55 +00001284 pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001285 pj_uint8_t pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001286
1287 /* Invoke external VAD if codec has no internal VAD */
1288 if (codec_data->vad && codec_data->vad_enabled) {
1289 pj_bool_t is_silence;
1290 pj_int32_t silence_duration;
1291
1292 silence_duration = pj_timestamp_diff32(&codec_data->last_tx,
1293 &input->timestamp);
1294
1295 is_silence = pjmedia_silence_det_detect(codec_data->vad,
1296 (const pj_int16_t*) input->buf,
1297 (input->size >> 1),
1298 NULL);
1299 if (is_silence &&
1300 PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 &&
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001301 silence_duration < (PJMEDIA_CODEC_MAX_SILENCE_PERIOD *
1302 (int)ippc->clock_rate / 1000))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001303 {
1304 output->type = PJMEDIA_FRAME_TYPE_NONE;
1305 output->buf = NULL;
1306 output->size = 0;
1307 output->timestamp = input->timestamp;
1308 return PJ_SUCCESS;
1309 } else {
1310 codec_data->last_tx = input->timestamp;
1311 }
1312 }
1313
1314 nsamples = input->size >> 1;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001315 samples_per_frame = ippc->samples_per_frame;
1316 pt = ippc->pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001317
1318 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
1319 PJMEDIA_CODEC_EPCMFRMINLEN);
1320
1321 /* Encode the frames */
1322 while (nsamples >= samples_per_frame) {
1323 USC_PCMStream in;
1324 USC_Bitstream out;
1325
1326 in.bitrate = codec_data->info->params.modes.bitrate;
1327 in.nbytes = samples_per_frame << 1;
1328 in.pBuffer = (char*)pcm_in;
1329 in.pcmType.bitPerSample = codec_data->info->params.pcmType.bitPerSample;
1330 in.pcmType.nChannels = codec_data->info->params.pcmType.nChannels;
1331 in.pcmType.sample_frequency = codec_data->info->params.pcmType.sample_frequency;
1332
Benny Prijonob1339242008-08-21 20:58:55 +00001333 out.pBuffer = (char*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001334
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001335#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001336 /* For AMR: reserve two octets for AMR frame info */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001337 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001338 out.pBuffer += 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001339 }
1340#endif
1341
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001342 if (USC_NoError != ippc->fxns->Encode(codec_data->enc, &in, &out)) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001343 break;
1344 }
1345
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001346#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001347 /* For AMR: put info (frametype, degraded, last frame, mode) in the
1348 * first two octets for payload packing.
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001349 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001350 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001351 pj_uint16_t *info = (pj_uint16_t*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001352
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001353 /* Two octets for AMR frame info, 0=LSB:
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001354 * bit 0-3 : frame type
1355 * bit 6 : last frame flag
1356 * bit 7 : quality flag
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001357 * bit 8-11 : mode
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001358 */
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001359 out.nbytes += 2;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001360 if (out.frametype == 0 || out.frametype == 4 ||
1361 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 5) ||
1362 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 6))
1363 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001364 /* Speech frame type */
1365 *info = (char)pjmedia_codec_amr_get_mode(out.bitrate);
1366 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001367 if (out.frametype == 5 || out.frametype == 6)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001368 *info |= 0x80;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001369 } else if (out.frametype == 1 || out.frametype == 2 ||
1370 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 6) ||
1371 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 7))
1372 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001373 /* SID frame type */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001374 *info = (pj_uint8_t)(pt == PJMEDIA_RTP_PT_AMRWB? 9 : 8);
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001375 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001376 if (out.frametype == 6 || out.frametype == 7)
1377 *info |= 0x80;
1378 } else {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001379 /* Untransmited */
1380 *info = 15;
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001381 out.nbytes = 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001382 }
1383
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001384 /* Mode */
1385 *info |= (char)pjmedia_codec_amr_get_mode(out.bitrate) << 8;
1386
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001387 /* Last frame flag */
1388 if (nsamples == samples_per_frame)
1389 *info |= 0x40;
1390 }
Nanang Izzuddin7dd32682008-08-19 11:23:33 +00001391#endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001392
1393 pcm_in += samples_per_frame;
1394 nsamples -= samples_per_frame;
1395 tx += out.nbytes;
1396 bits_out += out.nbytes;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001397
1398#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddine3a6fca2008-08-27 13:15:25 +00001399 if (pt == PJMEDIA_RTP_PT_G729) {
1400 if (out.frametype == 1) {
1401 /* SID */
1402 break;
1403 } else if (out.frametype == 0) {
1404 /* Untransmitted */
1405 tx -= out.nbytes;
1406 break;
1407 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001408 }
1409#endif
1410
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001411 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001412
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001413 if (ippc->pack != NULL) {
1414 ippc->pack(codec_data, output->buf, &tx, output_buf_len);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001415 }
1416
1417 /* Check if we don't need to transmit the frame (DTX) */
1418 if (tx == 0) {
1419 output->buf = NULL;
1420 output->size = 0;
1421 output->timestamp.u64 = input->timestamp.u64;
1422 output->type = PJMEDIA_FRAME_TYPE_NONE;
1423 return PJ_SUCCESS;
1424 }
1425
1426 output->size = tx;
1427 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1428 output->timestamp = input->timestamp;
1429
1430 return PJ_SUCCESS;
1431}
1432
1433/*
1434 * Decode frame.
1435 */
1436static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
1437 const struct pjmedia_frame *input,
1438 unsigned output_buf_len,
1439 struct pjmedia_frame *output)
1440{
1441 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001442 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001443 unsigned samples_per_frame;
1444 USC_PCMStream out;
1445 USC_Bitstream in;
1446 pj_uint8_t pt;
1447
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001448 pt = ippc->pt;
1449 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001450
1451 PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
1452 PJMEDIA_CODEC_EPCMTOOSHORT);
1453
1454 if (input->type == PJMEDIA_FRAME_TYPE_AUDIO) {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001455 if (ippc->predecode) {
1456 ippc->predecode(codec_data, input, &in);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001457 } else {
1458 /* Most IPP codecs have frametype==0 for speech frame */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001459 in.pBuffer = (char*)input->buf;
1460 in.nbytes = input->size;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001461 in.frametype = 0;
1462 in.bitrate = codec_data->info->params.modes.bitrate;
1463 }
1464
1465 out.pBuffer = output->buf;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001466 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001467
1468 if (input->type != PJMEDIA_FRAME_TYPE_AUDIO ||
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001469 USC_NoError != ippc->fxns->Decode(codec_data->dec, &in, &out))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001470 {
1471 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1472 output->size = samples_per_frame << 1;
1473 output->timestamp.u64 = input->timestamp.u64;
1474 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1475 return PJ_SUCCESS;
1476 }
1477
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001478#if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001479 /* For G.726: amplify decoding result (USC G.726 encoder deamplified it) */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001480 if (pt == PJMEDIA_RTP_PT_G726_16 || pt == PJMEDIA_RTP_PT_G726_24 ||
1481 pt == PJMEDIA_RTP_PT_G726_32 || pt == PJMEDIA_RTP_PT_G726_40)
1482 {
1483 unsigned i;
1484 pj_int16_t *s = (pj_int16_t*)output->buf;
1485
1486 for (i = 0; i < samples_per_frame; ++i)
1487 s[i] <<= 2;
1488 }
1489#endif
1490
1491 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1492 output->size = samples_per_frame << 1;
1493 output->timestamp.u64 = input->timestamp.u64;
1494
1495 /* Invoke external PLC if codec has no internal PLC */
1496 if (codec_data->plc && codec_data->plc_enabled)
1497 pjmedia_plc_save(codec_data->plc, (pj_int16_t*)output->buf);
1498
1499 return PJ_SUCCESS;
1500}
1501
1502/*
1503 * Recover lost frame.
1504 */
1505static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
1506 unsigned output_buf_len,
1507 struct pjmedia_frame *output)
1508{
1509 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001510 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001511 unsigned samples_per_frame;
1512
1513 PJ_UNUSED_ARG(output_buf_len);
1514
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001515 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001516
1517 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1518 output->size = samples_per_frame << 1;
1519
1520 if (codec_data->plc_enabled) {
1521 if (codec_data->plc) {
1522 pjmedia_plc_generate(codec_data->plc, (pj_int16_t*)output->buf);
1523 } else {
1524 USC_PCMStream out;
1525 out.pBuffer = output->buf;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001526 ippc->fxns->Decode(codec_data->dec, NULL, &out);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001527 }
1528 } else {
1529 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1530 }
1531
1532 return PJ_SUCCESS;
1533}
1534
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001535
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001536#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_IPP_LIBS
1537# pragma comment( lib, "ippcore.lib")
1538# pragma comment( lib, "ipps.lib")
1539# pragma comment( lib, "ippsc.lib")
1540# pragma comment( lib, "ippsr.lib")
Benny Prijonoc543e9e2009-01-03 12:19:53 +00001541//# pragma comment( lib, "ippcorel.lib")
1542//# pragma comment( lib, "ippsemerged.lib")
1543//# pragma comment( lib, "ippsmerged.lib")
1544//# pragma comment( lib, "ippscemerged.lib")
1545//# pragma comment( lib, "ippscmerged.lib")
1546//# pragma comment( lib, "ippsremerged.lib")
1547//# pragma comment( lib, "ippsrmerged.lib")
Benny Prijonoe1e6d512009-01-02 15:17:47 +00001548# if defined(IPP_VERSION_MAJOR) && IPP_VERSION_MAJOR>=6
1549# pragma comment( lib, "speech.lib")
1550# else
1551# pragma comment( lib, "usc.lib")
1552# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001553#endif
1554
1555
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001556#endif /* PJMEDIA_HAS_INTEL_IPP */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001557