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