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/task-queue.h"
25 //This constant was originally defined in vconf.h. However, in tizen 3, it
26 //appears, it is removed (or defined only in vconf-internals.h)
27 //It is not clear, if it is final solution, or not.
32 #include "sound/sound_instance.h"
33 #include "common/logger.h"
34 #include "common/converter.h"
39 using namespace common;
40 using namespace common::tools;
42 const std::map<std::string, sound_type_e> SoundManager::platform_enum_map_ = {
43 {"SYSTEM", SOUND_TYPE_SYSTEM},
44 {"NOTIFICATION", SOUND_TYPE_NOTIFICATION},
45 {"ALARM", SOUND_TYPE_ALARM},
46 {"MEDIA", SOUND_TYPE_MEDIA},
47 {"VOICE", SOUND_TYPE_VOICE},
48 {"RINGTONE", SOUND_TYPE_RINGTONE}};
50 PlatformResult SoundManager::StrToPlatformEnum(const std::string& key,
51 sound_type_e* sound_type) {
53 if (platform_enum_map_.find(key) == platform_enum_map_.end()) {
54 std::string message = "Platform enum value not found for key " + key;
55 return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message);
58 *sound_type = platform_enum_map_.at(key);
60 return PlatformResult(ErrorCode::NO_ERROR);
63 PlatformResult SoundManager::PlatformEnumToStr(const sound_type_e value,
64 std::string* sound_type) {
66 for (auto& item : platform_enum_map_) {
67 if (item.second == value) {
68 *sound_type = item.first;
70 return PlatformResult(ErrorCode::NO_ERROR);
75 "Platform enum value " + std::to_string(value) + " not found";
77 return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message);
80 std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) {
83 case SOUND_DEVICE_BUILTIN_SPEAKER:
85 case SOUND_DEVICE_BUILTIN_RECEIVER:
87 case SOUND_DEVICE_BUILTIN_MIC:
89 case SOUND_DEVICE_AUDIO_JACK:
91 case SOUND_DEVICE_BLUETOOTH:
93 case SOUND_DEVICE_HDMI:
95 case SOUND_DEVICE_MIRRORING:
97 case SOUND_DEVICE_USB_AUDIO:
100 LoggerE("Invalid sound_device_type_e: %d", type);
105 std::string SoundManager::SoundIOTypeToString(sound_device_io_direction_e type) {
108 case SOUND_DEVICE_IO_DIRECTION_IN:
110 case SOUND_DEVICE_IO_DIRECTION_OUT:
112 case SOUND_DEVICE_IO_DIRECTION_BOTH:
115 LoggerE("Invalid sound_device_io_direction_e: %d", type);
120 SoundManager::SoundManager(SoundInstance& instance)
121 : soundModeChangeListening(false),
122 sound_device_change_listener_(false),
124 soundModeListener(nullptr) {
128 SoundManager::~SoundManager() {
130 if (soundModeChangeListening) {
131 int status = vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, SoundManager::soundModeChangedCb);
132 if (VCONF_OK != status) {
133 LoggerE("Cannot disable listener!");
137 if (sound_device_change_listener_) {
138 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
139 LoggerE("Cannot unregister connection listener!");
142 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
143 LoggerE("Cannot unregister information listener!");
147 if (is_volume_change_listener_) {
148 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_volume_changed_cb()) {
149 LoggerE("Cannot unregister volume listener!");
154 void SoundManager::FillMaxVolumeMap() {
159 for (auto& item : platform_enum_map_) {
162 ret = sound_manager_get_max_volume(item.second, &max);
163 if (ret != SOUND_MANAGER_ERROR_NONE) {
164 LoggerE("SoundManagerGetMaxVolumeFailed : %d", ret);
167 LoggerD("maxVolume: %d - %d", item.second, max);
169 max_volume_map_[item.second] = max;
173 PlatformResult SoundManager::GetMaxVolume(sound_type_e type, int* max_volume) {
175 auto it = max_volume_map_.find(type);
176 if (it == max_volume_map_.end()) {
177 std::string sound_type;
178 PlatformResult status = PlatformEnumToStr(type, &sound_type);
179 if (status.IsError()) return status;
180 LoggerE("Failed to find maxVolume of type: %s", sound_type.c_str());
182 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume");
185 *max_volume = it->second;
187 return PlatformResult(ErrorCode::NO_ERROR);
190 double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
192 return static_cast<double>(volume) / max_volume;
195 void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
196 LoggerD("VolumeChangeCallback: type: %d, value: %d", type, value);
199 picojson::value response = picojson::value(picojson::object());
200 picojson::object& response_obj = response.get<picojson::object>();
203 std::make_pair("listenerId", picojson::value("VolumeChangeListener")));
205 std::string sound_type;
206 PlatformResult status = PlatformEnumToStr(type, &sound_type);
207 if (status.IsError())
211 std::make_pair("type", picojson::value(sound_type)));
214 status = GetMaxVolume(type, &max_volume);
215 if (status.IsError())
218 response_obj.insert(std::make_pair(
220 picojson::value(ConvertToSystemVolume(max_volume, value))));
222 instance_.PostMessage(response.serialize().c_str());
225 PlatformResult SoundManager::GetSoundMode(std::string* sound_mode_type) {
227 int isEnableSound = 0;
228 int isEnableVibrate = 0;
230 *sound_mode_type = "MUTE";
232 int ret = vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &isEnableSound);
233 if (VCONF_OK != ret) {
234 LoggerE("Unknown error : %d", ret);
235 return PlatformResult(ErrorCode::UNKNOWN_ERR,
236 "Unknown error: " + std::to_string(ret));
240 vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &isEnableVibrate);
241 if (VCONF_OK != ret) {
242 LoggerE("Unknown error : %d", ret);
243 return PlatformResult(ErrorCode::UNKNOWN_ERR,
244 "Unknown error: " + std::to_string(ret));
247 if (isEnableSound && isEnableVibrate) {
248 LoggerE("Wrong state (sound && vibration)");
249 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform has wrong state.");
253 *sound_mode_type = "SOUND";
254 } else if (isEnableVibrate) {
255 *sound_mode_type = "VIBRATE";
258 return PlatformResult(ErrorCode::NO_ERROR);
261 PlatformResult SoundManager::SetVolume(const picojson::object& args) {
263 const std::string& type = FromJson<std::string>(args, "type");
264 double volume = FromJson<double>(args, "volume");
266 LoggerD("SoundType: %s", type.c_str());
267 LoggerD("volume: %f", volume);
269 if (volume > 1.0 || volume < 0.0) {
270 LoggerE("Volume should be the value between 0 and 1.");
271 return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
272 "Volume should be the value between 0 and 1.");
275 sound_type_e sound_type;
276 PlatformResult status = SoundManager::StrToPlatformEnum(type, &sound_type);
277 if (status.IsError()) return status;
279 auto it = max_volume_map_.find(sound_type);
280 if (it == max_volume_map_.end()) {
281 LoggerE("Failed to find maxVolume of type: %d", type.c_str());
282 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume");
285 int max_volume = it->second;
286 int value = round(volume * max_volume);
287 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
289 int ret = sound_manager_set_volume(sound_type, value);
290 if (ret != SOUND_MANAGER_ERROR_NONE) {
291 LoggerE("Failed to set volume: %d", ret);
292 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to set volume");
295 return PlatformResult(ErrorCode::NO_ERROR);
298 PlatformResult SoundManager::GetVolume(const picojson::object& args,
301 const std::string& type = FromJson<std::string>(args, "type");
304 sound_type_e type_enum;
305 PlatformResult status = SoundManager::StrToPlatformEnum(type, &type_enum);
306 if (status.IsError()) return status;
309 status = GetMaxVolume(type_enum, &max_volume);
310 if (status.IsError()) return status;
312 int ret = sound_manager_get_volume(type_enum, &value);
313 if (ret != SOUND_MANAGER_ERROR_NONE) {
314 LoggerE("Failed to get volume: %d", ret);
315 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get volume");
318 *volume = ConvertToSystemVolume(max_volume, value);
319 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
321 return PlatformResult(ErrorCode::NO_ERROR);
324 void SoundManager::soundModeChangedCb(keynode_t*, void* user_data)
327 if (user_data == nullptr) {
328 LoggerE("Invalid callback data!");
331 SoundManager* self = static_cast<SoundManager*>(user_data);
333 std::string soundModeType;
334 PlatformResult status = self->GetSoundMode(&soundModeType);
336 if (status.IsSuccess() && self->soundModeListener) {
337 self->soundModeListener->OnSoundModeChange(soundModeType);
339 LoggerE("No SoundModeListener attached");
343 PlatformResult SoundManager::SetSoundModeChangeListener(
344 SoundManagerSoundModeChangedListener* listener) {
346 soundModeListener = listener;
347 if (soundModeChangeListening) return PlatformResult(ErrorCode::NO_ERROR);
349 int status = vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
350 SoundManager::soundModeChangedCb, this);
351 if (VCONF_OK == status) {
352 soundModeChangeListening = true;
353 return PlatformResult(ErrorCode::NO_ERROR);
356 LoggerE("SoundModeChangeListener no setted");
357 return PlatformResult(ErrorCode::UNKNOWN_ERR,
358 "SoundModeChangeListener no setted");
361 PlatformResult SoundManager::UnsetSoundModeChangeListener() {
363 soundModeListener = nullptr;
364 if (!soundModeChangeListening) {
365 return PlatformResult(ErrorCode::NO_ERROR);
368 int status = vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
369 SoundManager::soundModeChangedCb);
370 if (VCONF_OK == status) {
371 soundModeChangeListening = false;
372 return PlatformResult(ErrorCode::NO_ERROR);
375 LoggerE("SoundModeChangeListener no unsetted");
376 return PlatformResult(ErrorCode::UNKNOWN_ERR,
377 "SoundModeChangeListener no unsetted");
380 PlatformResult SoundManager::SetVolumeChangeListener() {
382 if (!is_volume_change_listener_) {
383 int ret = sound_manager_set_volume_changed_cb(
384 [](sound_type_e type, unsigned int value, void* ud) {
385 return static_cast<SoundManager*>(ud)
386 ->VolumeChangeCallback(type, value);
388 static_cast<void*>(this));
390 if (ret != SOUND_MANAGER_ERROR_NONE) {
391 LoggerE("Failed to set volume changed callback: error code: %d", ret);
392 return PlatformResult(ErrorCode::UNKNOWN_ERR,
393 "Failed to set volume changed callback");
396 is_volume_change_listener_ = true;
399 return PlatformResult(ErrorCode::NO_ERROR);
402 PlatformResult SoundManager::UnsetVolumeChangeListener() {
404 if (!is_volume_change_listener_) {
405 return PlatformResult(ErrorCode::NO_ERROR);
408 int ret = sound_manager_unset_volume_changed_cb();
409 if (ret != SOUND_MANAGER_ERROR_NONE) {
410 LoggerE("Failed to unset volume changed callback");
411 return PlatformResult(ErrorCode::UNKNOWN_ERR,
412 "Failed to unset volume changed callback");
415 is_volume_change_listener_ = false;
417 return PlatformResult(ErrorCode::NO_ERROR);
420 void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) {
423 int ret = SOUND_MANAGER_ERROR_NONE;
424 sound_device_list_h device_list = nullptr;
425 sound_device_h device = nullptr;
427 picojson::value response = picojson::value(picojson::array());
428 picojson::array& response_array = response.get<picojson::array>();
430 ret = sound_manager_get_current_device_list(mask, &device_list);
431 if (SOUND_MANAGER_ERROR_NONE != ret) {
432 ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed"), &out);
436 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
437 picojson::value val = picojson::value(picojson::object());
438 picojson::object& obj = val.get<picojson::object>();
439 PlatformResult result = GetDeviceInfo(device, true, false, &obj);
441 if (result.IsError()) {
442 ReportError(result, &out);
445 response_array.push_back(val);
448 ReportSuccess(response, out);
451 PlatformResult SoundManager::GetDeviceInfo(sound_device_h device,
453 bool check_connection,
454 picojson::object* obj) {
457 int ret = SOUND_MANAGER_ERROR_NONE;
461 ret = sound_manager_get_device_id(device, &id);
462 if (SOUND_MANAGER_ERROR_NONE != ret) {
463 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device id failed");
465 obj->insert(std::make_pair("id", picojson::value(static_cast<double>(id))));
468 char *name = nullptr;
469 ret = sound_manager_get_device_name(device, &name);
470 if (SOUND_MANAGER_ERROR_NONE != ret) {
471 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device name failed");
473 obj->insert(std::make_pair("name", picojson::value(name)));
476 sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER;
477 ret = sound_manager_get_device_type(device, &type);
478 if (SOUND_MANAGER_ERROR_NONE != ret) {
479 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed");
481 obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type))));
484 sound_device_io_direction_e direction = SOUND_DEVICE_IO_DIRECTION_IN;
485 ret = sound_manager_get_device_io_direction (device, &direction);
486 if (SOUND_MANAGER_ERROR_NONE != ret) {
487 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device direction failed");
489 obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
492 sound_device_state_e state = SOUND_DEVICE_STATE_DEACTIVATED;
493 ret = sound_manager_get_device_state(device, &state);
494 if (SOUND_MANAGER_ERROR_NONE != ret) {
495 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device state failed");
497 obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
500 if (check_connection) {
501 return IsDeviceConnected(type, direction, obj);
504 obj->insert(std::make_pair("isConnected", picojson::value(is_connected)));
505 return PlatformResult(ErrorCode::NO_ERROR);
508 PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type,
509 sound_device_io_direction_e direction,
510 picojson::object* obj) {
513 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
515 case SOUND_DEVICE_IO_DIRECTION_IN:
516 mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK;
518 case SOUND_DEVICE_IO_DIRECTION_OUT:
519 mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK;
521 case SOUND_DEVICE_IO_DIRECTION_BOTH:
522 mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK;
525 LoggerD("Invalid IOType (%d)", direction);
526 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Invalid IO type");
529 int ret = SOUND_MANAGER_ERROR_NONE;
530 sound_device_list_h device_list = nullptr;
531 sound_device_h device = nullptr;
532 sound_device_type_e device_type = SOUND_DEVICE_BUILTIN_SPEAKER;
534 ret = sound_manager_get_current_device_list(mask, &device_list);
535 if (SOUND_MANAGER_ERROR_NONE != ret) {
536 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed");
539 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
540 ret = sound_manager_get_device_type(device, &device_type);
541 if (SOUND_MANAGER_ERROR_NONE != ret) {
542 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device type failed");
545 if (type == device_type) {
546 obj->insert(std::make_pair("isConnected", picojson::value(true)));
547 return PlatformResult(ErrorCode::NO_ERROR);
551 obj->insert(std::make_pair("isConnected", picojson::value(false)));
552 return PlatformResult(ErrorCode::NO_ERROR);
555 void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) {
558 picojson::value response = picojson::value(picojson::object());
559 picojson::object& response_obj = response.get<picojson::object>();
561 PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj);
563 if (result.IsSuccess()) {
564 response_obj.insert(std::make_pair(
565 "listenerId", picojson::value("SoundDeviceStateChangeCallback")));
567 auto call_response = [this, response]()->void {
568 instance_.PostMessage(response.serialize().c_str());
571 TaskQueue::GetInstance().Async(call_response);
575 void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) {
577 SoundManager* h = static_cast<SoundManager*>(user_data);
578 h->DeviceChangeCB(device, is_connected, false);
581 void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info,
585 if (SOUND_DEVICE_CHANGED_INFO_STATE == changed_info) {
586 SoundManager* h = static_cast<SoundManager*>(user_data);
587 h->DeviceChangeCB(device, false, true);
591 PlatformResult SoundManager::AddDeviceStateChangeListener() {
594 int ret = SOUND_MANAGER_ERROR_NONE;
595 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
597 if (!sound_device_change_listener_) {
598 ret = sound_manager_set_device_connected_cb(mask, DeviceConnectionChangeCB, this);
599 if (SOUND_MANAGER_ERROR_NONE != ret) {
600 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting connection listener failed");
603 ret = sound_manager_set_device_information_changed_cb(mask, DeviceActivationChangeCB, this);
604 if (SOUND_MANAGER_ERROR_NONE != ret) {
605 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Setting information listener failed");
608 sound_device_change_listener_ = true;
611 return PlatformResult(ErrorCode::NO_ERROR);
614 PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
617 if (sound_device_change_listener_) {
618 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
619 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed");
622 if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
623 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed");
626 sound_device_change_listener_ = false;
629 return PlatformResult(ErrorCode::NO_ERROR);
633 } // namespace extension