blob: 864492680333da4e1fb9f93059d43dd3b867998d [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
647#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1 */
648
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000649/*
650 * Initialize and register IPP codec factory to pjmedia endpoint.
651 */
652PJ_DEF(pj_status_t) pjmedia_codec_ipp_init( pjmedia_endpt *endpt )
653{
654 pjmedia_codec_mgr *codec_mgr;
655 pj_status_t status;
656
657 if (ipp_factory.pool != NULL) {
658 /* Already initialized. */
659 return PJ_SUCCESS;
660 }
661
662 /* Create IPP codec factory. */
663 ipp_factory.base.op = &ipp_factory_op;
664 ipp_factory.base.factory_data = NULL;
665 ipp_factory.endpt = endpt;
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000666 ipp_factory.g7221_pcm_shift = PJMEDIA_G7221_DEFAULT_PCM_SHIFT;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000667
668 ipp_factory.pool = pjmedia_endpt_create_pool(endpt, "IPP codecs", 4000, 4000);
669 if (!ipp_factory.pool)
670 return PJ_ENOMEM;
671
672 /* Create mutex. */
673 status = pj_mutex_create_simple(ipp_factory.pool, "IPP codecs",
674 &ipp_factory.mutex);
675 if (status != PJ_SUCCESS)
676 goto on_error;
677
678 /* Get the codec manager. */
679 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
680 if (!codec_mgr) {
681 status = PJ_EINVALIDOP;
682 goto on_error;
683 }
684
685 /* Register codec factory to endpoint. */
686 status = pjmedia_codec_mgr_register_factory(codec_mgr,
687 &ipp_factory.base);
688 if (status != PJ_SUCCESS)
689 goto on_error;
690
691 /* Done. */
692 return PJ_SUCCESS;
693
694on_error:
695 pj_pool_release(ipp_factory.pool);
696 ipp_factory.pool = NULL;
697 return status;
698}
699
700/*
701 * Unregister IPP codecs factory from pjmedia endpoint.
702 */
703PJ_DEF(pj_status_t) pjmedia_codec_ipp_deinit(void)
704{
705 pjmedia_codec_mgr *codec_mgr;
706 pj_status_t status;
707
708 if (ipp_factory.pool == NULL) {
709 /* Already deinitialized */
710 return PJ_SUCCESS;
711 }
712
713 pj_mutex_lock(ipp_factory.mutex);
714
715 /* Get the codec manager. */
716 codec_mgr = pjmedia_endpt_get_codec_mgr(ipp_factory.endpt);
717 if (!codec_mgr) {
718 pj_pool_release(ipp_factory.pool);
719 ipp_factory.pool = NULL;
720 return PJ_EINVALIDOP;
721 }
722
723 /* Unregister IPP codecs factory. */
724 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
725 &ipp_factory.base);
726
727 /* Destroy mutex. */
728 pj_mutex_destroy(ipp_factory.mutex);
729
730 /* Destroy pool. */
731 pj_pool_release(ipp_factory.pool);
732 ipp_factory.pool = NULL;
733
734 return status;
735}
736
Nanang Izzuddindb5994b2010-08-10 15:06:40 +0000737/*
738 * Get current IPP codecs configuration settings.
739 */
740PJ_DEF(pj_status_t) pjmedia_codec_ipp_get_config(
741 pjmedia_codec_ipp_config *cfg)
742{
743 PJ_ASSERT_RETURN(cfg, PJ_EINVAL);
744
745 pj_bzero(cfg, sizeof(*cfg));
746 cfg->g7221_pcm_shift = ipp_factory.g7221_pcm_shift;
747
748 return PJ_SUCCESS;
749}
750
751
752/*
753 * Set IPP codecs configuration settings.
754 */
755PJ_DECL(pj_status_t) pjmedia_codec_ipp_set_config(
756 const pjmedia_codec_ipp_config *cfg)
757{
758 PJ_ASSERT_RETURN(cfg, PJ_EINVAL);
759
760 ipp_factory.g7221_pcm_shift = cfg->g7221_pcm_shift;
761
762 return PJ_SUCCESS;
763}
764
765
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000766/*
767 * Check if factory can allocate the specified codec.
768 */
769static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
770 const pjmedia_codec_info *info )
771{
772 unsigned i;
773
774 PJ_UNUSED_ARG(factory);
775
776 /* Type MUST be audio. */
777 if (info->type != PJMEDIA_TYPE_AUDIO)
778 return PJMEDIA_CODEC_EUNSUP;
779
780 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
781 pj_str_t name = pj_str((char*)ipp_codec[i].name);
782 if ((pj_stricmp(&info->encoding_name, &name) == 0) &&
783 (info->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
784 (info->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
785 (ipp_codec[i].enabled))
786 {
787 return PJ_SUCCESS;
788 }
789 }
790
791 /* Unsupported, or mode is disabled. */
792 return PJMEDIA_CODEC_EUNSUP;
793}
794
795/*
796 * Generate default attribute.
797 */
798static pj_status_t ipp_default_attr (pjmedia_codec_factory *factory,
799 const pjmedia_codec_info *id,
800 pjmedia_codec_param *attr )
801{
802 unsigned i;
803
804 PJ_ASSERT_RETURN(factory==&ipp_factory.base, PJ_EINVAL);
805
806 pj_bzero(attr, sizeof(pjmedia_codec_param));
807
808 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
809 pj_str_t name = pj_str((char*)ipp_codec[i].name);
810 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
811 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000812 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
813 (id->pt == (unsigned)ipp_codec[i].pt))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000814 {
815 attr->info.pt = (pj_uint8_t)id->pt;
816 attr->info.channel_cnt = ipp_codec[i].channel_count;
817 attr->info.clock_rate = ipp_codec[i].clock_rate;
818 attr->info.avg_bps = ipp_codec[i].def_bitrate;
819 attr->info.max_bps = ipp_codec[i].max_bitrate;
820 attr->info.pcm_bits_per_sample = 16;
821 attr->info.frm_ptime = (pj_uint16_t)
822 (ipp_codec[i].samples_per_frame * 1000 /
823 ipp_codec[i].channel_count /
824 ipp_codec[i].clock_rate);
825 attr->setting.frm_per_pkt = ipp_codec[i].frm_per_pkt;
826
827 /* Default flags. */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000828 attr->setting.plc = 1;
829 attr->setting.penh= 0;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +0000830 attr->setting.vad = 1;
831 attr->setting.cng = attr->setting.vad;
832 attr->setting.dec_fmtp = ipp_codec[i].dec_fmtp;
833
834 if (attr->setting.vad == 0) {
835#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
836 if (id->pt == PJMEDIA_RTP_PT_G729) {
837 /* Signal G729 Annex B is being disabled */
838 attr->setting.dec_fmtp.cnt = 1;
839 pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
840 pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
841 }
842#endif
843 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000844
845 return PJ_SUCCESS;
846 }
847 }
848
849 return PJMEDIA_CODEC_EUNSUP;
850}
851
852/*
853 * Enum codecs supported by this factory.
854 */
855static pj_status_t ipp_enum_codecs(pjmedia_codec_factory *factory,
856 unsigned *count,
857 pjmedia_codec_info codecs[])
858{
859 unsigned max;
860 unsigned i;
861
862 PJ_UNUSED_ARG(factory);
863 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
864
865 max = *count;
866
867 for (i = 0, *count = 0; i < PJ_ARRAY_SIZE(ipp_codec) && *count < max; ++i)
868 {
869 if (!ipp_codec[i].enabled)
870 continue;
871
872 pj_bzero(&codecs[*count], sizeof(pjmedia_codec_info));
873 codecs[*count].encoding_name = pj_str((char*)ipp_codec[i].name);
874 codecs[*count].pt = ipp_codec[i].pt;
875 codecs[*count].type = PJMEDIA_TYPE_AUDIO;
876 codecs[*count].clock_rate = ipp_codec[i].clock_rate;
877 codecs[*count].channel_cnt = ipp_codec[i].channel_count;
878
879 ++*count;
880 }
881
882 return PJ_SUCCESS;
883}
884
885/*
886 * Allocate a new codec instance.
887 */
888static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
889 const pjmedia_codec_info *id,
890 pjmedia_codec **p_codec)
891{
892 ipp_private_t *codec_data;
893 pjmedia_codec *codec;
894 int idx;
895 pj_pool_t *pool;
896 unsigned i;
897
898 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
899 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
900
901 pj_mutex_lock(ipp_factory.mutex);
902
903 /* Find codec's index */
904 idx = -1;
905 for (i = 0; i < PJ_ARRAY_SIZE(ipp_codec); ++i) {
906 pj_str_t name = pj_str((char*)ipp_codec[i].name);
907 if ((pj_stricmp(&id->encoding_name, &name) == 0) &&
908 (id->clock_rate == (unsigned)ipp_codec[i].clock_rate) &&
909 (id->channel_cnt == (unsigned)ipp_codec[i].channel_count) &&
910 (ipp_codec[i].enabled))
911 {
912 idx = i;
913 break;
914 }
915 }
916 if (idx == -1) {
917 *p_codec = NULL;
918 return PJMEDIA_CODEC_EFAILED;
919 }
920
921 /* Create pool for codec instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +0000922 pool = pjmedia_endpt_create_pool(ipp_factory.endpt, "IPPcodec", 512, 512);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +0000923 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
924 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
925 codec->op = &ipp_op;
926 codec->factory = factory;
927 codec->codec_data = PJ_POOL_ZALLOC_T(pool, ipp_private_t);
928 codec_data = (ipp_private_t*) codec->codec_data;
929
930 /* Create PLC if codec has no internal PLC */
931 if (!ipp_codec[idx].has_native_plc) {
932 pj_status_t status;
933 status = pjmedia_plc_create(pool, ipp_codec[idx].clock_rate,
934 ipp_codec[idx].samples_per_frame, 0,
935 &codec_data->plc);
936 if (status != PJ_SUCCESS) {
937 pj_pool_release(pool);
938 pj_mutex_unlock(ipp_factory.mutex);
939 return status;
940 }
941 }
942
943 /* Create silence detector if codec has no internal VAD */
944 if (!ipp_codec[idx].has_native_vad) {
945 pj_status_t status;
946 status = pjmedia_silence_det_create(pool,
947 ipp_codec[idx].clock_rate,
948 ipp_codec[idx].samples_per_frame,
949 &codec_data->vad);
950 if (status != PJ_SUCCESS) {
951 pj_pool_release(pool);
952 pj_mutex_unlock(ipp_factory.mutex);
953 return status;
954 }
955 }
956
957 codec_data->pool = pool;
958 codec_data->codec_idx = idx;
959
960 pj_mutex_unlock(ipp_factory.mutex);
961
962 *p_codec = codec;
963 return PJ_SUCCESS;
964}
965
966/*
967 * Free codec.
968 */
969static pj_status_t ipp_dealloc_codec( pjmedia_codec_factory *factory,
970 pjmedia_codec *codec )
971{
972 ipp_private_t *codec_data;
973
974 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
975 PJ_ASSERT_RETURN(factory == &ipp_factory.base, PJ_EINVAL);
976
977 /* Close codec, if it's not closed. */
978 codec_data = (ipp_private_t*) codec->codec_data;
979 if (codec_data->enc != NULL || codec_data->dec != NULL) {
980 ipp_codec_close(codec);
981 }
982
983 pj_pool_release(codec_data->pool);
984
985 return PJ_SUCCESS;
986}
987
988/*
989 * Init codec.
990 */
991static pj_status_t ipp_codec_init( pjmedia_codec *codec,
992 pj_pool_t *pool )
993{
994 PJ_UNUSED_ARG(codec);
995 PJ_UNUSED_ARG(pool);
996 return PJ_SUCCESS;
997}
998
999/*
1000 * Open codec.
1001 */
1002static pj_status_t ipp_codec_open( pjmedia_codec *codec,
1003 pjmedia_codec_param *attr )
1004{
1005 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001006 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001007 int info_size;
1008 pj_pool_t *pool;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001009 int i, j;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001010 USC_MemBank *membanks;
1011 int nb_membanks;
1012
1013 pool = codec_data->pool;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001014
1015 /* Get the codec info size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001016 if (USC_NoError != ippc->fxns->std.GetInfoSize(&info_size)) {
1017 PJ_LOG(1,(THIS_FILE, "Error getting codec info size"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001018 goto on_error;
1019 }
1020 /* Get the codec info */
1021 codec_data->info = pj_pool_zalloc(pool, info_size);
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001022 if (USC_NoError != ippc->fxns->std.GetInfo((USC_Handle)NULL,
1023 codec_data->info))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001024 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001025 PJ_LOG(1,(THIS_FILE, "Error getting codec info"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001026 goto on_error;
1027 }
1028
1029 /* PREPARING THE ENCODER */
1030
1031 /* Setting the encoder params */
1032 codec_data->info->params.direction = USC_ENCODE;
Nanang Izzuddinf216f822008-08-15 18:35:50 +00001033 codec_data->info->params.modes.vad = attr->setting.vad &&
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001034 ippc->has_native_vad;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001035 codec_data->info->params.modes.bitrate = attr->info.avg_bps;
1036 codec_data->info->params.law = 0; /* Linear PCM input */
1037
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001038#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
1039 if (ippc->pt == PJMEDIA_RTP_PT_G729) {
1040 /* Check if G729 Annex B is signaled to be disabled */
1041 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
1042 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
1043 {
1044 if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
1045 codec_data->info->params.modes.vad = 0;
1046 break;
1047 }
1048 }
1049 }
1050#endif
1051
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001052 /* Get number of memory blocks needed by the encoder */
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 encoder"));
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 encoder"));
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 encoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001077 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1078 membanks,
1079 &codec_data->enc))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001080 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001081 PJ_LOG(1,(THIS_FILE, "Error initializing encoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001082 goto on_error;
1083 }
1084
1085 /* PREPARING THE DECODER */
1086
1087 /* Setting the decoder params */
1088 codec_data->info->params.direction = USC_DECODE;
1089
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001090 /* Not sure if VAD affects decoder, just try to be safe */
Benny Prijono329d6382009-05-29 13:04:03 +00001091 //codec_data->info->params.modes.vad = ippc->has_native_vad;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001092
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001093 /* Get number of memory blocks needed by the decoder */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001094 if (USC_NoError != ippc->fxns->std.NumAlloc(&codec_data->info->params,
1095 &nb_membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001096 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001097 PJ_LOG(1,(THIS_FILE, "Error getting no of memory blocks of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001098 goto on_error;
1099 }
1100
1101 /* Allocate memory blocks table */
1102 membanks = (USC_MemBank*) pj_pool_zalloc(pool,
1103 sizeof(USC_MemBank) * nb_membanks);
1104 /* Get size of each memory block */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001105 if (USC_NoError != ippc->fxns->std.MemAlloc(&codec_data->info->params,
1106 membanks))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001107 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001108 PJ_LOG(1,(THIS_FILE, "Error getting memory blocks size of decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001109 goto on_error;
1110 }
1111
1112 /* Allocate memory for each block */
1113 for (i = 0; i < nb_membanks; i++) {
1114 membanks[i].pMem = (char*) pj_pool_zalloc(pool, membanks[i].nbytes);
1115 }
1116
1117 /* Create decoder instance */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001118 if (USC_NoError != ippc->fxns->std.Init(&codec_data->info->params,
1119 membanks, &codec_data->dec))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001120 {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001121 PJ_LOG(1,(THIS_FILE, "Error initializing decoder"));
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001122 goto on_error;
1123 }
1124
1125 /* Update codec info */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001126 ippc->fxns->std.GetInfo((USC_Handle)codec_data->enc, codec_data->info);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001127
1128 /* Get bitstream size */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001129 i = codec_data->info->params.modes.bitrate * ippc->samples_per_frame;
1130 j = ippc->clock_rate << 3;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001131 codec_data->frame_size = (pj_uint16_t)(i / j);
1132 if (i % j) ++codec_data->frame_size;
1133
1134 codec_data->vad_enabled = (attr->setting.vad != 0);
1135 codec_data->plc_enabled = (attr->setting.plc != 0);
1136
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001137#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
1138 /* Init AMR settings */
1139 if (ippc->pt == PJMEDIA_RTP_PT_AMR || ippc->pt == PJMEDIA_RTP_PT_AMRWB) {
1140 amr_settings_t *s;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001141 pj_uint8_t octet_align = 0;
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001142 pj_int8_t enc_mode;
1143
1144 enc_mode = pjmedia_codec_amr_get_mode(
1145 codec_data->info->params.modes.bitrate);
1146 pj_assert(enc_mode >= 0 && enc_mode <= 8);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001147
Benny Prijono329d6382009-05-29 13:04:03 +00001148 /* Check AMR specific attributes */
1149
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001150 for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
Benny Prijono329d6382009-05-29 13:04:03 +00001151 /* octet-align, one of the parameters that must have same value
1152 * in offer & answer (RFC 4867 Section 8.3.1). Just check fmtp
1153 * in the decoder side, since it's value is guaranteed to fulfil
1154 * above requirement (by SDP negotiator).
1155 */
1156 const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
1157
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001158 if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
1159 &STR_FMTP_OCTET_ALIGN) == 0)
1160 {
1161 octet_align=(pj_uint8_t)
Benny Prijono329d6382009-05-29 13:04:03 +00001162 pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
1163 break;
1164 }
1165 }
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001166
Benny Prijono329d6382009-05-29 13:04:03 +00001167 for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001168 /* mode-set, encoding mode is chosen based on local default mode
1169 * setting:
1170 * - if local default mode is included in the mode-set, use it
1171 * - otherwise, find the closest mode to local default mode;
1172 * if there are two closest modes, prefer to use the higher
1173 * one, e.g: local default mode is 4, the mode-set param
1174 * contains '2,3,5,6', then 5 will be chosen.
1175 */
Benny Prijono329d6382009-05-29 13:04:03 +00001176 const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
1177
1178 if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
1179 &STR_FMTP_MODE_SET) == 0)
1180 {
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001181 const char *p;
1182 pj_size_t l;
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001183 pj_int8_t diff = 99;
1184
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001185 p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
1186 l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
Benny Prijono329d6382009-05-29 13:04:03 +00001187
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001188 while (l--) {
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001189 if ((ippc->pt==PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') ||
1190 (ippc->pt==PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8'))
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001191 {
Benny Prijono1383e472009-08-01 09:23:15 +00001192 pj_int8_t tmp = (pj_int8_t)(*p - '0' - enc_mode);
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001193
1194 if (PJ_ABS(diff) > PJ_ABS(tmp) ||
1195 (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
1196 {
1197 diff = tmp;
1198 if (diff == 0) break;
1199 }
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001200 }
1201 ++p;
Benny Prijono329d6382009-05-29 13:04:03 +00001202 }
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001203
1204 if (diff == 99)
1205 goto on_error;
1206
Benny Prijono1383e472009-08-01 09:23:15 +00001207 enc_mode = (pj_int8_t)(enc_mode + diff);
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001208
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001209 break;
1210 }
1211 }
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001212
Benny Prijono329d6382009-05-29 13:04:03 +00001213 /* Initialize AMR specific settings */
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001214 s = PJ_POOL_ZALLOC_T(pool, amr_settings_t);
1215 codec_data->codec_setting = s;
1216
Benny Prijono6b6fce12009-03-17 10:13:30 +00001217 s->enc_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001218 s->enc_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001219 s->enc_setting.reorder = PJ_TRUE;
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001220 s->enc_setting.cmr = 15;
Benny Prijono329d6382009-05-29 13:04:03 +00001221
Benny Prijono6b6fce12009-03-17 10:13:30 +00001222 s->dec_setting.amr_nb = (pj_uint8_t)(ippc->pt == PJMEDIA_RTP_PT_AMR);
Nanang Izzuddin0b8f4ca2008-11-11 11:25:13 +00001223 s->dec_setting.octet_aligned = octet_align;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001224 s->dec_setting.reorder = PJ_TRUE;
Benny Prijono329d6382009-05-29 13:04:03 +00001225
Nanang Izzuddin0b9da642009-06-02 16:28:24 +00001226 /* Apply encoder mode/bitrate */
1227 s->enc_mode = enc_mode;
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001228 codec_data->info->params.modes.bitrate = s->enc_setting.amr_nb?
1229 pjmedia_codec_amrnb_bitrates[s->enc_mode]:
1230 pjmedia_codec_amrwb_bitrates[s->enc_mode];
1231 ippc->fxns->std.Control(&codec_data->info->params.modes,
1232 codec_data->enc);
Benny Prijono329d6382009-05-29 13:04:03 +00001233
Nanang Izzuddin18a9ef12009-06-02 12:38:15 +00001234 PJ_LOG(4,(THIS_FILE, "AMR%s encoding mode: %d (%dbps)",
1235 (s->enc_setting.amr_nb?"":"-WB"),
1236 s->enc_mode,
1237 codec_data->info->params.modes.bitrate));
Nanang Izzuddin06839e72010-01-27 11:48:31 +00001238
1239 /* Return back bitrate info to application */
1240 attr->info.avg_bps = codec_data->info->params.modes.bitrate;
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001241 }
1242#endif
1243
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001244#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1245 if (ippc->pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1246 ippc->pt <= PJMEDIA_RTP_PT_G7221_RSV2)
1247 {
1248 codec_data->g7221_pcm_shift = ipp_factory.g7221_pcm_shift;
1249 }
1250#endif
1251
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001252 return PJ_SUCCESS;
1253
1254on_error:
1255 return PJMEDIA_CODEC_EFAILED;
1256}
1257
1258/*
1259 * Close codec.
1260 */
1261static pj_status_t ipp_codec_close( pjmedia_codec *codec )
1262{
1263 PJ_UNUSED_ARG(codec);
1264
1265 return PJ_SUCCESS;
1266}
1267
1268
1269/*
1270 * Modify codec settings.
1271 */
1272static pj_status_t ipp_codec_modify(pjmedia_codec *codec,
1273 const pjmedia_codec_param *attr )
1274{
1275 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001276 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001277
1278 codec_data->vad_enabled = (attr->setting.vad != 0);
1279 codec_data->plc_enabled = (attr->setting.plc != 0);
1280
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001281 if (ippc->has_native_vad) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001282 USC_Modes modes;
1283
1284 modes = codec_data->info->params.modes;
1285 modes.vad = codec_data->vad_enabled;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001286 ippc->fxns->std.Control(&modes, codec_data->enc);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001287 }
1288
1289 return PJ_SUCCESS;
1290}
1291
1292/*
1293 * Get frames in the packet.
1294 */
1295static pj_status_t ipp_codec_parse( pjmedia_codec *codec,
1296 void *pkt,
1297 pj_size_t pkt_size,
1298 const pj_timestamp *ts,
1299 unsigned *frame_cnt,
1300 pjmedia_frame frames[])
1301{
1302 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001303 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001304 unsigned count = 0;
1305
1306 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
1307
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001308 if (ippc->parse != NULL) {
1309 return ippc->parse(codec_data, pkt, pkt_size, ts, frame_cnt, frames);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001310 }
1311
1312 while (pkt_size >= codec_data->frame_size && count < *frame_cnt) {
1313 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1314 frames[count].buf = pkt;
1315 frames[count].size = codec_data->frame_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
1318 pkt = ((char*)pkt) + codec_data->frame_size;
1319 pkt_size -= codec_data->frame_size;
1320
1321 ++count;
1322 }
1323
1324 if (pkt_size && count < *frame_cnt) {
1325 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
1326 frames[count].buf = pkt;
1327 frames[count].size = pkt_size;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001328 frames[count].timestamp.u64 = ts->u64 + count*ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001329 ++count;
1330 }
1331
1332 *frame_cnt = count;
1333 return PJ_SUCCESS;
1334}
1335
1336/*
1337 * Encode frames.
1338 */
1339static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
1340 const struct pjmedia_frame *input,
1341 unsigned output_buf_len,
1342 struct pjmedia_frame *output)
1343{
1344 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001345 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001346 unsigned samples_per_frame;
1347 unsigned nsamples;
1348 pj_size_t tx = 0;
1349 pj_int16_t *pcm_in = (pj_int16_t*)input->buf;
Benny Prijonob1339242008-08-21 20:58:55 +00001350 pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001351 pj_uint8_t pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001352
1353 /* Invoke external VAD if codec has no internal VAD */
1354 if (codec_data->vad && codec_data->vad_enabled) {
1355 pj_bool_t is_silence;
1356 pj_int32_t silence_duration;
1357
1358 silence_duration = pj_timestamp_diff32(&codec_data->last_tx,
1359 &input->timestamp);
1360
1361 is_silence = pjmedia_silence_det_detect(codec_data->vad,
1362 (const pj_int16_t*) input->buf,
1363 (input->size >> 1),
1364 NULL);
1365 if (is_silence &&
Nanang Izzuddin4ff93f42009-06-13 15:28:37 +00001366 (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
1367 silence_duration < (PJMEDIA_CODEC_MAX_SILENCE_PERIOD *
1368 (int)ippc->clock_rate / 1000)))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001369 {
1370 output->type = PJMEDIA_FRAME_TYPE_NONE;
1371 output->buf = NULL;
1372 output->size = 0;
1373 output->timestamp = input->timestamp;
1374 return PJ_SUCCESS;
1375 } else {
1376 codec_data->last_tx = input->timestamp;
1377 }
1378 }
1379
1380 nsamples = input->size >> 1;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001381 samples_per_frame = ippc->samples_per_frame;
1382 pt = ippc->pt;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001383
1384 PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
1385 PJMEDIA_CODEC_EPCMFRMINLEN);
1386
1387 /* Encode the frames */
1388 while (nsamples >= samples_per_frame) {
1389 USC_PCMStream in;
1390 USC_Bitstream out;
1391
1392 in.bitrate = codec_data->info->params.modes.bitrate;
1393 in.nbytes = samples_per_frame << 1;
1394 in.pBuffer = (char*)pcm_in;
1395 in.pcmType.bitPerSample = codec_data->info->params.pcmType.bitPerSample;
1396 in.pcmType.nChannels = codec_data->info->params.pcmType.nChannels;
1397 in.pcmType.sample_frequency = codec_data->info->params.pcmType.sample_frequency;
1398
Benny Prijonob1339242008-08-21 20:58:55 +00001399 out.pBuffer = (char*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001400
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001401#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001402 /* For AMR: reserve two octets for AMR frame info */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001403 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001404 out.pBuffer += 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001405 }
1406#endif
1407
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001408#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1409 /* For G722.1: adjust the encoder input signal level */
1410 if (pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1411 pt <= PJMEDIA_RTP_PT_G7221_RSV2 &&
1412 codec_data->g7221_pcm_shift)
1413 {
1414 unsigned i;
1415 for (i = 0; i < samples_per_frame; ++i)
1416 pcm_in[i] >>= codec_data->g7221_pcm_shift;
1417 }
1418#endif
1419
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001420 if (USC_NoError != ippc->fxns->Encode(codec_data->enc, &in, &out)) {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001421 break;
1422 }
1423
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001424#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
Nanang Izzuddin35e01de2008-10-29 10:17:02 +00001425 /* For AMR: put info (frametype, degraded, last frame, mode) in the
1426 * first two octets for payload packing.
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001427 */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001428 if (pt == PJMEDIA_RTP_PT_AMR || pt == PJMEDIA_RTP_PT_AMRWB) {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001429 pj_uint16_t *info = (pj_uint16_t*)bits_out;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001430
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001431 /* Two octets for AMR frame info, 0=LSB:
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001432 * bit 0-3 : frame type
1433 * bit 6 : last frame flag
1434 * bit 7 : quality flag
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001435 * bit 8-11 : mode
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001436 */
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001437 out.nbytes += 2;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001438 if (out.frametype == 0 || out.frametype == 4 ||
1439 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 5) ||
1440 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 6))
1441 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001442 /* Speech frame type */
1443 *info = (char)pjmedia_codec_amr_get_mode(out.bitrate);
1444 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001445 if (out.frametype == 5 || out.frametype == 6)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001446 *info |= 0x80;
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001447 } else if (out.frametype == 1 || out.frametype == 2 ||
1448 (pt == PJMEDIA_RTP_PT_AMR && out.frametype == 6) ||
1449 (pt == PJMEDIA_RTP_PT_AMRWB && out.frametype == 7))
1450 {
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001451 /* SID frame type */
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001452 *info = (pj_uint8_t)(pt == PJMEDIA_RTP_PT_AMRWB? 9 : 8);
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001453 /* Quality */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001454 if (out.frametype == 6 || out.frametype == 7)
1455 *info |= 0x80;
1456 } else {
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001457 /* Untransmited */
1458 *info = 15;
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001459 out.nbytes = 2;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001460 }
1461
Nanang Izzuddind55553a2008-10-28 02:24:46 +00001462 /* Mode */
1463 *info |= (char)pjmedia_codec_amr_get_mode(out.bitrate) << 8;
1464
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001465 /* Last frame flag */
1466 if (nsamples == samples_per_frame)
1467 *info |= 0x40;
1468 }
Nanang Izzuddin7dd32682008-08-19 11:23:33 +00001469#endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001470
1471 pcm_in += samples_per_frame;
1472 nsamples -= samples_per_frame;
1473 tx += out.nbytes;
1474 bits_out += out.nbytes;
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001475
1476#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
Nanang Izzuddine3a6fca2008-08-27 13:15:25 +00001477 if (pt == PJMEDIA_RTP_PT_G729) {
1478 if (out.frametype == 1) {
1479 /* SID */
1480 break;
1481 } else if (out.frametype == 0) {
1482 /* Untransmitted */
1483 tx -= out.nbytes;
1484 break;
1485 }
Nanang Izzuddin23a00b72008-08-25 13:58:25 +00001486 }
1487#endif
1488
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001489 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001490
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001491 if (ippc->pack != NULL) {
1492 ippc->pack(codec_data, output->buf, &tx, output_buf_len);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001493 }
1494
1495 /* Check if we don't need to transmit the frame (DTX) */
1496 if (tx == 0) {
1497 output->buf = NULL;
1498 output->size = 0;
1499 output->timestamp.u64 = input->timestamp.u64;
1500 output->type = PJMEDIA_FRAME_TYPE_NONE;
1501 return PJ_SUCCESS;
1502 }
1503
1504 output->size = tx;
1505 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1506 output->timestamp = input->timestamp;
1507
1508 return PJ_SUCCESS;
1509}
1510
1511/*
1512 * Decode frame.
1513 */
1514static pj_status_t ipp_codec_decode( pjmedia_codec *codec,
1515 const struct pjmedia_frame *input,
1516 unsigned output_buf_len,
1517 struct pjmedia_frame *output)
1518{
1519 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001520 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001521 unsigned samples_per_frame;
1522 USC_PCMStream out;
1523 USC_Bitstream in;
1524 pj_uint8_t pt;
1525
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001526 pt = ippc->pt;
1527 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001528
1529 PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1,
1530 PJMEDIA_CODEC_EPCMTOOSHORT);
1531
1532 if (input->type == PJMEDIA_FRAME_TYPE_AUDIO) {
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001533 if (ippc->predecode) {
1534 ippc->predecode(codec_data, input, &in);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001535 } else {
1536 /* Most IPP codecs have frametype==0 for speech frame */
Nanang Izzuddindf361e02008-08-16 06:46:08 +00001537 in.pBuffer = (char*)input->buf;
1538 in.nbytes = input->size;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001539 in.frametype = 0;
1540 in.bitrate = codec_data->info->params.modes.bitrate;
1541 }
1542
1543 out.pBuffer = output->buf;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001544 }
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001545
1546 if (input->type != PJMEDIA_FRAME_TYPE_AUDIO ||
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001547 USC_NoError != ippc->fxns->Decode(codec_data->dec, &in, &out))
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001548 {
1549 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1550 output->size = samples_per_frame << 1;
1551 output->timestamp.u64 = input->timestamp.u64;
1552 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1553 return PJ_SUCCESS;
1554 }
1555
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001556#if PJMEDIA_HAS_INTEL_IPP_CODEC_G726
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001557 /* For G.726: amplify decoding result (USC G.726 encoder deamplified it) */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001558 if (pt == PJMEDIA_RTP_PT_G726_16 || pt == PJMEDIA_RTP_PT_G726_24 ||
Nanang Izzuddincf4d1412010-06-07 05:23:56 +00001559 pt == PJMEDIA_RTP_PT_G726_32 || pt == PJMEDIA_RTP_PT_G726_40 ||
1560 pt == PJMEDIA_RTP_PT_G721)
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001561 {
1562 unsigned i;
1563 pj_int16_t *s = (pj_int16_t*)output->buf;
1564
1565 for (i = 0; i < samples_per_frame; ++i)
1566 s[i] <<= 2;
1567 }
1568#endif
1569
Nanang Izzuddindb5994b2010-08-10 15:06:40 +00001570#if PJMEDIA_HAS_INTEL_IPP_CODEC_G722_1
1571 /* For G722.1: adjust the decoder output signal level */
1572 if (pt >= PJMEDIA_RTP_PT_G722_1_16 &&
1573 pt <= PJMEDIA_RTP_PT_G7221_RSV2 &&
1574 codec_data->g7221_pcm_shift)
1575 {
1576 unsigned i;
1577 pj_int16_t *s = (pj_int16_t*)output->buf;
1578
1579 for (i = 0; i < samples_per_frame; ++i)
1580 s[i] <<= codec_data->g7221_pcm_shift;
1581 }
1582#endif
1583
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001584 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1585 output->size = samples_per_frame << 1;
1586 output->timestamp.u64 = input->timestamp.u64;
1587
1588 /* Invoke external PLC if codec has no internal PLC */
1589 if (codec_data->plc && codec_data->plc_enabled)
1590 pjmedia_plc_save(codec_data->plc, (pj_int16_t*)output->buf);
1591
1592 return PJ_SUCCESS;
1593}
1594
1595/*
1596 * Recover lost frame.
1597 */
1598static pj_status_t ipp_codec_recover(pjmedia_codec *codec,
1599 unsigned output_buf_len,
1600 struct pjmedia_frame *output)
1601{
1602 ipp_private_t *codec_data = (ipp_private_t*) codec->codec_data;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001603 struct ipp_codec *ippc = &ipp_codec[codec_data->codec_idx];
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001604 unsigned samples_per_frame;
1605
1606 PJ_UNUSED_ARG(output_buf_len);
1607
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001608 samples_per_frame = ippc->samples_per_frame;
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001609
1610 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
1611 output->size = samples_per_frame << 1;
1612
1613 if (codec_data->plc_enabled) {
1614 if (codec_data->plc) {
1615 pjmedia_plc_generate(codec_data->plc, (pj_int16_t*)output->buf);
1616 } else {
1617 USC_PCMStream out;
1618 out.pBuffer = output->buf;
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001619 ippc->fxns->Decode(codec_data->dec, NULL, &out);
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001620 }
1621 } else {
1622 pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
1623 }
1624
1625 return PJ_SUCCESS;
1626}
1627
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001628
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001629#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_IPP_LIBS
1630# pragma comment( lib, "ippcore.lib")
1631# pragma comment( lib, "ipps.lib")
1632# pragma comment( lib, "ippsc.lib")
1633# pragma comment( lib, "ippsr.lib")
Benny Prijonoc543e9e2009-01-03 12:19:53 +00001634//# pragma comment( lib, "ippcorel.lib")
1635//# pragma comment( lib, "ippsemerged.lib")
1636//# pragma comment( lib, "ippsmerged.lib")
1637//# pragma comment( lib, "ippscemerged.lib")
1638//# pragma comment( lib, "ippscmerged.lib")
1639//# pragma comment( lib, "ippsremerged.lib")
1640//# pragma comment( lib, "ippsrmerged.lib")
Benny Prijonoe1e6d512009-01-02 15:17:47 +00001641# if defined(IPP_VERSION_MAJOR) && IPP_VERSION_MAJOR>=6
1642# pragma comment( lib, "speech.lib")
1643# else
1644# pragma comment( lib, "usc.lib")
1645# endif
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001646#endif
1647
1648
Benny Prijonoa4e7cdd2008-08-19 15:01:48 +00001649#endif /* PJMEDIA_HAS_INTEL_IPP */
Nanang Izzuddin493a8db2008-08-15 13:17:39 +00001650