OPAL Version 3.10.2
opalplugin.hpp
Go to the documentation of this file.
00001 /*
00002  * opalplugins.hpp
00003  *
00004  * OPAL codec plugins handler (C++ version)
00005  *
00006  * Open Phone Abstraction Library (OPAL)
00007  * Formally known as the Open H323 project.
00008  *
00009  * Copyright (C) 2010 Vox Lucida
00010  *
00011  * The contents of this file are subject to the Mozilla Public License
00012  * Version 1.0 (the "License"); you may not use this file except in
00013  * compliance with the License. You may obtain a copy of the License at
00014  * http://www.mozilla.org/MPL/
00015  *
00016  * Software distributed under the License is distributed on an "AS IS"
00017  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00018  * the License for the specific language governing rights and limitations
00019  * under the License.
00020  *
00021  * The Original Code is Open Phone Abstraction Library.
00022  *
00023  * The Initial Developer of the Original Code is Vox Lucida
00024  *
00025  * Contributor(s): ______________________________________.
00026  *
00027  * $Revision: 25799 $
00028  * $Author: rjongbloed $
00029  * $Date: 2011-05-17 21:22:40 -0500 (Tue, 17 May 2011) $
00030  */
00031 
00032 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
00033 #define OPAL_CODEC_OPALPLUGIN_HPP
00034 
00035 #include "opalplugin.h"
00036 
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <limits.h>
00040 
00041 #include <map>
00042 #include <string>
00043 
00044 
00046 
00047 #ifndef PLUGINCODEC_TRACING
00048   #define PLUGINCODEC_TRACING 1
00049 #endif
00050 
00051 #if PLUGINCODEC_TRACING
00052   extern PluginCodec_LogFunction PluginCodec_LogFunctionInstance;
00053   extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
00054 
00055 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
00056   PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
00057   int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
00058   { \
00059     if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
00060       return false; \
00061  \
00062     PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
00063     if (PluginCodec_LogFunctionInstance != NULL) \
00064       PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
00065  \
00066     return true; \
00067   } \
00068 
00069   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
00070 #else
00071   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
00072   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00073 #endif
00074 
00075 #if !defined(PTRACE)
00076   #if PLUGINCODEC_TRACING
00077     #include <sstream>
00078     #define PTRACE_CHECK(level) \
00079         (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
00080     #define PTRACE(level, section, args) \
00081       if (PTRACE_CHECK(level)) { \
00082         std::ostringstream strm; strm << args; \
00083         PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
00084       } else (void)0
00085   #else
00086     #define PTRACE_CHECK(level)
00087     #define PTRACE(level, section, expr)
00088   #endif
00089 #endif
00090 
00091 
00093 
00094 class PluginCodec_MediaFormat
00095 {
00096   public:
00097     typedef struct PluginCodec_Option const * const * OptionsTable;
00098     typedef std::map<std::string, std::string> OptionMap;
00099 
00100   protected:
00101     OptionsTable m_options;
00102 
00103   protected:
00104     PluginCodec_MediaFormat(OptionsTable options)
00105       : m_options(options)
00106     {
00107     }
00108 
00109   public:
00110     virtual ~PluginCodec_MediaFormat()
00111     {
00112     }
00113 
00114 
00115     const void * GetOptionsTable() const { return m_options; }
00116 
00118     virtual bool IsValidForProtocol(const char * /*protocol*/)
00119     {
00120       return true;
00121     }
00122 
00123 
00125     bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
00126     {
00127       if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***))
00128         return false;
00129 
00130       OptionMap originalOptions;
00131       for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2)
00132         originalOptions[option[0]] = option[1];
00133 
00134       OptionMap changedOptions;
00135       if (!(this->*adjuster)(originalOptions, changedOptions))
00136         return false;
00137 
00138       char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *));
00139       *(char ***)parm = options;
00140       if (options == NULL)
00141         return false;
00142 
00143       for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) {
00144         *options++ = strdup(i->first.c_str());
00145         *options++ = strdup(i->second.c_str());
00146       }
00147 
00148       return true;
00149     }
00150 
00151 
00153     virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0;
00154 
00155 
00156     // Adjust codec specific options calculated from normalised options.
00157     virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0;
00158 
00159 
00160     static void Change(const char * value,
00161                        OptionMap  & original,
00162                        OptionMap  & changed,
00163                        const char * option)
00164     {
00165       if (original[option] != value)
00166         changed[option] = value;
00167     }
00168 
00169 
00170     static unsigned String2Unsigned(const std::string & str)
00171     {
00172       return strtoul(str.c_str(), NULL, 10);
00173     }
00174 
00175 
00176     static void Unsigned2String(unsigned value, std::string & str)
00177     {
00178       // Not very efficient, but really, really simple
00179       if (value > 9)
00180         Unsigned2String(value/10, str);
00181       str += (char)(value%10 + '0');
00182     }
00183 
00184 
00185     static void Change(unsigned     value,
00186                        OptionMap  & original,
00187                        OptionMap  & changed,
00188                        const char * option)
00189     {
00190       if (String2Unsigned(original[option]) != value)
00191         Unsigned2String(value, changed[option]);
00192     }
00193 
00194 
00195     static void ClampMax(unsigned     maximum,
00196                          OptionMap  & original,
00197                          OptionMap  & changed,
00198                          const char * option)
00199     {
00200       unsigned value = String2Unsigned(original[option]);
00201       if (value > maximum)
00202         Unsigned2String(maximum, changed[option]);
00203     }
00204 
00205 
00206     static void ClampMin(unsigned     minimum,
00207                          OptionMap  & original,
00208                          OptionMap  & changed,
00209                          const char * option)
00210     {
00211       unsigned value = String2Unsigned(original[option]);
00212       if (value < minimum)
00213         Unsigned2String(minimum, changed[option]);
00214     }
00215 };
00216 
00217 
00219 
00220 template<typename NAME>
00221 class PluginCodec
00222 {
00223   protected:
00224     PluginCodec(const PluginCodec_Definition * defn)
00225       : m_definition(defn)
00226       , m_optionsSame(false)
00227       , m_maxBitRate(defn->bitsPerSec)
00228       , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
00229     {
00230       PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
00231              << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
00232     }
00233 
00234 
00235   public:
00236     virtual ~PluginCodec()
00237     {
00238     }
00239 
00240 
00242     virtual bool Construct()
00243     {
00244       return true;
00245     }
00246 
00247 
00252     static bool Terminate()
00253     {
00254       return true;
00255     }
00256 
00257 
00259     virtual bool Transcode(const void * fromPtr,
00260                              unsigned & fromLen,
00261                                  void * toPtr,
00262                              unsigned & toLen,
00263                              unsigned & flags) = 0;
00264 
00265 
00267     virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
00268     {
00269       return true;
00270     }
00271 
00272 
00274     virtual size_t GetOutputDataSize()
00275     {
00276       return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
00277     }
00278 
00279 
00286     virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
00287     {
00288       return true;
00289     }
00290 
00291 
00293     virtual bool SetOptions(const char * const * options)
00294     {
00295       m_optionsSame = true;
00296 
00297       // get the media format options after adjustment from protocol negotiation
00298       for (const char * const * option = options; *option != NULL; option += 2) {
00299         if (!SetOption(option[0], option[1]))
00300           return false;
00301       }
00302 
00303       if (m_optionsSame)
00304         return true;
00305 
00306       return OnChangedOptions();
00307     }
00308 
00309 
00311     virtual bool OnChangedOptions()
00312     {
00313       return true;
00314     }
00315 
00316 
00318     virtual bool SetOption(const char * optionName, const char * optionValue)
00319     {
00320       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
00321         return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
00322 
00323       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
00324         return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second
00325 
00326       return true;
00327     }
00328 
00329 
00330     template <typename T>
00331     bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00332     {
00333       unsigned newValue = oldValue;
00334       if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum))
00335         return false;
00336       oldValue = (T)newValue;
00337       return true;
00338     }
00339 
00340 
00341     bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00342     {
00343       char * end;
00344       unsigned newValue = strtoul(optionValue, &end, 10);
00345       if (*end != '\0')
00346         return false;
00347 
00348       if (newValue < minimum)
00349         newValue = minimum;
00350       else if (newValue > maximum)
00351         newValue = maximum;
00352 
00353       if (oldValue != newValue) {
00354         oldValue = newValue;
00355         m_optionsSame = false;
00356       }
00357 
00358       return true;
00359     }
00360 
00361 
00362     template <typename T>
00363     bool SetOptionBoolean(T & oldValue, const char * optionValue)
00364     {
00365       bool opt = oldValue != 0;
00366       if (!SetOptionBoolean(opt, optionValue))
00367         return false;
00368       oldValue = (T)opt;
00369       return true;
00370     }
00371 
00372 
00373     bool SetOptionBoolean(bool & oldValue, const char * optionValue)
00374     {
00375       bool newValue;
00376       if (strcmp(optionValue, "0") == 0)
00377         newValue = false;
00378       else if (strcmp(optionValue, "1") == 0)
00379         newValue = true;
00380       else
00381         return false;
00382 
00383       if (oldValue != newValue) {
00384         oldValue = newValue;
00385         m_optionsSame = false;
00386       }
00387 
00388       return true;
00389     }
00390 
00391 
00392     bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
00393     {
00394       return SetOptionBit((unsigned &)oldValue, bit, optionValue);
00395     }
00396 
00397 
00398     bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
00399     {
00400       bool newValue;
00401       if (strcmp(optionValue, "0") == 0)
00402         newValue = false;
00403       else if (strcmp(optionValue, "1") == 0)
00404         newValue = true;
00405       else
00406         return false;
00407 
00408       if (((oldValue&bit) != 0) != newValue) {
00409         if (newValue)
00410           oldValue |= bit;
00411         else
00412           oldValue &= ~bit;
00413         m_optionsSame = false;
00414       }
00415 
00416       return true;
00417     }
00418 
00419 
00420     template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
00421     {
00422       CodecClass * codec = new CodecClass(defn);
00423       if (codec != NULL && codec->Construct())
00424         return codec;
00425 
00426       PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
00427       delete codec;
00428       return NULL;
00429     }
00430 
00431 
00432     static void Destroy(const PluginCodec_Definition * /*defn*/, void * context)
00433     {
00434       delete (PluginCodec *)context;
00435     }
00436 
00437 
00438     static int Transcode(const PluginCodec_Definition * /*defn*/,
00439                                                  void * context,
00440                                            const void * fromPtr,
00441                                              unsigned * fromLen,
00442                                                  void * toPtr,
00443                                              unsigned * toLen,
00444                                          unsigned int * flags)
00445     {
00446       if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
00447         return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
00448 
00449       PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
00450       return false;
00451     }
00452 
00453 
00454     static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00455     {
00456       return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
00457     }
00458 
00459 
00460     static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00461     {
00462       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
00463     }
00464 
00465 
00466     static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00467     {
00468       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
00469     }
00470 
00471 
00472     static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00473     {
00474       if (parm == NULL || len == NULL || *len != sizeof(char ***))
00475         return false;
00476 
00477       char ** strings = (char **)parm;
00478       for (char ** string = strings; *string != NULL; string++)
00479         free(*string);
00480       free(strings);
00481       return true;
00482     }
00483 
00484 
00485     static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
00486     {
00487       if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
00488         return false;
00489 
00490       *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
00491       *len = 0;
00492       return true;
00493     }
00494 
00495 
00496     static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00497     {
00498       PluginCodec * codec = (PluginCodec *)context;
00499       return len != NULL && *len == sizeof(const char **) && parm != NULL &&
00500              codec != NULL && codec->SetOptions((const char * const *)parm);
00501     }
00502 
00503     static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00504     {
00505       return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
00506              ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
00507     }
00508 
00509     static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00510     {
00511       PluginCodec * codec = (PluginCodec *)context;
00512       return len != NULL && parm != NULL &&
00513              codec != NULL && codec->SetInstanceID((const char *)parm, *len);
00514     }
00515 
00516     static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00517     {
00518       PluginCodec * codec = (PluginCodec *)context;
00519       return len != NULL && parm != NULL &&
00520              codec != NULL && codec->GetStatistics((char *)parm, *len);
00521     }
00522 
00523     static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00524     {
00525       PluginCodec * codec = (PluginCodec *)context;
00526       return codec != NULL && codec->Terminate();
00527     }
00528 
00529     static struct PluginCodec_ControlDefn * GetControls()
00530     {
00531       static PluginCodec_ControlDefn ControlsTable[] = {
00532         { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE,  PluginCodec::GetOutputDataSize },
00533         { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised },
00534         { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised },
00535         { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS,     PluginCodec::SetOptions },
00536         { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS,     PluginCodec::GetOptions },
00537         { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS,    PluginCodec::FreeOptions },
00538         { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL,    PluginCodec::ValidForProtocol },
00539         { PLUGINCODEC_CONTROL_SET_INSTANCE_ID,       PluginCodec::SetInstanceID },
00540         { PLUGINCODEC_CONTROL_GET_STATISTICS,        PluginCodec::GetStatistics },
00541         { PLUGINCODEC_CONTROL_TERMINATE_CODEC,       PluginCodec::Terminate },
00542         PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00543         { NULL }
00544       };
00545       return ControlsTable;
00546     }
00547 
00548   protected:
00549     const PluginCodec_Definition * m_definition;
00550 
00551     bool     m_optionsSame;
00552     unsigned m_maxBitRate;
00553     unsigned m_frameTime;
00554 };
00555 
00556 
00557 #endif // OPAL_CODEC_OPALPLUGIN_HPP