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