1 /*
2  * h323caps.cxx
3  *
4  * H.323 protocol handler
5  *
6  * Open H323 Library
7  *
8  * Copyright (c) 1998-2000 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  * Portions of this code were written with the assisance of funding from
25  * Vovida Networks, Inc. http://www.vovida.com.
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Revision: 28048 $
30  * $Author: rjongbloed $
31  * $Date: 2012-07-17 22:41:57 -0500 (Tue, 17 Jul 2012) $
32  */
33 
34 #include <ptlib.h>
35 
36 #include <opal/buildopts.h>
37 #if OPAL_H323
38 
39 #ifdef __GNUC__
40 #pragma implementation "h323caps.h"
41 #endif
42 
43 #include <h323/h323caps.h>
44 
45 #include <h323/h323ep.h>
46 #include <h323/h323con.h>
47 #include <h323/h323pdu.h>
48 #include <h323/transaddr.h>
49 #include <t38/h323t38.h>
50 #include <codec/opalplugin.h>
51 #include <codec/rfc2833.h>
52 
53 #include <algorithm>
54 
55 
56 #define DEFINE_G711_CAPABILITY(cls, code, capName) \
57 class cls : public H323_G711Capability { \
58   public: \
59     cls() : H323_G711Capability(code) { } \
60 }; \
61 H323_REGISTER_CAPABILITY(cls, capName) \
62 
63 
64 #ifndef NO_H323_AUDIO_CODECS
65 DEFINE_G711_CAPABILITY(H323_G711ALaw64Capability, H323_G711Capability::ALaw, OPAL_G711_ALAW_64K)
66 DEFINE_G711_CAPABILITY(H323_G711uLaw64Capability, H323_G711Capability::muLaw, OPAL_G711_ULAW_64K)
67 #endif
68 
69 
70 #if OPAL_T38_CAPABILITY
71 H323_REGISTER_CAPABILITY(H323_T38Capability, OPAL_T38);
72 #endif
73 
74 
75 #if PTRACING
operator <<(ostream & o,H323Capability::MainTypes t)76 ostream & operator<<(ostream & o , H323Capability::MainTypes t)
77 {
78   const char * const names[] = {
79     "Audio", "Video", "Data", "UserInput"
80   };
81   return o << names[t];
82 }
83 
operator <<(ostream & o,H323Capability::CapabilityDirection d)84 ostream & operator<<(ostream & o , H323Capability::CapabilityDirection d)
85 {
86   const char * const names[] = {
87     "Unknown", "Receive", "Transmit", "ReceiveAndTransmit", "NoDirection"
88   };
89   return o << names[d];
90 }
91 #endif
92 
93 
94 /////////////////////////////////////////////////////////////////////////////
95 
H323Capability()96 H323Capability::H323Capability()
97 {
98   assignedCapabilityNumber = 0; // Unassigned
99   capabilityDirection = e_Unknown;
100 }
101 
102 
Compare(const PObject & obj) const103 PObject::Comparison H323Capability::Compare(const PObject & obj) const
104 {
105   PAssert(PIsDescendant(&obj, H323Capability), PInvalidCast);
106   const H323Capability & other = (const H323Capability &)obj;
107 
108   int mt = GetMainType();
109   int omt = other.GetMainType();
110   if (mt < omt)
111     return LessThan;
112   if (mt > omt)
113     return GreaterThan;
114 
115   int st = GetSubType();
116   int ost = other.GetSubType();
117   if (st < ost)
118     return LessThan;
119   if (st > ost)
120     return GreaterThan;
121 
122   return EqualTo;
123 }
124 
125 
PrintOn(ostream & strm) const126 void H323Capability::PrintOn(ostream & strm) const
127 {
128   strm << GetFormatName();
129   if (assignedCapabilityNumber != 0)
130     strm << " <" << assignedCapabilityNumber << '>';
131 }
132 
133 
Create(const PString & name)134 H323Capability * H323Capability::Create(const PString & name)
135 {
136   H323Capability * cap = H323CapabilityFactory::CreateInstance(name);
137   if (cap == NULL)
138     return NULL;
139 
140   return (H323Capability *)cap->Clone();
141 }
142 
143 
GetDefaultSessionID() const144 unsigned H323Capability::GetDefaultSessionID() const
145 {
146   return 0;
147 }
148 
149 
SetTxFramesInPacket(unsigned)150 void H323Capability::SetTxFramesInPacket(unsigned /*frames*/)
151 {
152 }
153 
154 
GetTxFramesInPacket() const155 unsigned H323Capability::GetTxFramesInPacket() const
156 {
157   return 1;
158 }
159 
160 
GetRxFramesInPacket() const161 unsigned H323Capability::GetRxFramesInPacket() const
162 {
163   return 1;
164 }
165 
166 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const167 PBoolean H323Capability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
168 {
169   if (subTypePDU.GetTag() != GetSubType())
170     return false;
171 
172   if (mediaPacketization.IsEmpty())
173     return true;
174 
175   PStringSet mediaPacketizations = GetMediaFormat().GetMediaPacketizations();
176   if (mediaPacketizations.IsEmpty())
177     return true;
178 
179   return mediaPacketizations.Contains(mediaPacketization);
180 }
181 
182 
OnSendingPDU(H245_DataType &) const183 PBoolean H323Capability::OnSendingPDU(H245_DataType & /*pdu*/) const
184 {
185   GetWritableMediaFormat().SetOptionString(OpalMediaFormat::ProtocolOption(), PLUGINCODEC_OPTION_PROTOCOL_H323);
186   return m_mediaFormat.ToCustomisedOptions();
187 }
188 
189 
OnReceivedPDU(const H245_Capability & cap)190 PBoolean H323Capability::OnReceivedPDU(const H245_Capability & cap)
191 {
192   switch (cap.GetTag()) {
193     case H245_Capability::e_receiveVideoCapability:
194     case H245_Capability::e_receiveAudioCapability:
195     case H245_Capability::e_receiveDataApplicationCapability:
196     case H245_Capability::e_h233EncryptionReceiveCapability:
197     case H245_Capability::e_receiveUserInputCapability:
198       capabilityDirection = e_Receive;
199       break;
200 
201     case H245_Capability::e_transmitVideoCapability:
202     case H245_Capability::e_transmitAudioCapability:
203     case H245_Capability::e_transmitDataApplicationCapability:
204     case H245_Capability::e_h233EncryptionTransmitCapability:
205     case H245_Capability::e_transmitUserInputCapability:
206       capabilityDirection = e_Transmit;
207       break;
208 
209     case H245_Capability::e_receiveAndTransmitVideoCapability:
210     case H245_Capability::e_receiveAndTransmitAudioCapability:
211     case H245_Capability::e_receiveAndTransmitDataApplicationCapability:
212     case H245_Capability::e_receiveAndTransmitUserInputCapability:
213       capabilityDirection = e_ReceiveAndTransmit;
214       break;
215 
216     case H245_Capability::e_conferenceCapability:
217     case H245_Capability::e_h235SecurityCapability:
218     case H245_Capability::e_maxPendingReplacementFor:
219       capabilityDirection = e_NoDirection;
220   }
221 
222   GetWritableMediaFormat().SetOptionString(OpalMediaFormat::ProtocolOption(), PLUGINCODEC_OPTION_PROTOCOL_H323);
223   return m_mediaFormat.ToNormalisedOptions();
224 }
225 
226 
OnReceivedPDU(const H245_DataType &,PBoolean)227 PBoolean H323Capability::OnReceivedPDU(const H245_DataType & /*pdu*/, PBoolean /*receiver*/)
228 {
229   GetWritableMediaFormat().SetOptionString(OpalMediaFormat::ProtocolOption(), PLUGINCODEC_OPTION_PROTOCOL_H323);
230   return m_mediaFormat.ToNormalisedOptions();
231 }
232 
233 
IsUsable(const H323Connection &) const234 PBoolean H323Capability::IsUsable(const H323Connection &) const
235 {
236   return PTrue;
237 }
238 
239 
GetMediaFormat() const240 OpalMediaFormat H323Capability::GetMediaFormat() const
241 {
242   return m_mediaFormat.IsValid() ? m_mediaFormat : OpalMediaFormat(GetFormatName());
243 }
244 
245 
UpdateMediaFormat(const OpalMediaFormat & format)246 bool H323Capability::UpdateMediaFormat(const OpalMediaFormat &format)
247 {
248   OpalMediaFormat & mediaFormat = GetWritableMediaFormat();
249   if (mediaFormat != format)
250     return false;
251 
252   mediaFormat = format;
253   return true;
254 }
255 
256 
GetWritableMediaFormat() const257 OpalMediaFormat & H323Capability::GetWritableMediaFormat() const
258 {
259   if (!m_mediaFormat.IsValid())
260     m_mediaFormat = GetFormatName();
261   return m_mediaFormat;
262 }
263 
264 
265 /////////////////////////////////////////////////////////////////////////////
266 
H323RealTimeCapability()267 H323RealTimeCapability::H323RealTimeCapability()
268 {
269     rtpqos = NULL;
270 }
271 
H323RealTimeCapability(const H323RealTimeCapability & rtc)272 H323RealTimeCapability::H323RealTimeCapability(const H323RealTimeCapability & rtc)
273   : H323Capability(rtc)
274 {
275   if (rtc.rtpqos == NULL)
276     rtpqos = NULL;
277   else {
278     rtpqos  = new RTP_QOS();
279     *rtpqos = *rtc.rtpqos;
280   }
281 }
282 
~H323RealTimeCapability()283 H323RealTimeCapability::~H323RealTimeCapability()
284 {
285   if (rtpqos != NULL)
286     delete rtpqos;
287 }
288 
AttachQoS(RTP_QOS * _rtpqos)289 void H323RealTimeCapability::AttachQoS(RTP_QOS * _rtpqos)
290 {
291   if (rtpqos != NULL)
292     delete rtpqos;
293 
294   rtpqos = _rtpqos;
295 }
296 
CreateChannel(H323Connection & connection,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters * param) const297 H323Channel * H323RealTimeCapability::CreateChannel(H323Connection & connection,
298                                                     H323Channel::Directions dir,
299                                                     unsigned sessionID,
300                                  const H245_H2250LogicalChannelParameters * param) const
301 {
302   return connection.CreateRealTimeLogicalChannel(*this, dir, sessionID, param, rtpqos);
303 }
304 
305 
306 /////////////////////////////////////////////////////////////////////////////
307 
H323NonStandardCapabilityInfo(CompareFuncType _compareFunc,const BYTE * dataPtr,PINDEX dataSize)308 H323NonStandardCapabilityInfo::H323NonStandardCapabilityInfo(CompareFuncType _compareFunc,
309                                                              const BYTE * dataPtr,
310                                                              PINDEX dataSize)
311   :
312     t35CountryCode(OpalProductInfo::Default().t35CountryCode),
313     t35Extension(OpalProductInfo::Default().t35Extension),
314     manufacturerCode(OpalProductInfo::Default().manufacturerCode),
315     nonStandardData(dataPtr, dataSize == 0 && dataPtr != NULL
316                                  ? strlen((const char *)dataPtr) : dataSize),
317     comparisonOffset(0),
318     comparisonLength(0),
319     compareFunc(_compareFunc)
320 {
321 }
322 
H323NonStandardCapabilityInfo(const BYTE * dataPtr,PINDEX dataSize,PINDEX _offset,PINDEX _len)323 H323NonStandardCapabilityInfo::H323NonStandardCapabilityInfo(const BYTE * dataPtr,
324                                                              PINDEX dataSize,
325                                                              PINDEX _offset,
326                                                              PINDEX _len)
327   : t35CountryCode(OpalProductInfo::Default().t35CountryCode),
328     t35Extension(OpalProductInfo::Default().t35Extension),
329     manufacturerCode(OpalProductInfo::Default().manufacturerCode),
330     nonStandardData(dataPtr, dataSize == 0 && dataPtr != NULL
331                                  ? strlen((const char *)dataPtr) : dataSize),
332     comparisonOffset(_offset),
333     comparisonLength(_len),
334     compareFunc(NULL)
335 {
336 }
337 
338 
H323NonStandardCapabilityInfo(const PString & _oid,const BYTE * dataPtr,PINDEX dataSize,PINDEX _offset,PINDEX _len)339 H323NonStandardCapabilityInfo::H323NonStandardCapabilityInfo(const PString & _oid,
340                                                              const BYTE * dataPtr,
341                                                              PINDEX dataSize,
342                                                              PINDEX _offset,
343                                                              PINDEX _len)
344   : oid(_oid),
345     nonStandardData(dataPtr, dataSize == 0 && dataPtr != NULL
346                                  ? strlen((const char *)dataPtr) : dataSize),
347     comparisonOffset(_offset),
348     comparisonLength(_len),
349     compareFunc(NULL)
350 {
351 }
352 
353 
H323NonStandardCapabilityInfo(BYTE country,BYTE extension,WORD maufacturer,const BYTE * dataPtr,PINDEX dataSize,PINDEX _offset,PINDEX _len)354 H323NonStandardCapabilityInfo::H323NonStandardCapabilityInfo(BYTE country,
355                                                              BYTE extension,
356                                                              WORD maufacturer,
357                                                              const BYTE * dataPtr,
358                                                              PINDEX dataSize,
359                                                              PINDEX _offset,
360                                                              PINDEX _len)
361   : t35CountryCode(country),
362     t35Extension(extension),
363     manufacturerCode(maufacturer),
364     nonStandardData(dataPtr, dataSize == 0 && dataPtr != NULL
365                                  ? strlen((const char *)dataPtr) : dataSize),
366     comparisonOffset(_offset),
367     comparisonLength(_len),
368     compareFunc(NULL)
369 {
370 }
371 
372 
~H323NonStandardCapabilityInfo()373 H323NonStandardCapabilityInfo::~H323NonStandardCapabilityInfo()
374 {
375 }
376 
377 
OnSendingPDU(PBYTEArray & data) const378 PBoolean H323NonStandardCapabilityInfo::OnSendingPDU(PBYTEArray & data) const
379 {
380   data = nonStandardData;
381   return data.GetSize() > 0;
382 }
383 
384 
OnReceivedPDU(const PBYTEArray & data)385 PBoolean H323NonStandardCapabilityInfo::OnReceivedPDU(const PBYTEArray & data)
386 {
387   if (CompareData(data) != PObject::EqualTo)
388     return PFalse;
389 
390   nonStandardData = data;
391   return PTrue;
392 }
393 
394 
OnSendingNonStandardPDU(PASN_Choice & pdu,unsigned nonStandardTag) const395 PBoolean H323NonStandardCapabilityInfo::OnSendingNonStandardPDU(PASN_Choice & pdu,
396                                                             unsigned nonStandardTag) const
397 {
398   PBYTEArray data;
399   if (!OnSendingPDU(data))
400     return PFalse;
401 
402   pdu.SetTag(nonStandardTag);
403   H245_NonStandardParameter & param = (H245_NonStandardParameter &)pdu.GetObject();
404 
405   if (!oid) {
406     param.m_nonStandardIdentifier.SetTag(H245_NonStandardIdentifier::e_object);
407     PASN_ObjectId & nonStandardIdentifier = param.m_nonStandardIdentifier;
408     nonStandardIdentifier = oid;
409   }
410   else {
411     param.m_nonStandardIdentifier.SetTag(H245_NonStandardIdentifier::e_h221NonStandard);
412     H245_NonStandardIdentifier_h221NonStandard & h221 = param.m_nonStandardIdentifier;
413     h221.m_t35CountryCode = (unsigned)t35CountryCode;
414     h221.m_t35Extension = (unsigned)t35Extension;
415     h221.m_manufacturerCode = (unsigned)manufacturerCode;
416   }
417 
418   param.m_data = data;
419   return data.GetSize() > 0;
420 }
421 
422 
OnReceivedNonStandardPDU(const PASN_Choice & pdu,unsigned nonStandardTag)423 PBoolean H323NonStandardCapabilityInfo::OnReceivedNonStandardPDU(const PASN_Choice & pdu,
424                                                              unsigned nonStandardTag)
425 {
426   if (pdu.GetTag() != nonStandardTag)
427     return PFalse;
428 
429   const H245_NonStandardParameter & param = (const H245_NonStandardParameter &)pdu.GetObject();
430 
431   if (CompareParam(param) != PObject::EqualTo)
432     return PFalse;
433 
434   return OnReceivedPDU(param.m_data);
435 }
436 
437 
IsMatch(const H245_NonStandardParameter & param) const438 PBoolean H323NonStandardCapabilityInfo::IsMatch(const H245_NonStandardParameter & param) const
439 {
440   return CompareParam(param) == PObject::EqualTo && CompareData(param.m_data) == PObject::EqualTo;
441 }
442 
443 
CompareParam(const H245_NonStandardParameter & param) const444 PObject::Comparison H323NonStandardCapabilityInfo::CompareParam(const H245_NonStandardParameter & param) const
445 {
446   if (!oid) {
447     if (param.m_nonStandardIdentifier.GetTag() != H245_NonStandardIdentifier::e_object)
448       return PObject::LessThan;
449 
450     const PASN_ObjectId & nonStandardIdentifier = param.m_nonStandardIdentifier;
451     return oid.Compare(nonStandardIdentifier.AsString());
452   }
453 
454   if (param.m_nonStandardIdentifier.GetTag() != H245_NonStandardIdentifier::e_h221NonStandard)
455     return PObject::LessThan;
456 
457   const H245_NonStandardIdentifier_h221NonStandard & h221 = param.m_nonStandardIdentifier;
458 
459   if (h221.m_t35CountryCode < (unsigned)t35CountryCode)
460     return PObject::LessThan;
461   if (h221.m_t35CountryCode > (unsigned)t35CountryCode)
462     return PObject::GreaterThan;
463 
464   if (h221.m_t35Extension < (unsigned)t35Extension)
465     return PObject::LessThan;
466   if (h221.m_t35Extension > (unsigned)t35Extension)
467     return PObject::GreaterThan;
468 
469   if (h221.m_manufacturerCode < (unsigned)manufacturerCode)
470     return PObject::LessThan;
471   if (h221.m_manufacturerCode > (unsigned)manufacturerCode)
472     return PObject::GreaterThan;
473 
474 
475   return PObject::EqualTo;
476 }
477 
478 
CompareInfo(const H323NonStandardCapabilityInfo & other) const479 PObject::Comparison H323NonStandardCapabilityInfo::CompareInfo(const H323NonStandardCapabilityInfo & other) const
480 {
481   return CompareData(other.nonStandardData);
482 }
483 
484 
CompareData(const PBYTEArray & data) const485 PObject::Comparison H323NonStandardCapabilityInfo::CompareData(const PBYTEArray & data) const
486 {
487   if (comparisonOffset >= nonStandardData.GetSize())
488     return PObject::LessThan;
489   if (comparisonOffset >= data.GetSize())
490     return PObject::GreaterThan;
491 
492   PINDEX len = comparisonLength;
493   if (comparisonOffset+len > nonStandardData.GetSize())
494     len = nonStandardData.GetSize() - comparisonOffset;
495 
496   if (comparisonOffset+len > data.GetSize())
497     return PObject::GreaterThan;
498 
499   int cmp = memcmp((const BYTE *)nonStandardData + comparisonOffset,
500                    (const BYTE *)data + comparisonOffset,
501                    len);
502   if (cmp < 0)
503     return PObject::LessThan;
504   if (cmp > 0)
505     return PObject::GreaterThan;
506   return PObject::EqualTo;
507 }
508 
509 
510 /////////////////////////////////////////////////////////////////////////////
511 
H323GenericCapabilityInfo(const PString & standardId,unsigned bitRate)512 H323GenericCapabilityInfo::H323GenericCapabilityInfo(const PString & standardId, unsigned bitRate)
513   : m_identifier(standardId)
514   , maxBitRate(bitRate)
515 {
516 }
517 
518 
519 struct OpalMediaOptionSortByPosition
520 {
operator ()OpalMediaOptionSortByPosition521   bool operator()(OpalMediaOption const * const & o1, OpalMediaOption const * const & o2)
522   {
523     return o1->GetH245Generic().position < o2->GetH245Generic().position;
524   }
525 };
526 
OnSendingGenericPDU(H245_GenericCapability & pdu,const OpalMediaFormat & mediaFormat,H323Capability::CommandType type) const527 PBoolean H323GenericCapabilityInfo::OnSendingGenericPDU(H245_GenericCapability & pdu,
528                                                     const OpalMediaFormat & mediaFormat,
529                                                     H323Capability::CommandType type) const
530 {
531   H323SetCapabilityIdentifier(m_identifier, pdu.m_capabilityIdentifier);
532 
533   unsigned bitRate = maxBitRate != 0 ? maxBitRate : ((mediaFormat.GetBandwidth()+99)/100);
534   if (bitRate != 0) {
535     pdu.IncludeOptionalField(H245_GenericCapability::e_maxBitRate);
536     pdu.m_maxBitRate = bitRate;
537   }
538 
539   std::vector<OpalMediaOption const *> reorderedOptions;
540   for (PINDEX i = 0; i < mediaFormat.GetOptionCount(); i++) {
541     const OpalMediaOption & option = mediaFormat.GetOption(i);
542     const OpalMediaOption::H245GenericInfo & genericInfo = option.GetH245Generic();
543     if (genericInfo.mode == OpalMediaOption::H245GenericInfo::None)
544       continue;
545 
546     switch (type) {
547       case H323Capability::e_TCS :
548         if (genericInfo.excludeTCS)
549           continue;
550         break;
551       case H323Capability::e_OLC :
552         if (genericInfo.excludeOLC)
553           continue;
554         break;
555       case H323Capability::e_ReqMode :
556         if (genericInfo.excludeReqMode)
557           continue;
558         break;
559     }
560 
561     if (option.AsString() != genericInfo.defaultValue)
562       reorderedOptions.push_back(&option);
563   }
564 
565   std::sort(reorderedOptions.begin(), reorderedOptions.end(), OpalMediaOptionSortByPosition());
566 
567   for (std::vector<OpalMediaOption const *>::iterator it = reorderedOptions.begin(); it != reorderedOptions.end(); ++it) {
568     const OpalMediaOption & option = **it;
569     const OpalMediaOption::H245GenericInfo & genericInfo = option.GetH245Generic();
570 
571     H245_ArrayOf_GenericParameter & params =
572             genericInfo.mode == OpalMediaOption::H245GenericInfo::Collapsing ? pdu.m_collapsing : pdu.m_nonCollapsing;
573 
574     if (PIsDescendant(&option, OpalMediaOptionBoolean))
575       H323AddGenericParameterBoolean(params, genericInfo.ordinal, ((const OpalMediaOptionBoolean &)option).GetValue());
576     else if (PIsDescendant(&option, OpalMediaOptionUnsigned)) {
577       H245_ParameterValue::Choices tag;
578       switch (genericInfo.integerType) {
579         default :
580         case OpalMediaOption::H245GenericInfo::UnsignedInt :
581           tag = option.GetMerge() == OpalMediaOption::MinMerge ? H245_ParameterValue::e_unsignedMin : H245_ParameterValue::e_unsignedMax;
582           break;
583 
584         case OpalMediaOption::H245GenericInfo::Unsigned32 :
585           tag = option.GetMerge() == OpalMediaOption::MinMerge ? H245_ParameterValue::e_unsigned32Min : H245_ParameterValue::e_unsigned32Max;
586           break;
587 
588         case OpalMediaOption::H245GenericInfo::BooleanArray :
589           tag = H245_ParameterValue::e_booleanArray;
590           break;
591       }
592 
593       H323AddGenericParameterInteger(params, genericInfo.ordinal, ((const OpalMediaOptionUnsigned &)option).GetValue(), tag);
594     }
595     else if (PIsDescendant(&option, OpalMediaOptionOctets))
596       H323AddGenericParameterOctets(params, genericInfo.ordinal, ((const OpalMediaOptionOctets &)option).GetValue());
597     else
598       H323AddGenericParameterString(params, genericInfo.ordinal, option.AsString());
599   }
600 
601   if (pdu.m_collapsing.GetSize() > 0)
602     pdu.IncludeOptionalField(H245_GenericCapability::e_collapsing);
603 
604   if (pdu.m_nonCollapsing.GetSize() > 0)
605     pdu.IncludeOptionalField(H245_GenericCapability::e_nonCollapsing);
606 
607   return PTrue;
608 }
609 
OnReceivedGenericPDU(OpalMediaFormat & mediaFormat,const H245_GenericCapability & pdu,H323Capability::CommandType type)610 PBoolean H323GenericCapabilityInfo::OnReceivedGenericPDU(OpalMediaFormat & mediaFormat,
611                                                      const H245_GenericCapability & pdu,
612                                                      H323Capability::CommandType type)
613 {
614   if (H323GetCapabilityIdentifier(pdu.m_capabilityIdentifier) != m_identifier)
615     return false;
616 
617   if (pdu.HasOptionalField(H245_GenericCapability::e_maxBitRate)) {
618     maxBitRate = pdu.m_maxBitRate;
619     mediaFormat.SetOptionInteger(OpalMediaFormat::MaxBitRateOption(), maxBitRate*100);
620   }
621 
622   for (PINDEX i = 0; i < mediaFormat.GetOptionCount(); i++) {
623     const OpalMediaOption & option = mediaFormat.GetOption(i);
624     OpalMediaOption::H245GenericInfo genericInfo = option.GetH245Generic();
625     if (genericInfo.mode == OpalMediaOption::H245GenericInfo::None)
626       continue;
627     switch (type) {
628       case H323Capability::e_TCS :
629         if (genericInfo.excludeTCS)
630           continue;
631         break;
632       case H323Capability::e_OLC :
633         if (genericInfo.excludeOLC)
634           continue;
635         break;
636       case H323Capability::e_ReqMode :
637         if (genericInfo.excludeReqMode)
638           continue;
639         break;
640     }
641 
642     const H245_ParameterValue * param;
643     if (genericInfo.mode == OpalMediaOption::H245GenericInfo::Collapsing) {
644       if (!pdu.HasOptionalField(H245_GenericCapability::e_collapsing))
645         continue;
646       param = H323GetGenericParameter(pdu.m_collapsing, genericInfo.ordinal);
647     }
648     else {
649       if (!pdu.HasOptionalField(H245_GenericCapability::e_nonCollapsing))
650         continue;
651       param = H323GetGenericParameter(pdu.m_nonCollapsing, genericInfo.ordinal);
652     }
653 
654     if (PIsDescendant(&option, OpalMediaOptionBoolean))
655       ((OpalMediaOptionBoolean &)option).SetValue(false);
656 
657     if (param == NULL)
658       continue;
659 
660     if (PIsDescendant(&option, OpalMediaOptionBoolean)) {
661       if (param->GetTag() == H245_ParameterValue::e_logical) {
662         ((OpalMediaOptionBoolean &)option).SetValue(true);
663         continue;
664       }
665     }
666     else if (PIsDescendant(&option, OpalMediaOptionUnsigned)) {
667       unsigned tag;
668       switch (genericInfo.integerType) {
669         default :
670         case OpalMediaOption::H245GenericInfo::UnsignedInt :
671           tag = option.GetMerge() == OpalMediaOption::MinMerge ? H245_ParameterValue::e_unsignedMin : H245_ParameterValue::e_unsignedMax;
672           break;
673 
674         case OpalMediaOption::H245GenericInfo::Unsigned32 :
675           tag = option.GetMerge() == OpalMediaOption::MinMerge ? H245_ParameterValue::e_unsigned32Min : H245_ParameterValue::e_unsigned32Max;
676           break;
677 
678         case OpalMediaOption::H245GenericInfo::BooleanArray :
679           tag = H245_ParameterValue::e_booleanArray;
680           break;
681       }
682 
683       if (param->GetTag() == tag) {
684         ((OpalMediaOptionUnsigned &)option).SetValue((const PASN_Integer &)*param);
685         continue;
686       }
687     }
688     else {
689       if (param->GetTag() == H245_ParameterValue::e_octetString) {
690         const PASN_OctetString & octetString = *param;
691         if (PIsDescendant(&option, OpalMediaOptionOctets))
692           ((OpalMediaOptionOctets &)option).SetValue(octetString);
693         else
694           ((OpalMediaOption &)option).FromString(octetString.AsString());
695         continue;
696       }
697     }
698 
699     PTRACE(2, "H323\tInvalid generic parameter type (" << param->GetTagName()
700            << ") for option \"" << option.GetName() << "\" (" << option.GetClass() << ')');
701   }
702 
703   return PTrue;
704 }
705 
IsMatch(const H245_GenericCapability & param) const706 PBoolean H323GenericCapabilityInfo::IsMatch(const H245_GenericCapability & param) const
707 {
708   return H323GetCapabilityIdentifier(param.m_capabilityIdentifier) == m_identifier;
709 }
710 
CompareInfo(const H323GenericCapabilityInfo & obj) const711 PObject::Comparison H323GenericCapabilityInfo::CompareInfo(const H323GenericCapabilityInfo & obj) const
712 {
713   return m_identifier.Compare(obj.m_identifier);
714 }
715 
716 
717 /////////////////////////////////////////////////////////////////////////////
718 
H323AudioCapability()719 H323AudioCapability::H323AudioCapability()
720 {
721 }
722 
723 
GetMainType() const724 H323Capability::MainTypes H323AudioCapability::GetMainType() const
725 {
726   return e_Audio;
727 }
728 
729 
GetDefaultSessionID() const730 unsigned H323AudioCapability::GetDefaultSessionID() const
731 {
732   return DefaultAudioSessionID;
733 }
734 
735 
SetTxFramesInPacket(unsigned frames)736 void H323AudioCapability::SetTxFramesInPacket(unsigned frames)
737 {
738   GetWritableMediaFormat().SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), frames);
739 }
740 
741 
GetTxFramesInPacket() const742 unsigned H323AudioCapability::GetTxFramesInPacket() const
743 {
744   return GetMediaFormat().GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), 1);
745 }
746 
747 
GetRxFramesInPacket() const748 unsigned H323AudioCapability::GetRxFramesInPacket() const
749 {
750   return GetMediaFormat().GetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), 1);
751 }
752 
753 
OnSendingPDU(H245_Capability & cap) const754 PBoolean H323AudioCapability::OnSendingPDU(H245_Capability & cap) const
755 {
756   cap.SetTag(H245_Capability::e_receiveAudioCapability);
757   return OnSendingPDU((H245_AudioCapability &)cap, GetRxFramesInPacket(), e_TCS);
758 }
759 
760 
OnSendingPDU(H245_DataType & dataType) const761 PBoolean H323AudioCapability::OnSendingPDU(H245_DataType & dataType) const
762 {
763   dataType.SetTag(H245_DataType::e_audioData);
764   return H323Capability::OnSendingPDU(dataType) &&
765          OnSendingPDU((H245_AudioCapability &)dataType, GetTxFramesInPacket(), e_OLC);
766 }
767 
768 
OnSendingPDU(H245_ModeElement & mode) const769 PBoolean H323AudioCapability::OnSendingPDU(H245_ModeElement & mode) const
770 {
771   mode.m_type.SetTag(H245_ModeElementType::e_audioMode);
772   return OnSendingPDU((H245_AudioMode &)mode.m_type);
773 }
774 
775 
OnSendingPDU(H245_AudioCapability & pdu,unsigned packetSize) const776 PBoolean H323AudioCapability::OnSendingPDU(H245_AudioCapability & pdu,
777                                        unsigned packetSize) const
778 {
779   pdu.SetTag(GetSubType());
780 
781   // Set the maximum number of frames
782   PASN_Integer & value = pdu;
783   value = packetSize;
784   return PTrue;
785 }
786 
787 
OnSendingPDU(H245_AudioCapability & pdu,unsigned packetSize,CommandType) const788 PBoolean H323AudioCapability::OnSendingPDU(H245_AudioCapability & pdu,
789                                        unsigned packetSize,
790                                        CommandType) const
791 {
792   return OnSendingPDU(pdu, packetSize);
793 }
794 
795 
OnSendingPDU(H245_AudioMode & pdu) const796 PBoolean H323AudioCapability::OnSendingPDU(H245_AudioMode & pdu) const
797 {
798   static const H245_AudioMode::Choices AudioTable[] = {
799     H245_AudioMode::e_nonStandard,
800     H245_AudioMode::e_g711Alaw64k,
801     H245_AudioMode::e_g711Alaw56k,
802     H245_AudioMode::e_g711Ulaw64k,
803     H245_AudioMode::e_g711Ulaw56k,
804     H245_AudioMode::e_g722_64k,
805     H245_AudioMode::e_g722_56k,
806     H245_AudioMode::e_g722_48k,
807     H245_AudioMode::e_g7231,
808     H245_AudioMode::e_g728,
809     H245_AudioMode::e_g729,
810     H245_AudioMode::e_g729AnnexA,
811     H245_AudioMode::e_is11172AudioMode,
812     H245_AudioMode::e_is13818AudioMode,
813     H245_AudioMode::e_g729wAnnexB,
814     H245_AudioMode::e_g729AnnexAwAnnexB,
815     H245_AudioMode::e_g7231AnnexCMode,
816     H245_AudioMode::e_gsmFullRate,
817     H245_AudioMode::e_gsmHalfRate,
818     H245_AudioMode::e_gsmEnhancedFullRate,
819     H245_AudioMode::e_genericAudioMode,
820     H245_AudioMode::e_g729Extensions
821   };
822 
823   unsigned subType = GetSubType();
824   if (subType >= PARRAYSIZE(AudioTable))
825     return PFalse;
826 
827   pdu.SetTag(AudioTable[subType]);
828   return PTrue;
829 }
830 
831 
OnReceivedPDU(const H245_Capability & cap)832 PBoolean H323AudioCapability::OnReceivedPDU(const H245_Capability & cap)
833 {
834   if (cap.GetTag() != H245_Capability::e_receiveAudioCapability &&
835       cap.GetTag() != H245_Capability::e_receiveAndTransmitAudioCapability)
836     return PFalse;
837 
838   unsigned txFramesInPacket = GetTxFramesInPacket();
839   unsigned packetSize = GetRxFramesInPacket();
840   if (!OnReceivedPDU((const H245_AudioCapability &)cap, packetSize, e_TCS))
841     return PFalse;
842 
843   // Clamp our transmit size to maximum allowed
844   if (txFramesInPacket > packetSize) {
845     PTRACE(4, "H323\tCapability tx frames reduced from "
846            << txFramesInPacket << " to " << packetSize);
847     SetTxFramesInPacket(packetSize);
848   }
849   else {
850     PTRACE(4, "H323\tCapability tx frames left at "
851            << txFramesInPacket << " as remote allows " << packetSize);
852   }
853 
854   return H323Capability::OnReceivedPDU(cap);
855 }
856 
857 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)858 PBoolean H323AudioCapability::OnReceivedPDU(const H245_DataType & dataType, PBoolean receiver)
859 {
860   if (dataType.GetTag() != H245_DataType::e_audioData)
861     return PFalse;
862 
863   unsigned xFramesInPacket = receiver ? GetRxFramesInPacket() : GetTxFramesInPacket();
864   unsigned packetSize = xFramesInPacket;
865   if (!OnReceivedPDU((const H245_AudioCapability &)dataType, packetSize, e_OLC))
866     return PFalse;
867 
868   // Clamp our transmit size to maximum allowed
869   if (xFramesInPacket > packetSize) {
870     PTRACE(4, "H323\tCapability " << (receiver ? 'r' : 't') << "x frames reduced from "
871            << xFramesInPacket << " to " << packetSize);
872     if (!receiver)
873       SetTxFramesInPacket(packetSize);
874   }
875   else {
876     PTRACE(4, "H323\tCapability " << (receiver ? 'r' : 't') << "x frames left at "
877            << xFramesInPacket << " as remote allows " << packetSize);
878   }
879 
880   return H323Capability::OnReceivedPDU(dataType, receiver);
881 }
882 
883 
OnReceivedPDU(const H245_AudioCapability & pdu,unsigned & packetSize)884 PBoolean H323AudioCapability::OnReceivedPDU(const H245_AudioCapability & pdu,
885                                         unsigned & packetSize)
886 {
887   if (pdu.GetTag() != GetSubType())
888     return PFalse;
889 
890   const PASN_Integer & value = pdu;
891 
892   // Get the maximum number of frames
893   packetSize = value;
894   return PTrue;
895 }
896 
897 
OnReceivedPDU(const H245_AudioCapability & pdu,unsigned & packetSize,CommandType)898 PBoolean H323AudioCapability::OnReceivedPDU(const H245_AudioCapability & pdu,
899                                         unsigned & packetSize,
900                                         CommandType)
901 {
902   return OnReceivedPDU(pdu, packetSize);
903 }
904 
905 
906 /////////////////////////////////////////////////////////////////////////////
907 
H323GenericAudioCapability(const PString & standardId,PINDEX maxBitRate)908 H323GenericAudioCapability::H323GenericAudioCapability(const PString &standardId, PINDEX maxBitRate)
909   : H323AudioCapability(),
910     H323GenericCapabilityInfo(standardId, maxBitRate)
911 {
912 }
913 
Compare(const PObject & obj) const914 PObject::Comparison H323GenericAudioCapability::Compare(const PObject & obj) const
915 {
916   if (!PIsDescendant(&obj, H323GenericAudioCapability))
917     return LessThan;
918 
919   return CompareInfo((const H323GenericAudioCapability &)obj);
920 }
921 
922 
GetSubType() const923 unsigned H323GenericAudioCapability::GetSubType() const
924 {
925   return H245_AudioCapability::e_genericAudioCapability;
926 }
927 
928 
OnSendingPDU(H245_AudioCapability & pdu,unsigned,CommandType type) const929 PBoolean H323GenericAudioCapability::OnSendingPDU(H245_AudioCapability & pdu, unsigned, CommandType type) const
930 {
931   pdu.SetTag(H245_AudioCapability::e_genericAudioCapability);
932   return OnSendingGenericPDU(pdu, GetMediaFormat(), type);
933 }
934 
OnSendingPDU(H245_AudioMode & pdu) const935 PBoolean H323GenericAudioCapability::OnSendingPDU(H245_AudioMode & pdu) const
936 {
937   pdu.SetTag(H245_VideoMode::e_genericVideoMode);
938   return OnSendingGenericPDU(pdu, GetMediaFormat(), e_ReqMode);
939 }
940 
OnReceivedPDU(const H245_AudioCapability & pdu,unsigned & packetSize,CommandType type)941 PBoolean H323GenericAudioCapability::OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize, CommandType type)
942 {
943   if( pdu.GetTag() != H245_AudioCapability::e_genericAudioCapability)
944     return PFalse;
945   if (!OnReceivedGenericPDU(GetWritableMediaFormat(), pdu, type))
946     return PFalse;
947 
948   packetSize = GetRxFramesInPacket();
949   return PTrue;
950 }
951 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const952 PBoolean H323GenericAudioCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
953 {
954   return H323Capability::IsMatch(subTypePDU, mediaPacketization) &&
955          H323GenericCapabilityInfo::IsMatch((const H245_GenericCapability &)subTypePDU.GetObject());
956 }
957 
958 
959 /////////////////////////////////////////////////////////////////////////////
960 
H323NonStandardAudioCapability(H323NonStandardCapabilityInfo::CompareFuncType compareFunc,const BYTE * fixedData,PINDEX dataSize)961 H323NonStandardAudioCapability::H323NonStandardAudioCapability(
962       H323NonStandardCapabilityInfo::CompareFuncType compareFunc,
963       const BYTE * fixedData,
964       PINDEX dataSize)
965   : H323AudioCapability(),
966     H323NonStandardCapabilityInfo(compareFunc, fixedData, dataSize)
967 {
968 }
969 
H323NonStandardAudioCapability(const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)970 H323NonStandardAudioCapability::H323NonStandardAudioCapability(const BYTE * fixedData,
971                                                                      PINDEX dataSize,
972                                                                      PINDEX offset,
973                                                                      PINDEX length)
974   : H323AudioCapability(),
975     H323NonStandardCapabilityInfo(fixedData, dataSize, offset, length)
976 {
977 }
978 
H323NonStandardAudioCapability(const PString & oid,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)979 H323NonStandardAudioCapability::H323NonStandardAudioCapability(const PString & oid,
980                                                                  const BYTE * fixedData,
981                                                                        PINDEX dataSize,
982                                                                        PINDEX offset,
983                                                                       PINDEX length)
984   : H323AudioCapability(),
985     H323NonStandardCapabilityInfo(oid, fixedData, dataSize, offset, length)
986 {
987 }
988 
H323NonStandardAudioCapability(BYTE country,BYTE extension,WORD maufacturer,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)989 H323NonStandardAudioCapability::H323NonStandardAudioCapability(BYTE country,
990                                                                BYTE extension,
991                                                                WORD maufacturer,
992                                                        const BYTE * fixedData,
993                                                              PINDEX dataSize,
994                                                              PINDEX offset,
995                                                              PINDEX length)
996   : H323AudioCapability(),
997     H323NonStandardCapabilityInfo(country, extension, maufacturer, fixedData, dataSize, offset, length)
998 {
999 }
1000 
1001 
Compare(const PObject & obj) const1002 PObject::Comparison H323NonStandardAudioCapability::Compare(const PObject & obj) const
1003 {
1004   if (!PIsDescendant(&obj, H323NonStandardAudioCapability))
1005     return PObject::LessThan;
1006 
1007   return CompareInfo((const H323NonStandardAudioCapability &)obj);
1008 }
1009 
1010 
GetSubType() const1011 unsigned H323NonStandardAudioCapability::GetSubType() const
1012 {
1013   return H245_AudioCapability::e_nonStandard;
1014 }
1015 
1016 
OnSendingPDU(H245_AudioCapability & pdu,unsigned) const1017 PBoolean H323NonStandardAudioCapability::OnSendingPDU(H245_AudioCapability & pdu,
1018                                                   unsigned) const
1019 {
1020   return OnSendingNonStandardPDU(pdu, H245_AudioCapability::e_nonStandard);
1021 }
1022 
1023 
OnSendingPDU(H245_AudioMode & pdu) const1024 PBoolean H323NonStandardAudioCapability::OnSendingPDU(H245_AudioMode & pdu) const
1025 {
1026   return OnSendingNonStandardPDU(pdu, H245_AudioMode::e_nonStandard);
1027 }
1028 
1029 
OnReceivedPDU(const H245_AudioCapability & pdu,unsigned &)1030 PBoolean H323NonStandardAudioCapability::OnReceivedPDU(const H245_AudioCapability & pdu,
1031                                                    unsigned &)
1032 {
1033   return OnReceivedNonStandardPDU(pdu, H245_AudioCapability::e_nonStandard);
1034 }
1035 
1036 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const1037 PBoolean H323NonStandardAudioCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
1038 {
1039   return H323Capability::IsMatch(subTypePDU, mediaPacketization) &&
1040          H323NonStandardCapabilityInfo::IsMatch((const H245_NonStandardParameter &)subTypePDU.GetObject());
1041 }
1042 
1043 
1044 /////////////////////////////////////////////////////////////////////////////
1045 
1046 #if OPAL_VIDEO
1047 
GetMainType() const1048 H323Capability::MainTypes H323VideoCapability::GetMainType() const
1049 {
1050   return e_Video;
1051 }
1052 
1053 
OnSendingPDU(H245_Capability & cap) const1054 PBoolean H323VideoCapability::OnSendingPDU(H245_Capability & cap) const
1055 {
1056   cap.SetTag(H245_Capability::e_receiveVideoCapability);
1057   return OnSendingPDU((H245_VideoCapability &)cap, e_TCS);
1058 }
1059 
1060 
OnSendingPDU(H245_DataType & dataType) const1061 PBoolean H323VideoCapability::OnSendingPDU(H245_DataType & dataType) const
1062 {
1063   dataType.SetTag(H245_DataType::e_videoData);
1064   return H323Capability::OnSendingPDU(dataType) &&
1065          OnSendingPDU((H245_VideoCapability &)dataType, e_OLC);
1066 }
1067 
1068 
OnSendingPDU(H245_VideoCapability &) const1069 PBoolean H323VideoCapability::OnSendingPDU(H245_VideoCapability & /*pdu*/) const
1070 {
1071   return PFalse;
1072 }
1073 
1074 
OnSendingPDU(H245_VideoCapability & pdu,CommandType type) const1075 PBoolean H323VideoCapability::OnSendingPDU(H245_VideoCapability & pdu, CommandType type) const
1076 {
1077 #if OPAL_H239
1078   PINDEX role = 0;
1079   if (type != e_OLC || (role = GetMediaFormat().GetOptionEnum(OpalVideoFormat::ContentRoleOption())) == 0)
1080     return OnSendingPDU(pdu);
1081 
1082   H323H239VideoCapability h239(GetMediaFormat());
1083   return h239.OnSendingPDU(pdu, type);
1084 #else
1085   return OnSendingPDU(pdu);
1086 #endif
1087 }
1088 
1089 
OnSendingPDU(H245_ModeElement & mode) const1090 PBoolean H323VideoCapability::OnSendingPDU(H245_ModeElement & mode) const
1091 {
1092   mode.m_type.SetTag(H245_ModeElementType::e_videoMode);
1093   return OnSendingPDU((H245_VideoMode &)mode.m_type);
1094 }
1095 
1096 
OnReceivedPDU(const H245_Capability & cap)1097 PBoolean H323VideoCapability::OnReceivedPDU(const H245_Capability & cap)
1098 {
1099   if (cap.GetTag() != H245_Capability::e_receiveVideoCapability &&
1100       cap.GetTag() != H245_Capability::e_receiveAndTransmitVideoCapability)
1101     return PFalse;
1102 
1103   return OnReceivedPDU((const H245_VideoCapability &)cap, e_TCS) && H323Capability::OnReceivedPDU(cap);
1104 }
1105 
1106 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)1107 PBoolean H323VideoCapability::OnReceivedPDU(const H245_DataType & dataType, PBoolean receiver)
1108 {
1109   if (dataType.GetTag() != H245_DataType::e_videoData) {
1110     PTRACE(5, "H323\tdataType.GetTag() " << dataType.GetTag() << " != H245_DataType::e_videoData");
1111     return PFalse;
1112   }
1113 
1114   return OnReceivedPDU((const H245_VideoCapability &)dataType, e_OLC) &&
1115          H323Capability::OnReceivedPDU(dataType, receiver);
1116 }
1117 
1118 
OnReceivedPDU(const H245_VideoCapability &)1119 PBoolean H323VideoCapability::OnReceivedPDU(const H245_VideoCapability &)
1120 {
1121   return PFalse;
1122 }
1123 
1124 
OnReceivedPDU(const H245_VideoCapability & pdu,CommandType)1125 PBoolean H323VideoCapability::OnReceivedPDU(const H245_VideoCapability & pdu, CommandType)
1126 {
1127   return OnReceivedPDU(pdu);
1128 }
1129 
1130 
GetDefaultSessionID() const1131 unsigned H323VideoCapability::GetDefaultSessionID() const
1132 {
1133   return DefaultVideoSessionID;
1134 }
1135 
1136 
1137 /////////////////////////////////////////////////////////////////////////////
1138 
H323NonStandardVideoCapability(H323NonStandardCapabilityInfo::CompareFuncType compareFunc,const BYTE * fixedData,PINDEX dataSize)1139 H323NonStandardVideoCapability::H323NonStandardVideoCapability(
1140       H323NonStandardCapabilityInfo::CompareFuncType compareFunc,
1141       const BYTE * fixedData,
1142       PINDEX dataSize)
1143   : H323VideoCapability(),
1144     H323NonStandardCapabilityInfo(compareFunc, fixedData, dataSize)
1145 {
1146 }
1147 
H323NonStandardVideoCapability(const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1148 H323NonStandardVideoCapability::H323NonStandardVideoCapability(const BYTE * fixedData,
1149                                                                PINDEX dataSize,
1150                                                                PINDEX offset,
1151                                                                PINDEX length)
1152   : H323NonStandardCapabilityInfo(fixedData, dataSize, offset, length)
1153 {
1154 }
1155 
1156 
H323NonStandardVideoCapability(const PString & oid,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1157 H323NonStandardVideoCapability::H323NonStandardVideoCapability(const PString & oid,
1158                                                                const BYTE * fixedData,
1159                                                                PINDEX dataSize,
1160                                                                PINDEX offset,
1161                                                                PINDEX length)
1162   : H323NonStandardCapabilityInfo(oid, fixedData, dataSize, offset, length)
1163 {
1164 }
1165 
1166 
H323NonStandardVideoCapability(BYTE country,BYTE extension,WORD maufacturer,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1167 H323NonStandardVideoCapability::H323NonStandardVideoCapability(BYTE country,
1168                                                                BYTE extension,
1169                                                                WORD maufacturer,
1170                                                                const BYTE * fixedData,
1171                                                                PINDEX dataSize,
1172                                                                PINDEX offset,
1173                                                                PINDEX length)
1174   : H323NonStandardCapabilityInfo(country, extension, maufacturer, fixedData, dataSize, offset, length)
1175 {
1176 }
1177 
1178 
Compare(const PObject & obj) const1179 PObject::Comparison H323NonStandardVideoCapability::Compare(const PObject & obj) const
1180 {
1181   if (!PIsDescendant(&obj, H323NonStandardVideoCapability))
1182     return PObject::LessThan;
1183 
1184   return CompareInfo((const H323NonStandardVideoCapability &)obj);
1185 }
1186 
1187 
GetSubType() const1188 unsigned H323NonStandardVideoCapability::GetSubType() const
1189 {
1190   return H245_VideoCapability::e_nonStandard;
1191 }
1192 
1193 
OnSendingPDU(H245_VideoCapability & pdu) const1194 PBoolean H323NonStandardVideoCapability::OnSendingPDU(H245_VideoCapability & pdu) const
1195 {
1196   return OnSendingNonStandardPDU(pdu, H245_VideoCapability::e_nonStandard);
1197 }
1198 
1199 
OnSendingPDU(H245_VideoMode & pdu) const1200 PBoolean H323NonStandardVideoCapability::OnSendingPDU(H245_VideoMode & pdu) const
1201 {
1202   return OnSendingNonStandardPDU(pdu, H245_VideoMode::e_nonStandard);
1203 }
1204 
1205 
OnReceivedPDU(const H245_VideoCapability & pdu)1206 PBoolean H323NonStandardVideoCapability::OnReceivedPDU(const H245_VideoCapability & pdu)
1207 {
1208   return OnReceivedNonStandardPDU(pdu, H245_VideoCapability::e_nonStandard);
1209 }
1210 
1211 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const1212 PBoolean H323NonStandardVideoCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
1213 {
1214   return H323Capability::IsMatch(subTypePDU, mediaPacketization) &&
1215          H323NonStandardCapabilityInfo::IsMatch((const H245_NonStandardParameter &)subTypePDU.GetObject());
1216 }
1217 
1218 /////////////////////////////////////////////////////////////////////////////
1219 
H323GenericVideoCapability(const PString & standardId,PINDEX maxBitRate)1220 H323GenericVideoCapability::H323GenericVideoCapability(const PString &standardId, PINDEX maxBitRate)
1221   : H323VideoCapability(),
1222     H323GenericCapabilityInfo(standardId, maxBitRate)
1223 {
1224 }
1225 
Compare(const PObject & obj) const1226 PObject::Comparison H323GenericVideoCapability::Compare(const PObject & obj) const
1227 {
1228   if (!PIsDescendant(&obj, H323GenericVideoCapability))
1229     return LessThan;
1230 
1231   return CompareInfo((const H323GenericVideoCapability &)obj);
1232 }
1233 
1234 
GetSubType() const1235 unsigned H323GenericVideoCapability::GetSubType() const
1236 {
1237   return H245_VideoCapability::e_genericVideoCapability;
1238 }
1239 
1240 
OnSendingPDU(H245_VideoCapability & pdu,CommandType type) const1241 PBoolean H323GenericVideoCapability::OnSendingPDU(H245_VideoCapability & pdu, CommandType type) const
1242 {
1243   pdu.SetTag(H245_VideoCapability::e_genericVideoCapability);
1244   return OnSendingGenericPDU(pdu, GetMediaFormat(), type);
1245 }
1246 
OnSendingPDU(H245_VideoMode & pdu) const1247 PBoolean H323GenericVideoCapability::OnSendingPDU(H245_VideoMode & pdu) const
1248 {
1249   pdu.SetTag(H245_VideoMode::e_genericVideoMode);
1250   return OnSendingGenericPDU(pdu, GetMediaFormat(), e_ReqMode);
1251 }
1252 
OnReceivedPDU(const H245_VideoCapability & pdu,CommandType type)1253 PBoolean H323GenericVideoCapability::OnReceivedPDU(const H245_VideoCapability & pdu, CommandType type)
1254 {
1255   if (pdu.GetTag() != H245_VideoCapability::e_genericVideoCapability)
1256     return PFalse;
1257   return OnReceivedGenericPDU(GetWritableMediaFormat(), pdu, type);
1258 }
1259 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const1260 PBoolean H323GenericVideoCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
1261 {
1262   return H323Capability::IsMatch(subTypePDU, mediaPacketization) &&
1263          H323GenericCapabilityInfo::IsMatch((const H245_GenericCapability &)subTypePDU.GetObject());
1264 }
1265 
1266 
1267 /////////////////////////////////////////////////////////////////////////////
1268 
1269 #if OPAL_H239
1270 
H323ExtendedVideoCapability(const PString & identifier)1271 H323ExtendedVideoCapability::H323ExtendedVideoCapability(const PString & identifier)
1272   : H323GenericVideoCapability(identifier)
1273 {
1274 }
1275 
1276 
GetSubType() const1277 unsigned H323ExtendedVideoCapability::GetSubType() const
1278 {
1279   return H245_VideoCapability::e_extendedVideoCapability;
1280 }
1281 
1282 
OnSendingPDU(H245_VideoCapability & pdu,CommandType type) const1283 PBoolean H323ExtendedVideoCapability::OnSendingPDU(H245_VideoCapability & pdu, CommandType type) const
1284 {
1285   pdu.SetTag(H245_VideoCapability::e_extendedVideoCapability);
1286   H245_ExtendedVideoCapability & extcap = pdu;
1287 
1288   unsigned roleMask = UINT_MAX;
1289 
1290   for (OpalMediaFormatList::const_iterator videoFormat = m_videoFormats.begin(); videoFormat != m_videoFormats.end(); ++videoFormat) {
1291     if (videoFormat->GetMediaType() == OpalMediaType::Video()) {
1292       H323Capability * capability = H323Capability::Create(videoFormat->GetName());
1293       if (capability != NULL) {
1294         capability->UpdateMediaFormat(*videoFormat);
1295         H245_Capability h245Cap;
1296         if (capability->OnSendingPDU(h245Cap)) {
1297           PINDEX size = extcap.m_videoCapability.GetSize();
1298           extcap.m_videoCapability.SetSize(size+1);
1299           extcap.m_videoCapability[size] = h245Cap;
1300           roleMask &= videoFormat->GetOptionInteger(OpalVideoFormat::ContentRoleMaskOption());
1301         }
1302         delete capability;
1303       }
1304     }
1305   }
1306   if (extcap.m_videoCapability.GetSize() == 0) {
1307     PTRACE(2, "H323\tCannot encode H.239 video capability, no extended video codecs available");
1308     return false;
1309   }
1310 
1311   OpalMediaFormat videoCapExtMediaFormat(GetFormatName());
1312   if ((roleMask&0xfffc) != 0)
1313     roleMask = (roleMask&3)|2;
1314   videoCapExtMediaFormat.SetOptionInteger(OpalVideoFormat::ContentRoleMaskOption(), roleMask);
1315 
1316   extcap.IncludeOptionalField(H245_ExtendedVideoCapability::e_videoCapabilityExtension);
1317   extcap.m_videoCapabilityExtension.SetSize(1);
1318   return OnSendingGenericPDU(extcap.m_videoCapabilityExtension[0], OpalMediaFormat(GetFormatName()), type);
1319 }
1320 
1321 
OnSendingPDU(H245_VideoMode &) const1322 PBoolean H323ExtendedVideoCapability::OnSendingPDU(H245_VideoMode &) const
1323 {
1324   return false;
1325 }
1326 
1327 
OnReceivedPDU(const H245_VideoCapability & pdu,CommandType type)1328 PBoolean H323ExtendedVideoCapability::OnReceivedPDU(const H245_VideoCapability & pdu, CommandType type)
1329 {
1330   if (pdu.GetTag() != H245_VideoCapability::e_extendedVideoCapability)
1331     return false;
1332 
1333   const H245_ExtendedVideoCapability & extcap = pdu;
1334   if (!extcap.HasOptionalField(H245_ExtendedVideoCapability::e_videoCapabilityExtension)) {
1335     PTRACE(2, "H323\tNo H.239 video capability extension");
1336     return false;
1337   }
1338 
1339   PINDEX i = 0;
1340   for (;;) {
1341     if (i >= extcap.m_videoCapabilityExtension.GetSize()) {
1342       PTRACE(2, "H323\tNo H.239 video capability extension for " << m_identifier);
1343       return false;
1344     }
1345 
1346     if (H323GenericCapabilityInfo::IsMatch(extcap.m_videoCapabilityExtension[i]))
1347       break;
1348 
1349     ++i;
1350   }
1351 
1352   OpalMediaFormat videoCapExtMediaFormat(GetFormatName());
1353   if (!OnReceivedGenericPDU(videoCapExtMediaFormat, extcap.m_videoCapabilityExtension[i], type))
1354     return false;
1355 
1356   unsigned roleMask = videoCapExtMediaFormat.GetOptionInteger(OpalVideoFormat::ContentRoleMaskOption());
1357 
1358   H323Capabilities allVideoCapabilities;
1359   H323CapabilityFactory::KeyList_T stdCaps = H323CapabilityFactory::GetKeyList();
1360 
1361   for (H323CapabilityFactory::KeyList_T::const_iterator iterCap = stdCaps.begin(); iterCap != stdCaps.end(); ++iterCap) {
1362     H323Capability * capability = H323Capability::Create(*iterCap);
1363     if (capability->GetMainType() == H323Capability::e_Video)
1364       allVideoCapabilities.Add(capability);
1365     else
1366       delete capability;
1367   }
1368 
1369   m_videoFormats.RemoveAll();
1370 
1371   for (i = 0; i < extcap.m_videoCapability.GetSize(); ++i) {
1372     const H245_VideoCapability & vidCap = extcap.m_videoCapability[i];
1373     for (PINDEX c = 0; c < allVideoCapabilities.GetSize(); c++) {
1374       H323VideoCapability & capability = (H323VideoCapability &)allVideoCapabilities[c];
1375       if (capability.IsMatch(vidCap, PString::Empty()) && capability.OnReceivedPDU(vidCap, type)) {
1376         OpalMediaFormat mediaFormat = capability.GetMediaFormat();
1377         mediaFormat.SetOptionInteger(OpalVideoFormat::ContentRoleMaskOption(), roleMask);
1378         mediaFormat.SetOptionString(OpalMediaFormat::ProtocolOption(), PLUGINCODEC_OPTION_PROTOCOL_H323);
1379         if (mediaFormat.ToNormalisedOptions())
1380           m_videoFormats += mediaFormat;
1381       }
1382     }
1383   }
1384 
1385   PTRACE(4, "H323\tExtended video: " << setfill(',') << m_videoFormats);
1386   return !m_videoFormats.IsEmpty();
1387 }
1388 
1389 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const1390 PBoolean H323ExtendedVideoCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
1391 {
1392   if (!H323Capability::IsMatch(subTypePDU, mediaPacketization))
1393     return false;
1394 
1395   const H245_ExtendedVideoCapability & extcap = (const H245_ExtendedVideoCapability &)subTypePDU.GetObject();
1396   if (!extcap.HasOptionalField(H245_ExtendedVideoCapability::e_videoCapabilityExtension))
1397     return false;
1398 
1399   for (PINDEX i = 0; i < extcap.m_videoCapabilityExtension.GetSize(); ++i) {
1400     if (H323GenericCapabilityInfo::IsMatch(extcap.m_videoCapabilityExtension[i]))
1401       return true;
1402   }
1403 
1404   return false;
1405 }
1406 
1407 
1408 /////////////////////////////////////////////////////////////////////////////
1409 
H323GenericControlCapability(const PString & identifier)1410 H323GenericControlCapability::H323GenericControlCapability(const PString & identifier)
1411   : H323GenericCapabilityInfo(identifier)
1412 {
1413 }
1414 
1415 
GetMainType() const1416 H323Capability::MainTypes H323GenericControlCapability::GetMainType() const
1417 {
1418   return e_GenericControl;
1419 }
1420 
1421 
GetSubType() const1422 unsigned H323GenericControlCapability::GetSubType() const
1423 {
1424   return 0; // Unused
1425 }
1426 
1427 
OnSendingPDU(H245_Capability & pdu) const1428 PBoolean H323GenericControlCapability::OnSendingPDU(H245_Capability & pdu) const
1429 {
1430   pdu.SetTag(H245_Capability::e_genericControlCapability);
1431   return OnSendingGenericPDU(pdu, GetMediaFormat(), e_OLC);
1432 }
1433 
1434 
OnSendingPDU(H245_ModeElement &) const1435 PBoolean H323GenericControlCapability::OnSendingPDU(H245_ModeElement &) const
1436 {
1437   PTRACE(1, "H323\tCannot create GenericControlCapability mode");
1438   return false; // Can't be in mode request.
1439 }
1440 
1441 
OnReceivedPDU(const H245_Capability & pdu)1442 PBoolean H323GenericControlCapability::OnReceivedPDU(const H245_Capability & pdu)
1443 {
1444   if (pdu.GetTag() != H245_Capability::e_genericControlCapability)
1445     return false;
1446   return OnReceivedGenericPDU(GetWritableMediaFormat(), pdu, e_OLC);
1447 }
1448 
1449 
IsMatch(const PASN_Choice & subTypePDU,const PString &) const1450 PBoolean H323GenericControlCapability::IsMatch(const PASN_Choice & subTypePDU, const PString &) const
1451 {
1452   return H323GenericCapabilityInfo::IsMatch((const H245_GenericCapability &)subTypePDU.GetObject());
1453 }
1454 
1455 
CreateChannel(H323Connection &,H323Channel::Directions,unsigned,const H245_H2250LogicalChannelParameters *) const1456 H323Channel * H323GenericControlCapability::CreateChannel(H323Connection &,
1457                                                           H323Channel::Directions,
1458                                                           unsigned,
1459                                                           const H245_H2250LogicalChannelParameters *) const
1460 {
1461   PTRACE(1, "H323\tCannot create GenericControlCapability channel");
1462   return NULL;
1463 }
1464 
1465 
1466 /////////////////////////////////////////////////////////////////////////////
1467 
1468 const char H239MediaType[] = "H.239";
1469 
1470 class OpalH239MediaType : public OpalMediaTypeDefinition
1471 {
1472   public:
OpalH239MediaType()1473     OpalH239MediaType()
1474       : OpalMediaTypeDefinition(H239MediaType, NULL)
1475     { }
GetRTPEncoding() const1476     virtual PString GetRTPEncoding() const { return PString::Empty(); }
1477 #if OPAL_SIP
CreateSDPMediaDescription(const OpalTransportAddress &)1478     virtual SDPMediaDescription * CreateSDPMediaDescription(const OpalTransportAddress &) { return NULL; }
1479 #endif
1480 };
1481 
1482 OPAL_INSTANTIATE_MEDIATYPE2(H239, H239MediaType, OpalH239MediaType);
1483 
1484 
1485 
H323H239VideoCapability(const OpalMediaFormat & mediaFormat)1486 H323H239VideoCapability::H323H239VideoCapability(const OpalMediaFormat & mediaFormat)
1487   : H323ExtendedVideoCapability("0.0.8.239.1.2")
1488 {
1489   GetWritableMediaFormat() = mediaFormat;
1490 }
1491 
1492 
Compare(const PObject & obj) const1493 PObject::Comparison H323H239VideoCapability::Compare(const PObject & obj) const
1494 {
1495   Comparison comparison = H323ExtendedVideoCapability::Compare(obj);
1496   if (comparison != EqualTo)
1497     return comparison;
1498 
1499   return GetMediaFormat().Compare(((H323Capability &)obj).GetMediaFormat());
1500 }
1501 
1502 
Clone() const1503 PObject * H323H239VideoCapability::Clone() const
1504 {
1505   return new H323H239VideoCapability(*this);
1506 }
1507 
1508 
PrintOn(ostream & strm) const1509 void H323H239VideoCapability::PrintOn(ostream & strm) const
1510 {
1511   strm << GetMediaFormat() << '+';
1512   H323ExtendedVideoCapability::PrintOn(strm);
1513 }
1514 
1515 
GetFormatName() const1516 PString H323H239VideoCapability::GetFormatName() const
1517 {
1518   static class H239VideoMediaFormat : public OpalMediaFormat {
1519     public:
1520       H239VideoMediaFormat()
1521         : OpalMediaFormat("H.239-Video", H239MediaType, RTP_DataFrame::MaxPayloadType, NULL, false, 0, 0, 0, 0)
1522       {
1523         OpalMediaOption * option = new OpalMediaOptionUnsigned(OpalVideoFormat::ContentRoleMaskOption(),
1524                                                                true, OpalMediaOption::IntersectionMerge, 1, 1, 3);
1525 
1526         OpalMediaOption::H245GenericInfo genericInfo;
1527         genericInfo.ordinal = 1;
1528         genericInfo.mode = OpalMediaOption::H245GenericInfo::Collapsing;
1529         genericInfo.integerType = OpalMediaOption::H245GenericInfo::BooleanArray;
1530         genericInfo.excludeTCS = false;
1531         genericInfo.excludeOLC = false;
1532         genericInfo.excludeReqMode = true;
1533         option->SetH245Generic(genericInfo);
1534 
1535         AddOption(option);
1536       }
1537   } const name;
1538   return name;
1539 }
1540 
1541 
OnSendingPDU(H245_VideoCapability & pdu,CommandType type) const1542 PBoolean H323H239VideoCapability::OnSendingPDU(H245_VideoCapability & pdu, CommandType type) const
1543 {
1544   const_cast<H323H239VideoCapability*>(this)->m_videoFormats += GetMediaFormat();
1545   return H323ExtendedVideoCapability::OnSendingPDU(pdu, type);
1546 }
1547 
1548 
OnReceivedPDU(const H245_VideoCapability & pdu,CommandType type)1549 PBoolean H323H239VideoCapability::OnReceivedPDU(const H245_VideoCapability & pdu, CommandType type)
1550 {
1551   if (!H323ExtendedVideoCapability::OnReceivedPDU(pdu, type))
1552     return false;
1553 
1554   GetWritableMediaFormat() = m_videoFormats[0];
1555   return true;
1556 }
1557 
1558 
1559 /////////////////////////////////////////////////////////////////////////////
1560 
H323H239ControlCapability()1561 H323H239ControlCapability::H323H239ControlCapability()
1562   : H323GenericControlCapability("0.0.8.239.1.1")
1563 {
1564 }
1565 
1566 
Clone() const1567 PObject * H323H239ControlCapability::Clone() const
1568 {
1569   return new H323H239ControlCapability(*this);
1570 }
1571 
1572 
GetFormatName() const1573 PString H323H239ControlCapability::GetFormatName() const
1574 {
1575   static const OpalMediaFormat name("H.239-Control", H239MediaType, RTP_DataFrame::MaxPayloadType, NULL, false, 0, 0, 0, 0);
1576   return name;
1577 }
1578 
1579 
1580 #endif  // OPAL_H239
1581 
1582 #endif // OPAL_VIDEO
1583 
1584 /////////////////////////////////////////////////////////////////////////////
1585 
H323DataCapability(unsigned rate)1586 H323DataCapability::H323DataCapability(unsigned rate)
1587   : maxBitRate(rate)
1588 {
1589 }
1590 
1591 
GetMainType() const1592 H323Capability::MainTypes H323DataCapability::GetMainType() const
1593 {
1594   return e_Data;
1595 }
1596 
1597 
GetDefaultSessionID() const1598 unsigned H323DataCapability::GetDefaultSessionID() const
1599 {
1600   return 3;
1601 }
1602 
1603 
OnSendingPDU(H245_Capability & cap) const1604 PBoolean H323DataCapability::OnSendingPDU(H245_Capability & cap) const
1605 {
1606   cap.SetTag(H245_Capability::e_receiveAndTransmitDataApplicationCapability);
1607   H245_DataApplicationCapability & app = cap;
1608   app.m_maxBitRate = maxBitRate;
1609   return OnSendingPDU(app, e_TCS);
1610 }
1611 
1612 
OnSendingPDU(H245_DataType & dataType) const1613 PBoolean H323DataCapability::OnSendingPDU(H245_DataType & dataType) const
1614 {
1615   dataType.SetTag(H245_DataType::e_data);
1616   H245_DataApplicationCapability & app = dataType;
1617   app.m_maxBitRate = maxBitRate;
1618   return H323Capability::OnSendingPDU(dataType) &&
1619          OnSendingPDU(app, e_OLC);
1620 }
1621 
1622 
OnSendingPDU(H245_DataApplicationCapability &) const1623 PBoolean H323DataCapability::OnSendingPDU(H245_DataApplicationCapability &) const
1624 {
1625   return PFalse;
1626 }
1627 
1628 
OnSendingPDU(H245_DataApplicationCapability & pdu,CommandType) const1629 PBoolean H323DataCapability::OnSendingPDU(H245_DataApplicationCapability & pdu, CommandType) const
1630 {
1631   return OnSendingPDU(pdu);
1632 }
1633 
1634 
OnSendingPDU(H245_ModeElement & mode) const1635 PBoolean H323DataCapability::OnSendingPDU(H245_ModeElement & mode) const
1636 {
1637   mode.m_type.SetTag(H245_ModeElementType::e_dataMode);
1638   H245_DataMode & type = mode.m_type;
1639   type.m_bitRate = maxBitRate;
1640   return OnSendingPDU(type);
1641 }
1642 
1643 
OnReceivedPDU(const H245_Capability & cap)1644 PBoolean H323DataCapability::OnReceivedPDU(const H245_Capability & cap)
1645 {
1646   if (cap.GetTag() != H245_Capability::e_receiveDataApplicationCapability &&
1647       cap.GetTag() != H245_Capability::e_receiveAndTransmitDataApplicationCapability)
1648     return PFalse;
1649 
1650   const H245_DataApplicationCapability & app = cap;
1651   maxBitRate = app.m_maxBitRate;
1652 
1653   return OnReceivedPDU(app, e_TCS) && H323Capability::OnReceivedPDU(cap);
1654 }
1655 
1656 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)1657 PBoolean H323DataCapability::OnReceivedPDU(const H245_DataType & dataType, PBoolean receiver)
1658 {
1659   if (dataType.GetTag() != H245_DataType::e_data)
1660     return PFalse;
1661 
1662   const H245_DataApplicationCapability & app = dataType;
1663   maxBitRate = app.m_maxBitRate;
1664   return OnReceivedPDU(app, e_OLC) && H323Capability::OnReceivedPDU(dataType, receiver);
1665 }
1666 
1667 
OnReceivedPDU(const H245_DataApplicationCapability &)1668 PBoolean H323DataCapability::OnReceivedPDU(const H245_DataApplicationCapability &)
1669 {
1670   return PFalse;
1671 }
1672 
1673 
OnReceivedPDU(const H245_DataApplicationCapability & pdu,CommandType)1674 PBoolean H323DataCapability::OnReceivedPDU(const H245_DataApplicationCapability & pdu, CommandType)
1675 {
1676   return OnReceivedPDU(pdu);
1677 }
1678 
1679 
1680 /////////////////////////////////////////////////////////////////////////////
1681 
H323NonStandardDataCapability(unsigned maxBitRate,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1682 H323NonStandardDataCapability::H323NonStandardDataCapability(unsigned maxBitRate,
1683                                                          const BYTE * fixedData,
1684                                                              PINDEX dataSize,
1685                                                              PINDEX offset,
1686                                                              PINDEX length)
1687   : H323DataCapability(maxBitRate),
1688     H323NonStandardCapabilityInfo(fixedData, dataSize, offset, length)
1689 {
1690 }
1691 
1692 
H323NonStandardDataCapability(unsigned maxBitRate,const PString & oid,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1693 H323NonStandardDataCapability::H323NonStandardDataCapability(unsigned maxBitRate,
1694                                                              const PString & oid,
1695                                                              const BYTE * fixedData,
1696                                                              PINDEX dataSize,
1697                                                              PINDEX offset,
1698                                                              PINDEX length)
1699   : H323DataCapability(maxBitRate),
1700     H323NonStandardCapabilityInfo(oid, fixedData, dataSize, offset, length)
1701 {
1702 }
1703 
1704 
H323NonStandardDataCapability(unsigned maxBitRate,BYTE country,BYTE extension,WORD maufacturer,const BYTE * fixedData,PINDEX dataSize,PINDEX offset,PINDEX length)1705 H323NonStandardDataCapability::H323NonStandardDataCapability(unsigned maxBitRate,
1706                                                              BYTE country,
1707                                                              BYTE extension,
1708                                                              WORD maufacturer,
1709                                                              const BYTE * fixedData,
1710                                                              PINDEX dataSize,
1711                                                              PINDEX offset,
1712                                                              PINDEX length)
1713   : H323DataCapability(maxBitRate),
1714     H323NonStandardCapabilityInfo(country, extension, maufacturer, fixedData, dataSize, offset, length)
1715 {
1716 }
1717 
1718 
Compare(const PObject & obj) const1719 PObject::Comparison H323NonStandardDataCapability::Compare(const PObject & obj) const
1720 {
1721   if (!PIsDescendant(&obj, H323NonStandardDataCapability))
1722     return PObject::LessThan;
1723 
1724   return CompareInfo((const H323NonStandardDataCapability &)obj);
1725 }
1726 
1727 
GetSubType() const1728 unsigned H323NonStandardDataCapability::GetSubType() const
1729 {
1730   return H245_DataApplicationCapability_application::e_nonStandard;
1731 }
1732 
1733 
OnSendingPDU(H245_DataApplicationCapability & pdu) const1734 PBoolean H323NonStandardDataCapability::OnSendingPDU(H245_DataApplicationCapability & pdu) const
1735 {
1736   return OnSendingNonStandardPDU(pdu.m_application, H245_DataApplicationCapability_application::e_nonStandard);
1737 }
1738 
1739 
OnSendingPDU(H245_DataMode & pdu) const1740 PBoolean H323NonStandardDataCapability::OnSendingPDU(H245_DataMode & pdu) const
1741 {
1742   return OnSendingNonStandardPDU(pdu.m_application, H245_DataMode_application::e_nonStandard);
1743 }
1744 
1745 
OnReceivedPDU(const H245_DataApplicationCapability & pdu)1746 PBoolean H323NonStandardDataCapability::OnReceivedPDU(const H245_DataApplicationCapability & pdu)
1747 {
1748   return OnReceivedNonStandardPDU(pdu.m_application, H245_DataApplicationCapability_application::e_nonStandard);
1749 }
1750 
1751 
IsMatch(const PASN_Choice & subTypePDU,const PString & mediaPacketization) const1752 PBoolean H323NonStandardDataCapability::IsMatch(const PASN_Choice & subTypePDU, const PString & mediaPacketization) const
1753 {
1754   return H323Capability::IsMatch(subTypePDU, mediaPacketization) &&
1755          H323NonStandardCapabilityInfo::IsMatch((const H245_NonStandardParameter &)subTypePDU.GetObject());
1756 }
1757 
1758 
1759 /////////////////////////////////////////////////////////////////////////////
1760 
H323_G711Capability(Mode m,Speed s)1761 H323_G711Capability::H323_G711Capability(Mode m, Speed s)
1762   : H323AudioCapability()
1763 {
1764   mode = m;
1765   speed = s;
1766   SetTxFramesInPacket(240);   // 240ms max, 30ms desired
1767 }
1768 
1769 
Clone() const1770 PObject * H323_G711Capability::Clone() const
1771 {
1772   return new H323_G711Capability(*this);
1773 }
1774 
1775 
GetSubType() const1776 unsigned H323_G711Capability::GetSubType() const
1777 {
1778   static const unsigned G711SubType[2][2] = {
1779     { H245_AudioCapability::e_g711Alaw64k, H245_AudioCapability::e_g711Alaw56k },
1780     { H245_AudioCapability::e_g711Ulaw64k, H245_AudioCapability::e_g711Ulaw56k }
1781   };
1782   return G711SubType[mode][speed];
1783 }
1784 
1785 
GetFormatName() const1786 PString H323_G711Capability::GetFormatName() const
1787 {
1788   static const char * const G711Name[2][2] = {
1789     { OPAL_G711_ALAW_64K, "G.711-ALaw-56k" },
1790     { OPAL_G711_ULAW_64K, "G.711-uLaw-56k" }
1791   };
1792   return G711Name[mode][speed];
1793 }
1794 
1795 
1796 /////////////////////////////////////////////////////////////////////////////
1797 
1798 static const char * const UIISubTypeNames[H323_UserInputCapability::NumSubTypes] = {
1799   "UserInput/basicString",
1800   "UserInput/iA5String",
1801   "UserInput/generalString",
1802   "UserInput/dtmf",
1803   "UserInput/hookflash",
1804   OPAL_RFC2833
1805 };
1806 
GetSubTypeName(SubTypes s)1807 const char * H323_UserInputCapability::GetSubTypeName(SubTypes s)
1808 {
1809   return s < PARRAYSIZE(UIISubTypeNames) ? UIISubTypeNames[s] : "<Unknown>";
1810 }
1811 
1812 #define DECLARE_USER_INPUT_CLASS(type) \
1813 class H323_UserInputCapability_##type : public H323_UserInputCapability \
1814 { \
1815   public: \
1816     H323_UserInputCapability_##type() \
1817     : H323_UserInputCapability(H323_UserInputCapability::type) { } \
1818 };\
1819 
1820 #define DEFINE_USER_INPUT(type) \
1821   DECLARE_USER_INPUT_CLASS(type) \
1822   const OpalMediaFormat UserInput_##type( \
1823     UIISubTypeNames[H323_UserInputCapability::type], \
1824     OpalMediaType::UserInput(), RTP_DataFrame::IllegalPayloadType, NULL, PFalse, 1, 0, 0, 0 \
1825   ); \
1826   H323_REGISTER_CAPABILITY(H323_UserInputCapability_##type, UIISubTypeNames[H323_UserInputCapability::type]) \
1827 
1828 DEFINE_USER_INPUT(BasicString);
1829 DEFINE_USER_INPUT(IA5String);
1830 DEFINE_USER_INPUT(GeneralString);
1831 DEFINE_USER_INPUT(SignalToneH245);
1832 DEFINE_USER_INPUT(HookFlashH245);
1833 
1834 DECLARE_USER_INPUT_CLASS(SignalToneRFC2833)
H323_REGISTER_CAPABILITY(H323_UserInputCapability_SignalToneRFC2833,UIISubTypeNames[H323_UserInputCapability::SignalToneRFC2833])1835 H323_REGISTER_CAPABILITY(H323_UserInputCapability_SignalToneRFC2833, UIISubTypeNames[H323_UserInputCapability::SignalToneRFC2833])
1836 
1837 H323_UserInputCapability::H323_UserInputCapability(SubTypes _subType)
1838 {
1839   subType = _subType;
1840 }
1841 
1842 
Clone() const1843 PObject * H323_UserInputCapability::Clone() const
1844 {
1845   return new H323_UserInputCapability(*this);
1846 }
1847 
1848 
GetMainType() const1849 H323Capability::MainTypes H323_UserInputCapability::GetMainType() const
1850 {
1851   return e_UserInput;
1852 }
1853 
1854 
1855 #define SignalToneRFC2833_SubType 10000
1856 
1857 static unsigned UserInputCapabilitySubTypeCodes[] = {
1858   H245_UserInputCapability::e_basicString,
1859   H245_UserInputCapability::e_iA5String,
1860   H245_UserInputCapability::e_generalString,
1861   H245_UserInputCapability::e_dtmf,
1862   H245_UserInputCapability::e_hookflash,
1863   SignalToneRFC2833_SubType
1864 };
1865 
GetSubType() const1866 unsigned  H323_UserInputCapability::GetSubType()  const
1867 {
1868   return UserInputCapabilitySubTypeCodes[subType];
1869 }
1870 
1871 
GetFormatName() const1872 PString H323_UserInputCapability::GetFormatName() const
1873 {
1874   return UIISubTypeNames[subType];
1875 }
1876 
1877 
CreateChannel(H323Connection &,H323Channel::Directions,unsigned,const H245_H2250LogicalChannelParameters *) const1878 H323Channel * H323_UserInputCapability::CreateChannel(H323Connection &,
1879                                                       H323Channel::Directions,
1880                                                       unsigned,
1881                                                       const H245_H2250LogicalChannelParameters *) const
1882 {
1883   PTRACE(1, "H323\tCannot create UserInputCapability channel");
1884   return NULL;
1885 }
1886 
1887 
OnSendingPDU(H245_Capability & pdu) const1888 PBoolean H323_UserInputCapability::OnSendingPDU(H245_Capability & pdu) const
1889 {
1890   if (subType == SignalToneRFC2833) {
1891     pdu.SetTag(H245_Capability::e_receiveRTPAudioTelephonyEventCapability);
1892     H245_AudioTelephonyEventCapability & atec = pdu;
1893     OpalMediaFormat mediaFormat = GetMediaFormat();
1894     atec.m_dynamicRTPPayloadType = mediaFormat.GetPayloadType();
1895     PString events;
1896     if (!mediaFormat.GetOptionValue(OpalRFC288EventsName(), events))
1897       return false;
1898     atec.m_audioTelephoneEvent = events;
1899   }
1900   else {
1901     pdu.SetTag(H245_Capability::e_receiveUserInputCapability);
1902     H245_UserInputCapability & ui = pdu;
1903     ui.SetTag(UserInputCapabilitySubTypeCodes[subType]);
1904   }
1905   return true;
1906 }
1907 
1908 
OnSendingPDU(H245_DataType &) const1909 PBoolean H323_UserInputCapability::OnSendingPDU(H245_DataType &) const
1910 {
1911   PTRACE(1, "H323\tCannot have UserInputCapability in DataType");
1912   return PFalse;
1913 }
1914 
1915 
OnSendingPDU(H245_ModeElement &) const1916 PBoolean H323_UserInputCapability::OnSendingPDU(H245_ModeElement &) const
1917 {
1918   PTRACE(1, "H323\tCannot have UserInputCapability in ModeElement");
1919   return PFalse;
1920 }
1921 
1922 
OnReceivedPDU(const H245_Capability & pdu)1923 PBoolean H323_UserInputCapability::OnReceivedPDU(const H245_Capability & pdu)
1924 {
1925   if (pdu.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
1926     subType = SignalToneRFC2833;
1927     const H245_AudioTelephonyEventCapability & atec = pdu;
1928     OpalMediaFormat & mediaFormat = GetWritableMediaFormat();
1929     mediaFormat.SetPayloadType((RTP_DataFrame::PayloadTypes)(int)atec.m_dynamicRTPPayloadType);
1930     mediaFormat.SetOptionValue(OpalRFC288EventsName(), atec.m_audioTelephoneEvent);
1931     return H323Capability::OnReceivedPDU(pdu);
1932   }
1933 
1934   if (pdu.GetTag() != H245_Capability::e_receiveUserInputCapability &&
1935       pdu.GetTag() != H245_Capability::e_receiveAndTransmitUserInputCapability)
1936     return PFalse;
1937 
1938   const H245_UserInputCapability & ui = pdu;
1939   return ui.GetTag() == UserInputCapabilitySubTypeCodes[subType] && H323Capability::OnReceivedPDU(pdu);
1940 }
1941 
1942 
OnReceivedPDU(const H245_DataType &,PBoolean)1943 PBoolean H323_UserInputCapability::OnReceivedPDU(const H245_DataType &, PBoolean)
1944 {
1945   PTRACE(1, "H323\tCannot have UserInputCapability in DataType");
1946   return PFalse;
1947 }
1948 
1949 
IsUsable(const H323Connection & connection) const1950 PBoolean H323_UserInputCapability::IsUsable(const H323Connection & connection) const
1951 {
1952   if (connection.GetControlVersion() >= 7)
1953     return PTrue;
1954 
1955   if (connection.GetRemoteApplication().Find("AltiServ-ITG") != P_MAX_INDEX)
1956     return PFalse;
1957 
1958   return subType != SignalToneRFC2833;
1959 }
1960 
1961 
SetUserInputCapability(H323Capabilities & capabilities,PINDEX descriptorNum,PINDEX simultaneous,H323_UserInputCapability::SubTypes subType)1962 static PINDEX SetUserInputCapability(H323Capabilities & capabilities,
1963                                      PINDEX descriptorNum,
1964                                      PINDEX simultaneous,
1965                                      H323_UserInputCapability::SubTypes subType)
1966 {
1967   H323Capability * capability = capabilities.FindCapability(H323Capability::e_UserInput,
1968                                                UserInputCapabilitySubTypeCodes[subType]);
1969   if (capability == NULL)
1970     capability = new H323_UserInputCapability(subType);
1971   return capabilities.SetCapability(descriptorNum, simultaneous, capability);
1972 }
1973 
1974 
AddAllCapabilities(H323Capabilities & capabilities,PINDEX descriptorNum,PINDEX simultaneous,bool includeRFC2833)1975 void H323_UserInputCapability::AddAllCapabilities(H323Capabilities & capabilities,
1976                                                   PINDEX descriptorNum,
1977                                                   PINDEX simultaneous,
1978                                                   bool includeRFC2833)
1979 {
1980   PINDEX num = SetUserInputCapability(capabilities, descriptorNum, simultaneous, HookFlashH245);
1981   if (descriptorNum == P_MAX_INDEX) {
1982     descriptorNum = num;
1983     simultaneous = P_MAX_INDEX;
1984   }
1985   else if (simultaneous == P_MAX_INDEX)
1986     simultaneous = num+1;
1987 
1988   num = SetUserInputCapability(capabilities, descriptorNum, simultaneous, BasicString);
1989   if (simultaneous == P_MAX_INDEX)
1990     simultaneous = num;
1991 
1992   SetUserInputCapability(capabilities, descriptorNum, simultaneous, SignalToneH245);
1993 
1994   if (includeRFC2833)
1995     SetUserInputCapability(capabilities, descriptorNum, simultaneous, SignalToneRFC2833);
1996 }
1997 
1998 
1999 /////////////////////////////////////////////////////////////////////////////
2000 
SetSize(PINDEX newSize)2001 PBoolean H323SimultaneousCapabilities::SetSize(PINDEX newSize)
2002 {
2003   PINDEX oldSize = GetSize();
2004 
2005   if (!H323CapabilitiesListArray::SetSize(newSize))
2006     return PFalse;
2007 
2008   while (oldSize < newSize) {
2009     H323CapabilitiesList * list = new H323CapabilitiesList;
2010     // The lowest level list should not delete codecs on destruction
2011     list->DisallowDeleteObjects();
2012     SetAt(oldSize++, list);
2013   }
2014 
2015   return PTrue;
2016 }
2017 
2018 
SetSize(PINDEX newSize)2019 PBoolean H323CapabilitiesSet::SetSize(PINDEX newSize)
2020 {
2021   PINDEX oldSize = GetSize();
2022 
2023   if (!H323CapabilitiesSetArray::SetSize(newSize))
2024     return PFalse;
2025 
2026   while (oldSize < newSize)
2027     SetAt(oldSize++, new H323SimultaneousCapabilities);
2028 
2029   return PTrue;
2030 }
2031 
2032 
H323Capabilities()2033 H323Capabilities::H323Capabilities()
2034 {
2035 }
2036 
2037 
H323Capabilities(const H323Connection & connection,const H245_TerminalCapabilitySet & pdu)2038 H323Capabilities::H323Capabilities(const H323Connection & connection,
2039                                    const H245_TerminalCapabilitySet & pdu)
2040 {
2041   PTRACE(4, "H323\tH323Capabilities(ctor)");
2042 
2043   /** If mediaPacketization information is available, use this with the FindCapability() logic.
2044    *  Certain codecs, such as H.263, need additional information in order to match the specific
2045    *  version of the codec against possibly multiple codec with the same 'subtype' such as
2046    *  e_h263VideoCapability.
2047    */
2048   m_mediaPacketizations += "RFC2190";  // Always supported
2049   m_mediaPacketizations += OpalPluginCodec_Identifer_H264_Aligned; // Always supported
2050   const H245_MultiplexCapability * muxCap = NULL;
2051   if (pdu.HasOptionalField(H245_TerminalCapabilitySet::e_multiplexCapability)) {
2052     muxCap = &pdu.m_multiplexCapability;
2053 
2054     if (muxCap != NULL && muxCap->GetTag() == H245_MultiplexCapability::e_h2250Capability) {
2055       // H2250Capability ::=SEQUENCE
2056       const H245_H2250Capability & h225_0 = *muxCap;
2057 
2058       //  MediaPacketizationCapability ::=SEQUENCE
2059       const H245_MediaPacketizationCapability & mediaPacket = h225_0.m_mediaPacketizationCapability;
2060       if (mediaPacket.HasOptionalField(H245_MediaPacketizationCapability::e_rtpPayloadType)) {
2061         for (PINDEX i = 0; i < mediaPacket.m_rtpPayloadType.GetSize(); i++) {
2062           PString mediaPacketization = H323GetRTPPacketization(mediaPacket.m_rtpPayloadType[i]);
2063           if (!mediaPacketization.IsEmpty()) {
2064             m_mediaPacketizations += mediaPacketization;
2065             PTRACE(4, "H323\tH323Capabilities(ctor) Appended mediaPacketization="
2066                    << mediaPacketization << ", mediaPacketization count=" << m_mediaPacketizations.GetSize());
2067           }
2068         } // for ... m_rtpPayloadType.GetSize()
2069       } // e_rtpPayloadType
2070     } // e_h2250Capability
2071   } // e_multiplexCapability
2072 
2073   // Decode out of the PDU, the list of known codecs.
2074   if (pdu.HasOptionalField(H245_TerminalCapabilitySet::e_capabilityTable)) {
2075     H323Capabilities allCapabilities(connection.GetLocalCapabilities());
2076     allCapabilities.AddAllCapabilities(0, 0, "*");
2077     H323_UserInputCapability::AddAllCapabilities(allCapabilities, P_MAX_INDEX, P_MAX_INDEX);
2078 #if OPAL_H239
2079     allCapabilities.Add(new H323H239VideoCapability(OpalMediaFormat()));
2080     allCapabilities.Add(new H323H239ControlCapability());
2081 #endif
2082     allCapabilities.m_mediaPacketizations = m_mediaPacketizations;
2083     PTRACE(4, "H323\tParsing remote capabilities");
2084 
2085     for (PINDEX i = 0; i < pdu.m_capabilityTable.GetSize(); i++) {
2086       if (pdu.m_capabilityTable[i].HasOptionalField(H245_CapabilityTableEntry::e_capability)) {
2087         H323Capability * capability = allCapabilities.FindCapability(pdu.m_capabilityTable[i].m_capability);
2088         if (capability != NULL) {
2089           H323Capability * copy = (H323Capability *)capability->Clone();
2090           if (!copy->OnReceivedPDU(pdu.m_capabilityTable[i].m_capability))
2091             delete copy;
2092           else {
2093             copy->SetCapabilityNumber(pdu.m_capabilityTable[i].m_capabilityTableEntryNumber);
2094             table.Append(copy);
2095 
2096             if (!m_mediaPacketizations.IsEmpty()) { // also update the mediaPacketizations option
2097               OpalMediaFormat & mediaFormat = copy->GetWritableMediaFormat();
2098               PStringSet intersection;
2099               if (PStringSet::Intersection(m_mediaPacketizations, mediaFormat.GetMediaPacketizations(), &intersection))
2100                 mediaFormat.SetMediaPacketizations(intersection);
2101             }
2102           }
2103         }
2104       }
2105     }
2106   }
2107 
2108   PINDEX outerSize = pdu.m_capabilityDescriptors.GetSize();
2109   set.SetSize(outerSize);
2110   for (PINDEX outer = 0; outer < outerSize; outer++) {
2111     H245_CapabilityDescriptor & desc = pdu.m_capabilityDescriptors[outer];
2112     if (desc.HasOptionalField(H245_CapabilityDescriptor::e_simultaneousCapabilities)) {
2113       PINDEX middleSize = desc.m_simultaneousCapabilities.GetSize();
2114       set[outer].SetSize(middleSize);
2115       for (PINDEX middle = 0; middle < middleSize; middle++) {
2116         H245_AlternativeCapabilitySet & alt = desc.m_simultaneousCapabilities[middle];
2117         for (PINDEX inner = 0; inner < alt.GetSize(); inner++) {
2118           for (PINDEX cap = 0; cap < table.GetSize(); cap++) {
2119             if (table[cap].GetCapabilityNumber() == alt[inner]) {
2120               set[outer][middle].Append(&table[cap]);
2121               break;
2122             }
2123           }
2124         }
2125       }
2126     }
2127   }
2128 }
2129 
2130 
H323Capabilities(const H323Capabilities & original)2131 H323Capabilities::H323Capabilities(const H323Capabilities & original)
2132   : PObject(original)
2133 {
2134   operator=(original);
2135 }
2136 
2137 
operator =(const H323Capabilities & original)2138 H323Capabilities & H323Capabilities::operator=(const H323Capabilities & original)
2139 {
2140   RemoveAll();
2141 
2142   for (PINDEX i = 0; i < original.GetSize(); i++)
2143     Copy(original[i]);
2144 
2145   PINDEX outerSize = original.set.GetSize();
2146   set.SetSize(outerSize);
2147   for (PINDEX outer = 0; outer < outerSize; outer++) {
2148     PINDEX middleSize = original.set[outer].GetSize();
2149     set[outer].SetSize(middleSize);
2150     for (PINDEX middle = 0; middle < middleSize; middle++) {
2151       PINDEX innerSize = original.set[outer][middle].GetSize();
2152       for (PINDEX inner = 0; inner < innerSize; inner++)
2153         set[outer][middle].Append(FindCapability(original.set[outer][middle][inner].GetCapabilityNumber()));
2154     }
2155   }
2156 
2157   return *this;
2158 }
2159 
2160 
PrintOn(ostream & strm) const2161 void H323Capabilities::PrintOn(ostream & strm) const
2162 {
2163   std::streamsize indent = strm.precision()-1;
2164   strm << setw(indent) << " " << "Table:\n";
2165   for (PINDEX i = 0; i < table.GetSize(); i++)
2166     strm << setw(indent+2) << " " << table[i] << '\n';
2167 
2168   strm << setw(indent) << " " << "Set:\n";
2169   for (PINDEX outer = 0; outer < set.GetSize(); outer++) {
2170     strm << setw(indent+2) << " " << outer << ":\n";
2171     for (PINDEX middle = 0; middle < set[outer].GetSize(); middle++) {
2172       strm << setw(indent+4) << " " << middle << ":\n";
2173       for (PINDEX inner = 0; inner < set[outer][middle].GetSize(); inner++)
2174         strm << setw(indent+6) << " " << set[outer][middle][inner] << '\n';
2175     }
2176   }
2177 }
2178 
2179 
SetCapability(PINDEX descriptorNum,PINDEX simultaneousNum,H323Capability * capability)2180 PINDEX H323Capabilities::SetCapability(PINDEX descriptorNum,
2181                                        PINDEX simultaneousNum,
2182                                        H323Capability * capability)
2183 {
2184   // Make sure capability has been added to table.
2185   Add(capability);
2186 
2187   PBoolean newDescriptor = descriptorNum == P_MAX_INDEX;
2188   if (newDescriptor)
2189     descriptorNum = set.GetSize();
2190 
2191   // Make sure the outer array is big enough
2192   set.SetMinSize(descriptorNum+1);
2193 
2194   if (simultaneousNum == P_MAX_INDEX)
2195     simultaneousNum = set[descriptorNum].GetSize();
2196 
2197   // Make sure the middle array is big enough
2198   set[descriptorNum].SetMinSize(simultaneousNum+1);
2199 
2200   // Now we can put the new entry in.
2201   set[descriptorNum][simultaneousNum].Append(capability);
2202   return newDescriptor ? descriptorNum : simultaneousNum;
2203 }
2204 
2205 
MatchWildcard(const PCaselessString & str,const PStringArray & wildcard)2206 static PBoolean MatchWildcard(const PCaselessString & str, const PStringArray & wildcard)
2207 {
2208   PINDEX last = 0;
2209   for (PINDEX i = 0; i < wildcard.GetSize(); i++) {
2210     if (wildcard[i].IsEmpty())
2211       last = str.GetLength();
2212     else {
2213       PINDEX next = str.Find(wildcard[i], last);
2214       if (next == P_MAX_INDEX)
2215         return PFalse;
2216       last = next + wildcard[i].GetLength();
2217     }
2218   }
2219 
2220   return last == str.GetLength();
2221 }
2222 
2223 
AddMediaFormat(PINDEX descriptorNum,PINDEX simultaneous,const OpalMediaFormat & mediaFormat)2224 PINDEX H323Capabilities::AddMediaFormat(PINDEX descriptorNum,
2225                                         PINDEX simultaneous,
2226                                         const OpalMediaFormat & mediaFormat)
2227 {
2228   PINDEX reply = descriptorNum == P_MAX_INDEX ? P_MAX_INDEX : simultaneous;
2229 
2230   if (FindCapability(mediaFormat, H323Capability::e_Unknown, true) == NULL) {
2231     H323Capability * capability = H323Capability::Create(mediaFormat);
2232     if (capability != NULL) {
2233       capability->GetWritableMediaFormat() = mediaFormat;
2234       reply = SetCapability(descriptorNum, simultaneous, capability);
2235       m_mediaPacketizations.Union(mediaFormat.GetMediaPacketizations());
2236     }
2237   }
2238 
2239   return reply;
2240 }
2241 
2242 
AddAllCapabilities(PINDEX descriptorNum,PINDEX simultaneous,const PString & name,PBoolean exact)2243 PINDEX H323Capabilities::AddAllCapabilities(PINDEX descriptorNum,
2244                                             PINDEX simultaneous,
2245                                             const PString & name,
2246                                             PBoolean exact)
2247 {
2248   PINDEX reply = descriptorNum == P_MAX_INDEX ? P_MAX_INDEX : simultaneous;
2249 
2250   PStringArray wildcard = name.Tokenise('*', PFalse);
2251 
2252   H323CapabilityFactory::KeyList_T stdCaps = H323CapabilityFactory::GetKeyList();
2253   H323CapabilityFactory::KeyList_T::const_iterator r;
2254 
2255   for (r = stdCaps.begin(); r != stdCaps.end(); ++r) {
2256     PCaselessString capName = *r;
2257     if ((exact ? (capName == name) : MatchWildcard(capName, wildcard)) &&
2258         FindCapability(capName, H323Capability::e_Unknown, exact) == NULL) {
2259       H323Capability * capability = H323Capability::Create(capName);
2260       PINDEX num = SetCapability(descriptorNum, simultaneous, capability);
2261       if (descriptorNum == P_MAX_INDEX) {
2262         reply = num;
2263         descriptorNum = num;
2264         simultaneous = P_MAX_INDEX;
2265       }
2266       else if (simultaneous == P_MAX_INDEX) {
2267         if (reply == P_MAX_INDEX)
2268           reply = num;
2269         simultaneous = num;
2270       }
2271     }
2272   }
2273 
2274   return reply;
2275 }
2276 
2277 
MergeCapabilityNumber(const H323CapabilitiesList & table,unsigned newCapabilityNumber)2278 static unsigned MergeCapabilityNumber(const H323CapabilitiesList & table,
2279                                       unsigned newCapabilityNumber)
2280 {
2281   // Assign a unique number to the codec, check if the user wants a specific
2282   // value and start with that.
2283   if (newCapabilityNumber == 0)
2284     newCapabilityNumber = 1;
2285 
2286   PINDEX i = 0;
2287   while (i < table.GetSize()) {
2288     if (table[i].GetCapabilityNumber() != newCapabilityNumber)
2289       i++;
2290     else {
2291       // If it already in use, increment it
2292       newCapabilityNumber++;
2293       i = 0;
2294     }
2295   }
2296 
2297   return newCapabilityNumber;
2298 }
2299 
2300 
Add(H323Capability * capability)2301 void H323Capabilities::Add(H323Capability * capability)
2302 {
2303   // See if already added, confuses things if you add the same instance twice
2304   if (table.GetObjectsIndex(capability) != P_MAX_INDEX)
2305     return;
2306 
2307   capability->SetCapabilityNumber(MergeCapabilityNumber(table, 1));
2308   table.Append(capability);
2309 
2310   PTRACE(3, "H323\tAdded capability: " << *capability);
2311 }
2312 
2313 
Copy(const H323Capability & capability)2314 H323Capability * H323Capabilities::Copy(const H323Capability & capability)
2315 {
2316   H323Capability * newCapability = (H323Capability *)capability.Clone();
2317   newCapability->SetCapabilityNumber(MergeCapabilityNumber(table, capability.GetCapabilityNumber()));
2318   table.Append(newCapability);
2319 
2320   PTRACE(3, "H323\tAdded capability: " << *newCapability);
2321   return newCapability;
2322 }
2323 
2324 
Remove(H323Capability * capability)2325 void H323Capabilities::Remove(H323Capability * capability)
2326 {
2327   if (capability == NULL)
2328     return;
2329 
2330   PTRACE(3, "H323\tRemoving capability: " << *capability);
2331 
2332   unsigned capabilityNumber = capability->GetCapabilityNumber();
2333 
2334   for (PINDEX outer = 0; outer < set.GetSize(); ) {
2335     for (PINDEX middle = 0; middle < set[outer].GetSize(); ) {
2336       for (PINDEX inner = 0; inner < set[outer][middle].GetSize(); inner++) {
2337         if (set[outer][middle][inner].GetCapabilityNumber() == capabilityNumber) {
2338           set[outer][middle].RemoveAt(inner);
2339           break;
2340         }
2341       }
2342       if (set[outer][middle].GetSize() == 0)
2343         set[outer].RemoveAt(middle);
2344       else
2345         middle++;
2346     }
2347     if (set[outer].GetSize() == 0)
2348       set.RemoveAt(outer);
2349     else
2350       outer++;
2351   }
2352 
2353   table.Remove(capability);
2354 }
2355 
2356 
Remove(const PString & codecName)2357 void H323Capabilities::Remove(const PString & codecName)
2358 {
2359   H323Capability * cap = FindCapability(codecName);
2360   while (cap != NULL) {
2361     Remove(cap);
2362     cap = FindCapability(codecName);
2363   }
2364 }
2365 
2366 
Remove(const PStringArray & codecNames)2367 void H323Capabilities::Remove(const PStringArray & codecNames)
2368 {
2369   for (PINDEX i = 0; i < codecNames.GetSize(); i++)
2370     Remove(codecNames[i]);
2371 }
2372 
2373 
RemoveAll()2374 void H323Capabilities::RemoveAll()
2375 {
2376   table.RemoveAll();
2377   set.RemoveAll();
2378 }
2379 
2380 
FindCapability(unsigned capabilityNumber) const2381 H323Capability * H323Capabilities::FindCapability(unsigned capabilityNumber) const
2382 {
2383   for (PINDEX i = 0; i < table.GetSize(); i++) {
2384     if (table[i].GetCapabilityNumber() == capabilityNumber) {
2385       PTRACE(3, "H323\tFound capability: " << table[i]);
2386       return &table[i];
2387     }
2388   }
2389 
2390   PTRACE(4, "H323\tCould not find capability: " << capabilityNumber);
2391   return NULL;
2392 }
2393 
2394 
FindCapability(const PString & formatName,H323Capability::CapabilityDirection direction,PBoolean exact) const2395 H323Capability * H323Capabilities::FindCapability(const PString & formatName,
2396                                                   H323Capability::CapabilityDirection direction,
2397                                                   PBoolean exact) const
2398 {
2399   PStringArray wildcard = formatName.Tokenise('*', PFalse);
2400 
2401   for (PINDEX i = 0; i < table.GetSize(); i++) {
2402     PCaselessString str = table[i].GetFormatName();
2403     if ((exact ? (str == formatName) : MatchWildcard(str, wildcard)) &&
2404           (direction == H323Capability::e_Unknown ||
2405            table[i].GetCapabilityDirection() == direction)) {
2406       PTRACE(3, "H323\tFound capability: " << table[i]);
2407       return &table[i];
2408     }
2409   }
2410 
2411   PTRACE(4, "H323\tCould not find capability: \"" << formatName << '"');
2412   return NULL;
2413 }
2414 
2415 
FindCapability(H323Capability::CapabilityDirection direction) const2416 H323Capability * H323Capabilities::FindCapability(
2417                               H323Capability::CapabilityDirection direction) const
2418 {
2419   for (PINDEX i = 0; i < table.GetSize(); i++) {
2420     if (table[i].GetCapabilityDirection() == direction) {
2421       PTRACE(3, "H323\tFound capability: " << table[i]);
2422       return &table[i];
2423     }
2424   }
2425 
2426   PTRACE(4, "H323\tCould not find capability: \"" << direction << '"');
2427   return NULL;
2428 }
2429 
2430 
FindCapability(const H323Capability & capability) const2431 H323Capability * H323Capabilities::FindCapability(const H323Capability & capability) const
2432 {
2433 
2434   for (PINDEX i = 0; i < table.GetSize(); i++) {
2435     if (table[i] == capability) {
2436       PTRACE(3, "H323\tFound capability: " << table[i]);
2437       return &table[i];
2438     }
2439   }
2440 
2441   PTRACE(4, "H323\tCould not find capability: " << capability);
2442   return NULL;
2443 }
2444 
2445 
FindCapability(const H245_Capability & cap) const2446 H323Capability * H323Capabilities::FindCapability(const H245_Capability & cap) const
2447 {
2448   for (PINDEX i = 0; i < table.GetSize(); i++) {
2449     H323Capability & capability = table[i];
2450 
2451     for (PINDEX j = 0; j <= m_mediaPacketizations.GetSize(); ++j) {
2452       PString mediaPacketization;
2453       if (j < m_mediaPacketizations.GetSize())
2454         mediaPacketization = m_mediaPacketizations.GetKeyAt(j);
2455 
2456       switch (cap.GetTag()) {
2457         case H245_Capability::e_receiveAudioCapability :
2458         case H245_Capability::e_transmitAudioCapability :
2459         case H245_Capability::e_receiveAndTransmitAudioCapability :
2460           if (capability.GetMainType() == H323Capability::e_Audio) {
2461             const H245_AudioCapability & audio = cap;
2462             if (capability.IsMatch(audio, mediaPacketization))
2463               return &capability;
2464           }
2465           break;
2466 
2467         case H245_Capability::e_receiveVideoCapability :
2468         case H245_Capability::e_transmitVideoCapability :
2469         case H245_Capability::e_receiveAndTransmitVideoCapability :
2470           if (capability.GetMainType() == H323Capability::e_Video) {
2471             const H245_VideoCapability & video = cap;
2472             if (capability.IsMatch(video, mediaPacketization))
2473               return &capability;
2474           }
2475           break;
2476 
2477         case H245_Capability::e_receiveDataApplicationCapability :
2478         case H245_Capability::e_transmitDataApplicationCapability :
2479         case H245_Capability::e_receiveAndTransmitDataApplicationCapability :
2480           if (capability.GetMainType() == H323Capability::e_Data) {
2481             const H245_DataApplicationCapability & data = cap;
2482             if (capability.IsMatch(data.m_application, mediaPacketization))
2483               return &capability;
2484           }
2485           break;
2486 
2487         case H245_Capability::e_receiveUserInputCapability :
2488         case H245_Capability::e_transmitUserInputCapability :
2489         case H245_Capability::e_receiveAndTransmitUserInputCapability :
2490           if (capability.GetMainType() == H323Capability::e_UserInput) {
2491             const H245_UserInputCapability & ui = cap;
2492             if (capability.IsMatch(ui, mediaPacketization))
2493               return &capability;
2494           }
2495           break;
2496 
2497         case H245_Capability::e_receiveRTPAudioTelephonyEventCapability :
2498           return FindCapability(H323Capability::e_UserInput, SignalToneRFC2833_SubType);
2499 
2500         case H245_Capability::e_genericControlCapability :
2501           if (capability.GetMainType() == H323Capability::e_GenericControl) {
2502             if (capability.IsMatch(cap, mediaPacketization))
2503               return &capability;
2504           }
2505           break;
2506       }
2507     }
2508   }
2509 
2510 #if PTRACING
2511   if (PTrace::CanTrace(4)) {
2512     PString tagName;
2513     switch (cap.GetTag()) {
2514       case H245_Capability::e_receiveAudioCapability :
2515       case H245_Capability::e_transmitAudioCapability :
2516       case H245_Capability::e_receiveAndTransmitAudioCapability :
2517         tagName = ((const H245_AudioCapability &)cap).GetTagName();
2518         break;
2519 
2520       case H245_Capability::e_receiveVideoCapability :
2521       case H245_Capability::e_transmitVideoCapability :
2522       case H245_Capability::e_receiveAndTransmitVideoCapability :
2523         tagName = ((const H245_VideoCapability &)cap).GetTagName();
2524         break;
2525 
2526       case H245_Capability::e_receiveDataApplicationCapability :
2527       case H245_Capability::e_transmitDataApplicationCapability :
2528       case H245_Capability::e_receiveAndTransmitDataApplicationCapability :
2529         tagName = ((const H245_DataApplicationCapability &)cap).m_application.GetTagName();
2530         break;
2531 
2532       case H245_Capability::e_receiveUserInputCapability :
2533       case H245_Capability::e_transmitUserInputCapability :
2534       case H245_Capability::e_receiveAndTransmitUserInputCapability :
2535         tagName = ((const H245_UserInputCapability &)cap).GetTagName();
2536         break;
2537 
2538       default :
2539         tagName = "unknown";
2540         break;
2541     }
2542     PTRACE(4, "H323\tCould not find capability: " << cap.GetTagName() << ", type " << tagName);
2543   }
2544 #endif
2545   return NULL;
2546 }
2547 
2548 
FindCapability(const H245_DataType & dataType,const PString & mediaPacketization) const2549 H323Capability * H323Capabilities::FindCapability(const H245_DataType & dataType, const PString & mediaPacketization) const
2550 {
2551   for (PINDEX i = 0; i < table.GetSize(); i++) {
2552     H323Capability & capability = table[i];
2553     bool checkExact;
2554     switch (dataType.GetTag()) {
2555       case H245_DataType::e_audioData :
2556         checkExact = capability.GetMainType() == H323Capability::e_Audio &&
2557                      capability.IsMatch((const H245_AudioCapability &)dataType, mediaPacketization);
2558         break;
2559 
2560       case H245_DataType::e_videoData :
2561         checkExact = capability.GetMainType() == H323Capability::e_Video &&
2562                      capability.IsMatch((const H245_VideoCapability &)dataType, mediaPacketization);
2563         break;
2564 
2565       case H245_DataType::e_data :
2566         checkExact = capability.GetMainType() == H323Capability::e_Data &&
2567                      capability.IsMatch(((const H245_DataApplicationCapability &)dataType).m_application, mediaPacketization);
2568         break;
2569 
2570       default :
2571         checkExact = false;
2572     }
2573 
2574     if (checkExact) {
2575       H323Capability * compare = (H323Capability *)capability.Clone();
2576       if (compare->OnReceivedPDU(dataType, PFalse)) {
2577         if (*compare == capability) {
2578           delete compare;
2579           return &capability;
2580         }
2581         PTRACE(3, "H323\tCapability compare failed");
2582       }
2583       else {
2584         PTRACE(3, "H323\tOnReceived failed");
2585       }
2586       delete compare;
2587     }
2588   }
2589 
2590   /* Hate special cases ... but this is ... expedient.
2591      Due to an ambiguity in the TCS syntax, you cannot easily distinguish
2592      between H.263 and variants such as H,263+. Thus we have to allow for
2593      if we advertise H.263+ the other side may ask for baseline H.263. So
2594      we basically need to include all variants of H.263 if the TCS
2595      capability is there at all.
2596    */
2597   if (dataType.GetTag() == H245_DataType::e_videoData &&
2598       ((const H245_VideoCapability &)dataType).GetTag() == H245_VideoCapability::e_h263VideoCapability) {
2599     H323Capability * capability = FindCapability("*H.263*");
2600     if (capability != NULL)
2601       return capability;
2602   }
2603 
2604 #if PTRACING
2605   if (PTrace::CanTrace(4)) {
2606     PString tagName;
2607     switch (dataType.GetTag()) {
2608       case H245_DataType::e_audioData :
2609         tagName = ((const H245_AudioCapability &)dataType).GetTagName();
2610         break;
2611 
2612       case H245_DataType::e_videoData :
2613         tagName = ((const H245_VideoCapability &)dataType).GetTagName();
2614         break;
2615 
2616       case H245_DataType::e_data :
2617         tagName = ((const H245_DataApplicationCapability &)dataType).m_application.GetTagName();
2618         break;
2619 
2620       default :
2621         tagName = "unknown";
2622         break;
2623     }
2624     PTRACE(4, "H323\tCould not find capability: " << dataType.GetTagName() << ", type " << tagName);
2625   }
2626 #endif
2627   return NULL;
2628 }
2629 
2630 
FindCapability(const H245_ModeElement & modeElement,const PString & mediaPacketization) const2631 H323Capability * H323Capabilities::FindCapability(const H245_ModeElement & modeElement,
2632                                                   const PString & mediaPacketization) const
2633 {
2634   PTRACE(4, "H323\tFindCapability: " << modeElement.m_type.GetTagName());
2635 
2636   for (PINDEX i = 0; i < table.GetSize(); i++) {
2637     H323Capability & capability = table[i];
2638     switch (modeElement.m_type.GetTag()) {
2639       case H245_ModeElementType::e_audioMode :
2640         if (capability.GetMainType() == H323Capability::e_Audio) {
2641           const H245_AudioMode & audio = modeElement.m_type;
2642           if (capability.IsMatch(audio, mediaPacketization))
2643             return &capability;
2644         }
2645         break;
2646 
2647       case H245_ModeElementType::e_videoMode :
2648         if (capability.GetMainType() == H323Capability::e_Video) {
2649           const H245_VideoMode & video = modeElement.m_type;
2650           if (capability.IsMatch(video, mediaPacketization))
2651             return &capability;
2652         }
2653         break;
2654 
2655       case H245_ModeElementType::e_dataMode :
2656         if (capability.GetMainType() == H323Capability::e_Data) {
2657           const H245_DataMode & data = modeElement.m_type;
2658           if (capability.IsMatch(data.m_application, mediaPacketization))
2659             return &capability;
2660         }
2661         break;
2662 
2663       default :
2664         break;
2665     }
2666   }
2667 
2668 #if PTRACING
2669   if (PTrace::CanTrace(4)) {
2670     PString tagName;
2671     switch (modeElement.m_type.GetTag()) {
2672       case H245_ModeElementType::e_audioMode :
2673         tagName = ((const H245_AudioMode &)modeElement.m_type).GetTagName();
2674         break;
2675 
2676       case H245_ModeElementType::e_videoMode :
2677         tagName = ((const H245_VideoMode &)modeElement.m_type).GetTagName();
2678         break;
2679 
2680       case H245_ModeElementType::e_dataMode :
2681         tagName = ((const H245_DataMode &)modeElement.m_type).m_application.GetTagName();
2682         break;
2683 
2684       default :
2685         tagName = "unknown";
2686         break;
2687     }
2688     PTRACE(4, "H323\tCould not find capability: " << modeElement.m_type.GetTagName() << ", type " << tagName);
2689   }
2690 #endif
2691   return NULL;
2692 }
2693 
2694 
FindCapability(H323Capability::MainTypes mainType,unsigned subType) const2695 H323Capability * H323Capabilities::FindCapability(H323Capability::MainTypes mainType,
2696                                                   unsigned subType) const
2697 {
2698   for (PINDEX i = 0; i < table.GetSize(); i++) {
2699     H323Capability & capability = table[i];
2700     if (capability.GetMainType() == mainType &&
2701                         (subType == UINT_MAX || capability.GetSubType() == subType)) {
2702       PTRACE(3, "H323\tFound capability: " << capability);
2703       return &capability;
2704     }
2705   }
2706 
2707   PTRACE(4, "H323\tCould not find capability: " << mainType << " subtype=" << subType);
2708   return NULL;
2709 }
2710 
2711 
BuildPDU(const H323Connection & connection,H245_TerminalCapabilitySet & pdu) const2712 void H323Capabilities::BuildPDU(const H323Connection & connection,
2713                                 H245_TerminalCapabilitySet & pdu) const
2714 {
2715   PINDEX tableSize = table.GetSize();
2716   PINDEX setSize = set.GetSize();
2717   PAssert((tableSize > 0) == (setSize > 0), PLogicError);
2718   if (tableSize == 0 || setSize == 0)
2719     return;
2720 
2721   // Set the table of capabilities
2722   pdu.IncludeOptionalField(H245_TerminalCapabilitySet::e_capabilityTable);
2723 
2724   H245_H2250Capability & h225_0 = pdu.m_multiplexCapability;
2725   PINDEX rtpPacketizationCount = 0;
2726 
2727   // encode the capabilities
2728   PINDEX count = 0;
2729   PINDEX i;
2730   for (i = 0; i < tableSize; i++) {
2731     H323Capability & capability = table[i];
2732     if (capability.IsUsable(connection)) {
2733       pdu.m_capabilityTable.SetSize(count+1);
2734       H245_CapabilityTableEntry & entry = pdu.m_capabilityTable[count++];
2735       entry.m_capabilityTableEntryNumber = capability.GetCapabilityNumber();
2736       entry.IncludeOptionalField(H245_CapabilityTableEntry::e_capability);
2737       capability.GetWritableMediaFormat().ToCustomisedOptions();
2738       if (capability.OnSendingPDU(entry.m_capability))
2739         H323SetRTPPacketization(h225_0.m_mediaPacketizationCapability.m_rtpPayloadType, rtpPacketizationCount,
2740                                 capability.GetMediaFormat(), RTP_DataFrame::IllegalPayloadType);
2741       else
2742         pdu.m_capabilityTable.SetSize(count);
2743     }
2744   }
2745 
2746   // Have some mediaPacketizations to include.
2747   if (rtpPacketizationCount > 0) {
2748     h225_0.m_mediaPacketizationCapability.m_rtpPayloadType.SetSize(rtpPacketizationCount);
2749     h225_0.m_mediaPacketizationCapability.IncludeOptionalField(H245_MediaPacketizationCapability::e_rtpPayloadType);
2750   }
2751 
2752   // Set the sets of compatible capabilities
2753   pdu.IncludeOptionalField(H245_TerminalCapabilitySet::e_capabilityDescriptors);
2754 
2755   pdu.m_capabilityDescriptors.SetSize(setSize);
2756   for (PINDEX outer = 0; outer < setSize; outer++) {
2757     H245_CapabilityDescriptor & desc = pdu.m_capabilityDescriptors[outer];
2758     desc.m_capabilityDescriptorNumber = (unsigned)(outer + 1);
2759     desc.IncludeOptionalField(H245_CapabilityDescriptor::e_simultaneousCapabilities);
2760     PINDEX middleSize = set[outer].GetSize();
2761     desc.m_simultaneousCapabilities.SetSize(middleSize);
2762     for (PINDEX middle = 0; middle < middleSize; middle++) {
2763       H245_AlternativeCapabilitySet & alt = desc.m_simultaneousCapabilities[middle];
2764       PINDEX innerSize = set[outer][middle].GetSize();
2765       alt.SetSize(innerSize);
2766       count = 0;
2767       for (PINDEX inner = 0; inner < innerSize; inner++) {
2768         H323Capability & capability = set[outer][middle][inner];
2769         if (capability.IsUsable(connection)) {
2770           alt.SetSize(count+1);
2771           alt[count++] = capability.GetCapabilityNumber();
2772         }
2773       }
2774     }
2775   }
2776 }
2777 
2778 
Merge(const H323Capabilities & newCaps)2779 PBoolean H323Capabilities::Merge(const H323Capabilities & newCaps)
2780 {
2781   PTRACE_IF(4, !table.IsEmpty(), "H323\tCapability merge of:\n" << newCaps << "\nInto:\n" << *this);
2782 
2783   // Add any new capabilities not already in set.
2784   PINDEX i;
2785   for (i = 0; i < newCaps.GetSize(); i++) {
2786     // Only add if not already in
2787     if (!FindCapability(newCaps[i]))
2788       Copy(newCaps[i]);
2789   }
2790 
2791   // This should merge instead of just adding to it.
2792   PINDEX outerSize = newCaps.set.GetSize();
2793   PINDEX outerBase = set.GetSize();
2794   set.SetSize(outerBase+outerSize);
2795   for (PINDEX outer = 0; outer < outerSize; outer++) {
2796     PINDEX middleSize = newCaps.set[outer].GetSize();
2797     set[outerBase+outer].SetSize(middleSize);
2798     for (PINDEX middle = 0; middle < middleSize; middle++) {
2799       PINDEX innerSize = newCaps.set[outer][middle].GetSize();
2800       for (PINDEX inner = 0; inner < innerSize; inner++) {
2801         H323Capability * cap = FindCapability(newCaps.set[outer][middle][inner].GetCapabilityNumber());
2802         if (cap != NULL)
2803           set[outerBase+outer][middle].Append(cap);
2804       }
2805     }
2806   }
2807 
2808   PTRACE_IF(4, !table.IsEmpty(), "H323\tCapability merge result:\n" << *this);
2809   PTRACE(3, "H323\tReceived capability set, is " << (table.IsEmpty() ? "rejected" : "accepted"));
2810   return !table.IsEmpty();
2811 }
2812 
2813 
Reorder(const PStringArray & preferenceOrder)2814 void H323Capabilities::Reorder(const PStringArray & preferenceOrder)
2815 {
2816   if (preferenceOrder.IsEmpty())
2817     return;
2818 
2819   table.DisallowDeleteObjects();
2820 
2821   PINDEX preference = 0;
2822   PINDEX base = 0;
2823 
2824   for (preference = 0; preference < preferenceOrder.GetSize(); preference++) {
2825     PStringArray wildcard = preferenceOrder[preference].Tokenise('*', PFalse);
2826     for (PINDEX idx = base; idx < table.GetSize(); idx++) {
2827       PCaselessString str = table[idx].GetFormatName();
2828       if (MatchWildcard(str, wildcard)) {
2829         if (idx != base)
2830           table.InsertAt(base, table.RemoveAt(idx));
2831         base++;
2832       }
2833     }
2834   }
2835 
2836   for (PINDEX outer = 0; outer < set.GetSize(); outer++) {
2837     for (PINDEX middle = 0; middle < set[outer].GetSize(); middle++) {
2838       H323CapabilitiesList & list = set[outer][middle];
2839       for (PINDEX idx = 0; idx < table.GetSize(); idx++) {
2840         for (PINDEX inner = 0; inner < list.GetSize(); inner++) {
2841           if (&table[idx] == &list[inner]) {
2842             list.Append(list.RemoveAt(inner));
2843             break;
2844           }
2845         }
2846       }
2847     }
2848   }
2849 
2850   table.AllowDeleteObjects();
2851 }
2852 
2853 
IsAllowed(const H323Capability & capability)2854 PBoolean H323Capabilities::IsAllowed(const H323Capability & capability)
2855 {
2856   return IsAllowed(capability.GetCapabilityNumber());
2857 }
2858 
2859 
IsAllowed(const unsigned a_capno)2860 PBoolean H323Capabilities::IsAllowed(const unsigned a_capno)
2861 {
2862   // Check that capno is actually in the set
2863   PINDEX outerSize = set.GetSize();
2864   for (PINDEX outer = 0; outer < outerSize; outer++) {
2865     PINDEX middleSize = set[outer].GetSize();
2866     for (PINDEX middle = 0; middle < middleSize; middle++) {
2867       PINDEX innerSize = set[outer][middle].GetSize();
2868       for (PINDEX inner = 0; inner < innerSize; inner++) {
2869         if (a_capno == set[outer][middle][inner].GetCapabilityNumber()) {
2870           return PTrue;
2871         }
2872       }
2873     }
2874   }
2875   return PFalse;
2876 }
2877 
2878 
IsAllowed(const H323Capability & capability1,const H323Capability & capability2)2879 PBoolean H323Capabilities::IsAllowed(const H323Capability & capability1,
2880                                  const H323Capability & capability2)
2881 {
2882   return IsAllowed(capability1.GetCapabilityNumber(),
2883                    capability2.GetCapabilityNumber());
2884 }
2885 
2886 
IsAllowed(const unsigned a_capno1,const unsigned a_capno2)2887 PBoolean H323Capabilities::IsAllowed(const unsigned a_capno1, const unsigned a_capno2)
2888 {
2889   if (a_capno1 == a_capno2) {
2890     PTRACE(2, "H323\tH323Capabilities::IsAllowed() capabilities are the same.");
2891     return PTrue;
2892   }
2893 
2894   PINDEX outerSize = set.GetSize();
2895   for (PINDEX outer = 0; outer < outerSize; outer++) {
2896     PINDEX middleSize = set[outer].GetSize();
2897     for (PINDEX middle = 0; middle < middleSize; middle++) {
2898       PINDEX innerSize = set[outer][middle].GetSize();
2899       for (PINDEX inner = 0; inner < innerSize; inner++) {
2900         if (a_capno1 == set[outer][middle][inner].GetCapabilityNumber()) {
2901           /* Now go searching for the other half... */
2902           for (PINDEX middle2 = 0; middle2 < middleSize; ++middle2) {
2903             if (middle != middle2) {
2904               PINDEX innerSize2 = set[outer][middle2].GetSize();
2905               for (PINDEX inner2 = 0; inner2 < innerSize2; ++inner2) {
2906                 if (a_capno2 == set[outer][middle2][inner2].GetCapabilityNumber()) {
2907                   return PTrue;
2908                 }
2909               }
2910             }
2911           }
2912         }
2913       }
2914     }
2915   }
2916   return PFalse;
2917 }
2918 
2919 
GetMediaFormats() const2920 OpalMediaFormatList H323Capabilities::GetMediaFormats() const
2921 {
2922   OpalMediaFormatList formats;
2923 
2924   PINDEX outerSize = set.GetSize();
2925   for (PINDEX outer = 0; outer < outerSize; outer++) {
2926     PINDEX middleSize = set[outer].GetSize();
2927     for (PINDEX middle = 0; middle < middleSize; middle++) {
2928       PINDEX innerSize = set[outer][middle].GetSize();
2929       for (PINDEX inner = 0; inner < innerSize; inner++)
2930         formats += set[outer][middle][inner].GetMediaFormat();
2931     }
2932   }
2933 
2934   for (PINDEX i = 0; i < table.GetSize(); i++)
2935     formats += table[i].GetMediaFormat();
2936 
2937   return formats;
2938 }
2939 
2940 
2941 /////////////////////////////////////////////////////////////////////////////
2942 
2943 #ifndef PASN_NOPRINTON
2944 
2945 
2946 struct msNonStandardCodecDef {
2947   const char * name;
2948   BYTE sig[2];
2949 };
2950 
2951 
2952 static msNonStandardCodecDef msNonStandardCodec[] = {
2953   { "L&H CELP 4.8k", { 0x01, 0x11 } },
2954   { "ADPCM",         { 0x02, 0x00 } },
2955   { "L&H CELP 8k",   { 0x02, 0x11 } },
2956   { "L&H CELP 12k",  { 0x03, 0x11 } },
2957   { "L&H CELP 16k",  { 0x04, 0x11 } },
2958   { "IMA-ADPCM",     { 0x11, 0x00 } },
2959   { "GSM",           { 0x31, 0x00 } },
2960   { NULL,            { 0,    0    } }
2961 };
2962 
PrintOn(ostream & strm) const2963 void H245_AudioCapability::PrintOn(ostream & strm) const
2964 {
2965   strm << GetTagName();
2966 
2967   // tag 0 is nonstandard
2968   if (tag == 0) {
2969 
2970     H245_NonStandardParameter & param = (H245_NonStandardParameter &)GetObject();
2971     const PBYTEArray & data = param.m_data;
2972 
2973     switch (param.m_nonStandardIdentifier.GetTag()) {
2974       case H245_NonStandardIdentifier::e_h221NonStandard:
2975         {
2976           H245_NonStandardIdentifier_h221NonStandard & h221 = param.m_nonStandardIdentifier;
2977 
2978           // Microsoft is 181/0/21324
2979           if ((h221.m_t35CountryCode   == 181) &&
2980               (h221.m_t35Extension     == 0) &&
2981               (h221.m_manufacturerCode == 21324)
2982             ) {
2983             PString name = "Unknown";
2984             PINDEX i;
2985             if (data.GetSize() >= 21) {
2986               for (i = 0; msNonStandardCodec[i].name != NULL; i++) {
2987                 if ((data[20] == msNonStandardCodec[i].sig[0]) &&
2988                     (data[21] == msNonStandardCodec[i].sig[1])) {
2989                   name = msNonStandardCodec[i].name;
2990                   break;
2991                 }
2992               }
2993             }
2994             strm << (PString(" [Microsoft") & name) << "]";
2995           }
2996 
2997           // Equivalence is 9/0/61
2998           else if ((h221.m_t35CountryCode   == 9) &&
2999                    (h221.m_t35Extension     == 0) &&
3000                    (h221.m_manufacturerCode == 61)
3001                   ) {
3002             PString name;
3003             if (data.GetSize() > 0)
3004               name = PString((const char *)(const BYTE *)data, data.GetSize());
3005             strm << " [Equivalence " << name << "]";
3006           }
3007 
3008           // Xiph is 181/0/38
3009           else if ((h221.m_t35CountryCode   == 181) &&
3010                    (h221.m_t35Extension     == 0) &&
3011                    (h221.m_manufacturerCode == 38)
3012                   ) {
3013             PString name;
3014             if (data.GetSize() > 0)
3015               name = PString((const char *)(const BYTE *)data, data.GetSize());
3016             strm << " [Xiph " << name << "]";
3017           }
3018 
3019           // Cisco is 181/0/18
3020           else if ((h221.m_t35CountryCode   == 181) &&
3021                    (h221.m_t35Extension     == 0) &&
3022                    (h221.m_manufacturerCode == 18)
3023                   ) {
3024             PString name;
3025             if (data.GetSize() > 0)
3026               name = PString((const char *)(const BYTE *)data, data.GetSize());
3027             strm << " [Cisco " << name << "]";
3028           }
3029 
3030         }
3031         break;
3032       default:
3033         break;
3034     }
3035   }
3036 
3037   if (choice == NULL)
3038     strm << " (NULL)";
3039   else {
3040     strm << ' ' << *choice;
3041   }
3042 
3043   //PASN_Choice::PrintOn(strm);
3044 }
3045 
3046 #endif // PASN_NOPRINTON
3047 
3048 #endif // OPAL_H323
3049