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  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * - Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017 
00018  * - Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00025  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
00026  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00028  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Revision: 27366 $
00035  * $Author: rjongbloed $
00036  * $Date: 2012-03-29 00:58:03 -0500 (Thu, 29 Mar 2012) $
00037  */
00038 
00039 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
00040 #define OPAL_CODEC_OPALPLUGIN_HPP
00041 
00042 #include "opalplugin.h"
00043 
00044 #include <string.h>
00045 #include <stdlib.h>
00046 #include <limits.h>
00047 
00048 #include <map>
00049 #include <string>
00050 
00051 
00053 
00054 #ifndef PLUGINCODEC_TRACING
00055   #define PLUGINCODEC_TRACING 1
00056 #endif
00057 
00058 #if PLUGINCODEC_TRACING
00059   extern PluginCodec_LogFunction PluginCodec_LogFunctionInstance;
00060   extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
00061 
00062 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
00063   PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
00064   int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
00065   { \
00066     if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
00067       return false; \
00068  \
00069     PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
00070     if (PluginCodec_LogFunctionInstance != NULL) \
00071       PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
00072  \
00073     return true; \
00074   } \
00075 
00076   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
00077 #else
00078   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
00079   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00080 #endif
00081 
00082 #if !defined(PTRACE)
00083   #if PLUGINCODEC_TRACING
00084     #include <sstream>
00085     #define PTRACE_CHECK(level) \
00086         (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
00087     #define PTRACE(level, section, args) \
00088       if (PTRACE_CHECK(level)) { \
00089         std::ostringstream strm; strm << args; \
00090         PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
00091       } else (void)0
00092   #else
00093     #define PTRACE_CHECK(level)
00094     #define PTRACE(level, section, expr)
00095   #endif
00096 #endif
00097 
00098 
00100 
00101 class PluginCodec_MediaFormat
00102 {
00103   public:
00104     typedef struct PluginCodec_Option const * const * OptionsTable;
00105     typedef std::map<std::string, std::string> OptionMap;
00106 
00107   protected:
00108     OptionsTable m_options;
00109 
00110   protected:
00111     PluginCodec_MediaFormat(OptionsTable options)
00112       : m_options(options)
00113     {
00114     }
00115 
00116   public:
00117     virtual ~PluginCodec_MediaFormat()
00118     {
00119     }
00120 
00121 
00122     const void * GetOptionsTable() const { return m_options; }
00123 
00125     virtual bool IsValidForProtocol(const char * /*protocol*/)
00126     {
00127       return true;
00128     }
00129 
00130 
00132     bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
00133     {
00134       if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
00135         PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions.");
00136         return false;
00137       }
00138 
00139       OptionMap originalOptions;
00140       for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2)
00141         originalOptions[option[0]] = option[1];
00142 
00143       OptionMap changedOptions;
00144       if (!(this->*adjuster)(originalOptions, changedOptions)) {
00145         PTRACE(1, "Plugin", "Could not normalise/customise options.");
00146         return false;
00147       }
00148 
00149       char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *));
00150       *(char ***)parm = options;
00151       if (options == NULL) {
00152         PTRACE(1, "Plugin", "Could not allocate new option lists.");
00153         return false;
00154       }
00155 
00156       for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) {
00157         *options++ = strdup(i->first.c_str());
00158         *options++ = strdup(i->second.c_str());
00159       }
00160 
00161       return true;
00162     }
00163 
00164 
00166     virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0;
00167 
00168 
00169     // Adjust codec specific options calculated from normalised options.
00170     virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0;
00171 
00172 
00173     static void Change(const char * value,
00174                        OptionMap  & original,
00175                        OptionMap  & changed,
00176                        const char * option)
00177     {
00178       OptionMap::iterator it = original.find(option);
00179       if (it != original.end() && it->second != value)
00180         changed[option] = value;
00181     }
00182 
00183 
00184     static unsigned String2Unsigned(const std::string & str)
00185     {
00186       return strtoul(str.c_str(), NULL, 10);
00187     }
00188 
00189 
00190     static void AppendUnsigned2String(unsigned value, std::string & str)
00191     {
00192       // Not very efficient, but really, really simple
00193       if (value > 9)
00194         AppendUnsigned2String(value/10, str);
00195       str += (char)(value%10 + '0');
00196     }
00197 
00198 
00199     static void Unsigned2String(unsigned value, std::string & str)
00200     {
00201       str.clear();
00202       AppendUnsigned2String(value,str);
00203     }
00204 
00205 
00206     static void Change(unsigned     value,
00207                        OptionMap  & original,
00208                        OptionMap  & changed,
00209                        const char * option)
00210     {
00211       if (String2Unsigned(original[option]) != value)
00212         Unsigned2String(value, changed[option]);
00213     }
00214 
00215 
00216     static void ClampMax(unsigned     maximum,
00217                          OptionMap  & original,
00218                          OptionMap  & changed,
00219                          const char * option)
00220     {
00221       unsigned value = String2Unsigned(original[option]);
00222       if (value > maximum)
00223         Unsigned2String(maximum, changed[option]);
00224     }
00225 
00226 
00227     static void ClampMin(unsigned     minimum,
00228                          OptionMap  & original,
00229                          OptionMap  & changed,
00230                          const char * option)
00231     {
00232       unsigned value = String2Unsigned(original[option]);
00233       if (value < minimum)
00234         Unsigned2String(minimum, changed[option]);
00235     }
00236 
00237     virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/)
00238     {
00239       if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
00240         for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
00241           if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
00242             *options = NULL;
00243             break;
00244           }
00245         }
00246       }
00247     }
00248 
00249     static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
00250     {
00251       while (size-- > 0) {
00252         PluginCodec_MediaFormat * info = (PluginCodec_MediaFormat *)definitions->userData;
00253         if (info != NULL)
00254           info->AdjustForVersion(version, definitions);
00255         ++definitions;
00256       }
00257     }
00258 };
00259 
00260 
00262 
00263 template<typename NAME>
00264 class PluginCodec
00265 {
00266   protected:
00267     PluginCodec(const PluginCodec_Definition * defn)
00268       : m_definition(defn)
00269       , m_optionsSame(false)
00270       , m_maxBitRate(defn->bitsPerSec)
00271       , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
00272     {
00273       PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
00274              << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
00275     }
00276 
00277 
00278   public:
00279     virtual ~PluginCodec()
00280     {
00281     }
00282 
00283 
00285     virtual bool Construct()
00286     {
00287       return true;
00288     }
00289 
00290 
00295     static bool Terminate()
00296     {
00297       return true;
00298     }
00299 
00300 
00302     virtual bool Transcode(const void * fromPtr,
00303                              unsigned & fromLen,
00304                                  void * toPtr,
00305                              unsigned & toLen,
00306                              unsigned & flags) = 0;
00307 
00308 
00310     virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
00311     {
00312       return true;
00313     }
00314 
00315 
00317     virtual size_t GetOutputDataSize()
00318     {
00319       return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
00320     }
00321 
00322 
00329     virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
00330     {
00331       return true;
00332     }
00333 
00334 
00336     virtual bool SetOptions(const char * const * options)
00337     {
00338       m_optionsSame = true;
00339 
00340       // get the media format options after adjustment from protocol negotiation
00341       for (const char * const * option = options; *option != NULL; option += 2) {
00342         if (!SetOption(option[0], option[1])) {
00343           PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
00344           return false;
00345         }
00346       }
00347 
00348       if (m_optionsSame)
00349         return true;
00350 
00351       return OnChangedOptions();
00352     }
00353 
00354 
00356     virtual bool OnChangedOptions()
00357     {
00358       return true;
00359     }
00360 
00361 
00363     virtual bool SetOption(const char * optionName, const char * optionValue)
00364     {
00365       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
00366         return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
00367 
00368       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
00369         return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second
00370 
00371       return true;
00372     }
00373 
00374 
00375     template <typename T>
00376     bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00377     {
00378       unsigned newValue = oldValue;
00379       if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum))
00380         return false;
00381       oldValue = (T)newValue;
00382       return true;
00383     }
00384 
00385 
00386     bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00387     {
00388       char * end;
00389       unsigned newValue = strtoul(optionValue, &end, 10);
00390       if (*end != '\0')
00391         return false;
00392 
00393       if (newValue < minimum)
00394         newValue = minimum;
00395       else if (newValue > maximum)
00396         newValue = maximum;
00397 
00398       if (oldValue != newValue) {
00399         oldValue = newValue;
00400         m_optionsSame = false;
00401       }
00402 
00403       return true;
00404     }
00405 
00406 
00407     template <typename T>
00408     bool SetOptionBoolean(T & oldValue, const char * optionValue)
00409     {
00410       bool opt = oldValue != 0;
00411       if (!SetOptionBoolean(opt, optionValue))
00412         return false;
00413       oldValue = (T)opt;
00414       return true;
00415     }
00416 
00417 
00418     bool SetOptionBoolean(bool & oldValue, const char * optionValue)
00419     {
00420       bool newValue;
00421       if (     strcasecmp(optionValue, "0") == 0 ||
00422                strcasecmp(optionValue, "n") == 0 ||
00423                strcasecmp(optionValue, "f") == 0 ||
00424                strcasecmp(optionValue, "no") == 0 ||
00425                strcasecmp(optionValue, "false") == 0)
00426         newValue = false;
00427       else if (strcasecmp(optionValue, "1") == 0 ||
00428                strcasecmp(optionValue, "y") == 0 ||
00429                strcasecmp(optionValue, "t") == 0 ||
00430                strcasecmp(optionValue, "yes") == 0 ||
00431                strcasecmp(optionValue, "true") == 0)
00432         newValue = true;
00433       else
00434         return false;
00435 
00436       if (oldValue != newValue) {
00437         oldValue = newValue;
00438         m_optionsSame = false;
00439       }
00440 
00441       return true;
00442     }
00443 
00444 
00445     bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
00446     {
00447       return SetOptionBit((unsigned &)oldValue, bit, optionValue);
00448     }
00449 
00450 
00451     bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
00452     {
00453       bool newValue;
00454       if (strcmp(optionValue, "0") == 0)
00455         newValue = false;
00456       else if (strcmp(optionValue, "1") == 0)
00457         newValue = true;
00458       else
00459         return false;
00460 
00461       if (((oldValue&bit) != 0) != newValue) {
00462         if (newValue)
00463           oldValue |= bit;
00464         else
00465           oldValue &= ~bit;
00466         m_optionsSame = false;
00467       }
00468 
00469       return true;
00470     }
00471 
00472 
00473     template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
00474     {
00475       CodecClass * codec = new CodecClass(defn);
00476       if (codec != NULL && codec->Construct())
00477         return codec;
00478 
00479       PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
00480       delete codec;
00481       return NULL;
00482     }
00483 
00484 
00485     static void Destroy(const PluginCodec_Definition * /*defn*/, void * context)
00486     {
00487       delete (PluginCodec *)context;
00488     }
00489 
00490 
00491     static int Transcode(const PluginCodec_Definition * /*defn*/,
00492                                                  void * context,
00493                                            const void * fromPtr,
00494                                              unsigned * fromLen,
00495                                                  void * toPtr,
00496                                              unsigned * toLen,
00497                                          unsigned int * flags)
00498     {
00499       if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
00500         return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
00501 
00502       PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
00503       return false;
00504     }
00505 
00506 
00507     static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00508     {
00509       return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
00510     }
00511 
00512 
00513     static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00514     {
00515       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
00516     }
00517 
00518 
00519     static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00520     {
00521       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
00522     }
00523 
00524 
00525     static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00526     {
00527       if (parm == NULL || len == NULL || *len != sizeof(char ***))
00528         return false;
00529 
00530       char ** strings = (char **)parm;
00531       for (char ** string = strings; *string != NULL; string++)
00532         free(*string);
00533       free(strings);
00534       return true;
00535     }
00536 
00537 
00538     static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
00539     {
00540       if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
00541         return false;
00542 
00543       *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
00544       *len = 0;
00545       return true;
00546     }
00547 
00548 
00549     static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00550     {
00551       PluginCodec * codec = (PluginCodec *)context;
00552       return len != NULL && *len == sizeof(const char **) && parm != NULL &&
00553              codec != NULL && codec->SetOptions((const char * const *)parm);
00554     }
00555 
00556     static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00557     {
00558       return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
00559              ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
00560     }
00561 
00562     static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00563     {
00564       PluginCodec * codec = (PluginCodec *)context;
00565       return len != NULL && parm != NULL &&
00566              codec != NULL && codec->SetInstanceID((const char *)parm, *len);
00567     }
00568 
00569     static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00570     {
00571       PluginCodec * codec = (PluginCodec *)context;
00572       return len != NULL && parm != NULL &&
00573              codec != NULL && codec->GetStatistics((char *)parm, *len);
00574     }
00575 
00576     static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00577     {
00578       PluginCodec * codec = (PluginCodec *)context;
00579       return codec != NULL && codec->Terminate();
00580     }
00581 
00582     static struct PluginCodec_ControlDefn * GetControls()
00583     {
00584       static PluginCodec_ControlDefn ControlsTable[] = {
00585         { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE,  PluginCodec::GetOutputDataSize },
00586         { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised },
00587         { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised },
00588         { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS,     PluginCodec::SetOptions },
00589         { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS,     PluginCodec::GetOptions },
00590         { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS,    PluginCodec::FreeOptions },
00591         { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL,    PluginCodec::ValidForProtocol },
00592         { PLUGINCODEC_CONTROL_SET_INSTANCE_ID,       PluginCodec::SetInstanceID },
00593         { PLUGINCODEC_CONTROL_GET_STATISTICS,        PluginCodec::GetStatistics },
00594         { PLUGINCODEC_CONTROL_TERMINATE_CODEC,       PluginCodec::Terminate },
00595         PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00596         { NULL }
00597       };
00598       return ControlsTable;
00599     }
00600 
00601   protected:
00602     const PluginCodec_Definition * m_definition;
00603 
00604     bool     m_optionsSame;
00605     unsigned m_maxBitRate;
00606     unsigned m_frameTime;
00607 };
00608 
00609 
00610 #endif // OPAL_CODEC_OPALPLUGIN_HPP

Generated on 14 Aug 2013 for OPAL by  doxygen 1.4.7