1 /*
2 * Fax plugin codec for OPAL using SpanDSP
3 *
4 * Copyright (C) 2008 Post Increment, All Rights Reserved
5 *
6 * Contributor(s): Craig Southeren (craigs@postincrement.com)
7 * Robert Jongbloed (robertj@voxlucida.com.au)
8 * Vyacheslav Frolov
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License version 2.1,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * $Revision$
24 * $Author$
25 * $Date$
26 */
27
28 #include <codec/opalplugin.h>
29
30 extern "C" {
31 #include "spandsp.h"
32 };
33
34 #include <stdlib.h>
35
36 #if defined(_WIN32) || defined(_WIN32_WCE)
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
39 #include <io.h>
40 #define access _access
41 #define W_OK 2
42 #define R_OK 4
43 #define DIR_SEPERATORS "/\\:"
44 #else
45 #include <unistd.h>
46 #include <pthread.h>
47 #define DIR_SEPERATORS "/"
48 #endif
49
50 #include <sstream>
51 #include <vector>
52 #include <queue>
53 #include <map>
54
55
56 #define LOGGING 1
57 #define LOG_LEVEL_DEBUG 6
58 #define LOG_LEVEL_CONTEXT_ID 3
59
60 #define PCM_TRANSMIT_ON_IDLE true
61 #define DEFAULT_USE_ECM true
62
63 #define T38_PAYLOAD_CODE 38
64
65 #define BITS_PER_SECOND 14400
66 #define MICROSECONDS_PER_FRAME 20000
67 #define SAMPLES_PER_FRAME 160
68 #define BYTES_PER_FRAME 320
69 #define PREF_FRAMES_PER_PACKET 1
70 #define MAX_FRAMES_PER_PACKET 1
71
72
73 #if LOGGING
74
75 static PluginCodec_LogFunction LogFunction;
76
77 #define PTRACE_PARAM(param) param
78
79 #define PTRACE(level, args) \
80 if (LogFunction != NULL && LogFunction(level, NULL, 0, NULL, NULL)) { \
81 std::ostringstream strm; strm << args; \
82 LogFunction(level, __FILE__, __LINE__, "FaxCodec", strm.str().c_str()); \
83 } else (void)0
84
SpanDSP_Message(void * user_data,int level,const char * text)85 static void SpanDSP_Message(void *user_data, int level, const char *text)
86 {
87 if (*text != '\0' && LogFunction != NULL) {
88 if (level >= SPAN_LOG_DEBUG)
89 level = 5;
90 else
91 if (level >= SPAN_LOG_FLOW)
92 level = 4;
93 //else
94 //if (level >= SPAN_LOG_PROTOCOL_WARNING)
95 // level = 3;
96 else
97 if (level >= SPAN_LOG_PROTOCOL_ERROR)
98 level = 3;
99 //else
100 //if (level >= SPAN_LOG_WARNING)
101 // level = 3;
102 //else
103 //if (level >= SPAN_LOG_ERROR)
104 // level = 2;
105 else
106 level = 2;
107
108 if (!LogFunction(level, NULL, 0, NULL, NULL))
109 return;
110
111 int last = strlen(text)-1;
112 if (text[last] == '\n')
113 ((char *)text)[last] = '\0';
114 LogFunction(level, __FILE__, __LINE__, "SpanDSP", text);
115 }
116 }
117
InitLogging(logging_state_t * logging,const std::string & tag)118 static void InitLogging(logging_state_t * logging, const std::string & tag)
119 {
120 span_log_set_message_handler(logging, SpanDSP_Message, NULL);
121
122 int level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG;
123
124 if (!tag.empty()) {
125 level |= SPAN_LOG_SHOW_TAG;
126 span_log_set_tag(logging, tag.c_str());
127 }
128
129 span_log_set_level(logging, level);
130 }
131
132 class Tag
133 {
134 protected:
135 std::string m_tag;
136 };
137
138 #else // LOGGING
139
140 #define PTRACE_PARAM(param)
141 #define PTRACE(level, expr)
142 #define InitLogging(logging, tag)
143
144 #endif // LOGGING
145
146 /////////////////////////////////////////////////////////////////////////////
147
148 static const char L16Format[] = "L16";
149 static const char T38Format[] = "T.38";
150 static const char TIFFFormat[] = "TIFF-File";
151 static const char T38sdp[] = "t38";
152
153
154 static struct PluginCodec_Option const ReceivingOption =
155 {
156 PluginCodec_BoolOption, // PluginCodec_OptionTypes
157 "Receiving", // Generic (human readable) option name
158 true, // Read Only flag
159 PluginCodec_OrMerge, // Merge mode
160 "0", // Initial value
161 NULL, // SIP/SDP FMTP name
162 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
163 0 // H.245 Generic Capability number and scope bits
164 };
165
166 static struct PluginCodec_Option const TiffFileNameOption =
167 {
168 PluginCodec_StringOption, // PluginCodec_OptionTypes
169 "TIFF-File-Name", // Generic (human readable) option name
170 true, // Read Only flag
171 PluginCodec_MaxMerge, // Merge mode
172 "", // Initial value
173 NULL, // SIP/SDP FMTP name
174 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
175 0 // H.245 Generic Capability number and scope bits
176 };
177
178 static struct PluginCodec_Option const StationIdentifierOption =
179 {
180 PluginCodec_StringOption, // PluginCodec_OptionTypes
181 "Station-Identifier", // Generic (human readable) option name
182 true, // Read Only flag
183 PluginCodec_AlwaysMerge, // Merge mode
184 "", // Initial value
185 NULL, // SIP/SDP FMTP name
186 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
187 0 // H.245 Generic Capability number and scope bits
188 };
189
190 static struct PluginCodec_Option const HeaderInfoOption =
191 {
192 PluginCodec_StringOption, // PluginCodec_OptionTypes
193 "Header-Info", // Generic (human readable) option name
194 true, // Read Only flag
195 PluginCodec_MaxMerge, // Merge mode
196 "", // Initial value
197 NULL, // SIP/SDP FMTP name
198 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
199 0 // H.245 Generic Capability number and scope bits
200 };
201
202 static struct PluginCodec_Option const UseEcmOption =
203 {
204 PluginCodec_BoolOption, // PluginCodec_OptionTypes
205 "Use-ECM", // Generic (human readable) option name
206 false, // Read Only flag
207 PluginCodec_OrMerge, // Merge mode
208 "0", // Initial value
209 NULL, // SIP/SDP FMTP name
210 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
211 0 // H.245 Generic Capability number and scope bits
212 };
213
214
215 /*T.38/D.2.3.5
216 T38FaxVersion is negotiated. The entity answering the offer shall return the
217 same or a lower version number.
218 */
219 static struct PluginCodec_Option const T38FaxVersion =
220 {
221 PluginCodec_IntegerOption, // PluginCodec_OptionTypes
222 "T38FaxVersion", // Generic (human readable) option name
223 false, // Read Only flag
224 PluginCodec_MinMerge, // Merge mode
225 "0", // Initial value
226 NULL, // SIP/SDP FMTP name
227 "0", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
228 0, // H.245 Generic Capability number and scope bits
229 "0", // Minimum value
230 "1" // Maximum value
231 };
232
233 /*T.38/D.2.3.5
234 T38FaxRateManagement is declarative and the answer must contain the same value.
235 Note is also compulsory so has no default value.
236 */
237 static struct PluginCodec_Option const T38FaxRateManagement =
238 {
239 PluginCodec_EnumOption, // PluginCodec_OptionTypes
240 "T38FaxRateManagement", // Generic (human readable) option name
241 false, // Read Only flag
242 PluginCodec_AlwaysMerge, // Merge mode
243 "transferredTCF", // Initial value
244 NULL, // SIP/SDP FMTP name
245 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
246 0, // H.245 Generic Capability number and scope bits
247 "localTCF:transferredTCF" // enum values
248 };
249
250 /*T.38/D.2.3.5
251 T38MaxBitRate is declarative and the answer is independent of the offer. The
252 parameter simply indicates the maximum transmission bit rate supported by
253 the endpoint.
254 */
255 static struct PluginCodec_Option const T38MaxBitRate =
256 {
257 PluginCodec_IntegerOption, // PluginCodec_OptionTypes
258 "T38MaxBitRate", // Generic (human readable) option name
259 false, // Read Only flag
260 PluginCodec_NoMerge, // Merge mode
261 "14400", // Initial value
262 NULL, // SIP/SDP FMTP name
263 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
264 0, // H.245 Generic Capability number and scope bits
265 "300", // Minimum value
266 "56000" // Maximum value
267 };
268
269 /*T.38/D.2.3.5
270 T38FaxMaxBuffer is declarative and the answer is independent of the offer.
271 This parameter simply signals the buffer space available on the offering
272 endpoint and the answering endpoint. The answering endpoint may have more or
273 less buffer space than the offering endpoint. Each endpoint should be
274 considerate of the available buffer space on the opposite endpoint.
275 */
276 static struct PluginCodec_Option const T38FaxMaxBuffer =
277 {
278 PluginCodec_IntegerOption, // PluginCodec_OptionTypes
279 "T38FaxMaxBuffer", // Generic (human readable) option name
280 false, // Read Only flag
281 PluginCodec_NoMerge, // Merge mode
282 "2000", // Initial value
283 NULL, // SIP/SDP FMTP name
284 "528", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
285 0, // H.245 Generic Capability number and scope bits
286 "100", // Minimum value
287 "9999" // Maximum value
288 };
289
290 /*T.38/D.2.3.5
291 T38FaxMaxDatagram is declarative and the answer is independent of the offer.
292 This parameter signals the largest acceptable datagram for the offering
293 endpoint and the answering endpoint (i.e., the maximum size of the RTP
294 payload). The answering endpoint may accept a larger or smaller datagram
295 than the offering endpoint. Each endpoint should be considerate of the
296 maximum datagram size of the opposite endpoint.
297 */
298 static struct PluginCodec_Option const T38FaxMaxDatagram =
299 {
300 PluginCodec_IntegerOption, // PluginCodec_OptionTypes
301 "T38FaxMaxDatagram", // Generic (human readable) option name
302 false, // Read Only flag
303 PluginCodec_NoMerge, // Merge mode
304 "1400", // Initial value
305 NULL, // SIP/SDP FMTP name
306 "528", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
307 0, // H.245 Generic Capability number and scope bits
308 "10", // Minimum value
309 "1500" // Maximum value
310 };
311
312 /*T.38/D.2.3.5
313 T38FaxUdpEC is negotiated only when using UDPTL as the transport. If the
314 answering endpoint supports the offered error correction mode, then it shall
315 return the same value in the answer, otherwise the T38FaxUdpEC parameter
316 shall not be present in the answer.
317 */
318 static struct PluginCodec_Option const T38FaxUdpEC =
319 {
320 PluginCodec_EnumOption, // PluginCodec_OptionTypes
321 "T38FaxUdpEC", // Generic (human readable) option name
322 false, // Read Only flag
323 PluginCodec_AlwaysMerge, // Merge mode
324 "t38UDPRedundancy", // Initial value
325 NULL, // SIP/SDP FMTP name
326 NULL, // SIP/SDP FMTP default value (option not included in FMTP if have this value)
327 0, // H.245 Generic Capability number and scope bits
328 "t38UDPFEC:t38UDPRedundancy"// enum values
329 };
330
331 /*T.38/D.2.3.5
332 T38FaxFillBitRemoval is negotiated. If the answering entity does not support
333 this capability or if the capability was not in the offer, this parameter
334 shall not be present in the answer.
335 */
336 static struct PluginCodec_Option const T38FaxFillBitRemoval =
337 {
338 PluginCodec_BoolOption, // PluginCodec_OptionTypes
339 "T38FaxFillBitRemoval", // Generic (human readable) option name
340 false, // Read Only flag
341 PluginCodec_AndMerge, // Merge mode
342 "0", // Initial value
343 NULL, // SIP/SDP FMTP name
344 "0", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
345 0 // H.245 Generic Capability number and scope bits
346 };
347
348 /*T.38/D.2.3.5
349 T38FaxTranscodingMMR is negotiated. If the answering entity does not support
350 this capability or if the capability was not in the offer, this parameter
351 shall not be present in the answer.
352 */
353 static struct PluginCodec_Option const T38FaxTranscodingMMR =
354 {
355 PluginCodec_BoolOption, // PluginCodec_OptionTypes
356 "T38FaxTranscodingMMR", // Generic (human readable) option name
357 false, // Read Only flag
358 PluginCodec_AndMerge, // Merge mode
359 "0", // Initial value
360 NULL, // SIP/SDP FMTP name
361 "0", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
362 0 // H.245 Generic Capability number and scope bits
363 };
364
365 /*T.38/D.2.3.5
366 T38FaxTranscodingJBIG is negotiated. If the answering entity does not
367 support this capability or if the capability was not in the offer, this
368 parameter shall not be present in the answer.
369 */
370 static struct PluginCodec_Option const T38FaxTranscodingJBIG =
371 {
372 PluginCodec_BoolOption, // PluginCodec_OptionTypes
373 "T38FaxTranscodingJBIG", // Generic (human readable) option name
374 false, // Read Only flag
375 PluginCodec_AndMerge, // Merge mode
376 "0", // Initial value
377 NULL, // SIP/SDP FMTP name
378 "0", // SIP/SDP FMTP default value (option not included in FMTP if have this value)
379 0 // H.245 Generic Capability number and scope bits
380 };
381
382 static struct PluginCodec_Option const * const OptionTableTIFF[] = {
383 &ReceivingOption,
384 &TiffFileNameOption,
385 &HeaderInfoOption,
386 &UseEcmOption,
387 NULL
388 };
389
390 static struct PluginCodec_Option const * const OptionTableT38[] = {
391 &T38FaxVersion,
392 &T38FaxRateManagement,
393 &T38MaxBitRate,
394 &T38FaxMaxBuffer,
395 &T38FaxMaxDatagram,
396 &T38FaxUdpEC,
397 &T38FaxFillBitRemoval,
398 &T38FaxTranscodingMMR,
399 &T38FaxTranscodingJBIG,
400 &StationIdentifierOption,
401 &HeaderInfoOption,
402 &UseEcmOption,
403 NULL
404 };
405
406 static struct PluginCodec_Option const * const OptionTablePCM[] = {
407 NULL
408 };
409
410
411 /////////////////////////////////////////////////////////////////
412 //
413 // define a class to implement a critical section mutex
414 // based on PCriticalSection from PWLib
415
416 #ifdef _WIN32
417 class CriticalSection
418 {
419 private:
420 CRITICAL_SECTION m_CriticalSection;
421 public:
CriticalSection()422 inline CriticalSection() { InitializeCriticalSection(&m_CriticalSection); }
~CriticalSection()423 inline ~CriticalSection() { DeleteCriticalSection(&m_CriticalSection); }
Wait()424 inline void Wait() { EnterCriticalSection(&m_CriticalSection); }
Signal()425 inline void Signal() { LeaveCriticalSection(&m_CriticalSection); }
426 };
427 #else
428 class CriticalSection
429 {
430 private:
431 pthread_mutex_t m_Mutex;
432 public:
CriticalSection()433 inline CriticalSection() { pthread_mutex_init(&m_Mutex, NULL); }
~CriticalSection()434 inline ~CriticalSection() { pthread_mutex_destroy(&m_Mutex); }
Wait()435 inline void Wait() { pthread_mutex_lock(&m_Mutex); }
Signal()436 inline void Signal() { pthread_mutex_unlock(&m_Mutex); }
437 };
438 #endif
439
440 class WaitAndSignal
441 {
442 private:
443 CriticalSection & m_criticalSection;
444
operator =(const WaitAndSignal &)445 void operator=(const WaitAndSignal &) { }
WaitAndSignal(const WaitAndSignal & other)446 WaitAndSignal(const WaitAndSignal & other) : m_criticalSection(other.m_criticalSection) { }
447 public:
WaitAndSignal(const CriticalSection & cs)448 inline WaitAndSignal(const CriticalSection & cs)
449 : m_criticalSection((CriticalSection &)cs) { m_criticalSection.Wait(); }
~WaitAndSignal()450 inline ~WaitAndSignal() { m_criticalSection.Signal(); }
451 };
452
453
454 /////////////////////////////////////////////////////////////////
455
ParseBool(const char * str)456 static bool ParseBool(const char * str)
457 {
458 return str != NULL && *str != '\0' &&
459 (toupper(*str) == 'Y' || toupper(*str) == 'T' || atoi(str) != 0);
460 }
461
462
463 /////////////////////////////////////////////////////////////////
464
465 class FaxSpanDSP
466 #if LOGGING
467 : virtual public Tag
468 #endif
469 {
470 private:
471 unsigned m_referenceCount;
472
473 protected:
474 bool m_completed;
475 CriticalSection m_mutex;
476
477 bool m_useECM;
478 int m_supported_modems;
479
480 public:
FaxSpanDSP()481 FaxSpanDSP()
482 : m_referenceCount(1)
483 , m_completed(false)
484 , m_useECM(DEFAULT_USE_ECM)
485 , m_supported_modems(T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17)
486 {
487 }
488
489
~FaxSpanDSP()490 virtual ~FaxSpanDSP()
491 {
492 }
493
494
AddReference()495 void AddReference()
496 {
497 WaitAndSignal mutex(m_mutex);
498 ++m_referenceCount;
499 }
500
501
Dereference()502 bool Dereference()
503 {
504 WaitAndSignal mutex(m_mutex);
505 return --m_referenceCount == 0;
506 }
507
508
SetOptions(const char * const * options)509 bool SetOptions(const char * const * options)
510 {
511 if (options == NULL)
512 return false;
513
514 while (options[0] != NULL && options[1] != NULL) {
515 if (!SetOption(options[0], options[1]))
516 return false;
517 options += 2;
518 }
519
520 return true;
521 }
522
523 virtual bool Encode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags) = 0;
524 virtual bool Decode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags) = 0;
525 virtual bool Terminate() = 0;
526 virtual bool GetStats(void * fromPtr, unsigned fromLen) = 0;
527
528
529 protected:
SetOption(const char * PTRACE_PARAM (option),const char * PTRACE_PARAM (value))530 virtual bool SetOption(const char * PTRACE_PARAM(option), const char * PTRACE_PARAM(value))
531 {
532 PTRACE(3, m_tag << " SetOption: " << option << "=" << value);
533
534 if (strcasecmp(option, UseEcmOption.m_name) == 0) {
535 m_useECM = ParseBool(value);
536 return true;
537 }
538
539 return true;
540 }
541
HasError(bool retval,const char * errorMsg=NULL)542 bool HasError(bool retval, const char * errorMsg = NULL)
543 {
544 if (m_completed)
545 return true;
546
547 if (retval)
548 return false;
549
550 /// Error exit
551 m_completed = true;
552 if (errorMsg != NULL) {
553 PTRACE(1, m_tag << " Error: " << errorMsg);
554 }
555
556 return true;
557 }
558 };
559
560
561 /////////////////////////////////////////////////////////////////
562
563 class FaxT38
564 #if LOGGING
565 : virtual public Tag
566 #endif
567 {
568 private:
569 unsigned m_protoVersion;
570 unsigned m_RateManagement;
571 unsigned m_MaxBitRate;
572 unsigned m_MaxBuffer;
573 unsigned m_MaxDatagram;
574 unsigned m_UdpEC;
575 bool m_FillBitRemoval;
576 bool m_TranscodingMMR;
577 bool m_TranscodingJBIG;
578
579 t38_core_state_t * m_t38core;
580 int m_sequence;
581 std::queue< std::vector<uint8_t> > m_t38Queue;
582
583
584 protected:
FaxT38()585 FaxT38()
586 : m_protoVersion(0)
587 , m_RateManagement(1)
588 , m_MaxBitRate(14400)
589 , m_MaxBuffer(2000)
590 , m_MaxDatagram(528)
591 , m_UdpEC(1)
592 , m_FillBitRemoval(false)
593 , m_TranscodingMMR(false)
594 , m_TranscodingJBIG(false)
595 , m_t38core(NULL)
596 , m_sequence(0)
597 {
598 }
599
600
GetMaxBitRate() const601 unsigned GetMaxBitRate() const { return m_MaxBitRate; }
602
SetOption(const char * option,const char * value)603 bool SetOption(const char * option, const char * value)
604 {
605 if (strcasecmp(option, T38FaxVersion.m_name) == 0) {
606 m_protoVersion = atoi(value);
607 return true;
608 }
609
610 if (strcasecmp(option, T38FaxRateManagement.m_name) == 0) {
611 if (strcasecmp(value, "transferredTCF") == 0)
612 m_RateManagement = T38_DATA_RATE_MANAGEMENT_TRANSFERRED_TCF;
613 else if (strcasecmp(value, "localTCF") == 0)
614 m_RateManagement = T38_DATA_RATE_MANAGEMENT_LOCAL_TCF;
615 else
616 return false;
617 return true;
618 }
619
620 if (strcasecmp(option, T38MaxBitRate.m_name) == 0) {
621 m_MaxBitRate = atoi(value);
622 return true;
623 }
624
625 if (strcasecmp(option, T38FaxMaxBuffer.m_name) == 0) {
626 m_MaxBuffer = atoi(value);
627 return true;
628 }
629
630 if (strcasecmp(option, T38FaxMaxDatagram.m_name) == 0) {
631 m_MaxDatagram = atoi(value);
632 return true;
633 }
634
635 if (strcasecmp(option, T38FaxUdpEC.m_name) == 0) {
636 m_UdpEC = atoi(value);
637 return true;
638 }
639
640 if (strcasecmp(option, T38FaxFillBitRemoval.m_name) == 0) {
641 m_FillBitRemoval = ParseBool(value);
642 return true;
643 }
644
645 if (strcasecmp(option, T38FaxTranscodingMMR.m_name) == 0) {
646 m_TranscodingMMR = ParseBool(value);
647 return true;
648 }
649
650 if (strcasecmp(option, T38FaxTranscodingJBIG.m_name) == 0) {
651 m_TranscodingJBIG = ParseBool(value);
652 return true;
653 }
654
655 return true;
656 }
657
658
Open(t38_core_state_t * t38core)659 bool Open(t38_core_state_t * t38core)
660 {
661 m_t38core = t38core;
662 InitLogging(t38_core_get_logging_state(m_t38core), m_tag);
663 t38_set_t38_version(m_t38core, m_protoVersion);
664 t38_set_data_rate_management_method(m_t38core, m_RateManagement);
665 t38_set_fastest_image_data_rate(m_t38core, m_MaxBitRate);
666 t38_set_max_buffer_size(m_t38core, m_MaxBuffer);
667 t38_set_max_datagram_size(m_t38core, m_MaxDatagram);
668 // t38_set_XXXX(m_t38core, m_UdpEC); Don't know what this corresponds to!!
669 t38_set_fill_bit_removal(m_t38core, m_FillBitRemoval);
670 t38_set_mmr_transcoding(m_t38core, m_TranscodingMMR);
671 t38_set_jbig_transcoding(m_t38core, m_TranscodingJBIG);
672
673 return true;
674 }
675
676
EncodeRTP(void * toPtr,unsigned & toLen,unsigned & flags)677 bool EncodeRTP(void * toPtr, unsigned & toLen, unsigned & flags)
678 {
679 if (m_t38Queue.empty()) {
680 toLen = 0;
681 flags = PluginCodec_ReturnCoderLastFrame;
682 return true;
683 }
684
685 std::vector<uint8_t> & packet = m_t38Queue.front();
686 size_t size = packet.size() + PluginCodec_RTP_MinHeaderSize;
687
688 if (toLen < size)
689 return false;
690
691 toLen = size;
692
693 memcpy(PluginCodec_RTP_GetPayloadPtr(toPtr), &packet[0], packet.size());
694
695 uint16_t seq = uint16_t(m_sequence++);
696
697 #ifdef _MSC_VER
698 #pragma warning(disable:4244)
699 #endif
700 PluginCodec_RTP_SetSequenceNumber(toPtr, seq);
701 #ifdef _MSC_VER
702 #pragma warning(default:4244)
703 #endif
704
705 m_t38Queue.pop();
706
707 if (m_t38Queue.empty())
708 flags = PluginCodec_ReturnCoderLastFrame;
709
710 return true;
711 }
712
713
DecodeRTP(const void * fromPtr,unsigned & fromLen)714 bool DecodeRTP(const void * fromPtr, unsigned & fromLen)
715 {
716 int payloadSize = fromLen - PluginCodec_RTP_GetHeaderLength(fromPtr);
717
718 if (payloadSize < 0 || m_t38core == NULL)
719 return false;
720
721 if (payloadSize == 0)
722 return true;
723
724 return t38_core_rx_ifp_packet(m_t38core,
725 PluginCodec_RTP_GetPayloadPtr(fromPtr),
726 payloadSize,
727 PluginCodec_RTP_GetSequenceNumber(fromPtr)) != -1;
728 }
729
730
QueueT38(t38_core_state_t *,void * user_data,const uint8_t * buf,int len,int count)731 static int QueueT38(t38_core_state_t *, void * user_data, const uint8_t * buf, int len, int count)
732 {
733 if (user_data != NULL)
734 ((FaxT38 *)user_data)->QueueT38(buf, len, count);
735 return 0;
736 }
737
738 private:
QueueT38(const uint8_t * buf,int len,int)739 void QueueT38(const uint8_t * buf, int len, int /*count*/)
740 {
741 PTRACE(LOG_LEVEL_DEBUG, m_tag << " FaxT38::QueueT38 len=" << len);
742
743 m_t38Queue.push(std::vector<uint8_t>());
744 std::vector<uint8_t> & packet = m_t38Queue.back();
745
746 packet.resize(len);
747 memcpy(&packet[0], buf, len);
748 }
749 };
750
751
752 /////////////////////////////////////////////////////////////////
753
754 class FaxPCM
755 #if LOGGING
756 : virtual public Tag
757 #endif
758 {
759 private:
760 bool m_transmit_on_idle;
761
762 protected:
FaxPCM()763 FaxPCM()
764 : m_transmit_on_idle(PCM_TRANSMIT_ON_IDLE)
765 {
766 }
767
TransmitOnIdle() const768 bool TransmitOnIdle() const { return m_transmit_on_idle; }
769
SetOption(const char *,const char *)770 bool SetOption(const char * /*option*/, const char * /*value*/)
771 {
772 return true;
773 }
774 };
775
776
777 /////////////////////////////////////////////////////////////////
778
779 class MyStats : private t30_stats_t
780 {
781 bool m_completed;
782 bool m_receiving;
783 char m_phase;
784 std::string m_stationId;
785
786 public:
MyStats(t30_state_t * t30state,bool completed,bool receiving,char phase)787 MyStats(t30_state_t * t30state, bool completed, bool receiving, char phase)
788 : m_completed(completed)
789 , m_receiving(receiving)
790 , m_phase(phase)
791 {
792 t30_get_transfer_statistics(t30state, this);
793 const char * stationId = t30_get_rx_ident(t30state);
794 if (stationId != NULL && *stationId != '\0')
795 m_stationId = stationId;
796 }
797
798
operator <<(std::ostream & strm,const MyStats & stats)799 friend std::ostream & operator<<(std::ostream & strm, const MyStats & stats)
800 {
801 static const char * const CompressionNames[4] = { "N/A", "T.4 1d", "T.4 2d", "T.6" };
802
803 strm << "Status=";
804 if (stats.m_completed)
805 strm << stats.current_status << " (" << t30_completion_code_to_str(stats.current_status) << ')';
806 else
807 strm << "-1 (In progress)";
808 strm << "\n"
809 "Bit Rate=" << stats.bit_rate << "\n"
810 "Encoding=" << stats.compression << ' ' << CompressionNames[stats.compression&3] << "\n"
811 "Error Correction=" << stats.error_correcting_mode << "\n"
812 "Tx Pages=" << (stats.m_receiving ? -1 : stats.pages_tx) << "\n"
813 "Rx Pages=" << (stats.m_receiving ? stats.pages_rx : -1) << "\n"
814 "Total Pages=" << stats.pages_in_file << "\n"
815 "Image Bytes=" << stats.image_size << "\n"
816 "Resolution=" << stats.x_resolution << 'x' << stats.y_resolution << "\n"
817 "Page Size=" << stats.width << 'x' << stats.length << "\n"
818 "Bad Rows=" << stats.bad_rows << "\n"
819 "Most Bad Rows=" << stats.longest_bad_row_run << "\n"
820 "Correction Retries=" << stats.error_correcting_mode_retries << "\n"
821 "Station Identifier=" << stats.m_stationId << "\n"
822 "Phase=" << stats.m_phase;
823
824 return strm;
825 }
826 };
827
828
829 class FaxTIFF : public FaxSpanDSP
830 {
831 private:
832 bool m_receiving;
833 std::string m_tiffFileName;
834 std::string m_stationIdentifer;
835 std::string m_headerInfo;
836 int m_supported_image_sizes;
837 int m_supported_resolutions;
838 int m_supported_compressions;
839 char m_phase;
840
841 protected:
842 t30_state_t * m_t30State;
843
FaxTIFF()844 FaxTIFF()
845 : m_receiving(false)
846 , m_stationIdentifer("-")
847 , m_supported_image_sizes(T4_SUPPORT_LENGTH_US_LETTER |
848 T4_SUPPORT_LENGTH_US_LEGAL |
849 T4_SUPPORT_LENGTH_UNLIMITED |
850 T4_SUPPORT_LENGTH_A4 |
851 T4_SUPPORT_LENGTH_B4 |
852 T4_SUPPORT_WIDTH_215MM |
853 T4_SUPPORT_WIDTH_255MM |
854 T4_SUPPORT_WIDTH_303MM)
855 , m_supported_resolutions(T4_RESOLUTION_R8_STANDARD |
856 T4_RESOLUTION_R8_FINE |
857 T4_RESOLUTION_R8_SUPERFINE |
858 T4_RESOLUTION_200_400 |
859 T4_RESOLUTION_400_400)
860 , m_supported_compressions(T4_COMPRESSION_T4_1D |
861 T4_COMPRESSION_T4_2D |
862 T4_COMPRESSION_T6)
863 , m_phase('A')
864 {
865 }
866
867
SetOption(const char * option,const char * value)868 virtual bool SetOption(const char * option, const char * value)
869 {
870 if (!FaxSpanDSP::SetOption(option, value))
871 return false;
872
873 if (strcasecmp(option, TiffFileNameOption.m_name) == 0) {
874 if (m_tiffFileName.empty())
875 m_tiffFileName = value;
876 #if LOGGING
877 else if (*value != '\0' && m_tiffFileName != value)
878 PTRACE(2, m_tag << " Cannot change filename in mid stream from \"" << m_tiffFileName << "\" to \"" << value << '"');
879 #endif
880 return true;
881 }
882
883 if (strcasecmp(option, ReceivingOption.m_name) == 0) {
884 m_receiving = ParseBool(value);
885 return true;
886 }
887
888 if (strcasecmp(option, StationIdentifierOption.m_name) == 0) {
889 m_stationIdentifer = *value != '\0' ? value : "-";
890 return true;
891 }
892
893 if (strcasecmp(option, HeaderInfoOption.m_name) == 0) {
894 m_headerInfo = value;
895 return true;
896 }
897
898 return true;
899 }
900
901
Open(t30_state_t * t30state)902 bool Open(t30_state_t * t30state)
903 {
904 InitLogging(t30_get_logging_state(t30state), m_tag);
905
906 if (m_tiffFileName.empty()) {
907 PTRACE(1, m_tag << " No TIFF file to " << m_receiving ? "receive" : "transmit");
908 return false;
909 }
910
911 if (m_receiving) {
912 std::string dir;
913 std::string::size_type pos = m_tiffFileName.find_last_of(DIR_SEPERATORS);
914 if (pos == std::string::npos)
915 dir = ".";
916 else
917 dir.assign(m_tiffFileName, 0, pos+1);
918
919 if (access(dir.c_str(), W_OK) != 0) {
920 PTRACE(1, m_tag << " Cannot set receive TIFF file to \"" << m_tiffFileName << '"');
921 return false;
922 }
923
924 t30_set_rx_file(t30state, m_tiffFileName.c_str(), -1);
925 PTRACE(3, m_tag << " Set receive TIFF file to \"" << m_tiffFileName << '"');
926 }
927 else {
928 if (access(m_tiffFileName.c_str(), R_OK) != 0) {
929 PTRACE(1, m_tag << " Cannot set transmit TIFF file to \"" << m_tiffFileName << '"');
930 return false;
931 }
932
933 t30_set_tx_file(t30state, m_tiffFileName.c_str(), -1, -1);
934 PTRACE(3, m_tag << " Set transmit TIFF file to \"" << m_tiffFileName << '"');
935 }
936
937 m_t30State = t30state;
938 t30_set_phase_b_handler(t30state, PhaseB, this);
939 t30_set_phase_d_handler(t30state, PhaseD, this);
940 t30_set_phase_e_handler(t30state, PhaseE, this);
941
942 t30_set_tx_ident(t30state, m_stationIdentifer.c_str());
943 PTRACE(4, m_tag << " Set Station-Identifier to \"" << m_stationIdentifer << '"');
944
945 if (!m_headerInfo.empty()) {
946 if (t30_set_tx_page_header_info(t30state, m_headerInfo.c_str()) < 0)
947 PTRACE(1, m_tag << " Cannot set Header-Info to \"" << m_headerInfo << '"');
948 else
949 PTRACE(4, m_tag << " Set Header-Info to \"" << m_headerInfo << '"');
950 }
951
952 t30_set_supported_modems(t30state, m_supported_modems);
953 t30_set_supported_image_sizes(t30state, m_supported_image_sizes);
954 t30_set_supported_bilevel_resolutions(t30state, m_supported_resolutions);
955 t30_set_supported_compressions(t30state, m_supported_compressions);
956 t30_set_ecm_capability(t30state, m_useECM);
957
958 return true;
959 }
960
961
GetStats(t30_state_t * t30state,void * fromPtr,unsigned fromLen)962 bool GetStats(t30_state_t * t30state, void * fromPtr, unsigned fromLen)
963 {
964 if (t30state == NULL)
965 return false;
966
967 MyStats stats(t30state, m_completed, m_receiving, m_phase);
968 std::stringstream strm;
969 strm << stats;
970
971 std::string str = strm.str();
972 size_t len = str.length() + 1;
973 if (len > fromLen) {
974 len = fromLen;
975 str[len-1] = '\0';
976 }
977
978 memcpy(fromPtr, str.c_str(), len);
979
980 PTRACE(4, m_tag << " SpanDSP statistics:\n" << (char *)fromPtr);
981
982 return true;
983 }
984
985
IsReceiving() const986 bool IsReceiving() const { return m_receiving; }
987
988
PhaseB(void * user_data,int result)989 static int PhaseB(void * user_data, int result)
990 {
991 if (user_data != NULL)
992 ((FaxTIFF *)user_data)->PhaseB(result);
993 return T30_ERR_OK;
994 }
995
PhaseD(void * user_data,int result)996 static int PhaseD(void * user_data, int result)
997 {
998 if (user_data != NULL)
999 ((FaxTIFF *)user_data)->PhaseD(result);
1000 return T30_ERR_OK;
1001 }
1002
PhaseE(void * user_data,int result)1003 static void PhaseE(void * user_data, int result)
1004 {
1005 if (user_data != NULL)
1006 ((FaxTIFF *)user_data)->PhaseE(result);
1007 }
1008
1009
1010 private:
PhaseB(int)1011 void PhaseB(int)
1012 {
1013 m_phase = 'B';
1014 PTRACE(3, m_tag << " SpanDSP entered Phase B:\n"
1015 << MyStats(this->m_t30State, m_completed, m_receiving, m_phase));
1016 }
1017
PhaseD(int)1018 void PhaseD(int)
1019 {
1020 m_phase = 'D';
1021 PTRACE(3, m_tag << " SpanDSP entered Phase D:\n"
1022 << MyStats(this->m_t30State, m_completed, m_receiving, m_phase));
1023 }
1024
PhaseE(int result)1025 void PhaseE(int result)
1026 {
1027 if (result >= 0)
1028 m_completed = true; // Finished, exit codec loops
1029
1030 m_phase = 'E';
1031 PTRACE(3, m_tag << " SpanDSP entered Phase E:\n"
1032 << MyStats(this->m_t30State, m_completed, m_receiving, m_phase));
1033 }
1034 };
1035
1036
1037 /////////////////////////////////////////////////////////////////
1038
1039 class T38_PCM : public FaxSpanDSP, public FaxT38, public FaxPCM
1040 {
1041 protected:
1042 t38_gateway_state_t * m_t38State;
1043
1044 public:
T38_PCM(PTRACE_PARAM (const std::string & tag))1045 T38_PCM(PTRACE_PARAM(const std::string &tag))
1046 : m_t38State(NULL)
1047 {
1048 #if LOGGING
1049 m_tag = tag;
1050 #endif
1051
1052 PTRACE(4, m_tag << " Created T38_PCM");
1053 }
1054
1055
~T38_PCM()1056 ~T38_PCM()
1057 {
1058 if (m_t38State != NULL) {
1059 t38_gateway_release(m_t38State);
1060 t38_gateway_free(m_t38State);
1061 PTRACE(3, m_tag << " Closed T38_PCM/SpanDSP");
1062 }
1063
1064 PTRACE(4, m_tag << " Deleted T38_PCM instance.");
1065 }
1066
1067
Encode(const void * fromPtr,unsigned & fromLen,void * toPtr,unsigned & toLen,unsigned & flags)1068 virtual bool Encode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags)
1069 {
1070 // encode PCM-raw to T.38-RTP
1071
1072 WaitAndSignal mutex(m_mutex);
1073
1074 if (!Open())
1075 return false;
1076
1077 int samplesLeft = t38_gateway_rx(m_t38State, (int16_t *)fromPtr, fromLen/2);
1078
1079 if (samplesLeft < 0)
1080 return false;
1081
1082 fromLen -= samplesLeft*2;
1083
1084 if (!FaxT38::EncodeRTP(toPtr, toLen, flags))
1085 return false;
1086
1087
1088 PTRACE(LOG_LEVEL_DEBUG, m_tag <<
1089 " T38_PCM::Encode: fromLen=" << fromLen << " toLen=" << toLen <<
1090 " seq=" << (toLen > 0 ? PluginCodec_RTP_GetSequenceNumber(toPtr) : 0));
1091
1092 return true;
1093 }
1094
1095
Decode(const void * fromPtr,unsigned & fromLen,void * toPtr,unsigned & toLen,unsigned & flags)1096 virtual bool Decode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags)
1097 {
1098 // decode T.38-RTP to PCM-raw
1099
1100 WaitAndSignal mutex(m_mutex);
1101
1102 if (!Open())
1103 return false;
1104
1105 if (!FaxT38::DecodeRTP(fromPtr, fromLen))
1106 return false;
1107
1108 int samplesGenerated = t38_gateway_tx(m_t38State, (int16_t *)toPtr, toLen/2);
1109
1110 if (samplesGenerated < 0)
1111 return false;
1112
1113 toLen = samplesGenerated*2;
1114
1115 flags = PluginCodec_ReturnCoderLastFrame;
1116
1117 PTRACE(LOG_LEVEL_DEBUG, m_tag <<
1118 " T38_PCM::Decode: fromLen=" << fromLen << " toLen=" << toLen <<
1119 " seq=" << PluginCodec_RTP_GetSequenceNumber(fromPtr) <<
1120 " ts=" << PluginCodec_RTP_GetTimestamp(fromPtr) <<
1121 (toLen >= sizeof(long) && *(long *)toPtr ? " **********" : ""));
1122
1123 return true;
1124 }
1125
1126
Terminate()1127 virtual bool Terminate()
1128 {
1129 WaitAndSignal mutex(m_mutex);
1130
1131 PTRACE(4, m_tag << " T38_PCM::Terminate");
1132 return Open();
1133 }
1134
1135
GetStats(void *,unsigned)1136 virtual bool GetStats(void * /*fromPtr*/, unsigned /*fromLen*/)
1137 {
1138 // WaitAndSignal mutex(m_mutex);
1139
1140 return false;
1141 }
1142
1143
1144 protected:
SetOption(const char * option,const char * value)1145 virtual bool SetOption(const char * option, const char * value)
1146 {
1147 if (!FaxSpanDSP::SetOption(option, value))
1148 return false;
1149
1150 if (!FaxT38::SetOption(option, value))
1151 return false;
1152
1153 if (!FaxPCM::SetOption(option, value))
1154 return false;
1155
1156 return true;
1157 }
1158
1159
Open()1160 bool Open()
1161 {
1162 if (m_completed)
1163 return false;
1164
1165 if (m_t38State != NULL)
1166 return true;
1167
1168 PTRACE(3, m_tag << " Opening T38_PCM/SpanDSP");
1169
1170 m_t38State = t38_gateway_init(NULL, FaxT38::QueueT38, (FaxT38 *)this);
1171 if (HasError(m_t38State != NULL, "t38_gateway_init failed."))
1172 return false;
1173
1174 t38_gateway_set_supported_modems(m_t38State, m_supported_modems);
1175
1176 if (HasError(FaxT38::Open(t38_gateway_get_t38_core_state(m_t38State))))
1177 return false;
1178
1179 InitLogging(t38_gateway_get_logging_state(m_t38State), m_tag);
1180
1181 t38_gateway_set_transmit_on_idle(m_t38State, TransmitOnIdle());
1182 t38_gateway_set_ecm_capability(m_t38State, m_useECM);
1183 //t38_gateway_set_nsx_suppression(m_t38State, NULL, 0, NULL, 0);
1184
1185 return true;
1186 }
1187 };
1188
1189
1190 /////////////////////////////////////////////////////////////////
1191
1192 class TIFF_T38 : public FaxTIFF, public FaxT38
1193 {
1194 protected:
1195 t38_terminal_state_t * m_t38State;
1196
1197 public:
TIFF_T38(PTRACE_PARAM (const std::string & tag))1198 TIFF_T38(PTRACE_PARAM(const std::string &tag))
1199 : m_t38State(NULL)
1200 {
1201 #if LOGGING
1202 m_tag = tag;
1203 #endif
1204
1205 PTRACE(4, m_tag << " Created TIFF_T38");
1206 }
1207
1208
~TIFF_T38()1209 ~TIFF_T38()
1210 {
1211 if (m_t38State != NULL) {
1212 t30_terminate(t38_terminal_get_t30_state(m_t38State)); //call PhaseE
1213 t38_terminal_release(m_t38State);
1214 t38_terminal_free(m_t38State);
1215 PTRACE(3, m_tag << " Closed TIFF_T38/SpanDSP");
1216 }
1217
1218 PTRACE(4, m_tag << " Deleted TIFF_T38 instance.");
1219 }
1220
1221
Encode(const void *,unsigned & fromLen,void * toPtr,unsigned & toLen,unsigned & flags)1222 virtual bool Encode(const void * /*fromPtr*/, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags)
1223 {
1224 // encode TIFF-raw to T.38-RTP
1225
1226 WaitAndSignal mutex(m_mutex);
1227
1228 if (!Open())
1229 return false;
1230
1231 t38_terminal_send_timeout(m_t38State, fromLen/2);
1232
1233 if (!FaxT38::EncodeRTP(toPtr, toLen, flags))
1234 return false;
1235
1236 PTRACE(LOG_LEVEL_DEBUG, m_tag <<
1237 " TIFF_T38::Encode: fromLen=" << fromLen << " toLen=" << toLen <<
1238 " seq=" << (toLen > 0 ? PluginCodec_RTP_GetSequenceNumber(toPtr) : 0));
1239
1240 return true;
1241 }
1242
1243
Decode(const void * fromPtr,unsigned & fromLen,void *,unsigned & toLen,unsigned & flags)1244 virtual bool Decode(const void * fromPtr, unsigned & fromLen, void * /*toPtr*/, unsigned & toLen, unsigned & flags)
1245 {
1246 // decode T.38-RTP to PCM-raw
1247
1248 WaitAndSignal mutex(m_mutex);
1249
1250 if (!Open())
1251 return false;
1252
1253 if (!FaxT38::DecodeRTP(fromPtr, fromLen))
1254 return false;
1255
1256 toLen = 0;
1257 flags = PluginCodec_ReturnCoderLastFrame;
1258
1259 PTRACE(LOG_LEVEL_DEBUG, m_tag <<
1260 " TIFF_T38::Decode: fromLen=" << fromLen <<
1261 " seq=" << PluginCodec_RTP_GetSequenceNumber(fromPtr) <<
1262 " ts=" << PluginCodec_RTP_GetTimestamp(fromPtr));
1263
1264 return true;
1265 }
1266
1267
Terminate()1268 virtual bool Terminate()
1269 {
1270 WaitAndSignal mutex(m_mutex);
1271
1272 PTRACE(4, m_tag << " TIFF_T38::Terminate");
1273
1274 if (!Open())
1275 return false;
1276
1277 t30_terminate(t38_terminal_get_t30_state(m_t38State));
1278 return true;
1279 }
1280
1281
GetStats(void * fromPtr,unsigned fromLen)1282 virtual bool GetStats(void * fromPtr, unsigned fromLen)
1283 {
1284 WaitAndSignal mutex(m_mutex);
1285
1286 return FaxTIFF::GetStats(m_t38State != NULL ? t38_terminal_get_t30_state(m_t38State) : NULL, fromPtr, fromLen);
1287 }
1288
1289
1290 protected:
SetOption(const char * option,const char * value)1291 virtual bool SetOption(const char * option, const char * value)
1292 {
1293 if (!FaxTIFF::SetOption(option, value))
1294 return false;
1295
1296 if (!FaxT38::SetOption(option, value))
1297 return false;
1298
1299 return true;
1300 }
1301
1302
Open()1303 bool Open()
1304 {
1305 if (m_completed)
1306 return false;
1307
1308 if (m_t38State != NULL)
1309 return true;
1310
1311 PTRACE(3, m_tag << " Opening TIFF_T38/SpanDSP for " << (IsReceiving() ? "receive" : "transmit"));
1312
1313 // If our max bit rate is 9600 then explicitly remove V.17 or spandsp does 14400 anyway
1314 if (GetMaxBitRate() <= 9600)
1315 m_supported_modems &= ~T30_SUPPORT_V17;
1316
1317 m_t38State = t38_terminal_init(NULL, !IsReceiving(), FaxT38::QueueT38, (FaxT38 *)this);
1318 if (HasError(m_t38State != NULL, "t38_terminal_init failed."))
1319 return false;
1320
1321 if (HasError(FaxTIFF::Open(t38_terminal_get_t30_state(m_t38State))))
1322 return false;
1323
1324 if (HasError(FaxT38::Open(t38_terminal_get_t38_core_state(m_t38State))))
1325 return false;
1326
1327 InitLogging(t38_terminal_get_logging_state(m_t38State), m_tag);
1328 t38_terminal_set_config(m_t38State, false);
1329
1330 return true;
1331 }
1332 };
1333
1334
1335 /////////////////////////////////////////////////////////////////
1336
1337 class TIFF_PCM : public FaxTIFF, public FaxPCM
1338 {
1339 protected:
1340 fax_state_t * m_faxState;
1341
1342 public:
TIFF_PCM(PTRACE_PARAM (const std::string & tag))1343 TIFF_PCM(PTRACE_PARAM(const std::string &tag))
1344 : m_faxState(NULL)
1345 {
1346 #if LOGGING
1347 m_tag = tag;
1348 #endif
1349
1350 PTRACE(4, m_tag << " Created TIFF_PCM");
1351 }
1352
1353
~TIFF_PCM()1354 ~TIFF_PCM()
1355 {
1356 if (m_faxState != NULL) {
1357 t30_terminate(fax_get_t30_state(m_faxState)); //to call PhaseE with audio Fax
1358 fax_release(m_faxState);
1359 fax_free(m_faxState);
1360 PTRACE(3, m_tag << " Closed TIFF_PCM/SpanDSP");
1361 }
1362
1363 PTRACE(4, m_tag << " Deleted TIFF_PCM instance.");
1364 }
1365
1366
Encode(const void * fromPtr,unsigned & fromLen,void *,unsigned & toLen,unsigned & flags)1367 virtual bool Encode(const void * fromPtr, unsigned & fromLen, void * /*toPtr*/, unsigned & toLen, unsigned & flags)
1368 {
1369 // encode PCM-raw to TIFF-raw
1370
1371 WaitAndSignal mutex(m_mutex);
1372
1373 if (!Open())
1374 return false;
1375
1376 int samplesLeft = fax_rx(m_faxState, (int16_t *)fromPtr, fromLen/2);
1377
1378 if (samplesLeft < 0)
1379 return false;
1380
1381 fromLen -= samplesLeft*2;
1382
1383 toLen = 0;
1384 flags = PluginCodec_ReturnCoderLastFrame;
1385
1386 PTRACE(LOG_LEVEL_DEBUG, m_tag << " TIFF_PCM::Encode: fromLen=" << fromLen);
1387
1388 return true;
1389 }
1390
1391
Decode(const void *,unsigned & PTRACE_PARAM (fromLen),void * toPtr,unsigned & toLen,unsigned & flags)1392 virtual bool Decode(const void * /*fromPtr*/, unsigned & PTRACE_PARAM(fromLen), void * toPtr, unsigned & toLen, unsigned & flags)
1393 {
1394 // decode TIFF-raw to PCM-raw
1395
1396 WaitAndSignal mutex(m_mutex);
1397
1398 if (!Open())
1399 return false;
1400
1401 int samplesGenerated = fax_tx(m_faxState, (int16_t *)toPtr, toLen/2);
1402
1403 if (samplesGenerated < 0)
1404 return false;
1405
1406 toLen = samplesGenerated*2;
1407 flags = PluginCodec_ReturnCoderLastFrame;
1408
1409 PTRACE(LOG_LEVEL_DEBUG, m_tag <<
1410 " TIFF_PCM::Decode: fromLen=" << fromLen << " toLen=" << toLen <<
1411 (toLen >= sizeof(long) && *(long *)toPtr ? " **********" : ""));
1412
1413 return true;
1414 }
1415
1416
Terminate()1417 virtual bool Terminate()
1418 {
1419 WaitAndSignal mutex(m_mutex);
1420
1421 PTRACE(4, m_tag << " TIFF_PCM::Terminate");
1422
1423 if (!Open())
1424 return false;
1425
1426 t30_terminate(fax_get_t30_state(m_faxState));
1427 return true;
1428 }
1429
1430
GetStats(void * fromPtr,unsigned fromLen)1431 virtual bool GetStats(void * fromPtr, unsigned fromLen)
1432 {
1433 WaitAndSignal mutex(m_mutex);
1434
1435 return FaxTIFF::GetStats(m_faxState != NULL ? fax_get_t30_state(m_faxState) : NULL, fromPtr, fromLen);
1436 }
1437
1438 protected:
SetOption(const char * option,const char * value)1439 virtual bool SetOption(const char * option, const char * value)
1440 {
1441 if (!FaxTIFF::SetOption(option, value))
1442 return false;
1443
1444 if (!FaxPCM::SetOption(option, value))
1445 return false;
1446
1447 return true;
1448 }
1449
1450
Open()1451 bool Open()
1452 {
1453 if (m_completed)
1454 return false;
1455
1456 if (m_faxState != NULL)
1457 return true;
1458
1459 PTRACE(3, m_tag << " Opening TIFF_PCM/SpanDSP for " << (IsReceiving() ? "receive" : "transmit"));
1460
1461 m_faxState = fax_init(NULL, !IsReceiving());
1462 if (HasError(m_faxState != NULL, "t38_terminal_init failed."))
1463 return false;
1464
1465 if (HasError(FaxTIFF::Open(fax_get_t30_state(m_faxState))))
1466 return false;
1467
1468 InitLogging(fax_get_logging_state(m_faxState), m_tag);
1469 fax_set_transmit_on_idle(m_faxState, TransmitOnIdle());
1470
1471 return true;
1472 }
1473 };
1474
1475
1476 /////////////////////////////////////////////////////////////////
1477 typedef std::vector<unsigned char> InstanceKey;
1478
1479 #if LOGGING
KeyToStr(const InstanceKey & key)1480 static std::string KeyToStr(const InstanceKey &key)
1481 {
1482 std::ostringstream strm;
1483
1484 for (size_t i = 0 ; i < key.size() ; i++) {
1485 unsigned char ch = key[i];
1486
1487 if (ch >= 0x20 && ch <= 0x7E)
1488 strm << ch;
1489 else
1490 strm << "<0x" << std::hex << (unsigned)ch << std::dec << ">";
1491 }
1492
1493 return strm.str();
1494 }
1495 #endif
1496
1497 typedef std::map<InstanceKey, FaxSpanDSP *> InstanceMapType;
1498
1499 static InstanceMapType InstanceMap;
1500 static CriticalSection InstanceMapMutex;
1501
1502 class FaxCodecContext
1503 {
1504 private:
1505 const PluginCodec_Definition * m_definition;
1506 InstanceKey m_key;
1507 FaxSpanDSP * m_instance;
1508
1509 public:
FaxCodecContext(const PluginCodec_Definition * defn)1510 FaxCodecContext(const PluginCodec_Definition * defn)
1511 : m_definition(defn)
1512 , m_instance(NULL)
1513 {
1514 }
1515
1516
~FaxCodecContext()1517 ~FaxCodecContext()
1518 {
1519 if (m_instance == NULL)
1520 return;
1521
1522 WaitAndSignal mutex(InstanceMapMutex);
1523
1524 InstanceMapType::iterator iter = InstanceMap.find(m_key);
1525 if (iter != InstanceMap.end() && iter->second->Dereference()) {
1526 delete iter->second;
1527 InstanceMap.erase(iter);
1528 PTRACE(LOG_LEVEL_CONTEXT_ID, KeyToStr(m_key) << " Context Id removed");
1529 }
1530 }
1531
1532
SetContextId(void * parm,unsigned * parmLen)1533 bool SetContextId(void * parm, unsigned * parmLen)
1534 {
1535 if (parm == NULL || parmLen == NULL || *parmLen == 0)
1536 return false;
1537
1538 if (m_instance != NULL)
1539 return false;
1540
1541 m_key.resize(*parmLen);
1542 memcpy(&m_key[0], parm, *parmLen);
1543
1544 #if LOGGING
1545 std::string key = KeyToStr(m_key);
1546 #endif
1547
1548 WaitAndSignal mutex(InstanceMapMutex);
1549
1550 InstanceMapType::iterator iter = InstanceMap.find(m_key);
1551 if (iter != InstanceMap.end()) {
1552 PTRACE(LOG_LEVEL_CONTEXT_ID, key << " Context Id found");
1553
1554 m_instance = iter->second;
1555 m_instance->AddReference();
1556 }
1557 else {
1558 if (m_definition->sourceFormat == TIFFFormat) {
1559 if (m_definition->destFormat == T38Format)
1560 m_instance = new TIFF_T38(PTRACE_PARAM(key));
1561 else
1562 m_instance = new TIFF_PCM(PTRACE_PARAM(key));
1563 }
1564 else if (m_definition->sourceFormat == T38Format) {
1565 if (m_definition->destFormat == TIFFFormat)
1566 m_instance = new TIFF_T38(PTRACE_PARAM(key));
1567 else
1568 m_instance = new T38_PCM(PTRACE_PARAM(key));
1569 }
1570 else {
1571 if (m_definition->destFormat == TIFFFormat)
1572 m_instance = new TIFF_PCM(PTRACE_PARAM(key));
1573 else
1574 m_instance = new T38_PCM(PTRACE_PARAM(key));
1575 }
1576 InstanceMap[m_key] = m_instance;
1577
1578 PTRACE(LOG_LEVEL_CONTEXT_ID, key << " Context Id added");
1579 }
1580
1581 return true;
1582 }
1583
1584
SetOptions(const char * const * options)1585 bool SetOptions(const char * const * options)
1586 {
1587 return m_instance != NULL && m_instance->SetOptions(options);
1588 }
1589
1590
Encode(const void * fromPtr,unsigned & fromLen,void * toPtr,unsigned & toLen,unsigned & flags)1591 bool Encode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags)
1592 {
1593 return m_instance != NULL && m_instance->Encode(fromPtr, fromLen, toPtr, toLen, flags);
1594 }
1595
1596
Decode(const void * fromPtr,unsigned & fromLen,void * toPtr,unsigned & toLen,unsigned & flags)1597 bool Decode(const void * fromPtr, unsigned & fromLen, void * toPtr, unsigned & toLen, unsigned & flags)
1598 {
1599 return m_instance != NULL && m_instance->Decode(fromPtr, fromLen, toPtr, toLen, flags);
1600 }
1601
1602
Terminate()1603 bool Terminate()
1604 {
1605 return m_instance != NULL && m_instance->Terminate();
1606 }
1607
1608
GetStats(void * fromPtr,unsigned fromLen)1609 bool GetStats(void *fromPtr, unsigned fromLen)
1610 {
1611 return m_instance != NULL && m_instance->GetStats(fromPtr, fromLen);
1612 }
1613 };
1614
1615
1616 /////////////////////////////////////////////////////////////////////////////
1617
terminate_codec(const PluginCodec_Definition *,void * context,const char *,void *,unsigned *)1618 static int terminate_codec(const PluginCodec_Definition * ,
1619 void * context,
1620 const char * ,
1621 void *,
1622 unsigned *)
1623 {
1624 return context != NULL && ((FaxCodecContext *)context)->Terminate();
1625 }
1626
1627
get_codec_stats(const PluginCodec_Definition *,void * context,const char *,void * parm,unsigned * parmLen)1628 static int get_codec_stats(const PluginCodec_Definition * ,
1629 void * context,
1630 const char * ,
1631 void * parm,
1632 unsigned * parmLen)
1633 {
1634 return context != NULL &&
1635 parm != NULL &&
1636 parmLen != NULL &&
1637 ((FaxCodecContext *)context)->GetStats(parm, *parmLen);
1638 }
1639
1640
get_codec_options(const PluginCodec_Definition *,void * context,const char *,void * parm,unsigned * parmLen)1641 static int get_codec_options(const PluginCodec_Definition * ,
1642 void * context,
1643 const char * ,
1644 void * parm,
1645 unsigned * parmLen)
1646 {
1647 if (parm == NULL || parmLen == NULL || *parmLen != sizeof(struct PluginCodec_Option **))
1648 return false;
1649
1650 if (context != NULL) {
1651 if (strcasecmp((char *)context, T38Format) == 0) {
1652 *(struct PluginCodec_Option const * const * *)parm = OptionTableT38;
1653 return true;
1654 }
1655
1656 if (strcasecmp((char *)context, TIFFFormat) == 0) {
1657 *(struct PluginCodec_Option const * const * *)parm = OptionTableTIFF;
1658 return true;
1659 }
1660 }
1661
1662 *(struct PluginCodec_Option const * const * *)parm = OptionTablePCM;
1663
1664 return true;
1665 }
1666
1667
set_codec_options(const PluginCodec_Definition *,void * context,const char *,void * parm,unsigned * parmLen)1668 static int set_codec_options(const PluginCodec_Definition * ,
1669 void * context,
1670 const char * ,
1671 void * parm,
1672 unsigned * parmLen)
1673 {
1674 return context != NULL &&
1675 parm != NULL &&
1676 parmLen != NULL &&
1677 *parmLen == sizeof(const char **) &&
1678 ((FaxCodecContext *)context)->SetOptions((const char * const *)parm);
1679 }
1680
1681
set_instance_id(const PluginCodec_Definition *,void * context,const char *,void * parm,unsigned * parmLen)1682 static int set_instance_id(const PluginCodec_Definition * ,
1683 void * context,
1684 const char * ,
1685 void * parm,
1686 unsigned * parmLen)
1687 {
1688 return context != NULL && ((FaxCodecContext *)context)->SetContextId(parm, parmLen);
1689 }
1690
1691
1692 #if LOGGING
set_log_function(const PluginCodec_Definition *,void *,const char *,void * parm,unsigned * parmLen)1693 static int set_log_function(const PluginCodec_Definition * ,
1694 void * ,
1695 const char * ,
1696 void * parm,
1697 unsigned * parmLen)
1698 {
1699 if (parmLen == NULL || *parmLen != sizeof(PluginCodec_LogFunction))
1700 return false;
1701
1702 LogFunction = (PluginCodec_LogFunction)parm;
1703 return true;
1704 }
1705 #endif
1706
1707
1708 static struct PluginCodec_ControlDefn Controls[] = {
1709 { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS, get_codec_options },
1710 { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS, set_codec_options },
1711 { PLUGINCODEC_CONTROL_SET_INSTANCE_ID, set_instance_id },
1712 { PLUGINCODEC_CONTROL_GET_STATISTICS, get_codec_stats },
1713 { PLUGINCODEC_CONTROL_TERMINATE_CODEC, terminate_codec },
1714 #if LOGGING
1715 { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, set_log_function },
1716 #endif
1717 { NULL }
1718 };
1719
1720
1721 /////////////////////////////////////////////////////////////////////////////
1722
Create(const PluginCodec_Definition * codec)1723 static void * Create(const PluginCodec_Definition * codec)
1724 {
1725 return new FaxCodecContext(codec);
1726 }
1727
1728
Destroy(const PluginCodec_Definition *,void * context)1729 static void Destroy(const PluginCodec_Definition * /*codec*/, void * context)
1730 {
1731 delete (FaxCodecContext *)context;
1732 }
1733
1734
Encode(const PluginCodec_Definition *,void * context,const void * fromPtr,unsigned * fromLen,void * toPtr,unsigned * toLen,unsigned * flags)1735 static int Encode(const PluginCodec_Definition * /*codec*/,
1736 void * context,
1737 const void * fromPtr,
1738 unsigned * fromLen,
1739 void * toPtr,
1740 unsigned * toLen,
1741 unsigned * flags)
1742 {
1743 return context != NULL && ((FaxCodecContext *)context)->Encode(fromPtr, *fromLen, toPtr, *toLen, *flags);
1744 }
1745
1746
1747
Decode(const PluginCodec_Definition *,void * context,const void * fromPtr,unsigned * fromLen,void * toPtr,unsigned * toLen,unsigned * flags)1748 static int Decode(const PluginCodec_Definition * /*codec*/,
1749 void * context,
1750 const void * fromPtr,
1751 unsigned * fromLen,
1752 void * toPtr,
1753 unsigned * toLen,
1754 unsigned * flags)
1755 {
1756 return context != NULL && ((FaxCodecContext *)context)->Decode(fromPtr, *fromLen, toPtr, *toLen, *flags);
1757 }
1758
1759
1760 /////////////////////////////////////////////////////////////////////////////
1761
1762 static struct PluginCodec_information LicenseInfo = {
1763 1081086550, // timestamp = Sun 04 Apr 2004 01:49:10 PM UTC =
1764
1765 "Craig Southeren, Post Increment", // source code author
1766 "1.0", // source code version
1767 "craigs@postincrement.com", // source code email
1768 "http://www.postincrement.com", // source code URL
1769 "Copyright (C) 2007 by Post Increment, All Rights Reserved", // source code copyright
1770 "MPL 1.0", // source code license
1771 PluginCodec_License_MPL, // source code license
1772
1773 "T.38 Fax Codec", // codec description
1774 "Craig Southeren", // codec author
1775 "Version 1", // codec version
1776 "craigs@postincrement.com", // codec email
1777 "", // codec URL
1778 "", // codec copyright information
1779 NULL, // codec license
1780 PluginCodec_License_MPL // codec license code
1781 };
1782
1783 #define MY_API_VERSION PLUGIN_CODEC_VERSION_OPTIONS
1784
1785 static PluginCodec_Definition faxCodecDefn[] = {
1786
1787 {
1788 // encoder
1789 MY_API_VERSION, // codec API version
1790 &LicenseInfo, // license information
1791
1792 PluginCodec_MediaTypeFax | // audio codec
1793 PluginCodec_InputTypeRaw | // raw input data
1794 PluginCodec_OutputTypeRTP | // RTP output data
1795 PluginCodec_RTPTypeExplicit, // explicit RTP type
1796
1797 "PCM to T.38 Codec", // text decription
1798 L16Format, // source format
1799 T38Format, // destination format
1800
1801 NULL, // user data
1802
1803 8000, // samples per second
1804 BITS_PER_SECOND, // raw bits per second
1805 MICROSECONDS_PER_FRAME, // microseconds per frame
1806 SAMPLES_PER_FRAME, // samples per frame
1807 BYTES_PER_FRAME, // bytes per frame
1808 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1809 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1810 T38_PAYLOAD_CODE, // internal RTP payload code
1811 T38sdp, // RTP payload name
1812
1813 Create, // create codec function
1814 Destroy, // destroy codec
1815 Encode, // encode/decode
1816 Controls, // codec controls
1817
1818 PluginCodec_H323T38Codec, // h323CapabilityType
1819 NULL // h323CapabilityData
1820 },
1821
1822 {
1823 // decoder
1824 MY_API_VERSION, // codec API version
1825 &LicenseInfo, // license information
1826
1827 PluginCodec_EmptyPayload |
1828 PluginCodec_MediaTypeFax | // audio codec
1829 PluginCodec_InputTypeRTP | // RTP input data
1830 PluginCodec_OutputTypeRaw | // raw output data
1831 PluginCodec_RTPTypeExplicit, // explicit RTP type
1832
1833 "T.38 to PCM Codec", // text decription
1834 T38Format, // source format
1835 L16Format, // destination format
1836
1837 NULL, // user data
1838
1839 8000, // samples per second
1840 BITS_PER_SECOND, // raw bits per second
1841 MICROSECONDS_PER_FRAME, // microseconds per frame
1842 SAMPLES_PER_FRAME, // samples per frame
1843 BYTES_PER_FRAME, // bytes per frame
1844 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1845 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1846 T38_PAYLOAD_CODE, // internal RTP payload code
1847 T38sdp, // RTP payload name
1848
1849 Create, // create codec function
1850 Destroy, // destroy codec
1851 Decode, // encode/decode
1852 Controls, // codec controls
1853
1854 PluginCodec_H323T38Codec, // h323CapabilityType
1855 NULL // h323CapabilityData
1856 },
1857
1858 {
1859 // encoder
1860 MY_API_VERSION, // codec API version
1861 &LicenseInfo, // license information
1862
1863 PluginCodec_MediaTypeFax | // audio codec
1864 PluginCodec_InputTypeRaw | // raw input data
1865 PluginCodec_OutputTypeRTP | // RTP output data
1866 PluginCodec_RTPTypeDynamic, // dynamic RTP type
1867
1868 "TIFF to T.38 Codec", // text decription
1869 TIFFFormat, // source format
1870 T38Format, // destination format
1871
1872 NULL, // user data
1873
1874 8000, // samples per second
1875 BITS_PER_SECOND, // raw bits per second
1876 MICROSECONDS_PER_FRAME, // microseconds per frame
1877 SAMPLES_PER_FRAME, // samples per frame
1878 BYTES_PER_FRAME, // bytes per frame
1879 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1880 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1881 0, // dynamic payload
1882 NULL, // RTP payload name
1883
1884 Create, // create codec function
1885 Destroy, // destroy codec
1886 Encode, // encode/decode
1887 Controls, // codec controls
1888
1889 PluginCodec_H323T38Codec, // h323CapabilityType
1890 NULL // h323CapabilityData
1891 },
1892
1893 {
1894 // decoder
1895 MY_API_VERSION, // codec API version
1896 &LicenseInfo, // license information
1897
1898 PluginCodec_MediaTypeFax | // audio codec
1899 PluginCodec_InputTypeRTP | // RTP input data
1900 PluginCodec_OutputTypeRaw | // raw output data
1901 PluginCodec_RTPTypeDynamic, // dynamic RTP type
1902
1903 "T.38 to TIFF Codec", // text decription
1904 T38Format, // source format
1905 TIFFFormat, // destination format
1906
1907 NULL, // user data
1908
1909 8000, // samples per second
1910 BITS_PER_SECOND, // raw bits per second
1911 MICROSECONDS_PER_FRAME, // microseconds per frame
1912 SAMPLES_PER_FRAME, // samples per frame
1913 BYTES_PER_FRAME, // bytes per frame
1914 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1915 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1916 0, // dynamic payload
1917 NULL, // RTP payload name
1918
1919 Create, // create codec function
1920 Destroy, // destroy codec
1921 Decode, // encode/decode
1922 Controls, // codec controls
1923
1924 PluginCodec_H323T38Codec, // h323CapabilityType
1925 NULL // h323CapabilityData
1926 },
1927
1928 {
1929 // encoder
1930 MY_API_VERSION, // codec API version
1931 &LicenseInfo, // license information
1932
1933 PluginCodec_MediaTypeFax | // audio codec
1934 PluginCodec_InputTypeRaw | // raw input data
1935 PluginCodec_OutputTypeRaw | // raw output data
1936 PluginCodec_RTPTypeDynamic, // dynamic RTP type
1937
1938 "PCM to TIFF Codec", // text decription
1939 L16Format, // source format
1940 TIFFFormat, // destination format
1941
1942 NULL, // user data
1943
1944 8000, // samples per second
1945 BITS_PER_SECOND, // raw bits per second
1946 MICROSECONDS_PER_FRAME, // microseconds per frame
1947 SAMPLES_PER_FRAME, // samples per frame
1948 BYTES_PER_FRAME, // bytes per frame
1949 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1950 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1951 0, // dynamic payload
1952 NULL, // RTP payload name
1953
1954 Create, // create codec function
1955 Destroy, // destroy codec
1956 Encode, // encode/decode
1957 Controls, // codec controls
1958
1959 0, // h323CapabilityType
1960 NULL // h323CapabilityData
1961 },
1962
1963 {
1964 // decoder
1965 MY_API_VERSION, // codec API version
1966 &LicenseInfo, // license information
1967
1968 PluginCodec_MediaTypeFax | // audio codec
1969 PluginCodec_InputTypeRaw | // raw input data
1970 PluginCodec_OutputTypeRaw | // raw output data
1971 PluginCodec_RTPTypeDynamic, // dynamic RTP type
1972
1973 "TIFF to PCM Codec", // text decription
1974 TIFFFormat, // source format
1975 L16Format, // destination format
1976
1977 NULL, // user data
1978
1979 8000, // samples per second
1980 BITS_PER_SECOND, // raw bits per second
1981 MICROSECONDS_PER_FRAME, // microseconds per frame
1982 SAMPLES_PER_FRAME, // samples per frame
1983 BYTES_PER_FRAME, // bytes per frame
1984 PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
1985 MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
1986 0, // dynamic payload
1987 NULL, // RTP payload name
1988
1989 Create, // create codec function
1990 Destroy, // destroy codec
1991 Decode, // encode/decode
1992 Controls, // codec controls
1993
1994 0, // h323CapabilityType
1995 NULL // h323CapabilityData
1996 },
1997
1998 };
1999
2000 /////////////////////////////////////////////////////////////////////////////
2001
2002 extern "C" {
2003
2004 PLUGIN_CODEC_IMPLEMENT_ALL(SpanDSP, faxCodecDefn, MY_API_VERSION)
2005
2006 };
2007
2008