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