1 /*
2  * lidplugins.cxx
3  *
4  * Line Interface Device plugins manager
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (C) 2006 Post Increment
10  *
11  * The contents of this file are subject to the Mozilla Public License
12  * Version 1.0 (the "License"); you may not use this file except in
13  * compliance with the License. You may obtain a copy of the License at
14  * http://www.mozilla.org/MPL/
15  *
16  * Software distributed under the License is distributed on an "AS IS"
17  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18  * the License for the specific language governing rights and limitations
19  * under the License.
20  *
21  * The Original Code is Open Phone Abstraction Library.
22  *
23  * The Initial Developer of the Original Code is Post Increment
24  *
25  * Contributor(s): ______________________________________.
26  *
27  * $Revision: 26521 $
28  * $Author: rjongbloed $
29  * $Date: 2011-10-04 23:57:06 -0500 (Tue, 04 Oct 2011) $
30  */
31 
32 #ifdef __GNUC__
33 #pragma implementation "lidpluginmgr.h"
34 #endif
35 
36 #include <ptlib.h>
37 
38 #include <opal/buildopts.h>
39 
40 #include <lids/lidpluginmgr.h>
41 #include <ptclib/dtmf.h>
42 
43 
44 PFACTORY_CREATE_SINGLETON(PFactory<PPluginModuleManager>, OpalPluginLIDManager);
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 
OpalPluginLIDManager(PPluginManager * mgr)48 OpalPluginLIDManager::OpalPluginLIDManager(PPluginManager * mgr)
49   : PPluginModuleManager(PLUGIN_LID_GET_LIDS_FN_STR, mgr)
50 {
51   // cause the plugin manager to load all dynamic plugins
52   pluginMgr->AddNotifier(PCREATE_NOTIFIER(OnLoadModule), PTrue);
53 }
54 
55 
~OpalPluginLIDManager()56 OpalPluginLIDManager::~OpalPluginLIDManager()
57 {
58 }
59 
60 
OnLoadPlugin(PDynaLink & dll,INT code)61 void OpalPluginLIDManager::OnLoadPlugin(PDynaLink & dll, INT code)
62 {
63   PluginLID_GetDefinitionsFunction getDefinitions;
64   {
65     PDynaLink::Function fn;
66     if (!dll.GetFunction(PString(signatureFunctionName), fn)) {
67       PTRACE(3, "LID Plugin\tDLL " << dll.GetName() << " is not a plugin LID");
68       return;
69     }
70     getDefinitions = (PluginLID_GetDefinitionsFunction)fn;
71   }
72 
73   unsigned count;
74   PluginLID_Definition * lid = (*getDefinitions)(&count, PWLIB_PLUGIN_API_VERSION);
75   if (lid == NULL || count == 0) {
76     PTRACE(3, "LID Plugin\tDLL " << dll.GetName() << " contains no LID definitions");
77     return;
78   }
79 
80   PTRACE(3, "LID Plugin\tDLL " << dll.GetName() << " loaded " << count << "LID" << (count > 1 ? "s" : ""));
81 
82   while (count-- > 0) {
83     if (lid->name != NULL && *lid->name != '\0') {
84       switch (code) {
85         case 0 : // plugin loaded
86           m_registrations.Append(new OpalPluginLIDRegistration(*lid));
87           break;
88 
89         case 1 : // plugin unloaded
90           for (PList<OpalPluginLIDRegistration>::iterator iterLID = m_registrations.begin(); iterLID != m_registrations.end();) {
91             if (*iterLID == lid->name)
92               m_registrations.erase(iterLID++);
93              else
94                ++iterLID;
95           }
96       }
97     }
98     lid++;
99   }
100 }
101 
102 
OnShutdown()103 void OpalPluginLIDManager::OnShutdown()
104 {
105   m_registrations.RemoveAll();
106 }
107 
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 
OpalPluginLIDRegistration(const PluginLID_Definition & definition)111 OpalPluginLIDRegistration::OpalPluginLIDRegistration(const PluginLID_Definition & definition)
112   : OpalLIDRegistration(definition.name)
113   , m_definition(definition)
114 {
115 }
116 
117 
Create(void *) const118 OpalLineInterfaceDevice * OpalPluginLIDRegistration::Create(void *) const
119 {
120   return new OpalPluginLID(m_definition);
121 }
122 
123 
124 ///////////////////////////////////////////////////////////////////////////////
125 
OpalPluginLID(const PluginLID_Definition & definition)126 OpalPluginLID::OpalPluginLID(const PluginLID_Definition & definition)
127   : m_definition(definition)
128   , m_tonePlayer(NULL)
129   , m_lockOutTones(false)
130 {
131   if (m_definition.Create != NULL) {
132     m_context = definition.Create(&m_definition);
133     PTRACE_IF(1, m_context == NULL, "LID Plugin\tNo context for " << m_definition.description); \
134   }
135   else {
136     m_context = NULL;
137     PTRACE(1, "LID Plugin\tDefinition for " << m_definition.description << " invalid.");
138   }
139 }
140 
141 
~OpalPluginLID()142 OpalPluginLID::~OpalPluginLID()
143 {
144   StopTone(0);
145   if (m_context != NULL && m_definition.Destroy != NULL)
146     m_definition.Destroy(&m_definition, m_context);
147 }
148 
149 
150 #if PTRACING
151 
BadContext() const152 bool OpalPluginLID::BadContext() const
153 {
154   if (m_context != NULL)
155     return false;
156 
157   PTRACE(1, "LID Plugin\tNo context for " << m_definition.name);
158   return true;
159 }
160 
BadFunction(void * fnPtr,const char * fnName) const161 bool OpalPluginLID::BadFunction(void * fnPtr, const char * fnName) const
162 {
163   if (fnPtr != NULL)
164     return false;
165 
166   PTRACE(1, "LID Plugin\tFunction " << fnName << " not implemented in " << m_definition.name);
167   return true;
168 }
169 
170 
operator <<(ostream & stream,PluginLID_Errors error)171 static ostream & operator<<(ostream & stream, PluginLID_Errors error)
172 {
173   static const char * const names[] = {
174     "NoError",
175     "UnimplementedFunction",
176     "BadContext",
177     "InvalidParameter",
178     "NoSuchDevice",
179     "DeviceOpenFailed",
180     "UsesSoundChannel",
181     "DeviceNotOpen",
182     "NoSuchLine",
183     "OperationNotAllowed",
184     "NoMoreNames",
185     "BufferTooSmall",
186     "UnsupportedMediaFormat",
187     "NoDialTone",
188     "LineBusy",
189     "NoAnswer",
190     "Aborted",
191     "InternalError"
192   };
193 
194   if (error < PARRAYSIZE(names) && names[error] != NULL)
195     stream << names[error];
196   else
197     stream << "Code " << (int)error;
198 
199   return stream;
200 }
201 
CheckError(PluginLID_Errors error,const char * fnName) const202 PluginLID_Errors OpalPluginLID::CheckError(PluginLID_Errors error, const char * fnName) const
203 {
204   if (error != PluginLID_NoError && error != PluginLID_UnimplementedFunction && error != PluginLID_NoMoreNames) {
205     PTRACE(2, "LID Plugin\tFunction " << fnName << " in " << m_definition.name << " returned error " << error);
206   }
207 
208   osError = error;
209   return error;
210 }
211 
212 #define BAD_FN(fn)         (BadContext() || BadFunction((void *)m_definition.fn, #fn))
213 #define CHECK_FN(fn, args) (BadContext() ? PluginLID_BadContext : m_definition.fn == NULL ? PluginLID_UnimplementedFunction : CheckError(m_definition.fn args, #fn))
214 
215 #else // PTRACING
216 
217 #define BAD_FN(fn) (m_context == NULL || m_definition.fn == NULL)
218 #define CHECK_FN(fn, args) (m_context == NULL ? PluginLID_BadContext : m_definition.fn == NULL ? PluginLID_UnimplementedFunction : (osError = m_definition.fn args))
219 
220 #endif // PTRACING
221 
222 
Open(const PString & device)223 PBoolean OpalPluginLID::Open(const PString & device)
224 {
225   if (BAD_FN(Open))
226     return PFalse;
227 
228   Close();
229 
230 
231   switch (osError = m_definition.Open(m_context, device)) {
232     case PluginLID_NoError :
233       break;
234 
235     case PluginLID_UsesSoundChannel :
236       {
237         PString soundDevice;
238         PINDEX backslash = device.Find('\\');
239         if (backslash != P_MAX_INDEX)
240           soundDevice = device.Mid(backslash+1);
241         else
242           soundDevice = device;
243 
244         if (!m_player.Open(soundDevice, PSoundChannel::Player)) {
245           PTRACE(1, "LID Plugin\t" << m_definition.name << " requires sound system, but cannot open player for \"" << device << '"');
246           return PFalse;
247         }
248 
249         if (!m_recorder.Open(soundDevice, PSoundChannel::Recorder)) {
250           PTRACE(1, "LID Plugin\t" << m_definition.name << " requires sound system, but cannot open recorder for \"" << device << '"');
251           return PFalse;
252         }
253       }
254       break;
255 
256     case PluginLID_NoSuchDevice :
257       PTRACE(1, "LID Plugin\tNo such device as \"" << device << "\" in " << m_definition.name);
258       return PFalse;
259 
260     default :
261       PTRACE(1, "LID Plugin\tOpen of \"" << device << "\" in " << m_definition.name << " returned error " << osError);
262       return PFalse;
263   }
264 
265   m_deviceName = device;
266   os_handle = 1;
267   return PTrue;
268 }
269 
270 
Close()271 PBoolean OpalPluginLID::Close()
272 {
273   OpalLineInterfaceDevice::Close();
274 
275   StopTone(0);
276   m_player.Close();
277   m_recorder.Close();
278 
279   if (BAD_FN(Close))
280     return PFalse;
281 
282   return m_definition.Close(m_context) == PluginLID_NoError;
283 }
284 
285 
GetDeviceType() const286 PString OpalPluginLID::GetDeviceType() const
287 {
288   return m_definition.name;
289 }
290 
291 
GetDeviceName() const292 PString OpalPluginLID::GetDeviceName() const
293 {
294   return m_deviceName;
295 }
296 
297 
GetAllNames() const298 PStringArray OpalPluginLID::GetAllNames() const
299 {
300   PStringArray devices;
301 
302   char buffer[200];
303   unsigned index = 0;
304   while (CHECK_FN(GetDeviceName, (m_context, index++, buffer, sizeof(buffer))) == PluginLID_NoError)
305     devices.AppendString(buffer);
306 
307   return devices;
308 }
309 
310 
GetDescription() const311 PString OpalPluginLID::GetDescription() const
312 {
313   return m_definition.description;
314 }
315 
316 
GetLineCount() const317 unsigned OpalPluginLID::GetLineCount() const
318 {
319   unsigned count = 0;
320   CHECK_FN(GetLineCount, (m_context, &count));
321   return count;
322 }
323 
324 
IsLineTerminal(unsigned line)325 PBoolean OpalPluginLID::IsLineTerminal(unsigned line)
326 {
327   PluginLID_Boolean isTerminal = FALSE;
328   CHECK_FN(IsLineTerminal, (m_context, line, &isTerminal));
329   return isTerminal != FALSE;
330 }
331 
332 
IsLinePresent(unsigned line,PBoolean force)333 PBoolean OpalPluginLID::IsLinePresent(unsigned line, PBoolean force)
334 {
335   PluginLID_Boolean isPresent = FALSE;
336   CHECK_FN(IsLinePresent, (m_context, line, force, &isPresent));
337   return isPresent != FALSE;
338 }
339 
340 
IsLineOffHook(unsigned line)341 PBoolean OpalPluginLID::IsLineOffHook(unsigned line)
342 {
343   PluginLID_Boolean offHook = FALSE;
344   CHECK_FN(IsLineOffHook, (m_context, line, &offHook));
345   return offHook != FALSE;
346 }
347 
348 
SetLineOffHook(unsigned line,PBoolean newState)349 PBoolean OpalPluginLID::SetLineOffHook(unsigned line, PBoolean newState)
350 {
351   return CHECK_FN(SetLineOffHook, (m_context, line, newState)) == PluginLID_NoError;
352 }
353 
354 
HookFlash(unsigned line,unsigned flashTime)355 PBoolean OpalPluginLID::HookFlash(unsigned line, unsigned flashTime)
356 {
357   switch (CHECK_FN(HookFlash, (m_context, line, flashTime))) {
358     case PluginLID_UnimplementedFunction :
359       return OpalLineInterfaceDevice::HookFlash(line, flashTime);
360 
361     case PluginLID_NoError :
362       return PTrue;
363 
364     default : ;
365   }
366   return PFalse;
367 }
368 
369 
HasHookFlash(unsigned line)370 PBoolean OpalPluginLID::HasHookFlash(unsigned line)
371 {
372   PluginLID_Boolean flashed = FALSE;
373   CHECK_FN(HasHookFlash, (m_context, line, &flashed));
374   return flashed != FALSE;
375 }
376 
377 
IsLineRinging(unsigned line,DWORD * cadence)378 PBoolean OpalPluginLID::IsLineRinging(unsigned line, DWORD * cadence)
379 {
380   DWORD localCadence;
381   if (cadence == NULL)
382     cadence = &localCadence;
383 
384   if (CHECK_FN(IsLineRinging, (m_context, line, (unsigned long *)cadence)) == PluginLID_NoError)
385     return *cadence != 0;
386 
387   return PFalse;
388 }
389 
390 
RingLine(unsigned line,PINDEX nCadence,const unsigned * pattern,unsigned frequency)391 PBoolean OpalPluginLID::RingLine(unsigned line, PINDEX nCadence, const unsigned * pattern, unsigned frequency)
392 {
393   PUnsignedArray cadence;
394 
395   if (nCadence > 0 && pattern == NULL) {
396     PString description = m_callProgressTones[RingTone];
397     PINDEX colon = description.Find(':');
398     if (colon != P_MAX_INDEX) {
399       unsigned newFrequency = description.Left(colon).AsUnsigned();
400       if (newFrequency > 5 && newFrequency < 3000) {
401         PStringArray times = description.Mid(colon+1).Tokenise('-');
402         if (times.GetSize() > 1) {
403           cadence.SetSize(times.GetSize());
404           for (PINDEX i = 0; i < cadence.GetSize(); i++)
405             cadence[i] = (unsigned)(times[i].AsReal()*1000);
406           nCadence = cadence.GetSize();
407           pattern = cadence;
408           frequency = newFrequency;
409         }
410       }
411     }
412   }
413 
414   switch (CHECK_FN(RingLine, (m_context, line, nCadence, pattern, frequency))) {
415     case PluginLID_UnimplementedFunction :
416       if (nCadence > 0)
417         return StartTonePlayerThread(RingTone+NumTones);
418       StopTonePlayerThread();
419       return true;
420 
421     case PluginLID_NoError :
422       return true;
423 
424     default : ;
425   }
426   return PFalse;
427 }
428 
429 
SetLineConnected(unsigned line)430 PBoolean OpalPluginLID::SetLineConnected(unsigned line)
431 {
432   switch (CHECK_FN(SetLineConnected, (m_context, line))) {
433     case PluginLID_UnimplementedFunction :
434       return OpalLineInterfaceDevice::SetLineConnected(line);
435 
436     case PluginLID_NoError :
437       return true;
438 
439     default : ;
440   }
441   return PFalse;
442 }
443 
444 
IsLineConnected(unsigned line)445 PBoolean OpalPluginLID::IsLineConnected(unsigned line)
446 {
447   PluginLID_Boolean connected = FALSE;
448   switch (CHECK_FN(IsLineConnected, (m_context, line, &connected))) {
449     case PluginLID_UnimplementedFunction :
450       return OpalLineInterfaceDevice::IsLineConnected(line);
451 
452     case PluginLID_NoError :
453       return connected != FALSE;
454 
455     default : ;
456   }
457   return PFalse;
458 }
459 
460 
IsLineDisconnected(unsigned line,PBoolean checkForWink)461 PBoolean OpalPluginLID::IsLineDisconnected(unsigned line, PBoolean checkForWink)
462 {
463   PluginLID_Boolean disconnected = FALSE;
464   switch (CHECK_FN(IsLineDisconnected, (m_context, line, checkForWink, &disconnected))) {
465     case PluginLID_UnimplementedFunction :
466       return OpalLineInterfaceDevice::IsLineDisconnected(line, checkForWink);
467 
468     case PluginLID_NoError :
469       return disconnected != FALSE;
470 
471     default : ;
472   }
473   return PFalse;
474 }
475 
476 
SetLineToLineDirect(unsigned line1,unsigned line2,PBoolean connect)477 PBoolean OpalPluginLID::SetLineToLineDirect(unsigned line1, unsigned line2, PBoolean connect)
478 {
479   return CHECK_FN(SetLineToLineDirect, (m_context, line1, line2, connect)) == PluginLID_NoError;
480 }
481 
482 
IsLineToLineDirect(unsigned line1,unsigned line2)483 PBoolean OpalPluginLID::IsLineToLineDirect(unsigned line1, unsigned line2)
484 {
485   PluginLID_Boolean connected = FALSE;
486   CHECK_FN(IsLineToLineDirect, (m_context, line1, line2, &connected));
487   return connected != FALSE;
488 }
489 
490 
GetMediaFormats() const491 OpalMediaFormatList OpalPluginLID::GetMediaFormats() const
492 {
493   OpalMediaFormatList formats;
494 
495   char buffer[100];
496   unsigned index = 0;
497   for (;;) {
498     switch (CHECK_FN(GetSupportedFormat, (m_context, index++, buffer, sizeof(buffer)))) {
499       case PluginLID_NoMoreNames :
500         return formats;
501 
502       case PluginLID_UnimplementedFunction :
503         formats += OPAL_PCM16;
504         return formats;
505 
506       case PluginLID_NoError :
507       {
508         OpalMediaFormat format = buffer;
509         if (format.IsEmpty()) {
510           PTRACE(2, "LID Plugin\tCodec format \"" << buffer << "\" in " << m_definition.name << " is not supported by OPAL.");
511         }
512         else
513           formats += format;
514       }
515       break;
516 
517       default : ;
518     }
519   }
520 }
521 
522 
SetReadFormat(unsigned line,const OpalMediaFormat & mediaFormat)523 PBoolean OpalPluginLID::SetReadFormat(unsigned line, const OpalMediaFormat & mediaFormat)
524 {
525   switch (CHECK_FN(SetReadFormat, (m_context, line, mediaFormat))) {
526     case PluginLID_UnimplementedFunction :
527       return mediaFormat == OPAL_PCM16;
528 
529     case PluginLID_NoError :
530       return PTrue;
531 
532     default : ;
533   }
534   return PFalse;
535 }
536 
537 
SetWriteFormat(unsigned line,const OpalMediaFormat & mediaFormat)538 PBoolean OpalPluginLID::SetWriteFormat(unsigned line, const OpalMediaFormat & mediaFormat)
539 {
540   switch (CHECK_FN(SetWriteFormat, (m_context, line, mediaFormat))) {
541     case PluginLID_UnimplementedFunction :
542       return mediaFormat == OPAL_PCM16;
543 
544     case PluginLID_NoError :
545       return PTrue;
546 
547     default : ;
548   }
549   return PFalse;
550 }
551 
552 
GetReadFormat(unsigned line)553 OpalMediaFormat OpalPluginLID::GetReadFormat(unsigned line)
554 {
555   char buffer[100];
556   switch (CHECK_FN(GetReadFormat, (m_context, line, buffer, sizeof(buffer)))) {
557     case PluginLID_UnimplementedFunction :
558       return OPAL_PCM16;
559 
560     case PluginLID_NoError :
561       return buffer;
562 
563     default : ;
564   }
565   return OpalMediaFormat();
566 }
567 
568 
GetWriteFormat(unsigned line)569 OpalMediaFormat OpalPluginLID::GetWriteFormat(unsigned line)
570 {
571   char buffer[100];
572   switch (CHECK_FN(GetWriteFormat, (m_context, line, buffer, sizeof(buffer)))) {
573     case PluginLID_UnimplementedFunction :
574       return OPAL_PCM16;
575 
576     case PluginLID_NoError :
577       return buffer;
578 
579     default : ;
580   }
581   return OpalMediaFormat();
582 }
583 
584 
StopReading(unsigned line)585 PBoolean OpalPluginLID::StopReading(unsigned line)
586 {
587   OpalLineInterfaceDevice::StopReading(line);
588 
589   switch (CHECK_FN(StopReading, (m_context, line))) {
590     case PluginLID_UnimplementedFunction :
591       return m_recorder.Abort();
592 
593     case PluginLID_NoError :
594       return PTrue;
595 
596     default : ;
597   }
598   return PFalse;
599 }
600 
601 
StopWriting(unsigned line)602 PBoolean OpalPluginLID::StopWriting(unsigned line)
603 {
604   OpalLineInterfaceDevice::StopWriting(line);
605 
606   m_lockOutTones = false;
607 
608   switch (CHECK_FN(StopWriting, (m_context, line))) {
609     case PluginLID_UnimplementedFunction :
610       return m_player.Abort();
611 
612     case PluginLID_NoError :
613       return PTrue;
614 
615     default : ;
616   }
617   return PFalse;
618 }
619 
620 
SetReadFrameSize(unsigned line,PINDEX frameSize)621 PBoolean OpalPluginLID::SetReadFrameSize(unsigned line, PINDEX frameSize)
622 {
623   switch (CHECK_FN(SetReadFrameSize, (m_context, line, frameSize))) {
624     case PluginLID_UnimplementedFunction :
625       return m_recorder.SetBuffers(frameSize, 2000/frameSize+2); // Want about 250ms of buffering
626 
627     case PluginLID_NoError :
628       return PTrue;
629 
630     default : ;
631   }
632   return PFalse;
633 }
634 
635 
SetWriteFrameSize(unsigned line,PINDEX frameSize)636 PBoolean OpalPluginLID::SetWriteFrameSize(unsigned line, PINDEX frameSize)
637 {
638   switch (CHECK_FN(SetWriteFrameSize, (m_context, line, frameSize))) {
639     case PluginLID_UnimplementedFunction :
640       m_lockOutTones = true;
641       StopTone(line);
642       return m_player.SetBuffers(frameSize, 1000/frameSize+2); // Want about 125ms of buffering
643 
644     case PluginLID_NoError :
645       return PTrue;
646 
647    default : ;
648   }
649   return PFalse;
650 }
651 
652 
GetReadFrameSize(unsigned line)653 PINDEX OpalPluginLID::GetReadFrameSize(unsigned line)
654 {
655   unsigned frameSize = 0;
656   switch (CHECK_FN(GetReadFrameSize, (m_context, line, &frameSize))) {
657     case PluginLID_NoError :
658       return frameSize;
659 
660     case PluginLID_UnimplementedFunction :
661       PINDEX size, buffers;
662       return m_recorder.GetBuffers(size, buffers) ? size : 0;
663 
664       default : ;
665   }
666   return 0;
667 }
668 
669 
GetWriteFrameSize(unsigned line)670 PINDEX OpalPluginLID::GetWriteFrameSize(unsigned line)
671 {
672   unsigned frameSize = 0;
673   switch (CHECK_FN(GetWriteFrameSize, (m_context, line, &frameSize))) {
674     case PluginLID_NoError :
675       return frameSize;
676 
677     case PluginLID_UnimplementedFunction :
678       PINDEX size, buffers;
679       return m_player.GetBuffers(size, buffers) ? size : 0;
680 
681       default : ;
682   }
683   return 0;
684 }
685 
686 
ReadFrame(unsigned line,void * buffer,PINDEX & count)687 PBoolean OpalPluginLID::ReadFrame(unsigned line, void * buffer, PINDEX & count)
688 {
689   unsigned uiCount = 0;
690   switch (CHECK_FN(ReadFrame, (m_context, line, buffer, &uiCount))) {
691     case PluginLID_UnimplementedFunction :
692       count = GetReadFrameSize(line);
693       if (!m_recorder.Read(buffer, count))
694         return PFalse;
695       count = m_recorder.GetLastReadCount();
696       return PTrue;
697 
698     case PluginLID_NoError :
699       count = uiCount;
700       return PTrue;
701 
702    default : ;
703   }
704   return PFalse;
705 }
706 
707 
WriteFrame(unsigned line,const void * buffer,PINDEX count,PINDEX & written)708 PBoolean OpalPluginLID::WriteFrame(unsigned line, const void * buffer, PINDEX count, PINDEX & written)
709 {
710   StopTone(line);
711   m_lockOutTones = true;
712 
713   unsigned uiCount = 0;
714   switch (CHECK_FN(WriteFrame, (m_context, line, buffer, count, &uiCount))) {
715     case PluginLID_UnimplementedFunction :
716       if (!m_player.Write(buffer, count))
717         return PFalse;
718       written = m_player.GetLastWriteCount();
719       return PTrue;
720 
721     case PluginLID_NoError :
722       written = uiCount;
723       return PTrue;
724 
725     default : ;
726   }
727   return PFalse;
728 }
729 
730 
GetAverageSignalLevel(unsigned line,PBoolean playback)731 unsigned OpalPluginLID::GetAverageSignalLevel(unsigned line, PBoolean playback)
732 {
733   unsigned signal = UINT_MAX;
734   CHECK_FN(GetAverageSignalLevel, (m_context, line, playback, &signal));
735   return signal;
736 }
737 
738 
EnableAudio(unsigned line,PBoolean enable)739 PBoolean OpalPluginLID::EnableAudio(unsigned line, PBoolean enable)
740 {
741   switch (CHECK_FN(EnableAudio, (m_context, line, enable))) {
742     case PluginLID_UnimplementedFunction :
743       return OpalLineInterfaceDevice::EnableAudio(line, enable);
744 
745     case PluginLID_NoError :
746       return PTrue;
747 
748     default : ;
749   }
750   return PFalse;
751 }
752 
753 
IsAudioEnabled(unsigned line) const754 PBoolean OpalPluginLID::IsAudioEnabled(unsigned line) const
755 {
756   PluginLID_Boolean enabled = FALSE;
757   if (CHECK_FN(IsAudioEnabled, (m_context, line, &enabled)) == PluginLID_UnimplementedFunction)
758     return OpalLineInterfaceDevice::IsAudioEnabled(line);
759   return enabled != FALSE;
760 }
761 
762 
SetRecordVolume(unsigned line,unsigned volume)763 PBoolean OpalPluginLID::SetRecordVolume(unsigned line, unsigned volume)
764 {
765   switch (CHECK_FN(SetRecordVolume, (m_context, line, volume))) {
766     case PluginLID_UnimplementedFunction :
767       return m_recorder.SetVolume(volume);
768 
769     case PluginLID_NoError :
770       return PTrue;
771 
772     default : ;
773   }
774   return PFalse;
775 }
776 
777 
SetPlayVolume(unsigned line,unsigned volume)778 PBoolean OpalPluginLID::SetPlayVolume(unsigned line, unsigned volume)
779 {
780   switch (CHECK_FN(SetPlayVolume, (m_context, line, volume))) {
781     case PluginLID_UnimplementedFunction :
782       return m_player.SetVolume(volume);
783 
784     case PluginLID_NoError :
785       return PTrue;
786 
787     default : ;
788   }
789   return PFalse;
790 }
791 
792 
GetRecordVolume(unsigned line,unsigned & volume)793 PBoolean OpalPluginLID::GetRecordVolume(unsigned line, unsigned & volume)
794 {
795   switch (CHECK_FN(GetRecordVolume, (m_context, line, &volume))) {
796     case PluginLID_UnimplementedFunction :
797       return m_recorder.GetVolume(volume);
798 
799     case PluginLID_NoError :
800       return PTrue;
801 
802     default : ;
803   }
804   return PFalse;
805 }
806 
807 
GetPlayVolume(unsigned line,unsigned & volume)808 PBoolean OpalPluginLID::GetPlayVolume(unsigned line, unsigned & volume)
809 {
810   switch (CHECK_FN(GetPlayVolume, (m_context, line, &volume))) {
811     case PluginLID_UnimplementedFunction :
812       return m_player.GetVolume(volume);
813 
814     case PluginLID_NoError :
815       return PTrue;
816 
817       default:;
818 
819   }
820   return PFalse;
821 }
822 
823 
GetAEC(unsigned line) const824 OpalLineInterfaceDevice::AECLevels OpalPluginLID::GetAEC(unsigned line) const
825 {
826   unsigned level = AECError;
827   CHECK_FN(GetAEC, (m_context, line, &level));
828   return (AECLevels)level;
829 }
830 
831 
SetAEC(unsigned line,AECLevels level)832 PBoolean OpalPluginLID::SetAEC(unsigned line, AECLevels level)
833 {
834   return CHECK_FN(SetAEC, (m_context, line, level)) == PluginLID_NoError;
835 }
836 
837 
GetVAD(unsigned line) const838 PBoolean OpalPluginLID::GetVAD(unsigned line) const
839 {
840   PluginLID_Boolean vad = FALSE;
841   CHECK_FN(GetVAD, (m_context, line, &vad));
842   return vad != FALSE;
843 }
844 
845 
SetVAD(unsigned line,PBoolean enable)846 PBoolean OpalPluginLID::SetVAD(unsigned line, PBoolean enable)
847 {
848   return CHECK_FN(SetVAD, (m_context, line, enable)) == PluginLID_NoError;
849 }
850 
851 
GetCallerID(unsigned line,PString & idString,PBoolean full)852 PBoolean OpalPluginLID::GetCallerID(unsigned line, PString & idString, PBoolean full)
853 {
854   return CHECK_FN(GetCallerID, (m_context, line, idString.GetPointer(500), 500, full)) == PluginLID_NoError;
855 }
856 
857 
SetCallerID(unsigned line,const PString & idString)858 PBoolean OpalPluginLID::SetCallerID(unsigned line, const PString & idString)
859 {
860   if (idString.IsEmpty())
861     return PFalse;
862 
863   return CHECK_FN(SetCallerID, (m_context, line, idString)) == PluginLID_NoError;
864 }
865 
866 
SendVisualMessageWaitingIndicator(unsigned line,PBoolean on)867 PBoolean OpalPluginLID::SendVisualMessageWaitingIndicator(unsigned line, PBoolean on)
868 {
869   return CHECK_FN(SendVisualMessageWaitingIndicator, (m_context, line, on)) == PluginLID_NoError;
870 }
871 
872 
PlayDTMF(unsigned line,const char * digits,DWORD onTime,DWORD offTime)873 PBoolean OpalPluginLID::PlayDTMF(unsigned line, const char * digits, DWORD onTime, DWORD offTime)
874 {
875   return CHECK_FN(PlayDTMF, (m_context, line, digits, onTime, offTime)) == PluginLID_NoError;
876 }
877 
878 
ReadDTMF(unsigned line)879 char OpalPluginLID::ReadDTMF(unsigned line)
880 {
881   char dtmf = '\0';
882   CHECK_FN(ReadDTMF, (m_context, line, &dtmf));
883   return dtmf;
884 }
885 
886 
GetRemoveDTMF(unsigned line)887 PBoolean OpalPluginLID::GetRemoveDTMF(unsigned line)
888 {
889   PluginLID_Boolean remove = FALSE;
890   CHECK_FN(GetRemoveDTMF, (m_context, line, &remove));
891   return remove != FALSE;
892 }
893 
894 
SetRemoveDTMF(unsigned line,PBoolean removeTones)895 PBoolean OpalPluginLID::SetRemoveDTMF(unsigned line, PBoolean removeTones)
896 {
897   return CHECK_FN(SetRemoveDTMF, (m_context, line, removeTones)) == PluginLID_NoError;
898 }
899 
900 
IsToneDetected(unsigned line)901 OpalLineInterfaceDevice::CallProgressTones OpalPluginLID::IsToneDetected(unsigned line)
902 {
903   int tone = NoTone;
904   CHECK_FN(IsToneDetected, (m_context, line, &tone));
905   return (CallProgressTones)tone;
906 }
907 
908 
WaitForToneDetect(unsigned line,unsigned timeout)909 OpalLineInterfaceDevice::CallProgressTones OpalPluginLID::WaitForToneDetect(unsigned line, unsigned timeout)
910 {
911   int tone = NoTone;
912   if (CHECK_FN(WaitForToneDetect, (m_context, line, timeout, &tone)) == PluginLID_UnimplementedFunction)
913     return OpalLineInterfaceDevice::WaitForToneDetect(line, timeout);
914   return (CallProgressTones)tone;
915 }
916 
917 
WaitForTone(unsigned line,CallProgressTones tone,unsigned timeout)918 PBoolean OpalPluginLID::WaitForTone(unsigned line, CallProgressTones tone, unsigned timeout)
919 {
920   switch (CHECK_FN(WaitForTone, (m_context, line, tone, timeout))) {
921     case PluginLID_UnimplementedFunction :
922       return OpalLineInterfaceDevice::WaitForTone(line, tone, timeout);
923 
924     case PluginLID_NoError :
925       return PTrue;
926 
927     default:
928       break;
929   }
930 
931   return PFalse;
932 }
933 
934 
SetToneParameters(unsigned line,CallProgressTones tone,unsigned frequency1,unsigned frequency2,ToneMixingModes mode,PINDEX numCadences,const unsigned * onTimes,const unsigned * offTimes)935 bool OpalPluginLID::SetToneParameters(unsigned line,
936                                       CallProgressTones tone,
937                                       unsigned frequency1,
938                                       unsigned frequency2,
939                                       ToneMixingModes mode,
940                                       PINDEX numCadences,
941                                       const unsigned * onTimes,
942                                       const unsigned * offTimes)
943 {
944   return CHECK_FN(SetToneParameters, (m_context, line, tone, frequency1, frequency2, mode, numCadences, onTimes, offTimes)) == PluginLID_NoError;
945 }
946 
947 
TonePlayer(PThread &,INT tone)948 void OpalPluginLID::TonePlayer(PThread &, INT tone)
949 {
950   // CHeck if we have NumTones added to value which means high volume output
951   // typically if handset has no ringer, then just hammer the speaker.
952   bool highVolume = tone > NumTones;
953   if (highVolume)
954     tone -= NumTones;
955 
956   if (!PAssert(tone < NumTones, PInvalidParameter))
957     return;
958 
959   PTRACE(4, "LID Plugin\tStarting manual tone generation for \"" << m_callProgressTones[tone] << '"');
960 
961   // Get old volume level, if can't then do not do high volume
962   unsigned oldVolume;
963   if (!m_player.GetVolume(oldVolume))
964     highVolume = false;
965 
966   // Max out the volume level for player
967   if (highVolume)
968     m_player.SetVolume(100);
969 
970   PTones toneData;
971   if (toneData.Generate(m_callProgressTones[tone])) {
972     while (!m_stopTone.Wait(0)) {
973       if (!m_player.Write(toneData, toneData.GetSize()*2)) {
974         PTRACE(2, "LID Plugin\tTone generation write failed.");
975         break;
976       }
977     }
978   }
979   else {
980     PTRACE(2, "LID Plugin\tTone generation for \"" << m_callProgressTones[tone] << "\"failed.");
981   }
982 
983   m_player.Abort();
984 
985   // If we adjusted the volume, then put it back
986   if (highVolume)
987     m_player.SetVolume(oldVolume);
988 
989   PTRACE(4, "LID Plugin\tEnded manual tone generation for \"" << m_callProgressTones[tone] << '"');
990 }
991 
992 
StartTonePlayerThread(int tone)993 bool OpalPluginLID::StartTonePlayerThread(int tone)
994 {
995   StopTonePlayerThread();
996 
997   // Clear out extraneous signals
998   while (m_stopTone.Wait(0))
999     ;
1000 
1001   // Start new tone thread
1002   m_tonePlayer = PThread::Create(PCREATE_NOTIFIER(TonePlayer), tone, PThread::NoAutoDeleteThread, PThread::NormalPriority, "TonePlayer");
1003   return m_tonePlayer != NULL;
1004 }
1005 
1006 
StopTonePlayerThread()1007 void OpalPluginLID::StopTonePlayerThread()
1008 {
1009   // Stop previous tone, if running
1010   if (m_tonePlayer != NULL) {
1011     m_stopTone.Signal();
1012     m_tonePlayer->WaitForTermination(1000);
1013     delete m_tonePlayer;
1014     m_tonePlayer = NULL;
1015   }
1016 }
1017 
1018 
PlayTone(unsigned line,CallProgressTones tone)1019 PBoolean OpalPluginLID::PlayTone(unsigned line, CallProgressTones tone)
1020 {
1021   if (m_lockOutTones)
1022     return StopTone(line);
1023 
1024   switch (CHECK_FN(PlayTone, (m_context, line, tone))) {
1025     case PluginLID_UnimplementedFunction :
1026       return StartTonePlayerThread(tone);
1027 
1028     case PluginLID_NoError :
1029       return PTrue;
1030 
1031     default:
1032       break;
1033   }
1034 
1035   return PFalse;
1036 }
1037 
1038 
IsTonePlaying(unsigned line)1039 PBoolean OpalPluginLID::IsTonePlaying(unsigned line)
1040 {
1041   PluginLID_Boolean playing = FALSE;
1042   if (m_tonePlayer == NULL || m_tonePlayer->IsTerminated())
1043     CHECK_FN(IsTonePlaying, (m_context, line, &playing));
1044   return playing != FALSE;
1045 }
1046 
1047 
StopTone(unsigned line)1048 PBoolean OpalPluginLID::StopTone(unsigned line)
1049 {
1050   StopTonePlayerThread();
1051 
1052   switch (CHECK_FN(StopTone, (m_context, line))) {
1053     case PluginLID_UnimplementedFunction :
1054     case PluginLID_NoError :
1055       return PTrue;
1056     default:
1057       break;
1058   }
1059 
1060   return false;
1061 }
1062 
1063 
DialOut(unsigned line,const PString & number,const DialParams & params)1064 OpalLineInterfaceDevice::CallProgressTones OpalPluginLID::DialOut(unsigned line, const PString & number, const DialParams & params)
1065 {
1066   if (m_definition.DialOut == NULL)
1067     return OpalLineInterfaceDevice::DialOut(line, number, params);
1068 
1069   if (BAD_FN(DialOut))
1070     return NoTone;
1071 
1072   struct PluginLID_DialParams pparams;
1073   pparams.m_requireTones = params.m_requireTones;
1074   pparams.m_dialToneTimeout = params.m_dialToneTimeout;
1075   pparams.m_dialStartDelay = params.m_dialStartDelay;
1076   pparams.m_progressTimeout = params.m_progressTimeout;
1077   pparams.m_commaDelay = params.m_commaDelay;
1078 
1079   osError = m_definition.DialOut(m_context, line, number, &pparams);
1080   switch (osError)
1081   {
1082     case PluginLID_NoError :
1083       return RingTone;
1084     case PluginLID_NoDialTone :
1085       return DialTone;
1086     case PluginLID_LineBusy :
1087       return BusyTone;
1088     case PluginLID_NoAnswer :
1089       return ClearTone;
1090 #if PTRACING
1091     default :
1092       CheckError((PluginLID_Errors)osError, "DialOut");
1093 #endif
1094   }
1095 
1096   return NoTone;
1097 }
1098 
1099 
GetWinkDuration(unsigned line)1100 unsigned OpalPluginLID::GetWinkDuration(unsigned line)
1101 {
1102   unsigned duration = 0;
1103   CHECK_FN(GetWinkDuration, (m_context, line, &duration));
1104   return duration;
1105 }
1106 
1107 
SetWinkDuration(unsigned line,unsigned winkDuration)1108 PBoolean OpalPluginLID::SetWinkDuration(unsigned line, unsigned winkDuration)
1109 {
1110   return CHECK_FN(SetWinkDuration, (m_context, line, winkDuration)) == PluginLID_NoError;
1111 }
1112 
1113 
SetCountryCode(T35CountryCodes country)1114 PBoolean OpalPluginLID::SetCountryCode(T35CountryCodes country)
1115 {
1116   switch (CHECK_FN(SetCountryCode, (m_context, country))) {
1117     case PluginLID_UnimplementedFunction :
1118       return OpalLineInterfaceDevice::SetCountryCode(country);
1119 
1120     case PluginLID_NoError :
1121       return PTrue;
1122 
1123     default:
1124       break;
1125   }
1126 
1127   return PFalse;
1128 }
1129 
1130 
GetCountryCodeNameList() const1131 PStringList OpalPluginLID::GetCountryCodeNameList() const
1132 {
1133   PStringList countries;
1134 
1135   unsigned index = 0;
1136   for (;;) {
1137     unsigned countryCode = NumCountryCodes;
1138     switch (CHECK_FN(GetSupportedCountry, (m_context, index++, &countryCode))) {
1139       case PluginLID_UnimplementedFunction :
1140         return OpalLineInterfaceDevice::GetCountryCodeNameList();
1141 
1142       case PluginLID_NoError :
1143         if (countryCode < NumCountryCodes)
1144           countries.AppendString(GetCountryCodeName((T35CountryCodes)countryCode));
1145         break;
1146 
1147       case PluginLID_NoMoreNames :
1148         return countries;
1149 
1150       default :
1151         return PStringList();
1152     }
1153   }
1154 }
1155 
1156