1 /*
2  * opal_c.cxx
3  *
4  * "C" language interface for OPAL
5  *
6  * Open Phone Abstraction Library (OPAL)
7  *
8  * Copyright (c) 2008 Vox Lucida
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Open Phone Abstraction Library.
21  *
22  * The Initial Developer of the Original Code is Vox Lucida (Robert Jongbloed)
23  *
24  * This code was initially written with the assisance of funding from
25  * Stonevoice. http://www.stonevoice.com.
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Revision: 27795 $
30  * $Author: rjongbloed $
31  * $Date: 2012-06-07 22:49:21 -0500 (Thu, 07 Jun 2012) $
32  */
33 
34 #include <ptlib.h>
35 
36 #include <opal/buildopts.h>
37 
38 #include <opal.h>
39 #include <opal/manager.h>
40 
41 #if OPAL_HAS_PCSS
42 #include <opal/pcss.h>
43 #endif
44 
45 #include <opal/localep.h>
46 #include <h323/h323ep.h>
47 #include <sip/sipep.h>
48 #include <iax2/iax2ep.h>
49 #include <lids/lidep.h>
50 #include <t38/t38proto.h>
51 #include <opal/ivr.h>
52 
53 #include <queue>
54 
55 
56 class OpalManager_C;
57 
58 
operator <<(ostream & strm,OpalMessageType type)59 ostream & operator<<(ostream & strm, OpalMessageType type)
60 {
61   static const char * const Types[] = {
62     "IndCommandError",
63     "CmdSetGeneralParameters",
64     "CmdSetProtocolParameters",
65     "CmdRegistration",
66     "IndRegistration",
67     "CmdSetUpCall",
68     "IndIncomingCall",
69     "CmdAnswerCall",
70     "CmdClearCall",
71     "IndAlerting",
72     "IndEstablished",
73     "IndUserInput",
74     "IndCallCleared",
75     "CmdHoldCall",
76     "CmdRetrieveCall",
77     "CmdTransferCall",
78     "CmdUserInput",
79     "IndMessageWaiting",
80     "IndMediaStream",
81     "CmdMediaStream",
82     "CmdSetUserData",
83     "IndLineAppearance",
84     "CmdStartRecording",
85     "CmdStopRecording",
86     "IndProceeding",
87     "CmdAlerting",
88     "IndOnHold",
89     "IndOffHold",
90     "IndTransferCall",
91     "IndCompletedIVR"
92   };
93   if (type >= 0 && type < PARRAYSIZE(Types))
94     strm << Types[type];
95   else
96     strm << '<' << (unsigned)type << '>';
97   return strm;
98 }
99 
100 
operator <<(ostream & strm,OpalRegistrationStates state)101 ostream & operator<<(ostream & strm, OpalRegistrationStates state)
102 {
103   static const char * States[] = { "Successful", "Removed", "Failed", "Retrying", "Restored" };
104   return strm << States[state];
105 }
106 
107 
IsNullString(const char * str)108 inline bool IsNullString(const char * str)
109 {
110   return str == NULL || *str == '\0';
111 }
112 
113 
114 class OpalMessageBuffer
115 {
116   public:
117     OpalMessageBuffer(OpalMessageType type);
118     ~OpalMessageBuffer();
119 
operator ->() const120     OpalMessage * operator->() const { return  (OpalMessage *)m_data; }
operator *() const121     OpalMessage & operator *() const { return *(OpalMessage *)m_data; }
operator OpalMessage*() const122     operator OpalMessage *() const   { return  (OpalMessage *)m_data; }
123 
124     void SetString(const char * * variable, const char * value);
125     void SetError(const char * errorText);
126 
127     OpalMessage * Detach();
128 
129   private:
130     size_t m_size;
131     char * m_data;
132     std::vector<size_t> m_strPtrOffset;
133 };
134 
135 #define SET_MESSAGE_STRING(msg, member, str) (msg).SetString(&(msg)->member, str)
136 
137 
138 #if OPAL_HAS_PCSS
139 
140 class OpalPCSSEndPoint_C : public OpalPCSSEndPoint
141 {
142   public:
143     OpalPCSSEndPoint_C(OpalManager_C & manager);
144 
145     virtual PBoolean OnShowIncoming(const OpalPCSSConnection &);
146     virtual PBoolean OnShowOutgoing(const OpalPCSSConnection &);
147 
148   private:
149     OpalManager_C & m_manager;
150 };
151 
152 #endif // OPAL_HAS_PCSS
153 
154 
155 class OpalLocalEndPoint_C : public OpalLocalEndPoint
156 {
157   public:
158     OpalLocalEndPoint_C(OpalManager_C & manager);
159 
160     virtual bool OnOutgoingCall(const OpalLocalConnection &);
161     virtual bool OnIncomingCall(OpalLocalConnection &);
162     virtual bool OnReadMediaFrame(const OpalLocalConnection &, const OpalMediaStream & mediaStream, RTP_DataFrame &);
163     virtual bool OnWriteMediaFrame(const OpalLocalConnection &, const OpalMediaStream &, RTP_DataFrame & frame);
164     virtual bool OnReadMediaData(const OpalLocalConnection &, const OpalMediaStream &, void *, PINDEX, PINDEX &);
165     virtual bool OnWriteMediaData(const OpalLocalConnection &, const OpalMediaStream &, const void *, PINDEX, PINDEX &);
166 
167     OpalMediaDataFunction m_mediaReadData;
168     OpalMediaDataFunction m_mediaWriteData;
169     OpalMediaDataType     m_mediaDataHeader;
170 
171   private:
172     OpalManager_C & m_manager;
173 };
174 
175 
176 #if OPAL_IVR
177 
178 class OpalIVREndPoint_C : public OpalIVREndPoint
179 {
180   public:
181     OpalIVREndPoint_C(OpalManager_C & manager);
182 
183     virtual bool OnOutgoingCall(const OpalLocalConnection &);
184     virtual bool OnIncomingCall(OpalLocalConnection & connection);
185     virtual void OnEndDialog(OpalIVRConnection & connection);
186 
187   private:
188     OpalManager_C & m_manager;
189 };
190 
191 #endif // OPAL_IVR
192 
193 
194 #if OPAL_SIP
195 class SIPEndPoint_C : public SIPEndPoint
196 {
197   public:
198     SIPEndPoint_C(OpalManager_C & manager);
199 
200     virtual void OnRegistrationStatus(
201       const RegistrationStatus & status
202     );
203     virtual void OnSubscriptionStatus(
204       const PString & eventPackage, ///< Event package subscribed to
205       const SIPURL & uri,           ///< Target URI for the subscription.
206       bool wasSubscribing,          ///< Indication the subscribing or unsubscribing
207       bool reSubscribing,           ///< If subscribing then indication was refeshing subscription
208       SIP_PDU::StatusCodes reason   ///< Status of subscription
209     );
210     virtual void OnDialogInfoReceived(
211       const SIPDialogNotification & info  ///< Information on dialog state change
212     );
213 
214   private:
215     OpalManager_C & m_manager;
216 };
217 #endif
218 
219 
220 class OpalManager_C : public OpalManager
221 {
222   public:
OpalManager_C(unsigned version)223     OpalManager_C(unsigned version)
224       : m_localEP(NULL)
225 #if OPAL_HAS_PCSS
226       , m_pcssEP(NULL)
227 #endif
228 #if OPAL_IVR
229       , m_ivrEP(NULL)
230 #endif
231       , m_apiVersion(version)
232       , m_manualAlerting(false)
233       , m_messagesAvailable(0, INT_MAX)
234     {
235     }
236 
~OpalManager_C()237     ~OpalManager_C()
238     {
239       ShutDownEndpoints();
240     }
241 
242     bool Initialise(const PCaselessString & options);
243 
244     void PostMessage(OpalMessageBuffer & message);
245     OpalMessage * GetMessage(unsigned timeout);
246     OpalMessage * SendMessage(const OpalMessage * message);
247 
248     virtual void OnEstablishedCall(OpalCall & call);
249     virtual void OnHold(OpalConnection & connection, bool fromRemote, bool onHold);
250     virtual bool OnTransferNotify(OpalConnection &, const PStringToString &);
251     virtual PBoolean OnOpenMediaStream(OpalConnection & connection, OpalMediaStream & stream);
252     virtual void OnClosedMediaStream(const OpalMediaStream & stream);
253     virtual void OnUserInputString(OpalConnection & connection, const PString & value);
254     virtual void OnUserInputTone(OpalConnection & connection, char tone, int duration);
255     virtual void OnMWIReceived(const PString & party, MessageWaitingType type, const PString & extraInfo);
256     virtual void OnProceeding(OpalConnection & conenction);
257     virtual void OnClearedCall(OpalCall & call);
258 
259     void SendIncomingCallInfo(const OpalConnection & connection);
260 
261   private:
262     void HandleSetGeneral    (const OpalMessage & message, OpalMessageBuffer & response);
263     void HandleSetProtocol   (const OpalMessage & message, OpalMessageBuffer & response);
264     void HandleRegistration  (const OpalMessage & message, OpalMessageBuffer & response);
265     void HandleSetUpCall     (const OpalMessage & message, OpalMessageBuffer & response);
266     void HandleAlerting      (const OpalMessage & message, OpalMessageBuffer & response);
267     void HandleAnswerCall    (const OpalMessage & message, OpalMessageBuffer & response);
268     void HandleUserInput     (const OpalMessage & message, OpalMessageBuffer & response);
269     void HandleClearCall     (const OpalMessage & message, OpalMessageBuffer & response);
270     void HandleHoldCall      (const OpalMessage & message, OpalMessageBuffer & response);
271     void HandleRetrieveCall  (const OpalMessage & message, OpalMessageBuffer & response);
272     void HandleTransferCall  (const OpalMessage & message, OpalMessageBuffer & response);
273     void HandleMediaStream   (const OpalMessage & command, OpalMessageBuffer & response);
274     void HandleSetUserData   (const OpalMessage & command, OpalMessageBuffer & response);
275     void HandleStartRecording(const OpalMessage & command, OpalMessageBuffer & response);
276     void HandleStopRecording (const OpalMessage & command, OpalMessageBuffer & response);
277 
278     void OnIndMediaStream(const OpalMediaStream & stream, OpalMediaStates state);
279 
280     bool FindCall(const char * token, OpalMessageBuffer & response, PSafePtr<OpalCall> & call);
281 
282     OpalLocalEndPoint_C * m_localEP;
283 #if OPAL_HAS_PCSS
284     OpalPCSSEndPoint_C  * m_pcssEP;
285 #endif
286 #if OPAL_IVR
287     OpalIVREndPoint_C   * m_ivrEP;
288 #endif
289 
290     unsigned                  m_apiVersion;
291     bool                      m_manualAlerting;
292     std::queue<OpalMessage *> m_messageQueue;
293     PMutex                    m_messageMutex;
294     PSemaphore                m_messagesAvailable;
295     OpalMessageAvailableFunction m_messageAvailableCallback;
296 };
297 
298 
299 class PProcess_C : public PLibraryProcess
300 {
301 public:
PProcess_C(const PCaselessString & options)302   PProcess_C(const PCaselessString & options)
303   {
304 #if PTRACING
305     unsigned level = 0;
306     static char const TraceLevelKey[] = "TraceLevel=";
307     PINDEX pos = options.Find(TraceLevelKey);
308     if (pos != P_MAX_INDEX)
309       level = options.Mid(pos+sizeof(TraceLevelKey)-1).AsUnsigned();
310 
311 #ifdef WIN32
312     PString filename = "DEBUGSTREAM";
313 #else
314     PString filename = "stderr";
315 #endif
316     static char const TraceFileKey[] = "TraceFile=";
317     pos = options.Find(TraceFileKey);
318     if (pos != P_MAX_INDEX) {
319       pos += sizeof(TraceFileKey) - 1;
320       PINDEX end;
321       if (options[pos] == '"')
322         end = options.Find('"', ++pos);
323       else
324         end = options.Find(' ', pos);
325       filename = options(pos, end-1);
326     }
327 
328     unsigned traceOpts = PTrace::Timestamp|PTrace::Thread|PTrace::Blocks;
329     if (options.Find("TraceAppend") != P_MAX_INDEX)
330       traceOpts |= PTrace::AppendToFile;
331 
332     PTrace::Initialise(level, filename, traceOpts);
333     PTRACE(1, "OpalC\tStart Up, OPAL version " << OpalGetVersion());
334 #endif
335   }
336 
~PProcess_C()337   ~PProcess_C()
338   {
339     PTRACE(1, "OpalC\tShut Down.");
340   }
341 };
342 
343 struct OpalHandleStruct
344 {
OpalHandleStructOpalHandleStruct345   OpalHandleStruct(unsigned version, const PCaselessString & options)
346     : process(options)
347     , manager(version)
348   {
349   }
350 
351   PProcess_C     process;
352   OpalManager_C  manager;
353 };
354 
355 
356 ///////////////////////////////////////////////////////////////////////////////
357 
OpalMessageBuffer(OpalMessageType type)358 OpalMessageBuffer::OpalMessageBuffer(OpalMessageType type)
359   : m_size(sizeof(OpalMessage))
360   , m_data((char *)malloc(m_size))
361 {
362   memset(m_data, 0, m_size);
363   (*this)->m_type = type;
364 }
365 
366 
~OpalMessageBuffer()367 OpalMessageBuffer::~OpalMessageBuffer()
368 {
369   if (m_data != NULL)
370     free(m_data);
371 }
372 
373 
SetString(const char ** variable,const char * value)374 void OpalMessageBuffer::SetString(const char * * variable, const char * value)
375 {
376   PAssert((char *)variable >= m_data && (char *)variable < m_data+m_size, PInvalidParameter);
377 
378   size_t length = strlen(value)+1;
379 
380   char * newData = (char *)realloc(m_data, m_size + length);
381   if (PAssertNULL(newData) != m_data) {
382     // Memory has moved, this invalidates pointer variables so recalculate them
383     int delta = newData - m_data;
384     char * endData = m_data + m_size;
385     for (size_t i = 0; i < m_strPtrOffset.size(); ++i) {
386       const char ** ptr = (const char **)(newData + m_strPtrOffset[i]);
387       if (*ptr >= m_data && *ptr < endData)
388         *ptr += delta;
389     }
390     variable += delta/sizeof(char *);
391     m_data = newData;
392   }
393 
394   char * stringData = m_data + m_size;
395   memcpy(stringData, value, length);
396   m_size += length;
397 
398   *variable = stringData;
399 
400   m_strPtrOffset.push_back((char *)variable - m_data);
401 }
402 
403 
SetError(const char * errorText)404 void OpalMessageBuffer::SetError(const char * errorText)
405 {
406   OpalMessage * message = (OpalMessage *)m_data;
407   PTRACE(2, "OpalC API\tCommand " << message->m_type << " error: " << errorText);
408 
409   message->m_type = OpalIndCommandError;
410   m_strPtrOffset.clear();
411   SetString(&message->m_param.m_commandError, errorText);
412 }
413 
414 
Detach()415 OpalMessage * OpalMessageBuffer::Detach()
416 {
417   OpalMessage * message = (OpalMessage *)m_data;
418   m_data = NULL;
419   return message;
420 }
421 
422 
BuildProductName(const OpalProductInfo & info)423 PString BuildProductName(const OpalProductInfo & info)
424 {
425   if (info.comments.IsEmpty())
426     return info.name;
427   if (info.comments[0] == '(')
428     return info.name + ' ' + info.comments;
429   return info.name + " (" + info.comments + ')';
430 }
431 
432 
433 ///////////////////////////////////////
434 
OpalLocalEndPoint_C(OpalManager_C & mgr)435 OpalLocalEndPoint_C::OpalLocalEndPoint_C(OpalManager_C & mgr)
436   : OpalLocalEndPoint(mgr)
437   , m_mediaReadData(NULL)
438   , m_mediaWriteData(NULL)
439   , m_mediaDataHeader(OpalMediaDataPayloadOnly)
440   , m_manager(mgr)
441 {
442 }
443 
444 
SetOutgoingCallInfo(OpalMessageBuffer & message,const OpalConnection & connection)445 static void SetOutgoingCallInfo(OpalMessageBuffer & message, const OpalConnection & connection)
446 {
447   const OpalCall & call = connection.GetCall();
448   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyA, call.GetPartyA());
449   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyB, call.GetPartyB());
450   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_callToken, call.GetToken());
451   PTRACE(4, "OpalC API\tOnOutgoingCall:"
452             " token=\"" << message->m_param.m_callSetUp.m_callToken << "\""
453             " A=\""     << message->m_param.m_callSetUp.m_partyA << "\""
454             " B=\""     << message->m_param.m_callSetUp.m_partyB << '"');
455 }
456 
457 
OnOutgoingCall(const OpalLocalConnection & connection)458 bool OpalLocalEndPoint_C::OnOutgoingCall(const OpalLocalConnection & connection)
459 {
460   OpalMessageBuffer message(OpalIndAlerting);
461   SetOutgoingCallInfo(message, connection);
462   m_manager.PostMessage(message);
463   return true;
464 }
465 
466 
SendIncomingCallInfo(const OpalConnection & connection)467 void OpalManager_C::SendIncomingCallInfo(const OpalConnection & connection)
468 {
469   OpalMessageBuffer message(OpalIndIncomingCall);
470 
471   PSafePtr<OpalConnection> network = connection.GetOtherPartyConnection();
472   PAssert(network != NULL, PLogicError); // Should not happen!
473 
474   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_callToken, connection.GetCall().GetToken());
475   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_localAddress, network->GetLocalPartyURL());
476   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_remoteAddress, network->GetRemotePartyURL());
477   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_remotePartyNumber, network->GetRemotePartyNumber());
478   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_remoteDisplayName, network->GetRemotePartyName());
479   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_calledAddress, network->GetCalledPartyURL());
480   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_calledPartyNumber, network->GetCalledPartyNumber());
481 
482   if (m_apiVersion >= 22) {
483     PString redirect = network->GetRedirectingParty();
484     SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_referredByAddress, redirect);
485     if (!OpalIsE164(redirect)) {
486       redirect = PURL(redirect).GetUserName();
487       if (!OpalIsE164(redirect))
488         redirect.MakeEmpty();
489     }
490     SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_redirectingNumber, redirect);
491   }
492 
493   const OpalProductInfo & info = network->GetRemoteProductInfo();
494   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_product.m_vendor,  info.vendor);
495   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_product.m_name,    BuildProductName(info));
496   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_product.m_version, info.version);
497 
498   message->m_param.m_incomingCall.m_product.m_t35CountryCode   = info.t35CountryCode;
499   message->m_param.m_incomingCall.m_product.m_t35Extension     = info.t35Extension;
500   message->m_param.m_incomingCall.m_product.m_manufacturerCode = info.manufacturerCode;
501 
502   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_alertingType,   network->GetAlertingType());
503   SET_MESSAGE_STRING(message, m_param.m_incomingCall.m_protocolCallId, connection.GetIdentifier());
504 
505   PTRACE(4, "OpalC API\tOpalIndIncomingCall: token=\""  << message->m_param.m_incomingCall.m_callToken << "\"\n"
506             "  Local  - URL=\"" << message->m_param.m_incomingCall.m_localAddress << "\"\n"
507             "  Remote - URL=\"" << message->m_param.m_incomingCall.m_remoteAddress << "\""
508                     " E.164=\"" << message->m_param.m_incomingCall.m_remotePartyNumber << "\""
509                   " Display=\"" << message->m_param.m_incomingCall.m_remoteDisplayName << "\"\n"
510             "  Dest.  - URL=\"" << message->m_param.m_incomingCall.m_calledAddress << "\""
511                     " E.164=\"" << message->m_param.m_incomingCall.m_calledPartyNumber << "\"\n"
512             "  AlertingType=\"" << message->m_param.m_incomingCall.m_alertingType << "\"\n"
513             "        CallID=\"" << message->m_param.m_incomingCall.m_protocolCallId << '"');
514 
515   PostMessage(message);
516 }
517 
518 
OnIncomingCall(OpalLocalConnection & connection)519 bool OpalLocalEndPoint_C::OnIncomingCall(OpalLocalConnection & connection)
520 {
521   m_manager.SendIncomingCallInfo(connection);
522   return true;
523 }
524 
525 
OnReadMediaFrame(const OpalLocalConnection & connection,const OpalMediaStream & mediaStream,RTP_DataFrame & frame)526 bool OpalLocalEndPoint_C::OnReadMediaFrame(const OpalLocalConnection & connection,
527                                            const OpalMediaStream & mediaStream,
528                                            RTP_DataFrame & frame)
529 {
530   if (m_mediaDataHeader != OpalMediaDataWithHeader)
531     return false;
532 
533   if (m_mediaReadData == NULL)
534     return false;
535 
536   int result = m_mediaReadData(connection.GetCall().GetToken(),
537                                mediaStream.GetID(),
538                                mediaStream.GetMediaFormat().GetName(),
539                                connection.GetUserData(),
540                                frame.GetPointer(),
541                                frame.GetSize());
542   if (result < 0)
543     return false;
544 
545   frame.SetPayloadSize(result-frame.GetHeaderSize());
546   return true;
547 }
548 
549 
OnWriteMediaFrame(const OpalLocalConnection & connection,const OpalMediaStream & mediaStream,RTP_DataFrame & frame)550 bool OpalLocalEndPoint_C::OnWriteMediaFrame(const OpalLocalConnection & connection,
551                                             const OpalMediaStream & mediaStream,
552                                             RTP_DataFrame & frame)
553 {
554   if (m_mediaDataHeader != OpalMediaDataWithHeader)
555     return false;
556 
557   if (m_mediaWriteData == NULL)
558     return false;
559 
560   int result = m_mediaWriteData(connection.GetCall().GetToken(),
561                                 mediaStream.GetID(),
562                                 mediaStream.GetMediaFormat().GetName(),
563                                 connection.GetUserData(),
564                                 frame.GetPointer(),
565                                 frame.GetHeaderSize()+frame.GetPayloadSize());
566   return result >= 0;
567 }
568 
569 
OnReadMediaData(const OpalLocalConnection & connection,const OpalMediaStream & mediaStream,void * data,PINDEX size,PINDEX & length)570 bool OpalLocalEndPoint_C::OnReadMediaData(const OpalLocalConnection & connection,
571                                           const OpalMediaStream & mediaStream,
572                                           void * data,
573                                           PINDEX size,
574                                           PINDEX & length)
575 {
576   if (m_mediaDataHeader != OpalMediaDataPayloadOnly)
577     return false;
578 
579   if (m_mediaReadData == NULL)
580     return false;
581 
582   int result = m_mediaReadData(connection.GetCall().GetToken(),
583                                mediaStream.GetID(),
584                                mediaStream.GetMediaFormat().GetName(),
585                                connection.GetUserData(),
586                                data,
587                                size);
588   if (result < 0)
589     return false;
590 
591   length = result;
592   return true;
593 }
594 
595 
OnWriteMediaData(const OpalLocalConnection & connection,const OpalMediaStream & mediaStream,const void * data,PINDEX length,PINDEX & written)596 bool OpalLocalEndPoint_C::OnWriteMediaData(const OpalLocalConnection & connection,
597                                            const OpalMediaStream & mediaStream,
598                                            const void * data,
599                                            PINDEX length,
600                                            PINDEX & written)
601 {
602   if (m_mediaDataHeader != OpalMediaDataPayloadOnly)
603     return false;
604 
605   if (m_mediaWriteData == NULL)
606     return false;
607 
608   int result = m_mediaWriteData(connection.GetCall().GetToken(),
609                                 mediaStream.GetID(),
610                                 mediaStream.GetMediaFormat().GetName(),
611                                 connection.GetUserData(),
612                                 (void *)data,
613                                 length);
614   if (result < 0)
615     return false;
616 
617   written = result;
618   return true;
619 }
620 
621 
622 ///////////////////////////////////////
623 
624 #if OPAL_HAS_PCSS
625 
OpalPCSSEndPoint_C(OpalManager_C & mgr)626 OpalPCSSEndPoint_C::OpalPCSSEndPoint_C(OpalManager_C & mgr)
627   : OpalPCSSEndPoint(mgr)
628   , m_manager(mgr)
629 {
630 }
631 
632 
OnShowIncoming(const OpalPCSSConnection & connection)633 PBoolean OpalPCSSEndPoint_C::OnShowIncoming(const OpalPCSSConnection & connection)
634 {
635   m_manager.SendIncomingCallInfo(connection);
636   return true;
637 }
638 
639 
OnShowOutgoing(const OpalPCSSConnection & connection)640 PBoolean OpalPCSSEndPoint_C::OnShowOutgoing(const OpalPCSSConnection & connection)
641 {
642   OpalMessageBuffer message(OpalIndAlerting);
643   SetOutgoingCallInfo(message, connection);
644   m_manager.PostMessage(message);
645   return true;
646 }
647 
648 #endif // OPAL_HAS_PCSS
649 
650 
651 ///////////////////////////////////////
652 
653 #if OPAL_IVR
654 
OpalIVREndPoint_C(OpalManager_C & manager)655 OpalIVREndPoint_C::OpalIVREndPoint_C(OpalManager_C & manager)
656   : OpalIVREndPoint(manager)
657   , m_manager(manager)
658 {
659 }
660 
661 
OnOutgoingCall(const OpalLocalConnection & connection)662 bool OpalIVREndPoint_C::OnOutgoingCall(const OpalLocalConnection & connection)
663 {
664   OpalMessageBuffer message(OpalIndAlerting);
665   SetOutgoingCallInfo(message, connection);
666   m_manager.PostMessage(message);
667   return true;
668 }
669 
670 
OnIncomingCall(OpalLocalConnection & connection)671 bool OpalIVREndPoint_C::OnIncomingCall(OpalLocalConnection & connection)
672 {
673   m_manager.SendIncomingCallInfo(connection);
674   return true;
675 }
676 
677 
OnEndDialog(OpalIVRConnection & connection)678 void OpalIVREndPoint_C::OnEndDialog(OpalIVRConnection & connection)
679 {
680   PTRACE(4, "OpalC API\tOnEndDialog for " << connection);
681 
682   // Do not call ancestor and start a long pause, as do not want it to hang up
683   connection.TransferConnection("<vxml><form><break time=\"3600s\"/></form></vxml>");
684 
685   // Send message to app, which may (or may not) start a new IVR script
686   OpalMessageBuffer message(OpalIndCompletedIVR);
687   SET_MESSAGE_STRING(message, m_param.m_ivrStatus.m_callToken, connection.GetCall().GetToken());
688 
689   PStringStream varStr;
690   varStr << connection.GetVXMLSession().GetVariables();
691   SET_MESSAGE_STRING(message, m_param.m_ivrStatus.m_variables, varStr);
692 
693   m_manager.PostMessage(message);
694 }
695 
696 #endif
697 
698 
699 ///////////////////////////////////////
700 
701 #if OPAL_SIP
702 
SIPEndPoint_C(OpalManager_C & mgr)703 SIPEndPoint_C::SIPEndPoint_C(OpalManager_C & mgr)
704   : SIPEndPoint(mgr)
705   , m_manager(mgr)
706 {
707 }
708 
709 
OnRegistrationStatus(const RegistrationStatus & status)710 void SIPEndPoint_C::OnRegistrationStatus(const RegistrationStatus & status)
711 {
712   SIPEndPoint::OnRegistrationStatus(status);
713 
714   OpalMessageBuffer message(OpalIndRegistration);
715   SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_protocol, OPAL_PREFIX_SIP);
716   SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_serverName, status.m_addressofRecord);
717 
718   SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_product.m_vendor,  status.m_productInfo.vendor);
719   SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_product.m_name,    BuildProductName(status.m_productInfo));
720   SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_product.m_version, status.m_productInfo.version);
721 
722   message->m_param.m_registrationStatus.m_product.m_t35CountryCode   = status.m_productInfo.t35CountryCode;
723   message->m_param.m_registrationStatus.m_product.m_t35Extension     = status.m_productInfo.t35Extension;
724   message->m_param.m_registrationStatus.m_product.m_manufacturerCode = status.m_productInfo.manufacturerCode;
725 
726   if (status.m_reason == SIP_PDU::Information_Trying)
727     message->m_param.m_registrationStatus.m_status = OpalRegisterRetrying;
728   else if (status.m_reason/100 == 2) {
729     if (status.m_wasRegistering)
730       message->m_param.m_registrationStatus.m_status = status.m_reRegistering ? OpalRegisterRestored : OpalRegisterSuccessful;
731     else
732       message->m_param.m_registrationStatus.m_status = OpalRegisterRemoved;
733   }
734   else {
735     PStringStream strm;
736     strm << "Error " << status.m_reason << " in SIP ";
737     if (!status.m_wasRegistering)
738       strm << "un";
739     strm << "registration.";
740     SET_MESSAGE_STRING(message, m_param.m_registrationStatus.m_error, strm);
741     message->m_param.m_registrationStatus.m_status = status.m_wasRegistering ? OpalRegisterFailed : OpalRegisterRemoved;
742   }
743   PTRACE(4, "OpalC\tOnRegistrationStatus " << status.m_addressofRecord << ", status=" << message->m_param.m_registrationStatus.m_status);
744   m_manager.PostMessage(message);
745 }
746 
747 
OnSubscriptionStatus(const PString & eventPackage,const SIPURL & uri,bool wasSubscribing,bool reSubscribing,SIP_PDU::StatusCodes reason)748 void SIPEndPoint_C::OnSubscriptionStatus(const PString & eventPackage,
749                                          const SIPURL & uri,
750                                          bool wasSubscribing,
751                                          bool reSubscribing,
752                                          SIP_PDU::StatusCodes reason)
753 {
754   SIPEndPoint::OnSubscriptionStatus(eventPackage, uri, wasSubscribing, reSubscribing, reason);
755 
756   if (reason == SIP_PDU::Successful_OK && !reSubscribing) {
757     if (SIPEventPackage(SIPSubscribe::MessageSummary) == eventPackage) {
758       OpalMessageBuffer message(OpalIndMessageWaiting);
759       SET_MESSAGE_STRING(message, m_param.m_messageWaiting.m_party, uri.AsString());
760       SET_MESSAGE_STRING(message, m_param.m_messageWaiting.m_extraInfo, wasSubscribing ? "SUBSCRIBED" : "UNSUBSCRIBED");
761       PTRACE(4, "OpalC API\tOnSubscriptionStatus - MWI: party=\"" << message->m_param.m_messageWaiting.m_party
762                                               << "\" info=" << message->m_param.m_messageWaiting.m_extraInfo);
763       m_manager.PostMessage(message);
764     }
765     else if (SIPEventPackage(SIPSubscribe::Dialog) == eventPackage) {
766       OpalMessageBuffer message(OpalIndLineAppearance);
767       SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_line, uri.AsString());
768       message->m_param.m_lineAppearance.m_state = wasSubscribing ? OpalLineSubcribed : OpalLineUnsubcribed;
769       PTRACE(4, "OpalC API\tOnSubscriptionStatus - LineAppearance: line=\"" << message->m_param.m_lineAppearance.m_line);
770       m_manager.PostMessage(message);
771     }
772   }
773 }
774 
775 
GetParticipantName(const SIPDialogNotification::Participant & participant)776 static PString GetParticipantName(const SIPDialogNotification::Participant & participant)
777 {
778   PStringStream strm;
779   strm << '"' << participant.m_display << "\" <" << participant.m_URI << '>';
780   return strm;
781 }
782 
783 
OnDialogInfoReceived(const SIPDialogNotification & info)784 void SIPEndPoint_C::OnDialogInfoReceived(const SIPDialogNotification & info)
785 {
786   SIPEndPoint::OnDialogInfoReceived(info);
787 
788   OpalMessageBuffer message(OpalIndLineAppearance);
789   SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_line, info.m_entity);
790   message->m_param.m_lineAppearance.m_state = (OpalLineAppearanceStates)info.m_state;
791   message->m_param.m_lineAppearance.m_appearance = info.m_local.m_appearance;
792 
793   if (info.m_initiator) {
794     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_callId, info.m_callId+";to-tag="+info.m_remote.m_dialogTag+";from-tag="+info.m_local.m_dialogTag);
795     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_partyA, GetParticipantName(info.m_local));
796     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_partyB, GetParticipantName(info.m_remote));
797   }
798   else {
799     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_callId, info.m_callId+";to-tag="+info.m_local.m_dialogTag+";from-tag="+info.m_remote.m_dialogTag);
800     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_partyA, GetParticipantName(info.m_remote));
801     SET_MESSAGE_STRING(message, m_param.m_lineAppearance.m_partyB, GetParticipantName(info.m_local));
802   }
803 
804   PTRACE(4, "OpalC API\tOnDialogInfoReceived: entity=\"" << message->m_param.m_lineAppearance.m_line
805                                           << "\" callId=" << message->m_param.m_lineAppearance.m_callId);
806   m_manager.PostMessage(message);
807 }
808 
809 
810 #endif
811 
812 ///////////////////////////////////////
813 
Initialise(const PCaselessString & options)814 bool OpalManager_C::Initialise(const PCaselessString & options)
815 {
816   PString defProto, defUser;
817   PINDEX  defProtoPos = P_MAX_INDEX, defUserPos = P_MAX_INDEX;
818 
819 #if OPAL_H323
820   PINDEX h323Pos = options.Find("h323");
821   if (h323Pos < defProtoPos) {
822     defProto = "h323";
823     defProtoPos = h323Pos;
824   }
825 #endif
826 
827 #if OPAL_SIP
828   PINDEX sipPos = options.Find("sip");
829   if (sipPos < defProtoPos) {
830     defProto = "sip";
831     defProtoPos = sipPos;
832   }
833 #endif
834 
835 #if OPAL_IAX2
836   PINDEX iaxPos = options.Find("iax2");
837   if (iaxPos < defProtoPos) {
838     defProto = "iax2:<da>";
839     defProtoPos = iaxPos;
840   }
841 #endif
842 
843 #if OPAL_LID
844   PINDEX potsPos = options.Find("pots");
845   if (potsPos < defUserPos) {
846     defUser = "pots:<dn>";
847     defUserPos = potsPos;
848   }
849 
850   PINDEX pstnPos = options.Find("pstn");
851   if (pstnPos < defProtoPos) {
852     defProto = "pstn:<dn>";
853     defProtoPos = pstnPos;
854   }
855 #endif
856 
857 #if OPAL_FAX
858   PINDEX faxPos = options.Find("fax");
859   if (faxPos < defUserPos) {
860     defUser = "fax:";
861     defUserPos = faxPos;
862   }
863 
864   PINDEX t38Pos = options.Find("t38");
865   if (t38Pos < defUserPos) {
866     defUser = "t38:";
867     defUserPos = t38Pos;
868   }
869 #endif
870 
871   PINDEX pcPos = options.Find("pc");
872   if (pcPos < defUserPos) {
873     defUser = "pc:*";
874     defUserPos = pcPos;
875   }
876 
877   PINDEX localPos = options.Find("local");
878   if (localPos < defUserPos) {
879     defUser = "local:<du>";
880     defUserPos = localPos;
881   }
882 
883 
884 #if OPAL_IVR
885   PINDEX ivrPos = options.Find("ivr");
886   if (ivrPos < defUserPos) {
887     defUser = "ivr:";
888     defUserPos = localPos;
889   }
890 #endif
891 
892 #if OPAL_H323
893   if (h323Pos != P_MAX_INDEX) {
894     new H323EndPoint(*this);
895     AddRouteEntry("h323:.*=" + defUser);
896   }
897 #endif
898 
899 #if OPAL_SIP
900   if (sipPos != P_MAX_INDEX) {
901     new SIPEndPoint_C(*this);
902     AddRouteEntry("sip:.*=" + defUser);
903   }
904 #endif
905 
906 #if OPAL_IAX2
907   if (options.Find("iax2") != P_MAX_INDEX) {
908     new IAX2EndPoint(*this);
909     AddRouteEntry("iax2:.*=" + defUser);
910   }
911 #endif
912 
913 #if OPAL_LID
914   if (potsPos != P_MAX_INDEX || pstnPos != P_MAX_INDEX) {
915     new OpalLineEndPoint(*this);
916 
917     if (potsPos != P_MAX_INDEX)
918       AddRouteEntry("pots:.*=" + defProto + ":<da>");
919     if (pstnPos != P_MAX_INDEX)
920       AddRouteEntry("pstn:.*=" + defUser + ":<da>");
921   }
922 #endif
923 
924 #if OPAL_FAX
925   if (faxPos != P_MAX_INDEX || t38Pos != P_MAX_INDEX) {
926     new OpalFaxEndPoint(*this);
927 
928     if (faxPos != P_MAX_INDEX)
929       AddRouteEntry("fax:.*=" + defProto + ":<da>");
930     if (t38Pos != P_MAX_INDEX)
931       AddRouteEntry("t38:.*=" + defUser + ":<da>");
932   }
933 #endif
934 
935 #if OPAL_HAS_PCSS
936   if (pcPos != P_MAX_INDEX) {
937     m_pcssEP = new OpalPCSSEndPoint_C(*this);
938     AddRouteEntry("pc:.*=" + defProto + ":<da>");
939   }
940 #endif
941 
942   if (localPos != P_MAX_INDEX) {
943     m_localEP = new OpalLocalEndPoint_C(*this);
944     AddRouteEntry("local:.*=" + defProto + ":<da>");
945   }
946 
947 #if OPAL_IVR
948   if (ivrPos != P_MAX_INDEX) {
949     m_ivrEP = new OpalIVREndPoint_C(*this);
950     AddRouteEntry("ivr:.*=" + defProto + ":<da>");
951   }
952 #endif
953 
954   return true;
955 }
956 
957 
PostMessage(OpalMessageBuffer & message)958 void OpalManager_C::PostMessage(OpalMessageBuffer & message)
959 {
960   m_messageMutex.Wait();
961   if (m_messageAvailableCallback == NULL || m_messageAvailableCallback(message)) {
962     m_messageQueue.push(message.Detach());
963     m_messagesAvailable.Signal();
964   }
965   m_messageMutex.Signal();
966 }
967 
968 
GetMessage(unsigned timeout)969 OpalMessage * OpalManager_C::GetMessage(unsigned timeout)
970 {
971   OpalMessage * msg = NULL;
972 
973   if (m_messagesAvailable.Wait(timeout)) {
974     m_messageMutex.Wait();
975 
976     if (!m_messageQueue.empty()) {
977       msg = m_messageQueue.front();
978       m_messageQueue.pop();
979     }
980 
981     m_messageMutex.Signal();
982   }
983 
984   PTRACE_IF(4, msg != NULL, "OpalC API\tGiving message " << msg->m_type << " to application");
985   return msg;
986 }
987 
988 
SendMessage(const OpalMessage * message)989 OpalMessage * OpalManager_C::SendMessage(const OpalMessage * message)
990 {
991   if (message == NULL)
992     return NULL;
993 
994   PTRACE(4, "OpalC API\tHandling message " << message->m_type << " from application");
995 
996   OpalMessageBuffer response(message->m_type);
997 
998   switch (message->m_type) {
999     case OpalCmdSetGeneralParameters :
1000       HandleSetGeneral(*message, response);
1001       break;
1002     case OpalCmdSetProtocolParameters :
1003       HandleSetProtocol(*message, response);
1004       break;
1005     case OpalCmdRegistration :
1006       HandleRegistration(*message, response);
1007       break;
1008     case OpalCmdSetUpCall :
1009       HandleSetUpCall(*message, response);
1010       break;
1011     case OpalCmdAlerting :
1012       HandleAlerting(*message, response);
1013       break;
1014     case OpalCmdAnswerCall :
1015       HandleAnswerCall(*message, response);
1016       break;
1017     case OpalCmdUserInput :
1018       HandleUserInput(*message, response);
1019       break;
1020     case OpalCmdClearCall :
1021       HandleClearCall(*message, response);
1022       break;
1023     case OpalCmdHoldCall :
1024       HandleHoldCall(*message, response);
1025       break;
1026     case OpalCmdRetrieveCall :
1027       HandleRetrieveCall(*message, response);
1028       break;
1029     case OpalCmdTransferCall :
1030       HandleTransferCall(*message, response);
1031       break;
1032     case OpalCmdMediaStream :
1033       HandleMediaStream(*message, response);
1034       break;
1035     case OpalCmdSetUserData :
1036       HandleSetUserData(*message, response);
1037       break;
1038     case OpalCmdStartRecording :
1039       HandleStartRecording(*message, response);
1040       break;
1041     case OpalCmdStopRecording :
1042       HandleStopRecording(*message, response);
1043       break;
1044     default :
1045       return NULL;
1046   }
1047 
1048   return response.Detach();
1049 }
1050 
1051 
HandleSetGeneral(const OpalMessage & command,OpalMessageBuffer & response)1052 void OpalManager_C::HandleSetGeneral(const OpalMessage & command, OpalMessageBuffer & response)
1053 {
1054 #if OPAL_HAS_PCSS
1055   if (m_pcssEP != NULL) {
1056     SET_MESSAGE_STRING(response, m_param.m_general.m_audioRecordDevice, m_pcssEP->GetSoundChannelRecordDevice());
1057     if (!IsNullString(command.m_param.m_general.m_audioRecordDevice))
1058       m_pcssEP->SetSoundChannelRecordDevice(command.m_param.m_general.m_audioRecordDevice);
1059 
1060     SET_MESSAGE_STRING(response, m_param.m_general.m_audioPlayerDevice, m_pcssEP->GetSoundChannelPlayDevice());
1061     if (!IsNullString(command.m_param.m_general.m_audioPlayerDevice))
1062       m_pcssEP->SetSoundChannelPlayDevice(command.m_param.m_general.m_audioPlayerDevice);
1063   }
1064 #endif // OPAL_HAS_PCSS
1065 
1066 #if OPAL_VIDEO
1067   PVideoDevice::OpenArgs video = GetVideoInputDevice();
1068   SET_MESSAGE_STRING(response, m_param.m_general.m_videoInputDevice, video.deviceName);
1069   if (!IsNullString(command.m_param.m_general.m_videoInputDevice)) {
1070     video.deviceName = command.m_param.m_general.m_videoInputDevice;
1071     SetVideoInputDevice(video);
1072   }
1073 
1074   video = GetVideoOutputDevice();
1075   SET_MESSAGE_STRING(response, m_param.m_general.m_videoOutputDevice, video.deviceName);
1076   if (!IsNullString(command.m_param.m_general.m_videoOutputDevice)) {
1077     video.deviceName = command.m_param.m_general.m_videoOutputDevice;
1078     SetVideoOutputDevice(video);
1079   }
1080 
1081   video = GetVideoPreviewDevice();
1082   SET_MESSAGE_STRING(response, m_param.m_general.m_videoPreviewDevice, video.deviceName);
1083   if (!IsNullString(command.m_param.m_general.m_videoPreviewDevice)) {
1084     video.deviceName = command.m_param.m_general.m_videoPreviewDevice;
1085     SetVideoPreviewDevice(video);
1086   }
1087 #endif // OPAL_VIDEO
1088 
1089   PStringStream strm;
1090   strm << setfill('\n') << GetMediaFormatOrder();
1091   SET_MESSAGE_STRING(response, m_param.m_general.m_mediaOrder, strm);
1092   if (!IsNullString(command.m_param.m_general.m_mediaOrder))
1093     SetMediaFormatOrder(PString(command.m_param.m_general.m_mediaOrder).Lines());
1094 
1095   strm.flush();
1096   strm << setfill('\n') << GetMediaFormatMask();
1097   SET_MESSAGE_STRING(response, m_param.m_general.m_mediaMask, strm);
1098   if (!IsNullString(command.m_param.m_general.m_mediaMask))
1099     SetMediaFormatMask(PString(command.m_param.m_general.m_mediaMask).Lines());
1100 
1101   OpalMediaTypeFactory::KeyList_T allMediaTypes = OpalMediaType::GetList();
1102 
1103   for (OpalMediaType::AutoStartMode autoStart = OpalMediaType::Receive; autoStart < OpalMediaType::ReceiveTransmit; ++autoStart) {
1104     strm.MakeEmpty();
1105 
1106     OpalMediaTypeFactory::KeyList_T::iterator iterMediaType;
1107     for (iterMediaType = allMediaTypes.begin(); iterMediaType != allMediaTypes.end(); ++iterMediaType) {
1108       OpalMediaTypeDefinition * definition = OpalMediaType::GetDefinition(*iterMediaType);
1109       if ((definition->GetAutoStart()&autoStart) != 0) {
1110         if (!strm.IsEmpty())
1111           strm << ' ';
1112         strm << *iterMediaType;
1113         definition->SetAutoStart(autoStart, false);
1114       }
1115     }
1116 
1117     PString autoXxMedia;
1118     if (autoStart == OpalMediaType::Receive) {
1119       SET_MESSAGE_STRING(response, m_param.m_general.m_autoRxMedia, strm);
1120       if (command.m_param.m_general.m_autoRxMedia != NULL)
1121         autoXxMedia = command.m_param.m_general.m_autoRxMedia;
1122       else
1123         autoXxMedia = strm;
1124     }
1125     else {
1126       SET_MESSAGE_STRING(response, m_param.m_general.m_autoTxMedia, strm);
1127       if (command.m_param.m_general.m_autoTxMedia != NULL)
1128         autoXxMedia = command.m_param.m_general.m_autoTxMedia;
1129       else
1130         autoXxMedia = strm;
1131     }
1132 
1133     PStringArray enabledMediaTypes = autoXxMedia.Tokenise(" \t\n", false);
1134     for (PINDEX i = 0; i < enabledMediaTypes.GetSize(); ++i) {
1135       OpalMediaTypeDefinition * definition = OpalMediaType::GetDefinition(enabledMediaTypes[0]);
1136       if (definition != NULL)
1137         definition->SetAutoStart(autoStart, true);
1138     }
1139   }
1140 
1141   SET_MESSAGE_STRING(response, m_param.m_general.m_natRouter, GetTranslationHost());
1142   if (!IsNullString(command.m_param.m_general.m_natRouter)) {
1143     if (!SetTranslationHost(command.m_param.m_general.m_natRouter)) {
1144       response.SetError("Could not set NAT router address.");
1145       return;
1146     }
1147   }
1148 
1149   SET_MESSAGE_STRING(response, m_param.m_general.m_stunServer, GetSTUNServer());
1150   if (!IsNullString(command.m_param.m_general.m_stunServer)) {
1151     if (!SetSTUNServer(command.m_param.m_general.m_stunServer)) {
1152       response.SetError("Could not set STUN server address.");
1153       return;
1154     }
1155     if (GetSTUNClient()->GetNatType() == PSTUNClient::BlockedNat)
1156       response.SetError("STUN indicates Blocked NAT.");
1157   }
1158 
1159   response->m_param.m_general.m_tcpPortBase = GetTCPPortBase();
1160   response->m_param.m_general.m_tcpPortMax = GetTCPPortMax();
1161   if (command.m_param.m_general.m_tcpPortBase != 0)
1162     SetTCPPorts(command.m_param.m_general.m_tcpPortBase, command.m_param.m_general.m_tcpPortMax);
1163 
1164   response->m_param.m_general.m_udpPortBase = GetUDPPortBase();
1165   response->m_param.m_general.m_udpPortMax = GetUDPPortMax();
1166   if (command.m_param.m_general.m_udpPortBase != 0)
1167     SetUDPPorts(command.m_param.m_general.m_udpPortBase, command.m_param.m_general.m_udpPortMax);
1168 
1169   response->m_param.m_general.m_rtpPortBase = GetRtpIpPortBase();
1170   response->m_param.m_general.m_rtpPortMax = GetRtpIpPortMax();
1171   if (command.m_param.m_general.m_rtpPortBase != 0)
1172     SetRtpIpPorts(command.m_param.m_general.m_rtpPortBase, command.m_param.m_general.m_rtpPortMax);
1173 
1174   response->m_param.m_general.m_rtpTypeOfService = GetMediaTypeOfService();
1175   if (command.m_param.m_general.m_rtpTypeOfService != 0)
1176     SetMediaTypeOfService(command.m_param.m_general.m_rtpTypeOfService);
1177 
1178   response->m_param.m_general.m_rtpMaxPayloadSize = GetMaxRtpPayloadSize();
1179   if (command.m_param.m_general.m_rtpMaxPayloadSize != 0)
1180     SetMaxRtpPayloadSize(command.m_param.m_general.m_rtpMaxPayloadSize);
1181 
1182   response->m_param.m_general.m_minAudioJitter = GetMinAudioJitterDelay();
1183   response->m_param.m_general.m_maxAudioJitter = GetMaxAudioJitterDelay();
1184   if (command.m_param.m_general.m_minAudioJitter != 0 && command.m_param.m_general.m_maxAudioJitter != 0)
1185     SetAudioJitterDelay(command.m_param.m_general.m_minAudioJitter, command.m_param.m_general.m_maxAudioJitter);
1186 
1187   if (m_apiVersion < 2)
1188     return;
1189 
1190   OpalSilenceDetector::Params silenceDetectParams = GetSilenceDetectParams();
1191   response->m_param.m_general.m_silenceDetectMode = (OpalSilenceDetectMode)(silenceDetectParams.m_mode+1);
1192   if (command.m_param.m_general.m_silenceDetectMode != 0)
1193     silenceDetectParams.m_mode = (OpalSilenceDetector::Mode)(command.m_param.m_general.m_silenceDetectMode-1);
1194   response->m_param.m_general.m_silenceThreshold = silenceDetectParams.m_threshold;
1195   if (command.m_param.m_general.m_silenceThreshold != 0)
1196     silenceDetectParams.m_threshold = command.m_param.m_general.m_silenceThreshold;
1197   response->m_param.m_general.m_signalDeadband = silenceDetectParams.m_signalDeadband;
1198   if (command.m_param.m_general.m_signalDeadband != 0)
1199     silenceDetectParams.m_signalDeadband = command.m_param.m_general.m_signalDeadband;
1200   response->m_param.m_general.m_silenceDeadband = silenceDetectParams.m_silenceDeadband;
1201   if (command.m_param.m_general.m_silenceDeadband != 0)
1202     silenceDetectParams.m_silenceDeadband = command.m_param.m_general.m_silenceDeadband;
1203   response->m_param.m_general.m_silenceAdaptPeriod = silenceDetectParams.m_adaptivePeriod;
1204   if (command.m_param.m_general.m_silenceAdaptPeriod != 0)
1205     silenceDetectParams.m_adaptivePeriod = command.m_param.m_general.m_silenceAdaptPeriod;
1206   SetSilenceDetectParams(silenceDetectParams);
1207 
1208 #if OPAL_AEC
1209   OpalEchoCanceler::Params echoCancelParams = GetEchoCancelParams();
1210   response->m_param.m_general.m_echoCancellation = (OpalEchoCancelMode)(echoCancelParams.m_mode+1);
1211   if (command.m_param.m_general.m_echoCancellation != 0)
1212     echoCancelParams.m_mode = (OpalEchoCanceler::Mode)(command.m_param.m_general.m_echoCancellation-1);
1213   SetEchoCancelParams(echoCancelParams);
1214 #endif
1215 
1216   if (m_apiVersion < 3)
1217     return;
1218 
1219 #if OPAL_HAS_PCSS
1220   if (m_pcssEP != NULL) {
1221     response->m_param.m_general.m_audioBuffers = m_pcssEP->GetSoundChannelBufferDepth();
1222     if (command.m_param.m_general.m_audioBuffers != 0)
1223       m_pcssEP->SetSoundChannelBufferDepth(command.m_param.m_general.m_audioBuffers);
1224   }
1225 #endif
1226 
1227   if (m_apiVersion < 5)
1228     return;
1229 
1230   if (m_localEP != NULL) {
1231     response->m_param.m_general.m_mediaReadData = m_localEP->m_mediaReadData;
1232     if (command.m_param.m_general.m_mediaReadData != NULL)
1233       m_localEP->m_mediaReadData = command.m_param.m_general.m_mediaReadData;
1234 
1235     response->m_param.m_general.m_mediaWriteData = m_localEP->m_mediaWriteData;
1236     if (command.m_param.m_general.m_mediaWriteData != NULL)
1237       m_localEP->m_mediaWriteData = command.m_param.m_general.m_mediaWriteData;
1238 
1239     response->m_param.m_general.m_mediaDataHeader = m_localEP->m_mediaDataHeader;
1240     if (command.m_param.m_general.m_mediaDataHeader != 0)
1241       m_localEP->m_mediaDataHeader = command.m_param.m_general.m_mediaDataHeader;
1242 
1243     if (m_apiVersion >= 20) {
1244       response->m_param.m_general.m_mediaTiming = (OpalMediaTiming)(m_localEP->GetDefaultAudioSynchronicity()+1);
1245       if (command.m_param.m_general.m_mediaTiming != 0)
1246         m_localEP->SetDefaultAudioSynchronicity((OpalLocalEndPoint::Synchronicity)(command.m_param.m_general.m_mediaTiming-1));
1247       if (m_apiVersion >= 27) {
1248         response->m_param.m_general.m_videoSourceTiming = (OpalMediaTiming)(m_localEP->GetDefaultVideoSourceSynchronicity()+1);
1249         if (command.m_param.m_general.m_mediaTiming != 0)
1250           m_localEP->SetDefaultVideoSourceSynchronicity((OpalLocalEndPoint::Synchronicity)(command.m_param.m_general.m_videoSourceTiming-1));
1251       }
1252     }
1253   }
1254 
1255   if (m_apiVersion < 8)
1256     return;
1257 
1258   m_messageMutex.Wait();
1259   response->m_param.m_general.m_messageAvailable = m_messageAvailableCallback;
1260   m_messageAvailableCallback = command.m_param.m_general.m_messageAvailable;
1261   m_messageMutex.Signal();
1262 
1263   if (m_apiVersion < 14)
1264     return;
1265 
1266   OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats();
1267 
1268   PStringStream mediaOptions;
1269   for (OpalMediaFormatList::iterator itMediaFormat = allCodecs.begin(); itMediaFormat != allCodecs.end(); ++itMediaFormat) {
1270     if (itMediaFormat->IsTransportable()) {
1271       mediaOptions << *itMediaFormat << ":Media Type#" << itMediaFormat->GetMediaType() << '\n';
1272       for (PINDEX i = 0; i < itMediaFormat->GetOptionCount(); ++i) {
1273         const OpalMediaOption & option = itMediaFormat->GetOption(i);
1274         mediaOptions << *itMediaFormat << ':' << option.GetName() << (option.IsReadOnly() ? '#' : '=') << option << '\n';
1275       }
1276     }
1277   }
1278   SET_MESSAGE_STRING(response, m_param.m_general.m_mediaOptions, mediaOptions);
1279 
1280   PStringArray options = PString(command.m_param.m_general.m_mediaOptions).Lines();
1281   for (PINDEX i = 0; i < options.GetSize(); ++i) {
1282     PString optionSpec = options[i];
1283     PINDEX colon = optionSpec.Find(':');
1284     PINDEX equal = optionSpec.Find('=', colon);
1285     PString mediaName = optionSpec.Left(colon);
1286     PString optionName = optionSpec(colon+1, equal-1);
1287     PString optionValue = optionSpec.Mid(equal+1);
1288 
1289     if (mediaName.IsEmpty() || optionName.IsEmpty()) {
1290       PTRACE(2, "OpalC API\tInvalid syntax for media format option: \"" << optionSpec << '"');
1291     }
1292     else {
1293       OpalMediaType mediaType = mediaName.ToLower();
1294       if (OpalMediaTypeFactory::CreateInstance(mediaType) != NULL) {
1295         // Known media type name, change all codecs of that type
1296         for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) {
1297           if (it->GetMediaType() == mediaType) {
1298             if (it->SetOptionValue(optionName, optionValue)) {
1299               OpalMediaFormat::SetRegisteredMediaFormat(*it);
1300               PTRACE(4, "OpalC API\tSet " << mediaType << " media format \"" << *it
1301                      << "\" option \"" << optionName << "\" to \"" << optionValue << '"');
1302             }
1303             else {
1304               PTRACE(2, "OpalC API\tCould not set " << mediaType
1305                      << " media format option \"" << optionName << "\" to \"" << optionValue << '"');
1306             }
1307           }
1308         }
1309       }
1310       else {
1311         OpalMediaFormat mediaFormat = mediaName;
1312         if (mediaFormat.IsValid()) {
1313           if (mediaFormat.SetOptionValue(optionName, optionValue)) {
1314             OpalMediaFormat::SetRegisteredMediaFormat(mediaFormat);
1315             PTRACE(2, "OpalC API\tSet media format \"" << mediaFormat
1316                    << "\" option \"" << optionName << "\" to \"" << optionValue << '"');
1317           }
1318           else {
1319             PTRACE(2, "OpalC API\tCould not set media format \"" << mediaFormat
1320                    << "\" option \"" << optionName << "\" to \"" << optionValue << '"');
1321           }
1322         }
1323         else {
1324           PTRACE(2, "OpalC API\tTried to set option for unknown media format: \"" << mediaName << '"');
1325         }
1326       }
1327     }
1328   }
1329 
1330   if (m_apiVersion < 17)
1331     return;
1332 
1333 #if OPAL_HAS_PCSS
1334   if (m_pcssEP != NULL) {
1335     response->m_param.m_general.m_audioBufferTime = m_pcssEP->GetSoundChannelBufferTime();
1336     if (command.m_param.m_general.m_audioBufferTime != 0)
1337       m_pcssEP->SetSoundChannelBufferTime(command.m_param.m_general.m_audioBufferTime);
1338   }
1339 #endif
1340 
1341   if (m_apiVersion < 19)
1342     return;
1343 
1344   response->m_param.m_general.m_manualAlerting = m_manualAlerting ? 2 : 1;
1345   if (command.m_param.m_general.m_manualAlerting != 0) {
1346     m_manualAlerting = command.m_param.m_general.m_manualAlerting != 1;
1347     if (m_localEP)
1348       m_localEP->SetDeferredAlerting(m_manualAlerting);
1349 #if OPAL_HAS_PCSS
1350     if (m_pcssEP != NULL)
1351       m_pcssEP->SetDeferredAlerting(m_manualAlerting);
1352 #endif
1353 #if OPAL_IVR
1354     if (m_ivrEP != NULL)
1355       m_ivrEP->SetDeferredAlerting(m_manualAlerting);
1356 #endif
1357   }
1358 }
1359 
1360 
FillOpalProductInfo(const OpalMessage & command,OpalMessageBuffer & response,OpalProductInfo & info)1361 void FillOpalProductInfo(const OpalMessage & command, OpalMessageBuffer & response, OpalProductInfo & info)
1362 {
1363   SET_MESSAGE_STRING(response, m_param.m_protocol.m_product.m_vendor,  info.vendor);
1364   SET_MESSAGE_STRING(response, m_param.m_protocol.m_product.m_name,    BuildProductName(info));
1365   SET_MESSAGE_STRING(response, m_param.m_protocol.m_product.m_version, info.version);
1366 
1367   response->m_param.m_protocol.m_product.m_t35CountryCode   = info.t35CountryCode;
1368   response->m_param.m_protocol.m_product.m_t35Extension     = info.t35Extension;
1369   response->m_param.m_protocol.m_product.m_manufacturerCode = info.manufacturerCode;
1370 
1371   if (command.m_param.m_protocol.m_product.m_vendor != NULL)
1372     info.vendor = command.m_param.m_protocol.m_product.m_vendor;
1373 
1374   if (command.m_param.m_protocol.m_product.m_name != NULL) {
1375     PString str = command.m_param.m_protocol.m_product.m_name;
1376     PINDEX paren = str.Find('(');
1377     if (paren == P_MAX_INDEX)
1378       info.name = str;
1379     else {
1380       info.name = str.Left(paren).Trim();
1381       info.comments = str.Mid(paren);
1382     }
1383   }
1384 
1385   if (command.m_param.m_protocol.m_product.m_version != NULL)
1386     info.version = command.m_param.m_protocol.m_product.m_version;
1387 
1388   if (command.m_param.m_protocol.m_product.m_t35CountryCode != 0 && command.m_param.m_protocol.m_product.m_manufacturerCode != 0) {
1389     info.t35CountryCode   = (BYTE)command.m_param.m_protocol.m_product.m_t35CountryCode;
1390     info.t35Extension     = (BYTE)command.m_param.m_protocol.m_product.m_t35Extension;
1391     info.manufacturerCode = (WORD)command.m_param.m_protocol.m_product.m_manufacturerCode;
1392   }
1393 }
1394 
1395 
StartStopListeners(OpalEndPoint * ep,const PString & interfaces,OpalMessageBuffer & response)1396 static void StartStopListeners(OpalEndPoint * ep, const PString & interfaces, OpalMessageBuffer & response)
1397 {
1398   if (ep == NULL)
1399     return;
1400 
1401   ep->RemoveListener(NULL);
1402   if (interfaces.IsEmpty())
1403     return;
1404 
1405   PStringArray interfaceArray;
1406   if (interfaces != "*")
1407     interfaceArray = interfaces.Lines();
1408   if (!ep->StartListeners(interfaceArray))
1409     response.SetError("Could not start listener(s).");
1410 }
1411 
1412 
HandleSetProtocol(const OpalMessage & command,OpalMessageBuffer & response)1413 void OpalManager_C::HandleSetProtocol(const OpalMessage & command, OpalMessageBuffer & response)
1414 {
1415   if (IsNullString(command.m_param.m_protocol.m_prefix)) {
1416     SET_MESSAGE_STRING(response, m_param.m_protocol.m_userName, GetDefaultUserName());
1417     if (command.m_param.m_protocol.m_userName != NULL)
1418       SetDefaultUserName(command.m_param.m_protocol.m_userName);
1419 
1420     SET_MESSAGE_STRING(response, m_param.m_protocol.m_displayName, GetDefaultUserName());
1421     if (!IsNullString(command.m_param.m_protocol.m_displayName))
1422       SetDefaultDisplayName(command.m_param.m_protocol.m_displayName);
1423 
1424     OpalProductInfo product = GetProductInfo();
1425     FillOpalProductInfo(command, response, product);
1426     SetProductInfo(product);
1427 
1428     if (command.m_param.m_protocol.m_interfaceAddresses != NULL) {
1429 #if OPAL_H323
1430       StartStopListeners(FindEndPoint(OPAL_PREFIX_H323), command.m_param.m_protocol.m_interfaceAddresses, response);
1431 #endif
1432 #if OPAL_SIP
1433       StartStopListeners(FindEndPoint(OPAL_PREFIX_SIP),  command.m_param.m_protocol.m_interfaceAddresses, response);
1434 #endif
1435 #if OPAL_IAX2
1436       StartStopListeners(FindEndPoint(OPAL_PREFIX_IAX2),  command.m_param.m_protocol.m_interfaceAddresses, response);
1437 #endif
1438     }
1439 
1440     return;
1441   }
1442 
1443   OpalEndPoint * ep = FindEndPoint(command.m_param.m_protocol.m_prefix);
1444   if (ep == NULL) {
1445     response.SetError("No such protocol prefix");
1446     return;
1447   }
1448 
1449   SET_MESSAGE_STRING(response, m_param.m_protocol.m_userName, ep->GetDefaultLocalPartyName());
1450   if (command.m_param.m_protocol.m_userName != NULL)
1451     ep->SetDefaultLocalPartyName(command.m_param.m_protocol.m_userName);
1452 
1453   SET_MESSAGE_STRING(response, m_param.m_protocol.m_displayName, ep->GetDefaultDisplayName());
1454   if (!IsNullString(command.m_param.m_protocol.m_displayName))
1455     ep->SetDefaultDisplayName(command.m_param.m_protocol.m_displayName);
1456 
1457   OpalProductInfo product = ep->GetProductInfo();
1458   FillOpalProductInfo(command, response, product);
1459   ep->SetProductInfo(product);
1460 
1461 #if OPAL_IVR
1462   OpalIVREndPoint * ivr = dynamic_cast<OpalIVREndPoint *>(ep);
1463   if (ivr != NULL)
1464     ivr->SetDefaultVXML(command.m_param.m_protocol.m_interfaceAddresses);
1465   else
1466 #endif
1467   if (command.m_param.m_protocol.m_interfaceAddresses != NULL)
1468     StartStopListeners(ep, command.m_param.m_protocol.m_interfaceAddresses, response);
1469 
1470   if (m_apiVersion < 22)
1471     return;
1472 
1473   unsigned mode = ep->GetSendUserInputMode();
1474   if (mode != OpalConnection::SendUserInputAsProtocolDefault)
1475     ++mode;
1476   else
1477     mode = OpalUserInputDefault;
1478   response->m_param.m_protocol.m_userInputMode = (OpalUserInputModes)mode;
1479 
1480   mode = command.m_param.m_protocol.m_userInputMode;
1481   if (mode != OpalUserInputDefault && mode <= OpalConnection::NumSendUserInputModes)
1482     --mode;
1483   else
1484     mode = OpalConnection::SendUserInputAsProtocolDefault;
1485   ep->SetSendUserInputMode((OpalConnection::SendUserInputModes)mode);
1486 
1487   if (m_apiVersion < 23)
1488     return;
1489 
1490   PStringStream strm;
1491   strm << ep->GetDefaultStringOptions();
1492   SET_MESSAGE_STRING(response, m_param.m_protocol.m_defaultOptions, strm);
1493   if (!IsNullString(command.m_param.m_protocol.m_defaultOptions)) {
1494     OpalConnection::StringOptions newOptions;
1495     strm = command.m_param.m_protocol.m_defaultOptions;
1496     strm >> newOptions;
1497     ep->SetDefaultStringOptions(newOptions);
1498   }
1499 }
1500 
1501 
HandleRegistration(const OpalMessage & command,OpalMessageBuffer & response)1502 void OpalManager_C::HandleRegistration(const OpalMessage & command, OpalMessageBuffer & response)
1503 {
1504   OpalEndPoint * ep = FindEndPoint(command.m_param.m_registrationInfo.m_protocol);
1505   if (ep == NULL) {
1506     response.SetError("No such protocol prefix");
1507     return;
1508   }
1509 
1510 #if OPAL_H323
1511   H323EndPoint * h323 = dynamic_cast<H323EndPoint *>(ep);
1512   if (h323 != NULL) {
1513     if (command.m_param.m_registrationInfo.m_timeToLive == 0) {
1514       if (!h323->RemoveGatekeeper())
1515         response.SetError("Failed to initiate H.323 gatekeeper unregistration.");
1516     }
1517     else {
1518       if (!IsNullString(command.m_param.m_registrationInfo.m_identifier))
1519         h323->AddAliasName(command.m_param.m_registrationInfo.m_identifier);
1520       h323->SetGatekeeperPassword(command.m_param.m_registrationInfo.m_password, command.m_param.m_registrationInfo.m_authUserName);
1521       if (!h323->UseGatekeeper(command.m_param.m_registrationInfo.m_hostName, command.m_param.m_registrationInfo.m_adminEntity))
1522         response.SetError("Failed to initiate H.323 gatekeeper registration.");
1523     }
1524     return;
1525   }
1526 #endif
1527 
1528 #if OPAL_SIP
1529   SIPEndPoint * sip = dynamic_cast<SIPEndPoint *>(ep);
1530   if (sip != NULL) {
1531     if (IsNullString(command.m_param.m_registrationInfo.m_hostName) &&
1532           (IsNullString(command.m_param.m_registrationInfo.m_identifier) ||
1533                  strchr(command.m_param.m_registrationInfo.m_identifier, '@') == NULL)) {
1534       response.SetError("No domain specified for SIP registration.");
1535       return;
1536     }
1537 
1538     if (command.m_param.m_registrationInfo.m_timeToLive == 0) {
1539       if (!sip->Unregister(command.m_param.m_registrationInfo.m_identifier))
1540         response.SetError("Failed to initiate SIP unregistration.");
1541     }
1542     else {
1543       PString aor;
1544 
1545       if (m_apiVersion < 13 || command.m_param.m_registrationInfo.m_eventPackage == NULL) {
1546         SIPRegister::Params regParams;
1547         regParams.m_addressOfRecord = command.m_param.m_registrationInfo.m_identifier;
1548         regParams.m_registrarAddress = command.m_param.m_registrationInfo.m_hostName;
1549         regParams.m_authID = command.m_param.m_registrationInfo.m_authUserName;
1550         regParams.m_password = command.m_param.m_registrationInfo.m_password;
1551         regParams.m_realm = command.m_param.m_registrationInfo.m_adminEntity;
1552         regParams.m_expire = command.m_param.m_registrationInfo.m_timeToLive;
1553         if (m_apiVersion >= 7 && command.m_param.m_registrationInfo.m_restoreTime > 0)
1554           regParams.m_restoreTime = command.m_param.m_registrationInfo.m_restoreTime;
1555 
1556         if (sip->Register(regParams, aor))
1557           SET_MESSAGE_STRING(response, m_param.m_registrationInfo.m_identifier, aor);
1558         else
1559           response.SetError("Failed to initiate SIP registration.");
1560       }
1561 
1562       if (m_apiVersion >= 10) {
1563         SIPSubscribe::Params subParams;
1564         if (m_apiVersion < 13)
1565           subParams.m_eventPackage = SIPSubscribe::MessageSummary;
1566 
1567         else {
1568           if (command.m_param.m_registrationInfo.m_eventPackage == NULL)
1569             return;
1570           subParams.m_eventPackage = command.m_param.m_registrationInfo.m_eventPackage;
1571         }
1572 
1573         subParams.m_addressOfRecord = command.m_param.m_registrationInfo.m_identifier;
1574         subParams.m_agentAddress = command.m_param.m_registrationInfo.m_hostName;
1575         subParams.m_authID = command.m_param.m_registrationInfo.m_authUserName;
1576         subParams.m_password = command.m_param.m_registrationInfo.m_password;
1577         subParams.m_realm = command.m_param.m_registrationInfo.m_adminEntity;
1578 #if P_64BIT
1579         subParams.m_expire = m_apiVersion = command.m_param.m_registrationInfo.m_timeToLive;
1580 #else
1581         subParams.m_expire = m_apiVersion >= 13 ? command.m_param.m_registrationInfo.m_timeToLive
1582                                                : *(unsigned*)&command.m_param.m_registrationInfo.m_eventPackage; // Backward compatibility
1583 #endif
1584         subParams.m_restoreTime = command.m_param.m_registrationInfo.m_restoreTime;
1585         bool ok = sip->Subscribe(subParams, aor);
1586         if (m_apiVersion >= 13) {
1587           if (ok)
1588             SET_MESSAGE_STRING(response, m_param.m_registrationInfo.m_identifier, aor);
1589           else
1590             response.SetError("Failed to initiate SIP subscription.");
1591         }
1592       }
1593     }
1594     return;
1595   }
1596 #endif
1597 
1598   response.SetError("Protocol prefix does not support registration.");
1599 }
1600 
1601 
SetOptionOverrides(bool originating,OpalConnection::StringOptions & options,const OpalParamProtocol & params)1602 static void SetOptionOverrides(bool originating,
1603                                OpalConnection::StringOptions & options,
1604                                const OpalParamProtocol & params)
1605 {
1606   if (!IsNullString(params.m_defaultOptions)) {
1607     PStringStream strm(params.m_defaultOptions);
1608     strm >> options;
1609   }
1610 
1611   if (!IsNullString(params.m_userName))
1612     options.Set(originating ? OPAL_OPT_CALLING_PARTY_NAME : OPAL_OPT_CALLED_PARTY_NAME, params.m_userName);
1613 
1614   if (!IsNullString(params.m_displayName))
1615     options.Set(originating ? OPAL_OPT_CALLING_DISPLAY_NAME : OPAL_OPT_CALLED_DISPLAY_NAME, params.m_displayName);
1616 
1617   if (params.m_userInputMode > OpalUserInputDefault && params.m_userInputMode <= OpalUserInputInBand) {
1618     static char const * const ModeNames[] = { "Q.931", "String", "Tone", "RFC2833", "InBand" };
1619     options.Set(OPAL_OPT_USER_INPUT_MODE, ModeNames[params.m_userInputMode-1]);
1620   }
1621 }
1622 
1623 
HandleSetUpCall(const OpalMessage & command,OpalMessageBuffer & response)1624 void OpalManager_C::HandleSetUpCall(const OpalMessage & command, OpalMessageBuffer & response)
1625 {
1626   if (IsNullString(command.m_param.m_callSetUp.m_partyB)) {
1627     response.SetError("No destination address provided.");
1628     return;
1629   }
1630 
1631   PString partyA = command.m_param.m_callSetUp.m_partyA;
1632   if (partyA.IsEmpty()) {
1633 #if OPAL_HAS_PCSS
1634     if (m_pcssEP != NULL)
1635       partyA = "pc:*";
1636     else
1637 #endif
1638     if (m_localEP != NULL)
1639       partyA = "local:*";
1640 #if OPAL_IVR
1641     else if (m_ivrEP != NULL)
1642       partyA = "ivr:*";
1643 #endif
1644     else
1645       partyA = "pots:*";
1646   }
1647 
1648   OpalConnection::StringOptions options;
1649   if (!IsNullString(command.m_param.m_callSetUp.m_alertingType))
1650     options.SetAt(OPAL_OPT_ALERTING_TYPE, command.m_param.m_callSetUp.m_alertingType);
1651   if (m_apiVersion >= 26)
1652     SetOptionOverrides(true, options, command.m_param.m_answerCall.m_overrides);
1653 
1654   PString token;
1655   if (SetUpCall(partyA, command.m_param.m_callSetUp.m_partyB, token, NULL, 0, &options)) {
1656     SET_MESSAGE_STRING(response, m_param.m_callSetUp.m_partyA, partyA);
1657     SET_MESSAGE_STRING(response, m_param.m_callSetUp.m_partyB, command.m_param.m_callSetUp.m_partyB);
1658     SET_MESSAGE_STRING(response, m_param.m_callSetUp.m_callToken, token);
1659     PSafePtr<OpalCall> call = FindCallWithLock(token);
1660     if (call != NULL) {
1661       PSafePtr<OpalConnection> other = call->GetConnection(1);
1662       if (other != NULL)
1663         SET_MESSAGE_STRING(response, m_param.m_callSetUp.m_protocolCallId, other->GetIdentifier());
1664     }
1665   }
1666   else
1667     response.SetError("Call set up failed.");
1668 }
1669 
1670 
HandleAlerting(const OpalMessage & command,OpalMessageBuffer & response)1671 void OpalManager_C::HandleAlerting(const OpalMessage & command, OpalMessageBuffer & response)
1672 {
1673   if (IsNullString(command.m_param.m_callToken)) {
1674     response.SetError("No call token provided.");
1675     return;
1676   }
1677 
1678   OpalConnection::StringOptions options;
1679   if (m_apiVersion >= 26)
1680     SetOptionOverrides(false, options, command.m_param.m_answerCall.m_overrides);
1681 
1682 #if OPAL_HAS_PCSS
1683   if (m_pcssEP != NULL && m_pcssEP->AlertingIncomingCall(command.m_param.m_callToken, &options))
1684     return;
1685 #endif
1686 
1687 #if OPAL_IVR
1688   if (m_ivrEP != NULL && m_ivrEP->AlertingIncomingCall(command.m_param.m_callToken, &options))
1689     return;
1690 #endif
1691 
1692   if (m_localEP != NULL && m_localEP->AlertingIncomingCall(command.m_param.m_callToken, &options))
1693     return;
1694 
1695   response.SetError("No call found by the token provided.");
1696 }
1697 
1698 
HandleAnswerCall(const OpalMessage & command,OpalMessageBuffer & response)1699 void OpalManager_C::HandleAnswerCall(const OpalMessage & command, OpalMessageBuffer & response)
1700 {
1701   if (IsNullString(command.m_param.m_callToken)) {
1702     response.SetError("No call token provided.");
1703     return;
1704   }
1705 
1706   OpalConnection::StringOptions options;
1707   if (m_apiVersion >= 26)
1708     SetOptionOverrides(false, options, command.m_param.m_answerCall.m_overrides);
1709 
1710 #if OPAL_HAS_PCSS
1711   if (m_pcssEP != NULL && m_pcssEP->AcceptIncomingCall(command.m_param.m_callToken, &options))
1712     return;
1713 #endif
1714 
1715 #if OPAL_IVR
1716   if (m_ivrEP != NULL && m_ivrEP->AcceptIncomingCall(command.m_param.m_callToken, &options))
1717     return;
1718 #endif
1719 
1720   if (m_localEP != NULL && m_localEP->AcceptIncomingCall(command.m_param.m_callToken, &options))
1721     return;
1722 
1723   response.SetError("No call found by the token provided.");
1724 }
1725 
1726 
FindCall(const char * token,OpalMessageBuffer & response,PSafePtr<OpalCall> & call)1727 bool OpalManager_C::FindCall(const char * token, OpalMessageBuffer & response, PSafePtr<OpalCall> & call)
1728 {
1729   if (IsNullString(token)) {
1730     response.SetError("No call token provided.");
1731     return false;
1732   }
1733 
1734   call = FindCallWithLock(token);
1735   if (call == NULL) {
1736     response.SetError("No call found by the token provided.");
1737     return false;
1738   }
1739 
1740   return true;
1741 }
1742 
1743 
HandleUserInput(const OpalMessage & command,OpalMessageBuffer & response)1744 void OpalManager_C::HandleUserInput(const OpalMessage & command, OpalMessageBuffer & response)
1745 {
1746   if (IsNullString(command.m_param.m_userInput.m_userInput)) {
1747     response.SetError("No user input provided.");
1748     return;
1749   }
1750 
1751   PSafePtr<OpalCall> call;
1752   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1753     return;
1754 
1755   PSafePtr<OpalConnection> connection = call->GetConnection(0, PSafeReadOnly);
1756   while (connection->IsNetworkConnection()) {
1757     ++connection;
1758     if (connection == NULL) {
1759       response.SetError("No suitable connection for user input.");
1760       return;
1761     }
1762   }
1763 
1764   if (command.m_param.m_userInput.m_duration == 0)
1765     connection->OnUserInputString(command.m_param.m_userInput.m_userInput);
1766   else
1767     connection->OnUserInputTone(command.m_param.m_userInput.m_userInput[0], command.m_param.m_userInput.m_duration);
1768 }
1769 
1770 
HandleClearCall(const OpalMessage & command,OpalMessageBuffer & response)1771 void OpalManager_C::HandleClearCall(const OpalMessage & command, OpalMessageBuffer & response)
1772 {
1773   const char * callToken;
1774   OpalConnection::CallEndReason reason;
1775 
1776   if (m_apiVersion < 9) {
1777     callToken = command.m_param.m_callToken;
1778     reason = OpalConnection::EndedByLocalUser;
1779   }
1780   else {
1781     callToken = command.m_param.m_clearCall.m_callToken;
1782     reason.code = (OpalConnection::CallEndReasonCodes)command.m_param.m_clearCall.m_reason;
1783   }
1784 
1785   if (IsNullString(callToken)) {
1786     response.SetError("No call token provided.");
1787     return;
1788   }
1789 
1790   if (!ClearCall(callToken, reason))
1791     response.SetError("No call found by the token provided.");
1792 }
1793 
1794 
HandleHoldCall(const OpalMessage & command,OpalMessageBuffer & response)1795 void OpalManager_C::HandleHoldCall(const OpalMessage & command, OpalMessageBuffer & response)
1796 {
1797   PSafePtr<OpalCall> call;
1798   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1799     return;
1800 
1801   if (call->IsOnHold()) {
1802     response.SetError("Call is already on hold.");
1803     return;
1804   }
1805 
1806   call->Hold();
1807 }
1808 
1809 
HandleRetrieveCall(const OpalMessage & command,OpalMessageBuffer & response)1810 void OpalManager_C::HandleRetrieveCall(const OpalMessage & command, OpalMessageBuffer & response)
1811 {
1812   PSafePtr<OpalCall> call;
1813   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1814     return;
1815 
1816   if (!call->IsOnHold()) {
1817     response.SetError("Call is not on hold.");
1818     return;
1819   }
1820 
1821   call->Retrieve();
1822 }
1823 
1824 
HandleTransferCall(const OpalMessage & command,OpalMessageBuffer & response)1825 void OpalManager_C::HandleTransferCall(const OpalMessage & command, OpalMessageBuffer & response)
1826 {
1827   if (IsNullString(command.m_param.m_callSetUp.m_partyB)) {
1828     response.SetError("No destination address provided.");
1829     return;
1830   }
1831 
1832   PSafePtr<OpalCall> call;
1833   if (!FindCall(command.m_param.m_callSetUp.m_callToken, response, call))
1834     return;
1835 
1836   PString search = command.m_param.m_callSetUp.m_partyA;
1837   if (search.IsEmpty()) {
1838     search = command.m_param.m_callSetUp.m_partyB;
1839     search.Delete(search.Find(':'), P_MAX_INDEX);
1840   }
1841 
1842   PSafePtr<OpalConnection> connection = call->GetConnection(0, PSafeReadOnly);
1843   while (connection->GetLocalPartyURL().NumCompare(search) != EqualTo) {
1844     if (++connection == NULL) {
1845       response.SetError("Call does not have suitable connection to transfer from " + search);
1846       return;
1847     }
1848   }
1849 
1850   if (connection->GetPhase() < OpalConnection::ConnectedPhase)
1851     connection->ForwardCall(command.m_param.m_callSetUp.m_partyB);
1852   else
1853     call->Transfer(command.m_param.m_callSetUp.m_partyB, connection);
1854 }
1855 
1856 
HandleMediaStream(const OpalMessage & command,OpalMessageBuffer & response)1857 void OpalManager_C::HandleMediaStream(const OpalMessage & command, OpalMessageBuffer & response)
1858 {
1859   PSafePtr<OpalCall> call;
1860   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1861     return;
1862 
1863   PSafePtr<OpalConnection> connection = call->GetConnection(0, PSafeReadOnly);
1864   while (connection->IsNetworkConnection()) {
1865     ++connection;
1866     if (connection == NULL) {
1867       response.SetError("No suitable connection for media stream control.");
1868       return;
1869     }
1870   }
1871 
1872   OpalMediaType mediaType;
1873   bool source = false;
1874   if (!IsNullString(command.m_param.m_mediaStream.m_type)) {
1875     PString typeStr = command.m_param.m_mediaStream.m_type;
1876     mediaType = typeStr.Left(typeStr.Find(' '));
1877     source = typeStr.Find("out") != P_MAX_INDEX;
1878   }
1879 
1880   OpalMediaStreamPtr stream;
1881   if (!IsNullString(command.m_param.m_mediaStream.m_identifier))
1882     stream = connection->GetMediaStream(PString(command.m_param.m_mediaStream.m_identifier), source);
1883   else if (!IsNullString(command.m_param.m_mediaStream.m_type))
1884     stream = connection->GetMediaStream(mediaType, source);
1885   else {
1886     response.SetError("No identifer or type provided to locate media stream.");
1887     return;
1888   }
1889 
1890   if (stream == NULL && command.m_param.m_mediaStream.m_state != OpalMediaStateOpen) {
1891     response.SetError("Could not locate media stream.");
1892     return;
1893   }
1894 
1895   switch (command.m_param.m_mediaStream.m_state) {
1896     case OpalMediaStateNoChange :
1897       break;
1898 
1899     case OpalMediaStateOpen :
1900       if (mediaType.empty())
1901         response.SetError("Must provide type and direction to open media stream.");
1902       else {
1903         OpalMediaFormat mediaFormat(command.m_param.m_mediaStream.m_format);
1904         unsigned sessionID = 0;
1905         if (stream != NULL)
1906           sessionID = stream->GetSessionID();
1907         if (source)
1908           call->OpenSourceMediaStreams(*connection, mediaType, sessionID, mediaFormat);
1909         else
1910           call->OpenSourceMediaStreams(*call->GetOtherPartyConnection(*connection), mediaType, sessionID, mediaFormat);
1911       }
1912       break;
1913 
1914     case OpalMediaStateClose :
1915       connection->CloseMediaStream(*stream);
1916       break;
1917 
1918     case OpalMediaStatePause :
1919       stream->SetPaused(true);
1920       break;
1921 
1922     case OpalMediaStateResume :
1923       stream->SetPaused(false);
1924       break;
1925   }
1926 
1927   if (m_apiVersion < 25)
1928     return;
1929 
1930   if (command.m_param.m_mediaStream.m_volume != 0) {
1931     unsigned volume;
1932     if (command.m_param.m_mediaStream.m_volume < 0)
1933       volume = 0;
1934     else if (command.m_param.m_mediaStream.m_volume > 100)
1935       volume = 100;
1936     else
1937       volume = command.m_param.m_mediaStream.m_volume;
1938     connection->SetAudioVolume(stream->IsSource(), volume);
1939   }
1940 }
1941 
1942 
HandleStartRecording(const OpalMessage & command,OpalMessageBuffer & response)1943 void OpalManager_C::HandleStartRecording(const OpalMessage & command, OpalMessageBuffer & response)
1944 {
1945   PSafePtr<OpalCall> call;
1946   if (!FindCall(command.m_param.m_recording.m_callToken, response, call))
1947     return;
1948 
1949 #if OPAL_HAS_MIXER
1950   if (IsNullString(command.m_param.m_recording.m_file)) {
1951     if (!call->IsRecording())
1952       response.SetError("No recording active for call.");
1953     return;
1954   }
1955 
1956   OpalRecordManager::Options options;
1957   options.m_stereo = command.m_param.m_recording.m_channels == 2;
1958   if (m_apiVersion >= 21) {
1959     options.m_audioFormat = command.m_param.m_recording.m_audioFormat;
1960 #if OPAL_VIDEO
1961     options.m_videoFormat = command.m_param.m_recording.m_videoFormat;
1962     options.m_videoWidth  = command.m_param.m_recording.m_videoWidth;
1963     options.m_videoHeight = command.m_param.m_recording.m_videoHeight;
1964     options.m_videoRate   = command.m_param.m_recording.m_videoRate;
1965     options.m_videoMixing = (OpalRecordManager::VideoMode)command.m_param.m_recording.m_videoMixing;
1966 #endif
1967   }
1968 
1969   if (!call->StartRecording(command.m_param.m_recording.m_file, options))
1970 #else
1971   if (!IsNullString(command.m_param.m_recording.m_file))
1972 #endif
1973     response.SetError("Could not start recording for call.");
1974 }
1975 
1976 
HandleStopRecording(const OpalMessage & command,OpalMessageBuffer & response)1977 void OpalManager_C::HandleStopRecording(const OpalMessage & command, OpalMessageBuffer & response)
1978 {
1979   PSafePtr<OpalCall> call;
1980   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1981     return;
1982 
1983 #if OPAL_HAS_MIXER
1984   call->StopRecording();
1985 #endif
1986 }
1987 
1988 
HandleSetUserData(const OpalMessage & command,OpalMessageBuffer & response)1989 void OpalManager_C::HandleSetUserData(const OpalMessage & command, OpalMessageBuffer & response)
1990 {
1991   PSafePtr<OpalCall> call;
1992   if (!FindCall(command.m_param.m_userInput.m_callToken, response, call))
1993     return;
1994 
1995   PSafePtr<OpalLocalConnection> connection = call->GetConnectionAs<OpalLocalConnection>();
1996   if (connection == NULL) {
1997     response.SetError("No suitable connection for media stream control.");
1998     return;
1999   }
2000 
2001   connection->SetUserData(command.m_param.m_setUserData.m_userData);
2002 }
2003 
2004 
OnEstablishedCall(OpalCall & call)2005 void OpalManager_C::OnEstablishedCall(OpalCall & call)
2006 {
2007   OpalMessageBuffer message(OpalIndEstablished);
2008   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyA, call.GetPartyA());
2009   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyB, call.GetPartyB());
2010   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_callToken, call.GetToken());
2011   PTRACE(4, "OpalC API\tOnEstablishedCall:"
2012             " token=\"" << message->m_param.m_callSetUp.m_callToken << "\""
2013             " A=\""     << message->m_param.m_callSetUp.m_partyA << "\""
2014             " B=\""     << message->m_param.m_callSetUp.m_partyB << '"');
2015   PostMessage(message);
2016 }
2017 
2018 
OnHold(OpalConnection & connection,bool fromRemote,bool onHold)2019 void OpalManager_C::OnHold(OpalConnection & connection, bool fromRemote, bool onHold)
2020 {
2021   if (fromRemote) {
2022     OpalMessageBuffer message(onHold ? OpalIndOnHold : OpalIndOffHold);
2023     SET_MESSAGE_STRING(message, m_param.m_callToken, connection.GetCall().GetToken());
2024     PostMessage(message);
2025   }
2026 
2027   OpalManager::OnHold(connection, fromRemote, onHold);
2028 }
2029 
2030 
OnTransferNotify(OpalConnection & connection,const PStringToString & info)2031 bool OpalManager_C::OnTransferNotify(OpalConnection & connection,
2032                                      const PStringToString & info)
2033 {
2034   OpalMessageBuffer message(OpalIndTransferCall);
2035 
2036   SET_MESSAGE_STRING(message, m_param.m_transferStatus.m_callToken, connection.GetCall().GetToken());
2037   SET_MESSAGE_STRING(message, m_param.m_transferStatus.m_result, info["result"]);
2038 
2039   PStringStream infoStr;
2040   infoStr << info;
2041   SET_MESSAGE_STRING(message, m_param.m_transferStatus.m_info, infoStr);
2042 
2043   PostMessage(message);
2044 
2045   return OpalManager::OnTransferNotify(connection, info);
2046 }
2047 
2048 
OnIndMediaStream(const OpalMediaStream & stream,OpalMediaStates state)2049 void OpalManager_C::OnIndMediaStream(const OpalMediaStream & stream, OpalMediaStates state)
2050 {
2051   const OpalConnection & connection = stream.GetConnection();
2052   if (!connection.IsNetworkConnection())
2053     return;
2054 
2055   OpalMessageBuffer message(OpalIndMediaStream);
2056   SET_MESSAGE_STRING(message, m_param.m_mediaStream.m_callToken, connection.GetCall().GetToken());
2057   SET_MESSAGE_STRING(message, m_param.m_mediaStream.m_identifier, stream.GetID());
2058   PStringStream type;
2059   type << stream.GetMediaFormat().GetMediaType() << (stream.IsSource() ? " in" : " out");
2060   SET_MESSAGE_STRING(message, m_param.m_mediaStream.m_type, type);
2061   SET_MESSAGE_STRING(message, m_param.m_mediaStream.m_format, stream.GetMediaFormat().GetName());
2062   message->m_param.m_mediaStream.m_state = state;
2063   PTRACE(4, "OpalC API\tOnIndMediaStream:"
2064             " token=\"" << message->m_param.m_userInput.m_callToken << "\""
2065             " id=\"" << message->m_param.m_mediaStream.m_identifier << '"');
2066   PostMessage(message);
2067 }
2068 
2069 
OnOpenMediaStream(OpalConnection & connection,OpalMediaStream & stream)2070 PBoolean OpalManager_C::OnOpenMediaStream(OpalConnection & connection, OpalMediaStream & stream)
2071 {
2072   if (!OpalManager::OnOpenMediaStream(connection, stream))
2073     return false;
2074 
2075   OnIndMediaStream(stream, OpalMediaStateOpen);
2076   return true;
2077 }
2078 
2079 
OnClosedMediaStream(const OpalMediaStream & stream)2080 void OpalManager_C::OnClosedMediaStream(const OpalMediaStream & stream)
2081 {
2082   OnIndMediaStream(stream, OpalMediaStateClose);
2083   OpalManager::OnClosedMediaStream(stream);
2084 }
2085 
2086 
OnUserInputString(OpalConnection & connection,const PString & value)2087 void OpalManager_C::OnUserInputString(OpalConnection & connection, const PString & value)
2088 {
2089   OpalMessageBuffer message(OpalIndUserInput);
2090   SET_MESSAGE_STRING(message, m_param.m_userInput.m_callToken, connection.GetCall().GetToken());
2091   SET_MESSAGE_STRING(message, m_param.m_userInput.m_userInput, value);
2092   message->m_param.m_userInput.m_duration = 0;
2093   PTRACE(4, "OpalC API\tOnUserInputString:"
2094             " token=\"" << message->m_param.m_userInput.m_callToken << "\""
2095             " input=\"" << message->m_param.m_userInput.m_userInput << '"');
2096   PostMessage(message);
2097 
2098   OpalManager::OnUserInputString(connection, value);
2099 }
2100 
2101 
OnUserInputTone(OpalConnection & connection,char tone,int duration)2102 void OpalManager_C::OnUserInputTone(OpalConnection & connection, char tone, int duration)
2103 {
2104   char input[2];
2105   input[0] = tone;
2106   input[1] = '\0';
2107 
2108   OpalMessageBuffer message(OpalIndUserInput);
2109   SET_MESSAGE_STRING(message, m_param.m_userInput.m_callToken, connection.GetCall().GetToken());
2110   SET_MESSAGE_STRING(message, m_param.m_userInput.m_userInput, input);
2111   message->m_param.m_userInput.m_duration = duration;
2112   PTRACE(4, "OpalC API\tOnUserInputTone:"
2113             " token=\"" << message->m_param.m_userInput.m_callToken << "\""
2114             " input=\"" << message->m_param.m_userInput.m_userInput << '"');
2115   PostMessage(message);
2116 
2117   OpalManager::OnUserInputTone(connection, tone, duration);
2118 }
2119 
2120 
OnMWIReceived(const PString & party,MessageWaitingType type,const PString & extraInfo)2121 void OpalManager_C::OnMWIReceived(const PString & party, MessageWaitingType type, const PString & extraInfo)
2122 {
2123   OpalMessageBuffer message(OpalIndMessageWaiting);
2124   SET_MESSAGE_STRING(message, m_param.m_messageWaiting.m_party, party);
2125   static const char * const TypeNames[] = { "Voice", "Fax", "Pager", "Multimedia", "Text", "None" };
2126   if ((size_t)type < sizeof(TypeNames)/sizeof(TypeNames[0]))
2127     SET_MESSAGE_STRING(message, m_param.m_messageWaiting.m_type, TypeNames[type]);
2128   SET_MESSAGE_STRING(message, m_param.m_messageWaiting.m_extraInfo, extraInfo);
2129   PTRACE(4, "OpalC API\tOnMWIReceived: party=\"" << message->m_param.m_messageWaiting.m_party
2130                                    << "\" type=" << message->m_param.m_messageWaiting.m_type
2131                                    << "\" info=" << message->m_param.m_messageWaiting.m_extraInfo);
2132   PostMessage(message);
2133 
2134   OpalManager::OnMWIReceived(party, type, extraInfo);
2135 }
2136 
2137 
OnProceeding(OpalConnection & connection)2138 void OpalManager_C::OnProceeding(OpalConnection & connection)
2139 {
2140   OpalCall & call = connection.GetCall();
2141 
2142   OpalMessageBuffer message(OpalIndProceeding);
2143   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyA, call.GetPartyA());
2144   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_partyB, call.GetPartyB());
2145   SET_MESSAGE_STRING(message, m_param.m_callSetUp.m_callToken, call.GetToken());
2146   PTRACE(4, "OpalC API\tOnProceeding:"
2147             " token=\"" << message->m_param.m_callSetUp.m_callToken << "\""
2148             " A=\""     << message->m_param.m_callSetUp.m_partyA << "\""
2149             " B=\""     << message->m_param.m_callSetUp.m_partyB << '"');
2150   PostMessage(message);
2151 
2152   OpalManager::OnProceeding(connection);
2153 }
2154 
2155 
OnClearedCall(OpalCall & call)2156 void OpalManager_C::OnClearedCall(OpalCall & call)
2157 {
2158   OpalMessageBuffer message(OpalIndCallCleared);
2159   SET_MESSAGE_STRING(message, m_param.m_callCleared.m_callToken, call.GetToken());
2160 
2161 
2162   PStringStream str;
2163   str << (unsigned)call.GetCallEndReason() << ": " << call.GetCallEndReasonText();
2164 
2165   SET_MESSAGE_STRING(message, m_param.m_callCleared.m_reason, str);
2166   PTRACE(4, "OpalC API\tOnClearedCall:"
2167             " token=\""  << message->m_param.m_callCleared.m_callToken << "\""
2168             " reason=\"" << message->m_param.m_callCleared.m_reason << '"');
2169   PostMessage(message);
2170 
2171   OpalManager::OnClearedCall(call);
2172 }
2173 
2174 
2175 ///////////////////////////////////////////////////////////////////////////////
2176 
2177 extern "C" {
2178 
OpalInitialise(unsigned * version,const char * options)2179   OpalHandle OPAL_EXPORT OpalInitialise(unsigned * version, const char * options)
2180   {
2181     PCaselessString optionsString = IsNullString(options) ?
2182 #if OPAL_HAS_PCSS
2183             "pcss "
2184 #endif
2185             "h323 sip iax2 pots pstn fax t38 ivr" : options;
2186 
2187     unsigned callerVersion = 1;
2188     if (version != NULL) {
2189       callerVersion = *version;
2190       if (callerVersion > OPAL_C_API_VERSION)
2191         *version = OPAL_C_API_VERSION;
2192     }
2193 
2194     OpalHandle opal = new OpalHandleStruct(callerVersion, optionsString);
2195     if (opal->manager.Initialise(optionsString))
2196       return opal;
2197 
2198     delete opal;
2199     return NULL;
2200   }
2201 
2202 
OpalShutDown(OpalHandle handle)2203   void OPAL_EXPORT OpalShutDown(OpalHandle handle)
2204   {
2205     delete handle;
2206   }
2207 
2208 
OpalGetMessage(OpalHandle handle,unsigned timeout)2209   OpalMessage * OPAL_EXPORT OpalGetMessage(OpalHandle handle, unsigned timeout)
2210   {
2211     return handle == NULL ? NULL : handle->manager.GetMessage(timeout);
2212   }
2213 
2214 
OpalSendMessage(OpalHandle handle,const OpalMessage * message)2215   OpalMessage * OPAL_EXPORT OpalSendMessage(OpalHandle handle, const OpalMessage * message)
2216   {
2217     return handle == NULL ? NULL : handle->manager.SendMessage(message);
2218   }
2219 
2220 
OpalFreeMessage(OpalMessage * message)2221   void OPAL_EXPORT OpalFreeMessage(OpalMessage * message)
2222   {
2223     if (message != NULL)
2224       free(message);
2225   }
2226 
2227 }; // extern "C"
2228 
2229 
2230 ///////////////////////////////////////////////////////////////////////////////
2231 
OpalContext()2232 OpalContext::OpalContext()
2233   : m_handle(NULL)
2234 {
2235 }
2236 
2237 
~OpalContext()2238 OpalContext::~OpalContext()
2239 {
2240   ShutDown();
2241 }
2242 
2243 
Initialise(const char * options,unsigned version)2244 unsigned OpalContext::Initialise(const char * options, unsigned version)
2245 {
2246   ShutDown();
2247 
2248   m_handle = OpalInitialise(&version, options);
2249   return m_handle != NULL ? version : 0;
2250 }
2251 
2252 
ShutDown()2253 void OpalContext::ShutDown()
2254 {
2255   if (m_handle != NULL) {
2256     OpalShutDown(m_handle);
2257     m_handle = NULL;
2258   }
2259 }
2260 
2261 
GetMessage(OpalMessagePtr & message,unsigned timeout)2262 bool OpalContext::GetMessage(OpalMessagePtr & message, unsigned timeout)
2263 {
2264   if (m_handle == NULL) {
2265     message.SetType(OpalIndCommandError);
2266     message.m_message->m_param.m_commandError = "Uninitialised OPAL context.";
2267     return false;
2268   }
2269 
2270   message.m_message = OpalGetMessage(m_handle, timeout);
2271   if (message.m_message != NULL)
2272     return true;
2273 
2274   message.SetType(OpalIndCommandError);
2275   message.m_message->m_param.m_commandError = "Timeout getting message.";
2276   return false;
2277 }
2278 
2279 
SendMessage(const OpalMessagePtr & message,OpalMessagePtr & response)2280 bool OpalContext::SendMessage(const OpalMessagePtr & message, OpalMessagePtr & response)
2281 {
2282   if (m_handle == NULL) {
2283     response.SetType(OpalIndCommandError);
2284     response.m_message->m_param.m_commandError = "Uninitialised OPAL context.";
2285     return false;
2286   }
2287 
2288   response.m_message = OpalSendMessage(m_handle, message.m_message);
2289   if (response.m_message != NULL)
2290     return response.GetType() != OpalIndCommandError;
2291 
2292   response.SetType(OpalIndCommandError);
2293   response.m_message->m_param.m_commandError = "Invalid message.";
2294   return false;
2295 }
2296 
2297 
SetUpCall(OpalMessagePtr & response,const char * partyB,const char * partyA,const char * alertingType)2298 bool OpalContext::SetUpCall(OpalMessagePtr & response,
2299                             const char * partyB,
2300                             const char * partyA,
2301                             const char * alertingType)
2302 {
2303   OpalMessagePtr message(OpalCmdSetUpCall);
2304   OpalParamSetUpCall * param = message.GetCallSetUp();
2305   param->m_partyA = partyA;
2306   param->m_partyB = partyB;
2307   param->m_alertingType = alertingType;
2308   return SendMessage(message, response);
2309 }
2310 
2311 
AnswerCall(const char * callToken)2312 bool OpalContext::AnswerCall(const char * callToken)
2313 {
2314   OpalMessagePtr message(OpalCmdAnswerCall), response;
2315   message.SetCallToken(callToken);
2316   return SendMessage(message, response);
2317 }
2318 
2319 
ClearCall(const char * callToken,OpalCallEndReason reason)2320 bool OpalContext::ClearCall(const char * callToken, OpalCallEndReason reason)
2321 {
2322   OpalMessagePtr message(OpalCmdClearCall), response;
2323   OpalParamCallCleared * param = message.GetClearCall();
2324   param->m_callToken = callToken;
2325   param->m_reason = reason;
2326   return SendMessage(message, response);
2327 }
2328 
2329 
SendUserInput(const char * callToken,const char * userInput,unsigned duration)2330 bool OpalContext::SendUserInput(const char * callToken, const char * userInput, unsigned duration)
2331 {
2332   OpalMessagePtr message(OpalCmdClearCall), response;
2333   OpalParamUserInput * param = message.GetUserInput();
2334   param->m_callToken = callToken;
2335   param->m_userInput = userInput;
2336   param->m_duration = duration;
2337   return SendMessage(message, response);
2338 }
2339 
2340 
OpalMessagePtr(OpalMessageType type)2341 OpalMessagePtr::OpalMessagePtr(OpalMessageType type)
2342   : m_message(NULL)
2343 {
2344   SetType(type);
2345 }
2346 
2347 
~OpalMessagePtr()2348 OpalMessagePtr::~OpalMessagePtr()
2349 {
2350   OpalFreeMessage(m_message);
2351 }
2352 
2353 
GetType() const2354 OpalMessageType OpalMessagePtr::GetType() const
2355 {
2356   return m_message->m_type;
2357 }
2358 
2359 
SetType(OpalMessageType type)2360 void OpalMessagePtr::SetType(OpalMessageType type)
2361 {
2362   OpalFreeMessage(m_message);
2363 
2364   m_message = (OpalMessage *)malloc(sizeof(OpalMessage)); // Use malloc to be compatible with OpalFreeMessage
2365   memset(m_message, 0, sizeof(OpalMessage));
2366   m_message->m_type = type;
2367 }
2368 
2369 
GetCommandError() const2370 const char * OpalMessagePtr::GetCommandError() const
2371 {
2372   return m_message->m_type == OpalIndCommandError ? m_message->m_param.m_commandError : NULL;
2373 }
2374 
2375 
GetCallToken() const2376 const char * OpalMessagePtr::GetCallToken() const
2377 {
2378   switch (m_message->m_type) {
2379     case OpalCmdAnswerCall :
2380     case OpalCmdHoldCall :
2381     case OpalCmdRetrieveCall :
2382     case OpalCmdStopRecording :
2383     case OpalCmdAlerting :
2384       return m_message->m_param.m_callToken;
2385 
2386     case OpalCmdSetUpCall :
2387     case OpalIndProceeding :
2388     case OpalIndAlerting :
2389     case OpalIndEstablished :
2390       return m_message->m_param.m_callSetUp.m_callToken;
2391 
2392     case OpalIndIncomingCall :
2393       return m_message->m_param.m_incomingCall.m_callToken;
2394 
2395     case OpalIndMediaStream :
2396     case OpalCmdMediaStream :
2397       return m_message->m_param.m_mediaStream.m_callToken;
2398 
2399     case OpalCmdSetUserData :
2400       return m_message->m_param.m_setUserData.m_callToken;
2401 
2402     case OpalIndUserInput :
2403       return m_message->m_param.m_userInput.m_callToken;
2404 
2405     case OpalCmdStartRecording :
2406       return m_message->m_param.m_recording.m_callToken;
2407 
2408     case OpalIndCallCleared :
2409       return m_message->m_param.m_callCleared.m_callToken;
2410 
2411     case OpalCmdClearCall :
2412       return m_message->m_param.m_clearCall.m_callToken;
2413 
2414     default :
2415       return NULL;
2416   }
2417 }
2418 
2419 
SetCallToken(const char * callToken)2420 void OpalMessagePtr::SetCallToken(const char * callToken)
2421 {
2422   switch (m_message->m_type) {
2423     case OpalCmdAnswerCall :
2424     case OpalCmdHoldCall :
2425     case OpalCmdRetrieveCall :
2426     case OpalCmdStopRecording :
2427     case OpalCmdAlerting :
2428       m_message->m_param.m_callToken = callToken;
2429       break;
2430 
2431     case OpalCmdSetUpCall :
2432     case OpalIndProceeding :
2433     case OpalIndAlerting :
2434     case OpalIndEstablished :
2435       m_message->m_param.m_callSetUp.m_callToken = callToken;
2436       break;
2437 
2438     case OpalIndIncomingCall :
2439       m_message->m_param.m_incomingCall.m_callToken = callToken;
2440       break;
2441 
2442     case OpalIndMediaStream :
2443     case OpalCmdMediaStream :
2444       m_message->m_param.m_mediaStream.m_callToken = callToken;
2445       break;
2446 
2447     case OpalCmdSetUserData :
2448       m_message->m_param.m_setUserData.m_callToken = callToken;
2449       break;
2450 
2451     case OpalIndUserInput :
2452       m_message->m_param.m_userInput.m_callToken = callToken;
2453       break;
2454 
2455     case OpalCmdStartRecording :
2456       m_message->m_param.m_recording.m_callToken = callToken;
2457       break;
2458 
2459     case OpalIndCallCleared :
2460       m_message->m_param.m_callCleared.m_callToken = callToken;
2461       break;
2462 
2463     case OpalCmdClearCall :
2464       m_message->m_param.m_clearCall.m_callToken = callToken;
2465       break;
2466 
2467     default :
2468       break;
2469   }
2470 }
2471 
2472 
GetGeneralParams() const2473 OpalParamGeneral * OpalMessagePtr::GetGeneralParams() const
2474 {
2475   return m_message->m_type == OpalCmdSetGeneralParameters ? &m_message->m_param.m_general : NULL;
2476 }
2477 
2478 
GetProtocolParams() const2479 OpalParamProtocol * OpalMessagePtr::GetProtocolParams() const
2480 {
2481   return m_message->m_type == OpalCmdSetProtocolParameters ? &m_message->m_param.m_protocol : NULL;
2482 }
2483 
2484 
GetRegistrationInfo() const2485 OpalParamRegistration * OpalMessagePtr::GetRegistrationInfo() const
2486 {
2487   return m_message->m_type == OpalCmdRegistration ? &m_message->m_param.m_registrationInfo : NULL;
2488 }
2489 
2490 
GetRegistrationStatus() const2491 OpalStatusRegistration * OpalMessagePtr::GetRegistrationStatus() const
2492 {
2493   return m_message->m_type == OpalIndRegistration ? &m_message->m_param.m_registrationStatus : NULL;
2494 }
2495 
2496 
GetCallSetUp() const2497 OpalParamSetUpCall * OpalMessagePtr::GetCallSetUp() const
2498 {
2499   switch (m_message->m_type) {
2500     case OpalCmdSetUpCall :
2501     case OpalIndProceeding :
2502     case OpalIndAlerting :
2503     case OpalIndEstablished :
2504     case OpalIndCompletedIVR :
2505       return &m_message->m_param.m_callSetUp;
2506 
2507     default :
2508       return NULL;
2509   }
2510 }
2511 
2512 
GetIncomingCall() const2513 OpalStatusIncomingCall * OpalMessagePtr::GetIncomingCall() const
2514 {
2515   return m_message->m_type == OpalIndIncomingCall ? &m_message->m_param.m_incomingCall : NULL;
2516 }
2517 
2518 
GetAnswerCall() const2519 OpalParamAnswerCall * OpalMessagePtr::GetAnswerCall() const
2520 {
2521   return m_message->m_type == OpalCmdAlerting ||
2522          m_message->m_type == OpalCmdAnswerCall ? &m_message->m_param.m_answerCall : NULL;
2523 }
2524 
2525 
GetUserInput() const2526 OpalStatusUserInput * OpalMessagePtr::GetUserInput() const
2527 {
2528   switch (m_message->m_type) {
2529     case OpalIndUserInput :
2530     case OpalCmdUserInput :
2531       return &m_message->m_param.m_userInput;
2532 
2533     default :
2534       return NULL;
2535   }
2536 }
2537 
2538 
GetMessageWaiting() const2539 OpalStatusMessageWaiting * OpalMessagePtr::GetMessageWaiting() const
2540 {
2541   return m_message->m_type == OpalIndMessageWaiting ? &m_message->m_param.m_messageWaiting : NULL;
2542 }
2543 
2544 
GetLineAppearance() const2545 OpalStatusLineAppearance * OpalMessagePtr::GetLineAppearance() const
2546 {
2547   return m_message->m_type == OpalIndLineAppearance ? &m_message->m_param.m_lineAppearance : NULL;
2548 }
2549 
2550 
GetCallCleared() const2551 OpalStatusCallCleared * OpalMessagePtr::GetCallCleared() const
2552 {
2553   return m_message->m_type == OpalIndCallCleared ? &m_message->m_param.m_callCleared : NULL;
2554 }
2555 
2556 
GetClearCall() const2557 OpalParamCallCleared * OpalMessagePtr::GetClearCall() const
2558 {
2559   return m_message->m_type == OpalCmdClearCall ? &m_message->m_param.m_clearCall : NULL;
2560 }
2561 
2562 
GetMediaStream() const2563 OpalStatusMediaStream * OpalMessagePtr::GetMediaStream() const
2564 {
2565   switch (m_message->m_type) {
2566     case OpalIndMediaStream :
2567     case OpalCmdMediaStream :
2568       return &m_message->m_param.m_mediaStream;
2569 
2570     default :
2571       return NULL;
2572   }
2573 }
2574 
2575 
GetSetUserData() const2576 OpalParamSetUserData * OpalMessagePtr::GetSetUserData() const
2577 {
2578   return m_message->m_type == OpalCmdSetUserData ? &m_message->m_param.m_setUserData : NULL;
2579 }
2580 
2581 
GetRecording() const2582 OpalParamRecording * OpalMessagePtr::GetRecording() const
2583 {
2584   return m_message->m_type == OpalCmdStartRecording ? &m_message->m_param.m_recording : NULL;
2585 }
2586 
2587 
GetTransferStatus() const2588 OpalStatusTransferCall * OpalMessagePtr::GetTransferStatus() const
2589 {
2590   return m_message->m_type == OpalIndTransferCall ? &m_message->m_param.m_transferStatus : NULL;
2591 }
2592 
2593 
2594 ///////////////////////////////////////////////////////////////////////////////
2595