OPAL  Version 3.10.4
opalplugin.hpp
Go to the documentation of this file.
1 /*
2  * opalplugins.hpp
3  *
4  * OPAL codec plugins handler (C++ version)
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (C) 2010 Vox Lucida
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17 
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Revision: 26787 $
35  * $Author: rjongbloed $
36  * $Date: 2011-12-08 18:49:50 -0600 (Thu, 08 Dec 2011) $
37  */
38 
39 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
40 #define OPAL_CODEC_OPALPLUGIN_HPP
41 
42 #include "opalplugin.h"
43 
44 #include <string.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 
48 #include <map>
49 #include <string>
50 
51 
53 
54 #ifndef PLUGINCODEC_TRACING
55  #define PLUGINCODEC_TRACING 1
56 #endif
57 
58 #if PLUGINCODEC_TRACING
60  extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
61 
62 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
63  PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
64  int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
65  { \
66  if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
67  return false; \
68  \
69  PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
70  if (PluginCodec_LogFunctionInstance != NULL) \
71  PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
72  \
73  return true; \
74  } \
75 
76  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
77 #else
78  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
79  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
80 #endif
81 
82 #if !defined(PTRACE)
83  #if PLUGINCODEC_TRACING
84  #include <sstream>
85  #define PTRACE_CHECK(level) \
86  (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
87  #define PTRACE(level, section, args) \
88  if (PTRACE_CHECK(level)) { \
89  std::ostringstream strm; strm << args; \
90  PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
91  } else (void)0
92  #else
93  #define PTRACE_CHECK(level)
94  #define PTRACE(level, section, expr)
95  #endif
96 #endif
97 
98 
100 
102 {
103  public:
104  typedef struct PluginCodec_Option const * const * OptionsTable;
105  typedef std::map<std::string, std::string> OptionMap;
106 
107  protected:
109 
110  protected:
112  : m_options(options)
113  {
114  }
115 
116  public:
118  {
119  }
120 
121 
122  const void * GetOptionsTable() const { return m_options; }
123 
125  virtual bool IsValidForProtocol(const char * /*protocol*/)
126  {
127  return true;
128  }
129 
130 
132  bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
133  {
134  if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
135  PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions.");
136  return false;
137  }
138 
139  OptionMap originalOptions;
140  for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2)
141  originalOptions[option[0]] = option[1];
142 
143  OptionMap changedOptions;
144  if (!(this->*adjuster)(originalOptions, changedOptions)) {
145  PTRACE(1, "Plugin", "Could not normalise/customise options.");
146  return false;
147  }
148 
149  char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *));
150  *(char ***)parm = options;
151  if (options == NULL) {
152  PTRACE(1, "Plugin", "Could not allocate new option lists.");
153  return false;
154  }
155 
156  for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) {
157  *options++ = strdup(i->first.c_str());
158  *options++ = strdup(i->second.c_str());
159  }
160 
161  return true;
162  }
163 
164 
166  virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0;
167 
168 
169  // Adjust codec specific options calculated from normalised options.
170  virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0;
171 
172 
173  static void Change(const char * value,
174  OptionMap & original,
175  OptionMap & changed,
176  const char * option)
177  {
178  if (original[option] != value)
179  changed[option] = value;
180  }
181 
182 
183  static unsigned String2Unsigned(const std::string & str)
184  {
185  return strtoul(str.c_str(), NULL, 10);
186  }
187 
188 
189  static void AppendUnsigned2String(unsigned value, std::string & str)
190  {
191  // Not very efficient, but really, really simple
192  if (value > 9)
193  AppendUnsigned2String(value/10, str);
194  str += (char)(value%10 + '0');
195  }
196 
197 
198  static void Unsigned2String(unsigned value, std::string & str)
199  {
200  str.clear();
201  AppendUnsigned2String(value,str);
202  }
203 
204 
205  static void Change(unsigned value,
206  OptionMap & original,
207  OptionMap & changed,
208  const char * option)
209  {
210  if (String2Unsigned(original[option]) != value)
211  Unsigned2String(value, changed[option]);
212  }
213 
214 
215  static void ClampMax(unsigned maximum,
216  OptionMap & original,
217  OptionMap & changed,
218  const char * option)
219  {
220  unsigned value = String2Unsigned(original[option]);
221  if (value > maximum)
222  Unsigned2String(maximum, changed[option]);
223  }
224 
225 
226  static void ClampMin(unsigned minimum,
227  OptionMap & original,
228  OptionMap & changed,
229  const char * option)
230  {
231  unsigned value = String2Unsigned(original[option]);
232  if (value < minimum)
233  Unsigned2String(minimum, changed[option]);
234  }
235 
236  virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/)
237  {
238  if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
239  for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
240  if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
241  *options = NULL;
242  break;
243  }
244  }
245  }
246  }
247 
248  static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
249  {
250  while (size-- > 0) {
252  if (info != NULL)
253  info->AdjustForVersion(version, definitions);
254  ++definitions;
255  }
256  }
257 };
258 
259 
261 
262 template<typename NAME>
264 {
265  protected:
267  : m_definition(defn)
268  , m_optionsSame(false)
269  , m_maxBitRate(defn->bitsPerSec)
270  , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
271  {
272  PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
273  << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
274  }
275 
276 
277  public:
278  virtual ~PluginCodec()
279  {
280  }
281 
282 
284  virtual bool Construct()
285  {
286  return true;
287  }
288 
289 
294  static bool Terminate()
295  {
296  return true;
297  }
298 
299 
301  virtual bool Transcode(const void * fromPtr,
302  unsigned & fromLen,
303  void * toPtr,
304  unsigned & toLen,
305  unsigned & flags) = 0;
306 
307 
309  virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
310  {
311  return true;
312  }
313 
314 
316  virtual size_t GetOutputDataSize()
317  {
318  return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
319  }
320 
321 
328  virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
329  {
330  return true;
331  }
332 
333 
335  virtual bool SetOptions(const char * const * options)
336  {
337  m_optionsSame = true;
338 
339  // get the media format options after adjustment from protocol negotiation
340  for (const char * const * option = options; *option != NULL; option += 2) {
341  if (!SetOption(option[0], option[1])) {
342  PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
343  return false;
344  }
345  }
346 
347  if (m_optionsSame)
348  return true;
349 
350  return OnChangedOptions();
351  }
352 
353 
355  virtual bool OnChangedOptions()
356  {
357  return true;
358  }
359 
360 
362  virtual bool SetOption(const char * optionName, const char * optionValue)
363  {
364  if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
365  return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
366 
367  if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
368  return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second
369 
370  return true;
371  }
372 
373 
374  template <typename T>
375  bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
376  {
377  unsigned newValue = oldValue;
378  if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum))
379  return false;
380  oldValue = (T)newValue;
381  return true;
382  }
383 
384 
385  bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
386  {
387  char * end;
388  unsigned newValue = strtoul(optionValue, &end, 10);
389  if (*end != '\0')
390  return false;
391 
392  if (newValue < minimum)
393  newValue = minimum;
394  else if (newValue > maximum)
395  newValue = maximum;
396 
397  if (oldValue != newValue) {
398  oldValue = newValue;
399  m_optionsSame = false;
400  }
401 
402  return true;
403  }
404 
405 
406  template <typename T>
407  bool SetOptionBoolean(T & oldValue, const char * optionValue)
408  {
409  bool opt = oldValue != 0;
410  if (!SetOptionBoolean(opt, optionValue))
411  return false;
412  oldValue = (T)opt;
413  return true;
414  }
415 
416 
417  bool SetOptionBoolean(bool & oldValue, const char * optionValue)
418  {
419  bool newValue;
420  if ( strcasecmp(optionValue, "0") == 0 ||
421  strcasecmp(optionValue, "n") == 0 ||
422  strcasecmp(optionValue, "f") == 0 ||
423  strcasecmp(optionValue, "no") == 0 ||
424  strcasecmp(optionValue, "false") == 0)
425  newValue = false;
426  else if (strcasecmp(optionValue, "1") == 0 ||
427  strcasecmp(optionValue, "y") == 0 ||
428  strcasecmp(optionValue, "t") == 0 ||
429  strcasecmp(optionValue, "yes") == 0 ||
430  strcasecmp(optionValue, "true") == 0)
431  newValue = true;
432  else
433  return false;
434 
435  if (oldValue != newValue) {
436  oldValue = newValue;
437  m_optionsSame = false;
438  }
439 
440  return true;
441  }
442 
443 
444  bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
445  {
446  return SetOptionBit((unsigned &)oldValue, bit, optionValue);
447  }
448 
449 
450  bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
451  {
452  bool newValue;
453  if (strcmp(optionValue, "0") == 0)
454  newValue = false;
455  else if (strcmp(optionValue, "1") == 0)
456  newValue = true;
457  else
458  return false;
459 
460  if (((oldValue&bit) != 0) != newValue) {
461  if (newValue)
462  oldValue |= bit;
463  else
464  oldValue &= ~bit;
465  m_optionsSame = false;
466  }
467 
468  return true;
469  }
470 
471 
472  template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
473  {
474  CodecClass * codec = new CodecClass(defn);
475  if (codec != NULL && codec->Construct())
476  return codec;
477 
478  PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
479  delete codec;
480  return NULL;
481  }
482 
483 
484  static void Destroy(const PluginCodec_Definition * /*defn*/, void * context)
485  {
486  delete (PluginCodec *)context;
487  }
488 
489 
490  static int Transcode(const PluginCodec_Definition * /*defn*/,
491  void * context,
492  const void * fromPtr,
493  unsigned * fromLen,
494  void * toPtr,
495  unsigned * toLen,
496  unsigned int * flags)
497  {
498  if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
499  return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
500 
501  PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
502  return false;
503  }
504 
505 
506  static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
507  {
508  return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
509  }
510 
511 
512  static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
513  {
514  return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
515  }
516 
517 
518  static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
519  {
520  return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
521  }
522 
523 
524  static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
525  {
526  if (parm == NULL || len == NULL || *len != sizeof(char ***))
527  return false;
528 
529  char ** strings = (char **)parm;
530  for (char ** string = strings; *string != NULL; string++)
531  free(*string);
532  free(strings);
533  return true;
534  }
535 
536 
537  static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
538  {
539  if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
540  return false;
541 
542  *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
543  *len = 0;
544  return true;
545  }
546 
547 
548  static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
549  {
550  PluginCodec * codec = (PluginCodec *)context;
551  return len != NULL && *len == sizeof(const char **) && parm != NULL &&
552  codec != NULL && codec->SetOptions((const char * const *)parm);
553  }
554 
555  static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
556  {
557  return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
558  ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
559  }
560 
561  static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
562  {
563  PluginCodec * codec = (PluginCodec *)context;
564  return len != NULL && parm != NULL &&
565  codec != NULL && codec->SetInstanceID((const char *)parm, *len);
566  }
567 
568  static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
569  {
570  PluginCodec * codec = (PluginCodec *)context;
571  return len != NULL && parm != NULL &&
572  codec != NULL && codec->GetStatistics((char *)parm, *len);
573  }
574 
575  static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
576  {
577  PluginCodec * codec = (PluginCodec *)context;
578  return codec != NULL && codec->Terminate();
579  }
580 
582  {
583  static PluginCodec_ControlDefn ControlsTable[] = {
595  { NULL }
596  };
597  return ControlsTable;
598  }
599 
600  protected:
602 
604  unsigned m_maxBitRate;
605  unsigned m_frameTime;
606 };
607 
608 
609 #endif // OPAL_CODEC_OPALPLUGIN_HPP