home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / dynacodec.cxx < prev    next >
C/C++ Source or Header  |  2003-04-30  |  34KB  |  955 lines

  1. /*
  2.  * dynacodec.cxx
  3.  *
  4.  * Dynamic codec loading
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 2003 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Contributor(s): ______________________________________.
  25.  *
  26.  * $Log: dynacodec.cxx,v $
  27.  * Revision 1.5  2003/04/30 14:15:25  craigs
  28.  * Changed for new codec API
  29.  *
  30.  * Revision 1.4  2003/04/30 06:55:05  craigs
  31.  * Changed interface to DLL codec to improve Opal compatibility
  32.  *
  33.  * Revision 1.3  2003/04/30 04:56:42  craigs
  34.  * Changed interface to DLL codec to improve Opal compatibility
  35.  *
  36.  * Revision 1.2  2003/04/28 07:00:09  robertj
  37.  * Fixed problem with compiler(s) not correctly initialising static globals
  38.  *
  39.  * Revision 1.1  2003/04/27 23:49:48  craigs
  40.  * Initial version
  41.  *
  42.  */
  43.  
  44. #include <ptlib.h>
  45.  
  46. #include <dynacodec.h>
  47. #include <rtp.h>
  48. #include "h245.h"
  49.  
  50. #ifdef  _WIN32
  51. static const char * dllExt = ".dll";
  52. #else
  53. static const char * dllExt = ".so";
  54. #endif
  55.  
  56. static const char H323EXT[] = "{sw}";
  57.  
  58. #define CURRENT_API_VERSION   1           // library current supports this API version
  59.  
  60. #define EQUIVALENCE_COUNTRY_CODE       9  // Country code for Australia
  61. #define EQUIVALENCE_T35EXTENSION       0
  62. #define EQUIVALENCE_MANUFACTURER_CODE  61 // Allocated by Australian Communications Authority, Oct 2000
  63.  
  64. #define GSM_BYTES_PER_FRAME 33
  65.  
  66. // following attributes must exist on all codecs
  67. static const char ATTRIBUTE_APIVERSION[]                 = "apiversion";
  68. static const char ATTRIBUTE_TYPE[]                       = "type";     // audio or video
  69.  
  70. // following attributes are optional on all codecs
  71. static const char ATTRIBUTE_NAME[]              = "name";              // name fo the code
  72. static const char ATTRIBUTE_VERSION[]           = "version";           // codec version
  73. static const char ATTRIBUTE_DATE[]              = "date";              // date of DLL creation
  74.  
  75. static const char ATTRIBUTE_CODECVENDOR[]       = "codecvendor";       // vendor of the codec
  76. static const char ATTRIBUTE_CODECVERSION[]      = "codecversion";      // vendor version information
  77. static const char ATTRIBUTE_CODECCOPYRIGHT[]    = "codeccopyright";    // copyright notice
  78. static const char ATTRIBUTE_CODECDATE[]         = "codecdate";         // date associated with codec
  79. static const char ATTRIBUTE_CODECLICENSE[]      = "codeclicense";      // vendor codec licence information 
  80. static const char ATTRIBUTE_CODECSOURCE[]       = "codecsource";       // vendor source code location
  81. static const char ATTRIBUTE_CODECCONTACT[]      = "codeccontact";      // vendor contact email address 
  82.  
  83. static const char ATTRIBUTE_INTEGRATORNAME[]    = "integratorname";    // name of codec integrator
  84. static const char ATTRIBUTE_INTEGRATORCONTACT[] = "integratorcontact"; // integrator contact email address
  85.  
  86. // following attribute names must exist on all non-PCM16 codecs 
  87. // and be prefixed by "input" or "output" as appropriate
  88. static const char ATTRIBUTE_IOFORMAT[]                = "format";
  89. static const char ATTRIBUTE_IOBITPERSECOND[]          = "bitspersecond";
  90. static const char ATTRIBUTE_IOBITSPERFRAME[]          = "bitsperframe";   
  91. static const char ATTRIBUTE_IOBYTESPERFRAME[]         = "bytesperframe";
  92. static const char ATTRIBUTE_IOSAMPLERATE[]            = "samplerate";      
  93. static const char ATTRIBUTE_IOSAMPLESPERFRAME[]       = "samplesperframe";
  94. static const char ATTRIBUTE_IORTP[]                   = "rtp";              
  95. static const char ATTRIBUTE_IOSDP[]                   = "sdp";       
  96.  
  97. // following attribute names are optional on all non-PCM16 codecs 
  98. // and mst be prefixed by "input" or "output" as appropriate
  99. static const char ATTRIBUTE_SDPFMTP[]                    = "sdpfmtp";       
  100.  
  101. // the following attribute are optional for any codec
  102. static const char ATTRIBUTE_H323NOSTANDARDHEADER[]       = "h323nonstandardheader";
  103. static const char ATTRIBUTE_H323NOSTANDARDHEADERHEX[]    = "h323nonstandardheaderhex";
  104. static const char ATTRIBUTE_H323CODECSUBTYPE[]           = "h323codecsubtype";
  105. static const char ATTRIBUTE_T35COUNTRYCODE[]             = "t35countrycode";
  106. static const char ATTRIBUTE_T35EXTENSION[]               = "t35extension";
  107. static const char ATTRIBUTE_T35MANUFACTURER[]            = "t35manufacturer";
  108. static const char ATTRIBUTE_MAXFRAMESPERPACKET[]         = "maxframesperpacket";
  109. static const char ATTRIBUTE_PREFERREDTXFRAMESPERPACKET[] = "preferredtxframesperpacket";
  110. static const char ATTRIBUTE_MEDIAFORMATNAME[]            = "mediaformatname";
  111.  
  112. // input and output format strings
  113. static const char ATTRIBUTE_INPUTFORMAT[]                = "inputformat";
  114. static const char ATTRIBUTE_OUTPUTFORMAT[]               = "outputformat";
  115.  
  116. // common values used as attribute values
  117. static const char VALUE_PCM16[]  = "l16";
  118. static const char VALUE_AUDIO[]  = "audio";
  119. static const char VALUE_VIDEO[]  = "video";
  120. static const char VALUE_INPUT[]  = "input";
  121. static const char VALUE_OUTPUT[] = "output";
  122.  
  123. static const char *RequiredAttributes[] = {
  124.   ATTRIBUTE_APIVERSION,
  125.   ATTRIBUTE_INPUTFORMAT,
  126.   ATTRIBUTE_OUTPUTFORMAT,
  127.   NULL
  128. };
  129.  
  130. static const char *RequiredNonPCM16Attributes[] = {
  131.   ATTRIBUTE_IOFORMAT,
  132.   ATTRIBUTE_IOBITPERSECOND,
  133.   ATTRIBUTE_IOBITSPERFRAME,
  134.   ATTRIBUTE_IOBYTESPERFRAME,
  135.   ATTRIBUTE_IOSAMPLERATE,
  136.   ATTRIBUTE_IOSAMPLESPERFRAME,
  137.   ATTRIBUTE_IORTP,
  138.   ATTRIBUTE_IOSDP,
  139.   NULL
  140. };
  141.  
  142. class TempCodecInfo : public PObject
  143. {
  144.   PCLASSINFO(TempCodecInfo, PObject);
  145.   public:
  146.     TempCodecInfo(const PStringToString & _attributes, OpalDLLCodecInfo & _codecInfo)
  147.       : attributes(_attributes), codecInfo(_codecInfo)
  148.       { }
  149.  
  150.     PStringToString attributes;
  151.     OpalDLLCodecInfo & codecInfo;
  152. };
  153.  
  154. PDICTIONARY(TempCodecInfoDict, PCaselessString, TempCodecInfo);
  155.  
  156. /////////////////////////////////////////////////////////////////////////////
  157.  
  158. PMutex OpalDynaCodecDLL::mutex;
  159. BOOL OpalDynaCodecDLL::inited = FALSE;
  160. PDirectory OpalDynaCodecDLL::defaultCodecDir;
  161.  
  162. /////////////////////////////////////////////////////////////////////////////
  163.  
  164. OpalDLLCodecRec::OpalDLLCodecRec(OpalDynaCodecDLL & _encoder, 
  165.                             const PStringToString & _attributes, 
  166.                            const OpalDLLCodecInfo & _info,
  167.                                   OpalMediaFormat * _mediaFormat)
  168.  : encoder(_encoder), attributes(_attributes), info(_info), mediaFormat(_mediaFormat)
  169. {
  170. }
  171.  
  172. void * OpalDLLCodecRec::CreateContext() const
  173. {
  174.   void * context = NULL;
  175.   if (info.createContext != NULL)
  176.     context = (*info.createContext)(info.codecUserData);
  177.   return context;
  178. }
  179.  
  180. void OpalDLLCodecRec::DestroyContext(void * context) const
  181. {
  182.   if (info.destroyContext != NULL)
  183.     (*info.destroyContext)(info.codecUserData, context);
  184.   else if (context != NULL)
  185.     free(context);
  186. }
  187.  
  188. void OpalDLLCodecRec::SetParameter(const PString & attribute, const PString & value) const
  189. {
  190.   if (info.setParameter != NULL)
  191.     (*info.setParameter)(info.codecUserData, (const char *)attribute, (const char *)value);
  192. }
  193.  
  194. PString OpalDLLCodecRec::GetParameter(const PString & attribute, const char * defValue) const
  195. {
  196.   if (info.getParameter == NULL)
  197.     return defValue;
  198.  
  199.   char value[100];
  200.   if (!(*info.getParameter)(info.codecUserData, (const char *)attribute, value, sizeof(value)))
  201.     return PString::Empty();
  202.  
  203.   return PString(value);
  204. }
  205.  
  206. H323Capability * OpalDLLCodecRec::CreateCapability(H323EndPoint & ep) const
  207. {
  208.   // get T35 country code
  209.   BYTE country;
  210.   if (attributes.Contains(ATTRIBUTE_T35COUNTRYCODE))
  211.     country = (BYTE)attributes(ATTRIBUTE_T35COUNTRYCODE).AsUnsigned();
  212.   else
  213.     country = EQUIVALENCE_COUNTRY_CODE;                   /// t35 information
  214.  
  215.   // get T35 extension code
  216.   BYTE extension;
  217.   if (attributes.Contains(ATTRIBUTE_T35EXTENSION))
  218.     extension = (BYTE)attributes(ATTRIBUTE_T35EXTENSION).AsUnsigned();
  219.   else
  220.     extension = EQUIVALENCE_T35EXTENSION;                   /// t35 information
  221.  
  222.   // get T35 manufacturer code
  223.   WORD manufacturer;
  224.   if (attributes.Contains(ATTRIBUTE_T35MANUFACTURER))
  225.     manufacturer = (WORD)attributes(ATTRIBUTE_T35MANUFACTURER).AsUnsigned();
  226.   else
  227.     manufacturer = EQUIVALENCE_MANUFACTURER_CODE;              /// t35 information
  228.  
  229.   // look for specific paramaters for non-standard headers definitions
  230.   // if not, then use codec name 
  231.   PBYTEArray nonStandardHeader;
  232.   unsigned subType = 0;
  233.   if (attributes.Contains(ATTRIBUTE_H323CODECSUBTYPE)) {
  234.     subType = attributes(ATTRIBUTE_H323CODECSUBTYPE).AsUnsigned();
  235.   }
  236.  
  237.   else if (attributes.Contains(ATTRIBUTE_H323NOSTANDARDHEADER)) {
  238.     PString str = attributes(ATTRIBUTE_H323NOSTANDARDHEADER);
  239.     memcpy(nonStandardHeader.GetPointer(str.GetLength()), (const char *)str, str.GetLength());
  240.   }
  241.   
  242.   else if (attributes.Contains(ATTRIBUTE_H323NOSTANDARDHEADERHEX)) {
  243.     PStringArray tokens = attributes(ATTRIBUTE_H323NOSTANDARDHEADERHEX).Trim().Tokenise(", ");
  244.     PINDEX i;
  245.     PINDEX len = 0;
  246.     nonStandardHeader.SetSize(0);
  247.     for (i = 0; i < tokens.GetSize(); i++) {
  248.       PString hex = tokens[i].Trim();
  249.       if (hex.Left(2) *= "0x")
  250.         hex = hex.Mid(2);
  251.       int val;
  252.       if (sscanf((const char *)hex, "%2x", &val) == 1) {
  253.        nonStandardHeader.SetSize(len+1);
  254.        nonStandardHeader[len] = (BYTE)val;
  255.        len++;
  256.       }
  257.     }
  258.   }
  259.   
  260.   else {
  261.     PString name = attributes(ATTRIBUTE_NAME);
  262.     memcpy(nonStandardHeader.GetPointer(name.GetLength()), (const char *)name, name.GetLength());
  263.   }
  264.  
  265.   PString type = attributes(ATTRIBUTE_TYPE);
  266.   if (type *= "audio") {
  267.  
  268.     unsigned maxFramesPerPacket = 1;
  269.     if (attributes.Contains(ATTRIBUTE_MAXFRAMESPERPACKET)) {
  270.       unsigned v = attributes(ATTRIBUTE_MAXFRAMESPERPACKET).AsUnsigned();
  271.       if (v > 0)
  272.         maxFramesPerPacket = v;
  273.     }
  274.     unsigned txFramesPerPacket = maxFramesPerPacket;
  275.     if (attributes.Contains(ATTRIBUTE_PREFERREDTXFRAMESPERPACKET)) {
  276.       unsigned v = attributes(ATTRIBUTE_PREFERREDTXFRAMESPERPACKET).AsUnsigned();
  277.       if (0 < v && v <= maxFramesPerPacket)
  278.         txFramesPerPacket = v;
  279.     }
  280.  
  281.     if (subType != 0)
  282.       return new OpalDynaCodecStandardAudioCapability(*this,
  283.                                                        ep, 
  284.                                                        maxFramesPerPacket, 
  285.                                                        txFramesPerPacket,
  286.                                                        subType);
  287.     else
  288.       return new OpalDynaCodecNonStandardAudioCapability(*this,
  289.                                                          ep, 
  290.                                                          maxFramesPerPacket, 
  291.                                                          txFramesPerPacket, 
  292.                                                          country, 
  293.                                                          extension, 
  294.                                                          manufacturer, 
  295.                                                          (const BYTE *)nonStandardHeader,
  296.                                                          nonStandardHeader.GetSize());
  297.   }
  298.  
  299.   return NULL;
  300. }
  301.  
  302. /////////////////////////////////////////////////////////////////////////////
  303.  
  304. BOOL OpalDynaCodecDLL::LoadCodecs()
  305. {
  306.   return LoadCodecs(defaultCodecDir);
  307. }
  308.  
  309. BOOL OpalDynaCodecDLL::LoadCodecs(const PDirectory & _dir)
  310. {
  311.   PWaitAndSignal m(mutex);
  312.  
  313.   PDirectory dir = _dir;
  314.  
  315.   if (!dir.Open()) {
  316.     PTRACE(2, "OpalDynaCodecDLL\tCannot find dynamic codec directory " << dir);
  317.     return FALSE;
  318.   }
  319.  
  320.   do {
  321.     PFilePathString name = dir.GetEntryName();
  322.     if ((name.GetLength() > (PINDEX)strlen(dllExt)) && (name.Right(strlen(dllExt)) == dllExt)) {
  323.       PFileInfo info;
  324.       if (dir.GetInfo(info)) {
  325.         PTRACE(2, "OpalDynaCodecDLL\tLoading " << dir + name);
  326.         LoadCodec(dir + name);
  327.       }
  328.     }
  329.   } while (dir.Next());
  330.  
  331.   return TRUE;
  332. }
  333.  
  334. static BOOL CheckRequestNonPCM16Attributes(const PFilePath & fn, PINDEX i, const PStringToString & attributes, const PString & prefix)
  335. {
  336.   const char ** requiredAttributes = RequiredNonPCM16Attributes;
  337.   BOOL passed = TRUE;
  338.   while (*requiredAttributes != NULL) {
  339.     if (!attributes.Contains(prefix + *requiredAttributes)) {
  340.       PTRACE(2, "OpalDynaCodecDLL\tCodec " << i << " in " << fn << " missing required attribute " << prefix << *requiredAttributes);
  341.       passed = FALSE;
  342.     }
  343.     requiredAttributes++;
  344.   }
  345.   return passed;
  346. }
  347.  
  348. static SetPCM16Attributes(PStringToString & attributes, BOOL input)
  349. {
  350.   PString prefix, otherPrefix;
  351.   if (input) {
  352.     prefix      = VALUE_INPUT;
  353.     otherPrefix = VALUE_OUTPUT;
  354.   } else {
  355.     otherPrefix = VALUE_INPUT;
  356.     prefix      = VALUE_OUTPUT;
  357.   }
  358.  
  359.   // sample rate is identical
  360.   PString str = attributes(otherPrefix + ATTRIBUTE_IOSAMPLERATE);
  361.   attributes.SetAt(prefix + ATTRIBUTE_IOSAMPLERATE, str);
  362.   unsigned sampleRate = str.AsUnsigned();
  363.  
  364.   // bits per second is calculated from sample rate given 16 bits per sample
  365.   attributes.SetAt(prefix + ATTRIBUTE_IOBITPERSECOND, PString(PString::Unsigned, sampleRate * 16));
  366.  
  367.   // samples per frame is identical
  368.   str = attributes(otherPrefix + ATTRIBUTE_IOSAMPLESPERFRAME);
  369.   attributes.SetAt(prefix + ATTRIBUTE_IOSAMPLESPERFRAME, str);
  370.   unsigned samplesPerFrame = str.AsUnsigned();
  371.  
  372.   // bits per frame calculated from samples per frame given 16 bits per sample
  373.   attributes.SetAt(prefix + ATTRIBUTE_IOBITSPERFRAME, PString(PString::Unsigned, samplesPerFrame * 16));
  374.  
  375.   // byte per frame calculated from samples per frame given 2 bytes per sample
  376.   attributes.SetAt(prefix + ATTRIBUTE_IOBYTESPERFRAME, PString(PString::Unsigned, samplesPerFrame * 2));
  377.  
  378.   // set RTP and SDPs  type for pcm16
  379.   attributes.SetAt(prefix + ATTRIBUTE_IORTP,  (int)RTP_DataFrame::L16_Mono);
  380.   attributes.SetAt(prefix + ATTRIBUTE_IOSDP,  "L16");
  381. }
  382.  
  383.  
  384. BOOL OpalDynaCodecDLL::LoadCodec(const PFilePath & fn)
  385. {
  386.   PWaitAndSignal m(mutex);
  387.  
  388.   if (!inited) {
  389.     inited = TRUE;
  390.   }
  391.  
  392.   OpalDynaCodecDLL * codec = new OpalDynaCodecDLL(fn);
  393.   if (!codec->IsLoaded()) {
  394.     PTRACE(2, "OpalDynaCodecDLL\tCannot find file " << fn);
  395.     delete codec;
  396.     return FALSE;
  397.   }
  398.  
  399.   if (!codec->Load()) {
  400.     PTRACE(2, "OpalDynaCodecDLL\tFile " << fn << " does not contain an Opal codec library signature");
  401.     delete codec;
  402.     return FALSE;
  403.   }
  404.  
  405.   if (!codec->IsLoaded()) {
  406.     PTRACE(2, "OpalDynaCodecDLL\tFile " << fn << " does not implement Opal codec library API version " << CURRENT_API_VERSION);
  407.     delete codec;
  408.     return FALSE;
  409.   }
  410.  
  411.   unsigned count;
  412.   OpalDLLCodecInfo * codecInfo = codec->EnumerateCodecs(&count);
  413.   if (codecInfo == NULL || count == 0) {
  414.     PTRACE(2, "OpalDynaCodecDLL\tCodec " << fn << " contains no codecs");
  415.     delete codec;
  416.     return FALSE;
  417.   }
  418.  
  419.   TempCodecInfoDict tempCodecDict;
  420.  
  421.   // scan through the list and create a temporay list of validated definitions
  422.   // indexed by type and to and from formats
  423.   PINDEX i;
  424.   for (i = 0; i < (PINDEX)count; i++) {
  425.  
  426.     // get attributes;
  427.     PStringToString attributes;
  428.     const OpalDLLCodecKeyValue * keyValue = codecInfo[i].attributes;
  429.     while (keyValue->key != NULL) {
  430.       attributes.SetAt(keyValue->key, keyValue->value);
  431.       keyValue++;
  432.     }
  433.     keyValue = codecInfo[i].attributes2;
  434.     while (keyValue->key != NULL) {
  435.       attributes.SetAt(PCaselessString(keyValue->key), keyValue->value);
  436.       keyValue++;
  437.     }
  438.  
  439.     // check for required attributes
  440.     const char ** requiredAttributes = RequiredAttributes;
  441.     BOOL passed = TRUE;
  442.     while (*requiredAttributes != NULL) {
  443.       if (!attributes.Contains(*requiredAttributes)) {
  444.         PTRACE(2, "OpalDynaCodecDLL\tCodec " << i << " in " << fn << " missing required attribute " << *requiredAttributes);
  445.         passed = FALSE;
  446.       }
  447.       requiredAttributes++;
  448.     }
  449.  
  450.     // only accept video or audio codecs
  451.     PCaselessString type = attributes(ATTRIBUTE_TYPE);
  452.     if (!(type *= VALUE_VIDEO) && !(type *= VALUE_AUDIO)) {
  453.       PTRACE(2, "OpalDynaCodecDLL\tCodec " << i << " in " << fn << " has unknown type " << type);
  454.       passed = FALSE;
  455.     }
  456.  
  457.     // check input attributes
  458.     PCaselessString inputFormat  = attributes(ATTRIBUTE_INPUTFORMAT);
  459.     if (inputFormat != VALUE_PCM16)
  460.       passed = passed && CheckRequestNonPCM16Attributes(fn, i, attributes, VALUE_INPUT);
  461.     else
  462.       SetPCM16Attributes(attributes, TRUE);
  463.  
  464.     // check output attributes
  465.     PCaselessString outputFormat = attributes(ATTRIBUTE_OUTPUTFORMAT);
  466.     if (outputFormat != VALUE_PCM16)
  467.       passed = passed && CheckRequestNonPCM16Attributes(fn, i, attributes, VALUE_OUTPUT);
  468.     else
  469.       SetPCM16Attributes(attributes, FALSE);
  470.  
  471.     // if codec is not legal, then ignore it
  472.     if (!passed)
  473.       continue;
  474.  
  475.     // save information about this codec
  476.     PCaselessString key = type + "|" + inputFormat + "|" + outputFormat;
  477.     TempCodecInfo * info = new TempCodecInfo(attributes, codecInfo[i]);
  478.     tempCodecDict.SetAt(key, info);
  479.   }
  480.  
  481.   // merge the new codecs into the list
  482.   // note that OpenH323 can only deal with codecs that convert to or from PCM
  483.   for (i = 0; i < tempCodecDict.GetSize(); i++) {
  484.  
  485.     PString encoderKey = tempCodecDict.GetKeyAt(i);
  486.  
  487.     // look for specific codec types:
  488.     //     "formattype" == "audio" && "formatfrom" == "pcm"
  489.     if (encoderKey.Find("audio|l16|") == 0) {
  490.  
  491.       PString encoderPrefix(VALUE_OUTPUT);
  492.  
  493.       TempCodecInfo & encoderCodecInfo = tempCodecDict.GetDataAt(i);
  494.  
  495.       // ignore this codec if this mediaformat is already defined
  496.       // this ensures that loading the same codec will be idempotent
  497.       PString mediaFormatName = encoderCodecInfo.attributes(ATTRIBUTE_MEDIAFORMATNAME);
  498.       if (mediaFormatName.IsEmpty())
  499.         mediaFormatName = encoderCodecInfo.attributes(ATTRIBUTE_OUTPUTFORMAT);
  500.  
  501.       if (OpalMediaFormat::GetRegisteredMediaFormats().GetValuesIndex(mediaFormatName) != P_MAX_INDEX) {
  502.         PTRACE(2, "OpalDynaCodecDLL\tCodec " << i << " in " << fn << " defines already loaded codec " << mediaFormatName);
  503.         continue;
  504.       }
  505.  
  506.       PCaselessString type = encoderCodecInfo.attributes(ATTRIBUTE_TYPE);
  507.  
  508.       // see if there is an decoder that matches this encoder
  509.       PString decoderKey = encoderCodecInfo.attributes(ATTRIBUTE_TYPE) + 
  510.                            "|" + encoderCodecInfo.attributes(ATTRIBUTE_OUTPUTFORMAT) + 
  511.                            "|" + VALUE_PCM16;
  512.       if (!tempCodecDict.Contains(decoderKey)) {
  513.         PTRACE(2, "OpalDynaCodecDLL\tCodec " << i << " contains an encoder but no decoder for " << mediaFormatName);
  514.       } 
  515.       
  516.       else {
  517.         TempCodecInfo & decoderCodecInfo = tempCodecDict[decoderKey];
  518.  
  519.         // get rtp payload type from encoder
  520.         BYTE rtpPayloadType = 0;
  521.         PString rtp = encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IORTP);
  522.         if (rtp *= "dynamic")
  523.           rtpPayloadType = (BYTE)RTP_DataFrame::DynamicBase;
  524.         else
  525.           rtpPayloadType = (BYTE)encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IORTP).AsUnsigned();
  526.  
  527.         // do codec-type specific attribute checking
  528.         PCaselessString type = encoderCodecInfo.attributes(ATTRIBUTE_TYPE);
  529.         OpalMediaFormat * mediaFormat = NULL;
  530.  
  531.         if (type *= "audio") {
  532.           mediaFormat = new OpalMediaFormat(
  533.                                             mediaFormatName,  
  534.                                             OpalMediaFormat::DefaultAudioSessionID,
  535.                                             (RTP_DataFrame::PayloadTypes)rtpPayloadType,
  536.                                             TRUE,
  537.                                             encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IOBITPERSECOND).AsUnsigned(),
  538.                                             encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IOBYTESPERFRAME).AsUnsigned(),
  539.                                             encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IOSAMPLESPERFRAME).AsUnsigned(),
  540.                                             OpalMediaFormat::AudioTimeUnits);
  541.  
  542.         } else if (type *= "video") {
  543.           mediaFormat = new OpalMediaFormat(
  544.                                             mediaFormatName,  
  545.                                             OpalMediaFormat::DefaultVideoSessionID,
  546.                                             (RTP_DataFrame::PayloadTypes)rtpPayloadType,
  547.                                             FALSE,
  548.                                             encoderCodecInfo.attributes(encoderPrefix + ATTRIBUTE_IOBITPERSECOND).AsUnsigned(),
  549.                                             0,
  550.                                             0,
  551.                                             OpalMediaFormat::VideoTimeUnits);
  552.         } else {
  553.           PAssertAlways(PString("unknown codec type ") + type);
  554.         }
  555.  
  556.         // indicate how many times this codec has been used
  557.         codec->referenceCount += 2;
  558.  
  559.         // register the codec
  560.         new OpalDynaCodecRegistration(*mediaFormat + H323EXT, 
  561.                                       new OpalDLLCodecRec(*codec, encoderCodecInfo.attributes, codecInfo[i], mediaFormat),
  562.                                       new OpalDLLCodecRec(*codec, decoderCodecInfo.attributes, codecInfo[i], mediaFormat),
  563.                                       mediaFormat);
  564.  
  565.         PTRACE(2, "OpalDynaCodecDLL\tLoaded " << type << " codec \"" << *mediaFormat << "\" from " << fn);
  566.       }
  567.     }
  568.   }
  569.  
  570.   if (codec->referenceCount == 0) {
  571.     PTRACE(2, "OpalDynaCodecDLL\tCodec " << fn << " contains no complete codecs");
  572.     delete codec;
  573.     return FALSE;
  574.   }
  575.  
  576.   return TRUE;
  577. }
  578.  
  579. PINDEX OpalDynaCodecDLL::AddAudioCapabilities(H323EndPoint & ep,
  580.                                               PINDEX descriptorNum,
  581.                                               PINDEX simultaneousNum,
  582.                                               H323Capabilities & capabilities)
  583. {
  584.   return OpalDynaCodecDLL::AddCapabilities(ep, descriptorNum, simultaneousNum, capabilities, "audio");
  585. }
  586.  
  587. PINDEX OpalDynaCodecDLL::AddVideoCapabilities(H323EndPoint & ep,
  588.                                               PINDEX descriptorNum,
  589.                                               PINDEX simultaneousNum,
  590.                                               H323Capabilities & capabilities)
  591. {
  592.   return OpalDynaCodecDLL::AddCapabilities(ep, descriptorNum, simultaneousNum, capabilities, "video");
  593. }
  594.  
  595.  
  596. PINDEX OpalDynaCodecDLL::AddCapabilities(H323EndPoint & ep,
  597.                                          PINDEX descriptorNum,
  598.                                          PINDEX simultaneousNum,
  599.                                          H323Capabilities & capabilities,
  600.                                          const PString & type)
  601. {
  602.   PWaitAndSignal mutex(H323CapabilityRegistration::GetMutex());
  603.   H323CapabilityRegistration * find = H323CapabilityRegistration::registeredCapabilitiesListHead;
  604.  
  605.   PINDEX added = 0;
  606.   while (find != NULL) {
  607.     if (find->IsDescendant(OpalDynaCodecRegistration::Class())) {
  608.       OpalDynaCodecRegistration * dynaCodec = (OpalDynaCodecRegistration *)find;
  609.       if (dynaCodec->encoderInfo->attributes(ATTRIBUTE_TYPE) *= type) {
  610.         H323Capability * cap = find->Create(ep);
  611.         if (cap != NULL) {
  612.           capabilities.SetCapability(descriptorNum, simultaneousNum, find->Create(ep));
  613.           added++;
  614.         }
  615.       }
  616.     }
  617.     find = find->link;
  618.   }
  619.  
  620.   return added;
  621. }
  622.  
  623. /////////////////////////////////////////////////////////////////////////////
  624.  
  625. OpalDynaCodecDLL::OpalDynaCodecDLL(const PFilePath & fn)
  626.   : PDynaLink(fn)
  627. {
  628.   referenceCount = 0;
  629. }
  630.  
  631. BOOL OpalDynaCodecDLL::Load()
  632. {
  633. #ifdef _WIN32
  634.   unsigned (FAR *versionFn)(unsigned apiVersion);
  635. #else
  636.   unsigned (*versionFn)(unsigned apiVersion);
  637. #endif
  638.  
  639.   if (!GetFunction("OpalCheckAPIVersion", (Function &)versionFn) || !(*versionFn)(CURRENT_API_VERSION)) {
  640.     Close();
  641.     return FALSE;
  642.   }
  643.  
  644.   if (!GetFunction("OpalEnumerateCodecs", (Function &)EnumerateCodecsFn))
  645.     Close();
  646.  
  647.   return TRUE;
  648. }
  649.  
  650. OpalDLLCodecInfo * OpalDynaCodecDLL::EnumerateCodecs(unsigned * count)
  651. {
  652.   return (*EnumerateCodecsFn)(CURRENT_API_VERSION, count);
  653. }
  654.  
  655. /////////////////////////////////////////////////////////////////////////////
  656.  
  657. OpalDynaAudioCodec::OpalDynaAudioCodec(const OpalDLLCodecRec & _info, Direction dir)
  658.   : H323FramedAudioCodec(*_info.mediaFormat, dir), info(_info)
  659. {
  660.   PString prefix = (dir == Encoder) ? VALUE_OUTPUT : VALUE_INPUT;
  661.  
  662.   context         = info.CreateContext();
  663.   samplesPerFrame = info.attributes(prefix + ATTRIBUTE_IOSAMPLESPERFRAME).AsUnsigned();
  664.   bytesPerFrame   = info.attributes(prefix + ATTRIBUTE_IOBYTESPERFRAME).AsUnsigned();
  665.  
  666.   PTRACE(3, "Codec\t" << *info.mediaFormat << " " << (dir == Encoder ? "en" : "de")
  667.          << "coder created");
  668. }
  669.  
  670. OpalDynaAudioCodec::~OpalDynaAudioCodec()
  671. {  
  672.   info.DestroyContext(context);
  673. }
  674.  
  675. BOOL OpalDynaAudioCodec::EncodeFrame(BYTE * buffer, unsigned & length)
  676. {
  677.   if (info.info.encoder == NULL)
  678.     return FALSE;
  679.  
  680.   return (*info.info.encoder)(info.info.codecUserData, context, 
  681.                                    sampleBuffer, samplesPerFrame, buffer, &length);
  682. }
  683.  
  684. BOOL OpalDynaAudioCodec::DecodeFrame(const BYTE * buffer, unsigned length, unsigned & written)
  685. {
  686.   if (info.info.encoder == NULL)
  687.     return FALSE;
  688.  
  689.   if (length < bytesPerFrame)
  690.     return FALSE;
  691.  
  692.   return (*info.info.encoder)(info.info.codecUserData, context, buffer, length, &sampleBuffer[0], &written);
  693. }
  694.  
  695. /////////////////////////////////////////////////////////////////////////////
  696.  
  697. OpalDynaCodecRegistration::OpalDynaCodecRegistration(const PString & name, 
  698.                                                      OpalDLLCodecRec * _encoderInfo,
  699.                                                      OpalDLLCodecRec * _decoderInfo,
  700.                                                      OpalMediaFormat * _mediaFormat)
  701.   : H323CapabilityRegistration(name), 
  702.     encoderInfo(_encoderInfo),
  703.     decoderInfo(_decoderInfo),
  704.     mediaFormat(_mediaFormat)
  705. {
  706. }
  707.  
  708. H323Capability * OpalDynaCodecRegistration::Create(H323EndPoint & ep) const
  709. {
  710.   return decoderInfo->CreateCapability(ep);
  711. }
  712.  
  713.  
  714. /////////////////////////////////////////////////////////////////////////////
  715.  
  716. OpalDynaCodecNonStandardAudioCapability::OpalDynaCodecNonStandardAudioCapability(
  717.       const OpalDLLCodecRec & _info,
  718.       H323EndPoint & _endpoint,
  719.       unsigned maxPacketSize,         /// Maximum size of an audio packet in frames
  720.       unsigned desiredPacketSize,     /// Desired transmit size of an audio packet in frames
  721.       BYTE country,                   /// t35 information
  722.       BYTE extension,                 /// t35 information
  723.       WORD manufacturer,              /// t35 information
  724.       const BYTE * nonstdHeader,      /// nonstandard header
  725.       PINDEX nonstdHeaderLen)
  726.  
  727.   : H323NonStandardAudioCapability(maxPacketSize, 
  728.                                    desiredPacketSize, 
  729.                                    country,
  730.                                    extension,
  731.                                    manufacturer,
  732.                                    nonstdHeader,
  733.                                    nonstdHeaderLen),
  734.     info(_info), endpoint(_endpoint)
  735. {
  736. }
  737.  
  738. PObject * OpalDynaCodecNonStandardAudioCapability::Clone() const
  739. {
  740.   return new OpalDynaCodecNonStandardAudioCapability(*this);
  741. }
  742.  
  743. PString OpalDynaCodecNonStandardAudioCapability::GetFormatName() const
  744. {
  745.   return *info.mediaFormat + H323EXT;
  746. }
  747.  
  748. H323Codec * OpalDynaCodecNonStandardAudioCapability::CreateCodec(H323Codec::Direction direction) const
  749. {
  750.   return new OpalDynaAudioCodec(info, direction);
  751. }
  752.  
  753. /////////////////////////////////////////////////////////////////////////////
  754.  
  755. OpalDynaCodecStandardAudioCapability::OpalDynaCodecStandardAudioCapability(
  756.       const OpalDLLCodecRec & _info,
  757.       H323EndPoint & _endpoint,
  758.       unsigned maxPacketSize,         /// Maximum size of an audio packet in frames
  759.       unsigned desiredPacketSize,     /// Desired transmit size of an audio packet in frames
  760.       unsigned _subType)
  761.   : H323AudioCapability(maxPacketSize, desiredPacketSize), 
  762.     info(_info), endpoint(_endpoint), subType(_subType)
  763. {
  764. }
  765.  
  766. PObject * OpalDynaCodecStandardAudioCapability::Clone() const
  767. {
  768.   return new OpalDynaCodecStandardAudioCapability(*this);
  769. }
  770.  
  771. PString OpalDynaCodecStandardAudioCapability::GetFormatName() const
  772. {
  773.   return *info.mediaFormat + H323EXT;
  774. }
  775.  
  776. unsigned OpalDynaCodecStandardAudioCapability::GetSubType() const
  777. {
  778.   return subType;
  779. }
  780.  
  781. H323Codec * OpalDynaCodecStandardAudioCapability::CreateCodec(H323Codec::Direction direction) const
  782. {
  783.   return new OpalDynaAudioCodec(info, direction);
  784. }
  785.  
  786. BOOL OpalDynaCodecStandardAudioCapability::OnSendingPDU(H245_AudioCapability & cap, unsigned packetSize) const
  787. {
  788.   switch (subType) {
  789.     case H245_AudioCapability::e_g7231:
  790.       {
  791.         cap.SetTag(H245_AudioCapability::e_g7231);
  792.         H245_AudioCapability_g7231 & g7231 = cap;
  793.         g7231.m_maxAl_sduAudioFrames = packetSize;
  794.         //TODO:  g7231.m_silenceSuppression   = info.GetParameter((direction == Encoder), "silenceSuppression", "0").AsUnsigned();
  795.       }
  796.       break;
  797.  
  798.     case H245_AudioCapability::e_gsmFullRate:
  799.       {
  800.         cap.SetTag(H245_AudioCapability::e_gsmFullRate);
  801.         H245_GSMAudioCapability & gsm = cap;
  802.         gsm.m_audioUnitSize = packetSize*GSM_BYTES_PER_FRAME;
  803.       }
  804.       break;
  805.  
  806.     //case H245_AudioCapability::e_g728:
  807.     //case H245_AudioCapability::e_g729:
  808.     //case H245_AudioCapability::e_g729AnnexA;
  809.     //case H245_AudioCapability::e_g728:
  810.     //case H245_AudioCapability::e_g711Alaw64k:
  811.     //case H245_AudioCapability::e_g711Alaw56k:
  812.     //case H245_AudioCapability::e_g711Ulaw64k:
  813.     //case H245_AudioCapability::e_g711Ulaw56k:
  814.     //case H245_AudioCapability::e_g722_64k:
  815.     //case H245_AudioCapability::e_g722_56k:
  816.     //case H245_AudioCapability::e_g722_48k:
  817.     default:
  818.       break;
  819.   }
  820.  
  821.   return TRUE;
  822. }
  823.  
  824.  
  825. BOOL OpalDynaCodecStandardAudioCapability::OnReceivedPDU(const H245_AudioCapability & cap, unsigned & packetSize)
  826. {
  827.   if (cap.GetTag() != subType)
  828.     return FALSE;
  829.  
  830.   switch (subType) {
  831.     case H245_AudioCapability::e_g7231:
  832.       {
  833.         const H245_AudioCapability_g7231 & g7231 = cap;
  834.         packetSize = g7231.m_maxAl_sduAudioFrames;
  835.         //TODO: info.SetParameter((direction == Encoder), "silenceSuppression", PString(PString::Unsigned, g7231.m_silenceSuppression));
  836.       }
  837.       break;
  838.  
  839.     case H245_AudioCapability::e_gsmFullRate:
  840.       {
  841.         const H245_GSMAudioCapability & gsm = cap;
  842.         packetSize = gsm.m_audioUnitSize / GSM_BYTES_PER_FRAME;
  843.         if (packetSize == 0)
  844.           packetSize = 1;
  845.       }
  846.       break;
  847.  
  848.     //case H245_AudioCapability::e_g728:
  849.     //case H245_AudioCapability::e_g729:
  850.     //case H245_AudioCapability::e_g729AnnexA;
  851.     //case H245_AudioCapability::e_g728:
  852.     //case H245_AudioCapability::e_g711Alaw64k:
  853.     //case H245_AudioCapability::e_g711Alaw56k:
  854.     //case H245_AudioCapability::e_g711Ulaw64k:
  855.     //case H245_AudioCapability::e_g711Ulaw56k:
  856.     //case H245_AudioCapability::e_g722_64k:
  857.     //case H245_AudioCapability::e_g722_56k:
  858.     //case H245_AudioCapability::e_g722_48k:
  859.     default:
  860.       break;
  861.   }
  862.  
  863.   return TRUE;
  864. }
  865.  
  866. /////////////////////////////////////////////////////////////////////////////
  867.  
  868. OpalDynaCodecStandardVideoCapability::OpalDynaCodecStandardVideoCapability(
  869.       const OpalDLLCodecRec & _info,
  870.       H323EndPoint & _endpoint,
  871.       unsigned _subType)
  872.  
  873.   : H323VideoCapability(), 
  874.     info(_info), endpoint(_endpoint), subType(_subType)
  875. {
  876. }
  877.  
  878. PObject * OpalDynaCodecStandardVideoCapability::Clone() const
  879. {
  880.   return new OpalDynaCodecStandardVideoCapability(*this);
  881. }
  882.  
  883. PString OpalDynaCodecStandardVideoCapability::GetFormatName() const
  884. {
  885.   return *info.mediaFormat + H323EXT;
  886. }
  887.  
  888. unsigned OpalDynaCodecStandardVideoCapability::GetSubType() const
  889. {
  890.   return subType;
  891. }
  892.  
  893. H323Codec * OpalDynaCodecStandardVideoCapability::CreateCodec(H323Codec::Direction direction) const
  894. {
  895.   return new OpalDynaVideoCodec(info, direction);
  896. }
  897.  
  898.  
  899. BOOL OpalDynaCodecStandardVideoCapability::OnSendingPDU(H245_VideoCapability & /*pdu*/) const
  900. {
  901.   /*
  902.   switch (subType) {
  903.     default:
  904.       break;
  905.   }
  906.   */
  907.   return TRUE;
  908. }
  909.  
  910. BOOL OpalDynaCodecStandardVideoCapability::OnSendingPDU(H245_VideoMode & /*pdu*/) const
  911. {
  912.   /*
  913.   switch (subType) {
  914.     default:
  915.       break;
  916.   }
  917.   */  
  918.   return TRUE;
  919. }
  920.  
  921. BOOL OpalDynaCodecStandardVideoCapability::OnReceivedPDU(const H245_VideoCapability & /*pdu*/)
  922. {
  923.   /*
  924.   switch (subType) {
  925.     default:
  926.       break;
  927.   }
  928.   */
  929.   return TRUE;
  930. }
  931.  
  932. /////////////////////////////////////////////////////////////////////////////
  933.  
  934. OpalDynaVideoCodec::OpalDynaVideoCodec(const OpalDLLCodecRec & _info, Direction dir)
  935.   : H323VideoCodec(*_info.mediaFormat, dir), info(_info)
  936. {
  937.   context = info.CreateContext();
  938. }
  939.  
  940. OpalDynaVideoCodec::~OpalDynaVideoCodec()
  941. {
  942.   info.DestroyContext(context);
  943. }
  944.  
  945. BOOL OpalDynaVideoCodec::Read(BYTE * /*buffer*/, unsigned & /*length*/, RTP_DataFrame & /*rtpFrame*/)
  946. {
  947.   return FALSE;
  948. }
  949.  
  950. BOOL OpalDynaVideoCodec::Write(const BYTE * /*buffer*/, unsigned /*length*/, const RTP_DataFrame & /*rtp*/, unsigned & /*written*/)
  951. {
  952.   return FALSE;
  953. }
  954.  
  955. /////////////////////////////////////////////////////////////////////////////