media/webrtc/signaling/src/callcontrol/CallControlManagerImpl.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:af9de8288f44
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include <errno.h>
6 #include <string>
7 #include <prcvar.h>
8 #include <prlock.h>
9
10 #include "CSFLog.h"
11
12 #include "CC_SIPCCDevice.h"
13 #include "CC_SIPCCDeviceInfo.h"
14 #include "CC_SIPCCFeatureInfo.h"
15 #include "CC_SIPCCLine.h"
16 #include "CC_SIPCCLineInfo.h"
17 #include "CC_SIPCCCallInfo.h"
18 #include "CallControlManagerImpl.h"
19 #include "csf_common.h"
20
21 extern "C"
22 {
23 #include "config_api.h"
24 }
25
26
27 static const char logTag[] = "CallControlManager";
28
29 using namespace std;
30 using namespace CSFUnified;
31
32 namespace CSF
33 {
34
35
36 CallControlManagerImpl::CallControlManagerImpl()
37 : m_lock("CallControlManagerImpl"),
38 multiClusterMode(false),
39 sipccLoggingMask(0xFFFFFFFF),
40 authenticationStatus(AuthenticationStatusEnum::eNotAuthenticated),
41 connectionState(ConnectionStatusEnum::eIdle)
42 {
43 CSFLogInfo(logTag, "CallControlManagerImpl()");
44 }
45
46 CallControlManagerImpl::~CallControlManagerImpl()
47 {
48 CSFLogInfo(logTag, "~CallControlManagerImpl()");
49 destroy();
50 }
51
52 bool CallControlManagerImpl::destroy()
53 {
54 CSFLogInfo(logTag, "destroy()");
55 bool retval = disconnect();
56 if(retval == false)
57 {
58 return retval;
59 }
60 return retval;
61 }
62
63 // Observers
64 void CallControlManagerImpl::addCCObserver ( CC_Observer * observer )
65 {
66 mozilla::MutexAutoLock lock(m_lock);
67 if (observer == nullptr)
68 {
69 CSFLogError(logTag, "NULL value for \"observer\" passed to addCCObserver().");
70 return;
71 }
72
73 ccObservers.insert(observer);
74 }
75
76 void CallControlManagerImpl::removeCCObserver ( CC_Observer * observer )
77 {
78 mozilla::MutexAutoLock lock(m_lock);
79 ccObservers.erase(observer);
80 }
81
82 void CallControlManagerImpl::addECCObserver ( ECC_Observer * observer )
83 {
84 mozilla::MutexAutoLock lock(m_lock);
85 if (observer == nullptr)
86 {
87 CSFLogError(logTag, "NULL value for \"observer\" passed to addECCObserver().");
88 return;
89 }
90
91 eccObservers.insert(observer);
92 }
93
94 void CallControlManagerImpl::removeECCObserver ( ECC_Observer * observer )
95 {
96 mozilla::MutexAutoLock lock(m_lock);
97 eccObservers.erase(observer);
98 }
99
100 void CallControlManagerImpl::setMultiClusterMode(bool allowMultipleClusters)
101 {
102 CSFLogInfo(logTag, "setMultiClusterMode(%s)",
103 allowMultipleClusters ? "TRUE" : "FALSE");
104 multiClusterMode = allowMultipleClusters;
105 }
106
107 void CallControlManagerImpl::setSIPCCLoggingMask(const cc_int32_t mask)
108 {
109 CSFLogInfo(logTag, "setSIPCCLoggingMask(%u)", mask);
110 sipccLoggingMask = mask;
111 }
112
113 void CallControlManagerImpl::setAuthenticationString(const std::string &authString)
114 {
115 CSFLogInfo(logTag, "setAuthenticationString()");
116 this->authString = authString;
117 }
118
119 void CallControlManagerImpl::setSecureCachePath(const std::string &secureCachePath)
120 {
121 CSFLogInfo(logTag, "setSecureCachePath(%s)", secureCachePath.c_str());
122 this->secureCachePath = secureCachePath;
123 }
124
125 // Add local codecs
126 void CallControlManagerImpl::setAudioCodecs(int codecMask)
127 {
128 CSFLogDebug(logTag, "setAudioCodecs %X", codecMask);
129
130 VcmSIPCCBinding::setAudioCodecs(codecMask);
131 }
132
133 void CallControlManagerImpl::setVideoCodecs(int codecMask)
134 {
135 CSFLogDebug(logTag, "setVideoCodecs %X", codecMask);
136
137 VcmSIPCCBinding::setVideoCodecs(codecMask);
138 }
139
140 AuthenticationStatusEnum::AuthenticationStatus CallControlManagerImpl::getAuthenticationStatus()
141 {
142 return authenticationStatus;
143 }
144
145 bool CallControlManagerImpl::registerUser( const std::string& deviceName, const std::string& user, const std::string& password, const std::string& domain )
146 {
147 setConnectionState(ConnectionStatusEnum::eRegistering);
148
149 CSFLogInfo(logTag, "registerUser(%s, %s )", user.c_str(), domain.c_str());
150 if(phone != nullptr)
151 {
152 setConnectionState(ConnectionStatusEnum::eReady);
153
154 CSFLogError(logTag, "registerUser() failed - already connected!");
155 return false;
156 }
157
158 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
159 phone = softPhone;
160 phone->init(user, password, domain, deviceName);
161 softPhone->setLoggingMask(sipccLoggingMask);
162 phone->addCCObserver(this);
163
164 phone->setP2PMode(false);
165
166 bool bStarted = phone->startService();
167 if (!bStarted) {
168 setConnectionState(ConnectionStatusEnum::eFailed);
169 } else {
170 setConnectionState(ConnectionStatusEnum::eReady);
171 }
172
173 return bStarted;
174 }
175
176 bool CallControlManagerImpl::startP2PMode(const std::string& user)
177 {
178 setConnectionState(ConnectionStatusEnum::eRegistering);
179
180 CSFLogInfo(logTag, "startP2PMode(%s)", user.c_str());
181 if(phone != nullptr)
182 {
183 setConnectionState(ConnectionStatusEnum::eReady);
184
185 CSFLogError(logTag, "startP2PMode() failed - already started in p2p mode!");
186 return false;
187 }
188
189 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
190 phone = softPhone;
191 phone->init(user, "", "127.0.0.1", "sipdevice");
192 softPhone->setLoggingMask(sipccLoggingMask);
193 phone->addCCObserver(this);
194
195 phone->setP2PMode(true);
196
197 bool bStarted = phone->startService();
198 if (!bStarted) {
199 setConnectionState(ConnectionStatusEnum::eFailed);
200 } else {
201 setConnectionState(ConnectionStatusEnum::eReady);
202 }
203
204 return bStarted;
205 }
206
207 bool CallControlManagerImpl::startSDPMode()
208 {
209 CSFLogInfo(logTag, "startSDPMode");
210 if(phone != nullptr)
211 {
212 CSFLogError(logTag, "%s failed - already started in SDP mode!",__FUNCTION__);
213 return false;
214 }
215 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
216 phone = softPhone;
217 phone->init("JSEP", "", "127.0.0.1", "sipdevice");
218 softPhone->setLoggingMask(sipccLoggingMask);
219 phone->addCCObserver(this);
220 phone->setSDPMode(true);
221
222 return phone->startService();
223 }
224
225 bool CallControlManagerImpl::disconnect()
226 {
227 CSFLogInfo(logTag, "disconnect()");
228 if(phone == nullptr)
229 return true;
230
231 connectionState = ConnectionStatusEnum::eIdle;
232 phone->removeCCObserver(this);
233 phone->stop();
234 phone->destroy();
235 phone = nullptr;
236 softPhone = nullptr;
237
238 return true;
239 }
240
241 std::string CallControlManagerImpl::getPreferredDeviceName()
242 {
243 return preferredDevice;
244 }
245
246 std::string CallControlManagerImpl::getPreferredLineDN()
247 {
248 return preferredLineDN;
249 }
250
251 ConnectionStatusEnum::ConnectionStatus CallControlManagerImpl::getConnectionStatus()
252 {
253 return connectionState;
254 }
255
256 std::string CallControlManagerImpl::getCurrentServer()
257 {
258 return "";
259 }
260
261 // Currently controlled device
262 CC_DevicePtr CallControlManagerImpl::getActiveDevice()
263 {
264 if(phone != nullptr)
265 return phone->getActiveDevice();
266
267 return CC_DevicePtr();
268 }
269
270 // All known devices
271 PhoneDetailsVtrPtr CallControlManagerImpl::getAvailablePhoneDetails()
272 {
273 PhoneDetailsVtrPtr result = PhoneDetailsVtrPtr(new PhoneDetailsVtr());
274 for(PhoneDetailsMap::iterator it = phoneDetailsMap.begin(); it != phoneDetailsMap.end(); it++)
275 {
276 PhoneDetailsPtr details = it->second.get();
277 result->push_back(details);
278 }
279 return result;
280 }
281
282 PhoneDetailsPtr CallControlManagerImpl::getAvailablePhoneDetails(const std::string& deviceName)
283 {
284 PhoneDetailsMap::iterator it = phoneDetailsMap.find(deviceName);
285 if(it != phoneDetailsMap.end())
286 {
287 return it->second.get();
288 }
289 return PhoneDetailsPtr();
290 }
291 // Media setup
292 VideoControlPtr CallControlManagerImpl::getVideoControl()
293 {
294 if(phone != nullptr)
295 return phone->getVideoControl();
296
297 return VideoControlPtr();
298 }
299
300 AudioControlPtr CallControlManagerImpl::getAudioControl()
301 {
302 if(phone != nullptr)
303 return phone->getAudioControl();
304
305 return AudioControlPtr();
306 }
307
308 bool CallControlManagerImpl::setProperty(ConfigPropertyKeysEnum::ConfigPropertyKeys key, std::string& value)
309 {
310 unsigned long strtoul_result;
311 char *strtoul_end;
312
313 CSFLogInfo(logTag, "setProperty( %s )", value.c_str());
314
315 if (key == ConfigPropertyKeysEnum::eLocalVoipPort) {
316 errno = 0;
317 strtoul_result = strtoul(value.c_str(), &strtoul_end, 10);
318
319 if (errno || value.c_str() == strtoul_end || strtoul_result > USHRT_MAX) {
320 return false;
321 }
322
323 CCAPI_Config_set_local_voip_port((int) strtoul_result);
324 } else if (key == ConfigPropertyKeysEnum::eRemoteVoipPort) {
325 errno = 0;
326 strtoul_result = strtoul(value.c_str(), &strtoul_end, 10);
327
328 if (errno || value.c_str() == strtoul_end || strtoul_result > USHRT_MAX) {
329 return false;
330 }
331
332 CCAPI_Config_set_remote_voip_port((int) strtoul_result);
333 } else if (key == ConfigPropertyKeysEnum::eTransport) {
334 if (value == "tcp")
335 CCAPI_Config_set_transport_udp(false);
336 else
337 CCAPI_Config_set_transport_udp(true);
338 }
339
340 return true;
341 }
342
343 std::string CallControlManagerImpl::getProperty(ConfigPropertyKeysEnum::ConfigPropertyKeys key)
344 {
345 std::string retValue = "NONESET";
346 char tmpString[11];
347
348 CSFLogInfo(logTag, "getProperty()");
349
350 if (key == ConfigPropertyKeysEnum::eLocalVoipPort) {
351 csf_sprintf(tmpString, sizeof(tmpString), "%u", CCAPI_Config_get_local_voip_port());
352 retValue = tmpString;
353 } else if (key == ConfigPropertyKeysEnum::eRemoteVoipPort) {
354 csf_sprintf(tmpString, sizeof(tmpString), "%u", CCAPI_Config_get_remote_voip_port());
355 retValue = tmpString;
356 } else if (key == ConfigPropertyKeysEnum::eVersion) {
357 const char* version = CCAPI_Config_get_version();
358 retValue = version;
359 }
360
361 return retValue;
362 }
363 /*
364 There are a number of factors that determine PhoneAvailabilityType::PhoneAvailability. The supported states for this enum are:
365 { eUnknown, eAvailable, eUnAvailable, eNotAllowed }. eUnknown is the default value, which is set when there is no information
366 available that would otherwise determine the availability value. The factors that can influence PhoneAvailability are:
367 phone mode, and for a given device (described by DeviceInfo) the model, and the name of the device. For phone control mode, the
368 device registration and whether CUCM says the device is CTI controllable (or not) is a factor.
369
370 For Phone Control mode the state machine is:
371
372 is blacklisted model name? -> Yes -> NOT_ALLOWED
373 (see Note1 below)
374 ||
375 \/
376 No
377 ||
378 \/
379 is CTI Controllable?
380 (determined from CUCM) -> No -> NOT_ALLOWED
381 ||
382 \/
383 Yes
384 ||
385 \/
386 Can we tell if it's registered? -> No -> ?????? TODO: Seems to depends on other factors (look at suggestedAvailability parameter
387 || in DeviceSubProviderImpl.addOrUpdateDevice() in CSF1G Java code.
388 \/
389 Yes
390 ||
391 \/
392 is Registered?
393 (determined from CUCM) -> No -> NOT_AVAILABLE
394 ||
395 \/
396 Yes
397 ||
398 \/
399 AVAILABLE
400
401 ========
402
403 For Softphone mode the state machine is:
404
405 is device excluded?
406 (based on "ExcludedDevices" -> Yes -> NOT_ALLOWED
407 config settings
408 (see Note2 below))
409 ||
410 \/
411 No
412 ||
413 \/
414 isSoftphone?
415
416
417
418 Note1: model name has to match completely, ie it's not a sub-string match, but we are ignoring case. So, if the blacklist
419 contains a string "Cisco Unified Personal Communicator" then the model has to match this completely (but can be a
420 different case) to be a match. In CSF1G the blacklist is hard-wired to:
421 { "Cisco Unified Personal Communicator",
422 "Cisco Unified Client Services Framework",
423 "Client Services Framework",
424 "Client Services Core" }
425
426 Note2: The "ExcludedDevices" is a comma-separated list of device name prefixes (not model name). Unlike the above, this is
427 a sub-string match, but only a "starts with" sub-string match, not anywhere in the string. If the device name
428 is a complete match then this is also excluded, ie doesn't have to be a sub-string. For example, if the
429 ExcludeDevices list contains { "ECP", "UPC" } then assuming we're in softphone mode, then any device whose
430 name starts with the strings ECP or UPC, or whose complete name is either of these will be deemed to be excluded
431 and will be marked as NOT_ALLOWED straightaway. In Phone Control mode the "ExcludedDevices" list i not taken into
432 account at all in the determination of availability.
433
434 Note3: isSoftphone() function
435
436 The config service provides a list of "blacklisted" device name prefixes, that is, if the name of the device starts with a
437 sub-string that matches an entry in the blacklist, then it is straightaway removed from the list? marked as NOT_ALLOWED.
438 */
439
440 // CC_Observers
441 void CallControlManagerImpl::onDeviceEvent(ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info)
442 {
443 notifyDeviceEventObservers(deviceEvent, devicePtr, info);
444 }
445 void CallControlManagerImpl::onFeatureEvent(ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info)
446 {
447 notifyFeatureEventObservers(deviceEvent, devicePtr, info);
448 }
449 void CallControlManagerImpl::onLineEvent(ccapi_line_event_e lineEvent, CC_LinePtr linePtr, CC_LineInfoPtr info)
450 {
451 notifyLineEventObservers(lineEvent, linePtr, info);
452 }
453 void CallControlManagerImpl::onCallEvent(ccapi_call_event_e callEvent, CC_CallPtr callPtr, CC_CallInfoPtr info)
454 {
455 notifyCallEventObservers(callEvent, callPtr, info);
456 }
457
458
459 void CallControlManagerImpl::notifyDeviceEventObservers (ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info)
460 {
461 mozilla::MutexAutoLock lock(m_lock);
462 set<CC_Observer*>::const_iterator it = ccObservers.begin();
463 for ( ; it != ccObservers.end(); it++ )
464 {
465 (*it)->onDeviceEvent(deviceEvent, devicePtr, info);
466 }
467 }
468
469 void CallControlManagerImpl::notifyFeatureEventObservers (ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info)
470 {
471 mozilla::MutexAutoLock lock(m_lock);
472 set<CC_Observer*>::const_iterator it = ccObservers.begin();
473 for ( ; it != ccObservers.end(); it++ )
474 {
475 (*it)->onFeatureEvent(deviceEvent, devicePtr, info);
476 }
477 }
478
479 void CallControlManagerImpl::notifyLineEventObservers (ccapi_line_event_e lineEvent, CC_LinePtr linePtr, CC_LineInfoPtr info)
480 {
481 mozilla::MutexAutoLock lock(m_lock);
482 set<CC_Observer*>::const_iterator it = ccObservers.begin();
483 for ( ; it != ccObservers.end(); it++ )
484 {
485 (*it)->onLineEvent(lineEvent, linePtr, info);
486 }
487 }
488
489 void CallControlManagerImpl::notifyCallEventObservers (ccapi_call_event_e callEvent, CC_CallPtr callPtr, CC_CallInfoPtr info)
490 {
491 mozilla::MutexAutoLock lock(m_lock);
492 set<CC_Observer*>::const_iterator it = ccObservers.begin();
493 for ( ; it != ccObservers.end(); it++ )
494 {
495 (*it)->onCallEvent(callEvent, callPtr, info);
496 }
497 }
498
499 void CallControlManagerImpl::notifyAvailablePhoneEvent (AvailablePhoneEventType::AvailablePhoneEvent event,
500 const PhoneDetailsPtr availablePhoneDetails)
501 {
502 mozilla::MutexAutoLock lock(m_lock);
503 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
504 for ( ; it != eccObservers.end(); it++ )
505 {
506 (*it)->onAvailablePhoneEvent(event, availablePhoneDetails);
507 }
508 }
509
510 void CallControlManagerImpl::notifyAuthenticationStatusChange (AuthenticationStatusEnum::AuthenticationStatus status)
511 {
512 mozilla::MutexAutoLock lock(m_lock);
513 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
514 for ( ; it != eccObservers.end(); it++ )
515 {
516 (*it)->onAuthenticationStatusChange(status);
517 }
518 }
519
520 void CallControlManagerImpl::notifyConnectionStatusChange(ConnectionStatusEnum::ConnectionStatus status)
521 {
522 mozilla::MutexAutoLock lock(m_lock);
523 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
524 for ( ; it != eccObservers.end(); it++ )
525 {
526 (*it)->onConnectionStatusChange(status);
527 }
528 }
529
530 void CallControlManagerImpl::setConnectionState(ConnectionStatusEnum::ConnectionStatus status)
531 {
532 connectionState = status;
533 notifyConnectionStatusChange(status);
534 }
535 }

mercurial