2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "sound/sound_manager.h"
19 #include <tizen/tizen.h>
21 #include <vconf-keys.h>
23 #include "common/converter.h"
24 #include "common/logger.h"
25 #include "common/task-queue.h"
26 #include "common/tools.h"
28 //This constant was originally defined in vconf.h. However, in tizen 3, it
29 //appears, it is removed (or defined only in vconf-internals.h)
30 //It is not clear, if it is final solution, or not.
35 #include "sound/sound_instance.h"
40 using namespace common;
41 using namespace common::tools;
43 const std::map<std::string, sound_type_e> SoundManager::platform_enum_map_ = {
44 {"SYSTEM", SOUND_TYPE_SYSTEM},
45 {"NOTIFICATION", SOUND_TYPE_NOTIFICATION},
46 {"ALARM", SOUND_TYPE_ALARM},
47 {"MEDIA", SOUND_TYPE_MEDIA},
48 {"VOICE", SOUND_TYPE_VOICE},
49 {"RINGTONE", SOUND_TYPE_RINGTONE}};
51 PlatformResult SoundManager::StrToPlatformEnum(const std::string& key,
52 sound_type_e* sound_type) {
54 if (platform_enum_map_.find(key) == platform_enum_map_.end()) {
55 std::string message = "Platform enum value not found for key " + key;
56 return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message);
59 *sound_type = platform_enum_map_.at(key);
61 return PlatformResult(ErrorCode::NO_ERROR);
64 PlatformResult SoundManager::PlatformEnumToStr(const sound_type_e value,
65 std::string* sound_type) {
67 for (auto& item : platform_enum_map_) {
68 if (item.second == value) {
69 *sound_type = item.first;
71 return PlatformResult(ErrorCode::NO_ERROR);
76 "Platform enum value " + std::to_string(value) + " not found";
78 return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message);
81 std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) {
84 case SOUND_DEVICE_BUILTIN_SPEAKER:
86 case SOUND_DEVICE_BUILTIN_RECEIVER:
88 case SOUND_DEVICE_BUILTIN_MIC:
90 case SOUND_DEVICE_AUDIO_JACK:
92 case SOUND_DEVICE_BLUETOOTH:
94 case SOUND_DEVICE_HDMI:
96 case SOUND_DEVICE_MIRRORING:
98 case SOUND_DEVICE_USB_AUDIO:
101 LoggerE("Invalid sound_device_type_e: %d", type);
106 std::string SoundManager::SoundIOTypeToString(sound_device_io_direction_e type) {
109 case SOUND_DEVICE_IO_DIRECTION_IN:
111 case SOUND_DEVICE_IO_DIRECTION_OUT:
113 case SOUND_DEVICE_IO_DIRECTION_BOTH:
116 LoggerE("Invalid sound_device_io_direction_e: %d", type);
121 SoundManager::SoundManager(SoundInstance& instance)
122 : is_volume_change_listener_(false),
123 soundModeChangeListening(false),
124 sound_device_change_listener_(false),
126 soundModeListener(nullptr) {
130 SoundManager::~SoundManager() {
132 if (soundModeChangeListening) {
133 int status = vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, SoundManager::soundModeChangedCb);
134 if (VCONF_OK != status) {
135 LoggerE("Cannot disable listener!");
139 if (sound_device_change_listener_) {
140 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
141 LoggerE("Cannot unregister connection listener!");
144 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
145 LoggerE("Cannot unregister information listener!");
149 if (is_volume_change_listener_) {
150 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_volume_changed_cb()) {
151 LoggerE("Cannot unregister volume listener!");
156 void SoundManager::FillMaxVolumeMap() {
161 for (auto& item : platform_enum_map_) {
164 ret = sound_manager_get_max_volume(item.second, &max);
165 if (ret != SOUND_MANAGER_ERROR_NONE) {
166 LoggerE("SoundManagerGetMaxVolumeFailed : %d", ret);
169 LoggerD("maxVolume: %d - %d", item.second, max);
171 max_volume_map_[item.second] = max;
175 PlatformResult SoundManager::GetMaxVolume(sound_type_e type, int* max_volume) {
177 auto it = max_volume_map_.find(type);
178 if (it == max_volume_map_.end()) {
179 std::string sound_type;
180 PlatformResult status = PlatformEnumToStr(type, &sound_type);
181 if (status.IsError()) return status;
182 LoggerE("Failed to find maxVolume of type: %s", sound_type.c_str());
184 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume");
187 *max_volume = it->second;
189 return PlatformResult(ErrorCode::NO_ERROR);
192 double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
194 return round(static_cast<double>(volume) * 10 / max_volume) / 10;
197 void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
198 LoggerD("VolumeChangeCallback: type: %d, value: %d", type, value);
201 picojson::value response = picojson::value(picojson::object());
202 picojson::object& response_obj = response.get<picojson::object>();
205 std::make_pair("listenerId", picojson::value("VolumeChangeListener")));
207 std::string sound_type;
208 PlatformResult status = PlatformEnumToStr(type, &sound_type);
209 if (status.IsError())
213 std::make_pair("type", picojson::value(sound_type)));
216 status = GetMaxVolume(type, &max_volume);
217 if (status.IsError())
220 response_obj.insert(std::make_pair(
222 picojson::value(ConvertToSystemVolume(max_volume, value))));
224 Instance::PostMessage(&instance_, response.serialize().c_str());
227 PlatformResult SoundManager::GetSoundMode(std::string* sound_mode_type) {
229 int isEnableSound = 0;
230 int isEnableVibrate = 0;
232 *sound_mode_type = "MUTE";
234 int ret = vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &isEnableSound);
235 if (VCONF_OK != ret) {
236 LoggerE("Unknown error : %d", ret);
237 return PlatformResult(ErrorCode::UNKNOWN_ERR,
238 "Unknown error: " + std::to_string(ret));
242 vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &isEnableVibrate);
243 if (VCONF_OK != ret) {
244 LoggerE("Unknown error : %d", ret);
245 return PlatformResult(ErrorCode::UNKNOWN_ERR,
246 "Unknown error: " + std::to_string(ret));
249 if (isEnableSound && isEnableVibrate) {
250 LoggerE("Wrong state (sound && vibration)");
251 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform has wrong state.");
255 *sound_mode_type = "SOUND";
256 } else if (isEnableVibrate) {
257 *sound_mode_type = "VIBRATE";
260 return PlatformResult(ErrorCode::NO_ERROR);
263 PlatformResult SoundManager::SetVolume(const picojson::object& args) {
265 const std::string& type = FromJson<std::string>(args, "type");
266 double volume = FromJson<double>(args, "volume");
268 LoggerD("SoundType: %s", type.c_str());
269 LoggerD("volume: %f", volume);
271 if (volume > 1.0 || volume < 0.0) {
272 LoggerE("Volume should be the value between 0 and 1.");
273 return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
274 "Volume should be the value between 0 and 1.");
277 sound_type_e sound_type;
278 PlatformResult status = SoundManager::StrToPlatformEnum(type, &sound_type);
279 if (status.IsError()) return status;
281 auto it = max_volume_map_.find(sound_type);
282 if (it == max_volume_map_.end()) {
283 LoggerE("Failed to find maxVolume of type: %d", type.c_str());
284 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume");
287 int max_volume = it->second;
288 int value = round(volume * max_volume);
289 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
291 int ret = sound_manager_set_volume(sound_type, value);
292 if (ret != SOUND_MANAGER_ERROR_NONE) {
293 LoggerE("Failed to set volume: %d", ret);
294 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to set volume");
297 return PlatformResult(ErrorCode::NO_ERROR);
300 PlatformResult SoundManager::GetVolume(const picojson::object& args,
303 const std::string& type = FromJson<std::string>(args, "type");
306 sound_type_e type_enum;
307 PlatformResult status = SoundManager::StrToPlatformEnum(type, &type_enum);
308 if (status.IsError()) return status;
311 status = GetMaxVolume(type_enum, &max_volume);
312 if (status.IsError()) return status;
314 int ret = sound_manager_get_volume(type_enum, &value);
315 if (ret != SOUND_MANAGER_ERROR_NONE) {
316 LoggerE("Failed to get volume: %d", ret);
317 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get volume");
320 *volume = ConvertToSystemVolume(max_volume, value);
321 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
323 return PlatformResult(ErrorCode::NO_ERROR);
326 void SoundManager::soundModeChangedCb(keynode_t*, void* user_data)
329 if (user_data == nullptr) {
330 LoggerE("Invalid callback data!");
333 SoundManager* self = static_cast<SoundManager*>(user_data);
335 std::string soundModeType;
336 PlatformResult status = self->GetSoundMode(&soundModeType);
338 if (status.IsSuccess() && self->soundModeListener) {
339 self->soundModeListener->OnSoundModeChange(soundModeType);
341 LoggerE("No SoundModeListener attached");
345 PlatformResult SoundManager::SetSoundModeChangeListener(
346 SoundManagerSoundModeChangedListener* listener) {
348 soundModeListener = listener;
349 if (soundModeChangeListening) return PlatformResult(ErrorCode::NO_ERROR);
351 int status = vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
352 SoundManager::soundModeChangedCb, this);
353 if (VCONF_OK == status) {
354 soundModeChangeListening = true;
355 return PlatformResult(ErrorCode::NO_ERROR);
358 LoggerE("SoundModeChangeListener no setted");
359 return PlatformResult(ErrorCode::UNKNOWN_ERR,
360 "SoundModeChangeListener no setted");
363 PlatformResult SoundManager::UnsetSoundModeChangeListener() {
365 soundModeListener = nullptr;
366 if (!soundModeChangeListening) {
367 return PlatformResult(ErrorCode::NO_ERROR);
370 int status = vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
371 SoundManager::soundModeChangedCb);
372 if (VCONF_OK == status) {
373 soundModeChangeListening = false;
374 return PlatformResult(ErrorCode::NO_ERROR);
377 LoggerE("SoundModeChangeListener no unsetted");
378 return PlatformResult(ErrorCode::UNKNOWN_ERR,
379 "SoundModeChangeListener no unsetted");
382 PlatformResult SoundManager::SetVolumeChangeListener() {
384 if (!is_volume_change_listener_) {
385 int ret = sound_manager_set_volume_changed_cb(
386 [](sound_type_e type, unsigned int value, void* ud) {
387 return static_cast<SoundManager*>(ud)
388 ->VolumeChangeCallback(type, value);
390 static_cast<void*>(this));
392 if (ret != SOUND_MANAGER_ERROR_NONE) {
393 LoggerE("Failed to set volume changed callback: error code: %d", ret);
394 return PlatformResult(ErrorCode::UNKNOWN_ERR,
395 "Failed to set volume changed callback");
398 is_volume_change_listener_ = true;
401 return PlatformResult(ErrorCode::NO_ERROR);
404 PlatformResult SoundManager::UnsetVolumeChangeListener() {
406 if (!is_volume_change_listener_) {
407 return PlatformResult(ErrorCode::NO_ERROR);
410 int ret = sound_manager_unset_volume_changed_cb();
411 if (ret != SOUND_MANAGER_ERROR_NONE) {
412 LoggerE("Failed to unset volume changed callback");
413 return PlatformResult(ErrorCode::UNKNOWN_ERR,
414 "Failed to unset volume changed callback");
417 is_volume_change_listener_ = false;
419 return PlatformResult(ErrorCode::NO_ERROR);
422 void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) {
425 sound_device_list_h device_list = nullptr;
426 sound_device_h device = nullptr;
428 picojson::value response = picojson::value(picojson::array());
429 picojson::array& response_array = response.get<picojson::array>();
431 int ret = sound_manager_get_current_device_list(mask, &device_list);
432 if (SOUND_MANAGER_ERROR_NONE != ret && SOUND_MANAGER_ERROR_NO_DATA != ret) {
433 ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed"), &out);
437 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
438 picojson::value val = picojson::value(picojson::object());
439 picojson::object& obj = val.get<picojson::object>();
440 PlatformResult result = GetDeviceInfo(device, true, false, &obj);
442 if (result.IsError()) {
443 ReportError(result, &out);
446 response_array.push_back(val);
449 ReportSuccess(response, out);
452 PlatformResult SoundManager::GetDeviceInfo(sound_device_h device,
454 bool check_connection,
455 picojson::object* obj) {
460 int ret = sound_manager_get_device_id(device, &id);
461 if (SOUND_MANAGER_ERROR_NONE != ret) {
462 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device id failed");
464 obj->insert(std::make_pair("id", picojson::value(static_cast<double>(id))));
467 char *name = nullptr;
468 ret = sound_manager_get_device_name(device, &name);
469 if (SOUND_MANAGER_ERROR_NONE != ret) {
470 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device name failed");
472 obj->insert(std::make_pair("name", picojson::value(name)));
475 sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER;
476 ret = sound_manager_get_device_type(device, &type);
477 if (SOUND_MANAGER_ERROR_NONE != ret) {
478 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed");
480 obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type))));
483 sound_device_io_direction_e direction = SOUND_DEVICE_IO_DIRECTION_IN;
484 ret = sound_manager_get_device_io_direction (device, &direction);
485 if (SOUND_MANAGER_ERROR_NONE != ret) {
486 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device direction failed");
488 obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
491 sound_device_state_e state = SOUND_DEVICE_STATE_DEACTIVATED;
492 ret = sound_manager_get_device_state(device, &state);
493 if (SOUND_MANAGER_ERROR_NONE != ret) {
494 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device state failed");
496 obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
499 if (check_connection) {
500 return IsDeviceConnected(type, direction, obj);
503 obj->insert(std::make_pair("isConnected", picojson::value(is_connected)));
504 return PlatformResult(ErrorCode::NO_ERROR);
507 PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type,
508 sound_device_io_direction_e direction,
509 picojson::object* obj) {
512 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
514 case SOUND_DEVICE_IO_DIRECTION_IN:
515 mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK;
517 case SOUND_DEVICE_IO_DIRECTION_OUT:
518 mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK;
520 case SOUND_DEVICE_IO_DIRECTION_BOTH:
521 mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK;
524 LoggerD("Invalid IOType (%d)", direction);
525 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Invalid IO type");
528 sound_device_list_h device_list = nullptr;
529 sound_device_h device = nullptr;
530 sound_device_type_e device_type = SOUND_DEVICE_BUILTIN_SPEAKER;
532 int ret = sound_manager_get_current_device_list(mask, &device_list);
533 if (SOUND_MANAGER_ERROR_NONE != ret) {
534 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed");
537 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
538 ret = sound_manager_get_device_type(device, &device_type);
539 if (SOUND_MANAGER_ERROR_NONE != ret) {
540 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed");
543 if (type == device_type) {
544 obj->insert(std::make_pair("isConnected", picojson::value(true)));
545 return PlatformResult(ErrorCode::NO_ERROR);
549 obj->insert(std::make_pair("isConnected", picojson::value(false)));
550 return PlatformResult(ErrorCode::NO_ERROR);
553 void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) {
556 picojson::value response = picojson::value(picojson::object());
557 picojson::object& response_obj = response.get<picojson::object>();
559 PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj);
561 if (result.IsSuccess()) {
562 response_obj.insert(std::make_pair(
563 "listenerId", picojson::value("SoundDeviceStateChangeCallback")));
565 auto call_response = [this, response]()->void {
566 Instance::PostMessage(&instance_, response.serialize().c_str());
569 TaskQueue::GetInstance().Async(call_response);
573 void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) {
575 SoundManager* h = static_cast<SoundManager*>(user_data);
576 h->DeviceChangeCB(device, is_connected, false);
579 void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info,
583 if (SOUND_DEVICE_CHANGED_INFO_STATE == changed_info) {
584 SoundManager* h = static_cast<SoundManager*>(user_data);
585 h->DeviceChangeCB(device, false, true);
589 PlatformResult SoundManager::AddDeviceStateChangeListener() {
592 int ret = SOUND_MANAGER_ERROR_NONE;
593 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
595 if (!sound_device_change_listener_) {
596 ret = sound_manager_set_device_connected_cb(mask, DeviceConnectionChangeCB, this);
597 if (SOUND_MANAGER_ERROR_NONE != ret) {
598 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting connection listener failed");
601 ret = sound_manager_set_device_information_changed_cb(mask, DeviceActivationChangeCB, this);
602 if (SOUND_MANAGER_ERROR_NONE != ret) {
603 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting information listener failed");
606 sound_device_change_listener_ = true;
609 return PlatformResult(ErrorCode::NO_ERROR);
612 PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
615 if (sound_device_change_listener_) {
616 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
617 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed");
620 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
621 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed");
624 sound_device_change_listener_ = false;
627 return PlatformResult(ErrorCode::NO_ERROR);
631 } // namespace extension