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.2 2006/04/24 12:53:50 rjongbloed
23 * Port of H.224 Far End Camera Control to DevStudio/Windows
25 * Revision 1.1 2006/04/20 16:48:17 hfriederich
26 * Initial version of H.224/H.281 implementation.
32 #include <h224/h224.h>
33 #include <h224/h224handler.h>
34 #include <h323/h323con.h>
37 H224_Frame::H224_Frame(PINDEX size
)
38 : Q922_Frame(H224_HEADER_SIZE
+ size
)
40 SetHighPriority(FALSE
);
42 SetControlFieldOctet(0x03);
44 BYTE
*data
= GetInformationFieldPtr();
46 // setting destination & source terminal address to BROADCAST
52 // setting Client ID to CME
55 // setting ES / BS / C1 / C0 / Segment number to zero
59 H224_Frame::~H224_Frame()
63 void H224_Frame::SetHighPriority(BOOL flag
)
65 SetHighOrderAddressOctet(0x00);
68 SetLowOrderAddressOctet(0x71);
70 SetLowOrderAddressOctet(0x061);
74 WORD
H224_Frame::GetDestinationTerminalAddress() const
76 BYTE
*data
= GetInformationFieldPtr();
77 return (WORD
)((data
[0] << 8) | data
[1]);
80 void H224_Frame::SetDestinationTerminalAddress(WORD address
)
82 BYTE
*data
= GetInformationFieldPtr();
83 data
[0] = (BYTE
)(address
>> 8);
84 data
[1] = (BYTE
) address
;
87 WORD
H224_Frame::GetSourceTerminalAddress() const
89 BYTE
*data
= GetInformationFieldPtr();
90 return (WORD
)((data
[2] << 8) | data
[3]);
93 void H224_Frame::SetSourceTerminalAddress(WORD address
)
95 BYTE
*data
= GetInformationFieldPtr();
96 data
[2] = (BYTE
)(address
>> 8);
97 data
[3] = (BYTE
) address
;
100 BYTE
H224_Frame::GetClientID() const
102 BYTE
*data
= GetInformationFieldPtr();
104 return data
[4] & 0x7f;
107 void H224_Frame::SetClientID(BYTE clientID
)
109 // At the moment, only H.281 (client ID 0x01)
111 PAssert(clientID
<= 0x01, "Invalid client ID");
113 BYTE
*data
= GetInformationFieldPtr();
118 BOOL
H224_Frame::GetBS() const
120 BYTE
*data
= GetInformationFieldPtr();
122 return (data
[5] & 0x80) != 0;
125 void H224_Frame::SetBS(BOOL flag
)
127 BYTE
*data
= GetInformationFieldPtr();
136 BOOL
H224_Frame::GetES() const
138 BYTE
*data
= GetInformationFieldPtr();
140 return (data
[5] & 0x40) != 0;
143 void H224_Frame::SetES(BOOL flag
)
145 BYTE
*data
= GetInformationFieldPtr();
154 BOOL
H224_Frame::GetC1() const
156 BYTE
*data
= GetInformationFieldPtr();
158 return (data
[5] & 0x20) != 0;
161 void H224_Frame::SetC1(BOOL flag
)
163 BYTE
*data
= GetInformationFieldPtr();
172 BOOL
H224_Frame::GetC0() const
174 BYTE
*data
= GetInformationFieldPtr();
176 return (data
[5] & 0x10) != 0;
179 void H224_Frame::SetC0(BOOL flag
)
181 BYTE
*data
= GetInformationFieldPtr();
190 BYTE
H224_Frame::GetSegmentNumber() const
192 BYTE
*data
= GetInformationFieldPtr();
194 return (data
[5] & 0x0f);
197 void H224_Frame::SetSegmentNumber(BYTE segmentNumber
)
199 BYTE
*data
= GetInformationFieldPtr();
202 data
[5] |= (segmentNumber
& 0x0f);
205 BOOL
H224_Frame::Decode(const BYTE
*data
,
208 BOOL result
= Q922_Frame::Decode(data
, size
);
210 if(result
== FALSE
) {
214 // doing some validity check for H.224 frames
215 BYTE highOrderAddressOctet
= GetHighOrderAddressOctet();
216 BYTE lowOrderAddressOctet
= GetLowOrderAddressOctet();
217 BYTE controlFieldOctet
= GetControlFieldOctet();
219 if((highOrderAddressOctet
!= 0x00) ||
220 (!(lowOrderAddressOctet
== 0x61 || lowOrderAddressOctet
== 0x71)) ||
221 (controlFieldOctet
!= 0x03) ||
222 (GetClientID() > 0x02))
230 ////////////////////////////////////
232 OpalH224Handler::OpalH224Handler(OpalConnection
& connection
,
236 session
= connection
.UseSession(connection
.GetTransport(),
239 h281Handler
= connection
.CreateH281ProtocolHandler(*this);
240 receiverThread
= NULL
;
244 OpalH224Handler::~OpalH224Handler()
249 void OpalH224Handler::StartTransmit()
251 PWaitAndSignal
m(transmitMutex
);
253 if(canTransmit
== TRUE
) {
259 transmitFrame
= new RTP_DataFrame(300);
261 // Use payload code 100 as this seems to be common to other implementations
262 transmitFrame
->SetPayloadType((RTP_DataFrame::PayloadTypes
)100);
263 transmitBitIndex
= 7;
264 transmitStartTime
= new PTime();
267 SendExtraCapabilities();
270 void OpalH224Handler::StopTransmit()
272 PWaitAndSignal
m(transmitMutex
);
274 delete transmitStartTime
;
275 transmitStartTime
= NULL
;
280 void OpalH224Handler::StartReceive()
282 if(receiverThread
!= NULL
) {
283 PTRACE(5, "H.224 handler is already receiving");
287 receiverThread
= CreateH224ReceiverThread();
288 receiverThread
->Resume();
291 void OpalH224Handler::StopReceive()
293 if(receiverThread
!= NULL
) {
294 receiverThread
->Close();
298 BOOL
OpalH224Handler::SendClientList()
300 PWaitAndSignal
m(transmitMutex
);
302 if(canTransmit
== FALSE
) {
306 H224_Frame h224Frame
= H224_Frame(4);
307 h224Frame
.SetHighPriority(TRUE
);
308 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
309 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
312 h224Frame
.SetClientID(0x00);
314 // Begin and end of sequence
315 h224Frame
.SetBS(TRUE
);
316 h224Frame
.SetES(TRUE
);
317 h224Frame
.SetC1(FALSE
);
318 h224Frame
.SetC0(FALSE
);
319 h224Frame
.SetSegmentNumber(0);
321 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
323 ptr
[0] = 0x01; // Client list code
324 ptr
[1] = 0x00; // Message code
325 ptr
[2] = 0x01; // one client
326 ptr
[3] = (0x80 | H281_CLIENT_ID
); // H.281 with etra capabilities
328 TransmitFrame(h224Frame
);
333 BOOL
OpalH224Handler::SendExtraCapabilities()
335 PWaitAndSignal
m(transmitMutex
);
337 if(canTransmit
== FALSE
) {
341 h281Handler
->SendExtraCapabilities();
346 BOOL
OpalH224Handler::SendClientListCommand()
348 PWaitAndSignal
m(transmitMutex
);
350 if(canTransmit
== FALSE
) {
354 H224_Frame h224Frame
= H224_Frame(2);
355 h224Frame
.SetHighPriority(TRUE
);
356 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
357 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
360 h224Frame
.SetClientID(0x00);
362 // Begin and end of sequence
363 h224Frame
.SetBS(TRUE
);
364 h224Frame
.SetES(TRUE
);
365 h224Frame
.SetC1(FALSE
);
366 h224Frame
.SetC0(FALSE
);
367 h224Frame
.SetSegmentNumber(0);
369 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
371 ptr
[0] = 0x01; // Client list code
372 ptr
[1] = 0xff; // Command code
374 TransmitFrame(h224Frame
);
379 BOOL
OpalH224Handler::SendExtraCapabilitiesCommand(BYTE clientID
)
381 PWaitAndSignal
m(transmitMutex
);
383 if(canTransmit
== FALSE
) {
387 if(clientID
!= H281_CLIENT_ID
) {
391 H224_Frame h224Frame
= H224_Frame(4);
392 h224Frame
.SetHighPriority(TRUE
);
393 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
394 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
397 h224Frame
.SetClientID(0x00);
399 // Begin and end of sequence
400 h224Frame
.SetBS(TRUE
);
401 h224Frame
.SetES(TRUE
);
402 h224Frame
.SetC1(FALSE
);
403 h224Frame
.SetC0(FALSE
);
404 h224Frame
.SetSegmentNumber(0);
406 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
408 ptr
[0] = 0x01; // Client list code
409 ptr
[1] = 0xFF; // Response code
410 ptr
[2] = (0x80 | clientID
); // clientID with extra capabilities
412 TransmitFrame(h224Frame
);
417 BOOL
OpalH224Handler::SendExtraCapabilitiesMessage(BYTE clientID
,
418 BYTE
*data
, PINDEX length
)
420 PWaitAndSignal
m(transmitMutex
);
422 // only H.281 supported at the moment
423 if(clientID
!= H281_CLIENT_ID
) {
428 if(canTransmit
== FALSE
) {
432 H224_Frame h224Frame
= H224_Frame(length
+3);
433 h224Frame
.SetHighPriority(TRUE
);
434 h224Frame
.SetDestinationTerminalAddress(H224_BROADCAST
);
435 h224Frame
.SetSourceTerminalAddress(H224_BROADCAST
);
437 // use clientID zero to indicate a CME frame
438 h224Frame
.SetClientID(0x00);
440 // Begin and end of sequence, rest is zero
441 h224Frame
.SetBS(TRUE
);
442 h224Frame
.SetES(TRUE
);
443 h224Frame
.SetC1(FALSE
);
444 h224Frame
.SetC0(FALSE
);
445 h224Frame
.SetSegmentNumber(0);
447 BYTE
*ptr
= h224Frame
.GetClientDataPtr();
449 ptr
[0] = 0x02; // Extra Capabilities code
450 ptr
[1] = 0x00; // Response Code
451 ptr
[2] = (0x80 | clientID
); // EX CAPS and ClientID
453 memcpy(ptr
+3, data
, length
);
455 TransmitFrame(h224Frame
);
460 BOOL
OpalH224Handler::TransmitClientFrame(BYTE clientID
, H224_Frame
& frame
)
462 PWaitAndSignal
m(transmitMutex
);
464 // only H.281 is supported at the moment
465 if(clientID
!= H281_CLIENT_ID
) {
469 frame
.SetClientID(clientID
);
471 TransmitFrame(frame
);
476 BOOL
OpalH224Handler::OnReceivedFrame(H224_Frame
& frame
)
478 if(frame
.GetDestinationTerminalAddress() != H224_BROADCAST
) {
479 // only broadcast frames are handled at the moment
480 PTRACE(3, "Received H.224 frame with non-broadcast address");
483 BYTE clientID
= frame
.GetClientID();
485 if(clientID
== 0x00) {
486 return OnReceivedCMEMessage(frame
);
489 if(clientID
== H281_CLIENT_ID
) {
490 h281Handler
->OnReceivedMessage((const H281_Frame
&)frame
);
496 BOOL
OpalH224Handler::OnReceivedCMEMessage(H224_Frame
& frame
)
498 BYTE
*data
= frame
.GetClientDataPtr();
500 if(data
[0] == 0x01) { // Client list code
502 if(data
[1] == 0x00) { // Message
503 return OnReceivedClientList(frame
);
505 } else if(data
[1] == 0xff) { // Command
506 return OnReceivedClientListCommand();
509 } else if(data
[0] == 0x02) { // Extra Capabilities code
511 if(data
[1] == 0x00) { // Message
512 return OnReceivedExtraCapabilities(frame
);
514 } else if(data
[1] == 0xff) {// Command
515 return OnReceivedExtraCapabilitiesCommand();
519 // incorrect frames are simply ignored
523 BOOL
OpalH224Handler::OnReceivedClientList(H224_Frame
& frame
)
525 BYTE
*data
= frame
.GetClientDataPtr();
527 BYTE numberOfClients
= data
[2];
531 BOOL remoteHasH281
= FALSE
;
533 while(numberOfClients
> 0) {
535 BYTE clientID
= (data
[i
] & 0x7f);
537 if(clientID
== H281_CLIENT_ID
) {
538 remoteHasH281
= TRUE
;
540 } else if(clientID
== 0x7e) { // extended client ID
542 } else if(clientID
== 0x7f) { // non-standard client ID
544 } else { // other standard client ID such as T.140
550 h281Handler
->SetRemoteHasH281(remoteHasH281
);
555 BOOL
OpalH224Handler::OnReceivedClientListCommand()
561 BOOL
OpalH224Handler::OnReceivedExtraCapabilities(H224_Frame
& frame
)
563 BYTE
*data
= frame
.GetClientDataPtr();
565 BYTE clientID
= (data
[2] & 0x7f);
567 if(clientID
== H281_CLIENT_ID
) {
568 PINDEX size
= frame
.GetClientDataSize() - 3;
569 h281Handler
->OnReceivedExtraCapabilities((data
+ 3), size
);
575 BOOL
OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
577 SendExtraCapabilities();
581 OpalH224ReceiverThread
* OpalH224Handler::CreateH224ReceiverThread()
583 return new OpalH224ReceiverThread(this, *session
);
586 void OpalH224Handler::TransmitFrame(H224_Frame
& frame
)
588 PINDEX size
= frame
.GetEncodedSize();
590 if(!frame
.Encode(transmitFrame
->GetPayloadPtr(), size
, transmitBitIndex
)) {
591 PTRACE(3, "Failed to encode H.224 frame");
595 // determining correct timestamp
596 PTime currentTime
= PTime();
597 PTimeInterval timePassed
= currentTime
- *transmitStartTime
;
598 transmitFrame
->SetTimestamp((DWORD
)timePassed
.GetMilliSeconds() * 8);
600 transmitFrame
->SetPayloadSize(size
);
601 transmitFrame
->SetMarker(TRUE
);
603 if(!session
->WriteData(*transmitFrame
)) {
604 PTRACE(3, "Failed to write encoded H.224 frame");
608 ////////////////////////////////////
610 OpalH224ReceiverThread::OpalH224ReceiverThread(OpalH224Handler
*theH224Handler
, RTP_Session
& session
)
611 : PThread(10000, NoAutoDeleteThread
, HighestPriority
, "H.224 Receiver Thread"),
614 h224Handler
= theH224Handler
;
619 OpalH224ReceiverThread::~OpalH224ReceiverThread()
623 void OpalH224ReceiverThread::Main()
625 RTP_DataFrame packet
= RTP_DataFrame(300);
626 H224_Frame h224Frame
= H224_Frame();
632 if(!rtpSession
.ReadBufferedData(timestamp
, packet
)) {
637 timestamp
= packet
.GetTimestamp();
639 if(h224Frame
.Decode(packet
.GetPayloadPtr(), packet
.GetPayloadSize())) {
640 BOOL result
= h224Handler
->OnReceivedFrame(h224Frame
);
642 if(result
== FALSE
) {
643 // FALSE indicates a serious problem, therefore the thread is closed
647 PTRACE(3, "Decoding of H.224 frame failed");
652 if(terminate
== TRUE
) {
658 void OpalH224ReceiverThread::Close()
660 rtpSession
.Close(TRUE
);
668 PAssert(WaitForTermination(10000), "H224 receiver thread not terminated");