Changed LID tone handling to use new tone generation for accurate country based tones.
[opal.git] / src / h224 / h224.cxx
blob4b8ad942a60454dd4e4a2c6d0675a859dace2f5c
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.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.
33 #include <ptlib.h>
35 #ifdef __GNUC__
36 #pragma implementation "h224.h"
37 #pragma implementation "h224handler.h"
38 #endif
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
55 data[0] = 0;
56 data[1] = 0;
57 data[2] = 0;
58 data[3] = 0;
60 // setting Client ID to CME
61 data[4] = 0;
63 // setting ES / BS / C1 / C0 / Segment number to zero
64 data[5] = 0;
67 H224_Frame::~H224_Frame()
71 void H224_Frame::SetHighPriority(BOOL flag)
73 SetHighOrderAddressOctet(0x00);
75 if(flag) {
76 SetLowOrderAddressOctet(0x71);
77 } else {
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)
118 // is supported
119 PAssert(clientID <= 0x01, "Invalid client ID");
121 BYTE *data = GetInformationFieldPtr();
123 data[4] = clientID;
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();
137 if(flag) {
138 data[5] |= 0x80;
139 } else {
140 data[5] &= 0x7f;
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();
155 if(flag) {
156 data[5] |= 0x40;
157 } else {
158 data[5] &= 0xbf;
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();
173 if(flag) {
174 data[5] |= 0x20;
175 } else {
176 data[5] &= 0xdf;
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();
191 if(flag) {
192 data[5] |= 0x10;
193 } else {
194 data[5] &= 0xef;
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();
209 data[5] &= 0xf0;
210 data[5] |= (segmentNumber & 0x0f);
213 BOOL H224_Frame::Decode(const BYTE *data,
214 PINDEX size)
216 BOOL result = Q922_Frame::Decode(data, size);
218 if(result == FALSE) {
219 return 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))
232 return FALSE;
235 return TRUE;
238 ////////////////////////////////////
240 OpalH224Handler::OpalH224Handler(OpalConnection & connection,
241 unsigned sessionID)
242 : transmitMutex()
244 session = connection.UseSession(connection.GetTransport(),
245 sessionID);
247 h281Handler = connection.CreateH281ProtocolHandler(*this);
248 receiverThread = NULL;
252 OpalH224Handler::~OpalH224Handler()
254 delete h281Handler;
257 void OpalH224Handler::StartTransmit()
259 PWaitAndSignal m(transmitMutex);
261 if(canTransmit == TRUE) {
262 return;
265 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();
274 SendClientList();
275 SendExtraCapabilities();
278 void OpalH224Handler::StopTransmit()
280 PWaitAndSignal m(transmitMutex);
282 delete transmitStartTime;
283 transmitStartTime = NULL;
285 canTransmit = FALSE;
288 void OpalH224Handler::StartReceive()
290 if(receiverThread != NULL) {
291 PTRACE(5, "H.224 handler is already receiving");
292 return;
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) {
311 return FALSE;
314 H224_Frame h224Frame = H224_Frame(4);
315 h224Frame.SetHighPriority(TRUE);
316 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
317 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
319 // CME frame
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);
338 return TRUE;
341 BOOL OpalH224Handler::SendExtraCapabilities()
343 PWaitAndSignal m(transmitMutex);
345 if(canTransmit == FALSE) {
346 return FALSE;
349 h281Handler->SendExtraCapabilities();
351 return TRUE;
354 BOOL OpalH224Handler::SendClientListCommand()
356 PWaitAndSignal m(transmitMutex);
358 if(canTransmit == FALSE) {
359 return FALSE;
362 H224_Frame h224Frame = H224_Frame(2);
363 h224Frame.SetHighPriority(TRUE);
364 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
365 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
367 // CME frame
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);
384 return TRUE;
387 BOOL OpalH224Handler::SendExtraCapabilitiesCommand(BYTE clientID)
389 PWaitAndSignal m(transmitMutex);
391 if(canTransmit == FALSE) {
392 return FALSE;
395 if(clientID != H281_CLIENT_ID) {
396 return FALSE;
399 H224_Frame h224Frame = H224_Frame(4);
400 h224Frame.SetHighPriority(TRUE);
401 h224Frame.SetDestinationTerminalAddress(H224_BROADCAST);
402 h224Frame.SetSourceTerminalAddress(H224_BROADCAST);
404 // CME frame
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);
422 return TRUE;
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) {
433 return FALSE;
436 if(canTransmit == FALSE) {
437 return 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);
465 return TRUE;
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) {
474 return FALSE;
477 frame.SetClientID(clientID);
479 TransmitFrame(frame);
481 return TRUE;
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");
489 return TRUE;
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);
501 return TRUE;
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
528 return TRUE;
531 BOOL OpalH224Handler::OnReceivedClientList(H224_Frame & frame)
533 BYTE *data = frame.GetClientDataPtr();
535 BYTE numberOfClients = data[2];
537 PINDEX i = 3;
539 BOOL remoteHasH281 = FALSE;
541 while(numberOfClients > 0) {
543 BYTE clientID = (data[i] & 0x7f);
545 if(clientID == H281_CLIENT_ID) {
546 remoteHasH281 = TRUE;
547 i++;
548 } else if(clientID == 0x7e) { // extended client ID
549 i += 2;
550 } else if(clientID == 0x7f) { // non-standard client ID
551 i += 6;
552 } else { // other standard client ID such as T.140
553 i++;
555 numberOfClients--;
558 h281Handler->SetRemoteHasH281(remoteHasH281);
560 return TRUE;
563 BOOL OpalH224Handler::OnReceivedClientListCommand()
565 SendClientList();
566 return TRUE;
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);
580 return TRUE;
583 BOOL OpalH224Handler::OnReceivedExtraCapabilitiesCommand()
585 SendExtraCapabilities();
586 return TRUE;
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");
600 return;
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"),
620 rtpSession(session)
622 h224Handler = theH224Handler;
623 timestamp = 0;
624 terminate = FALSE;
627 OpalH224ReceiverThread::~OpalH224ReceiverThread()
631 void OpalH224ReceiverThread::Main()
633 RTP_DataFrame packet = RTP_DataFrame(300);
634 H224_Frame h224Frame = H224_Frame();
636 for (;;) {
638 inUse.Wait();
640 if(!rtpSession.ReadBufferedData(timestamp, packet)) {
641 inUse.Signal();
642 return;
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
652 return;
654 } else {
655 PTRACE(3, "Decoding of H.224 frame failed");
658 inUse.Signal();
660 if(terminate == TRUE) {
661 return;
666 void OpalH224ReceiverThread::Close()
668 rtpSession.Close(TRUE);
670 inUse.Wait();
672 terminate = TRUE;
674 inUse.Signal();
676 PAssert(WaitForTermination(10000), "H224 receiver thread not terminated");