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