4 * H.224 implementation for the OpenH323 Project.
6 * Copyright (c) 2006 Network for Educational Technology, ETH Zurich.
7 * Written by Hannes Friederich.
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/
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
19 * Contributor(s): ______________________________________.
22 * Revision 1.3 2006/05/01 10:29:50 csoutheren
23 * Added pragams for gcc < 4
25 * Revision 1.2 2006/04/24 12:53:50 rjongbloed
26 * Port of H.224 Far End Camera Control to DevStudio/Windows
28 * Revision 1.1 2006/04/20 16:48:17 hfriederich
29 * Initial version of H.224/H.281 implementation.
36 #pragma implementation "h224.h"
37 #pragma implementation "h224handler.h"
40 #include <h224/h224.h>
41 #include <h224/h224handler.h>
42 #include <h323/h323con.h>
45 H224_Frame::H224_Frame(PINDEX size
)
46 : Q922_Frame(H224_HEADER_SIZE
+ size
)
48 SetHighPriority(FALSE
);
50 SetControlFieldOctet(0x03);
52 BYTE
*data
= GetInformationFieldPtr();
54 // setting destination & source terminal address to BROADCAST
60 // setting Client ID to CME
63 // setting ES / BS / C1 / C0 / Segment number to zero
67 H224_Frame::~H224_Frame()
71 void H224_Frame::SetHighPriority(BOOL flag
)
73 SetHighOrderAddressOctet(0x00);
76 SetLowOrderAddressOctet(0x71);
78 SetLowOrderAddressOctet(0x061);
82 WORD
H224_Frame::GetDestinationTerminalAddress() const
84 BYTE
*data
= GetInformationFieldPtr();
85 return (WORD
)((data
[0] << 8) | data
[1]);
88 void H224_Frame::SetDestinationTerminalAddress(WORD address
)
90 BYTE
*data
= GetInformationFieldPtr();
91 data
[0] = (BYTE
)(address
>> 8);
92 data
[1] = (BYTE
) address
;
95 WORD
H224_Frame::GetSourceTerminalAddress() const
97 BYTE
*data
= GetInformationFieldPtr();
98 return (WORD
)((data
[2] << 8) | data
[3]);
101 void H224_Frame::SetSourceTerminalAddress(WORD address
)
103 BYTE
*data
= GetInformationFieldPtr();
104 data
[2] = (BYTE
)(address
>> 8);
105 data
[3] = (BYTE
) address
;
108 BYTE
H224_Frame::GetClientID() const
110 BYTE
*data
= GetInformationFieldPtr();
112 return data
[4] & 0x7f;
115 void H224_Frame::SetClientID(BYTE clientID
)
117 // At the moment, only H.281 (client ID 0x01)
119 PAssert(clientID
<= 0x01, "Invalid client ID");
121 BYTE
*data
= GetInformationFieldPtr();
126 BOOL
H224_Frame::GetBS() const
128 BYTE
*data
= GetInformationFieldPtr();
130 return (data
[5] & 0x80) != 0;
133 void H224_Frame::SetBS(BOOL flag
)
135 BYTE
*data
= GetInformationFieldPtr();
144 BOOL
H224_Frame::GetES() const
146 BYTE
*data
= GetInformationFieldPtr();
148 return (data
[5] & 0x40) != 0;
151 void H224_Frame::SetES(BOOL flag
)
153 BYTE
*data
= GetInformationFieldPtr();
162 BOOL
H224_Frame::GetC1() const
164 BYTE
*data
= GetInformationFieldPtr();
166 return (data
[5] & 0x20) != 0;
169 void H224_Frame::SetC1(BOOL flag
)
171 BYTE
*data
= GetInformationFieldPtr();
180 BOOL
H224_Frame::GetC0() const
182 BYTE
*data
= GetInformationFieldPtr();
184 return (data
[5] & 0x10) != 0;
187 void H224_Frame::SetC0(BOOL flag
)
189 BYTE
*data
= GetInformationFieldPtr();
198 BYTE
H224_Frame::GetSegmentNumber() const
200 BYTE
*data
= GetInformationFieldPtr();
202 return (data
[5] & 0x0f);
205 void H224_Frame::SetSegmentNumber(BYTE segmentNumber
)
207 BYTE
*data
= GetInformationFieldPtr();
210 data
[5] |= (segmentNumber
& 0x0f);
213 BOOL
H224_Frame::Decode(const BYTE
*data
,
216 BOOL result
= Q922_Frame::Decode(data
, size
);
218 if(result
== FALSE
) {
222 // doing some validity check for H.224 frames
223 BYTE highOrderAddressOctet
= GetHighOrderAddressOctet();
224 BYTE lowOrderAddressOctet
= GetLowOrderAddressOctet();
225 BYTE controlFieldOctet
= GetControlFieldOctet();
227 if((highOrderAddressOctet
!= 0x00) ||
228 (!(lowOrderAddressOctet
== 0x61 || lowOrderAddressOctet
== 0x71)) ||
229 (controlFieldOctet
!= 0x03) ||
230 (GetClientID() > 0x02))
238 ////////////////////////////////////
240 OpalH224Handler::OpalH224Handler(OpalConnection
& connection
,
244 session
= connection
.UseSession(connection
.GetTransport(),
247 h281Handler
= connection
.CreateH281ProtocolHandler(*this);
248 receiverThread
= NULL
;
252 OpalH224Handler::~OpalH224Handler()
257 void OpalH224Handler::StartTransmit()
259 PWaitAndSignal
m(transmitMutex
);
261 if(canTransmit
== TRUE
) {
267 transmitFrame
= new RTP_DataFrame(300);
269 // Use payload code 100 as this seems to be common to other implementations
270 transmitFrame
->SetPayloadType((RTP_DataFrame::PayloadTypes
)100);
271 transmitBitIndex
= 7;
272 transmitStartTime
= new PTime();
275 SendExtraCapabilities();
278 void OpalH224Handler::StopTransmit()
280 PWaitAndSignal
m(transmitMutex
);
282 delete transmitStartTime
;
283 transmitStartTime
= NULL
;
288 void OpalH224Handler::StartReceive()
290 if(receiverThread
!= NULL
) {
291 PTRACE(5, "H.224 handler is already receiving");
295 receiverThread
= CreateH224ReceiverThread();
296 receiverThread
->Resume();
299 void OpalH224Handler::StopReceive()
301 if(receiverThread
!= NULL
) {
302 receiverThread
->Close();
306 BOOL
OpalH224Handler::SendClientList()
308 PWaitAndSignal
m(transmitMutex
);
310 if(canTransmit
== FALSE
) {
314 H224_Frame h224Frame
= H224_Frame(4);
315 h224Frame
.SetHighPriority(TRUE
);
316 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
317 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
320 h224Frame
.SetClientID(0x00);
322 // Begin and end of sequence
323 h224Frame
.SetBS(TRUE
);
324 h224Frame
.SetES(TRUE
);
325 h224Frame
.SetC1(FALSE
);
326 h224Frame
.SetC0(FALSE
);
327 h224Frame
.SetSegmentNumber(0);
329 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
331 ptr
[0] = 0x01; // Client list code
332 ptr
[1] = 0x00; // Message code
333 ptr
[2] = 0x01; // one client
334 ptr
[3] = (0x80 | H281_CLIENT_ID
); // H.281 with etra capabilities
336 TransmitFrame(h224Frame
);
341 BOOL
OpalH224Handler::SendExtraCapabilities()
343 PWaitAndSignal
m(transmitMutex
);
345 if(canTransmit
== FALSE
) {
349 h281Handler
->SendExtraCapabilities();
354 BOOL
OpalH224Handler::SendClientListCommand()
356 PWaitAndSignal
m(transmitMutex
);
358 if(canTransmit
== FALSE
) {
362 H224_Frame h224Frame
= H224_Frame(2);
363 h224Frame
.SetHighPriority(TRUE
);
364 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
365 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
368 h224Frame
.SetClientID(0x00);
370 // Begin and end of sequence
371 h224Frame
.SetBS(TRUE
);
372 h224Frame
.SetES(TRUE
);
373 h224Frame
.SetC1(FALSE
);
374 h224Frame
.SetC0(FALSE
);
375 h224Frame
.SetSegmentNumber(0);
377 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
379 ptr
[0] = 0x01; // Client list code
380 ptr
[1] = 0xff; // Command code
382 TransmitFrame(h224Frame
);
387 BOOL
OpalH224Handler::SendExtraCapabilitiesCommand(BYTE clientID
)
389 PWaitAndSignal
m(transmitMutex
);
391 if(canTransmit
== FALSE
) {
395 if(clientID
!= H281_CLIENT_ID
) {
399 H224_Frame h224Frame
= H224_Frame(4);
400 h224Frame
.SetHighPriority(TRUE
);
401 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
402 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
405 h224Frame
.SetClientID(0x00);
407 // Begin and end of sequence
408 h224Frame
.SetBS(TRUE
);
409 h224Frame
.SetES(TRUE
);
410 h224Frame
.SetC1(FALSE
);
411 h224Frame
.SetC0(FALSE
);
412 h224Frame
.SetSegmentNumber(0);
414 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
416 ptr
[0] = 0x01; // Client list code
417 ptr
[1] = 0xFF; // Response code
418 ptr
[2] = (0x80 | clientID
); // clientID with extra capabilities
420 TransmitFrame(h224Frame
);
425 BOOL
OpalH224Handler::SendExtraCapabilitiesMessage(BYTE clientID
,
426 BYTE
*data
, PINDEX length
)
428 PWaitAndSignal
m(transmitMutex
);
430 // only H.281 supported at the moment
431 if(clientID
!= H281_CLIENT_ID
) {
436 if(canTransmit
== FALSE
) {
440 H224_Frame h224Frame
= H224_Frame(length
+3);
441 h224Frame
.SetHighPriority(TRUE
);
442 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
443 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
445 // use clientID zero to indicate a CME frame
446 h224Frame
.SetClientID(0x00);
448 // Begin and end of sequence, rest is zero
449 h224Frame
.SetBS(TRUE
);
450 h224Frame
.SetES(TRUE
);
451 h224Frame
.SetC1(FALSE
);
452 h224Frame
.SetC0(FALSE
);
453 h224Frame
.SetSegmentNumber(0);
455 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
457 ptr
[0] = 0x02; // Extra Capabilities code
458 ptr
[1] = 0x00; // Response Code
459 ptr
[2] = (0x80 | clientID
); // EX CAPS and ClientID
461 memcpy(ptr
+3, data
, length
);
463 TransmitFrame(h224Frame
);
468 BOOL
OpalH224Handler::TransmitClientFrame(BYTE clientID
, H224_Frame
& frame
)
470 PWaitAndSignal
m(transmitMutex
);
472 // only H.281 is supported at the moment
473 if(clientID
!= H281_CLIENT_ID
) {
477 frame
.SetClientID(clientID
);
479 TransmitFrame(frame
);
484 BOOL
OpalH224Handler::OnReceivedFrame(H224_Frame
& frame
)
486 if(frame
.GetDestinationTerminalAddress() != H224_BROADCAST
) {
487 // only broadcast frames are handled at the moment
488 PTRACE(3, "Received H.224 frame with non-broadcast address");
491 BYTE clientID
= frame
.GetClientID();
493 if(clientID
== 0x00) {
494 return OnReceivedCMEMessage(frame
);
497 if(clientID
== H281_CLIENT_ID
) {
498 h281Handler
->OnReceivedMessage((const H281_Frame
&)frame
);
504 BOOL
OpalH224Handler::OnReceivedCMEMessage(H224_Frame
& frame
)
506 BYTE
*data
= frame
.GetClientDataPtr();
508 if(data
[0] == 0x01) { // Client list code
510 if(data
[1] == 0x00) { // Message
511 return OnReceivedClientList(frame
);
513 } else if(data
[1] == 0xff) { // Command
514 return OnReceivedClientListCommand();
517 } else if(data
[0] == 0x02) { // Extra Capabilities code
519 if(data
[1] == 0x00) { // Message
520 return OnReceivedExtraCapabilities(frame
);
522 } else if(data
[1] == 0xff) {// Command
523 return OnReceivedExtraCapabilitiesCommand();
527 // incorrect frames are simply ignored
531 BOOL
OpalH224Handler::OnReceivedClientList(H224_Frame
& frame
)
533 BYTE
*data
= frame
.GetClientDataPtr();
535 BYTE numberOfClients
= data
[2];
539 BOOL remoteHasH281
= FALSE
;
541 while(numberOfClients
> 0) {
543 BYTE clientID
= (data
[i
] & 0x7f);
545 if(clientID
== H281_CLIENT_ID
) {
546 remoteHasH281
= TRUE
;
548 } else if(clientID
== 0x7e) { // extended client ID
550 } else if(clientID
== 0x7f) { // non-standard client ID
552 } else { // other standard client ID such as T.140
558 h281Handler
->SetRemoteHasH281(remoteHasH281
);
563 BOOL
OpalH224Handler::OnReceivedClientListCommand()
569 BOOL
OpalH224Handler::OnReceivedExtraCapabilities(H224_Frame
& frame
)
571 BYTE
*data
= frame
.GetClientDataPtr();
573 BYTE clientID
= (data
[2] & 0x7f);
575 if(clientID
== H281_CLIENT_ID
) {
576 PINDEX size
= frame
.GetClientDataSize() - 3;
577 h281Handler
->OnReceivedExtraCapabilities((data
+ 3), size
);
583 BOOL
OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
585 SendExtraCapabilities();
589 OpalH224ReceiverThread
* OpalH224Handler::CreateH224ReceiverThread()
591 return new OpalH224ReceiverThread(this, *session
);
594 void OpalH224Handler::TransmitFrame(H224_Frame
& frame
)
596 PINDEX size
= frame
.GetEncodedSize();
598 if(!frame
.Encode(transmitFrame
->GetPayloadPtr(), size
, transmitBitIndex
)) {
599 PTRACE(3, "Failed to encode H.224 frame");
603 // determining correct timestamp
604 PTime currentTime
= PTime();
605 PTimeInterval timePassed
= currentTime
- *transmitStartTime
;
606 transmitFrame
->SetTimestamp((DWORD
)timePassed
.GetMilliSeconds() * 8);
608 transmitFrame
->SetPayloadSize(size
);
609 transmitFrame
->SetMarker(TRUE
);
611 if(!session
->WriteData(*transmitFrame
)) {
612 PTRACE(3, "Failed to write encoded H.224 frame");
616 ////////////////////////////////////
618 OpalH224ReceiverThread::OpalH224ReceiverThread(OpalH224Handler
*theH224Handler
, RTP_Session
& session
)
619 : PThread(10000, NoAutoDeleteThread
, HighestPriority
, "H.224 Receiver Thread"),
622 h224Handler
= theH224Handler
;
627 OpalH224ReceiverThread::~OpalH224ReceiverThread()
631 void OpalH224ReceiverThread::Main()
633 RTP_DataFrame packet
= RTP_DataFrame(300);
634 H224_Frame h224Frame
= H224_Frame();
640 if(!rtpSession
.ReadBufferedData(timestamp
, packet
)) {
645 timestamp
= packet
.GetTimestamp();
647 if(h224Frame
.Decode(packet
.GetPayloadPtr(), packet
.GetPayloadSize())) {
648 BOOL result
= h224Handler
->OnReceivedFrame(h224Frame
);
650 if(result
== FALSE
) {
651 // FALSE indicates a serious problem, therefore the thread is closed
655 PTRACE(3, "Decoding of H.224 frame failed");
660 if(terminate
== TRUE
) {
666 void OpalH224ReceiverThread::Close()
668 rtpSession
.Close(TRUE
);
676 PAssert(WaitForTermination(10000), "H224 receiver thread not terminated");