Changed LID tone handling to use new tone generation for accurate country based tones.
[opal.git] / src / t38 / t38proto.cxx
blob81be1901798dfc2bff73c0fdc54bec2aa9c048b8
1 /*
2 * t38proto.cxx
4 * T.38 protocol handler
6 * Open Phone Abstraction Library
8 * Copyright (c) 1998-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): Vyacheslav Frolov.
26 * $Log$
27 * Revision 2.8 2005/02/21 12:20:08 rjongbloed
28 * Added new "options list" to the OpalMediaFormat class.
30 * Revision 2.7 2003/01/07 04:39:53 robertj
31 * Updated to OpenH323 v1.11.2
33 * Revision 2.6 2002/11/10 11:33:20 robertj
34 * Updated to OpenH323 v1.10.3
36 * Revision 2.5 2002/09/04 06:01:49 robertj
37 * Updated to OpenH323 v1.9.6
39 * Revision 2.4 2002/02/11 09:32:13 robertj
40 * Updated to openH323 v1.8.0
42 * Revision 2.3 2002/01/22 05:21:54 robertj
43 * Added RTP encoding name string to media format database.
44 * Changed time units to clock rate in Hz.
46 * Revision 2.2 2002/01/14 06:35:59 robertj
47 * Updated to OpenH323 v1.7.9
49 * Revision 2.1 2001/08/01 05:05:26 robertj
50 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
52 * Revision 2.0 2001/07/27 15:48:25 robertj
53 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
55 * Revision 1.17 2002/12/19 01:49:08 robertj
56 * Fixed incorrect setting of optional fields in pre-corrigendum packet
57 * translation function, thanks Vyacheslav Frolov
59 * Revision 1.16 2002/12/06 04:18:02 robertj
60 * Fixed GNU warning
62 * Revision 1.15 2002/12/02 04:08:02 robertj
63 * Turned T.38 Originate inside out, so now has WriteXXX() functions that can
64 * be call ed in different thread contexts.
66 * Revision 1.14 2002/12/02 00:37:19 robertj
67 * More implementation of T38 base library code, some taken from the t38modem
68 * application by Vyacheslav Frolov, eg redundent frames.
70 * Revision 1.13 2002/11/21 06:40:00 robertj
71 * Changed promiscuous mode to be three way. Fixes race condition in gkserver
72 * which can cause crashes or more PDUs to be sent to the wrong place.
74 * Revision 1.12 2002/09/25 05:20:40 robertj
75 * Fixed warning on no trace version.
77 * Revision 1.11 2002/08/05 10:03:48 robertj
78 * Cosmetic changes to normalise the usage of pragma interface/implementation.
80 * Revision 1.10 2002/02/09 04:39:05 robertj
81 * Changes to allow T.38 logical channels to use single transport which is
82 * now owned by the OpalT38Protocol object instead of H323Channel.
84 * Revision 1.9 2002/01/01 23:27:50 craigs
85 * Added CleanupOnTermination functions
86 * Thanks to Vyacheslav Frolov
88 * Revision 1.8 2001/12/22 22:18:07 craigs
89 * Canged to ignore subsequent PDUs with identical sequence numbers
91 * Revision 1.7 2001/12/22 01:56:51 robertj
92 * Cleaned up code and allowed for repeated sequence numbers.
94 * Revision 1.6 2001/12/19 09:15:43 craigs
95 * Added changes from Vyacheslav Frolov
97 * Revision 1.5 2001/12/14 08:36:36 robertj
98 * More implementation of T.38, thanks Adam Lazur
100 * Revision 1.4 2001/11/11 23:18:53 robertj
101 * MSVC warnings removed.
103 * Revision 1.3 2001/11/11 23:07:52 robertj
104 * Some clean ups after T.38 commit, thanks Adam Lazur
106 * Revision 1.2 2001/11/09 05:39:54 craigs
107 * Added initial T.38 support thanks to Adam Lazur
109 * Revision 1.1 2001/07/17 04:44:32 robertj
110 * Partial implementation of T.120 and T.38 logical channels.
114 #include <ptlib.h>
116 #ifdef __GNUC__
117 #pragma implementation "t38proto.h"
118 #endif
120 #include <t38/t38proto.h>
122 #include <h323/transaddr.h>
123 #include <asn/t38.h>
126 #define new PNEW
129 const OpalMediaFormat OpalT38(
130 OPAL_T38,
131 OpalMediaFormat::DefaultDataSessionID,
132 RTP_DataFrame::IllegalPayloadType,
133 "t38",
134 FALSE, // No jitter for data
135 1440, // 100's bits/sec
141 /////////////////////////////////////////////////////////////////////////////
143 OpalT38Protocol::OpalT38Protocol()
145 transport = NULL;
146 autoDeleteTransport = FALSE;
147 corrigendumASN = TRUE;
148 indicatorRedundancy = 0;
149 lowSpeedRedundancy = 0;
150 highSpeedRedundancy = 0;
151 lastSentSequenceNumber = -1;
155 OpalT38Protocol::~OpalT38Protocol()
157 if (autoDeleteTransport)
158 delete transport;
161 void OpalT38Protocol::Close()
163 transport->Close();
167 void OpalT38Protocol::SetTransport(H323Transport * t, BOOL autoDelete)
169 if (transport != t) {
170 if (autoDeleteTransport)
171 delete transport;
173 transport = t;
176 autoDeleteTransport = autoDelete;
180 BOOL OpalT38Protocol::Originate()
182 PTRACE(3, "T38\tOriginate, transport=" << *transport);
184 // Application would normally override this. The default just sends
185 // a "heartbeat".
186 while (WriteIndicator(T38_Type_of_msg_t30_indicator::e_no_signal))
187 PThread::Sleep(500);
189 return FALSE;
193 BOOL OpalT38Protocol::WritePacket(const T38_IFPPacket & ifp)
195 T38_UDPTLPacket udptl;
197 // If there are redundant frames saved from last time, put them in
198 if (!redundantIFPs.IsEmpty()) {
199 udptl.m_error_recovery.SetTag(T38_UDPTLPacket_error_recovery::e_secondary_ifp_packets);
200 T38_UDPTLPacket_error_recovery_secondary_ifp_packets & secondary = udptl.m_error_recovery;
201 secondary.SetSize(redundantIFPs.GetSize());
202 for (PINDEX i = 0; i < redundantIFPs.GetSize(); i++)
203 secondary[i].SetValue(redundantIFPs[i]);
206 // Encode the current ifp, but need to do stupid things as there are two
207 // versions of the ASN out there, completely incompatible.
208 if (corrigendumASN || !ifp.HasOptionalField(T38_IFPPacket::e_data_field))
209 udptl.m_primary_ifp_packet.EncodeSubType(ifp);
210 else {
211 T38_PreCorrigendum_IFPPacket old_ifp;
213 old_ifp.m_type_of_msg = ifp.m_type_of_msg;
215 old_ifp.IncludeOptionalField(T38_IFPPacket::e_data_field);
217 PINDEX count = ifp.m_data_field.GetSize();
218 old_ifp.m_data_field.SetSize(count);
220 for (PINDEX i = 0 ; i < count; i++) {
221 old_ifp.m_data_field[i].m_field_type = ifp.m_data_field[i].m_field_type;
222 if (ifp.m_data_field[i].HasOptionalField(T38_Data_Field_subtype::e_field_data)) {
223 old_ifp.m_data_field[i].IncludeOptionalField(T38_Data_Field_subtype::e_field_data);
224 old_ifp.m_data_field[i].m_field_data = ifp.m_data_field[i].m_field_data;
228 udptl.m_primary_ifp_packet.PASN_OctetString::EncodeSubType(old_ifp);
231 lastSentSequenceNumber = (lastSentSequenceNumber + 1) & 0xffff;
232 udptl.m_seq_number = lastSentSequenceNumber;
234 PPER_Stream rawData;
235 udptl.Encode(rawData);
237 #if PTRACING
238 if (PTrace::CanTrace(4)) {
239 PTRACE(4, "T38\tSending PDU:\n "
240 << setprecision(2) << ifp << "\n "
241 << setprecision(2) << udptl << "\n "
242 << setprecision(2) << rawData);
244 else {
245 PTRACE(3, "T38\tSending PDU:"
246 " seq=" << lastSentSequenceNumber <<
247 " type=" << ifp.m_type_of_msg.GetTagName());
249 #endif
251 if (!transport->WritePDU(rawData)) {
252 PTRACE(1, "T38\tWritePacket error: " << transport->GetErrorText());
253 return FALSE;
256 // Calculate the level of redundency for this data phase
257 PINDEX maxRedundancy;
258 if (ifp.m_type_of_msg.GetTag() == T38_Type_of_msg::e_t30_indicator)
259 maxRedundancy = indicatorRedundancy;
260 else if ((T38_Type_of_msg_data)ifp.m_type_of_msg == T38_Type_of_msg_data::e_v21)
261 maxRedundancy = lowSpeedRedundancy;
262 else
263 maxRedundancy = highSpeedRedundancy;
265 // Push down the current ifp into redundant data
266 if (maxRedundancy > 0)
267 redundantIFPs.InsertAt(0, new PBYTEArray(udptl.m_primary_ifp_packet.GetValue()));
269 // Remove redundant data that are surplus to requirements
270 while (redundantIFPs.GetSize() > maxRedundancy)
271 redundantIFPs.RemoveAt(maxRedundancy);
273 return TRUE;
277 BOOL OpalT38Protocol::WriteIndicator(unsigned indicator)
279 T38_IFPPacket ifp;
281 ifp.SetTag(T38_Type_of_msg::e_t30_indicator);
282 T38_Type_of_msg_t30_indicator & ind = ifp.m_type_of_msg;
283 ind.SetValue(indicator);
285 return WritePacket(ifp);
289 BOOL OpalT38Protocol::WriteMultipleData(unsigned mode,
290 PINDEX count,
291 unsigned * type,
292 const PBYTEArray * data)
294 T38_IFPPacket ifp;
296 ifp.SetTag(T38_Type_of_msg::e_data);
297 T38_Type_of_msg_data & datamode = ifp.m_type_of_msg;
298 datamode.SetValue(mode);
300 ifp.IncludeOptionalField(T38_IFPPacket::e_data_field);
301 ifp.m_data_field.SetSize(count);
302 for (PINDEX i = 0; i < count; i++) {
303 ifp.m_data_field[i].m_field_type.SetValue(type[i]);
304 ifp.m_data_field[i].m_field_data.SetValue(data[i]);
307 return WritePacket(ifp);
311 BOOL OpalT38Protocol::WriteData(unsigned mode, unsigned type, const PBYTEArray & data)
313 return WriteMultipleData(mode, 1, &type, &data);
317 BOOL OpalT38Protocol::Answer()
319 PTRACE(3, "T38\tAnswer, transport=" << *transport);
321 // Should probably get this from the channel open negotiation, but for
322 // the time being just accept from whoever sends us something first
323 transport->SetPromiscuous(H323Transport::AcceptFromAnyAutoSet);
325 int consecutiveBadPackets = 0;
326 int expectedSequenceNumber = 0; // 16 bit
327 BOOL firstPacket = TRUE;
329 for (;;) {
330 PPER_Stream rawData;
331 if (!transport->ReadPDU(rawData)) {
332 PTRACE(1, "T38\tError reading PDU: " << transport->GetErrorText(PChannel::LastReadError));
333 return FALSE;
336 /* when we get the first packet, set the RemoteAddress and then turn off
337 * promiscuous listening */
338 if (firstPacket) {
339 PTRACE(3, "T38\tReceived first packet, remote=" << transport->GetRemoteAddress());
340 transport->SetPromiscuous(H323Transport::AcceptFromRemoteOnly);
341 firstPacket = FALSE;
344 // Decode the PDU
345 T38_UDPTLPacket udptl;
346 if (udptl.Decode(rawData))
347 consecutiveBadPackets = 0;
348 else {
349 consecutiveBadPackets++;
350 PTRACE(2, "T38\tRaw data decode failure:\n "
351 << setprecision(2) << rawData << "\n UDPTL = "
352 << setprecision(2) << udptl);
353 if (consecutiveBadPackets > 3) {
354 PTRACE(1, "T38\tRaw data decode failed multiple times, aborting!");
355 return FALSE;
357 continue;
360 T38_IFPPacket ifp;
361 if (!udptl.m_primary_ifp_packet.DecodeSubType(ifp)) {
362 PTRACE(2, "T38\tUDPTLPacket decode failure:\n "
363 << setprecision(2) << rawData << "\n UDPTL = "
364 << setprecision(2) << udptl << "\n ifp = "
365 << setprecision(2) << ifp);
366 continue;
369 unsigned receivedSequenceNumber = udptl.m_seq_number;
371 #if PTRACING
372 if (PTrace::CanTrace(5)) {
373 PTRACE(4, "T38\tReceived UDPTL packet:\n "
374 << setprecision(2) << rawData << "\n "
375 << setprecision(2) << udptl);
377 if (PTrace::CanTrace(4)) {
378 PTRACE(4, "T38\tReceived UDPTL packet:\n " << setprecision(2) << udptl);
380 else {
381 PTRACE(3, "T38\tReceived UDPTL packet: seq=" << receivedSequenceNumber);
383 #endif
385 // Calculate the number of lost packets, if the number lost is really
386 // really big then it means it is actually a packet arriving out of order
387 int lostPackets = (receivedSequenceNumber - expectedSequenceNumber)&0xffff;
388 if (lostPackets > 32767) {
389 PTRACE(3, "T38\tIgnoring out of order packet");
390 continue;
393 expectedSequenceNumber = (WORD)(receivedSequenceNumber+1);
395 // See if this is the expected packet
396 if (lostPackets > 0) {
397 // Not what was expected, see if we have enough redundant data
398 if (udptl.m_error_recovery.GetTag() == T38_UDPTLPacket_error_recovery::e_secondary_ifp_packets) {
399 T38_UDPTLPacket_error_recovery_secondary_ifp_packets & secondary = udptl.m_error_recovery;
400 int nRedundancy = secondary.GetSize();
401 if (lostPackets >= nRedundancy) {
402 if (!HandlePacketLost(lostPackets - nRedundancy)) {
403 PTRACE(1, "T38\tHandle packet failed, aborting answer");
404 return FALSE;
406 lostPackets = nRedundancy;
408 while (lostPackets > 0) {
409 if (!HandleRawIFP(secondary[lostPackets++])) {
410 PTRACE(1, "T38\tHandle packet failed, aborting answer");
411 return FALSE;
415 else {
416 if (!HandlePacketLost(lostPackets)) {
417 PTRACE(1, "T38\tHandle lost packet, aborting answer");
418 return FALSE;
423 if (!HandleRawIFP(udptl.m_primary_ifp_packet)) {
424 PTRACE(1, "T38\tHandle packet failed, aborting answer");
425 return FALSE;
431 BOOL OpalT38Protocol::HandleRawIFP(const PASN_OctetString & pdu)
433 T38_IFPPacket ifp;
435 if (corrigendumASN) {
436 if (pdu.DecodeSubType(ifp))
437 return HandlePacket(ifp);
439 PTRACE(2, "T38\tIFP decode failure:\n " << setprecision(2) << ifp);
440 return TRUE;
443 T38_PreCorrigendum_IFPPacket old_ifp;
444 if (!pdu.DecodeSubType(old_ifp)) {
445 PTRACE(2, "T38\tPre-corrigendum IFP decode failure:\n " << setprecision(2) << old_ifp);
446 return TRUE;
449 ifp.m_type_of_msg = old_ifp.m_type_of_msg;
451 if (old_ifp.HasOptionalField(T38_IFPPacket::e_data_field)) {
452 ifp.IncludeOptionalField(T38_IFPPacket::e_data_field);
453 PINDEX count = old_ifp.m_data_field.GetSize();
454 ifp.m_data_field.SetSize(count);
455 for (PINDEX i = 0 ; i < count; i++) {
456 ifp.m_data_field[i].m_field_type = old_ifp.m_data_field[i].m_field_type;
457 if (old_ifp.m_data_field[i].HasOptionalField(T38_Data_Field_subtype::e_field_data)) {
458 ifp.m_data_field[i].IncludeOptionalField(T38_Data_Field_subtype::e_field_data);
459 ifp.m_data_field[i].m_field_data = old_ifp.m_data_field[i].m_field_data;
464 return HandlePacket(ifp);
468 BOOL OpalT38Protocol::HandlePacket(const T38_IFPPacket & ifp)
470 if (ifp.m_type_of_msg.GetTag() == T38_Type_of_msg::e_t30_indicator)
471 return OnIndicator((T38_Type_of_msg_t30_indicator)ifp.m_type_of_msg);
473 for (PINDEX i = 0; i < ifp.m_data_field.GetSize(); i++) {
474 if (!OnData((T38_Type_of_msg_data)ifp.m_type_of_msg,
475 ifp.m_data_field[i].m_field_type,
476 ifp.m_data_field[i].m_field_data.GetValue()))
477 return FALSE;
479 return TRUE;
483 BOOL OpalT38Protocol::OnIndicator(unsigned indicator)
485 switch (indicator) {
486 case T38_Type_of_msg_t30_indicator::e_no_signal :
487 break;
489 case T38_Type_of_msg_t30_indicator::e_cng :
490 return OnCNG();
492 case T38_Type_of_msg_t30_indicator::e_ced :
493 return OnCED();
495 case T38_Type_of_msg_t30_indicator::e_v21_preamble :
496 return OnPreamble();
498 case T38_Type_of_msg_t30_indicator::e_v27_2400_training :
499 case T38_Type_of_msg_t30_indicator::e_v27_4800_training :
500 case T38_Type_of_msg_t30_indicator::e_v29_7200_training :
501 case T38_Type_of_msg_t30_indicator::e_v29_9600_training :
502 case T38_Type_of_msg_t30_indicator::e_v17_7200_short_training :
503 case T38_Type_of_msg_t30_indicator::e_v17_7200_long_training :
504 case T38_Type_of_msg_t30_indicator::e_v17_9600_short_training :
505 case T38_Type_of_msg_t30_indicator::e_v17_9600_long_training :
506 case T38_Type_of_msg_t30_indicator::e_v17_12000_short_training :
507 case T38_Type_of_msg_t30_indicator::e_v17_12000_long_training :
508 case T38_Type_of_msg_t30_indicator::e_v17_14400_short_training :
509 case T38_Type_of_msg_t30_indicator::e_v17_14400_long_training :
510 return OnTraining(indicator);
512 default:
513 break;
516 return TRUE;
520 BOOL OpalT38Protocol::OnCNG()
522 return TRUE;
526 BOOL OpalT38Protocol::OnCED()
528 return TRUE;
532 BOOL OpalT38Protocol::OnPreamble()
534 return TRUE;
538 BOOL OpalT38Protocol::OnTraining(unsigned /*indicator*/)
540 return TRUE;
544 BOOL OpalT38Protocol::OnData(unsigned /*mode*/,
545 unsigned /*type*/,
546 const PBYTEArray & /*data*/)
548 return TRUE;
552 #if PTRACING
553 #define PTRACE_nLost nLost
554 #else
555 #define PTRACE_nLost
556 #endif
558 BOOL OpalT38Protocol::HandlePacketLost(unsigned PTRACE_nLost)
560 PTRACE(2, "T38\tHandlePacketLost, n=" << PTRACE_nLost);
561 /* don't handle lost packets yet */
562 return TRUE;
566 /////////////////////////////////////////////////////////////////////////////