michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef _WIN32 michael@0: #include //plat_api.h seems to need some of the types defined in Windows.h (e.g. boolean) michael@0: #endif michael@0: michael@0: #include "CSFLog.h" michael@0: michael@0: #include "CC_CallTypes.h" michael@0: #include "CC_SIPCCService.h" michael@0: #include "NullDeleter.h" michael@0: #include "CC_SIPCCDevice.h" michael@0: #include "CC_SIPCCDeviceInfo.h" michael@0: #include "CC_SIPCCFeatureInfo.h" michael@0: #include "CC_SIPCCCallServerInfo.h" michael@0: #include "CC_SIPCCCall.h" michael@0: #include "CC_SIPCCCallInfo.h" michael@0: #include "CC_SIPCCLine.h" michael@0: #include "CC_SIPCCLineInfo.h" michael@0: #include "CSFMediaProvider.h" michael@0: #include "CSFAudioTermination.h" michael@0: #include "CSFVideoTermination.h" michael@0: michael@0: #include "base/platform_thread.h" michael@0: #include "base/time.h" michael@0: michael@0: extern "C" { michael@0: #include "ccapi_device.h" michael@0: } michael@0: #include "debug-psipcc-types.h" michael@0: #include "VcmSIPCCBinding.h" michael@0: michael@0: #include "csf_common.h" michael@0: michael@0: static const char* logTag = "CC_SIPCCService"; michael@0: michael@0: using namespace std; michael@0: michael@0: #define MAX_SUPPORTED_NUM_CALLS 100 michael@0: #define MAX_SUPPORTED_NUM_LINES 100 michael@0: #define MAX_SUPPORTED_NUM_FEATURES 100 michael@0: #define MAX_SUPPORTED_NUM_CALL_SERVERS 100 michael@0: michael@0: extern "C" michael@0: { michael@0: #include "cpr_types.h" michael@0: #include "ccapi_device.h" michael@0: #include "ccapi_device_info.h" michael@0: #include "ccapi_call.h" michael@0: michael@0: #include "cpr_stdio.h" michael@0: #include "config_api.h" michael@0: #include "ccapi_service.h" michael@0: #include "plat_api.h" michael@0: michael@0: /** michael@0: * configCtlFetchReq michael@0: * michael@0: * This function tells the config manager to fetch the CTL file michael@0: * and then fetch the config from the CUCM. It is expected that michael@0: * this will result in processing of michael@0: * the config file after the config managers response is received. michael@0: * michael@0: * The response received for this request is asynchronous and michael@0: * should be handled via event provided by config manager. michael@0: * The CCAPI_Config_reponse api needs to be called for the michael@0: * handling of the response to the fetch request michael@0: * michael@0: */ michael@0: void configCtlFetchReq(int device_handle) michael@0: { michael@0: CSFLogDebug(logTag, "In configCtlFetchReq"); michael@0: michael@0: CSF::CC_SIPCCService * pPhone = CSF::CC_SIPCCService::_self; michael@0: michael@0: if (pPhone == nullptr) michael@0: { michael@0: CSFLogError( logTag, "CC_SIPCCService::_self is NULL."); michael@0: } michael@0: else michael@0: { michael@0: CCAPI_Start_response(device_handle, pPhone->deviceName.c_str(), pPhone->sipUser.c_str(), michael@0: pPhone->sipPassword.c_str(), pPhone->sipDomain.c_str()); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * configFetchReq michael@0: * michael@0: * This function tells the config manager to fetch the latest config michael@0: * from the CUCM. It is expected that this will result in processing of michael@0: * the config file after the config managers response is received. michael@0: * michael@0: * The response received for this request is asynchronous and michael@0: * should be handled via event provided by config manager. michael@0: * The CCAPI_Config_reponse api needs to be called for the michael@0: * handling of the response to the fetch request michael@0: * michael@0: * There are cases where only the config file is needed, for eg: during michael@0: * Apply Config, for those situation we use this API michael@0: * michael@0: */ michael@0: void configFetchReq(int device_handle) michael@0: { michael@0: CSFLogDebug( logTag, "In configFetchReq"); michael@0: michael@0: configCtlFetchReq(device_handle); michael@0: } michael@0: michael@0: /** michael@0: * configParserError michael@0: * michael@0: * Notify the config manager that the config file has an error michael@0: * and a new config file needs to be downloaded. michael@0: * michael@0: * The error could be XML format error or minimum config not being michael@0: * present in the config file. It is expected that michael@0: * this will result in processing of michael@0: * the config file after the config managers response is received. michael@0: * michael@0: */ michael@0: void configParserError(void) michael@0: { michael@0: CSFLogError( logTag, "In configParserError"); michael@0: } michael@0: michael@0: /** michael@0: * Inform application that pSipcc stack has receive a NOTIFY message of event michael@0: * type "service-control" and action=apply-config. The arguments passed to this michael@0: * function contains the parameter values received in the message. michael@0: * michael@0: * @param config_version [in] latest version stamp of phone configuration. michael@0: * @param dial_plan_version [in] latest version stamp of the dial plan. michael@0: * @param fcp_version [in] latest version stamp of feature policy control. michael@0: * @param cucm_result [in] action taken by the cucm for the changes applied by the michael@0: * user to the phone configuration. cucm result could be michael@0: * @li "no_change" - the new phone configuration changes do not impact Unified CM, michael@0: * @li "config_applied" - The Unified CM Administration applied the michael@0: * configuration changes dynamically without requiring phone to re-register, michael@0: * @li "reregister_needed" - The Unified CM Administration applied the michael@0: * configuration changes and required the phone to re-register to make them michael@0: * effective. michael@0: * @param load_id [in] - firmware image name that phone should be running with michael@0: * @param inactive_load_id [in] - firmware image name that phone should be in inactive partition. michael@0: * @param load_server [in] - address of load server to download the firmware michael@0: * image load_id. michael@0: * @param log_server [in] - log server address where error report need to be michael@0: * sent. Error report, for example, could be related to image download failure michael@0: * or phone configuration file download failure. michael@0: * @param ppid [in] whether peer to peer upgrade is available michael@0: * @return void michael@0: */ michael@0: void configApplyConfigNotify(cc_string_t config_version, michael@0: cc_string_t dial_plan_version, michael@0: cc_string_t fcp_version, michael@0: cc_string_t cucm_result, michael@0: cc_string_t load_id, michael@0: cc_string_t inactive_load_id, michael@0: cc_string_t load_server, michael@0: cc_string_t log_server, michael@0: cc_boolean ppid) michael@0: { michael@0: CSFLogDebug( logTag, "In configApplyConfigNotify"); michael@0: } michael@0: michael@0: char * platGetIPAddr () michael@0: { michael@0: CSFLogDebug( logTag, "In platGetIPAddr()"); michael@0: michael@0: CSF::CC_SIPCCService * pPhone = CSF::CC_SIPCCService::_self; michael@0: michael@0: if (pPhone == nullptr) michael@0: { michael@0: CSFLogError( logTag, "In platGetIPAddr(). CC_SIPCCService::_self is NULL."); michael@0: return (char *) ""; michael@0: } michael@0: michael@0: return (char*) pPhone->localAddress.c_str(); michael@0: } michael@0: michael@0: void ccmedia_flash_once_timer_callback (void) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * dialPlanFetchReq michael@0: * michael@0: * This function tells the get file request service to fetch the latest dial michael@0: * plan from the CUCM. michael@0: * michael@0: * @param device_handle [in] handle of the device, the response is for michael@0: * @param dialPlanFileName [in] the name of dialplan file to retrieve michael@0: * michael@0: */ michael@0: cc_boolean dialPlanFetchReq(int device_handle, char* dialPlanFileName) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: /** michael@0: * fcpFetchReq michael@0: * michael@0: * This function tells the get file request service to fetch the latest fcp michael@0: * file from the CUCM. michael@0: * michael@0: * @param device_handle [in] handle of the device, the response is for michael@0: * @param dialPlanFileName [in] the name of fcp file to retrieve michael@0: * michael@0: */ michael@0: cc_boolean fcpFetchReq(int device_handle, char* fcpFileName) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: extern cc_int32_t SipDebugMessage; michael@0: extern cc_int32_t SipDebugState; michael@0: extern cc_int32_t SipDebugTask; michael@0: extern cc_int32_t SipDebugRegState; michael@0: extern cc_int32_t GSMDebug; michael@0: extern cc_int32_t FIMDebug; michael@0: extern cc_int32_t LSMDebug; michael@0: extern cc_int32_t FSMDebugSM; michael@0: extern int32_t CSMDebugSM; michael@0: extern cc_int32_t CCDebug; michael@0: extern cc_int32_t CCDebugMsg; michael@0: extern cc_int32_t AuthDebug; michael@0: extern cc_int32_t ConfigDebug; michael@0: extern cc_int32_t DpintDebug; michael@0: extern cc_int32_t KpmlDebug; michael@0: extern cc_int32_t VCMDebug; michael@0: extern cc_int32_t g_CCAppDebug; michael@0: extern cc_int32_t g_CCLogDebug; michael@0: extern cc_int32_t TNPDebug; michael@0: michael@0: static cc_int32_t * _maskedLoggingEntriesArray[19] = { michael@0: &SipDebugMessage, //13 michael@0: &SipDebugState, //12 michael@0: &SipDebugTask, //11 michael@0: &SipDebugRegState, //14 michael@0: &GSMDebug, //7 michael@0: &FIMDebug, //4 michael@0: &LSMDebug, //8 michael@0: &FSMDebugSM, //5 michael@0: &CSMDebugSM, //?? michael@0: &CCDebug, //2 michael@0: &CCDebugMsg, //3 michael@0: &AuthDebug, //6 michael@0: &ConfigDebug, //0 michael@0: &DpintDebug, //18 michael@0: &KpmlDebug, //19 michael@0: &VCMDebug, //?? michael@0: &g_CCAppDebug, //0 michael@0: &g_CCLogDebug, //?? michael@0: &TNPDebug, //1 michael@0: }; michael@0: michael@0: //Following are not covered above. : michael@0: //g_cacDebug,9 michael@0: //g_dcsmDebug, 10 michael@0: //SipDebugTrx, 14 michael@0: //TMRDebug, 15 michael@0: //SipDebugDM, 16 michael@0: //g_DEFDebug, 17 michael@0: //g_blfDebug, 21 michael@0: //g_configappDebug, 23 michael@0: //CCEVENTDebug, 24 michael@0: //PLATDebug, 25 michael@0: michael@0: //If you add more to this array then you'll need to manually update "HAS_21_BITS" below to be "HAS_22_BITS" michael@0: //of whatever the new number of bits defined ends up as. Then modify the code that currently uses HAS_21_BITS michael@0: //below to use your new #define. michael@0: #define HAS_21_BITS 0x1FFFFF michael@0: michael@0: static int _maxBitValueMaskedLoggingEntries = csf_countof(_maskedLoggingEntriesArray);//Should be 21 michael@0: michael@0: michael@0: } //end extern C michael@0: michael@0: extern "C" void CCAPI_DeviceListener_onDeviceEvent(ccapi_device_event_e type, cc_device_handle_t hDevice, cc_deviceinfo_ref_t dev_info) michael@0: { michael@0: //CSFLogDebug( logTag, "In CCAPI_DeviceListener_onDeviceEvent"); michael@0: CSF::CC_SIPCCService::onDeviceEvent(type, hDevice, dev_info); michael@0: } michael@0: michael@0: extern "C" void CCAPI_DeviceListener_onFeatureEvent(ccapi_device_event_e type, cc_deviceinfo_ref_t dev_info, cc_featureinfo_ref_t feature_info) michael@0: { michael@0: //CSFLogDebug( logTag, "In CCAPI_DeviceListener_onFeatureEvent"); michael@0: CSF::CC_SIPCCService::onFeatureEvent(type, dev_info, feature_info); michael@0: } michael@0: michael@0: extern "C" void CCAPI_LineListener_onLineEvent(ccapi_line_event_e type, cc_lineid_t line, cc_lineinfo_ref_t info) michael@0: { michael@0: //CSFLogDebug( logTag, "In CCAPI_LineListener_onLineEvent"); michael@0: CSF::CC_SIPCCService::onLineEvent(type, line, info); michael@0: } michael@0: michael@0: extern "C" void CCAPI_CallListener_onCallEvent(ccapi_call_event_e type, cc_call_handle_t handle, cc_callinfo_ref_t info) michael@0: { michael@0: //CSFLogDebug( logTag, "In CCAPI_CallListener_onCallEvent"); michael@0: CSF::CC_SIPCCService::onCallEvent(type, handle, info); michael@0: } michael@0: michael@0: michael@0: michael@0: namespace CSF michael@0: { michael@0: michael@0: CC_SIPCCService* CC_SIPCCService::_self = nullptr; michael@0: michael@0: CC_SIPCCService::CC_SIPCCService() michael@0: : loggingMask(0), michael@0: bCreated(false), michael@0: bStarted(false), michael@0: m_lock("CC_SIPCCService"), michael@0: bUseConfig(false) michael@0: { michael@0: // Only one instance allowed! michael@0: assert(_self == nullptr); michael@0: _self = this; michael@0: // Commented as part of media provider removal michael@0: //vcmMediaBridge.setStreamObserver(this); michael@0: //vcmMediaBridge.setMediaProviderObserver(this); michael@0: } michael@0: michael@0: CC_SIPCCService::~CC_SIPCCService() michael@0: { michael@0: destroy(); michael@0: michael@0: _self = nullptr; michael@0: } michael@0: michael@0: bool CC_SIPCCService::init(const std::string& user, const std::string& password, const std::string& domain, const std::string& device) michael@0: { michael@0: sipUser = user; michael@0: sipPassword = password; michael@0: sipDomain = domain; michael@0: deviceName = device; michael@0: michael@0: if (!(bCreated = (CCAPI_Service_create() == CC_SUCCESS))) michael@0: { michael@0: CSFLogError( logTag, "Call to CCAPI_Service_create() failed."); michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void CC_SIPCCService::destroy() michael@0: { michael@0: stop(); michael@0: michael@0: if (bCreated) michael@0: { michael@0: if (CCAPI_Service_destroy() == CC_FAILURE) michael@0: { michael@0: CSFLogError( logTag, "Call to CCAPI_Service_destroy() failed."); michael@0: } michael@0: michael@0: bCreated = false; michael@0: } michael@0: michael@0: deviceName = ""; michael@0: loggingMask = 0; michael@0: michael@0: CC_SIPCCDevice::reset(); michael@0: CC_SIPCCDeviceInfo::reset(); michael@0: CC_SIPCCFeatureInfo::reset(); michael@0: CC_SIPCCCallServerInfo::reset(); michael@0: CC_SIPCCLine::reset(); michael@0: CC_SIPCCLineInfo::reset(); michael@0: CC_SIPCCCall::reset(); michael@0: CC_SIPCCCallInfo::reset(); michael@0: michael@0: if(audioControlWrapper != nullptr) michael@0: { michael@0: audioControlWrapper->setAudioControl(nullptr); michael@0: } michael@0: if(videoControlWrapper != nullptr) michael@0: { michael@0: videoControlWrapper->setVideoControl(nullptr); michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::setDeviceName(const std::string& deviceName) michael@0: { michael@0: this->deviceName = deviceName; michael@0: } michael@0: michael@0: void CC_SIPCCService::setLoggingMask(int mask) michael@0: { michael@0: this->loggingMask = mask; michael@0: } michael@0: michael@0: void CC_SIPCCService::setLocalAddressAndGateway(const std::string& localAddress, michael@0: const std::string& defaultGW) michael@0: { michael@0: this->localAddress = localAddress; michael@0: this->defaultGW = defaultGW; michael@0: michael@0: CCAPI_Device_IP_Update(CCAPI_Device_getDeviceID(), localAddress.c_str(), "", 0, michael@0: localAddress.c_str(), "", 0); michael@0: michael@0: AudioTermination* audio = VcmSIPCCBinding::getAudioTermination(); michael@0: if(audio != nullptr) michael@0: { michael@0: audio->setLocalIP(localAddress.c_str()); michael@0: } michael@0: VideoTermination* video = VcmSIPCCBinding::getVideoTermination(); michael@0: if(video != nullptr) michael@0: { michael@0: video->setLocalIP(localAddress.c_str()); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * New function to start sip stack without device file download. michael@0: */ michael@0: bool CC_SIPCCService::startService() michael@0: { michael@0: AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination(); michael@0: VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination(); michael@0: michael@0: if(pAudio != nullptr) michael@0: { michael@0: pAudio->setMediaPorts(16384, 32766); michael@0: pAudio->setDSCPValue(184); michael@0: pAudio->setVADEnabled(false); michael@0: } michael@0: michael@0: if (pVideo != nullptr) michael@0: { michael@0: pVideo->setDSCPValue(136); michael@0: } michael@0: michael@0: bUseConfig = false; michael@0: if (!(bStarted = (CCAPI_Service_start() == CC_SUCCESS))) michael@0: { michael@0: CSFLogError( logTag, "Call to CCAPI_Service_start() failed."); michael@0: return false; michael@0: } michael@0: michael@0: CC_DevicePtr devicePtr = CC_SIPCCDevice::createDevice (); michael@0: if (devicePtr == nullptr) michael@0: { michael@0: CSFLogWarn( logTag, "stopping because createDevice failed"); michael@0: stop(); michael@0: return false; michael@0: } michael@0: CSFLogDebug( logTag, "About to imposeLoggingMask"); michael@0: applyLoggingMask(loggingMask); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: michael@0: void CC_SIPCCService::stop() michael@0: { michael@0: if (bStarted) michael@0: { michael@0: // But first, tear down all existing calls. michael@0: endAllActiveCalls(); michael@0: michael@0: if (CCAPI_Service_stop() == CC_FAILURE) michael@0: { michael@0: CSFLogError( logTag, "Call to CCAPI_Service_stop() failed."); michael@0: } michael@0: michael@0: bStarted = false; michael@0: } michael@0: } michael@0: michael@0: bool CC_SIPCCService::isStarted() michael@0: { michael@0: return bStarted; michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: CC_DevicePtr CC_SIPCCService::getActiveDevice() michael@0: { michael@0: return CC_SIPCCDevice::wrap(CCAPI_Device_getDeviceID()).get(); michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: vector CC_SIPCCService::getDevices() michael@0: { michael@0: vector devices; michael@0: michael@0: CC_SIPCCDevicePtr pDevice = CC_SIPCCDevice::wrap(CCAPI_Device_getDeviceID()); michael@0: if(pDevice != nullptr) michael@0: { michael@0: devices.push_back(pDevice.get()); michael@0: } michael@0: michael@0: return devices; michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: AudioControlPtr CC_SIPCCService::getAudioControl () michael@0: { michael@0: if(audioControlWrapper != nullptr) michael@0: { michael@0: return audioControlWrapper.get(); michael@0: } michael@0: else michael@0: { michael@0: audioControlWrapper = AudioControlWrapperPtr(new AudioControlWrapper(VcmSIPCCBinding::getAudioControl())); michael@0: return audioControlWrapper.get(); michael@0: } michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: VideoControlPtr CC_SIPCCService::getVideoControl () michael@0: { michael@0: if(videoControlWrapper != nullptr) michael@0: { michael@0: return videoControlWrapper.get(); michael@0: } michael@0: else michael@0: { michael@0: videoControlWrapper = VideoControlWrapperPtr(new VideoControlWrapper(VcmSIPCCBinding::getVideoControl())); michael@0: return videoControlWrapper.get(); michael@0: } michael@0: } michael@0: michael@0: michael@0: void CC_SIPCCService::applyLoggingMask (int newMask) michael@0: { michael@0: if (newMask >> _maxBitValueMaskedLoggingEntries > 0) michael@0: { michael@0: CSFLogWarn( logTag, "Value of 0x%x specified for mask includes at least one bit value that exceeds the maximum supported bitfield value. " michael@0: "Ignoring unsupported bits.", newMask); michael@0: } michael@0: michael@0: CSFLogDebug( logTag, "Applying a sipcc log mask = %d", newMask); michael@0: michael@0: loggingMask = newMask & (HAS_21_BITS); michael@0: michael@0: for (int i=0; i<_maxBitValueMaskedLoggingEntries; i++) michael@0: { michael@0: *(_maskedLoggingEntriesArray[i]) = (loggingMask >> i) & 0x1; michael@0: } michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::endAllActiveCalls() michael@0: { michael@0: CC_DevicePtr device = getActiveDevice(); michael@0: if(device != nullptr) michael@0: { michael@0: CC_DeviceInfoPtr deviceInfo = device->getDeviceInfo(); michael@0: vector calls = deviceInfo->getCalls(); michael@0: CSFLogInfo( logTag, "endAllActiveCalls(): %lu calls to be ended.", calls.size()); michael@0: for(vector::iterator it = calls.begin(); it != calls.end(); it++) michael@0: { michael@0: // For each active call, if it can be ended, do so. michael@0: CC_CallPtr call = *it; michael@0: CC_CallInfoPtr callInfo = call->getCallInfo(); michael@0: if(callInfo->hasCapability(CC_CallCapabilityEnum::canEndCall)) michael@0: { michael@0: CSFLogDebug( logTag, "endAllActiveCalls(): ending call %s -> %s [%s]", michael@0: callInfo->getCallingPartyNumber().c_str(), michael@0: callInfo->getCalledPartyNumber().c_str(), michael@0: call_state_getname(callInfo->getCallState())); michael@0: call->endCall(); michael@0: } michael@0: else if(callInfo->hasCapability(CC_CallCapabilityEnum::canResume) && callInfo->getCallState() != REMHOLD) michael@0: { michael@0: CSFLogDebug( logTag, "endAllActiveCalls(): resume then ending call %s -> %s, [%s]", michael@0: callInfo->getCallingPartyNumber().c_str(), michael@0: callInfo->getCalledPartyNumber().c_str(), michael@0: call_state_getname(callInfo->getCallState())); michael@0: call->muteAudio(); michael@0: call->resume(callInfo->getVideoDirection()); michael@0: call->endCall(); michael@0: } michael@0: } michael@0: michael@0: if(!calls.empty()) michael@0: { michael@0: #ifdef MOZILLA_INTERNAL_API michael@0: // If we had any calls, allow a short time for the SIP messaging to go out michael@0: PlatformThread::Sleep(500); michael@0: #endif michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: // C++ Event Handlers michael@0: void CC_SIPCCService::onDeviceEvent(ccapi_device_event_e type, cc_device_handle_t handle, cc_deviceinfo_ref_t info) michael@0: { michael@0: if (_self == nullptr) michael@0: { michael@0: CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of device event."); michael@0: return; michael@0: } michael@0: michael@0: mozilla::MutexAutoLock lock(_self->m_lock); michael@0: michael@0: CC_SIPCCDevicePtr devicePtr = CC_SIPCCDevice::wrap(handle); michael@0: if (devicePtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify device observers for device handle (%u), as failed to create CC_DevicePtr", handle); michael@0: return; michael@0: } michael@0: michael@0: CC_SIPCCDeviceInfoPtr infoPtr = CC_SIPCCDeviceInfo::wrap(info); michael@0: if (infoPtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify call observers for device handle (%u), as failed to create CC_DeviceInfoPtr", handle); michael@0: return; michael@0: } michael@0: michael@0: CSFLogInfo( logTag, "onDeviceEvent( %s, %s, [%s] )", michael@0: device_event_getname(type), michael@0: devicePtr->toString().c_str(), michael@0: infoPtr->getDeviceName().c_str()); michael@0: _self->notifyDeviceEventObservers(type, devicePtr.get(), infoPtr.get()); michael@0: } michael@0: michael@0: void CC_SIPCCService::onFeatureEvent(ccapi_device_event_e type, cc_deviceinfo_ref_t /* device_info */, cc_featureinfo_ref_t feature_info) michael@0: { michael@0: michael@0: if (_self == nullptr) michael@0: { michael@0: CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of device event."); michael@0: return; michael@0: } michael@0: michael@0: mozilla::MutexAutoLock lock(_self->m_lock); michael@0: michael@0: cc_device_handle_t hDevice = CCAPI_Device_getDeviceID(); michael@0: CC_DevicePtr devicePtr = CC_SIPCCDevice::wrap(hDevice).get(); michael@0: if (devicePtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify device observers for device handle (%u), as failed to create CC_DevicePtr", hDevice); michael@0: return; michael@0: } michael@0: michael@0: CC_FeatureInfoPtr infoPtr = CC_SIPCCFeatureInfo::wrap(feature_info).get(); michael@0: if (infoPtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify call observers for feature info handle (%p), as failed to create CC_FeatureInfoPtr", feature_info); michael@0: return; michael@0: } michael@0: michael@0: CSFLogInfo( logTag, "onFeatureEvent( %s, %s, [%s] )", michael@0: device_event_getname(type), michael@0: devicePtr->toString().c_str(), michael@0: infoPtr->getDisplayName().c_str()); michael@0: _self->notifyFeatureEventObservers(type, devicePtr, infoPtr); michael@0: } michael@0: michael@0: void CC_SIPCCService::onLineEvent(ccapi_line_event_e eventType, cc_lineid_t line, cc_lineinfo_ref_t info) michael@0: { michael@0: if (_self == nullptr) michael@0: { michael@0: CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of line event."); michael@0: return; michael@0: } michael@0: michael@0: mozilla::MutexAutoLock lock(_self->m_lock); michael@0: michael@0: CC_LinePtr linePtr = CC_SIPCCLine::wrap(line).get(); michael@0: if (linePtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify line observers for line lineId (%u), as failed to create CC_LinePtr", line); michael@0: return; michael@0: } michael@0: michael@0: CC_LineInfoPtr infoPtr = CC_SIPCCLineInfo::wrap(info).get(); michael@0: if (infoPtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify line observers for line lineId (%u), as failed to create CC_LineInfoPtr", line); michael@0: return; michael@0: } michael@0: michael@0: CSFLogInfo( logTag, "onLineEvent(%s, %s, [%s|%s]", michael@0: line_event_getname(eventType), linePtr->toString().c_str(), michael@0: infoPtr->getNumber().c_str(), (infoPtr->getRegState() ? "INS" : "OOS")); michael@0: _self->notifyLineEventObservers(eventType, linePtr, infoPtr); michael@0: } michael@0: michael@0: void CC_SIPCCService::onCallEvent(ccapi_call_event_e eventType, cc_call_handle_t handle, cc_callinfo_ref_t info) michael@0: { michael@0: if (_self == nullptr) michael@0: { michael@0: CSFLogError( logTag, "CC_SIPCCService::_self is NULL. Unable to notify observers of call event."); michael@0: return; michael@0: } michael@0: michael@0: mozilla::MutexAutoLock lock(_self->m_lock); michael@0: michael@0: CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(handle); michael@0: if (callPtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify call observers for call handle (%u), as failed to create CC_CallPtr", handle); michael@0: return; michael@0: } michael@0: michael@0: CC_SIPCCCallInfoPtr infoPtr = CC_SIPCCCallInfo::wrap(info); michael@0: if (infoPtr == nullptr) michael@0: { michael@0: CSFLogError( logTag, "Unable to notify call observers for call handle (%u), as failed to create CC_CallInfoPtr", handle); michael@0: return; michael@0: } michael@0: michael@0: infoPtr->setMediaData(callPtr->getMediaData()); michael@0: michael@0: set capSet = infoPtr->getCapabilitySet(); michael@0: CSFLogInfo( logTag, "onCallEvent(%s, %s, [%s|%s]", michael@0: call_event_getname(eventType), callPtr->toString().c_str(), michael@0: call_state_getname(infoPtr->getCallState()), CC_CallCapabilityEnum::toString(capSet).c_str()); michael@0: _self->notifyCallEventObservers(eventType, callPtr.get(), infoPtr.get()); michael@0: michael@0: // To prevent leaking CC_SIPCCCalls, we remove them from the wrapper michael@0: // map when the call event information indicates an "on hook" event. michael@0: if (infoPtr->getCallState() == ONHOOK) { michael@0: CSFLogDebug( logTag, "Removing call info from wrapper map (handle=%u)", michael@0: handle); michael@0: CC_SIPCCCall::release(handle); michael@0: } michael@0: michael@0: // Once the call info is dispatched to the observers, we never need to michael@0: // refer to it again. The next operation will contain its own unique info. michael@0: CC_SIPCCCallInfo::release(info); michael@0: } michael@0: michael@0: void CC_SIPCCService::addCCObserver ( CC_Observer * observer ) michael@0: { michael@0: mozilla::MutexAutoLock lock(m_lock); michael@0: if (observer == nullptr) michael@0: { michael@0: CSFLogError( logTag, "NULL value for \"observer\" passed to addCCObserver()."); michael@0: return; michael@0: } michael@0: michael@0: ccObservers.insert(observer); michael@0: } michael@0: michael@0: void CC_SIPCCService::removeCCObserver ( CC_Observer * observer ) michael@0: { michael@0: mozilla::MutexAutoLock lock(m_lock); michael@0: ccObservers.erase(observer); michael@0: } michael@0: michael@0: //Notify Observers michael@0: void CC_SIPCCService::notifyDeviceEventObservers (ccapi_device_event_e eventType, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info) michael@0: { michael@0: // m_lock must be held by the function that called us michael@0: set::const_iterator it = ccObservers.begin(); michael@0: for ( ; it != ccObservers.end(); it++ ) michael@0: { michael@0: (*it)->onDeviceEvent(eventType, devicePtr, info); michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::notifyFeatureEventObservers (ccapi_device_event_e eventType, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info) michael@0: { michael@0: // m_lock must be held by the function that called us michael@0: set::const_iterator it = ccObservers.begin(); michael@0: for ( ; it != ccObservers.end(); it++ ) michael@0: { michael@0: (*it)->onFeatureEvent(eventType, devicePtr, info); michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::notifyLineEventObservers (ccapi_line_event_e eventType, CC_LinePtr linePtr, CC_LineInfoPtr info) michael@0: { michael@0: // m_lock must be held by the function that called us michael@0: set::const_iterator it = ccObservers.begin(); michael@0: for ( ; it != ccObservers.end(); it++ ) michael@0: { michael@0: (*it)->onLineEvent(eventType, linePtr, info); michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::notifyCallEventObservers (ccapi_call_event_e eventType, CC_CallPtr callPtr, CC_CallInfoPtr info) michael@0: { michael@0: // m_lock must be held by the function that called us michael@0: set::const_iterator it = ccObservers.begin(); michael@0: for ( ; it != ccObservers.end(); it++ ) michael@0: { michael@0: (*it)->onCallEvent(eventType, callPtr, info); michael@0: } michael@0: } michael@0: michael@0: // This is called when the SIP stack has caused a new stream to be allocated. This function will michael@0: // find the call associated with that stream so that the call can store the streamId. michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::registerStream(cc_call_handle_t call, int streamId, bool isVideo) michael@0: { michael@0: CSFLogDebug( logTag, "registerStream for call: %d strId=%d video=%s", michael@0: call, streamId, isVideo ? "TRUE" : "FALSE"); michael@0: // get the object corresponding to the handle michael@0: CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call); michael@0: if (callPtr != nullptr) michael@0: { michael@0: callPtr->addStream(streamId, isVideo); michael@0: } michael@0: else michael@0: { michael@0: CSFLogError( logTag, "registerStream(), No call found for allocated Stream: %d, %s", michael@0: streamId, isVideo ? "TRUE" : "FALSE"); michael@0: } michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::deregisterStream(cc_call_handle_t call, int streamId) michael@0: { michael@0: // get the object corresponding to the handle michael@0: CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call); michael@0: if (callPtr != nullptr) michael@0: { michael@0: callPtr->removeStream(streamId); michael@0: } michael@0: else michael@0: { michael@0: CSFLogError( logTag, "deregisterStream(), No call found for deallocated Stream: %d", streamId); michael@0: } michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::dtmfBurst(int digit, int direction, int duration) michael@0: { michael@0: // We haven't a clue what stream to use. Search for a call which has an audio stream. michael@0: vector calls; michael@0: { michael@0: // First build a list of all the calls. michael@0: cc_deviceinfo_ref_t deviceInfoRef = CCAPI_Device_getDeviceInfo(CCAPI_Device_getDeviceID()); michael@0: cc_call_handle_t handles[MAX_SUPPORTED_NUM_CALLS] = {}; michael@0: cc_uint16_t numHandles = csf_countof(handles); michael@0: michael@0: CCAPI_DeviceInfo_getCalls(deviceInfoRef, handles, &numHandles); michael@0: michael@0: for (int i=0; i::iterator it = calls.begin(); it != calls.end() && !bSent; it++) michael@0: { michael@0: CC_SIPCCCallMediaDataPtr pMediaData = (*it)->getMediaData(); michael@0: michael@0: mozilla::MutexAutoLock lock(pMediaData->streamMapMutex); michael@0: for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) michael@0: { michael@0: if (entry->second.isVideo == false) michael@0: { michael@0: // first is the streamId michael@0: if (pAudio->sendDtmf(entry->first, digit)) michael@0: { michael@0: // We have sent a digit, done. michael@0: bSent = true; michael@0: break; michael@0: } michael@0: else michael@0: { michael@0: CSFLogWarn( logTag, "dtmfBurst:sendDtmf returned fail"); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::sendIFrame(cc_call_handle_t call_handle) michael@0: { michael@0: CC_SIPCCCallPtr callPtr = CC_SIPCCCall::wrap(call_handle); michael@0: CC_SIPCCCallMediaDataPtr pMediaData=callPtr->getMediaData(); michael@0: if (pMediaData != nullptr) michael@0: { michael@0: for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) michael@0: { michael@0: if (entry->second.isVideo == true) michael@0: { michael@0: VcmSIPCCBinding::getVideoTermination()->sendIFrame( entry->first ); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool CC_SIPCCService::isValidMediaPortRange(int mediaStartPort, int mediaEndPort) michael@0: { michael@0: if(mediaStartPort < 1024 || michael@0: mediaStartPort > 65535 || michael@0: mediaEndPort < 1024 || michael@0: mediaEndPort > 65535 || michael@0: mediaEndPort - mediaStartPort < 3) michael@0: { michael@0: return false; michael@0: } michael@0: else michael@0: { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: bool CC_SIPCCService::isValidDSCPValue(int value) michael@0: { michael@0: //value is 8-bit value, but the two least significant bits are unused, michael@0: //leaving an effective 6 bits of information. Valid values are therefore michael@0: //all multiples of 4 that lie between 0 and 252 inclusive. michael@0: if(value >= 0 && michael@0: value <= 252 && michael@0: value % 4 == 0) michael@0: { michael@0: return true; michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::onVideoModeChanged( bool enable ) michael@0: { michael@0: } michael@0: michael@0: // !!! Note that accessing *Ptr instances from multiple threads can michael@0: // lead to deadlocks, crashes, and spinning threads. Calls to this michael@0: // method are not safe except from ccapp_thread. michael@0: void CC_SIPCCService::onKeyFrameRequested( int stream ) michael@0: // This is called when the Video Provider indicates that it needs to send a request for new key frame to the sender michael@0: { michael@0: CSFLogDebug(logTag, "onKeyFrameRequested for stream "); michael@0: // We haven't a clue what stream to use. Search for a call which has an audio stream. michael@0: vector calls; michael@0: { michael@0: // First build a list of all the calls. michael@0: cc_deviceinfo_ref_t deviceInfoRef = CCAPI_Device_getDeviceInfo(CCAPI_Device_getDeviceID()); michael@0: cc_call_handle_t handles[MAX_SUPPORTED_NUM_CALLS] = {}; michael@0: cc_uint16_t numHandles = csf_countof(handles); michael@0: michael@0: CCAPI_DeviceInfo_getCalls(deviceInfoRef, handles, &numHandles); michael@0: michael@0: for (int i=0; i::iterator it = calls.begin(); it != calls.end() && !bSent; it++) michael@0: { michael@0: CC_SIPCCCallMediaDataPtr pMediaData = (*it)->getMediaData(); michael@0: michael@0: mozilla::MutexAutoLock lock(pMediaData->streamMapMutex); michael@0: for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++) michael@0: { michael@0: if ((entry->first==stream) && (entry->second.isVideo == true)) michael@0: { michael@0: CSFLogDebug(logTag, "Send SIP message to originator for stream id %d", stream); michael@0: if ((*it)->sendInfo ( "","application/media_control+xml", "\n" michael@0: "\n" michael@0: "\n" michael@0: " \n" michael@0: " \n" michael@0: " \n" michael@0: " \n" michael@0: " \n" michael@0: "\n" michael@0: "\n")) michael@0: { michael@0: CSFLogWarn(logTag, "sendinfo returned true"); michael@0: bSent = true; michael@0: break; michael@0: } michael@0: else michael@0: { michael@0: CSFLogWarn(logTag, "sendinfo returned false"); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void CC_SIPCCService::onMediaLost( int callId ) michael@0: { michael@0: } michael@0: michael@0: void CC_SIPCCService::onMediaRestored( int callId ) michael@0: { michael@0: } michael@0: michael@0: bool CC_SIPCCService::setLocalVoipPort(int port) { michael@0: return CCAPI_Config_set_local_voip_port(port); michael@0: } michael@0: michael@0: bool CC_SIPCCService::setRemoteVoipPort(int port) { michael@0: return CCAPI_Config_set_remote_voip_port(port); michael@0: } michael@0: michael@0: bool CC_SIPCCService::setP2PMode(bool mode) { michael@0: return CCAPI_Config_set_p2p_mode(mode); michael@0: } michael@0: michael@0: bool CC_SIPCCService::setSDPMode(bool mode) { michael@0: return CCAPI_Config_set_sdp_mode(mode); michael@0: } michael@0: michael@0: } // End of namespace CSF