1/*
2 * Python bindings.
3 *
4 * Open Phone Abstraction Library (OPAL)
5 *
6 * Copyright (c) 2011 Demetrius Cassidy
7 *
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
12 *
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15 * the License for the specific language governing rights and limitations
16 * under the License.
17 *
18 * The Original Code is Open Phone Abstraction Library (OPAL)
19 *
20 * The Initial Developer of the Original Code is Demetrius Cassidy
21 *
22 * Contributor(s): ______________________________________.
23 *
24 * $Revision: 26570 $
25 * $Author: rjongbloed $
26 * $Date: 2011-10-09 20:00:46 -0500 (Sun, 09 Oct 2011) $
27 */
28
29///////////////////////////////////////////////////////////////////////////////
30
31/**Base class for options attached to an OpalMediaFormat.
32  */
33class OpalMediaOption : PObject /Abstract/
34{
35%TypeHeaderCode
36#include <ptlib.h>
37#include <opal/mediafmt.h>
38%End
39
40  public:
41    enum MergeType {
42      NoMerge,
43      MinMerge,
44      MaxMerge,
45      EqualMerge,
46      NotEqualMerge,
47      AlwaysMerge,
48
49      // Synonyms
50      AndMerge = MinMerge,
51      OrMerge  = MaxMerge
52    };
53
54  protected:
55    OpalMediaOption(
56      const PString & name
57    );
58    OpalMediaOption(
59      const char * name,
60      bool readOnly,
61      MergeType merge
62    );
63
64  public:
65    virtual Comparison Compare(const PObject & obj) const;
66
67    virtual bool Merge(
68      const OpalMediaOption & option
69    );
70    virtual Comparison CompareValue(
71      const OpalMediaOption & option
72    ) const = 0;
73    virtual void Assign(
74      const OpalMediaOption & option
75    ) = 0;
76
77    PString AsString() const;
78    bool FromString(const PString & value);
79
80    const PString & GetName() const;
81
82    bool IsReadOnly() const;
83    void SetReadOnly(bool readOnly);
84
85    MergeType GetMerge() const;
86    void SetMerge(MergeType merge);
87
88    const PString & GetFMTPName() const;
89    void SetFMTPName(const char * name);
90
91    const PString & GetFMTPDefault() const;
92    void SetFMTPDefault(const char * value);
93
94
95    struct H245GenericInfo {
96      H245GenericInfo();
97      unsigned ordinal;
98
99      enum Modes {
100        None,
101        Collapsing,
102        NonCollapsing
103      };
104
105      enum IntegerTypes {
106        UnsignedInt,
107        Unsigned32,
108        BooleanArray
109      };
110
111      bool excludeTCS;
112      bool excludeOLC;
113      bool excludeReqMode;
114    };
115
116    const H245GenericInfo & GetH245Generic() const;
117    void SetH245Generic(const H245GenericInfo & genericInfo);
118
119};
120
121///////////////////////////////////////////////////////////////////////////////
122
123/**This class describes a media format as used in the OPAL system. A media
124   format is the type of any media data that is trasferred between OPAL
125   entities. For example an audio codec such as G.723.1 is a media format, a
126   video codec such as H.261 is also a media format.
127  */
128class OpalMediaFormat : PContainer
129{
130
131%TypeHeaderCode
132#include <ptlib.h>
133#include <opal/mediafmt.h>
134%End
135
136  public:
137    /**This form of the constructor will register the full details of the
138       media format into an internal database. This would typically be used
139       as a static global. In fact it would be very dangerous for an instance
140       to use this constructor in any other way, especially local variables.
141
142       If the rtpPayloadType is RTP_DataFrame::DynamicBase, then the RTP
143       payload type is actually set to the first unused dynamic RTP payload
144       type that is in the registers set of media formats.
145
146       The frameSize parameter indicates that the media format has a maximum
147       size for each data frame, eg G.723.1 frames are no more than 24 bytes
148       long. If zero then there is no intrinsic maximum, eg G.711.
149      */
150    OpalMediaFormat(
151      const char * fullName,                      ///<  Full name of media format
152      const OpalMediaType & mediaType,            ///<  media type for this format
153      RTP_DataFrame::PayloadTypes rtpPayloadType, ///<  RTP payload type code
154      const char * encodingName,                  ///<  RTP encoding name
155      PBoolean     needsJitter,                   ///<  Indicate format requires a jitter buffer
156      unsigned bandwidth,                         ///<  Bandwidth in bits/second
157      PINDEX   frameSize,                         ///<  Size of frame in bytes (if applicable)
158      unsigned frameTime,                         ///<  Time for frame in RTP units (if applicable)
159      unsigned clockRate,                         ///<  Clock rate for data (if applicable)
160      time_t timeStamp = 0                        ///<  timestamp (for versioning)
161    );
162
163    /**Construct a media format, searching database for information.
164       This constructor will search through the RegisteredMediaFormats list
165       for the match of the payload type, if found the other information
166       fields are set from the database. If not found then the ancestor
167       string is set to the empty string.
168
169       Note it is impossible to determine the order of registration so this
170       should not be relied on.
171      */
172    OpalMediaFormat(
173      RTP_DataFrame::PayloadTypes rtpPayloadType, ///<  RTP payload type code
174      unsigned clockRate,                         ///<  clock rate
175      const char * rtpEncodingName = NULL,        ///<  RTP payload type name
176      const char * protocol = NULL                ///<  valid protocol (if NULL, then all)
177    );
178
179    /**Construct a media format, searching database for information.
180       This constructor will search through the RegisteredMediaFormats list
181       for the wildcard match of the parameter string, if found the other
182       information fields are set from the database. If not found then the
183       ancestor string is set to the empty string.
184
185       The wildcard string is a simple substring match using the '*'
186       character. For example: "G.711*" would match the first of
187       "G.711-uLaw-64k" and "G.711-ALaw-64k" to have been registered.
188
189       Note it is impossible to determine the order of registration so this
190       should not be relied on.
191      */
192    OpalMediaFormat(
193      const char * wildcard  ///<  Wildcard name to search for
194    );
195
196    /**Construct a media format, searching database for information.
197       This constructor will search through the RegisteredMediaFormats list
198       for the wildcard match of the parameter string, if found the other
199       information fields are set from the database. If not found then the
200       ancestor string is set to the empty string.
201
202       The wildcard string is a simple substring match using the '*'
203       character. For example: "G.711*" would match the first of
204       "G.711-uLaw-64k" and "G.711-ALaw-64k" to have been registered.
205
206       Note it is impossible to determine the order of registration so this
207       should not be relied on.
208      */
209    OpalMediaFormat(
210      const PString & wildcard  ///<  Wildcard name to search for
211    );
212
213
214    /**Create a copy of the media format.
215      */
216    virtual PObject * Clone() const;
217
218    /**Compare two media formats.
219      */
220    virtual Comparison Compare(const PObject & obj) const;
221
222    /**This will translate the codec specific "custom" options to OPAL
223       "normalised" options, e.g. For H.261 "QCIF MPI"="1", "CIF MPI"="5"
224        would be translated to "Frame Width"="176", "Frame Height"="144".
225      */
226    bool ToNormalisedOptions();
227
228    /**This will do the reverse of ToNormalisedOptions, translating the OPAL
229       "normalised" options to codec specific "custom" options.
230      */
231    bool ToCustomisedOptions();
232
233    /**Merge with another media format. This will alter and validate
234       the options for this media format according to the merge rule for
235       each option. The parameter is typically a "capability" while the
236       current object isthe proposed channel format. This if the current
237       object has a tx number of frames of 3, but the parameter has a value
238       of 1, then the current object will be set to 1.
239
240       Returns PFalse if the media formats are incompatible and cannot be
241       merged.
242      */
243    bool Merge(
244      const OpalMediaFormat & mediaFormat
245    );
246
247    /**Get the name of the format
248      */
249    PString GetName() const;
250
251    /**Return PTrue if media format info is valid. This may be used if the
252       single string constructor is used to check that it matched something
253       in the registered media formats database.
254      */
255    PBoolean IsValid() const;
256
257    /**Return PTrue if media format info may be sent via RTP. Some formats are internal
258       use only and are never transported "over the wire".
259      */
260    PBoolean IsTransportable() const;
261
262    /**Get the RTP payload type that is to be used for this media format.
263       This will either be an intrinsic one for the media format eg GSM or it
264       will be automatically calculated as a dynamic media format that will be
265       uniqueue amongst the registered media formats.
266      */
267    RTP_DataFrame::PayloadTypes GetPayloadType() const;
268    void SetPayloadType(RTP_DataFrame::PayloadTypes type);
269
270    /**Get the RTP encoding name that is to be used for this media format.
271      */
272    const char * GetEncodingName() const;
273
274    /** Get the media type for this format
275      */
276    OpalMediaType GetMediaType() const;
277
278    /**Determine if the media format requires a jitter buffer. As a rule an
279       audio codec needs a jitter buffer and all others do not.
280      */
281    bool NeedsJitterBuffer() const;
282    static const PString & NeedsJitterOption();
283
284    /**Get the average bandwidth used in bits/second.
285      */
286    unsigned GetBandwidth() const;
287    static const PString & MaxBitRateOption();
288    static const PString & TargetBitRateOption();
289
290    /**Get the maximum frame size in bytes. If this returns zero then the
291       media format has no intrinsic maximum frame size, eg a video format
292       would return zero but G.723.1 would return 24.
293      */
294    PINDEX GetFrameSize() const;
295    static const PString & MaxFrameSizeOption();
296
297    /**Get the frame time in RTP timestamp units. If this returns zero then
298       the media format is not real time and has no intrinsic timing eg T.120
299      */
300    unsigned GetFrameTime() const;
301    static const PString & FrameTimeOption();
302
303    /**Get the number of RTP timestamp units per millisecond.
304      */
305    unsigned GetTimeUnits() const;
306
307    enum StandardClockRate {
308      AudioClockRate = 8000,  ///<  8kHz sample rate
309      VideoClockRate = 90000  ///<  90kHz sample rate
310    };
311
312    /**Get the clock rate in Hz for this format.
313      */
314    unsigned GetClockRate() const;
315    static const PString & ClockRateOption();
316
317    /**Get the name of the OpalMediaOption indicating the protocol the format is being used on.
318      */
319    static const PString & ProtocolOption();
320
321    /**Get the name of the OpalMediaOption indicating the maximum RTP payload size.
322      */
323    static const PString & MaxTxPacketSizeOption();
324
325    /**Get all of the option values of the format as a dictionary.
326       Each entry is a name value pair.
327      */
328    PStringToString GetOptions() const;
329
330    /**Get the number of options this media format has.
331      */
332    PINDEX GetOptionCount() const;
333
334    /**Get the option instance at the specified index. This contains the
335       description and value for the option.
336      */
337    const OpalMediaOption & GetOption(
338      PINDEX index   ///<  Index of option in list to get
339    ) const;
340
341    /**Get the option value of the specified name as a string.
342
343       Returns false of the option is not present.
344      */
345    bool GetOptionValue(
346      const PString & name,   ///<  Option name
347      PString & value /Out/        ///<  String to receive option value
348    ) const;
349
350    /**Set the option value of the specified name as a string.
351       Note the option will not be added if it does not exist, the option
352       must be explicitly added using AddOption().
353
354       Returns false of the option is not present.
355      */
356    bool SetOptionValue(
357      const PString & name,   ///<  Option name
358      const PString & value   ///<  New option value as string
359    );
360
361    /**Get the option value of the specified name as a boolean. The default
362       value is returned if the option is not present.
363      */
364    bool GetOptionBoolean(
365      const PString & name,   ///<  Option name
366      bool dflt = PFalse       ///<  Default value if option not present
367    ) const;
368
369    /**Set the option value of the specified name as a boolean.
370       Note the option will not be added if it does not exist, the option
371       must be explicitly added using AddOption().
372
373       Returns false of the option is not present or is not of the same type.
374      */
375    bool SetOptionBoolean(
376      const PString & name,   ///<  Option name
377      bool value              ///<  New value for option
378    );
379
380    /**Get the option value of the specified name as an integer. The default
381       value is returned if the option is not present.
382      */
383    int GetOptionInteger(
384      const PString & name,   ///<  Option name
385      int dflt = 0            ///<  Default value if option not present
386    ) const;
387
388    /**Set the option value of the specified name as an integer.
389       Note the option will not be added if it does not exist, the option
390       must be explicitly added using AddOption().
391
392       Returns false of the option is not present, not of the same type or
393       is putside the allowable range.
394      */
395    bool SetOptionInteger(
396      const PString & name,   ///<  Option name
397      int value               ///<  New value for option
398    );
399
400    /**Get the option value of the specified name as a real. The default
401       value is returned if the option is not present.
402      */
403    double GetOptionReal(
404      const PString & name,   ///<  Option name
405      double dflt = 0         ///<  Default value if option not present
406    ) const;
407
408    /**Set the option value of the specified name as a real.
409       Note the option will not be added if it does not exist, the option
410       must be explicitly added using AddOption().
411
412       Returns false of the option is not present or is not of the same type.
413      */
414    bool SetOptionReal(
415      const PString & name,   ///<  Option name
416      double value            ///<  New value for option
417    );
418
419    /**Get the option value of the specified name as an index into an
420       enumeration list. The default value is returned if the option is not
421       present.
422      */
423    PINDEX GetOptionEnum(
424      const PString & name,   ///<  Option name
425      PINDEX dflt = 0         ///<  Default value if option not present
426    ) const;
427
428    /**Set the option value of the specified name as an index into an enumeration.
429       Note the option will not be added if it does not exist, the option
430       must be explicitly added using AddOption().
431
432       Returns false of the option is not present or is not of the same type.
433      */
434    bool SetOptionEnum(
435      const PString & name,   ///<  Option name
436      PINDEX value            ///<  New value for option
437    );
438
439    /**Get the option value of the specified name as a string. The default
440       value is returned if the option is not present.
441      */
442    PString GetOptionString(
443      const PString & name,                   ///<  Option name
444      const PString & dflt = PString::Empty() ///<  Default value if option not present
445    ) const;
446
447    /**Set the option value of the specified name as a string.
448       Note the option will not be added if it does not exist, the option
449       must be explicitly added using AddOption().
450
451       Returns false of the option is not present or is not of the same type.
452      */
453    bool SetOptionString(
454      const PString & name,   ///<  Option name
455      const PString & value   ///<  New value for option
456    );
457
458    /**Set the option value of the specified name as an octet array.
459       Note the option will not be added if it does not exist, the option
460       must be explicitly added using AddOption().
461
462       Returns false of the option is not present or is not of the same type.
463      */
464    bool SetOptionOctets(
465      const PString & name,       ///<  Option name
466      const BYTE * data,          ///<  Octets in option
467      PINDEX length               ///<  Number of octets
468    );
469
470    /**Get a copy of the list of media formats that have been registered.
471      */
472    static OpalMediaFormatList GetAllRegisteredMediaFormats();
473    static void GetAllRegisteredMediaFormats(
474      OpalMediaFormatList & copy    ///<  List to receive the copy of the master list
475    );
476
477    /**Set the options on the master format list entry.
478       The media format must already be registered. Returns false if not.
479      */
480    static bool SetRegisteredMediaFormat(
481      const OpalMediaFormat & mediaFormat  ///<  Media format to copy to master list
482    );
483
484	/**Remove the media format from master format list entry.
485       The media format must already be registered. Returns false if not.
486    */
487    static bool RemoveRegisteredMediaFormat(
488      const OpalMediaFormat & mediaFormat  ///<  Media format to copy to master list
489    );
490
491    /**
492      * Add a new option to this media format
493      */
494    bool AddOption(
495      OpalMediaOption * option,
496      PBoolean overwrite = PFalse
497    );
498
499    /**
500      * Determine if media format has the specified option.
501      */
502    bool HasOption(const PString & name) const;
503
504    /**
505      * Get a pointer to the specified media format option.
506      * Returns NULL if thee option does not exist.
507      */
508    OpalMediaOption * FindOption(
509      const PString & name
510    ) const;
511
512    /** Returns PTrue if the media format is valid for the protocol specified
513        This allow plugin codecs to customise which protocols they are valid for
514        The default implementation returns true unless the protocol is H.323
515        and the rtpEncodingName is NULL
516      */
517    bool IsValidForProtocol(const PString & protocol) const;
518
519    time_t GetCodecVersionTime() const;
520
521    static const PString & MediaPacketizationOption();
522    static const PString & MediaPacketizationsOption();
523
524	SIP_PYOBJECT __repr__();
525%MethodCode
526	sipRes = PyString_FromString(sipCpp->GetName());
527%End
528
529	int __nonzero__();
530%MethodCode
531	sipRes = sipCpp->IsValid();
532%End
533
534	int __contains__(const PString & name);
535%MethodCode
536	sipRes = (*a0 == sipCpp->GetName());
537%End
538
539	int __eq__(const PString & name);
540%MethodCode
541	sipRes = (*a0 == sipCpp->GetName());
542%End
543
544};
545
546class OpalMediaFormatInternal : PObject
547{
548  public:
549    OpalMediaFormatInternal(
550      const char * fullName,
551      const OpalMediaType & mediaType,
552      RTP_DataFrame::PayloadTypes rtpPayloadType,
553      const char * encodingName,
554      PBoolean     needsJitter,
555      unsigned bandwidth,
556      PINDEX   frameSize,
557      unsigned frameTime,
558      unsigned clockRate,
559      time_t timeStamp
560    );
561
562    const PCaselessString & GetName() const;
563
564    virtual PObject * Clone() const;
565
566    virtual bool IsValid() const;
567    virtual bool IsTransportable() const;
568
569    virtual PStringToString GetOptions() const;
570    virtual bool GetOptionValue(const PString & name, PString & value) const;
571    virtual bool SetOptionValue(const PString & name, const PString & value);
572    virtual bool GetOptionBoolean(const PString & name, bool dflt) const;
573    virtual bool SetOptionBoolean(const PString & name, bool value);
574    virtual int GetOptionInteger(const PString & name, int dflt) const;
575    virtual bool SetOptionInteger(const PString & name, int value);
576    virtual double GetOptionReal(const PString & name, double dflt) const;
577    virtual bool SetOptionReal(const PString & name, double value);
578    virtual PINDEX GetOptionEnum(const PString & name, PINDEX dflt) const;
579    virtual bool SetOptionEnum(const PString & name, PINDEX value);
580    virtual PString GetOptionString(const PString & name, const PString & dflt) const;
581    virtual bool SetOptionString(const PString & name, const PString & value);
582    virtual bool GetOptionOctets(const PString & name, PBYTEArray & octets) const;
583    virtual bool SetOptionOctets(const PString & name, const PBYTEArray & octets);
584    virtual bool SetOptionOctets(const PString & name, const BYTE * data, PINDEX length);
585    virtual bool AddOption(OpalMediaOption * option, PBoolean overwrite = false);
586    virtual OpalMediaOption * FindOption(const PString & name) const;
587
588    virtual bool ToNormalisedOptions();
589    virtual bool ToCustomisedOptions();
590    virtual bool Merge(const OpalMediaFormatInternal & mediaFormat);
591
592    virtual bool ValidateMerge(const OpalMediaFormatInternal & mediaFormat) const;
593
594    virtual bool IsValidForProtocol(const PString & protocol) const;
595};
596
597class OpalAudioFormat : OpalMediaFormat
598{
599  public:
600    OpalAudioFormat(
601      OpalMediaFormatInternal * info = NULL
602    );
603
604    OpalAudioFormat(
605      const char * fullName,    ///<  Full name of media format
606      RTP_DataFrame::PayloadTypes rtpPayloadType, ///<  RTP payload type code
607      const char * encodingName,///<  RTP encoding name
608      PINDEX   frameSize,       ///<  Size of frame in bytes (if applicable)
609      unsigned frameTime,       ///<  Time for frame in RTP units (if applicable)
610      unsigned rxFrames,        ///<  Maximum number of frames per packet we can receive
611      unsigned txFrames,        ///<  Desired number of frames per packet we transmit
612      unsigned maxFrames = 256, ///<  Maximum possible frames per packet
613      unsigned clockRate = 8000, ///<  Clock Rate
614      time_t timeStamp = 0       ///<  timestamp (for versioning)
615    );
616
617    static const PString & RxFramesPerPacketOption();
618    static const PString & TxFramesPerPacketOption();
619    static const PString & MaxFramesPerPacketOption();
620    static const PString & ChannelsOption();
621};
622
623
624%MappedType OpalMediaFormatList
625{
626%TypeHeaderCode
627#include <ptlib.h>
628#include <ptlib/lists.h>
629#include <opal/mediafmt.h>
630%End
631
632%ConvertFromTypeCode
633    // Create the list.
634    PyObject *l;
635	SIP_SSIZE_T i = 0;
636
637    if ((l = PyList_New(sipCpp->GetSize())) == NULL)
638        return NULL;
639
640    // Go through each element in the C++ instance and convert it to a
641    // wrapped TYPE.
642    for (OpalMediaFormatList::iterator iter = sipCpp->begin(); iter != sipCpp->end(); iter++)
643    {
644		OpalMediaFormat *fmt = new OpalMediaFormat(*iter);
645        PyObject *pobj;
646
647		// Get the Python wrapper for the Type instance, creating a new
648		// one if necessary, and handle any ownership transfer.
649		if ((pobj = sipConvertFromNewType(fmt, sipType_OpalMediaFormat, Py_None)) == NULL)
650		{
651			// There was an error so garbage collect the Python list.
652			Py_DECREF(l);
653			return NULL;
654		}
655
656		// Add the wrapper to the list.
657        PyList_SET_ITEM(l, i++, pobj);
658	}
659
660	// Return the Python list.
661    return l;
662%End
663
664%ConvertToTypeCode
665	// Check if type is compatible
666	if (sipIsErr == NULL)
667	{
668		// Must be any iterable
669		PyObject *i = PyObject_GetIter(sipPy);
670		bool iterable = (i != NULL);
671		Py_XDECREF(i);
672		return iterable;
673	}
674
675	// Iterate over the object
676	PyObject *iterator = PyObject_GetIter(sipPy);
677	PyObject *item;
678	int state;
679
680	OpalMediaFormatList *plist = new OpalMediaFormatList;
681
682	while ((item = PyIter_Next(iterator)))
683	{
684	   if (!sipCanConvertToType(item, sipType_OpalMediaFormat, SIP_NOT_NONE))
685	   {
686		   PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to OpalMediaFormat");
687		   *sipIsErr = 1;
688		   break;
689	   }
690
691	   //Python should retain ownership, as we are creating a copy of this object in our list.
692	   OpalMediaFormat* p = reinterpret_cast<OpalMediaFormat*>(
693			sipConvertToType(item, sipType_OpalMediaFormat, Py_None, SIP_NOT_NONE, &state, sipIsErr));
694
695	   if (!*sipIsErr)
696		   *plist+=*p;
697
698	   sipReleaseType(p, sipType_OpalMediaFormat, state);
699	   Py_DECREF(item);
700	}
701
702	Py_DECREF(iterator);
703
704	if (*sipIsErr)
705	{
706	   delete plist;
707	   return 0;
708	}
709
710	*sipCppPtr = plist;
711	return sipGetState(sipTransferObj);
712%End
713};
714
715
716class OpalVideoFormat : OpalMediaFormat
717{
718%TypeHeaderCode
719#include <ptlib.h>
720#include <opal/mediafmt.h>
721%End
722
723  public:
724    OpalVideoFormat(
725      const char * fullName,    ///<  Full name of media format
726      RTP_DataFrame::PayloadTypes rtpPayloadType, ///<  RTP payload type code
727      const char * encodingName,///<  RTP encoding name
728      unsigned maxFrameWidth,   ///<  Width of video frame
729      unsigned maxFrameHeight,  ///<  Height of video frame
730      unsigned maxFrameRate,    ///<  Number of frames per second
731      unsigned maxBitRate,      ///<  Maximum bits per second
732      time_t timeStamp = 0      ///<  timestamp (for versioning)
733    );
734
735    static const PString & FrameWidthOption();
736    static const PString & FrameHeightOption();
737    static const PString & MinRxFrameWidthOption();
738    static const PString & MinRxFrameHeightOption();
739    static const PString & MaxRxFrameWidthOption();
740    static const PString & MaxRxFrameHeightOption();
741    static const PString & TemporalSpatialTradeOffOption();
742    static const PString & TxKeyFramePeriodOption();
743    static const PString & RateControlEnableOption();
744    static const PString & RateControllerOption();
745
746    /**The "role" of the content in the video stream based on this media
747       format. This is based on RFC4796 and H.239 semantics and is an
748       enumeration consisting of:
749          Value          H.239                RFC4796
750          NoRole         Not used             (not populated)
751          Presentation   Presentation (0x01)  slides
752          Main           Live (0x02)          main
753          Speaker        Live (0x02)          speaker
754          SignLanguage   Live (0x02)          sl
755      */
756    enum ContentRole {
757      eNoRole,
758      ePresentation,
759      eMainRole,
760      eSpeaker,
761      eSignLanguage,
762      eNumRoles
763    };
764
765    enum
766	{
767		ContentRoleMask = 15
768	};
769
770	static unsigned ContentRoleBit(ContentRole contentRole);
771    static const PString & ContentRoleOption();
772    static const PString & ContentRoleMaskOption();
773};