1 /****************************************************************************
2 *
3 * AMR-WB (ITU G.722.2) Plugin codec for OpenH323/OPAL
4 *
5 * Copyright (c) 2009 Nimajin Software Consulting, All Rights Reserved
6 *
7 * Permission to copy, use, sell and distribute this file is granted
8 * provided this copyright notice appears in all copies.
9 * Permission to modify the code herein and to distribute modified code is
10 * granted provided this copyright notice appears in all copies, and a
11 * notice that the code was modified is included with the copyright notice.
12 *
13 * This software and information is provided "as is" without express or im-
14 * plied warranty, and with no claim as to its suitability for any purpose.
15 *
16 ****************************************************************************
17 *
18 * AMR WB ACELP wideband decoder described in 3GPP TS 26.171, 26.190, 26.201
19 * AMR-WB is, in fact, ITU G.722.2.
20 * G.722.2 Annex F specifies usage in H.245.
21 * There is newer but conflicting H.245 info in H.245 v13 Annex R.
22 * This code follows the G.722.2 H.245 signaling.
23 * Its payload format & SDP parameters are described in IETF RFC 3267
24 * This implementation employs 3GPP TS 26.173 fixed point reference code.
25 * It implements Adaptive Multi Rate Wideband speech transcoder (3GPP TS
26 * 26.190), Voice Activity Detection (3GPP TS 26.194), and comfort noise (3GPP
27 * TS 26.192)
28 * This build has not defined IF2
29 * Encodes to octet-aligned format only (not bandwidth efficient)
30 * Encodes to 23.85 kbps only (no mode change support)
31 * Mode adaption not supported (needs work to link decoder to encoder)
32 * Decoder handles only 1 frame (no multichannel or interleaving)
33 * Decoder can handle any mode, and both octet-aligned and bandwidth efficient
34 * AMR-WB is patented. Use requires licence from VoiceAge.
35 *
36 * Initial development by: Ted Szoczei, Nimajin Software Consulting, 09-12-31
37 *
38 * 06-04-03 Revise to conform to RFC 3267: use correct packet sizes, handle
39 * missing CMR, detect use of bandwidth efficient mode, pass quality
40 * indicator to decoder. /tsz
41 ****************************************************************************/
42
43
44 #define _CRT_NONSTDC_NO_DEPRECATE 1
45 #define _CRT_SECURE_NO_WARNINGS 1
46
47 #include <stdlib.h>
48
49 #ifndef PLUGIN_CODEC_DLL_EXPORTS
50 #include "plugin-config.h"
51 #endif
52
53 #include <codec/opalplugin.h>
54
55
56 static struct PluginCodec_information AMRWBLicenseInformation = {
57 1262283223, // version timestamp = Thu Dec 31 18:13:43 2009
58
59 "Ted Szoczei, Nimajin Software Consulting", // source code author
60 "1.0", // source code version
61 "ted.szoczei@nimajin.com", // source code email
62 "http://www.nimajin.com", // source code URL
63 "Copyright (c) 2009 Nimajin Software Consulting", // source code copyright
64 "None", // source code license
65 PluginCodec_License_None, // source code license
66
67 "G.722.2 AMR-WB (Wideband Adaptive Multirate Codec)", // codec description
68 "3rd Generation Partnership Project (3GPP)", // codec author
69 "TS 26.173 V6.0.0 2004-12", // codec version
70 NULL, // codec email
71 "http://www.3gpp.org", // codec URL
72 "", // codec copyright information
73 "", // codec license
74 PluginCodec_License_RoyaltiesRequired // codec license code
75 };
76
77 /////////////////////////////////////////////////////////////////////////////
78
79
80 extern "C" {
81 #include "AMR-WB/enc_if.h"
82 #include "AMR-WB/dec_if.h"
83 };
84
85 enum ConversionMode { // these equate to modes in enc_main.c
86 AMRWB_7k = 0, // 6.60 kbit/s
87 AMRWB_9k, // 8.85 kbit/s
88 AMRWB_12k, // 12.65 kbit/s
89 AMRWB_14k, // 14.25 kbit/s
90 AMRWB_16k, // 15.85 kbit/s
91 AMRWB_18k, // 18.25 kbit/s
92 AMRWB_20k, // 19.85 kbit/s
93 AMRWB_23k, // 23.05 kbit/s
94 AMRWB_24k, // 23.85 kbit/s default
95 AMRWB_MODES,
96 AMRWB_SID = 9, // dtx
97 AMRWB_LOST = 14,
98 AMRWB_NODATA = 15
99 };
100
101 // This stuff copied from AMR-WB/if_rom.c
102 // AMR-WB did not extern their block size table, they only use it to clear data before encoding.
103
104 // One encoded frame (bytes): includes TOC, but not header
105 // AMRWB_core_block_bits is the number of bits for each core frame
106 // AMRWB_block_size_octet is the number of octets for each core frame and ToC for RFC 3267 octet-aligned packing
107
108 const UWord16 AMRWB_core_block_bits[16]= { 132, 177, 253, 285, 317, 365, 397, 461, 477, 40, 40, 0, 0, 0, 0, 0 };
109 const UWord16 AMRWB_efficient_ToC_bits = 6;
110 const UWord16 AMRWB_efficient_CMR_bits = 4;
111
112 const UWord8 AMRWB_block_size_octet[16]= { 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1 };
113
114 // RFC 3267 octet-aligned ToC adds 8 bits to each core speech bits frame and 8 per packet for header
115 // RFC 3267 bandwidth-efficient adds 6 bits to each core speech bits frame and 4 per packet for header
116 // 3GPP IF1 mode adds 24 bits to core speech bits
117 // 3GPP IF2 mode adds 5 bits to core speech bits
118
119 #define AMRWB_ALIGNED_BPS(mode) ((AMRWB_block_size_octet[(mode)] + 1) * 50 * 8)
120
121 // All formats except 3GPP IF1 pad the core frame to fill the last octet (even when there are multiple
122 // frames within the packet).
123 // This build has not defined IF2
124 // RFC 3267 bandwidth-efficient format does not pad between multiple ToC entries.
125 // LOST & NODATA packets have no core data, Thus the rounding-up for block size only counts for
126 // their ToC entries.
127
128 // works with 320 samples per frame (20 ms)
129
130 #define AMRWB_FRAME_SAMPLES 320
131
132
133 /////////////////////////////////////////////////////////////////////////////
134 // Convert PCM16-16KHZ to AMR-WB
135 // Convert 320 samples of audio (mode 0 produces 19 bytes output, mode 8, 62)
136 // Output packed according to RFC 3267, section 4.4 (octet aligned)
137 // Supports only single 20 ms frame per packet.
138
139 // this is what we hand back when we are asked to create an encoder
140 typedef struct
141 {
142 void * state; // Encoder interface's opaque state
143 unsigned mode; // current mode
144 int vad; // silence suppression 1/0
145 } AMRWBEncoderContext;
146
147
AMRWBEncoderCreate(const struct PluginCodec_Definition * codec)148 static void * AMRWBEncoderCreate (const struct PluginCodec_Definition * codec)
149 {
150 AMRWBEncoderContext * Context = (AMRWBEncoderContext *) malloc (sizeof(AMRWBEncoderContext));
151 if (Context == NULL)
152 return NULL;
153
154 Context->mode = AMRWB_24k; // start off in 23.85kbps mode
155 Context->vad = 0; // with no VAD/DTX/CN
156
157 Context->state = E_IF_init ();
158 if (Context->state == NULL)
159 {
160 free (Context);
161 return NULL;
162 }
163 return Context;
164 }
165
166
AMRWBEncoderDestroy(const struct PluginCodec_Definition * codec,void * context)167 static void AMRWBEncoderDestroy (const struct PluginCodec_Definition * codec, void * context)
168 {
169 AMRWBEncoderContext * Context = (AMRWBEncoderContext *)context;
170 E_IF_exit (Context->state);
171 free (Context);
172 }
173
174
AMRWBEncode(const struct PluginCodec_Definition * codec,void * context,const void * fromPtr,unsigned * fromLen,void * toPtr,unsigned * toLen,unsigned int * flag)175 static int AMRWBEncode (const struct PluginCodec_Definition * codec,
176 void * context,
177 const void * fromPtr,
178 unsigned * fromLen,
179 void * toPtr,
180 unsigned * toLen,
181 unsigned int * flag)
182 {
183 AMRWBEncoderContext * Context = (AMRWBEncoderContext *)context;
184 if (*fromLen != AMRWB_FRAME_SAMPLES * sizeof(short))
185 {
186 //PTRACE(2, "Codec\tAMR-WB encoder: Audio data of size " << *fromLen << " did not match expected " << AMRWB_FRAME_SAMPLES * sizeof(short));
187 return 0;
188 }
189 if (*toLen < (unsigned) AMRWB_block_size_octet[Context->mode] + 1)
190 {
191 //PTRACE(2,"Codec\tAMR-WB encoder: Output buffer of size " << *toLen << " too short for mode " << mode);
192 return 0;
193 }
194 // First byte is CMR (change mode request). 0xF0 means we'll take anything.
195 UWord8 * Dest = (UWord8 *) toPtr;
196 *Dest++ = 0x80;//0xF0; / 0x80 means we want 24kbps only (BT phone won't accept 0xF0)
197
198 // Next byte is TOC (containing frame type), then follows encoded data
199 // The TOC and data are both written by E_IF_encode.
200 int ByteCount = E_IF_encode (Context->state, (Word16) Context->mode, (short *) fromPtr, Dest, Context->vad);
201 if (ByteCount < 1)
202 {
203 *toLen = 0;
204 return 0; // Bad mode
205 }
206 *toLen = ByteCount + 1;
207 return 1;
208 }
209
210
211 /////////////////////////////////////////////////////////////////////////////
212 // Convert AMR-WB to PCM16-16KHZ
213 // Convert encoded source to 320 samples of audio.
214 // Allows only input packed according to RFC 3267, section 4.4 (octet aligned),
215 // but header byte (change mode request) may be missing.
216 // this code does not handle multiple frame packets!
217
218
AMRWBDecoderCreate(const struct PluginCodec_Definition * codec)219 static void * AMRWBDecoderCreate (const struct PluginCodec_Definition * codec)
220 {
221 return D_IF_init ();
222 }
223
224
AMRWBDecoderDestroy(const struct PluginCodec_Definition * codec,void * context)225 static void AMRWBDecoderDestroy (const struct PluginCodec_Definition * codec, void * context)
226 {
227 D_IF_exit (context);
228 }
229
230
231 // AMRWB_7k = 0 0x04 frame_type = 0, fqi = 1
232 // AMRWB_9k, 0x0C frame_type = 1, fqi = 1
233 // AMRWB_12k, 0x14 frame_type = 2, fqi = 1
234 // AMRWB_14k, 0x1C frame_type = 3, fqi = 1
235 // AMRWB_16k, 0x24 frame_type = 4, fqi = 1
236 // AMRWB_18k, 0x2C frame_type = 5, fqi = 1
237 // AMRWB_20k, 0x34 frame_type = 6, fqi = 1
238 // AMRWB_23k, 0x3C frame_type = 7, fqi = 1
239 // AMRWB_24k, 0x44 frame_type = 8, fqi = 1
240 // AMRWB_SID = 9, 0x4C frame_type = 9, fqi = 1 DTX/VAD/CN
241 // AMRWB_LOST = 14,
242 // AMRWB_NODATA = 15
243
AMRWBTypeGet(const UWord8 byte)244 static int AMRWBTypeGet (const UWord8 byte)
245 {
246 if ((byte & 0x03) != 0) // pad bits must be 0
247 return -1;
248
249 int Type = (byte >> 3) & 0x0F;
250 if (Type > AMRWB_SID && Type != AMRWB_LOST && Type != AMRWB_NODATA)
251 return -1;
252
253 return Type;
254 }
255
AMRWBIsBandWidthEfficient(const unsigned short word,const unsigned int packetSize)256 int AMRWBIsBandWidthEfficient (const unsigned short word, const unsigned int packetSize)
257 {
258 int RequestedMode = (word >> 12) & 0x0F;
259 if (RequestedMode > AMRWB_24k && RequestedMode != AMRWB_NODATA)
260 return 0;
261
262 int Type = (word >> 7) & 0x0F;
263 if (Type > AMRWB_SID && Type != AMRWB_LOST && Type != AMRWB_NODATA)
264 return 0;
265
266 // this code does not handle multiple frame packets!
267 unsigned int ExpectedSize = (AMRWB_core_block_bits[Type] + AMRWB_efficient_ToC_bits + AMRWB_efficient_CMR_bits + 7) / 8;
268 return (ExpectedSize == packetSize)? 1 : 0;
269 }
270
271
AMRWBDecode(const struct PluginCodec_Definition * codec,void * context,const void * fromPtr,unsigned * fromLen,void * toPtr,unsigned * toLen,unsigned int * flag)272 static int AMRWBDecode (const struct PluginCodec_Definition * codec,
273 void * context,
274 const void * fromPtr,
275 unsigned * fromLen,
276 void * toPtr,
277 unsigned * toLen,
278 unsigned int * flag)
279 {
280 if (fromPtr == NULL || fromLen == NULL || (*flag & PluginCodec_CoderSilenceFrame) != 0)
281 { // no data: return comfort noise
282 D_IF_decode (context, NULL, (Word16 *) toPtr, _no_frame);
283 }
284 else
285 {
286 if (*fromLen < 1)
287 {
288 //PTRACE(2,"Codec\tAMR-WB decoder: No input");
289 return 0;
290 }
291 if (*toLen < AMRWB_FRAME_SAMPLES * sizeof(short))
292 {
293 //PTRACE(2,"Codec\tAMR-WB decoder: Output buffer of size " << *toLen << " less than " << AMRWB_FRAME_SAMPLES * sizeof(short) << " required");
294 return 0;
295 }
296 // test the input packet
297 UWord8 * Src = (UWord8 *) fromPtr;
298 int Quality = ((*(Src + 1) & 0x04) == 0)? _bad_frame : _good_frame;
299 int Followed = (*(Src + 1) >> 7) & 0x01;
300 int FrameType = AMRWBTypeGet (*(Src + 1));
301 int RequestedMode = -1;
302 int ValidPacket = -1; // -3=bad CMR octet, -2=bad size, -1=bad frametype, 0=bad CMR value, 1=good
303 int Input = 1; // offset into Src of start of data (Toc) for decoding
304 if (FrameType >= 0)
305 { // check for valid header & ToC pair
306 ValidPacket = (*fromLen == AMRWB_block_size_octet[FrameType] + 1)? 1 : -2;
307 if (ValidPacket > 0)
308 { // size is right
309 if ((*Src & 0x0F) != 0) // test CMR byte structure
310 ValidPacket = -3;
311 else
312 { // test CMR value
313 RequestedMode = (*Src >> 4) & 0x0F;
314 if (RequestedMode < AMRWB_7k
315 || (RequestedMode > AMRWB_24k && RequestedMode != 0x0F))
316 ValidPacket = 0; // probably proper octet-aligned packet but possibly bad, check alternatives
317 }
318 }
319 }
320 if (ValidPacket <= 0)
321 { // not a valid 2-octet header & TOC, try just ToC
322 int TOCFrameType = AMRWBTypeGet (*Src);
323 if (TOCFrameType >= 0 && *fromLen == AMRWB_block_size_octet[TOCFrameType])
324 {
325 ValidPacket = 1;
326 FrameType = TOCFrameType;
327 Quality = ((*Src & 0x04) == 0)? _bad_frame : _good_frame;
328 Followed = (*Src & 0x80) >> 7;
329 Input = 0;
330 //PTRACE(2, "Codec\tAMR-WB decoder: Received packet without header (CMR) octet - contrary to RFC 3267, processed anyway");
331 //PTRACE(2, "Codec\tAMR-WB decoder: First octet value was ToC 0x"
332 // << hex << setfill('0') << setprecision(2) << (unsigned) *Src << dec << setfill(' ')
333 // << " (F=" << Followed << " FT=" << FrameType << " Q=" << (Quality ^ 1) << ')');
334 }
335 } // check if invalid octet-aligned packet is bandwidth efficient type
336 if (ValidPacket < 0 && AMRWBIsBandWidthEfficient ((*Src << 8) + *(Src + 1), *fromLen))
337 {
338 //PTRACE(2, "Codec\tAMR-WB decoder: Received packet appeared to be packed in RFC 3267 bandwidth efficient mode. Unsupported.");
339 return 0;
340 }
341 switch (ValidPacket)
342 { // it's octet-aligned but bad
343 case -1:
344 //PTRACE(2, "Codec\tAMR-WB decoder: Received packet with invalid ToC octet 0x"
345 // << hex << setfill('0') << setprecision(2) << (unsigned)*(Src + 1) << dec << setfill(' '));
346 return 0;
347
348 case -2:
349 //PTRACE(2, "Codec\tAMR-WB decoder: Packet size " << *fromLen << " did not match expected " << (unsigned)(AMRWB_block_size_octet[FrameType] + 1) << " for frame type " << FrameType);
350 return 0;
351
352 case -3:
353 //PTRACE(2, "Codec\tAMR-WB decoder: Received packet with invalid header octet 0x"
354 // << hex << setfill('0') << setprecision(2) << (unsigned) *Src << dec << setfill(' '));
355 return 0;
356 }
357 // Aw.. we did all that work and can't change encoder's mode because send & receive contexts are not attached!
358 //if (ValidPacket == 0)
359 // PTRACE(2, "Codec\tAMR-WB decoder: Received packet with invalid requested mode " << RequestedMode << ", mode change ignored");
360
361 //else if (RequestedMode != 0x0F) // 0x0F means no change requested, so we'll just stick to sending whatever the last mode was
362 // mode = (ConversionMode) RequestedMode;
363
364 //if (Followed)
365 // PTRACE(2, "Codec\tAMR-WB decoder: Received packet indicated multiple frames. Unsupported. Audio was lost.");
366
367 D_IF_decode (context, Src + Input, (Word16 *) toPtr, Quality);
368
369 // return the number of decoded bytes to the caller
370 *fromLen = AMRWB_block_size_octet[FrameType] + Input; // Actual bytes consumed
371 }
372 *toLen = AMRWB_FRAME_SAMPLES * sizeof(short);
373 return 1;
374 }
375
376
377 /////////////////////////////////////////////////////////////////////////////
378
379 // H.245 generic parameters; see G.722.2
380 enum
381 {
382 H245_G7222_MAXAL_SDUFRAMES_RX = 0 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS,
383 H245_G7222_MAXAL_SDUFRAMES_TX = 0 | PluginCodec_H245_Collapsing | PluginCodec_H245_OLC,
384 H245_G7222_REQUEST_MODE = 1 | PluginCodec_H245_NonCollapsing| PluginCodec_H245_ReqMode,
385 H245_G7222_OCTET_ALIGNED = 2 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
386 H245_G7222_MODE_SET = 3 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
387 H245_G7222_MODE_CHANGE_PERIOD = 4 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
388 H245_G7222_MODE_CHANGE_NEIGHBOUR=5| PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
389 H245_G7222_CRC = 6 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
390 H245_G7222_ROBUST_SORTING = 7 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
391 H245_G7222_INTERLEAVING = 8 | PluginCodec_H245_Collapsing | PluginCodec_H245_TCS | PluginCodec_H245_OLC | PluginCodec_H245_ReqMode,
392 };
393
394 // limit frames per packet to 1
395
396 static struct PluginCodec_Option const AMRWBOptionRxFramesPerPacket =
397 {
398 PluginCodec_IntegerOption, // PluginCodec_OptionTypes
399 PLUGINCODEC_OPTION_RX_FRAMES_PER_PACKET, // Generic (human readable) option name
400 false, // User Read/Only flag
401 PluginCodec_MinMerge, // Merge mode
402 "1", // Initial value
403 NULL, // SIP/SDP FMTP name
404 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
405 H245_G7222_MAXAL_SDUFRAMES_RX, // H.245 generic capability code and bit mask
406 "1", // Minimum value
407 "1" // Maximum value // Do not change!! See above.
408 };
409
410 static struct PluginCodec_Option const AMRWBOptionTxFramesPerPacket =
411 {
412 PluginCodec_IntegerOption, // Option type
413 PLUGINCODEC_OPTION_TX_FRAMES_PER_PACKET, // User visible name
414 false, // User Read/Only flag
415 PluginCodec_MinMerge, // Merge mode
416 "1", // Initial value
417 NULL, // FMTP option name
418 NULL, // FMTP default value
419 H245_G7222_MAXAL_SDUFRAMES_TX, // H.245 generic capability code and bit mask
420 "1", // Minimum value
421 "1" // Maximum value
422 };
423
424 // this is here so FMTP always adds 'octet-align=1'
425 // this option is indicated in fmtp by its presence
426
427 static struct PluginCodec_Option const AMRWBOptionOctetAlign =
428 {
429 PluginCodec_BoolOption, // Option type
430 "Octet Aligned", // User visible name
431 true, // User Read/Only flag
432 PluginCodec_EqualMerge, // Merge mode
433 "1", // Initial value
434 "octet-align", // FMTP option name
435 NULL, // FMTP default value
436 H245_G7222_OCTET_ALIGNED // H.245 generic capability code and bit mask
437 };
438
439 static struct PluginCodec_Option const ModeSetG7222 =
440 {
441 PluginCodec_IntegerOption, // Option type
442 "Mode Set", // User visible name
443 true, // User Read/Only flag
444 PluginCodec_EqualMerge, // Merge mode
445 "0x1ff", // Initial value
446 NULL, // FMTP option name
447 NULL, // FMTP default value
448 H245_G7222_MODE_SET // H.245 generic capability code and bit mask
449 };
450
451 static struct PluginCodec_Option const ModeChangePeriodG7222 =
452 {
453 PluginCodec_IntegerOption, // Option type
454 "Mode Change Period", // User visible name
455 false, // User Read/Only flag
456 PluginCodec_MinMerge, // Merge mode
457 "0", // Initial value
458 NULL, // FMTP option name
459 NULL, // FMTP default value
460 H245_G7222_MODE_CHANGE_PERIOD, // H.245 generic capability code and bit mask
461 "0", // Minimum value
462 "1000" // Maximum value
463 };
464
465 static struct PluginCodec_Option const ModeChangeNeighbourG7222 =
466 {
467 PluginCodec_BoolOption, // Option type
468 "Mode Change Neighbour", // User visible name
469 false, // User Read/Only flag
470 PluginCodec_AndMerge, // Merge mode
471 "0", // Initial value
472 NULL, // FMTP option name
473 NULL, // FMTP default value
474 H245_G7222_MODE_CHANGE_NEIGHBOUR // H.245 generic capability code and bit mask
475 };
476
477 static struct PluginCodec_Option const CRC_G7222 =
478 {
479 PluginCodec_BoolOption, // Option type
480 "CRC", // User visible name
481 true, // User Read/Only flag
482 PluginCodec_AndMerge, // Merge mode
483 "0", // Initial value
484 NULL, // FMTP option name
485 NULL, // FMTP default value
486 H245_G7222_CRC // H.245 generic capability code and bit mask
487 };
488
489 static struct PluginCodec_Option const RobustSortingG7222 =
490 {
491 PluginCodec_BoolOption, // Option type
492 "Robust Sorting", // User visible name
493 true, // User Read/Only flag
494 PluginCodec_AndMerge, // Merge mode
495 "0", // Initial value
496 NULL, // FMTP option name
497 NULL, // FMTP default value
498 H245_G7222_ROBUST_SORTING // H.245 generic capability code and bit mask
499 };
500
501 static struct PluginCodec_Option const InterleavingG7222 =
502 {
503 PluginCodec_BoolOption, // Option type
504 "Interleaving", // User visible name
505 true, // User Read/Only flag
506 PluginCodec_AndMerge, // Merge mode
507 "0", // Initial value
508 NULL, // FMTP option name
509 NULL, // FMTP default value
510 H245_G7222_INTERLEAVING // H.245 generic capability code and bit mask
511 };
512
513 static struct PluginCodec_Option const MediaPacketizationRFC3267 =
514 {
515 PluginCodec_StringOption, // Option type
516 PLUGINCODEC_MEDIA_PACKETIZATION, // User visible name
517 true, // User Read/Only flag
518 PluginCodec_NoMerge, // Merge mode
519 "RFC3267" // Initial value
520 };
521
522 #ifdef PLUGINCODEC_MEDIA_PACKETIZATIONS
523 static struct PluginCodec_Option const MediaPacketizationsRFC3267 =
524 {
525 PluginCodec_StringOption, // Option type
526 PLUGINCODEC_MEDIA_PACKETIZATIONS, // User visible name
527 true, // User Read/Only flag
528 PluginCodec_NoMerge, // Merge mode
529 "RFC3267,RFC4867" // Initial value
530 };
531 #endif
532
533 static struct PluginCodec_Option const * const AMRWBOptionTable[] = {
534 &AMRWBOptionRxFramesPerPacket,
535 &AMRWBOptionTxFramesPerPacket,
536 &MediaPacketizationRFC3267,
537 #ifdef PLUGINCODEC_MEDIA_PACKETIZATIONS
538 &MediaPacketizationsRFC3267,
539 #endif
540 &AMRWBOptionOctetAlign,
541 //&ModeSetG7222,
542 &ModeChangePeriodG7222,
543 &ModeChangeNeighbourG7222,
544 &CRC_G7222,
545 &RobustSortingG7222,
546 &InterleavingG7222,
547 NULL
548 };
549
550
AMRWBOptionsGet(const struct PluginCodec_Definition * defn,void * context,const char * name,void * parm,unsigned * parmLen)551 static int AMRWBOptionsGet (const struct PluginCodec_Definition * defn,
552 void * context,
553 const char * name,
554 void * parm,
555 unsigned * parmLen)
556 {
557 if (parm == NULL || parmLen == NULL || *parmLen != sizeof(struct PluginCodec_Option **))
558 return 0;
559
560 *(struct PluginCodec_Option const * const * *)parm = AMRWBOptionTable;
561 return 1;
562 }
563
564
565 static struct PluginCodec_ControlDefn AMRWBEncoderControlDefn[] =
566 {
567 { "get_codec_options", AMRWBOptionsGet },
568 { NULL }
569 };
570
571
572 /////////////////////////////////////////////////////////////////////////////
573
574 // Ref. Table F.1/G.722.2
575 static const struct PluginCodec_H323GenericCodecData AMRWBG7222Capability =
576 {
577 OpalPluginCodec_Identifer_G7222, // capability identifier
578 };
579 // Note: because these parameters are defined in options, they're not needed here
580
581
582 /////////////////////////////////////////////////////////////////////////////
583
584 // Effects of PluginCodec_DecodeSilence when stream detects silence:
585 // Encoder
586 // DecodeSilence=1: Transcode will pass us 0 for fromPtr & fromLen
587 // Typically we will use this to fill output with comfort noise frame
588 // DecodeSilence=0: Transcode will pass us input of inputBytesPerFrame 0's
589 // Decoder
590 // DecodeSilence=1: Transcode will pass us 0 for fromPtr & fromLen and set PluginCodec_CoderSilenceFrame flag
591 // Typically we will use this to fill output with comfort noise
592 // DecodeSilence=0: Transcode will not call us, and pass along an outputBytesPerFrame 0-filled frame
593 // AMR-WB encoder supports VAD if dtx flag is set. Then encoder will send SIDs during silence.
594 // But encoder requires full frame to detect silence, so leave PluginCodec_DecodeSilence off encoder.
595 // AMR-WB decoder will generate something if told frame was lost, so use PluginCodec_DecodeSilence on decoder
596 // to indicate lost frame with PluginCodec_CoderSilenceFrame flag.
597
598
599 static struct PluginCodec_Definition AMRWBCodecDefinition[] =
600 {
601 { // amr-wb encoder
602 PLUGIN_CODEC_VERSION_OPTIONS, // codec API version
603 &AMRWBLicenseInformation, // license information
604
605 PluginCodec_MediaTypeAudio | // audio codec
606 PluginCodec_InputTypeRaw | // raw input data
607 PluginCodec_OutputTypeRaw | // raw output data
608 PluginCodec_RTPTypeDynamic, // dynamic RTP type
609
610 "G.722.2(AMR-WB)", // text decription
611 "PCM-16-16kHz", // source format
612 "G.722.2", // destination format
613
614 NULL, // user data
615
616 16000, // samples per second
617 AMRWB_ALIGNED_BPS (AMRWB_24k), // raw bits per second
618 20000, // microseconds per frame
619 AMRWB_FRAME_SAMPLES, // samples per frame
620 AMRWB_block_size_octet[AMRWB_24k] + 1, // bytes per frame
621
622 1, // recommended number of frames per packet
623 1, // maximum number of frames per packet
624 0, // IANA RTP payload code
625 "AMR-WB", // RTP payload name
626
627 AMRWBEncoderCreate, // create codec function
628 AMRWBEncoderDestroy, // destroy codec
629 AMRWBEncode, // encode/decode
630 AMRWBEncoderControlDefn, // codec controls
631
632 PluginCodec_H323Codec_generic, // h323CapabilityType
633 &AMRWBG7222Capability // h323CapabilityData
634 },
635 { // amr-wb decoder
636 PLUGIN_CODEC_VERSION_OPTIONS, // codec API version
637 &AMRWBLicenseInformation, // license information
638
639 PluginCodec_MediaTypeAudio | // audio codec
640 PluginCodec_InputTypeRaw | // raw input data
641 PluginCodec_OutputTypeRaw | // raw output data
642 PluginCodec_RTPTypeDynamic | // dynamic RTP type
643 PluginCodec_DecodeSilence, // Can accept missing (empty) frames and generate silence
644
645 "G.722.2(AMR-WB)", // text decription
646 "G.722.2", // source format
647 "PCM-16-16kHz", // destination format
648
649 NULL, // user data
650
651 16000, // samples per second
652 AMRWB_ALIGNED_BPS (AMRWB_24k), // raw bits per second
653 20000, // microseconds per frame
654 AMRWB_FRAME_SAMPLES, // samples per frame
655 AMRWB_block_size_octet[AMRWB_24k] + 1, // bytes per frame
656 1, // recommended number of frames per packet
657 1, // maximum number of frames per packet
658 0, // IANA RTP payload code
659 "AMR-WB", // RTP payload name
660
661 AMRWBDecoderCreate, // create codec function
662 AMRWBDecoderDestroy, // destroy codec
663 AMRWBDecode, // encode/decode
664 NULL, // codec controls
665
666 PluginCodec_H323Codec_generic, // h323CapabilityType
667 &AMRWBG7222Capability // h323CapabilityData
668 }
669 };
670
671 extern "C"
672 {
673 PLUGIN_CODEC_IMPLEMENT_ALL(AMRWB, AMRWBCodecDefinition, PLUGIN_CODEC_VERSION_OPTIONS)
674 };
675
676 /////////////////////////////////////////////////////////////////////////////
677