1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1036 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef _WIN32 1.9 +#include <windows.h> //plat_api.h seems to need some of the types defined in Windows.h (e.g. boolean) 1.10 +#endif 1.11 + 1.12 +#include "CSFLog.h" 1.13 + 1.14 +#include "CC_CallTypes.h" 1.15 +#include "CC_SIPCCService.h" 1.16 +#include "NullDeleter.h" 1.17 +#include "CC_SIPCCDevice.h" 1.18 +#include "CC_SIPCCDeviceInfo.h" 1.19 +#include "CC_SIPCCFeatureInfo.h" 1.20 +#include "CC_SIPCCCallServerInfo.h" 1.21 +#include "CC_SIPCCCall.h" 1.22 +#include "CC_SIPCCCallInfo.h" 1.23 +#include "CC_SIPCCLine.h" 1.24 +#include "CC_SIPCCLineInfo.h" 1.25 +#include "CSFMediaProvider.h" 1.26 +#include "CSFAudioTermination.h" 1.27 +#include "CSFVideoTermination.h" 1.28 + 1.29 +#include "base/platform_thread.h" 1.30 +#include "base/time.h" 1.31 + 1.32 +extern "C" { 1.33 +#include "ccapi_device.h" 1.34 +} 1.35 +#include "debug-psipcc-types.h" 1.36 +#include "VcmSIPCCBinding.h" 1.37 + 1.38 +#include "csf_common.h" 1.39 + 1.40 +static const char* logTag = "CC_SIPCCService"; 1.41 + 1.42 +using namespace std; 1.43 + 1.44 +#define MAX_SUPPORTED_NUM_CALLS 100 1.45 +#define MAX_SUPPORTED_NUM_LINES 100 1.46 +#define MAX_SUPPORTED_NUM_FEATURES 100 1.47 +#define MAX_SUPPORTED_NUM_CALL_SERVERS 100 1.48 + 1.49 +extern "C" 1.50 +{ 1.51 +#include "cpr_types.h" 1.52 +#include "ccapi_device.h" 1.53 +#include "ccapi_device_info.h" 1.54 +#include "ccapi_call.h" 1.55 + 1.56 +#include "cpr_stdio.h" 1.57 +#include "config_api.h" 1.58 +#include "ccapi_service.h" 1.59 +#include "plat_api.h" 1.60 + 1.61 +/** 1.62 + * configCtlFetchReq 1.63 + * 1.64 + * This function tells the config manager to fetch the CTL file 1.65 + * and then fetch the config from the CUCM. It is expected that 1.66 + * this will result in processing of 1.67 + * the config file after the config managers response is received. 1.68 + * 1.69 + * The response received for this request is asynchronous and 1.70 + * should be handled via event provided by config manager. 1.71 + * The CCAPI_Config_reponse api needs to be called for the 1.72 + * handling of the response to the fetch request 1.73 + * 1.74 + */ 1.75 +void configCtlFetchReq(int device_handle) 1.76 +{ 1.77 + CSFLogDebug(logTag, "In configCtlFetchReq"); 1.78 + 1.79 + CSF::CC_SIPCCService * pPhone = CSF::CC_SIPCCService::_self; 1.80 + 1.81 + if (pPhone == nullptr) 1.82 + { 1.83 + CSFLogError( logTag, "CC_SIPCCService::_self is NULL."); 1.84 + } 1.85 + else 1.86 + { 1.87 + CCAPI_Start_response(device_handle, pPhone->deviceName.c_str(), pPhone->sipUser.c_str(), 1.88 + pPhone->sipPassword.c_str(), pPhone->sipDomain.c_str()); 1.89 + } 1.90 +} 1.91 + 1.92 +/** 1.93 + * configFetchReq 1.94 + * 1.95 + * This function tells the config manager to fetch the latest config 1.96 + * from the CUCM. It is expected that this will result in processing of 1.97 + * the config file after the config managers response is received. 1.98 + * 1.99 + * The response received for this request is asynchronous and 1.100 + * should be handled via event provided by config manager. 1.101 + * The CCAPI_Config_reponse api needs to be called for the 1.102 + * handling of the response to the fetch request 1.103 + * 1.104 + * There are cases where only the config file is needed, for eg: during 1.105 + * Apply Config, for those situation we use this API 1.106 + * 1.107 + */ 1.108 +void configFetchReq(int device_handle) 1.109 +{ 1.110 + CSFLogDebug( logTag, "In configFetchReq"); 1.111 + 1.112 + configCtlFetchReq(device_handle); 1.113 +} 1.114 + 1.115 +/** 1.116 + * configParserError 1.117 + * 1.118 + * Notify the config manager that the config file has an error 1.119 + * and a new config file needs to be downloaded. 1.120 + * 1.121 + * The error could be XML format error or minimum config not being 1.122 + * present in the config file. It is expected that 1.123 + * this will result in processing of 1.124 + * the config file after the config managers response is received. 1.125 + * 1.126 + */ 1.127 +void configParserError(void) 1.128 +{ 1.129 + CSFLogError( logTag, "In configParserError"); 1.130 +} 1.131 + 1.132 +/** 1.133 + * Inform application that pSipcc stack has receive a NOTIFY message of event 1.134 + * type "service-control" and action=apply-config. The arguments passed to this 1.135 + * function contains the parameter values received in the message. 1.136 + * 1.137 + * @param config_version [in] latest version stamp of phone configuration. 1.138 + * @param dial_plan_version [in] latest version stamp of the dial plan. 1.139 + * @param fcp_version [in] latest version stamp of feature policy control. 1.140 + * @param cucm_result [in] action taken by the cucm for the changes applied by the 1.141 + * user to the phone configuration. cucm result could be 1.142 + * @li "no_change" - the new phone configuration changes do not impact Unified CM, 1.143 + * @li "config_applied" - The Unified CM Administration applied the 1.144 + * configuration changes dynamically without requiring phone to re-register, 1.145 + * @li "reregister_needed" - The Unified CM Administration applied the 1.146 + * configuration changes and required the phone to re-register to make them 1.147 + * effective. 1.148 + * @param load_id [in] - firmware image name that phone should be running with 1.149 + * @param inactive_load_id [in] - firmware image name that phone should be in inactive partition. 1.150 + * @param load_server [in] - address of load server to download the firmware 1.151 + * image load_id. 1.152 + * @param log_server [in] - log server address where error report need to be 1.153 + * sent. Error report, for example, could be related to image download failure 1.154 + * or phone configuration file download failure. 1.155 + * @param ppid [in] whether peer to peer upgrade is available 1.156 + * @return void 1.157 + */ 1.158 +void configApplyConfigNotify(cc_string_t config_version, 1.159 + cc_string_t dial_plan_version, 1.160 + cc_string_t fcp_version, 1.161 + cc_string_t cucm_result, 1.162 + cc_string_t load_id, 1.163 + cc_string_t inactive_load_id, 1.164 + cc_string_t load_server, 1.165 + cc_string_t log_server, 1.166 + cc_boolean ppid) 1.167 +{ 1.168 + CSFLogDebug( logTag, "In configApplyConfigNotify"); 1.169 +} 1.170 + 1.171 +char * platGetIPAddr () 1.172 +{ 1.173 + CSFLogDebug( logTag, "In platGetIPAddr()"); 1.174 + 1.175 + CSF::CC_SIPCCService * pPhone = CSF::CC_SIPCCService::_self; 1.176 + 1.177 + if (pPhone == nullptr) 1.178 + { 1.179 + CSFLogError( logTag, "In platGetIPAddr(). CC_SIPCCService::_self is NULL."); 1.180 + return (char *) ""; 1.181 + } 1.182 + 1.183 + return (char*) pPhone->localAddress.c_str(); 1.184 +} 1.185 + 1.186 +void ccmedia_flash_once_timer_callback (void) 1.187 +{ 1.188 +} 1.189 + 1.190 +/** 1.191 + * dialPlanFetchReq 1.192 + * 1.193 + * This function tells the get file request service to fetch the latest dial 1.194 + * plan from the CUCM. 1.195 + * 1.196 + * @param device_handle [in] handle of the device, the response is for 1.197 + * @param dialPlanFileName [in] the name of dialplan file to retrieve 1.198 + * 1.199 + */ 1.200 +cc_boolean dialPlanFetchReq(int device_handle, char* dialPlanFileName) 1.201 +{ 1.202 + return 0; 1.203 +} 1.204 + 1.205 +/** 1.206 + * fcpFetchReq 1.207 + * 1.208 + * This function tells the get file request service to fetch the latest fcp 1.209 + * file from the CUCM. 1.210 + * 1.211 + * @param device_handle [in] handle of the device, the response is for 1.212 + * @param dialPlanFileName [in] the name of fcp file to retrieve 1.213 + * 1.214 + */ 1.215 +cc_boolean fcpFetchReq(int device_handle, char* fcpFileName) 1.216 +{ 1.217 + return 0; 1.218 +} 1.219 + 1.220 +extern cc_int32_t SipDebugMessage; 1.221 +extern cc_int32_t SipDebugState; 1.222 +extern cc_int32_t SipDebugTask; 1.223 +extern cc_int32_t SipDebugRegState; 1.224 +extern cc_int32_t GSMDebug; 1.225 +extern cc_int32_t FIMDebug; 1.226 +extern cc_int32_t LSMDebug; 1.227 +extern cc_int32_t FSMDebugSM; 1.228 +extern int32_t CSMDebugSM; 1.229 +extern cc_int32_t CCDebug; 1.230 +extern cc_int32_t CCDebugMsg; 1.231 +extern cc_int32_t AuthDebug; 1.232 +extern cc_int32_t ConfigDebug; 1.233 +extern cc_int32_t DpintDebug; 1.234 +extern cc_int32_t KpmlDebug; 1.235 +extern cc_int32_t VCMDebug; 1.236 +extern cc_int32_t g_CCAppDebug; 1.237 +extern cc_int32_t g_CCLogDebug; 1.238 +extern cc_int32_t TNPDebug; 1.239 + 1.240 +static cc_int32_t * _maskedLoggingEntriesArray[19] = { 1.241 + &SipDebugMessage, //13 1.242 + &SipDebugState, //12 1.243 + &SipDebugTask, //11 1.244 + &SipDebugRegState, //14 1.245 + &GSMDebug, //7 1.246 + &FIMDebug, //4 1.247 + &LSMDebug, //8 1.248 + &FSMDebugSM, //5 1.249 + &CSMDebugSM, //?? 1.250 + &CCDebug, //2 1.251 + &CCDebugMsg, //3 1.252 + &AuthDebug, //6 1.253 + &ConfigDebug, //0 1.254 + &DpintDebug, //18 1.255 + &KpmlDebug, //19 1.256 + &VCMDebug, //?? 1.257 + &g_CCAppDebug, //0 1.258 + &g_CCLogDebug, //?? 1.259 + &TNPDebug, //1 1.260 +}; 1.261 + 1.262 +//Following are not covered above. : 1.263 +//g_cacDebug,9 1.264 +//g_dcsmDebug, 10 1.265 +//SipDebugTrx, 14 1.266 +//TMRDebug, 15 1.267 +//SipDebugDM, 16 1.268 +//g_DEFDebug, 17 1.269 +//g_blfDebug, 21 1.270 +//g_configappDebug, 23 1.271 +//CCEVENTDebug, 24 1.272 +//PLATDebug, 25 1.273 + 1.274 +//If you add more to this array then you'll need to manually update "HAS_21_BITS" below to be "HAS_22_BITS" 1.275 +//of whatever the new number of bits defined ends up as. Then modify the code that currently uses HAS_21_BITS 1.276 +//below to use your new #define. 1.277 +#define HAS_21_BITS 0x1FFFFF 1.278 + 1.279 +static int _maxBitValueMaskedLoggingEntries = csf_countof(_maskedLoggingEntriesArray);//Should be 21 1.280 + 1.281 + 1.282 +} //end extern C 1.283 + 1.284 +extern "C" void CCAPI_DeviceListener_onDeviceEvent(ccapi_device_event_e type, cc_device_handle_t hDevice, cc_deviceinfo_ref_t dev_info) 1.285 +{ 1.286 + //CSFLogDebug( logTag, "In CCAPI_DeviceListener_onDeviceEvent"); 1.287 + CSF::CC_SIPCCService::onDeviceEvent(type, hDevice, dev_info); 1.288 +} 1.289 + 1.290 +extern "C" void CCAPI_DeviceListener_onFeatureEvent(ccapi_device_event_e type, cc_deviceinfo_ref_t dev_info, cc_featureinfo_ref_t feature_info) 1.291 +{ 1.292 + //CSFLogDebug( logTag, "In CCAPI_DeviceListener_onFeatureEvent"); 1.293 + CSF::CC_SIPCCService::onFeatureEvent(type, dev_info, feature_info); 1.294 +} 1.295 + 1.296 +extern "C" void CCAPI_LineListener_onLineEvent(ccapi_line_event_e type, cc_lineid_t line, cc_lineinfo_ref_t info) 1.297 +{ 1.298 + //CSFLogDebug( logTag, "In CCAPI_LineListener_onLineEvent"); 1.299 + CSF::CC_SIPCCService::onLineEvent(type, line, info); 1.300 +} 1.301 + 1.302 +extern "C" void CCAPI_CallListener_onCallEvent(ccapi_call_event_e type, cc_call_handle_t handle, cc_callinfo_ref_t info) 1.303 +{ 1.304 + //CSFLogDebug( logTag, "In CCAPI_CallListener_onCallEvent"); 1.305 + CSF::CC_SIPCCService::onCallEvent(type, handle, info); 1.306 +} 1.307 + 1.308 + 1.309 + 1.310 +namespace CSF 1.311 +{ 1.312 + 1.313 +CC_SIPCCService* CC_SIPCCService::_self = nullptr; 1.314 + 1.315 +CC_SIPCCService::CC_SIPCCService() 1.316 +: loggingMask(0), 1.317 + bCreated(false), 1.318 + bStarted(false), 1.319 + m_lock("CC_SIPCCService"), 1.320 + bUseConfig(false) 1.321 +{ 1.322 + // Only one instance allowed! 1.323 + assert(_self == nullptr); 1.324 + _self = this; 1.325 + // <emannion> Commented as part of media provider removal 1.326 + //vcmMediaBridge.setStreamObserver(this); 1.327 + //vcmMediaBridge.setMediaProviderObserver(this); 1.328 +} 1.329 + 1.330 +CC_SIPCCService::~CC_SIPCCService() 1.331 +{ 1.332 + destroy(); 1.333 + 1.334 + _self = nullptr; 1.335 +} 1.336 + 1.337 +bool CC_SIPCCService::init(const std::string& user, const std::string& password, const std::string& domain, const std::string& device) 1.338 +{ 1.339 + sipUser = user; 1.340 + sipPassword = password; 1.341 + sipDomain = domain; 1.342 + deviceName = device; 1.343 + 1.344 + if (!(bCreated = (CCAPI_Service_create() == CC_SUCCESS))) 1.345 + { 1.346 + CSFLogError( logTag, "Call to CCAPI_Service_create() failed."); 1.347 + return false; 1.348 + } 1.349 + return true; 1.350 +} 1.351 + 1.352 +void CC_SIPCCService::destroy() 1.353 +{ 1.354 + stop(); 1.355 + 1.356 + if (bCreated) 1.357 + { 1.358 + if (CCAPI_Service_destroy() == CC_FAILURE) 1.359 + { 1.360 + CSFLogError( logTag, "Call to CCAPI_Service_destroy() failed."); 1.361 + } 1.362 + 1.363 + bCreated = false; 1.364 + } 1.365 + 1.366 + deviceName = ""; 1.367 + loggingMask = 0; 1.368 + 1.369 + CC_SIPCCDevice::reset(); 1.370 + CC_SIPCCDeviceInfo::reset(); 1.371 + CC_SIPCCFeatureInfo::reset(); 1.372 + CC_SIPCCCallServerInfo::reset(); 1.373 + CC_SIPCCLine::reset(); 1.374 + CC_SIPCCLineInfo::reset(); 1.375 + CC_SIPCCCall::reset(); 1.376 + CC_SIPCCCallInfo::reset(); 1.377 + 1.378 + if(audioControlWrapper != nullptr) 1.379 + { 1.380 + audioControlWrapper->setAudioControl(nullptr); 1.381 + } 1.382 + if(videoControlWrapper != nullptr) 1.383 + { 1.384 + videoControlWrapper->setVideoControl(nullptr); 1.385 + } 1.386 +} 1.387 + 1.388 +void CC_SIPCCService::setDeviceName(const std::string& deviceName) 1.389 +{ 1.390 + this->deviceName = deviceName; 1.391 +} 1.392 + 1.393 +void CC_SIPCCService::setLoggingMask(int mask) 1.394 +{ 1.395 + this->loggingMask = mask; 1.396 +} 1.397 + 1.398 +void CC_SIPCCService::setLocalAddressAndGateway(const std::string& localAddress, 1.399 + const std::string& defaultGW) 1.400 +{ 1.401 + this->localAddress = localAddress; 1.402 + this->defaultGW = defaultGW; 1.403 + 1.404 + CCAPI_Device_IP_Update(CCAPI_Device_getDeviceID(), localAddress.c_str(), "", 0, 1.405 + localAddress.c_str(), "", 0); 1.406 + 1.407 + AudioTermination* audio = VcmSIPCCBinding::getAudioTermination(); 1.408 + if(audio != nullptr) 1.409 + { 1.410 + audio->setLocalIP(localAddress.c_str()); 1.411 + } 1.412 + VideoTermination* video = VcmSIPCCBinding::getVideoTermination(); 1.413 + if(video != nullptr) 1.414 + { 1.415 + video->setLocalIP(localAddress.c_str()); 1.416 + } 1.417 +} 1.418 + 1.419 +/* 1.420 + * New function to start sip stack without device file download. 1.421 + */ 1.422 +bool CC_SIPCCService::startService() 1.423 +{ 1.424 + AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination(); 1.425 + VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination(); 1.426 + 1.427 + if(pAudio != nullptr) 1.428 + { 1.429 + pAudio->setMediaPorts(16384, 32766); 1.430 + pAudio->setDSCPValue(184); 1.431 + pAudio->setVADEnabled(false); 1.432 + } 1.433 + 1.434 + if (pVideo != nullptr) 1.435 + { 1.436 + pVideo->setDSCPValue(136); 1.437 + } 1.438 + 1.439 + bUseConfig = false; 1.440 + if (!(bStarted = (CCAPI_Service_start() == CC_SUCCESS))) 1.441 + { 1.442 + CSFLogError( logTag, "Call to CCAPI_Service_start() failed."); 1.443 + return false; 1.444 + } 1.445 + 1.446 + CC_DevicePtr devicePtr = CC_SIPCCDevice::createDevice (); 1.447 + if (devicePtr == nullptr) 1.448 + { 1.449 + CSFLogWarn( logTag, "stopping because createDevice failed"); 1.450 + stop(); 1.451 + return false; 1.452 + } 1.453 + CSFLogDebug( logTag, "About to imposeLoggingMask"); 1.454 + applyLoggingMask(loggingMask); 1.455 + 1.456 + return true; 1.457 +} 1.458 + 1.459 + 1.460 +void CC_SIPCCService::stop() 1.461 +{ 1.462 + if (bStarted) 1.463 + { 1.464 + // But first, tear down all existing calls. 1.465 + endAllActiveCalls(); 1.466 + 1.467 + if (CCAPI_Service_stop() == CC_FAILURE) 1.468 + { 1.469 + CSFLogError( logTag, "Call to CCAPI_Service_stop() failed."); 1.470 + } 1.471 + 1.472 + bStarted = false; 1.473 + } 1.474 +} 1.475 + 1.476 +bool CC_SIPCCService::isStarted() 1.477 +{ 1.478 + return bStarted; 1.479 +} 1.480 + 1.481 +// !!! Note that accessing *Ptr instances from multiple threads can 1.482 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.483 +// method are not safe except from ccapp_thread. 1.484 +CC_DevicePtr CC_SIPCCService::getActiveDevice() 1.485 +{ 1.486 + return CC_SIPCCDevice::wrap(CCAPI_Device_getDeviceID()).get(); 1.487 +} 1.488 + 1.489 +// !!! Note that accessing *Ptr instances from multiple threads can 1.490 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.491 +// method are not safe except from ccapp_thread. 1.492 +vector<CC_DevicePtr> CC_SIPCCService::getDevices() 1.493 +{ 1.494 + vector<CC_DevicePtr> devices; 1.495 + 1.496 + CC_SIPCCDevicePtr pDevice = CC_SIPCCDevice::wrap(CCAPI_Device_getDeviceID()); 1.497 + if(pDevice != nullptr) 1.498 + { 1.499 + devices.push_back(pDevice.get()); 1.500 + } 1.501 + 1.502 + return devices; 1.503 +} 1.504 + 1.505 +// !!! Note that accessing *Ptr instances from multiple threads can 1.506 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.507 +// method are not safe except from ccapp_thread. 1.508 +AudioControlPtr CC_SIPCCService::getAudioControl () 1.509 +{ 1.510 + if(audioControlWrapper != nullptr) 1.511 + { 1.512 + return audioControlWrapper.get(); 1.513 + } 1.514 + else 1.515 + { 1.516 + audioControlWrapper = AudioControlWrapperPtr(new AudioControlWrapper(VcmSIPCCBinding::getAudioControl())); 1.517 + return audioControlWrapper.get(); 1.518 + } 1.519 +} 1.520 + 1.521 +// !!! Note that accessing *Ptr instances from multiple threads can 1.522 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.523 +// method are not safe except from ccapp_thread. 1.524 +VideoControlPtr CC_SIPCCService::getVideoControl () 1.525 +{ 1.526 + if(videoControlWrapper != nullptr) 1.527 + { 1.528 + return videoControlWrapper.get(); 1.529 + } 1.530 + else 1.531 + { 1.532 + videoControlWrapper = VideoControlWrapperPtr(new VideoControlWrapper(VcmSIPCCBinding::getVideoControl())); 1.533 + return videoControlWrapper.get(); 1.534 + } 1.535 +} 1.536 + 1.537 + 1.538 +void CC_SIPCCService::applyLoggingMask (int newMask) 1.539 +{ 1.540 + if (newMask >> _maxBitValueMaskedLoggingEntries > 0) 1.541 + { 1.542 + CSFLogWarn( logTag, "Value of 0x%x specified for mask includes at least one bit value that exceeds the maximum supported bitfield value. " 1.543 + "Ignoring unsupported bits.", newMask); 1.544 + } 1.545 + 1.546 + CSFLogDebug( logTag, "Applying a sipcc log mask = %d", newMask); 1.547 + 1.548 + loggingMask = newMask & (HAS_21_BITS); 1.549 + 1.550 + for (int i=0; i<_maxBitValueMaskedLoggingEntries; i++) 1.551 + { 1.552 + *(_maskedLoggingEntriesArray[i]) = (loggingMask >> i) & 0x1; 1.553 + } 1.554 +} 1.555 + 1.556 +// !!! Note that accessing *Ptr instances from multiple threads can 1.557 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.558 +// method are not safe except from ccapp_thread. 1.559 +void CC_SIPCCService::endAllActiveCalls() 1.560 +{ 1.561 + CC_DevicePtr device = getActiveDevice(); 1.562 + if(device != nullptr) 1.563 + { 1.564 + CC_DeviceInfoPtr deviceInfo = device->getDeviceInfo(); 1.565 + vector<CC_CallPtr> calls = deviceInfo->getCalls(); 1.566 + CSFLogInfo( logTag, "endAllActiveCalls(): %lu calls to be ended.", calls.size()); 1.567 + for(vector<CC_CallPtr>::iterator it = calls.begin(); it != calls.end(); it++) 1.568 + { 1.569 + // For each active call, if it can be ended, do so. 1.570 + CC_CallPtr call = *it; 1.571 + CC_CallInfoPtr callInfo = call->getCallInfo(); 1.572 + if(callInfo->hasCapability(CC_CallCapabilityEnum::canEndCall)) 1.573 + { 1.574 + CSFLogDebug( logTag, "endAllActiveCalls(): ending call %s -> %s [%s]", 1.575 + callInfo->getCallingPartyNumber().c_str(), 1.576 + callInfo->getCalledPartyNumber().c_str(), 1.577 + call_state_getname(callInfo->getCallState())); 1.578 + call->endCall(); 1.579 + } 1.580 + else if(callInfo->hasCapability(CC_CallCapabilityEnum::canResume) && callInfo->getCallState() != REMHOLD) 1.581 + { 1.582 + CSFLogDebug( logTag, "endAllActiveCalls(): resume then ending call %s -> %s, [%s]", 1.583 + callInfo->getCallingPartyNumber().c_str(), 1.584 + callInfo->getCalledPartyNumber().c_str(), 1.585 + call_state_getname(callInfo->getCallState())); 1.586 + call->muteAudio(); 1.587 + call->resume(callInfo->getVideoDirection()); 1.588 + call->endCall(); 1.589 + } 1.590 + } 1.591 + 1.592 + if(!calls.empty()) 1.593 + { 1.594 +#ifdef MOZILLA_INTERNAL_API 1.595 + // If we had any calls, allow a short time for the SIP messaging to go out 1.596 + PlatformThread::Sleep(500); 1.597 +#endif 1.598 + } 1.599 + } 1.600 +} 1.601 + 1.602 + 1.603 +// C++ Event Handlers 1.604 +void CC_SIPCCService::onDeviceEvent(ccapi_device_event_e type, cc_device_handle_t handle, cc_deviceinfo_ref_t info) 1.605 +{ 1.606 + if (_self == nullptr) 1.607 + { 1.608 + CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of device event."); 1.609 + return; 1.610 + } 1.611 + 1.612 + mozilla::MutexAutoLock lock(_self->m_lock); 1.613 + 1.614 + CC_SIPCCDevicePtr devicePtr = CC_SIPCCDevice::wrap(handle); 1.615 + if (devicePtr == nullptr) 1.616 + { 1.617 + CSFLogError( logTag, "Unable to notify device observers for device handle (%u), as failed to create CC_DevicePtr", handle); 1.618 + return; 1.619 + } 1.620 + 1.621 + CC_SIPCCDeviceInfoPtr infoPtr = CC_SIPCCDeviceInfo::wrap(info); 1.622 + if (infoPtr == nullptr) 1.623 + { 1.624 + CSFLogError( logTag, "Unable to notify call observers for device handle (%u), as failed to create CC_DeviceInfoPtr", handle); 1.625 + return; 1.626 + } 1.627 + 1.628 + CSFLogInfo( logTag, "onDeviceEvent( %s, %s, [%s] )", 1.629 + device_event_getname(type), 1.630 + devicePtr->toString().c_str(), 1.631 + infoPtr->getDeviceName().c_str()); 1.632 + _self->notifyDeviceEventObservers(type, devicePtr.get(), infoPtr.get()); 1.633 +} 1.634 + 1.635 +void CC_SIPCCService::onFeatureEvent(ccapi_device_event_e type, cc_deviceinfo_ref_t /* device_info */, cc_featureinfo_ref_t feature_info) 1.636 +{ 1.637 + 1.638 + if (_self == nullptr) 1.639 + { 1.640 + CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of device event."); 1.641 + return; 1.642 + } 1.643 + 1.644 + mozilla::MutexAutoLock lock(_self->m_lock); 1.645 + 1.646 + cc_device_handle_t hDevice = CCAPI_Device_getDeviceID(); 1.647 + CC_DevicePtr devicePtr = CC_SIPCCDevice::wrap(hDevice).get(); 1.648 + if (devicePtr == nullptr) 1.649 + { 1.650 + CSFLogError( logTag, "Unable to notify device observers for device handle (%u), as failed to create CC_DevicePtr", hDevice); 1.651 + return; 1.652 + } 1.653 + 1.654 + CC_FeatureInfoPtr infoPtr = CC_SIPCCFeatureInfo::wrap(feature_info).get(); 1.655 + if (infoPtr == nullptr) 1.656 + { 1.657 + CSFLogError( logTag, "Unable to notify call observers for feature info handle (%p), as failed to create CC_FeatureInfoPtr", feature_info); 1.658 + return; 1.659 + } 1.660 + 1.661 + CSFLogInfo( logTag, "onFeatureEvent( %s, %s, [%s] )", 1.662 + device_event_getname(type), 1.663 + devicePtr->toString().c_str(), 1.664 + infoPtr->getDisplayName().c_str()); 1.665 + _self->notifyFeatureEventObservers(type, devicePtr, infoPtr); 1.666 +} 1.667 + 1.668 +void CC_SIPCCService::onLineEvent(ccapi_line_event_e eventType, cc_lineid_t line, cc_lineinfo_ref_t info) 1.669 +{ 1.670 + if (_self == nullptr) 1.671 + { 1.672 + CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of line event."); 1.673 + return; 1.674 + } 1.675 + 1.676 + mozilla::MutexAutoLock lock(_self->m_lock); 1.677 + 1.678 + CC_LinePtr linePtr = CC_SIPCCLine::wrap(line).get(); 1.679 + if (linePtr == nullptr) 1.680 + { 1.681 + CSFLogError( logTag, "Unable to notify line observers for line lineId (%u), as failed to create CC_LinePtr", line); 1.682 + return; 1.683 + } 1.684 + 1.685 + CC_LineInfoPtr infoPtr = CC_SIPCCLineInfo::wrap(info).get(); 1.686 + if (infoPtr == nullptr) 1.687 + { 1.688 + CSFLogError( logTag, "Unable to notify line observers for line lineId (%u), as failed to create CC_LineInfoPtr", line); 1.689 + return; 1.690 + } 1.691 + 1.692 + CSFLogInfo( logTag, "onLineEvent(%s, %s, [%s|%s]", 1.693 + line_event_getname(eventType), linePtr->toString().c_str(), 1.694 + infoPtr->getNumber().c_str(), (infoPtr->getRegState() ? "INS" : "OOS")); 1.695 + _self->notifyLineEventObservers(eventType, linePtr, infoPtr); 1.696 +} 1.697 + 1.698 +void CC_SIPCCService::onCallEvent(ccapi_call_event_e eventType, cc_call_handle_t handle, cc_callinfo_ref_t info) 1.699 +{ 1.700 + if (_self == nullptr) 1.701 + { 1.702 + CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of call event."); 1.703 + return; 1.704 + } 1.705 + 1.706 + mozilla::MutexAutoLock lock(_self->m_lock); 1.707 + 1.708 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(handle); 1.709 + if (callPtr == nullptr) 1.710 + { 1.711 + CSFLogError( logTag, "Unable to notify call observers for call handle (%u), as failed to create CC_CallPtr", handle); 1.712 + return; 1.713 + } 1.714 + 1.715 + CC_SIPCCCallInfoPtr infoPtr = CC_SIPCCCallInfo::wrap(info); 1.716 + if (infoPtr == nullptr) 1.717 + { 1.718 + CSFLogError( logTag, "Unable to notify call observers for call handle (%u), as failed to create CC_CallInfoPtr", handle); 1.719 + return; 1.720 + } 1.721 + 1.722 + infoPtr->setMediaData(callPtr->getMediaData()); 1.723 + 1.724 + set<CSF::CC_CallCapabilityEnum::CC_CallCapability> capSet = infoPtr->getCapabilitySet(); 1.725 + CSFLogInfo( logTag, "onCallEvent(%s, %s, [%s|%s]", 1.726 + call_event_getname(eventType), callPtr->toString().c_str(), 1.727 + call_state_getname(infoPtr->getCallState()), CC_CallCapabilityEnum::toString(capSet).c_str()); 1.728 + _self->notifyCallEventObservers(eventType, callPtr.get(), infoPtr.get()); 1.729 + 1.730 + // To prevent leaking CC_SIPCCCalls, we remove them from the wrapper 1.731 + // map when the call event information indicates an "on hook" event. 1.732 + if (infoPtr->getCallState() == ONHOOK) { 1.733 + CSFLogDebug( logTag, "Removing call info from wrapper map (handle=%u)", 1.734 + handle); 1.735 + CC_SIPCCCall::release(handle); 1.736 + } 1.737 + 1.738 + // Once the call info is dispatched to the observers, we never need to 1.739 + // refer to it again. The next operation will contain its own unique info. 1.740 + CC_SIPCCCallInfo::release(info); 1.741 +} 1.742 + 1.743 +void CC_SIPCCService::addCCObserver ( CC_Observer * observer ) 1.744 +{ 1.745 + mozilla::MutexAutoLock lock(m_lock); 1.746 + if (observer == nullptr) 1.747 + { 1.748 + CSFLogError( logTag, "NULL value for \"observer\" passed to addCCObserver()."); 1.749 + return; 1.750 + } 1.751 + 1.752 + ccObservers.insert(observer); 1.753 +} 1.754 + 1.755 +void CC_SIPCCService::removeCCObserver ( CC_Observer * observer ) 1.756 +{ 1.757 + mozilla::MutexAutoLock lock(m_lock); 1.758 + ccObservers.erase(observer); 1.759 +} 1.760 + 1.761 +//Notify Observers 1.762 +void CC_SIPCCService::notifyDeviceEventObservers (ccapi_device_event_e eventType, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info) 1.763 +{ 1.764 + // m_lock must be held by the function that called us 1.765 + set<CC_Observer*>::const_iterator it = ccObservers.begin(); 1.766 + for ( ; it != ccObservers.end(); it++ ) 1.767 + { 1.768 + (*it)->onDeviceEvent(eventType, devicePtr, info); 1.769 + } 1.770 +} 1.771 + 1.772 +void CC_SIPCCService::notifyFeatureEventObservers (ccapi_device_event_e eventType, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info) 1.773 +{ 1.774 + // m_lock must be held by the function that called us 1.775 + set<CC_Observer*>::const_iterator it = ccObservers.begin(); 1.776 + for ( ; it != ccObservers.end(); it++ ) 1.777 + { 1.778 + (*it)->onFeatureEvent(eventType, devicePtr, info); 1.779 + } 1.780 +} 1.781 + 1.782 +void CC_SIPCCService::notifyLineEventObservers (ccapi_line_event_e eventType, CC_LinePtr linePtr, CC_LineInfoPtr info) 1.783 +{ 1.784 + // m_lock must be held by the function that called us 1.785 + set<CC_Observer*>::const_iterator it = ccObservers.begin(); 1.786 + for ( ; it != ccObservers.end(); it++ ) 1.787 + { 1.788 + (*it)->onLineEvent(eventType, linePtr, info); 1.789 + } 1.790 +} 1.791 + 1.792 +void CC_SIPCCService::notifyCallEventObservers (ccapi_call_event_e eventType, CC_CallPtr callPtr, CC_CallInfoPtr info) 1.793 +{ 1.794 + // m_lock must be held by the function that called us 1.795 + set<CC_Observer*>::const_iterator it = ccObservers.begin(); 1.796 + for ( ; it != ccObservers.end(); it++ ) 1.797 + { 1.798 + (*it)->onCallEvent(eventType, callPtr, info); 1.799 + } 1.800 +} 1.801 + 1.802 +// This is called when the SIP stack has caused a new stream to be allocated. This function will 1.803 +// find the call associated with that stream so that the call can store the streamId. 1.804 + 1.805 +// !!! Note that accessing *Ptr instances from multiple threads can 1.806 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.807 +// method are not safe except from ccapp_thread. 1.808 +void CC_SIPCCService::registerStream(cc_call_handle_t call, int streamId, bool isVideo) 1.809 +{ 1.810 + CSFLogDebug( logTag, "registerStream for call: %d strId=%d video=%s", 1.811 + call, streamId, isVideo ? "TRUE" : "FALSE"); 1.812 + // get the object corresponding to the handle 1.813 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call); 1.814 + if (callPtr != nullptr) 1.815 + { 1.816 + callPtr->addStream(streamId, isVideo); 1.817 + } 1.818 + else 1.819 + { 1.820 + CSFLogError( logTag, "registerStream(), No call found for allocated Stream: %d, %s", 1.821 + streamId, isVideo ? "TRUE" : "FALSE"); 1.822 + } 1.823 +} 1.824 + 1.825 +// !!! Note that accessing *Ptr instances from multiple threads can 1.826 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.827 +// method are not safe except from ccapp_thread. 1.828 +void CC_SIPCCService::deregisterStream(cc_call_handle_t call, int streamId) 1.829 +{ 1.830 + // get the object corresponding to the handle 1.831 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call); 1.832 + if (callPtr != nullptr) 1.833 + { 1.834 + callPtr->removeStream(streamId); 1.835 + } 1.836 + else 1.837 + { 1.838 + CSFLogError( logTag, "deregisterStream(), No call found for deallocated Stream: %d", streamId); 1.839 + } 1.840 +} 1.841 + 1.842 +// !!! Note that accessing *Ptr instances from multiple threads can 1.843 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.844 +// method are not safe except from ccapp_thread. 1.845 +void CC_SIPCCService::dtmfBurst(int digit, int direction, int duration) 1.846 +{ 1.847 + // We haven't a clue what stream to use. Search for a call which has an audio stream. 1.848 + vector<CC_SIPCCCallPtr> calls; 1.849 + { 1.850 + // First build a list of all the calls. 1.851 + cc_deviceinfo_ref_t deviceInfoRef = CCAPI_Device_getDeviceInfo(CCAPI_Device_getDeviceID()); 1.852 + cc_call_handle_t handles[MAX_SUPPORTED_NUM_CALLS] = {}; 1.853 + cc_uint16_t numHandles = csf_countof(handles); 1.854 + 1.855 + CCAPI_DeviceInfo_getCalls(deviceInfoRef, handles, &numHandles); 1.856 + 1.857 + for (int i=0; i<numHandles; i++) 1.858 + { 1.859 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(handles[i]); 1.860 + calls.push_back(callPtr); 1.861 + } 1.862 + CCAPI_Device_releaseDeviceInfo(deviceInfoRef); 1.863 + } 1.864 + 1.865 + // Using the list of all calls, search for those containing an audio stream. 1.866 + // Send a DTMF digit on the first one we find. 1.867 + 1.868 + AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination(); 1.869 + bool bSent = false; 1.870 + for(vector<CC_SIPCCCallPtr>::iterator it = calls.begin(); it != calls.end() && !bSent; it++) 1.871 + { 1.872 + CC_SIPCCCallMediaDataPtr pMediaData = (*it)->getMediaData(); 1.873 + 1.874 + mozilla::MutexAutoLock lock(pMediaData->streamMapMutex); 1.875 + for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) 1.876 + { 1.877 + if (entry->second.isVideo == false) 1.878 + { 1.879 + // first is the streamId 1.880 + if (pAudio->sendDtmf(entry->first, digit)) 1.881 + { 1.882 + // We have sent a digit, done. 1.883 + bSent = true; 1.884 + break; 1.885 + } 1.886 + else 1.887 + { 1.888 + CSFLogWarn( logTag, "dtmfBurst:sendDtmf returned fail"); 1.889 + } 1.890 + } 1.891 + } 1.892 + } 1.893 +} 1.894 + 1.895 +// !!! Note that accessing *Ptr instances from multiple threads can 1.896 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.897 +// method are not safe except from ccapp_thread. 1.898 +void CC_SIPCCService::sendIFrame(cc_call_handle_t call_handle) 1.899 +{ 1.900 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call_handle); 1.901 + CC_SIPCCCallMediaDataPtr pMediaData=callPtr->getMediaData(); 1.902 + if (pMediaData != nullptr) 1.903 + { 1.904 + for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) 1.905 + { 1.906 + if (entry->second.isVideo == true) 1.907 + { 1.908 + VcmSIPCCBinding::getVideoTermination()->sendIFrame( entry->first ); 1.909 + } 1.910 + } 1.911 + } 1.912 +} 1.913 + 1.914 +bool CC_SIPCCService::isValidMediaPortRange(int mediaStartPort, int mediaEndPort) 1.915 +{ 1.916 + if(mediaStartPort < 1024 || 1.917 + mediaStartPort > 65535 || 1.918 + mediaEndPort < 1024 || 1.919 + mediaEndPort > 65535 || 1.920 + mediaEndPort - mediaStartPort < 3) 1.921 + { 1.922 + return false; 1.923 + } 1.924 + else 1.925 + { 1.926 + return true; 1.927 + } 1.928 +} 1.929 + 1.930 +bool CC_SIPCCService::isValidDSCPValue(int value) 1.931 +{ 1.932 + //value is 8-bit value, but the two least significant bits are unused, 1.933 + //leaving an effective 6 bits of information. Valid values are therefore 1.934 + //all multiples of 4 that lie between 0 and 252 inclusive. 1.935 + if(value >= 0 && 1.936 + value <= 252 && 1.937 + value % 4 == 0) 1.938 + { 1.939 + return true; 1.940 + } 1.941 + else 1.942 + { 1.943 + return false; 1.944 + } 1.945 +} 1.946 + 1.947 +void CC_SIPCCService::onVideoModeChanged( bool enable ) 1.948 +{ 1.949 +} 1.950 + 1.951 +// !!! Note that accessing *Ptr instances from multiple threads can 1.952 +// lead to deadlocks, crashes, and spinning threads. Calls to this 1.953 +// method are not safe except from ccapp_thread. 1.954 +void CC_SIPCCService::onKeyFrameRequested( int stream ) 1.955 +// This is called when the Video Provider indicates that it needs to send a request for new key frame to the sender 1.956 +{ 1.957 + CSFLogDebug(logTag, "onKeyFrameRequested for stream "); 1.958 + // We haven't a clue what stream to use. Search for a call which has an audio stream. 1.959 + vector<CC_SIPCCCallPtr> calls; 1.960 + { 1.961 + // First build a list of all the calls. 1.962 + cc_deviceinfo_ref_t deviceInfoRef = CCAPI_Device_getDeviceInfo(CCAPI_Device_getDeviceID()); 1.963 + cc_call_handle_t handles[MAX_SUPPORTED_NUM_CALLS] = {}; 1.964 + cc_uint16_t numHandles = csf_countof(handles); 1.965 + 1.966 + CCAPI_DeviceInfo_getCalls(deviceInfoRef, handles, &numHandles); 1.967 + 1.968 + for (int i=0; i<numHandles; i++) 1.969 + { 1.970 + CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(handles[i]); 1.971 + //CC_SIPCCCallPtr callPtr = wrapCall(handles[i]); 1.972 + calls.push_back(callPtr); 1.973 + } 1.974 + CCAPI_Device_releaseDeviceInfo(deviceInfoRef); 1.975 + } 1.976 + 1.977 + // Using the list of all calls, search for those containing an video stream. 1.978 + // Send the send info SIP message when we find the one with the correct stream id. 1.979 + 1.980 + bool bSent = false; 1.981 + for(vector<CC_SIPCCCallPtr>::iterator it = calls.begin(); it != calls.end() && !bSent; it++) 1.982 + { 1.983 + CC_SIPCCCallMediaDataPtr pMediaData = (*it)->getMediaData(); 1.984 + 1.985 + mozilla::MutexAutoLock lock(pMediaData->streamMapMutex); 1.986 + for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) 1.987 + { 1.988 + if ((entry->first==stream) && (entry->second.isVideo == true)) 1.989 + { 1.990 + CSFLogDebug(logTag, "Send SIP message to originator for stream id %d", stream); 1.991 + if ((*it)->sendInfo ( "","application/media_control+xml", "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" 1.992 + "<media_control>\n" 1.993 + "\n" 1.994 + " <vc_primitive>\n" 1.995 + " <to_encoder>\n" 1.996 + " <picture_fast_update/>\n" 1.997 + " </to_encoder>\n" 1.998 + " </vc_primitive>\n" 1.999 + "\n" 1.1000 + "</media_control>\n")) 1.1001 + { 1.1002 + CSFLogWarn(logTag, "sendinfo returned true"); 1.1003 + bSent = true; 1.1004 + break; 1.1005 + } 1.1006 + else 1.1007 + { 1.1008 + CSFLogWarn(logTag, "sendinfo returned false"); 1.1009 + } 1.1010 + } 1.1011 + } 1.1012 + } 1.1013 +} 1.1014 + 1.1015 +void CC_SIPCCService::onMediaLost( int callId ) 1.1016 +{ 1.1017 +} 1.1018 + 1.1019 +void CC_SIPCCService::onMediaRestored( int callId ) 1.1020 +{ 1.1021 +} 1.1022 + 1.1023 +bool CC_SIPCCService::setLocalVoipPort(int port) { 1.1024 + return CCAPI_Config_set_local_voip_port(port); 1.1025 +} 1.1026 + 1.1027 +bool CC_SIPCCService::setRemoteVoipPort(int port) { 1.1028 + return CCAPI_Config_set_remote_voip_port(port); 1.1029 +} 1.1030 + 1.1031 +bool CC_SIPCCService::setP2PMode(bool mode) { 1.1032 + return CCAPI_Config_set_p2p_mode(mode); 1.1033 +} 1.1034 + 1.1035 +bool CC_SIPCCService::setSDPMode(bool mode) { 1.1036 + return CCAPI_Config_set_sdp_mode(mode); 1.1037 +} 1.1038 + 1.1039 +} // End of namespace CSF