blob: 948c3e73c7fac47a1495f0c8543c26fda6409944 [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>
Nanang Izzuddin0b9da642009-06-02 16:28:24 +000029#include <pj/math.h>
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000030#include <pj/pool.h>
31#include <pj/string.h>
32#include <pj/os.h>
33
Nanang Izzuddin23a00b72008-08-25 13:58:25 +000034
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000035/*
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000036 * Only build this file if PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000037 */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +000038#if defined(PJMEDIA_HAS_INTEL_IPP) && PJMEDIA_HAS_INTEL_IPP != 0
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000039
40#include <usc.h>
Benny Prijonoe1e6d512009-01-02 15:17:47 +000041#include <ippversion.h>
Nanang Izzuddin493a8db2008-08-15 13:17:39 +000042
43#define THIS_FILE "ipp_codecs.c"
44
45/* Prototypes for IPP codecs factory */
46static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
47 const pjmedia_codec_info *id );
48static pj_status_t ipp_default_attr( pjmedia_codec_factory *factory,
49 const pjmedia_codec_info *id,
50 pjmedia_codec_param *attr );
51static pj_status_t ipp_enum_codecs( pjmedia_codec_factory *factory,
52 unsigned *count,
53 pjmedia_codec_info codecs[]);
54static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
55 const pjmedia_codec_info *id,
56 pjmedia_codec **p_codec);
57static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
58 pjmedia_codec *codec );
59
60/* Prototypes for IPP codecs implementation. */
61static pj_status_t ipp_codec_init( pjmedia_codec *codec,
62 pj_pool_t *pool );
63static pj_status_t ipp_codec_open( pjmedia_codec *codec,
64 pjmedia_codec_param *attr );
65static pj_status_t ipp_codec_close( pjmedia_codec *codec );
66static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
67 const pjmedia_codec_param *attr );
68static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
69 void *pkt,
70 pj_size_t pkt_size,
71 const pj_timestamp *ts,
72 unsigned *frame_cnt,
73 pjmedia_frame frames[]);
74static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
75 const struct pjmedia_frame *input,
76 unsigned output_buf_len,
77 struct pjmedia_frame *output);
78static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
79 const struct pjmedia_frame *input,
80 unsigned output_buf_len,
81 struct pjmedia_frame *output);
82static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
83 unsigned output_buf_len,
84 struct pjmedia_frame *output);
85
86/* Definition for IPP codecs operations. */
87static pjmedia_codec_op ipp_op =
88{
89 &ipp_codec_init,
90 &ipp_codec_open,
91 &ipp_codec_close,
92 &ipp_codec_modify,
93 &ipp_codec_parse,
94 &ipp_codec_encode,
95 &ipp_codec_decode,
96 &ipp_codec_recover
97};
98
99/* Definition for IPP codecs factory operations. */
100static pjmedia_codec_factory_op ipp_factory_op =
101{
102 &ipp_test_alloc,
103 &ipp_default_attr,
104 &ipp_enum_codecs,
105 &ipp_alloc_codec,
106 &ipp_dealloc_codec
107};
108
109/* IPP codecs factory */
110static struct ipp_factory {
111 pjmedia_codec_factory base;
112 pjmedia_endpt *endpt;
113 pj_pool_t *pool;
114 pj_mutex_t *mutex;
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000115 unsigned g7221_pcm_shift;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000116} ipp_factory;
117
118/* IPP codecs private data. */
119typedef struct ipp_private {
120 int codec_idx; /**< Codec index. */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000121 void *codec_setting; /**< Specific codec setting. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000122 pj_pool_t *pool; /**< Pool for each instance. */
123
124 USC_Handle enc; /**< Encoder state. */
125 USC_Handle dec; /**< Decoder state. */
126 USC_CodecInfo *info; /**< Native codec info. */
127 pj_uint16_t frame_size; /**< Bitstream frame size. */
128
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000129 pj_bool_t plc_enabled; /**< PLC enabled flag. */
130 pjmedia_plc *plc; /**< PJMEDIA PLC engine, NULL if
131 codec has internal PLC. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000132
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000133 pj_bool_t vad_enabled; /**< VAD enabled flag. */
134 pjmedia_silence_det *vad; /**< PJMEDIA VAD engine, NULL if
135 codec has internal VAD. */
136 pj_timestamp last_tx; /**< Timestamp of last transmit.*/
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000137
138 unsigned g7221_pcm_shift; /**< G722.1 PCM level adjustment*/
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000139} ipp_private_t;
140
141
142/* USC codec implementations. */
143extern USC_Fxns USC_G729AFP_Fxns;
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000144extern USC_Fxns USC_G729I_Fxns;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000145extern USC_Fxns USC_G723_Fxns;
146extern USC_Fxns USC_G726_Fxns;
147extern USC_Fxns USC_G728_Fxns;
148extern USC_Fxns USC_G722_Fxns;
149extern USC_Fxns USC_GSMAMR_Fxns;
150extern USC_Fxns USC_AMRWB_Fxns;
151extern USC_Fxns USC_AMRWBE_Fxns;
152
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000153
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000154/* CUSTOM CALLBACKS */
155
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000156/* This callback is useful for translating RTP frame into USC frame, e.g:
157 * reassigning frame attributes, reorder bitstream. Default behaviour of
158 * the translation is just setting the USC frame buffer & its size as
159 * specified in RTP frame, setting USC frame frametype to 0, setting bitrate
160 * of USC frame to bitrate info of codec_data. Implement this callback when
161 * the default behaviour is unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000162 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000163typedef void (*predecode_cb)(ipp_private_t *codec_data,
164 const pjmedia_frame *rtp_frame,
165 USC_Bitstream *usc_frame);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000166
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000167/* Parse frames from a packet. Default behaviour of frame parsing is
168 * just separating frames based on calculating frame length derived
169 * from bitrate. Implement this callback when the default behaviour is
170 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000171 */
172typedef pj_status_t (*parse_cb)(ipp_private_t *codec_data, void *pkt,
173 pj_size_t pkt_size, const pj_timestamp *ts,
174 unsigned *frame_cnt, pjmedia_frame frames[]);
175
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000176/* Pack frames into a packet. Default behaviour of packing frames is
177 * just stacking the frames with octet aligned without adding any
178 * payload header. Implement this callback when the default behaviour is
179 * unapplicable.
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000180 */
181typedef pj_status_t (*pack_cb)(ipp_private_t *codec_data, void *pkt,
182 pj_size_t *pkt_size, pj_size_t max_pkt_size);
183
184
185
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000186/* Custom callback implementations. */
187static void predecode_g723( ipp_private_t *codec_data,
188 const pjmedia_frame *rtp_frame,
189 USC_Bitstream *usc_frame);
190static pj_status_t parse_g723( ipp_private_t *codec_data, void *pkt,
191 pj_size_t pkt_size, const pj_timestamp *ts,
192 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000193
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000194static void predecode_g729( ipp_private_t *codec_data,
195 const pjmedia_frame *rtp_frame,
196 USC_Bitstream *usc_frame);
197
198static void predecode_amr( ipp_private_t *codec_data,
199 const pjmedia_frame *rtp_frame,
200 USC_Bitstream *usc_frame);
201static pj_status_t parse_amr( ipp_private_t *codec_data, void *pkt,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000202 pj_size_t pkt_size, const pj_timestamp *ts,
203 unsigned *frame_cnt, pjmedia_frame frames[]);
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000204static pj_status_t pack_amr( ipp_private_t *codec_data, void *pkt,
205 pj_size_t *pkt_size, pj_size_t max_pkt_size);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000206
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000207static void predecode_g7221( ipp_private_t *codec_data,
208 const pjmedia_frame *rtp_frame,
209 USC_Bitstream *usc_frame);
210static pj_status_t pack_g7221( ipp_private_t *codec_data, void *pkt,
211 pj_size_t *pkt_size, pj_size_t max_pkt_size);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000212
213/* IPP codec implementation descriptions. */
214static struct ipp_codec {
215 int enabled; /* Is this codec enabled? */
216 const char *name; /* Codec name. */
217 pj_uint8_t pt; /* Payload type. */
218 USC_Fxns *fxns; /* USC callback functions. */
219 unsigned clock_rate; /* Codec's clock rate. */
220 unsigned channel_count; /* Codec's channel count. */
221 unsigned samples_per_frame; /* Codec's samples count. */
222
223 unsigned def_bitrate; /* Default bitrate of this codec. */
224 unsigned max_bitrate; /* Maximum bitrate of this codec. */
225 pj_uint8_t frm_per_pkt; /* Default num of frames per packet.*/
226 int has_native_vad; /* Codec has internal VAD? */
227 int has_native_plc; /* Codec has internal PLC? */
228
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000229 predecode_cb predecode; /* Callback to translate RTP frame
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000230 into USC frame. */
231 parse_cb parse; /* Callback to parse bitstream. */
232 pack_cb pack; /* Callback to pack bitstream. */
233
234 pjmedia_codec_fmtp dec_fmtp; /* Decoder's fmtp params. */
235}
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000236
237ipp_codec[] =
238{
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000239# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Benny Prijono329d6382009-05-29 13:04:03 +0000240 /* AMR-NB SID seems to produce noise, so let's just disable its VAD. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000241 {1, "AMR", PJMEDIA_RTP_PT_AMR, &USC_GSMAMR_Fxns, 8000, 1, 160,
Benny Prijono329d6382009-05-29 13:04:03 +0000242 7400, 12200, 2, 0, 1,
243 &predecode_amr, &parse_amr, &pack_amr,
244 {1, {{{"octet-align", 11}, {"1", 1}}} }
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000245 },
246# endif
247
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000248# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMRWB
249 {1, "AMR-WB", PJMEDIA_RTP_PT_AMRWB, &USC_AMRWB_Fxns, 16000, 1, 320,
250 15850, 23850, 1, 1, 1,
Benny Prijono329d6382009-05-29 13:04:03 +0000251 &predecode_amr, &parse_amr, &pack_amr,
252 {1, {{{"octet-align", 11}, {"1", 1}}} }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000253 },
254# endif
255
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000256# if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000257# if defined(PJ_HAS_FLOATING_POINT) && (PJ_HAS_FLOATING_POINT != 0)
258 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729AFP_Fxns, 8000, 1, 80,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000259 8000, 11800, 2, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000260 &predecode_g729, NULL, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000261 },
Nanang Izzuddin762a5bd2008-09-16 14:11:09 +0000262# else
263 {1, "G729", PJMEDIA_RTP_PT_G729, &USC_G729I_Fxns, 8000, 1, 80,
264 8000, 11800, 2, 1, 1,
265 &predecode_g729, NULL, NULL
266 },
267# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000268# endif
269
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000270# if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000271 /* This is actually G.723.1 */
272 {1, "G723", PJMEDIA_RTP_PT_G723, &USC_G723_Fxns, 8000, 1, 240,
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000273 6300, 6300, 1, 1, 1,
Nanang Izzuddindf361e02008-08-16 06:46:08 +0000274 &predecode_g723, &parse_g723, NULL
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000275 },
276# endif
277
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000278# if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000279 {0, "G726-16", PJMEDIA_RTP_PT_G726_16, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000280 16000, 16000, 2, 0, 0,
281 NULL, NULL, NULL
282 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000283 {0, "G726-24", PJMEDIA_RTP_PT_G726_24, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000284 24000, 24000, 2, 0, 0,
285 NULL, NULL, NULL
286 },
287 {1, "G726-32", PJMEDIA_RTP_PT_G726_32, &USC_G726_Fxns, 8000, 1, 80,
288 32000, 32000, 2, 0, 0,
289 NULL, NULL, NULL
290 },
Nanang Izzuddinf216f822008-08-15 18:35:50 +0000291 {0, "G726-40", PJMEDIA_RTP_PT_G726_40, &USC_G726_Fxns, 8000, 1, 80,
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000292 40000, 40000, 2, 0, 0,
293 NULL, NULL, NULL
294 },
Nanang Izzuddincf4d1412010-06-07 05:23:56 +0000295 /* Old definition of G726-32 */
296 {1, "G721", PJMEDIA_RTP_PT_G721, &USC_G726_Fxns, 8000, 1, 80,
297 32000, 32000, 2, 0, 0,
298 NULL, NULL, NULL
299 },
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000300# endif
301
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000302# if PJMEDIA_HAS_INTEL_IPP_CODEC_G728
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000303 {1, "G728", PJMEDIA_RTP_PT_G728, &USC_G728_Fxns, 8000, 1, 80,
304 16000, 16000, 2, 0, 1,
305 NULL, NULL, NULL
306 },
307# endif
308
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000309# if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000310 {0, "G7221", PJMEDIA_RTP_PT_G722_1_16, &USC_G722_Fxns, 16000, 1, 320,
311 16000, 16000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000312 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000313 {1, {{{"bitrate", 7}, {"16000", 5}}} }
314 },
315 {1, "G7221", PJMEDIA_RTP_PT_G722_1_24, &USC_G722_Fxns, 16000, 1, 320,
316 24000, 24000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000317 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000318 {1, {{{"bitrate", 7}, {"24000", 5}}} }
319 },
320 {1, "G7221", PJMEDIA_RTP_PT_G722_1_32, &USC_G722_Fxns, 16000, 1, 320,
321 32000, 32000, 1, 0, 1,
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000322 predecode_g7221, NULL, pack_g7221,
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000323 {1, {{{"bitrate", 7}, {"32000", 5}}} }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000324 },
325# endif
326};
327
328
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000329#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
330
331static void predecode_g729( ipp_private_t *codec_data,
332 const pjmedia_frame *rtp_frame,
333 USC_Bitstream *usc_frame)
334{
335 switch (rtp_frame->size) {
336 case 2:
337 /* SID */
338 usc_frame->frametype = 1;
339 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
340 break;
341 case 8:
342 /* G729D */
343 usc_frame->frametype = 2;
344 usc_frame->bitrate = 6400;
345 break;
346 case 10:
347 /* G729 */
348 usc_frame->frametype = 3;
349 usc_frame->bitrate = 8000;
350 break;
351 case 15:
352 /* G729E */
353 usc_frame->frametype = 4;
354 usc_frame->bitrate = 11800;
355 break;
356 default:
357 usc_frame->frametype = 0;
358 usc_frame->bitrate = 0;
359 break;
360 }
361
362 usc_frame->pBuffer = rtp_frame->buf;
363 usc_frame->nbytes = rtp_frame->size;
364}
365
366#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G729 */
367
368
369#if PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1
370
371static void predecode_g723( ipp_private_t *codec_data,
372 const pjmedia_frame *rtp_frame,
373 USC_Bitstream *usc_frame)
374{
375 int i, HDR = 0;
376 pj_uint8_t *f = (pj_uint8_t*)rtp_frame->buf;
377
378 PJ_UNUSED_ARG(codec_data);
379
380 for (i = 0; i < 2; ++i){
381 int tmp;
382 tmp = (f[0] >> (i & 0x7)) & 1;
383 HDR += tmp << i ;
384 }
385
386 usc_frame->pBuffer = rtp_frame->buf;
387 usc_frame->nbytes = rtp_frame->size;
388 usc_frame->bitrate = HDR == 0? 6300 : 5300;
389 usc_frame->frametype = 0;
390}
391
392static pj_status_t parse_g723(ipp_private_t *codec_data, void *pkt,
393 pj_size_t pkt_size, const pj_timestamp *ts,
394 unsigned *frame_cnt, pjmedia_frame frames[])
395{
396 unsigned count = 0;
397 pj_uint8_t *f = (pj_uint8_t*)pkt;
398
399 while (pkt_size && count < *frame_cnt) {
400 int framesize, i, j;
401 int HDR = 0;
402
403 for (i = 0; i < 2; ++i){
404 j = (f[0] >> (i & 0x7)) & 1;
405 HDR += j << i ;
406 }
407
408 if (HDR == 0)
409 framesize = 24;
410 else if (HDR == 1)
411 framesize = 20;
412 else if (HDR == 2)
413 framesize = 4;
414 else if (HDR == 3)
415 framesize = 1;
416 else {
417 pj_assert(!"Unknown G723.1 frametype, packet may be corrupted!");
418 return PJMEDIA_CODEC_EINMODE;
419 }
420
421 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
422 frames[count].buf = f;
423 frames[count].size = framesize;
424 frames[count].timestamp.u64 = ts->u64 + count *
425 ipp_codec[codec_data->codec_idx].samples_per_frame;
426
427 f += framesize;
428 pkt_size -= framesize;
429
430 ++count;
431 }
432
433 *frame_cnt = count;
434 return PJ_SUCCESS;
435}
436
437#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1 */
438
439
440#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
441
442#include <pjmedia-codec/amr_helper.h>
443
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000444typedef struct amr_settings_t {
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000445 pjmedia_codec_amr_pack_setting enc_setting;
446 pjmedia_codec_amr_pack_setting dec_setting;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000447 pj_int8_t enc_mode;
448} amr_settings_t;
449
450
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000451/* Rearrange AMR bitstream and convert RTP frame into USC frame:
452 * - make the start_bit to be 0
453 * - if it is speech frame, reorder bitstream from sensitivity bits order
454 * to encoder bits order.
455 * - set the appropriate value of usc_frame.
456 */
457static void predecode_amr( ipp_private_t *codec_data,
458 const pjmedia_frame *rtp_frame,
459 USC_Bitstream *usc_frame)
460{
461 pjmedia_frame frame;
462 pjmedia_codec_amr_bit_info *info;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000463 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000464
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000465 setting = &((amr_settings_t*)codec_data->codec_setting)->dec_setting;
466
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000467 frame = *rtp_frame;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000468 pjmedia_codec_amr_predecode(rtp_frame, setting, &frame);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000469 info = (pjmedia_codec_amr_bit_info*) &frame.bit_info;
470
471 usc_frame->pBuffer = frame.buf;
472 usc_frame->nbytes = frame.size;
473 if (info->mode != -1) {
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000474 usc_frame->bitrate = setting->amr_nb?
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000475 pjmedia_codec_amrnb_bitrates[info->mode]:
476 pjmedia_codec_amrwb_bitrates[info->mode];
477 } else {
478 usc_frame->bitrate = 0;
479 }
480
481 if (frame.size > 5) {
482 /* Speech */
483 if (info->good_quality)
484 usc_frame->frametype = 0;
485 else
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000486 usc_frame->frametype = setting->amr_nb ? 5 : 6;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000487 } else if (frame.size == 5) {
488 /* SID */
489 if (info->good_quality) {
490 pj_bool_t STI;
491 STI = (((pj_uint8_t*)frame.buf)[35 >> 3] & 0x10) != 0;
492 usc_frame->frametype = STI? 2 : 1;
493 } else {
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000494 usc_frame->frametype = setting->amr_nb ? 6 : 7;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000495 }
496 } else {
497 /* no data */
498 usc_frame->frametype = 3;
499 }
500}
501
502/* Pack AMR payload */
503static pj_status_t pack_amr(ipp_private_t *codec_data, void *pkt,
504 pj_size_t *pkt_size, pj_size_t max_pkt_size)
505{
Nanang Izzuddin0290a572010-05-11 06:33:55 +0000506 enum {MAX_FRAMES_PER_PACKET = PJMEDIA_MAX_FRAME_DURATION_MS / 20};
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000507
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000508 pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
509 unsigned nframes = 0;
510 pjmedia_codec_amr_bit_info *info;
511 pj_uint8_t *r; /* Read cursor */
512 pj_uint8_t SID_FT;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000513 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000514
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000515 setting = &((amr_settings_t*)codec_data->codec_setting)->enc_setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000516
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000517 SID_FT = (pj_uint8_t)(setting->amr_nb? 8 : 9);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000518
519 /* Align pkt buf right */
520 r = (pj_uint8_t*)pkt + max_pkt_size - *pkt_size;
521 pj_memmove(r, pkt, *pkt_size);
522
523 /* Get frames */
524 for (;;) {
525 pj_bool_t eof;
526 pj_uint16_t info_;
527
528 info_ = *((pj_uint16_t*)r);
529 eof = ((info_ & 0x40) != 0);
530
531 info = (pjmedia_codec_amr_bit_info*) &frames[nframes].bit_info;
532 pj_bzero(info, sizeof(*info));
533 info->frame_type = (pj_uint8_t)(info_ & 0x0F);
534 info->good_quality = (pj_uint8_t)((info_ & 0x80) == 0);
535 info->mode = (pj_int8_t) ((info_ >> 8) & 0x0F);
536
537 frames[nframes].buf = r + 2;
538 frames[nframes].size = info->frame_type <= SID_FT ?
539 pjmedia_codec_amrnb_framelen[info->frame_type] :
540 0;
541
542 r += frames[nframes].size + 2;
543
544 /* Last frame */
545 if (++nframes >= MAX_FRAMES_PER_PACKET || eof)
546 break;
547 }
548
549 /* Pack */
550 *pkt_size = max_pkt_size;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000551 return pjmedia_codec_amr_pack(frames, nframes, setting, pkt, pkt_size);
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000552}
553
554
555/* Parse AMR payload into frames. */
556static pj_status_t parse_amr(ipp_private_t *codec_data, void *pkt,
557 pj_size_t pkt_size, const pj_timestamp *ts,
558 unsigned *frame_cnt, pjmedia_frame frames[])
559{
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000560 amr_settings_t* s = (amr_settings_t*)codec_data->codec_setting;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000561 pjmedia_codec_amr_pack_setting *setting;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000562 pj_status_t status;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000563 pj_uint8_t cmr;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000564
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000565 setting = &s->dec_setting;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000566
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000567 status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, setting, frames,
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000568 frame_cnt, &cmr);
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000569 if (status != PJ_SUCCESS)
570 return status;
571
572 /* Check Change Mode Request. */
Nanang Izzuddin42bb38b2010-05-26 13:50:42 +0000573 if (((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) &&
574 s->enc_mode != cmr)
575 {
Benny Prijono329d6382009-05-29 13:04:03 +0000576 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
577
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +0000578 s->enc_mode = cmr;
Benny Prijono329d6382009-05-29 13:04:03 +0000579 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
580 pjmedia_codec_amrnb_bitrates[s->enc_mode] :
581 pjmedia_codec_amrwb_bitrates[s->enc_mode];
582 ippc->fxns->std.Control(&codec_data->info->params.modes,
583 codec_data->enc);
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +0000584
585 PJ_LOG(4,(THIS_FILE, "AMR%s switched encoding mode to: %d (%dbps)",
586 (s->enc_setting.amr_nb?"":"-WB"),
587 s->enc_mode,
588 codec_data->info->params.modes.bitrate));
Nanang Izzuddin35e01de2008-10-29 10:17:02 +0000589 }
590
591 return PJ_SUCCESS;
Nanang Izzuddind55553a2008-10-28 02:24:46 +0000592}
593
594#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_AMR */
595
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000596
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000597#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
598
599static void predecode_g7221( ipp_private_t *codec_data,
600 const pjmedia_frame *rtp_frame,
601 USC_Bitstream *usc_frame)
602{
603 usc_frame->pBuffer = (char*)rtp_frame->buf;
604 usc_frame->nbytes = rtp_frame->size;
605 usc_frame->frametype = 0;
606 usc_frame->bitrate = codec_data->info->params.modes.bitrate;
607
608#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
609 {
610 pj_uint16_t *p, *p_end;
611
612 p = (pj_uint16_t*)rtp_frame->buf;
613 p_end = p + rtp_frame->size/2;
614 while (p < p_end) {
615 *p = pj_ntohs(*p);
616 ++p;
617 }
618 }
619#endif
620}
621
622static pj_status_t pack_g7221( ipp_private_t *codec_data, void *pkt,
623 pj_size_t *pkt_size, pj_size_t max_pkt_size)
624{
625 PJ_UNUSED_ARG(codec_data);
626 PJ_UNUSED_ARG(max_pkt_size);
627
628#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
629 {
630 pj_uint16_t *p, *p_end;
631
632 p = (pj_uint16_t*)pkt;
633 p_end = p + *pkt_size/2;
634 while (p < p_end) {
635 *p = pj_htons(*p);
636 ++p;
637 }
638 }
639#else
640 PJ_UNUSED_ARG(pkt);
641 PJ_UNUSED_ARG(pkt_size);
642#endif
643
644 return PJ_SUCCESS;
645}
646
Nanang Izzuddinfef5a3f2010-08-11 07:18:08 +0000647
648#include <pjmedia-codec/g7221.h>
649
650
651PJ_DEF(pj_status_t) pjmedia_codec_g7221_set_pcm_shift(int val)
652{
653 PJ_ASSERT_RETURN(val >= 0, PJ_EINVAL);
654
655 ipp_factory.g7221_pcm_shift = val;
656 return PJ_SUCCESS;
657}
658
659
Nanang Izzuddin1b9f46b2009-04-06 13:52:01 +0000660#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1 */
661
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000662/*
663 * Initialize and register IPP codec factory to pjmedia endpoint.
664 */
665PJ_DEF(pj_status_t) pjmedia_codec_ipp_init( pjmedia_endpt *endpt )
666{
667 pjmedia_codec_mgr *codec_mgr;
668 pj_status_t status;
669
670 if (ipp_factory.pool != NULL) {
671 /* Already initialized. */
672 return PJ_SUCCESS;
673 }
674
675 /* Create IPP codec factory. */
676 ipp_factory.base.op = &ipp_factory_op;
677 ipp_factory.base.factory_data = NULL;
678 ipp_factory.endpt = endpt;
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000679 ipp_factory.g7221_pcm_shift = PJMEDIA_G7221_DEFAULT_PCM_SHIFT;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000680
681 ipp_factory.pool = pjmedia_endpt_create_pool(endpt, "IPP codecs", 4000, 4000);
682 if (!ipp_factory.pool)
683 return PJ_ENOMEM;
684
685 /* Create mutex. */
686 status = pj_mutex_create_simple(ipp_factory.pool, "IPP codecs",
687 &ipp_factory.mutex);
688 if (status != PJ_SUCCESS)
689 goto on_error;
690
691 /* Get the codec manager. */
692 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
693 if (!codec_mgr) {
694 status = PJ_EINVALIDOP;
695 goto on_error;
696 }
697
698 /* Register codec factory to endpoint. */
699 status = pjmedia_codec_mgr_register_factory(codec_mgr,
700 &ipp_factory.base);
701 if (status != PJ_SUCCESS)
702 goto on_error;
703
704 /* Done. */
705 return PJ_SUCCESS;
706
707on_error:
708 pj_pool_release(ipp_factory.pool);
709 ipp_factory.pool = NULL;
710 return status;
711}
712
713/*
714 * Unregister IPP codecs factory from pjmedia endpoint.
715 */
716PJ_DEF(pj_status_t) pjmedia_codec_ipp_deinit(void)
717{
718 pjmedia_codec_mgr *codec_mgr;
719 pj_status_t status;
720
721 if (ipp_factory.pool == NULL) {
722 /* Already deinitialized */
723 return PJ_SUCCESS;
724 }
725
726 pj_mutex_lock(ipp_factory.mutex);
727
728 /* Get the codec manager. */
729 codec_mgr = pjmedia_endpt_get_codec_mgr(ipp_factory.endpt);
730 if (!codec_mgr) {
731 pj_pool_release(ipp_factory.pool);
732 ipp_factory.pool = NULL;
733 return PJ_EINVALIDOP;
734 }
735
736 /* Unregister IPP codecs factory. */
737 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
738 &ipp_factory.base);
739
740 /* Destroy mutex. */
741 pj_mutex_destroy(ipp_factory.mutex);
742
743 /* Destroy pool. */
744 pj_pool_release(ipp_factory.pool);
745 ipp_factory.pool = NULL;
746
747 return status;
748}
749
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000750
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000751/*
752 * Check if factory can allocate the specified codec.
753 */
754static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
755 const pjmedia_codec_info *info )
756{
757 unsigned i;
758
759 PJ_UNUSED_ARG(factory);
760
761 /* Type MUST be audio. */
762 if (info->type != PJMEDIA_TYPE_AUDIO)
763 return PJMEDIA_CODEC_EUNSUP;
764
765 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
766 pj_str_t name = pj_str((char*)ipp_codec[i].name);
767 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
768 (info->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
769 (info->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
770 (ipp_codec[i].enabled))
771 {
772 return PJ_SUCCESS;
773 }
774 }
775
776 /* Unsupported, or mode is disabled. */
777 return PJMEDIA_CODEC_EUNSUP;
778}
779
780/*
781 * Generate default attribute.
782 */
783static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
784 const pjmedia_codec_info *id,
785 pjmedia_codec_param *attr )
786{
787 unsigned i;
788
789 PJ_ASSERT_RETURN(factory==&ipp_factory.base, PJ_EINVAL);
790
791 pj_bzero(attr, sizeof(pjmedia_codec_param));
792
793 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
794 pj_str_t name = pj_str((char*)ipp_codec[i].name);
795 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
796 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000797 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
798 (id->pt == (unsigned)ipp_codec[i].pt))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000799 {
800 attr->info.pt = (pj_uint8_t)id->pt;
801 attr->info.channel_cnt = ipp_codec[i].channel_count;
802 attr->info.clock_rate = ipp_codec[i].clock_rate;
803 attr->info.avg_bps = ipp_codec[i].def_bitrate;
804 attr->info.max_bps = ipp_codec[i].max_bitrate;
805 attr->info.pcm_bits_per_sample = 16;
806 attr->info.frm_ptime = (pj_uint16_t)
807 (ipp_codec[i].samples_per_frame * 1000 /
808 ipp_codec[i].channel_count /
809 ipp_codec[i].clock_rate);
810 attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
811
812 /* Default flags. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000813 attr->setting.plc = 1;
814 attr->setting.penh= 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000815 attr->setting.vad = 1;
816 attr->setting.cng = attr->setting.vad;
817 attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
818
819 if (attr->setting.vad == 0) {
820#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
821 if (id->pt == PJMEDIA_RTP_PT_G729) {
822 /* Signal G729 Annex B is being disabled */
823 attr->setting.dec_fmtp.cnt = 1;
824 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
825 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
826 }
827#endif
828 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000829
830 return PJ_SUCCESS;
831 }
832 }
833
834 return PJMEDIA_CODEC_EUNSUP;
835}
836
837/*
838 * Enum codecs supported by this factory.
839 */
840static pj_status_t ipp_enum_codecs(pjmedia_codec_factory *factory,
841 unsigned *count,
842 pjmedia_codec_info codecs[])
843{
844 unsigned max;
845 unsigned i;
846
847 PJ_UNUSED_ARG(factory);
848 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
849
850 max = *count;
851
852 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(ipp_codec) && *count < max; ++i)
853 {
854 if (!ipp_codec[i].enabled)
855 continue;
856
857 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
858 codecs[*count].encoding_name = pj_str((char*)ipp_codec[i].name);
859 codecs[*count].pt = ipp_codec[i].pt;
860 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
861 codecs[*count].clock_rate = ipp_codec[i].clock_rate;
862 codecs[*count].channel_cnt = ipp_codec[i].channel_count;
863
864 ++*count;
865 }
866
867 return PJ_SUCCESS;
868}
869
870/*
871 * Allocate a new codec instance.
872 */
873static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
874 const pjmedia_codec_info *id,
875 pjmedia_codec **p_codec)
876{
877 ipp_private_t *codec_data;
878 pjmedia_codec *codec;
879 int idx;
880 pj_pool_t *pool;
881 unsigned i;
882
883 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
884 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
885
886 pj_mutex_lock(ipp_factory.mutex);
887
888 /* Find codec's index */
889 idx = -1;
890 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
891 pj_str_t name = pj_str((char*)ipp_codec[i].name);
892 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
893 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
894 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
895 (ipp_codec[i].enabled))
896 {
897 idx = i;
898 break;
899 }
900 }
901 if (idx == -1) {
902 *p_codec = NULL;
903 return PJMEDIA_CODEC_EFAILED;
904 }
905
906 /* Create pool for codec instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000907 pool = pjmedia_endpt_create_pool(ipp_factory.endpt, "IPPcodec", 512, 512);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000908 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
909 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
910 codec->op = &ipp_op;
911 codec->factory = factory;
912 codec->codec_data = PJ_POOL_ZALLOC_T(pool, ipp_private_t);
913 codec_data = (ipp_private_t*) codec->codec_data;
914
915 /* Create PLC if codec has no internal PLC */
916 if (!ipp_codec[idx].has_native_plc) {
917 pj_status_t status;
918 status = pjmedia_plc_create(pool, ipp_codec[idx].clock_rate,
919 ipp_codec[idx].samples_per_frame, 0,
920 &codec_data->plc);
921 if (status != PJ_SUCCESS) {
922 pj_pool_release(pool);
923 pj_mutex_unlock(ipp_factory.mutex);
924 return status;
925 }
926 }
927
928 /* Create silence detector if codec has no internal VAD */
929 if (!ipp_codec[idx].has_native_vad) {
930 pj_status_t status;
931 status = pjmedia_silence_det_create(pool,
932 ipp_codec[idx].clock_rate,
933 ipp_codec[idx].samples_per_frame,
934 &codec_data->vad);
935 if (status != PJ_SUCCESS) {
936 pj_pool_release(pool);
937 pj_mutex_unlock(ipp_factory.mutex);
938 return status;
939 }
940 }
941
942 codec_data->pool = pool;
943 codec_data->codec_idx = idx;
944
945 pj_mutex_unlock(ipp_factory.mutex);
946
947 *p_codec = codec;
948 return PJ_SUCCESS;
949}
950
951/*
952 * Free codec.
953 */
954static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
955 pjmedia_codec *codec )
956{
957 ipp_private_t *codec_data;
958
959 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
960 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
961
962 /* Close codec, if it's not closed. */
963 codec_data = (ipp_private_t*) codec->codec_data;
964 if (codec_data->enc != NULL || codec_data->dec != NULL) {
965 ipp_codec_close(codec);
966 }
967
968 pj_pool_release(codec_data->pool);
969
970 return PJ_SUCCESS;
971}
972
973/*
974 * Init codec.
975 */
976static pj_status_t ipp_codec_init( pjmedia_codec *codec,
977 pj_pool_t *pool )
978{
979 PJ_UNUSED_ARG(codec);
980 PJ_UNUSED_ARG(pool);
981 return PJ_SUCCESS;
982}
983
984/*
985 * Open codec.
986 */
987static pj_status_t ipp_codec_open( pjmedia_codec *codec,
988 pjmedia_codec_param *attr )
989{
990 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000991 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000992 int info_size;
993 pj_pool_t *pool;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000994 int i, j;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000995 USC_MemBank *membanks;
996 int nb_membanks;
997
998 pool = codec_data->pool;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000999
1000 /* Get the codec info size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001001 if (USC_NoError != ippc->fxns->std.GetInfoSize(&info_size)) {
1002 PJ_LOG(1,(THIS_FILE, "Error getting codec info size"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001003 goto on_error;
1004 }
1005 /* Get the codec info */
1006 codec_data->info = pj_pool_zalloc(pool, info_size);
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001007 if (USC_NoError != ippc->fxns->std.GetInfo((USC_Handle)NULL,
1008 codec_data->info))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001009 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001010 PJ_LOG(1,(THIS_FILE, "Error getting codec info"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001011 goto on_error;
1012 }
1013
1014 /* PREPARING THE ENCODER */
1015
1016 /* Setting the encoder params */
1017 codec_data->info->params.direction = USC_ENCODE;
Nanang Izzuddinf216f822008-08-15 18:35:50 +00001018 codec_data->info->params.modes.vad = attr->setting.vad &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001019 ippc->has_native_vad;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001020 codec_data->info->params.modes.bitrate = attr->info.avg_bps;
1021 codec_data->info->params.law = 0; /* Linear PCM input */
1022
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001023#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
1024 if (ippc->pt == PJMEDIA_RTP_PT_G729) {
1025 /* Check if G729 Annex B is signaled to be disabled */
1026 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
1027 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
1028 {
1029 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
Nanang Izzuddinb99def52010-08-18 15:08:30 +00001030 {
1031 attr->setting.vad = 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001032 codec_data->info->params.modes.vad = 0;
Nanang Izzuddinb99def52010-08-18 15:08:30 +00001033 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001034 break;
1035 }
1036 }
1037 }
1038#endif
1039
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001040 /* Get number of memory blocks needed by the encoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001041 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1042 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001043 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001044 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001045 goto on_error;
1046 }
1047
1048 /* Allocate memory blocks table */
1049 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1050 sizeof(USC_MemBank) * nb_membanks);
1051 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001052 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1053 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001054 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001055 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001056 goto on_error;
1057 }
1058
1059 /* Allocate memory for each block */
1060 for (i = 0; i < nb_membanks; i++) {
1061 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1062 }
1063
1064 /* Create encoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001065 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1066 membanks,
1067 &codec_data->enc))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001068 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001069 PJ_LOG(1,(THIS_FILE, "Error initializing encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001070 goto on_error;
1071 }
1072
1073 /* PREPARING THE DECODER */
1074
1075 /* Setting the decoder params */
1076 codec_data->info->params.direction = USC_DECODE;
1077
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001078 /* Not sure if VAD affects decoder, just try to be safe */
Benny Prijono329d6382009-05-29 13:04:03 +00001079 //codec_data->info->params.modes.vad = ippc->has_native_vad;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001080
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001081 /* Get number of memory blocks needed by the decoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001082 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1083 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001084 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001085 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001086 goto on_error;
1087 }
1088
1089 /* Allocate memory blocks table */
1090 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1091 sizeof(USC_MemBank) * nb_membanks);
1092 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001093 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1094 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001095 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001096 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001097 goto on_error;
1098 }
1099
1100 /* Allocate memory for each block */
1101 for (i = 0; i < nb_membanks; i++) {
1102 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1103 }
1104
1105 /* Create decoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001106 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1107 membanks, &codec_data->dec))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001108 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001109 PJ_LOG(1,(THIS_FILE, "Error initializing decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001110 goto on_error;
1111 }
1112
1113 /* Update codec info */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001114 ippc->fxns->std.GetInfo((USC_Handle)codec_data->enc, codec_data->info);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001115
1116 /* Get bitstream size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001117 i = codec_data->info->params.modes.bitrate * ippc->samples_per_frame;
1118 j = ippc->clock_rate << 3;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001119 codec_data->frame_size = (pj_uint16_t)(i / j);
1120 if (i % j) ++codec_data->frame_size;
1121
1122 codec_data->vad_enabled = (attr->setting.vad != 0);
1123 codec_data->plc_enabled = (attr->setting.plc != 0);
1124
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001125#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
1126 /* Init AMR settings */
1127 if (ippc->pt == PJMEDIA_RTP_PT_AMR || ippc->pt == PJMEDIA_RTP_PT_AMRWB) {
1128 amr_settings_t *s;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001129 pj_uint8_t octet_align = 0;
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001130 pj_int8_t enc_mode;
1131
1132 enc_mode = pjmedia_codec_amr_get_mode(
1133 codec_data->info->params.modes.bitrate);
1134 pj_assert(enc_mode >= 0 && enc_mode <= 8);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001135
Benny Prijono329d6382009-05-29 13:04:03 +00001136 /* Check AMR specific attributes */
1137
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001138 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
Benny Prijono329d6382009-05-29 13:04:03 +00001139 /* octet-align, one of the parameters that must have same value
1140 * in offer & answer (RFC 4867 Section 8.3.1). Just check fmtp
1141 * in the decoder side, since it's value is guaranteed to fulfil
1142 * above requirement (by SDP negotiator).
1143 */
1144 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
1145
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001146 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
1147 &STR_FMTP_OCTET_ALIGN) == 0)
1148 {
1149 octet_align=(pj_uint8_t)
Benny Prijono329d6382009-05-29 13:04:03 +00001150 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
1151 break;
1152 }
1153 }
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001154
Benny Prijono329d6382009-05-29 13:04:03 +00001155 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001156 /* mode-set, encoding mode is chosen based on local default mode
1157 * setting:
1158 * - if local default mode is included in the mode-set, use it
1159 * - otherwise, find the closest mode to local default mode;
1160 * if there are two closest modes, prefer to use the higher
1161 * one, e.g: local default mode is 4, the mode-set param
1162 * contains '2,3,5,6', then 5 will be chosen.
1163 */
Benny Prijono329d6382009-05-29 13:04:03 +00001164 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
1165
1166 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
1167 &STR_FMTP_MODE_SET) == 0)
1168 {
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001169 const char *p;
1170 pj_size_t l;
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001171 pj_int8_t diff = 99;
1172
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001173 p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
1174 l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
Benny Prijono329d6382009-05-29 13:04:03 +00001175
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001176 while (l--) {
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001177 if ((ippc->pt==PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') ||
1178 (ippc->pt==PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8'))
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001179 {
Benny Prijono1383e472009-08-01 09:23:15 +00001180 pj_int8_t tmp = (pj_int8_t)(*p - '0' - enc_mode);
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001181
1182 if (PJ_ABS(diff) > PJ_ABS(tmp) ||
1183 (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
1184 {
1185 diff = tmp;
1186 if (diff == 0) break;
1187 }
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001188 }
1189 ++p;
Benny Prijono329d6382009-05-29 13:04:03 +00001190 }
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001191
1192 if (diff == 99)
1193 goto on_error;
1194
Benny Prijono1383e472009-08-01 09:23:15 +00001195 enc_mode = (pj_int8_t)(enc_mode + diff);
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001196
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001197 break;
1198 }
1199 }
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001200
Benny Prijono329d6382009-05-29 13:04:03 +00001201 /* Initialize AMR specific settings */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001202 s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
1203 codec_data->codec_setting = s;
1204
Benny Prijono6b6fce12009-03-17 10:13:30 +00001205 s->enc_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001206 s->enc_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001207 s->enc_setting.reorder = PJ_TRUE;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001208 s->enc_setting.cmr = 15;
Benny Prijono329d6382009-05-29 13:04:03 +00001209
Benny Prijono6b6fce12009-03-17 10:13:30 +00001210 s->dec_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001211 s->dec_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001212 s->dec_setting.reorder = PJ_TRUE;
Benny Prijono329d6382009-05-29 13:04:03 +00001213
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001214 /* Apply encoder mode/bitrate */
1215 s->enc_mode = enc_mode;
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001216 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
1217 pjmedia_codec_amrnb_bitrates[s->enc_mode]:
1218 pjmedia_codec_amrwb_bitrates[s->enc_mode];
1219 ippc->fxns->std.Control(&codec_data->info->params.modes,
1220 codec_data->enc);
Benny Prijono329d6382009-05-29 13:04:03 +00001221
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001222 PJ_LOG(4,(THIS_FILE, "AMR%s encoding mode: %d (%dbps)",
1223 (s->enc_setting.amr_nb?"":"-WB"),
1224 s->enc_mode,
1225 codec_data->info->params.modes.bitrate));
Nanang Izzuddin06839e72010-01-27 11:48:31 +00001226
1227 /* Return back bitrate info to application */
1228 attr->info.avg_bps = codec_data->info->params.modes.bitrate;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001229 }
1230#endif
1231
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001232#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1233 if (ippc->pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1234 ippc->pt <= PJMEDIA_RTP_PT_G7221_RSV2)
1235 {
1236 codec_data->g7221_pcm_shift = ipp_factory.g7221_pcm_shift;
1237 }
1238#endif
1239
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001240 return PJ_SUCCESS;
1241
1242on_error:
1243 return PJMEDIA_CODEC_EFAILED;
1244}
1245
1246/*
1247 * Close codec.
1248 */
1249static pj_status_t ipp_codec_close( pjmedia_codec *codec )
1250{
1251 PJ_UNUSED_ARG(codec);
1252
1253 return PJ_SUCCESS;
1254}
1255
1256
1257/*
1258 * Modify codec settings.
1259 */
1260static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
1261 const pjmedia_codec_param *attr )
1262{
1263 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001264 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001265
1266 codec_data->vad_enabled = (attr->setting.vad != 0);
1267 codec_data->plc_enabled = (attr->setting.plc != 0);
1268
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001269 if (ippc->has_native_vad) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001270 USC_Modes modes;
1271
1272 modes = codec_data->info->params.modes;
1273 modes.vad = codec_data->vad_enabled;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001274 ippc->fxns->std.Control(&modes, codec_data->enc);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001275 }
1276
1277 return PJ_SUCCESS;
1278}
1279
1280/*
1281 * Get frames in the packet.
1282 */
1283static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
1284 void *pkt,
1285 pj_size_t pkt_size,
1286 const pj_timestamp *ts,
1287 unsigned *frame_cnt,
1288 pjmedia_frame frames[])
1289{
1290 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001291 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001292 unsigned count = 0;
1293
1294 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
1295
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001296 if (ippc->parse != NULL) {
1297 return ippc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001298 }
1299
1300 while (pkt_size >= codec_data->frame_size && count < *frame_cnt) {
1301 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1302 frames[count].buf = pkt;
1303 frames[count].size = codec_data->frame_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001304 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001305
1306 pkt = ((char*)pkt) + codec_data->frame_size;
1307 pkt_size -= codec_data->frame_size;
1308
1309 ++count;
1310 }
1311
1312 if (pkt_size && count < *frame_cnt) {
1313 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1314 frames[count].buf = pkt;
1315 frames[count].size = pkt_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001316 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001317 ++count;
1318 }
1319
1320 *frame_cnt = count;
1321 return PJ_SUCCESS;
1322}
1323
1324/*
1325 * Encode frames.
1326 */
1327static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
1328 const struct pjmedia_frame *input,
1329 unsigned output_buf_len,
1330 struct pjmedia_frame *output)
1331{
1332 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001333 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001334 unsigned samples_per_frame;
1335 unsigned nsamples;
1336 pj_size_t tx = 0;
1337 pj_int16_t *pcm_in = (pj_int16_t*)input->buf;
Benny Prijonob1339242008-08-21 20:58:55 +00001338 pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001339 pj_uint8_t pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001340
1341 /* Invoke external VAD if codec has no internal VAD */
1342 if (codec_data->vad && codec_data->vad_enabled) {
1343 pj_bool_t is_silence;
1344 pj_int32_t silence_duration;
1345
1346 silence_duration = pj_timestamp_diff32(&codec_data->last_tx,
1347 &input->timestamp);
1348
1349 is_silence = pjmedia_silence_det_detect(codec_data->vad,
1350 (const pj_int16_t*) input->buf,
1351 (input->size >> 1),
1352 NULL);
1353 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +00001354 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
1355 silence_duration < (PJMEDIA_CODEC_MAX_SILENCE_PERIOD *
1356 (int)ippc->clock_rate / 1000)))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001357 {
1358 output->type = PJMEDIA_FRAME_TYPE_NONE;
1359 output->buf = NULL;
1360 output->size = 0;
1361 output->timestamp = input->timestamp;
1362 return PJ_SUCCESS;
1363 } else {
1364 codec_data->last_tx = input->timestamp;
1365 }
1366 }
1367
1368 nsamples = input->size >> 1;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001369 samples_per_frame = ippc->samples_per_frame;
1370 pt = ippc->pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001371
1372 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
1373 PJMEDIA_CODEC_EPCMFRMINLEN);
1374
1375 /* Encode the frames */
1376 while (nsamples >= samples_per_frame) {
1377 USC_PCMStream in;
1378 USC_Bitstream out;
1379
1380 in.bitrate = codec_data->info->params.modes.bitrate;
1381 in.nbytes = samples_per_frame << 1;
1382 in.pBuffer = (char*)pcm_in;
1383 in.pcmType.bitPerSample = codec_data->info->params.pcmType.bitPerSample;
1384 in.pcmType.nChannels = codec_data->info->params.pcmType.nChannels;
1385 in.pcmType.sample_frequency = codec_data->info->params.pcmType.sample_frequency;
1386
Benny Prijonob1339242008-08-21 20:58:55 +00001387 out.pBuffer = (char*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001388
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001389#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001390 /* For AMR: reserve two octets for AMR frame info */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001391 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001392 out.pBuffer += 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001393 }
1394#endif
1395
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001396#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1397 /* For G722.1: adjust the encoder input signal level */
1398 if (pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1399 pt <= PJMEDIA_RTP_PT_G7221_RSV2 &&
1400 codec_data->g7221_pcm_shift)
1401 {
1402 unsigned i;
1403 for (i = 0; i < samples_per_frame; ++i)
1404 pcm_in[i] >>= codec_data->g7221_pcm_shift;
1405 }
1406#endif
1407
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001408 if (USC_NoError != ippc->fxns->Encode(codec_data->enc, &in, &out)) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001409 break;
1410 }
1411
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001412#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001413 /* For AMR: put info (frametype, degraded, last frame, mode) in the
1414 * first two octets for payload packing.
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001415 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001416 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001417 pj_uint16_t *info = (pj_uint16_t*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001418
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001419 /* Two octets for AMR frame info, 0=LSB:
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001420 * bit 0-3 : frame type
1421 * bit 6 : last frame flag
1422 * bit 7 : quality flag
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001423 * bit 8-11 : mode
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001424 */
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001425 out.nbytes += 2;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001426 if (out.frametype == 0 || out.frametype == 4 ||
1427 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 5) ||
1428 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 6))
1429 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001430 /* Speech frame type */
1431 *info = (char)pjmedia_codec_amr_get_mode(out.bitrate);
1432 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001433 if (out.frametype == 5 || out.frametype == 6)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001434 *info |= 0x80;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001435 } else if (out.frametype == 1 || out.frametype == 2 ||
1436 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 6) ||
1437 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 7))
1438 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001439 /* SID frame type */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001440 *info = (pj_uint8_t)(pt == PJMEDIA_RTP_PT_AMRWB? 9 : 8);
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001441 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001442 if (out.frametype == 6 || out.frametype == 7)
1443 *info |= 0x80;
1444 } else {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001445 /* Untransmited */
1446 *info = 15;
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001447 out.nbytes = 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001448 }
1449
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001450 /* Mode */
1451 *info |= (char)pjmedia_codec_amr_get_mode(out.bitrate) << 8;
1452
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001453 /* Last frame flag */
1454 if (nsamples == samples_per_frame)
1455 *info |= 0x40;
1456 }
Nanang Izzuddin7dd32682008-08-19 11:23:33 +00001457#endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001458
1459 pcm_in += samples_per_frame;
1460 nsamples -= samples_per_frame;
1461 tx += out.nbytes;
1462 bits_out += out.nbytes;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001463
1464#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddine3a6fca2008-08-27 13:15:25 +00001465 if (pt == PJMEDIA_RTP_PT_G729) {
1466 if (out.frametype == 1) {
1467 /* SID */
1468 break;
1469 } else if (out.frametype == 0) {
1470 /* Untransmitted */
1471 tx -= out.nbytes;
1472 break;
1473 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001474 }
1475#endif
1476
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001477 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001478
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001479 if (ippc->pack != NULL) {
1480 ippc->pack(codec_data, output->buf, &tx, output_buf_len);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001481 }
1482
1483 /* Check if we don't need to transmit the frame (DTX) */
1484 if (tx == 0) {
1485 output->buf = NULL;
1486 output->size = 0;
1487 output->timestamp.u64 = input->timestamp.u64;
1488 output->type = PJMEDIA_FRAME_TYPE_NONE;
1489 return PJ_SUCCESS;
1490 }
1491
1492 output->size = tx;
1493 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1494 output->timestamp = input->timestamp;
1495
1496 return PJ_SUCCESS;
1497}
1498
1499/*
1500 * Decode frame.
1501 */
1502static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
1503 const struct pjmedia_frame *input,
1504 unsigned output_buf_len,
1505 struct pjmedia_frame *output)
1506{
1507 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001508 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001509 unsigned samples_per_frame;
1510 USC_PCMStream out;
1511 USC_Bitstream in;
1512 pj_uint8_t pt;
1513
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001514 pt = ippc->pt;
1515 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001516
1517 PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
1518 PJMEDIA_CODEC_EPCMTOOSHORT);
1519
1520 if (input->type == PJMEDIA_FRAME_TYPE_AUDIO) {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001521 if (ippc->predecode) {
1522 ippc->predecode(codec_data, input, &in);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001523 } else {
1524 /* Most IPP codecs have frametype==0 for speech frame */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001525 in.pBuffer = (char*)input->buf;
1526 in.nbytes = input->size;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001527 in.frametype = 0;
1528 in.bitrate = codec_data->info->params.modes.bitrate;
1529 }
1530
1531 out.pBuffer = output->buf;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001532 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001533
1534 if (input->type != PJMEDIA_FRAME_TYPE_AUDIO ||
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001535 USC_NoError != ippc->fxns->Decode(codec_data->dec, &in, &out))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001536 {
1537 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1538 output->size = samples_per_frame << 1;
1539 output->timestamp.u64 = input->timestamp.u64;
1540 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1541 return PJ_SUCCESS;
1542 }
1543
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001544#if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001545 /* For G.726: amplify decoding result (USC G.726 encoder deamplified it) */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001546 if (pt == PJMEDIA_RTP_PT_G726_16 || pt == PJMEDIA_RTP_PT_G726_24 ||
Nanang Izzuddincf4d1412010-06-07 05:23:56 +00001547 pt == PJMEDIA_RTP_PT_G726_32 || pt == PJMEDIA_RTP_PT_G726_40 ||
1548 pt == PJMEDIA_RTP_PT_G721)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001549 {
1550 unsigned i;
1551 pj_int16_t *s = (pj_int16_t*)output->buf;
1552
1553 for (i = 0; i < samples_per_frame; ++i)
1554 s[i] <<= 2;
1555 }
1556#endif
1557
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001558#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1559 /* For G722.1: adjust the decoder output signal level */
1560 if (pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1561 pt <= PJMEDIA_RTP_PT_G7221_RSV2 &&
1562 codec_data->g7221_pcm_shift)
1563 {
1564 unsigned i;
1565 pj_int16_t *s = (pj_int16_t*)output->buf;
1566
1567 for (i = 0; i < samples_per_frame; ++i)
1568 s[i] <<= codec_data->g7221_pcm_shift;
1569 }
1570#endif
1571
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001572 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1573 output->size = samples_per_frame << 1;
1574 output->timestamp.u64 = input->timestamp.u64;
1575
1576 /* Invoke external PLC if codec has no internal PLC */
1577 if (codec_data->plc && codec_data->plc_enabled)
1578 pjmedia_plc_save(codec_data->plc, (pj_int16_t*)output->buf);
1579
1580 return PJ_SUCCESS;
1581}
1582
1583/*
1584 * Recover lost frame.
1585 */
1586static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
1587 unsigned output_buf_len,
1588 struct pjmedia_frame *output)
1589{
1590 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001591 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001592 unsigned samples_per_frame;
1593
1594 PJ_UNUSED_ARG(output_buf_len);
1595
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001596 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001597
1598 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1599 output->size = samples_per_frame << 1;
1600
1601 if (codec_data->plc_enabled) {
1602 if (codec_data->plc) {
1603 pjmedia_plc_generate(codec_data->plc, (pj_int16_t*)output->buf);
1604 } else {
1605 USC_PCMStream out;
1606 out.pBuffer = output->buf;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001607 ippc->fxns->Decode(codec_data->dec, NULL, &out);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001608 }
1609 } else {
1610 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1611 }
1612
1613 return PJ_SUCCESS;
1614}
1615
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001616
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001617#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_IPP_LIBS
1618# pragma comment( lib, "ippcore.lib")
1619# pragma comment( lib, "ipps.lib")
1620# pragma comment( lib, "ippsc.lib")
1621# pragma comment( lib, "ippsr.lib")
Benny Prijonoc543e9e2009-01-03 12:19:53 +00001622//# pragma comment( lib, "ippcorel.lib")
1623//# pragma comment( lib, "ippsemerged.lib")
1624//# pragma comment( lib, "ippsmerged.lib")
1625//# pragma comment( lib, "ippscemerged.lib")
1626//# pragma comment( lib, "ippscmerged.lib")
1627//# pragma comment( lib, "ippsremerged.lib")
1628//# pragma comment( lib, "ippsrmerged.lib")
Benny Prijonoe1e6d512009-01-02 15:17:47 +00001629# if defined(IPP_VERSION_MAJOR) && IPP_VERSION_MAJOR>=6
1630# pragma comment( lib, "speech.lib")
1631# else
1632# pragma comment( lib, "usc.lib")
1633# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001634#endif
1635
1636
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001637#endif /* PJMEDIA_HAS_INTEL_IPP */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001638