From 27e0878afed06f5d421cdad0772cf9f8762cd3ad Mon Sep 17 00:00:00 2001 From: Tomasz Marciniak Date: Tue, 3 Mar 2015 07:40:12 +0100 Subject: [PATCH] [Sound] Added implementation for tizen 2.4 [Verification] Code compiles without errors. Functions successfully tested. Change-Id: Ie1b4442cdaac4f039d21e792f48638ee117cf106 Signed-off-by: Tomasz Marciniak --- src/sound/sound_api.js | 107 +++++++++++++++ src/sound/sound_instance.cc | 46 +++++++ src/sound/sound_instance.h | 5 + src/sound/sound_manager.cc | 265 +++++++++++++++++++++++++++++++++++- src/sound/sound_manager.h | 15 ++ 5 files changed, 437 insertions(+), 1 deletion(-) diff --git a/src/sound/sound_api.js b/src/sound/sound_api.js index b9301cdf..cbf94c8a 100644 --- a/src/sound/sound_api.js +++ b/src/sound/sound_api.js @@ -26,6 +26,61 @@ var SoundModeType = { MUTE: 'MUTE' }; +function _createSoundDeviceInfoArray(e) { + var devices_array = []; + + e.forEach(function (data) { + devices_array.push(new SoundDeviceInfo(data)); + }); + + return devices_array; +}; + +function ListenerManager(native, listenerName) { + this.listeners = {}; + this.nextId = 1; + this.nativeSet = false; + this.native = native; + this.listenerName = listenerName; +}; + +ListenerManager.prototype.onListenerCalled = function(msg) { + var obj = new SoundDeviceInfo(msg); + for (var watchId in this.listeners) { + if (this.listeners.hasOwnProperty(watchId)) { + this.listeners[watchId](obj); + } + } +}; + +ListenerManager.prototype.addListener = function(callback) { + var id = this.nextId; + if (!this.nativeSet) { + this.native.addListener(this.listenerName, this.onListenerCalled.bind(this)); + this.native.callSync('SoundManager_addDeviceStateChangeListener'); + this.nativeSet = true; + } + + this.listeners[id] = callback; + ++this.nextId; + + return id; +}; + +ListenerManager.prototype.removeListener = function(watchId) { + if (this.listeners.hasOwnProperty(watchId)) { + delete this.listeners[watchId]; + } + + if (this.nativeSet && type_.isEmptyObject(this.listeners)) { + this.native.callSync('SoundManager_removeDeviceStateChangeListener'); + this.native.removeListener(this.listenerName); + this.nativeSet = false; + } +}; + +var DEVICE_STATE_CHANGE_LISTENER = 'SoundDeviceStateChangeCallback'; +var soundDeviceStateChangeListener = new ListenerManager(native_, DEVICE_STATE_CHANGE_LISTENER); function SoundManager() {} @@ -132,5 +187,57 @@ SoundManager.prototype.unsetVolumeChangeListener = function() { } }; +SoundManager.prototype.getConnectedDeviceList = function() { + var result = native_.callSync('SoundManager_getConnectedDeviceList', {}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + + var devices = _createSoundDeviceInfoArray(native_.getResultObject(result)); + return devices; +}; + +SoundManager.prototype.getActivatedDeviceList = function() { + var result = native_.callSync('SoundManager_getActivatedDeviceList', {}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + + var devices = _createSoundDeviceInfoArray(native_.getResultObject(result)); + return devices; +}; + +SoundManager.prototype.addDeviceStateChangeListener = function() { + var args = validator_.validateArgs(arguments, [ + { + name : 'eventCallback', + type : types_.FUNCTION + } + ]); + + return soundDeviceStateChangeListener.addListener(args.eventCallback); +}; + +SoundManager.prototype.removeDeviceStateChangeListener = function() { + var args = validator_.validateArgs(arguments, [ + { + name : 'watchId', + type : types_.LONG + } + ]); + + soundDeviceStateChangeListener.removeListener(args.watchId); +}; + +function SoundDeviceInfo(data) { + Object.defineProperties(this, { + id: {value: data.id, writable: false, enumerable: true}, + name: {value: data.name, writable: false, enumerable: true}, + device : {value: data.device, writable: false, enumerable: true}, + direction : {value: data.direction, writable: false, enumerable: true}, + isConnected: {value: data.isConnected, writable: false, enumerable: true}, + isActivated: {value: data.isActivated, writable: false, enumerable: true}, + }); +}; exports = new SoundManager(); diff --git a/src/sound/sound_instance.cc b/src/sound/sound_instance.cc index 7363a40a..5a6e78ec 100644 --- a/src/sound/sound_instance.cc +++ b/src/sound/sound_instance.cc @@ -34,6 +34,12 @@ SoundInstance::SoundInstance() { REGISTER_SYNC("SoundManager_setSoundModeChangeListener", SoundManagerSetSoundModeChangeListener); REGISTER_SYNC("SoundManager_setVolumeChangeListener", SoundManagerSetVolumeChangeListener); REGISTER_SYNC("SoundManager_getSoundMode", SoundManagerGetSoundMode); + REGISTER_SYNC("SoundManager_getConnectedDeviceList", SoundManagerGetConnectedDeviceList); + REGISTER_SYNC("SoundManager_getActivatedDeviceList", SoundManagerGetActivatedDeviceList); + REGISTER_SYNC("SoundManager_addDeviceStateChangeListener", + SoundManagerAddDeviceStateChangeListener); + REGISTER_SYNC("SoundManager_removeDeviceStateChangeListener", + SoundManagerRemoveDeviceStateChangeListener); #undef REGISTER_SYNC manager_ = SoundManager::GetInstance(); @@ -139,6 +145,46 @@ void SoundInstance::SoundManagerUnsetVolumeChangeListener( ReportError(status, &out); } +void SoundInstance::SoundManagerGetConnectedDeviceList( + const picojson::value& args, picojson::object& out) { + + LoggerD("Entered"); + manager_->GetDeviceList(SOUND_DEVICE_ALL_MASK, out); +} + +void SoundInstance::SoundManagerGetActivatedDeviceList( + const picojson::value& args, picojson::object& out) { + + LoggerD("Entered"); + manager_->GetDeviceList(SOUND_DEVICE_STATE_ACTIVATED_MASK, out); +} + +void SoundInstance::SoundManagerAddDeviceStateChangeListener( + const picojson::value& args, picojson::object& out) { + + LoggerD("Entered"); + PlatformResult result = manager_->AddDeviceStateChangeListener(); + + if (result.IsSuccess()) { + ReportSuccess(out); + } else { + ReportError(result, &out); + } +} + +void SoundInstance::SoundManagerRemoveDeviceStateChangeListener( + const picojson::value& args, picojson::object& out) { + + LoggerD("Entered"); + PlatformResult result = manager_->RemoveDeviceStateChangeListener(); + + if (result.IsSuccess()) { + ReportSuccess(out); + } else { + ReportError(result, &out); + } +} + #undef CHECK_EXIST } // namespace sound diff --git a/src/sound/sound_instance.h b/src/sound/sound_instance.h index f3c762ef..48a001ad 100644 --- a/src/sound/sound_instance.h +++ b/src/sound/sound_instance.h @@ -27,6 +27,11 @@ class SoundInstance : public common::ParsedInstance, public SoundManagerSoundMod void SoundManagerSetSoundModeChangeListener(const picojson::value& args, picojson::object& out); void SoundManagerSetVolumeChangeListener(const picojson::value& args, picojson::object& out); void SoundManagerGetSoundMode(const picojson::value& args, picojson::object& out); + void SoundManagerGetConnectedDeviceList(const picojson::value& args, picojson::object& out); + void SoundManagerGetActivatedDeviceList(const picojson::value& args, picojson::object& out); + void SoundManagerAddDeviceStateChangeListener(const picojson::value& args, picojson::object& out); + void SoundManagerRemoveDeviceStateChangeListener( + const picojson::value& args, picojson::object& out); void OnSoundModeChange(const std::string& newmode); }; diff --git a/src/sound/sound_manager.cc b/src/sound/sound_manager.cc index 21968215..89c16632 100644 --- a/src/sound/sound_manager.cc +++ b/src/sound/sound_manager.cc @@ -8,6 +8,7 @@ #include #include +#include "common/task-queue.h" //This constant was originally defined in vconf.h. However, in tizen 3, it //appears, it is removed (or defined only in vconf-internals.h) @@ -24,6 +25,7 @@ namespace extension { namespace sound { using namespace common; +using namespace common::tools; const std::map SoundManager::platform_enum_map_ = { {"SYSTEM", SOUND_TYPE_SYSTEM}, @@ -61,8 +63,48 @@ PlatformResult SoundManager::PlatformEnumToStr(const sound_type_e value, return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message); } +std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) { + switch (type) { + case SOUND_DEVICE_BUILTIN_SPEAKER: + return "SPEAKER"; + case SOUND_DEVICE_BUILTIN_RECEIVER: + return "RECEIVER"; + case SOUND_DEVICE_BUILTIN_MIC: + return "MIC"; + case SOUND_DEVICE_AUDIO_JACK: + return "AUDIO_JACK"; + case SOUND_DEVICE_BLUETOOTH: + return "BLUETOOTH"; + case SOUND_DEVICE_HDMI: + return "HDMI"; + case SOUND_DEVICE_MIRRORING: + return "MIRRORING"; + case SOUND_DEVICE_USB_AUDIO: + return "USB_AUDIO"; + default: + LoggerE("Invalid sound_device_type_e: %d", type); + return ""; + } +} + +std::string SoundManager::SoundIOTypeToString(sound_device_io_direction_e type) { + switch (type) { + case SOUND_DEVICE_IO_DIRECTION_IN: + return "IN"; + case SOUND_DEVICE_IO_DIRECTION_OUT: + return "OUT"; + case SOUND_DEVICE_IO_DIRECTION_BOTH: + return "BOTH"; + default: + LoggerE("Invalid sound_device_io_direction_e: %d", type); + return ""; + } +} + SoundManager::SoundManager() - : soundModeChangeListening(false), soundModeListener(nullptr) { + : soundModeChangeListening(false), + sound_device_change_listener_(false), + soundModeListener(nullptr) { FillMaxVolumeMap(); } @@ -73,6 +115,16 @@ SoundManager::~SoundManager() { LoggerE("Cannot disable listener!"); } } + + if (sound_device_change_listener_) { + if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) { + LoggerE("Cannot unregister connection listener!"); + } + + if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) { + LoggerE("Cannot unregister information listener!"); + } + } } SoundManager* SoundManager::GetInstance() { @@ -335,5 +387,216 @@ PlatformResult SoundManager::UnsetVolumeChangeListener() { return PlatformResult(ErrorCode::NO_ERROR); } +void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) { + LoggerD("Entered"); + + int ret = SOUND_MANAGER_ERROR_NONE; + sound_device_list_h device_list = nullptr; + sound_device_h device = nullptr; + + picojson::value response = picojson::value(picojson::array()); + picojson::array& response_array = response.get(); + + ret = sound_manager_get_current_device_list(mask, &device_list); + if (SOUND_MANAGER_ERROR_NONE != ret) { + ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed"), &out); + return; + } + + while (!(ret = sound_manager_get_next_device(device_list, &device))) { + picojson::value val = picojson::value(picojson::object()); + picojson::object& obj = val.get(); + PlatformResult result = GetDeviceInfo(device, true, false, &obj); + + if (result.IsError()) { + ReportError(result, &out); + return; + } + response_array.push_back(val); + } + + ReportSuccess(response, out); +} + +PlatformResult SoundManager::GetDeviceInfo(sound_device_h device, + bool is_connected, + bool check_connection, + picojson::object* obj) { + LoggerD("Entered"); + + int ret = SOUND_MANAGER_ERROR_NONE; + + //get id + int id = 0; + ret = sound_manager_get_device_id(device, &id); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device id failed"); + } + obj->insert(std::make_pair("id", picojson::value(static_cast(id)))); + + //get name + char *name = nullptr; + ret = sound_manager_get_device_name(device, &name); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device name failed"); + } + obj->insert(std::make_pair("name", picojson::value(name))); + + //get type + sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER; + ret = sound_manager_get_device_type(device, &type); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed"); + } + obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type)))); + + //get direction + sound_device_io_direction_e direction = SOUND_DEVICE_IO_DIRECTION_IN; + ret = sound_manager_get_device_io_direction (device, &direction); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device direction failed"); + } + obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction)))); + + //get state + sound_device_state_e state = SOUND_DEVICE_STATE_DEACTIVATED; + ret = sound_manager_get_device_state(device, &state); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device state failed"); + } + obj->insert(std::make_pair("isActivated", picojson::value(static_cast(state)))); + + //get connection + if (check_connection) { + return IsDeviceConnected(type, direction, obj); + } + + obj->insert(std::make_pair("isConnected", picojson::value(is_connected))); + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type, + sound_device_io_direction_e direction, + picojson::object* obj) { + LoggerD("Entered"); + + sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK; + switch (direction) { + case SOUND_DEVICE_IO_DIRECTION_IN: + mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK; + break; + case SOUND_DEVICE_IO_DIRECTION_OUT: + mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK; + break; + case SOUND_DEVICE_IO_DIRECTION_BOTH: + mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK; + break; + default: + LoggerD("Invalid IOType (%d)", direction); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Invalid IO type"); + } + + int ret = SOUND_MANAGER_ERROR_NONE; + sound_device_list_h device_list = nullptr; + sound_device_h device = nullptr; + sound_device_type_e device_type = SOUND_DEVICE_BUILTIN_SPEAKER; + + ret = sound_manager_get_current_device_list(mask, &device_list); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed"); + } + + while (!(ret = sound_manager_get_next_device(device_list, &device))) { + ret = sound_manager_get_device_type(device, &device_type); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed"); + } + + if (type == device_type) { + obj->insert(std::make_pair("isConnected", picojson::value(true))); + return PlatformResult(ErrorCode::NO_ERROR); + } + } + + obj->insert(std::make_pair("isConnected", picojson::value(false))); + return PlatformResult(ErrorCode::NO_ERROR); +} + +void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) { + LoggerD("Entered"); + + picojson::value response = picojson::value(picojson::object()); + picojson::object& response_obj = response.get(); + + PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj); + + if (result.IsSuccess()) { + response_obj.insert(std::make_pair( + "listenerId", picojson::value("SoundDeviceStateChangeCallback"))); + + auto call_response = [response]()->void { + SoundInstance::GetInstance().PostMessage(response.serialize().c_str()); + }; + + TaskQueue::GetInstance().Async(call_response); + } +} + +void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) { + LoggerD("Entered"); + + SoundManager::GetInstance()->DeviceChangeCB(device, is_connected, false); +} + +void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info, + void *user_data) { + LoggerD("Entered"); + + if (SOUND_DEVICE_CAHNGED_INFO_STATE == changed_info) { + SoundManager::GetInstance()->DeviceChangeCB(device, false, true); + } +} + +PlatformResult SoundManager::AddDeviceStateChangeListener() { + LoggerD("Entered"); + + int ret = SOUND_MANAGER_ERROR_NONE; + sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK; + + if (!sound_device_change_listener_) { + ret = sound_manager_set_device_connected_cb(mask, DeviceConnectionChangeCB, nullptr); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting connection listener failed"); + } + + ret = sound_manager_set_device_information_changed_cb(mask, DeviceActivationChangeCB, nullptr); + if (SOUND_MANAGER_ERROR_NONE != ret) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting information listener failed"); + } + + sound_device_change_listener_ = true; + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult SoundManager::RemoveDeviceStateChangeListener() { + LoggerD("Entered"); + + if (sound_device_change_listener_) { + if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed"); + } + + if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) { + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed"); + } + + sound_device_change_listener_ = false; + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + } // namespace sound } // namespace extension diff --git a/src/sound/sound_manager.h b/src/sound/sound_manager.h index 4c0781de..ecda42a4 100644 --- a/src/sound/sound_manager.h +++ b/src/sound/sound_manager.h @@ -32,6 +32,10 @@ class SoundManager { common::PlatformResult UnsetSoundModeChangeListener(); common::PlatformResult SetVolumeChangeListener(); common::PlatformResult UnsetVolumeChangeListener(); + void GetDeviceList(sound_device_mask_e mask, picojson::object& out); + void DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection); + common::PlatformResult AddDeviceStateChangeListener(); + common::PlatformResult RemoveDeviceStateChangeListener(); private: SoundManager(); @@ -50,9 +54,20 @@ class SoundManager { sound_type_e* sound_type); static common::PlatformResult PlatformEnumToStr(const sound_type_e value, std::string* sound_type); + + common::PlatformResult GetDeviceInfo(sound_device_h device, + bool is_connected, + bool check_connection, + picojson::object* obj); + common::PlatformResult IsDeviceConnected(sound_device_type_e type, + sound_device_io_direction_e direction, + picojson::object* obj); + static std::string SoundDeviceTypeToString(sound_device_type_e type); + static std::string SoundIOTypeToString(sound_device_io_direction_e type); static double ConvertToSystemVolume(int max_volume, int volume); static void soundModeChangedCb(keynode_t* node, void* user_data); bool soundModeChangeListening; + bool sound_device_change_listener_; SoundManagerSoundModeChangedListener* soundModeListener; }; -- 2.34.1