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