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 LogAndCreateResult(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 LogAndCreateResult(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;
183 return LogAndCreateResult(
184 ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume",
185 ("Failed to find maxVolume of type: %s", sound_type.c_str()));
188 *max_volume = it->second;
190 return PlatformResult(ErrorCode::NO_ERROR);
193 double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
195 return round(static_cast<double>(volume) * 100 / max_volume) / 100;
198 void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
199 LoggerD("VolumeChangeCallback: type: %d, value: %d", type, value);
202 picojson::value response = picojson::value(picojson::object());
203 picojson::object& response_obj = response.get<picojson::object>();
206 std::make_pair("listenerId", picojson::value("VolumeChangeListener")));
208 std::string sound_type;
209 PlatformResult status = PlatformEnumToStr(type, &sound_type);
210 if (status.IsError())
214 std::make_pair("type", picojson::value(sound_type)));
217 status = GetMaxVolume(type, &max_volume);
218 if (status.IsError())
221 response_obj.insert(std::make_pair(
223 picojson::value(ConvertToSystemVolume(max_volume, value))));
225 Instance::PostMessage(&instance_, response.serialize().c_str());
228 PlatformResult SoundManager::GetSoundMode(std::string* sound_mode_type) {
230 int isEnableSound = 0;
231 int isEnableVibrate = 0;
233 *sound_mode_type = "MUTE";
235 int ret = vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &isEnableSound);
236 if (VCONF_OK != ret) {
237 return LogAndCreateResult(
238 ErrorCode::UNKNOWN_ERR, "Unknown error: " + std::to_string(ret),
239 ("vconf_get_bool error: %d (%s)", ret, get_error_message(ret)));
242 ret = vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &isEnableVibrate);
243 if (VCONF_OK != ret) {
244 return LogAndCreateResult(
245 ErrorCode::UNKNOWN_ERR, "Unknown error: " + std::to_string(ret),
246 ("vconf_get_bool error: %d (%s)", ret, get_error_message(ret)));
249 if (isEnableSound && isEnableVibrate) {
251 ErrorCode::UNKNOWN_ERR, "Platform has wrong state.",
252 ("Wrong state (sound && vibration)"));
256 *sound_mode_type = "SOUND";
257 } else if (isEnableVibrate) {
258 *sound_mode_type = "VIBRATE";
261 return PlatformResult(ErrorCode::NO_ERROR);
264 PlatformResult SoundManager::SetVolume(const picojson::object& args) {
266 const std::string& type = FromJson<std::string>(args, "type");
267 double volume = FromJson<double>(args, "volume");
269 LoggerD("SoundType: %s", type.c_str());
270 LoggerD("volume: %f", volume);
272 if (volume > 1.0 || volume < 0.0) {
273 return LogAndCreateResult(
274 ErrorCode::INVALID_VALUES_ERR,
275 "Volume should be the value between 0 and 1.");
278 sound_type_e sound_type;
279 PlatformResult status = SoundManager::StrToPlatformEnum(type, &sound_type);
280 if (status.IsError()) return status;
282 auto it = max_volume_map_.find(sound_type);
283 if (it == max_volume_map_.end()) {
284 return LogAndCreateResult(
285 ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume",
286 ("Failed to find maxVolume of type: %d", type.c_str()));
289 int max_volume = it->second;
290 int value = round(volume * max_volume);
291 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
293 int ret = sound_manager_set_volume(sound_type, value);
294 if (ret != SOUND_MANAGER_ERROR_NONE) {
295 return LogAndCreateResult(
296 ErrorCode::UNKNOWN_ERR, "Failed to set volume",
297 ("Failed to set volume: %d (%s)", ret, get_error_message(ret)));
300 return PlatformResult(ErrorCode::NO_ERROR);
303 PlatformResult SoundManager::GetVolume(const picojson::object& args,
306 const std::string& type = FromJson<std::string>(args, "type");
309 sound_type_e type_enum;
310 PlatformResult status = SoundManager::StrToPlatformEnum(type, &type_enum);
311 if (status.IsError()) return status;
314 status = GetMaxVolume(type_enum, &max_volume);
315 if (status.IsError()) return status;
317 int ret = sound_manager_get_volume(type_enum, &value);
318 if (ret != SOUND_MANAGER_ERROR_NONE) {
319 return LogAndCreateResult(
320 ErrorCode::UNKNOWN_ERR, "Failed to get volume",
321 ("Failed to get volume: %d (%s)", ret, get_error_message(ret)));
324 *volume = ConvertToSystemVolume(max_volume, value);
325 LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
327 return PlatformResult(ErrorCode::NO_ERROR);
330 void SoundManager::soundModeChangedCb(keynode_t*, void* user_data)
333 if (user_data == nullptr) {
334 LoggerE("Invalid callback data!");
337 SoundManager* self = static_cast<SoundManager*>(user_data);
339 std::string soundModeType;
340 PlatformResult status = self->GetSoundMode(&soundModeType);
342 if (status.IsSuccess() && self->soundModeListener) {
343 self->soundModeListener->OnSoundModeChange(soundModeType);
345 LoggerE("No SoundModeListener attached");
349 PlatformResult SoundManager::SetSoundModeChangeListener(
350 SoundManagerSoundModeChangedListener* listener) {
352 soundModeListener = listener;
353 if (soundModeChangeListening) return PlatformResult(ErrorCode::NO_ERROR);
355 int status = vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
356 SoundManager::soundModeChangedCb, this);
357 if (VCONF_OK == status) {
358 soundModeChangeListening = true;
359 return PlatformResult(ErrorCode::NO_ERROR);
362 return LogAndCreateResult(
363 ErrorCode::UNKNOWN_ERR, "SoundModeChangeListener not set");
366 PlatformResult SoundManager::UnsetSoundModeChangeListener() {
368 soundModeListener = nullptr;
369 if (!soundModeChangeListening) {
370 return PlatformResult(ErrorCode::NO_ERROR);
373 int status = vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL,
374 SoundManager::soundModeChangedCb);
375 if (VCONF_OK == status) {
376 soundModeChangeListening = false;
377 return PlatformResult(ErrorCode::NO_ERROR);
380 return LogAndCreateResult(
381 ErrorCode::UNKNOWN_ERR, "SoundModeChangeListener not unset");
384 PlatformResult SoundManager::SetVolumeChangeListener() {
386 if (!is_volume_change_listener_) {
387 int ret = sound_manager_set_volume_changed_cb(
388 [](sound_type_e type, unsigned int value, void* ud) {
389 return static_cast<SoundManager*>(ud)
390 ->VolumeChangeCallback(type, value);
392 static_cast<void*>(this));
394 if (ret != SOUND_MANAGER_ERROR_NONE) {
395 return LogAndCreateResult(
396 ErrorCode::UNKNOWN_ERR, "Failed to set volume changed callback",
397 ("Failed to set volume changed callback: error: %d (%s)",
398 ret, get_error_message(ret)));
401 is_volume_change_listener_ = true;
404 return PlatformResult(ErrorCode::NO_ERROR);
407 PlatformResult SoundManager::UnsetVolumeChangeListener() {
409 if (!is_volume_change_listener_) {
410 return PlatformResult(ErrorCode::NO_ERROR);
413 int ret = sound_manager_unset_volume_changed_cb();
414 if (ret != SOUND_MANAGER_ERROR_NONE) {
415 return LogAndCreateResult(
416 ErrorCode::UNKNOWN_ERR, "Failed to unset volume changed callback",
417 ("sound_manager_unset_volume_changed_cb error: %d (%s)", ret, get_error_message(ret)));
420 is_volume_change_listener_ = false;
422 return PlatformResult(ErrorCode::NO_ERROR);
425 void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) {
428 sound_device_list_h device_list = nullptr;
429 sound_device_h device = nullptr;
431 picojson::value response = picojson::value(picojson::array());
432 picojson::array& response_array = response.get<picojson::array>();
434 int ret = sound_manager_get_current_device_list(mask, &device_list);
435 if (SOUND_MANAGER_ERROR_NONE != ret && SOUND_MANAGER_ERROR_NO_DATA != ret) {
437 PlatformResult(ErrorCode::UNKNOWN_ERR, "Getting device list failed"), &out,
438 ("sound_manager_get_current_device_list error: %d (%s)", ret, get_error_message(ret)));
442 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
443 picojson::value val = picojson::value(picojson::object());
444 picojson::object& obj = val.get<picojson::object>();
445 PlatformResult result = GetDeviceInfo(device, true, false, &obj);
447 if (result.IsError()) {
448 LogAndReportError(result, &out);
451 response_array.push_back(val);
454 ReportSuccess(response, out);
457 PlatformResult SoundManager::GetDeviceInfo(sound_device_h device,
459 bool check_connection,
460 picojson::object* obj) {
465 int ret = sound_manager_get_device_id(device, &id);
466 if (SOUND_MANAGER_ERROR_NONE != ret) {
467 return LogAndCreateResult(
468 ErrorCode::UNKNOWN_ERR, "Getting device id failed",
469 ("sound_manager_get_device_id error: %d (%s)", ret, get_error_message(ret)));
471 obj->insert(std::make_pair("id", picojson::value(static_cast<double>(id))));
474 char *name = nullptr;
475 ret = sound_manager_get_device_name(device, &name);
476 if (SOUND_MANAGER_ERROR_NONE != ret) {
477 return LogAndCreateResult(
478 ErrorCode::UNKNOWN_ERR, "Getting device name failed",
479 ("sound_manager_get_device_name error: %d (%s)", ret, get_error_message(ret)));
481 obj->insert(std::make_pair("name", picojson::value(name)));
484 sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER;
485 ret = sound_manager_get_device_type(device, &type);
486 if (SOUND_MANAGER_ERROR_NONE != ret) {
487 return LogAndCreateResult(
488 ErrorCode::UNKNOWN_ERR, "Getting device type failed",
489 ("sound_manager_get_device_type error: %d (%s)", ret, get_error_message(ret)));
491 obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type))));
494 sound_device_io_direction_e direction = SOUND_DEVICE_IO_DIRECTION_IN;
495 ret = sound_manager_get_device_io_direction (device, &direction);
496 if (SOUND_MANAGER_ERROR_NONE != ret) {
497 return LogAndCreateResult(
498 ErrorCode::UNKNOWN_ERR, "Getting device direction failed",
499 ("sound_manager_get_device_io_direction error: %d (%s)", ret, get_error_message(ret)));
501 obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
504 sound_device_state_e state = SOUND_DEVICE_STATE_DEACTIVATED;
505 ret = sound_manager_get_device_state(device, &state);
506 if (SOUND_MANAGER_ERROR_NONE != ret) {
507 return LogAndCreateResult(
508 ErrorCode::UNKNOWN_ERR, "Getting device state failed",
509 ("sound_manager_get_device_state error: %d (%s)", ret, get_error_message(ret)));
511 obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
514 if (check_connection) {
515 return IsDeviceConnected(type, direction, obj);
518 obj->insert(std::make_pair("isConnected", picojson::value(is_connected)));
519 return PlatformResult(ErrorCode::NO_ERROR);
522 PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type,
523 sound_device_io_direction_e direction,
524 picojson::object* obj) {
527 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
529 case SOUND_DEVICE_IO_DIRECTION_IN:
530 mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK;
532 case SOUND_DEVICE_IO_DIRECTION_OUT:
533 mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK;
535 case SOUND_DEVICE_IO_DIRECTION_BOTH:
536 mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK;
539 return LogAndCreateResult(
540 ErrorCode::UNKNOWN_ERR, "Invalid IO type",
541 ("Invalid IOType (%d)", direction));
544 sound_device_list_h device_list = nullptr;
545 sound_device_h device = nullptr;
546 sound_device_type_e device_type = SOUND_DEVICE_BUILTIN_SPEAKER;
548 int ret = sound_manager_get_current_device_list(mask, &device_list);
549 if (SOUND_MANAGER_ERROR_NONE != ret) {
550 return LogAndCreateResult(
551 ErrorCode::UNKNOWN_ERR, "Getting device list failed",
552 ("sound_manager_get_current_device_list error: %d (%s)", ret, get_error_message(ret)));
555 while (!(ret = sound_manager_get_next_device(device_list, &device))) {
556 ret = sound_manager_get_device_type(device, &device_type);
557 if (SOUND_MANAGER_ERROR_NONE != ret) {
558 return LogAndCreateResult(
559 ErrorCode::UNKNOWN_ERR, "Getting device type failed",
560 ("sound_manager_get_device_type error: %d (%s)", ret, get_error_message(ret)));
563 if (type == device_type) {
564 obj->insert(std::make_pair("isConnected", picojson::value(true)));
565 return PlatformResult(ErrorCode::NO_ERROR);
569 obj->insert(std::make_pair("isConnected", picojson::value(false)));
570 return PlatformResult(ErrorCode::NO_ERROR);
573 void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) {
576 picojson::value response = picojson::value(picojson::object());
577 picojson::object& response_obj = response.get<picojson::object>();
579 PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj);
581 if (result.IsSuccess()) {
582 response_obj.insert(std::make_pair(
583 "listenerId", picojson::value("SoundDeviceStateChangeCallback")));
585 auto call_response = [this, response]()->void {
586 Instance::PostMessage(&instance_, response.serialize().c_str());
589 TaskQueue::GetInstance().Async(call_response);
593 void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) {
595 SoundManager* h = static_cast<SoundManager*>(user_data);
596 h->DeviceChangeCB(device, is_connected, false);
599 void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info,
603 if (SOUND_DEVICE_CHANGED_INFO_STATE == changed_info) {
604 SoundManager* h = static_cast<SoundManager*>(user_data);
605 h->DeviceChangeCB(device, false, true);
609 PlatformResult SoundManager::AddDeviceStateChangeListener() {
612 int ret = SOUND_MANAGER_ERROR_NONE;
613 sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
615 if (!sound_device_change_listener_) {
616 ret = sound_manager_set_device_connected_cb(mask, DeviceConnectionChangeCB, this);
617 if (SOUND_MANAGER_ERROR_NONE != ret) {
618 return LogAndCreateResult(
619 ErrorCode::UNKNOWN_ERR, "Setting connection listener failed",
620 ("sound_manager_set_device_connected_cb error: %d (%s)",
621 ret, get_error_message(ret)));
624 ret = sound_manager_set_device_information_changed_cb(mask, DeviceActivationChangeCB, this);
625 if (SOUND_MANAGER_ERROR_NONE != ret) {
626 return LogAndCreateResult(
627 ErrorCode::UNKNOWN_ERR, "Setting information listener failed",
628 ("sound_manager_set_device_information_changed_cb error: %d (%s)",
629 ret, get_error_message(ret)));
632 sound_device_change_listener_ = true;
635 return PlatformResult(ErrorCode::NO_ERROR);
638 PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
641 if (sound_device_change_listener_) {
642 int ret = sound_manager_unset_device_connected_cb();
643 if (SOUND_MANAGER_ERROR_NONE != ret) {
644 return LogAndCreateResult(
645 ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed",
646 ("sound_manager_unset_device_connected_cb error: %d (%s)", ret, get_error_message(ret)));
649 ret = sound_manager_unset_device_information_changed_cb();
650 if (SOUND_MANAGER_ERROR_NONE != ret) {
651 return LogAndCreateResult(
652 ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed",
653 ("sound_manager_unset_device_information_changed_cb error: %d (%s)", ret, get_error_message(ret)));
656 sound_device_change_listener_ = false;
659 return PlatformResult(ErrorCode::NO_ERROR);
663 } // namespace extension