Port of H.224 Far End Camera Control to DevStudio/Windows
[opal/cbnco.git] / src / h224 / h224.cxx
blob49a04e8f2fceb5b90cb7a92c2ca62ef11aa48925
1 /*
2 * h224.cxx
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
17 * under the License.
19 * Contributor(s): ______________________________________.
21 * $Log$
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.
30 #include <ptlib.h>
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
47 data[0] = 0;
48 data[1] = 0;
49 data[2] = 0;
50 data[3] = 0;
52 // setting Client ID to CME
53 data[4] = 0;
55 // setting ES / BS / C1 / C0 / Segment number to zero
56 data[5] = 0;
59 H224_Frame::~H224_Frame()
63 void H224_Frame::SetHighPriority(BOOL flag)
65 SetHighOrderAddressOctet(0x00);
67 if(flag) {
68 SetLowOrderAddressOctet(0x71);
69 } else {
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)
110 // is supported
111 PAssert(clientID <= 0x01, "Invalid client ID");
113 BYTE *data = GetInformationFieldPtr();
115 data[4] = clientID;
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();
129 if(flag) {
130 data[5] |= 0x80;
131 } else {
132 data[5] &= 0x7f;
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();
147 if(flag) {
148 data[5] |= 0x40;
149 } else {
150 data[5] &= 0xbf;
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();
165 if(flag) {
166 data[5] |= 0x20;
167 } else {
168 data[5] &= 0xdf;
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();
183 if(flag) {
184 data[5] |= 0x10;
185 } else {
186 data[5] &= 0xef;
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();
201 data[5] &= 0xf0;
202 data[5] |= (segmentNumber & 0x0f);
205 BOOL H224_Frame::Decode(const BYTE *data,
206 PINDEX size)
208 BOOL result = Q922_Frame::Decode(data, size);
210 if(result == FALSE) {
211 return 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))
224 return FALSE;
227 return TRUE;
230 ////////////////////////////////////
232 OpalH224Handler::OpalH224Handler(OpalConnection & connection,
233 unsigned sessionID)
234 : transmitMutex()
236 session = connection.UseSession(connection.GetTransport(),
237 sessionID);
239 h281Handler = connection.CreateH281ProtocolHandler(*this);
240 receiverThread = NULL;
244 OpalH224Handler::~OpalH224Handler()
246 delete h281Handler;
249 void OpalH224Handler::StartTransmit()
251 PWaitAndSignal m(transmitMutex);
253 if(canTransmit == TRUE) {
254 return;
257 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();
266 SendClientList();
267 SendExtraCapabilities();
270 void OpalH224Handler::StopTransmit()
272 PWaitAndSignal m(transmitMutex);
274 delete transmitStartTime;
275 transmitStartTime = NULL;
277 canTransmit = FALSE;
280 void OpalH224Handler::StartReceive()
282 if(receiverThread != NULL) {
283 PTRACE(5, "H.224 handler is already receiving");
284 return;
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) {
303 return FALSE;
306 H224_Frame h224Frame = H224_Frame(4);
307 h224Frame.SetHighPriority(TRUE);
308 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
309 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
311 // CME frame
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);
330 return TRUE;
333 BOOL OpalH224Handler::SendExtraCapabilities()
335 PWaitAndSignal m(transmitMutex);
337 if(canTransmit == FALSE) {
338 return FALSE;
341 h281Handler->SendExtraCapabilities();
343 return TRUE;
346 BOOL OpalH224Handler::SendClientListCommand()
348 PWaitAndSignal m(transmitMutex);
350 if(canTransmit == FALSE) {
351 return FALSE;
354 H224_Frame h224Frame = H224_Frame(2);
355 h224Frame.SetHighPriority(TRUE);
356 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
357 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
359 // CME frame
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);
376 return TRUE;
379 BOOL OpalH224Handler::SendExtraCapabilitiesCommand(BYTE clientID)
381 PWaitAndSignal m(transmitMutex);
383 if(canTransmit == FALSE) {
384 return FALSE;
387 if(clientID != H281_CLIENT_ID) {
388 return FALSE;
391 H224_Frame h224Frame = H224_Frame(4);
392 h224Frame.SetHighPriority(TRUE);
393 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
394 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
396 // CME frame
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);
414 return TRUE;
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) {
425 return FALSE;
428 if(canTransmit == FALSE) {
429 return 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);
457 return TRUE;
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) {
466 return FALSE;
469 frame.SetClientID(clientID);
471 TransmitFrame(frame);
473 return TRUE;
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");
481 return TRUE;
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);
493 return TRUE;
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
520 return TRUE;
523 BOOL OpalH224Handler::OnReceivedClientList(H224_Frame & frame)
525 BYTE *data = frame.GetClientDataPtr();
527 BYTE numberOfClients = data[2];
529 PINDEX i = 3;
531 BOOL remoteHasH281 = FALSE;
533 while(numberOfClients > 0) {
535 BYTE clientID = (data[i] & 0x7f);
537 if(clientID == H281_CLIENT_ID) {
538 remoteHasH281 = TRUE;
539 i++;
540 } else if(clientID == 0x7e) { // extended client ID
541 i += 2;
542 } else if(clientID == 0x7f) { // non-standard client ID
543 i += 6;
544 } else { // other standard client ID such as T.140
545 i++;
547 numberOfClients--;
550 h281Handler->SetRemoteHasH281(remoteHasH281);
552 return TRUE;
555 BOOL OpalH224Handler::OnReceivedClientListCommand()
557 SendClientList();
558 return TRUE;
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);
572 return TRUE;
575 BOOL OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
577 SendExtraCapabilities();
578 return TRUE;
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");
592 return;
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"),
612 rtpSession(session)
614 h224Handler = theH224Handler;
615 timestamp = 0;
616 terminate = FALSE;
619 OpalH224ReceiverThread::~OpalH224ReceiverThread()
623 void OpalH224ReceiverThread::Main()
625 RTP_DataFrame packet = RTP_DataFrame(300);
626 H224_Frame h224Frame = H224_Frame();
628 for (;;) {
630 inUse.Wait();
632 if(!rtpSession.ReadBufferedData(timestamp, packet)) {
633 inUse.Signal();
634 return;
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
644 return;
646 } else {
647 PTRACE(3, "Decoding of H.224 frame failed");
650 inUse.Signal();
652 if(terminate == TRUE) {
653 return;
658 void OpalH224ReceiverThread::Close()
660 rtpSession.Close(TRUE);
662 inUse.Wait();
664 terminate = TRUE;
666 inUse.Signal();
668 PAssert(WaitForTermination(10000), "H224 receiver thread not terminated");