1 /*
2 * h224.cxx
3 *
4 * H.224 implementation for the OpenH323 Project.
5 *
6 * Copyright (c) 2006 Network for Educational Technology, ETH Zurich.
7 * Written by Hannes Friederich.
8 *
9 * The contents of this file are subject to the Mozilla Public License
10 * Version 1.0 (the "License"); you may not use this file except in
11 * compliance with the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
13 *
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16 * the License for the specific language governing rights and limitations
17 * under the License.
18 *
19 * Contributor(s): ______________________________________.
20 *
21 * $Revision: 27149 $
22 * $Author: rjongbloed $
23 * $Date: 2012-03-07 18:32:36 -0600 (Wed, 07 Mar 2012) $
24 */
25
26 /*
27 This file implements H.224 as part of H.323, as well as RFC 4573 for H.224 over SIP
28 */
29
30 #include <ptlib.h>
31
32 #include <opal/buildopts.h>
33
34 #ifdef __GNUC__
35 #pragma implementation "h224.h"
36 #pragma implementation "h224handler.h"
37 #endif
38
39 #if OPAL_HAS_H224
40
41 #include <h224/h224.h>
42 #include <h224/h224handler.h>
43
44 #if OPAL_SIP
45 #include <sip/sdp.h>
46 #endif
47
48 #define H224_MAX_HEADER_SIZE 6+5
49
50 /////////////////////////////////////////////////////////////////////////
51
52 OPAL_INSTANTIATE_MEDIATYPE(h224, OpalH224MediaType);
53
OpalH224MediaType()54 OpalH224MediaType::OpalH224MediaType()
55 : OpalRTPAVPMediaType("h224", "application")
56 {
57 }
58
MediaType()59 const OpalMediaType & OpalH224MediaType::MediaType()
60 {
61 static const OpalMediaType type = "h224";
62 return type;
63 }
64
65 #if OPAL_SIP
66
67 class SDPH224MediaDescription : public SDPRTPAVPMediaDescription
68 {
69 PCLASSINFO(SDPH224MediaDescription, SDPRTPAVPMediaDescription);
70 public:
SDPH224MediaDescription(const OpalTransportAddress & address)71 SDPH224MediaDescription(const OpalTransportAddress & address)
72 : SDPRTPAVPMediaDescription(address, OpalH224MediaType::MediaType())
73 {
74 }
75
CreateEmpty() const76 virtual SDPMediaDescription * CreateEmpty() const
77 {
78 return new SDPH224MediaDescription(OpalTransportAddress());
79 }
80
GetSDPMediaType() const81 virtual PString GetSDPMediaType() const
82 {
83 return "application";
84 }
85 };
86
CreateSDPMediaDescription(const OpalTransportAddress & localAddress)87 SDPMediaDescription * OpalH224MediaType::CreateSDPMediaDescription(const OpalTransportAddress & localAddress)
88 {
89 return new SDPH224MediaDescription(localAddress);
90 }
91
92 #endif
93
94 /////////////////////////////////////////////////////////////////////////
95
GetOpalH224_H323AnnexQ()96 const OpalMediaFormat & GetOpalH224_H323AnnexQ()
97 {
98 static class H224_AnnexQ_MediaFormat : public OpalH224MediaFormat {
99 public:
100 H224_AnnexQ_MediaFormat()
101 : OpalH224MediaFormat("H.224/H323AnnexQ", RTP_DataFrame::DynamicBase)
102 {
103 OpalMediaOption * option = new OpalMediaOptionBoolean("HDLC Tunneling", true, OpalMediaOption::MinMerge, false);
104 AddOption(option);
105 }
106 } const h224q;
107 return h224q;
108 };
109
GetOpalH224_HDLCTunneling()110 const OpalMediaFormat & GetOpalH224_HDLCTunneling()
111 {
112 static class H224_HDLCTunneling_MediaFormat : public OpalH224MediaFormat {
113 public:
114 H224_HDLCTunneling_MediaFormat()
115 : OpalH224MediaFormat("H.224/HDLCTunneling", RTP_DataFrame::MaxPayloadType) // HDLC tunnelled is not sent over RTP
116 {
117 OpalMediaOption * option = new OpalMediaOptionBoolean("HDLC Tunneling", true, OpalMediaOption::MinMerge, true);
118 AddOption(option);
119 }
120 } const h224h;
121 return h224h;
122 }
123
OpalH224MediaFormat(const char * fullName,RTP_DataFrame::PayloadTypes rtpPayloadType)124 OpalH224MediaFormat::OpalH224MediaFormat(
125 const char * fullName, ///< Full name of media format
126 RTP_DataFrame::PayloadTypes rtpPayloadType ///< RTP payload type code
127 )
128 : OpalMediaFormat(fullName,
129 "h224",
130 rtpPayloadType,
131 "h224",
132 PFalse,
133 6400, // 6.4kbit/s as defined in RFC 4573
134 0,
135 0,
136 4800, // As defined in RFC 4573
137 0)
138 {
139 }
140
Clone() const141 PObject * OpalH224MediaFormat::Clone() const
142 {
143 return new OpalH224MediaFormat(*this);
144 }
145
IsValidForProtocol(const PString & protocol) const146 PBoolean OpalH224MediaFormat::IsValidForProtocol(const PString & protocol) const
147 {
148 // HDLC tunnelling only makes sense for H.323. Everything else uses RTP;
149 return !GetOptionBoolean("HDLC Tunneling") || (protocol == "h323");
150 }
151
152 /////////////////////////////////////////////////////////////////////////
153
H224_Frame(PINDEX size)154 H224_Frame::H224_Frame(PINDEX size)
155 : Q922_Frame(H224_MAX_HEADER_SIZE + size)
156 {
157 SetHighPriority(PFalse);
158 SetControlFieldOctet(0x03); // UI-Mode
159 SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
160 SetSourceTerminalAddress(OpalH224Handler::Broadcast);
161
162 // setting Client ID to CME
163 SetClientID(OpalH224Client::CMEClientID);
164
165 // Setting ES / BS / C1 / C0 / Segment number to zero
166 SetBS(PFalse);
167 SetES(PFalse);
168 SetC1(PFalse);
169 SetC0(PFalse);
170 SetSegmentNumber(0x00);
171
172 SetClientDataSize(size);
173 }
174
H224_Frame(const OpalH224Client & h224Client,PINDEX size)175 H224_Frame::H224_Frame(const OpalH224Client & h224Client, PINDEX size)
176 : Q922_Frame(H224_MAX_HEADER_SIZE + size)
177 {
178 SetHighPriority(PFalse);
179 SetControlFieldOctet(0x03); // UI-Mode
180 SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
181 SetSourceTerminalAddress(OpalH224Handler::Broadcast);
182
183 SetClient(h224Client);
184
185 // Setting ES / BS / C1 / C0 / Segment number to zero
186 SetBS(PFalse);
187 SetES(PFalse);
188 SetC1(PFalse);
189 SetC0(PFalse);
190 SetSegmentNumber(0x00);
191
192 SetClientDataSize(size);
193 }
194
~H224_Frame()195 H224_Frame::~H224_Frame()
196 {
197 }
198
SetHighPriority(PBoolean flag)199 void H224_Frame::SetHighPriority(PBoolean flag)
200 {
201 SetHighOrderAddressOctet(0x00);
202
203 if (flag) {
204 SetLowOrderAddressOctet(0x71);
205 } else {
206 SetLowOrderAddressOctet(0x061);
207 }
208 }
209
GetDestinationTerminalAddress() const210 WORD H224_Frame::GetDestinationTerminalAddress() const
211 {
212 BYTE *data = GetInformationFieldPtr();
213 return (WORD)((data[0] << 8) | data[1]);
214 }
215
SetDestinationTerminalAddress(WORD address)216 void H224_Frame::SetDestinationTerminalAddress(WORD address)
217 {
218 BYTE *data = GetInformationFieldPtr();
219 data[0] = (BYTE)(address >> 8);
220 data[1] = (BYTE) address;
221 }
222
GetSourceTerminalAddress() const223 WORD H224_Frame::GetSourceTerminalAddress() const
224 {
225 BYTE *data = GetInformationFieldPtr();
226 return (WORD)((data[2] << 8) | data[3]);
227 }
228
SetSourceTerminalAddress(WORD address)229 void H224_Frame::SetSourceTerminalAddress(WORD address)
230 {
231 BYTE *data = GetInformationFieldPtr();
232 data[2] = (BYTE)(address >> 8);
233 data[3] = (BYTE) address;
234 }
235
SetClient(const OpalH224Client & h224Client)236 void H224_Frame::SetClient(const OpalH224Client & h224Client)
237 {
238 BYTE clientID = h224Client.GetClientID();
239
240 SetClientID(clientID);
241
242 if (clientID == OpalH224Client::ExtendedClientID) {
243 SetExtendedClientID(h224Client.GetExtendedClientID());
244
245 } else if (clientID == OpalH224Client::NonStandardClientID) {
246 SetNonStandardClientInformation(h224Client.GetCountryCode(),
247 h224Client.GetCountryCodeExtension(),
248 h224Client.GetManufacturerCode(),
249 h224Client.GetManufacturerClientID());
250 }
251 }
252
GetClientID() const253 BYTE H224_Frame::GetClientID() const
254 {
255 BYTE *data = GetInformationFieldPtr();
256 return data[4] & 0x7f;
257 }
258
SetClientID(BYTE clientID)259 void H224_Frame::SetClientID(BYTE clientID)
260 {
261 BYTE *data = GetInformationFieldPtr();
262 data[4] = (clientID & 0x7f);
263 }
264
GetExtendedClientID() const265 BYTE H224_Frame::GetExtendedClientID() const
266 {
267 if (GetClientID() != OpalH224Client::ExtendedClientID) {
268 return 0x00;
269 }
270
271 BYTE *data = GetInformationFieldPtr();
272 return data[5];
273 }
274
SetExtendedClientID(BYTE extendedClientID)275 void H224_Frame::SetExtendedClientID(BYTE extendedClientID)
276 {
277 if (GetClientID() != OpalH224Client::ExtendedClientID) {
278 return;
279 }
280
281 BYTE *data = GetInformationFieldPtr();
282 data[5] = extendedClientID;
283 }
284
GetCountryCode() const285 BYTE H224_Frame::GetCountryCode() const
286 {
287 if (GetClientID() != OpalH224Client::NonStandardClientID) {
288 return 0x00;
289 }
290
291 BYTE *data = GetInformationFieldPtr();
292 return data[5];
293 }
294
GetCountryCodeExtension() const295 BYTE H224_Frame::GetCountryCodeExtension() const
296 {
297 if (GetClientID() != OpalH224Client::NonStandardClientID) {
298 return 0x00;
299 }
300
301 BYTE *data = GetInformationFieldPtr();
302 return data[6];
303 }
304
GetManufacturerCode() const305 WORD H224_Frame::GetManufacturerCode() const
306 {
307 if (GetClientID() != OpalH224Client::NonStandardClientID) {
308 return 0x0000;
309 }
310
311 BYTE *data = GetInformationFieldPtr();
312 return (((WORD)data[7] << 8) | (WORD)data[8]);
313 }
314
GetManufacturerClientID() const315 BYTE H224_Frame::GetManufacturerClientID() const
316 {
317 if (GetClientID() != OpalH224Client::NonStandardClientID) {
318 return 0x00;
319 }
320
321 BYTE *data = GetInformationFieldPtr();
322 return data[9];
323 }
324
SetNonStandardClientInformation(BYTE countryCode,BYTE countryCodeExtension,WORD manufacturerCode,BYTE manufacturerClientID)325 void H224_Frame::SetNonStandardClientInformation(BYTE countryCode,
326 BYTE countryCodeExtension,
327 WORD manufacturerCode,
328 BYTE manufacturerClientID)
329 {
330 if (GetClientID() != OpalH224Client::NonStandardClientID) {
331 return;
332 }
333
334 BYTE *data = GetInformationFieldPtr();
335
336 data[5] = countryCode;
337 data[6] = countryCodeExtension;
338 data[7] = (BYTE)(manufacturerCode << 8);
339 data[8] = (BYTE) manufacturerCode;
340 data[9] = manufacturerClientID;
341 }
342
GetBS() const343 PBoolean H224_Frame::GetBS() const
344 {
345 BYTE *data = GetInformationFieldPtr();
346
347 return (data[5] & 0x80) != 0;
348 }
349
SetBS(PBoolean flag)350 void H224_Frame::SetBS(PBoolean flag)
351 {
352 BYTE *data = GetInformationFieldPtr();
353
354 if (flag) {
355 data[5] |= 0x80;
356 } else {
357 data[5] &= 0x7f;
358 }
359 }
360
GetES() const361 PBoolean H224_Frame::GetES() const
362 {
363 BYTE *data = GetInformationFieldPtr();
364
365 return (data[5] & 0x40) != 0;
366 }
367
SetES(PBoolean flag)368 void H224_Frame::SetES(PBoolean flag)
369 {
370 BYTE *data = GetInformationFieldPtr();
371
372 if (flag) {
373 data[5] |= 0x40;
374 } else {
375 data[5] &= 0xbf;
376 }
377 }
378
GetC1() const379 PBoolean H224_Frame::GetC1() const
380 {
381 BYTE *data = GetInformationFieldPtr();
382
383 return (data[5] & 0x20) != 0;
384 }
385
SetC1(PBoolean flag)386 void H224_Frame::SetC1(PBoolean flag)
387 {
388 BYTE *data = GetInformationFieldPtr();
389
390 if (flag) {
391 data[5] |= 0x20;
392 } else {
393 data[5] &= 0xdf;
394 }
395 }
396
GetC0() const397 PBoolean H224_Frame::GetC0() const
398 {
399 BYTE *data = GetInformationFieldPtr();
400
401 return (data[5] & 0x10) != 0;
402 }
403
SetC0(PBoolean flag)404 void H224_Frame::SetC0(PBoolean flag)
405 {
406 BYTE *data = GetInformationFieldPtr();
407
408 if (flag) {
409 data[5] |= 0x10;
410 } else {
411 data[5] &= 0xef;
412 }
413 }
414
GetSegmentNumber() const415 BYTE H224_Frame::GetSegmentNumber() const
416 {
417 BYTE *data = GetInformationFieldPtr();
418
419 return (data[5] & 0x0f);
420 }
421
SetSegmentNumber(BYTE segmentNumber)422 void H224_Frame::SetSegmentNumber(BYTE segmentNumber)
423 {
424 BYTE *data = GetInformationFieldPtr();
425
426 data[5] &= 0xf0;
427 data[5] |= (segmentNumber & 0x0f);
428 }
429
GetClientDataPtr() const430 BYTE * H224_Frame::GetClientDataPtr() const
431 {
432 BYTE * data = GetInformationFieldPtr();
433 return (data + GetHeaderSize());
434 }
435
GetClientDataSize() const436 PINDEX H224_Frame::GetClientDataSize() const
437 {
438 PINDEX size = GetInformationFieldSize();
439 return (size - GetHeaderSize());
440 }
441
SetClientDataSize(PINDEX size)442 void H224_Frame::SetClientDataSize(PINDEX size)
443 {
444 SetInformationFieldSize(size + GetHeaderSize());
445 }
446
DecodeAnnexQ(const BYTE * data,PINDEX size)447 PBoolean H224_Frame::DecodeAnnexQ(const BYTE *data, PINDEX size)
448 {
449 PBoolean result = Q922_Frame::DecodeAnnexQ(data, size);
450
451 if (result == PFalse) {
452 return PFalse;
453 }
454
455 // doing some validity checks for H.224 frames
456 BYTE highOrderAddressOctet = GetHighOrderAddressOctet();
457 BYTE lowOrderAddressOctet = GetLowOrderAddressOctet();
458 BYTE controlFieldOctet = GetControlFieldOctet();
459
460 if ((highOrderAddressOctet != 0x00) ||
461 (!(lowOrderAddressOctet == 0x61 || lowOrderAddressOctet == 0x71)) ||
462 (controlFieldOctet != 0x03)) {
463 return PFalse;
464 }
465
466 return PTrue;
467
468 }
469
DecodeHDLC(const BYTE * data,PINDEX size)470 PBoolean H224_Frame::DecodeHDLC(const BYTE *data, PINDEX size)
471 {
472 PBoolean result = Q922_Frame::DecodeHDLC(data, size);
473
474 if (result == PFalse) {
475 return PFalse;
476 }
477
478 // doing some validity checks for H.224 frames
479 BYTE highOrderAddressOctet = GetHighOrderAddressOctet();
480 BYTE lowOrderAddressOctet = GetLowOrderAddressOctet();
481 BYTE controlFieldOctet = GetControlFieldOctet();
482
483 if ((highOrderAddressOctet != 0x00) ||
484 (!(lowOrderAddressOctet == 0x61 || lowOrderAddressOctet == 0x71)) ||
485 (controlFieldOctet != 0x03)) {
486 return PFalse;
487 }
488
489 return PTrue;
490 }
491
GetHeaderSize() const492 PINDEX H224_Frame::GetHeaderSize() const
493 {
494 BYTE clientID = GetClientID();
495
496 if (clientID < OpalH224Client::ExtendedClientID) {
497 return 6;
498 } else if (clientID == OpalH224Client::ExtendedClientID) {
499 return 7; // one extra octet
500 } else {
501 return 11; // 5 extra octets
502 }
503 }
504
505 ////////////////////////////////////
506
OpalH224Handler()507 OpalH224Handler::OpalH224Handler()
508 : transmitMutex(),
509 transmitFrame(300),
510 receiveFrame()
511 {
512 canTransmit = PFalse;
513 transmitBitIndex = 7;
514 transmitStartTime = NULL;
515 transmitMediaStream = NULL;
516
517 transmitHDLCTunneling = PFalse;
518 receiveHDLCTunneling = PFalse;
519
520 clients.DisallowDeleteObjects();
521 }
522
~OpalH224Handler()523 OpalH224Handler::~OpalH224Handler()
524 {
525 }
526
AddClient(OpalH224Client & client)527 PBoolean OpalH224Handler::AddClient(OpalH224Client & client)
528 {
529 if (client.GetClientID() == OpalH224Client::CMEClientID) {
530 return PFalse; // No client may have CMEClientID
531 }
532
533 if (clients.GetObjectsIndex(&client) != P_MAX_INDEX) {
534 return PFalse; // Only allow one instance of a client
535 }
536
537 clients.Append(&client);
538 client.SetH224Handler(this);
539 return PTrue;
540 }
541
RemoveClient(OpalH224Client & client)542 PBoolean OpalH224Handler::RemoveClient(OpalH224Client & client)
543 {
544 PBoolean result = clients.Remove(&client);
545 if (result == PTrue) {
546 client.SetH224Handler(NULL);
547 }
548 return result;
549 }
550
SetTransmitMediaFormat(const OpalMediaFormat & mediaFormat)551 void OpalH224Handler::SetTransmitMediaFormat(const OpalMediaFormat & mediaFormat)
552 {
553 PAssert(mediaFormat.GetMediaType() == "h224", "H.224 handler passed incorrect media format");
554 transmitHDLCTunneling = mediaFormat.GetOptionBoolean("HDLC Tunneling");
555 }
556
SetReceiveMediaFormat(const OpalMediaFormat & mediaFormat)557 void OpalH224Handler::SetReceiveMediaFormat(const OpalMediaFormat & mediaFormat)
558 {
559 PAssert(mediaFormat.GetMediaType() == "h224", "H.224 handler passed incorrect media format");
560 receiveHDLCTunneling = mediaFormat.GetOptionBoolean("HDLC Tunneling");
561 }
562
SetTransmitMediaStream(OpalH224MediaStream * mediaStream)563 void OpalH224Handler::SetTransmitMediaStream(OpalH224MediaStream * mediaStream)
564 {
565 PWaitAndSignal m(transmitMutex);
566
567 transmitMediaStream = mediaStream;
568
569 if (transmitMediaStream != NULL) {
570 transmitFrame.SetPayloadType(transmitMediaStream->GetMediaFormat().GetPayloadType());
571 }
572 }
573
StartTransmit()574 void OpalH224Handler::StartTransmit()
575 {
576 PWaitAndSignal m(transmitMutex);
577
578 if (canTransmit == PTrue) {
579 return;
580 }
581
582 canTransmit = PTrue;
583
584 transmitBitIndex = 7;
585 transmitStartTime = new PTime();
586
587 SendClientList();
588 SendExtraCapabilities();
589 }
590
StopTransmit()591 void OpalH224Handler::StopTransmit()
592 {
593 PWaitAndSignal m(transmitMutex);
594
595 if (canTransmit == PFalse) {
596 return;
597 }
598
599 delete transmitStartTime;
600 transmitStartTime = NULL;
601
602 canTransmit = PFalse;
603 }
604
SendClientList()605 PBoolean OpalH224Handler::SendClientList()
606 {
607 PWaitAndSignal m(transmitMutex);
608
609 if (canTransmit == PFalse) {
610 return PFalse;
611 }
612
613 // If all clients are non-standard, 5 octets per clients + 3 octets header information
614 H224_Frame h224Frame = H224_Frame(5*clients.GetSize() + 3);
615
616 h224Frame.SetHighPriority(PTrue);
617 h224Frame.SetDestinationTerminalAddress(Broadcast);
618 h224Frame.SetSourceTerminalAddress(Broadcast);
619
620 // CME frame
621 h224Frame.SetClientID(OpalH224Client::CMEClientID);
622
623 // Begin and end of sequence
624 h224Frame.SetBS(PTrue);
625 h224Frame.SetES(PTrue);
626 h224Frame.SetC1(PFalse);
627 h224Frame.SetC0(PFalse);
628 h224Frame.SetSegmentNumber(0);
629
630 BYTE *ptr = h224Frame.GetClientDataPtr();
631
632 ptr[0] = OpalH224Handler::CMEClientListCode;
633 ptr[1] = OpalH224Handler::CMEMessage;
634 ptr[2] = (BYTE)clients.GetSize();
635
636 PINDEX dataIndex = 3;
637 for (PINDEX i = 0; i < clients.GetSize(); i++) {
638 OpalH224Client & client = clients[i];
639
640 BYTE clientID = client.GetClientID();
641
642 if (client.HasExtraCapabilities()) {
643 ptr[dataIndex] = (0x80 | clientID);
644 } else {
645 ptr[dataIndex] = (0x7f & clientID);
646 }
647 dataIndex++;
648
649 if (clientID == OpalH224Client::ExtendedClientID) {
650 ptr[dataIndex] = client.GetExtendedClientID();
651 dataIndex++;
652
653 } else if (clientID == OpalH224Client::NonStandardClientID) {
654
655 ptr[dataIndex] = client.GetCountryCode();
656 dataIndex++;
657 ptr[dataIndex] = client.GetCountryCodeExtension();
658 dataIndex++;
659
660 WORD manufacturerCode = client.GetManufacturerCode();
661 ptr[dataIndex] = (BYTE)(manufacturerCode >> 8);
662 dataIndex++;
663 ptr[dataIndex] = (BYTE) manufacturerCode;
664 dataIndex++;
665
666 ptr[dataIndex] = client.GetManufacturerClientID();
667 dataIndex++;
668 }
669 }
670
671 h224Frame.SetClientDataSize(dataIndex);
672
673 TransmitFrame(h224Frame);
674
675 return PTrue;
676 }
677
SendExtraCapabilities()678 PBoolean OpalH224Handler::SendExtraCapabilities()
679 {
680 for (PINDEX i = 0; i < clients.GetSize(); i++) {
681 OpalH224Client & client = clients[i];
682 client.SendExtraCapabilities();
683 }
684
685 return PTrue;
686 }
687
SendClientListCommand()688 PBoolean OpalH224Handler::SendClientListCommand()
689 {
690 PWaitAndSignal m(transmitMutex);
691
692 if (canTransmit == PFalse) {
693 return PFalse;
694 }
695
696 H224_Frame h224Frame = H224_Frame(2);
697 h224Frame.SetHighPriority(PTrue);
698 h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
699 h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
700
701 // CME frame
702 h224Frame.SetClientID(OpalH224Client::CMEClientID);
703
704 // Begin and end of sequence
705 h224Frame.SetBS(PTrue);
706 h224Frame.SetES(PTrue);
707 h224Frame.SetC1(PFalse);
708 h224Frame.SetC0(PFalse);
709 h224Frame.SetSegmentNumber(0);
710
711 BYTE *ptr = h224Frame.GetClientDataPtr();
712
713 ptr[0] = OpalH224Handler::CMEClientListCode;
714 ptr[1] = OpalH224Handler::CMECommand;
715
716 TransmitFrame(h224Frame);
717
718 return PTrue;
719 }
720
SendExtraCapabilitiesCommand(const OpalH224Client & client)721 PBoolean OpalH224Handler::SendExtraCapabilitiesCommand(const OpalH224Client & client)
722 {
723 PWaitAndSignal m(transmitMutex);
724
725 if (canTransmit == PFalse) {
726 return PFalse;
727 }
728
729 if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
730 return PFalse; // only allow if the client is really registered
731 }
732
733 H224_Frame h224Frame = H224_Frame(8);
734 h224Frame.SetHighPriority(PTrue);
735 h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
736 h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
737
738 // CME frame
739 h224Frame.SetClientID(OpalH224Client::CMEClientID);
740
741 // Begin and end of sequence
742 h224Frame.SetBS(PTrue);
743 h224Frame.SetES(PTrue);
744 h224Frame.SetC1(PFalse);
745 h224Frame.SetC0(PFalse);
746 h224Frame.SetSegmentNumber(0);
747
748 BYTE *ptr = h224Frame.GetClientDataPtr();
749
750 ptr[0] = OpalH224Handler::CMEExtraCapabilitiesCode;
751 ptr[1] = OpalH224Handler::CMECommand;
752
753 PINDEX dataSize;
754
755 BYTE extendedCapabilitiesFlag = client.HasExtraCapabilities() ? 0x80 : 0x00;
756 BYTE clientID = client.GetClientID();
757 ptr[2] = (extendedCapabilitiesFlag | (clientID & 0x7f));
758
759 if (clientID < OpalH224Client::ExtendedClientID) {
760 dataSize = 3;
761 } else if (clientID == OpalH224Client::ExtendedClientID) {
762 ptr[3] = client.GetExtendedClientID();
763 dataSize = 4;
764 } else {
765 ptr[3] = client.GetCountryCode();
766 ptr[4] = client.GetCountryCodeExtension();
767
768 WORD manufacturerCode = client.GetManufacturerCode();
769 ptr[5] = (BYTE)(manufacturerCode >> 8);
770 ptr[6] = (BYTE) manufacturerCode;
771
772 ptr[7] = client.GetManufacturerClientID();
773 dataSize = 8;
774 }
775 h224Frame.SetClientDataSize(dataSize);
776
777 TransmitFrame(h224Frame);
778
779 return PTrue;
780 }
781
SendExtraCapabilitiesMessage(const OpalH224Client & client,BYTE * data,PINDEX length)782 PBoolean OpalH224Handler::SendExtraCapabilitiesMessage(const OpalH224Client & client,
783 BYTE *data, PINDEX length)
784 {
785 PWaitAndSignal m(transmitMutex);
786
787 if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
788 return PFalse; // Only allow if the client is really registered
789 }
790
791 H224_Frame h224Frame = H224_Frame(length+3);
792 h224Frame.SetHighPriority(PTrue);
793 h224Frame.SetDestinationTerminalAddress(OpalH224Handler::Broadcast);
794 h224Frame.SetSourceTerminalAddress(OpalH224Handler::Broadcast);
795
796 // use clientID zero to indicate a CME frame
797 h224Frame.SetClientID(OpalH224Client::CMEClientID);
798
799 // Begin and end of sequence, rest is zero
800 h224Frame.SetBS(PTrue);
801 h224Frame.SetES(PTrue);
802 h224Frame.SetC1(PFalse);
803 h224Frame.SetC0(PFalse);
804 h224Frame.SetSegmentNumber(0);
805
806 BYTE *ptr = h224Frame.GetClientDataPtr();
807
808 ptr[0] = CMEExtraCapabilitiesCode;
809 ptr[1] = CMEMessage;
810
811 PINDEX headerSize;
812 BYTE clientID = client.GetClientID();
813 BYTE extendedCapabilitiesFlag = client.HasExtraCapabilities() ? 0x80 : 0x00;
814
815 ptr[2] = (extendedCapabilitiesFlag | (clientID & 0x7f));
816
817 if (clientID < OpalH224Client::ExtendedClientID) {
818 headerSize = 3;
819 } else if (clientID == OpalH224Client::ExtendedClientID) {
820 ptr[3] = client.GetExtendedClientID();
821 headerSize = 4;
822 } else {
823 ptr[3] = client.GetCountryCode();
824 ptr[4] = client.GetCountryCodeExtension();
825
826 WORD manufacturerCode = client.GetManufacturerCode();
827 ptr[5] = (BYTE) (manufacturerCode >> 8);
828 ptr[6] = (BYTE) manufacturerCode;
829
830 ptr[7] = client.GetManufacturerClientID();
831 headerSize = 8;
832 }
833
834 h224Frame.SetClientDataSize(length+headerSize);
835 memcpy(ptr+headerSize, data, length);
836
837 TransmitFrame(h224Frame);
838
839 return PTrue;
840 }
841
TransmitClientFrame(const OpalH224Client & client,H224_Frame & frame)842 PBoolean OpalH224Handler::TransmitClientFrame(const OpalH224Client & client, H224_Frame & frame)
843 {
844 PWaitAndSignal m(transmitMutex);
845
846 if (canTransmit == PFalse) {
847 return PFalse;
848 }
849
850 if (clients.GetObjectsIndex(&client) == P_MAX_INDEX) {
851 return PFalse; // Only allow if the client is really registered
852 }
853
854 TransmitFrame(frame);
855
856 return PTrue;
857 }
858
OnReceivedFrame(H224_Frame & frame)859 PBoolean OpalH224Handler::OnReceivedFrame(H224_Frame & frame)
860 {
861 if (frame.GetDestinationTerminalAddress() != OpalH224Handler::Broadcast) {
862 // only broadcast frames are handled at the moment
863 PTRACE(3, "H.224\tReceived frame with non-broadcast address");
864 return PTrue;
865 }
866 BYTE clientID = frame.GetClientID();
867
868 if (clientID == OpalH224Client::CMEClientID) {
869 return OnReceivedCMEMessage(frame);
870 }
871
872 for (PINDEX i = 0; i < clients.GetSize(); i++) {
873 OpalH224Client & client = clients[i];
874 if (client.GetClientID() == clientID) {
875 PBoolean found = PFalse;
876 if (clientID < OpalH224Client::ExtendedClientID) {
877 found = PTrue;
878 } else if (clientID == OpalH224Client::ExtendedClientID) {
879 if (client.GetExtendedClientID() == frame.GetExtendedClientID()) {
880 found = PTrue;
881 }
882 } else {
883 if (client.GetCountryCode() == frame.GetCountryCode() &&
884 client.GetCountryCodeExtension() == frame.GetCountryCodeExtension() &&
885 client.GetManufacturerCode() == frame.GetManufacturerCode() &&
886 client.GetManufacturerClientID() == frame.GetManufacturerClientID()) {
887 found = PTrue;
888 }
889 }
890 if (found == PTrue) {
891 client.OnReceivedMessage(frame);
892 return PTrue;
893 }
894 }
895 }
896
897 // ignore if no client found
898
899 return PTrue;
900 }
901
OnReceivedCMEMessage(H224_Frame & frame)902 PBoolean OpalH224Handler::OnReceivedCMEMessage(H224_Frame & frame)
903 {
904 BYTE *data = frame.GetClientDataPtr();
905
906 if (data[0] == CMEClientListCode) {
907
908 if (data[1] == CMEMessage) {
909 return OnReceivedClientList(frame);
910
911 } else if (data[1] == CMECommand) {
912 return OnReceivedClientListCommand();
913 }
914
915 } else if (data[0] == CMEExtraCapabilitiesCode) {
916
917 if (data[1] == CMEMessage) {
918 return OnReceivedExtraCapabilities(frame);
919
920 } else if (data[1] == CMECommand) {
921 return OnReceivedExtraCapabilitiesCommand();
922 }
923 }
924
925 // incorrect frames are simply ignored
926 return PTrue;
927 }
928
OnReceivedClientList(H224_Frame & frame)929 PBoolean OpalH224Handler::OnReceivedClientList(H224_Frame & frame)
930 {
931 // First, reset all clients
932 for (PINDEX i = 0; i < clients.GetSize(); i++)
933 {
934 OpalH224Client & client = clients[i];
935 client.SetRemoteClientAvailable(PFalse, PFalse);
936 }
937
938 BYTE *data = frame.GetClientDataPtr();
939
940 BYTE numberOfClients = data[2];
941
942 PINDEX dataIndex = 3;
943
944 while (numberOfClients > 0) {
945
946 BYTE clientID = (data[dataIndex] & 0x7f);
947 PBoolean hasExtraCapabilities = (data[dataIndex] & 0x80) != 0 ? PTrue: PFalse;
948 dataIndex++;
949 BYTE extendedClientID = 0x00;
950 BYTE countryCode = CountryCodeEscape;
951 BYTE countryCodeExtension = 0x00;
952 WORD manufacturerCode = 0x0000;
953 BYTE manufacturerClientID = 0x00;
954
955 if (clientID == OpalH224Client::ExtendedClientID) {
956 extendedClientID = data[dataIndex];
957 dataIndex++;
958 } else if (clientID == OpalH224Client::NonStandardClientID) {
959 countryCode = data[dataIndex];
960 dataIndex++;
961 countryCodeExtension = data[dataIndex];
962 dataIndex++;
963 manufacturerCode = (((WORD)data[dataIndex] << 8) | (WORD)data[dataIndex+1]);
964 dataIndex += 2;
965 manufacturerClientID = data[dataIndex];
966 dataIndex++;
967 }
968
969 for (PINDEX i = 0; i < clients.GetSize(); i++) {
970 OpalH224Client & client = clients[i];
971 PBoolean found = PFalse;
972 if (client.GetClientID() == clientID) {
973 if (clientID < OpalH224Client::ExtendedClientID) {
974 found = PTrue;
975 } else if (clientID == OpalH224Client::ExtendedClientID) {
976 if (client.GetExtendedClientID() == extendedClientID) {
977 found = PTrue;
978 }
979 } else {
980 if (client.GetCountryCode() == countryCode &&
981 client.GetCountryCodeExtension() == countryCodeExtension &&
982 client.GetManufacturerCode() == manufacturerCode &&
983 client.GetManufacturerClientID() == manufacturerClientID) {
984 found = PTrue;
985 }
986 }
987 }
988 if (found == PTrue) {
989 client.SetRemoteClientAvailable(PTrue, hasExtraCapabilities);
990 break;
991 }
992 }
993 numberOfClients--;
994 }
995
996
997 return PTrue;
998 }
999
OnReceivedClientListCommand()1000 PBoolean OpalH224Handler::OnReceivedClientListCommand()
1001 {
1002 SendClientList();
1003 return PTrue;
1004 }
1005
OnReceivedExtraCapabilities(H224_Frame & frame)1006 PBoolean OpalH224Handler::OnReceivedExtraCapabilities(H224_Frame & frame)
1007 {
1008 BYTE *data = frame.GetClientDataPtr();
1009
1010 BYTE clientID = (data[2] & 0x7f);
1011 PINDEX dataIndex = 0;
1012 BYTE extendedClientID = 0x00;
1013 BYTE countryCode = CountryCodeEscape;
1014 BYTE countryCodeExtension = 0x00;
1015 WORD manufacturerCode = 0x0000;
1016 BYTE manufacturerClientID = 0x00;
1017
1018 if (clientID < OpalH224Client::ExtendedClientID) {
1019 dataIndex = 3;
1020 } else if (clientID == OpalH224Client::ExtendedClientID) {
1021 extendedClientID = data[3];
1022 dataIndex = 4;
1023 } else if (clientID == OpalH224Client::NonStandardClientID) {
1024 countryCode = data[3];
1025 countryCodeExtension = data[4];
1026 manufacturerCode = (((WORD)data[5] << 8) | (WORD)data[6]);
1027 manufacturerClientID = data[7];
1028 dataIndex = 8;
1029 }
1030
1031 for (PINDEX i = 0; i < clients.GetSize(); i++) {
1032 OpalH224Client & client = clients[i];
1033 PBoolean found = PFalse;
1034 if (client.GetClientID() == clientID) {
1035 if (clientID < OpalH224Client::ExtendedClientID) {
1036 found = PTrue;
1037 } else if (clientID == OpalH224Client::ExtendedClientID) {
1038 if (client.GetExtendedClientID() == extendedClientID) {
1039 found = PTrue;
1040 }
1041 } else {
1042 if (client.GetCountryCode() == countryCode &&
1043 client.GetCountryCodeExtension() == countryCodeExtension &&
1044 client.GetManufacturerCode() == manufacturerCode &&
1045 client.GetManufacturerClientID() == manufacturerClientID) {
1046 found = PTrue;
1047 }
1048 }
1049 }
1050 if (found) {
1051 PINDEX size = frame.GetClientDataSize() - dataIndex;
1052 client.SetRemoteClientAvailable(PTrue, PTrue);
1053 client.OnReceivedExtraCapabilities((data + dataIndex), size);
1054 return PTrue;
1055 }
1056 }
1057
1058 // Simply ignore if no client is available for this clientID
1059
1060 return PTrue;
1061 }
1062
OnReceivedExtraCapabilitiesCommand()1063 PBoolean OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
1064 {
1065 SendExtraCapabilities();
1066 return PTrue;
1067 }
1068
HandleFrame(const RTP_DataFrame & dataFrame)1069 PBoolean OpalH224Handler::HandleFrame(const RTP_DataFrame & dataFrame)
1070 {
1071 if (receiveHDLCTunneling) {
1072 if (receiveFrame.DecodeHDLC(dataFrame.GetPayloadPtr(), dataFrame.GetPayloadSize())) {
1073 PBoolean result = OnReceivedFrame(receiveFrame);
1074 return result;
1075 } else {
1076 PTRACE(1, "H224\tDecoding of the frame failed");
1077 return PFalse;
1078 }
1079 } else {
1080 if (receiveFrame.DecodeAnnexQ(dataFrame.GetPayloadPtr(), dataFrame.GetPayloadSize())) {
1081 PBoolean result = OnReceivedFrame(receiveFrame);
1082 return result;
1083 } else {
1084 PTRACE(1, "H224\tDecoding of the frame failed");
1085 return PFalse;
1086 }
1087 }
1088 }
1089
TransmitFrame(H224_Frame & frame)1090 void OpalH224Handler::TransmitFrame(H224_Frame & frame)
1091 {
1092 PINDEX size;
1093 if (transmitHDLCTunneling) {
1094 size = frame.GetHDLCEncodedSize();
1095 transmitFrame.SetMinSize(size);
1096 if (!frame.EncodeHDLC(transmitFrame.GetPayloadPtr(), size, transmitBitIndex)) {
1097 PTRACE(1, "H224\tFailed to encode the frame");
1098 return;
1099 }
1100 } else {
1101 size = frame.GetAnnexQEncodedSize();
1102 transmitFrame.SetMinSize(size);
1103 if (!frame.EncodeAnnexQ(transmitFrame.GetPayloadPtr(), size)) {
1104 PTRACE(1, "H224\tFailed to encode the frame");
1105 return;
1106 }
1107 }
1108
1109 // determining correct timestamp
1110 PTime currentTime = PTime();
1111 PTimeInterval timePassed = currentTime - *transmitStartTime;
1112 transmitFrame.SetTimestamp((DWORD)timePassed.GetMilliSeconds() * 8);
1113
1114 transmitFrame.SetPayloadSize(size);
1115 transmitFrame.SetMarker(PTrue);
1116
1117 if (transmitMediaStream != NULL) {
1118 transmitMediaStream->PushPacket(transmitFrame);
1119 }
1120 }
1121
1122 ////////////////////////////////////
1123
OpalH224MediaStream(OpalConnection & connection,OpalH224Handler & handler,const OpalMediaFormat & mediaFormat,unsigned sessionID,PBoolean isSource)1124 OpalH224MediaStream::OpalH224MediaStream(OpalConnection & connection,
1125 OpalH224Handler & handler,
1126 const OpalMediaFormat & mediaFormat,
1127 unsigned sessionID,
1128 PBoolean isSource)
1129 : OpalMediaStream(connection, mediaFormat, sessionID, isSource),
1130 h224Handler(handler)
1131 {
1132 if (isSource == PTrue) {
1133 h224Handler.SetTransmitMediaFormat(mediaFormat);
1134 h224Handler.SetTransmitMediaStream(this);
1135 } else {
1136 h224Handler.SetReceiveMediaFormat(mediaFormat);
1137 }
1138 }
1139
~OpalH224MediaStream()1140 OpalH224MediaStream::~OpalH224MediaStream()
1141 {
1142 Close();
1143 }
1144
OnStartMediaPatch()1145 void OpalH224MediaStream::OnStartMediaPatch()
1146 {
1147 h224Handler.StartTransmit();
1148 OpalMediaStream::OnStartMediaPatch();
1149 }
1150
1151
InternalClose()1152 void OpalH224MediaStream::InternalClose()
1153 {
1154 if (IsSource()) {
1155 h224Handler.StopTransmit();
1156 h224Handler.SetTransmitMediaStream(NULL);
1157 }
1158 }
1159
1160
ReadPacket(RTP_DataFrame &)1161 PBoolean OpalH224MediaStream::ReadPacket(RTP_DataFrame & /*packet*/)
1162 {
1163 return PFalse;
1164 }
1165
WritePacket(RTP_DataFrame & packet)1166 PBoolean OpalH224MediaStream::WritePacket(RTP_DataFrame & packet)
1167 {
1168 return h224Handler.HandleFrame(packet);
1169 }
1170
1171 ////////////////////////////////////
1172
OpalH224Client()1173 OpalH224Client::OpalH224Client()
1174 {
1175 remoteClientAvailable = PFalse;
1176 remoteClientHasExtraCapabilities = PFalse;
1177 h224Handler = NULL;
1178 }
1179
~OpalH224Client()1180 OpalH224Client::~OpalH224Client()
1181 {
1182 }
1183
Compare(const PObject & obj)1184 PObject::Comparison OpalH224Client::Compare(const PObject & obj)
1185 {
1186 if (!PIsDescendant(&obj, OpalH224Client)) {
1187 return LessThan;
1188 }
1189
1190 const OpalH224Client & otherClient = (const OpalH224Client &) obj;
1191
1192 BYTE clientID = GetClientID();
1193 BYTE otherClientID = otherClient.GetClientID();
1194
1195 if (clientID < otherClientID) {
1196 return LessThan;
1197 } else if (clientID > otherClientID) {
1198 return GreaterThan;
1199 }
1200
1201 if (clientID < ExtendedClientID) {
1202 return EqualTo;
1203 }
1204
1205 if (clientID == ExtendedClientID) {
1206 BYTE extendedClientID = GetExtendedClientID();
1207 BYTE otherExtendedClientID = otherClient.GetExtendedClientID();
1208
1209 if (extendedClientID < otherExtendedClientID) {
1210 return LessThan;
1211 } else if (extendedClientID > otherExtendedClientID) {
1212 return GreaterThan;
1213 } else {
1214 return EqualTo;
1215 }
1216 }
1217
1218 // Non-standard client.
1219 // Compare country code, extended country code, manufacturer code, manufacturer client ID
1220 BYTE countryCode = GetCountryCode();
1221 BYTE otherCountryCode = otherClient.GetCountryCode();
1222 if (countryCode < otherCountryCode) {
1223 return LessThan;
1224 } else if (countryCode > otherCountryCode) {
1225 return GreaterThan;
1226 }
1227
1228 BYTE countryCodeExtension = GetCountryCodeExtension();
1229 BYTE otherCountryCodeExtension = otherClient.GetCountryCodeExtension();
1230 if (countryCodeExtension < otherCountryCodeExtension) {
1231 return LessThan;
1232 } else if (countryCodeExtension > otherCountryCodeExtension) {
1233 return GreaterThan;
1234 }
1235
1236 WORD manufacturerCode = GetManufacturerCode();
1237 WORD otherManufacturerCode = otherClient.GetManufacturerCode();
1238 if (manufacturerCode < otherManufacturerCode) {
1239 return LessThan;
1240 } else if (manufacturerCode > otherManufacturerCode) {
1241 return GreaterThan;
1242 }
1243
1244 BYTE manufacturerClientID = GetManufacturerClientID();
1245 BYTE otherManufacturerClientID = otherClient.GetManufacturerClientID();
1246
1247 if (manufacturerClientID < otherManufacturerClientID) {
1248 return LessThan;
1249 } else if (manufacturerClientID > otherManufacturerClientID) {
1250 return GreaterThan;
1251 }
1252
1253 return EqualTo;
1254 }
1255
SetRemoteClientAvailable(PBoolean available,PBoolean hasExtraCapabilities)1256 void OpalH224Client::SetRemoteClientAvailable(PBoolean available, PBoolean hasExtraCapabilities)
1257 {
1258 remoteClientAvailable = available;
1259 remoteClientHasExtraCapabilities = hasExtraCapabilities;
1260 }
1261
1262 #endif // OPAL_HAS_H224
1263