Merge "Revert "[secureelement] - Checking privileges moved to JS layer"" into tizen_3.0
[platform/core/api/webapi-plugins.git] / src / sound / sound_manager.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "sound/sound_manager.h"
18
19 #include <tizen/tizen.h>
20 #include <vconf.h>
21 #include <vconf-keys.h>
22
23 #include "common/converter.h"
24 #include "common/logger.h"
25 #include "common/task-queue.h"
26 #include "common/tools.h"
27
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.
31 #ifndef VCONF_OK
32 #define VCONF_OK 0
33 #endif
34
35 #include "sound/sound_instance.h"
36
37 namespace extension {
38 namespace sound {
39
40 using namespace common;
41 using namespace common::tools;
42
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}};
50
51 PlatformResult SoundManager::StrToPlatformEnum(const std::string& key,
52                                                sound_type_e* sound_type) {
53   LoggerD("Enter");
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);
57   }
58
59   *sound_type = platform_enum_map_.at(key);
60
61   return PlatformResult(ErrorCode::NO_ERROR);
62 }
63
64 PlatformResult SoundManager::PlatformEnumToStr(const sound_type_e value,
65                                                std::string* sound_type) {
66   LoggerD("Enter");
67   for (auto& item : platform_enum_map_) {
68     if (item.second == value) {
69       *sound_type = item.first;
70
71       return PlatformResult(ErrorCode::NO_ERROR);
72     }
73   }
74
75   std::string message =
76       "Platform enum value " + std::to_string(value) + " not found";
77
78   return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, message);
79 }
80
81 std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) {
82   LoggerD("Enter");
83   switch (type) {
84     case SOUND_DEVICE_BUILTIN_SPEAKER:
85       return "SPEAKER";
86     case SOUND_DEVICE_BUILTIN_RECEIVER:
87       return "RECEIVER";
88     case SOUND_DEVICE_BUILTIN_MIC:
89       return "MIC";
90     case SOUND_DEVICE_AUDIO_JACK:
91       return "AUDIO_JACK";
92     case SOUND_DEVICE_BLUETOOTH:
93       return "BLUETOOTH";
94     case SOUND_DEVICE_HDMI:
95       return "HDMI";
96     case SOUND_DEVICE_MIRRORING:
97       return "MIRRORING";
98     case SOUND_DEVICE_USB_AUDIO:
99       return "USB_AUDIO";
100     default:
101       LoggerE("Invalid sound_device_type_e: %d", type);
102       return "";
103   }
104 }
105
106 std::string SoundManager::SoundIOTypeToString(sound_device_io_direction_e type) {
107   LoggerD("Enter");
108   switch (type) {
109     case SOUND_DEVICE_IO_DIRECTION_IN:
110       return "IN";
111     case SOUND_DEVICE_IO_DIRECTION_OUT:
112       return "OUT";
113     case SOUND_DEVICE_IO_DIRECTION_BOTH:
114       return "BOTH";
115     default:
116       LoggerE("Invalid sound_device_io_direction_e: %d", type);
117       return "";
118   }
119 }
120
121 SoundManager::SoundManager(SoundInstance& instance)
122     : is_volume_change_listener_(false),
123       soundModeChangeListening(false),
124       sound_device_change_listener_(false),
125       instance_(instance),
126       soundModeListener(nullptr) {
127   FillMaxVolumeMap();
128 }
129
130 SoundManager::~SoundManager() {
131   LoggerD("Enter");
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!");
136     }
137   }
138
139   if (sound_device_change_listener_) {
140     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
141       LoggerE("Cannot unregister connection listener!");
142     }
143
144     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
145       LoggerE("Cannot unregister information listener!");
146     }
147   }
148
149   if (is_volume_change_listener_) {
150     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_volume_changed_cb()) {
151       LoggerE("Cannot unregister volume listener!");
152     }
153   }
154 }
155
156 void SoundManager::FillMaxVolumeMap() {
157   LoggerD("Enter");
158   int max = 100;
159   int ret;
160
161   for (auto& item : platform_enum_map_) {
162     max = 100;
163
164     ret = sound_manager_get_max_volume(item.second, &max);
165     if (ret != SOUND_MANAGER_ERROR_NONE) {
166       LoggerE("SoundManagerGetMaxVolumeFailed : %d", ret);
167     }
168
169     LoggerD("maxVolume: %d - %d", item.second, max);
170
171     max_volume_map_[item.second] = max;
172   }
173 }
174
175 PlatformResult SoundManager::GetMaxVolume(sound_type_e type, int* max_volume) {
176   LoggerD("Enter");
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
183     return LogAndCreateResult(
184               ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume",
185               ("Failed to find maxVolume of type: %s", sound_type.c_str()));
186   }
187
188   *max_volume = it->second;
189
190   return PlatformResult(ErrorCode::NO_ERROR);
191 }
192
193 double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
194   LoggerD("Enter");
195   return round(static_cast<double>(volume) * 100 / max_volume) / 100;
196 }
197
198 void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
199   LoggerD("VolumeChangeCallback: type: %d, value: %d", type, value);
200
201   // Prepare response
202   picojson::value response = picojson::value(picojson::object());
203   picojson::object& response_obj = response.get<picojson::object>();
204
205   response_obj.insert(
206       std::make_pair("listenerId", picojson::value("VolumeChangeListener")));
207
208   std::string sound_type;
209   PlatformResult status = PlatformEnumToStr(type, &sound_type);
210   if (status.IsError())
211       return;
212
213   response_obj.insert(
214       std::make_pair("type", picojson::value(sound_type)));
215
216   int max_volume;
217   status = GetMaxVolume(type, &max_volume);
218   if (status.IsError())
219       return;
220
221   response_obj.insert(std::make_pair(
222       "volume",
223       picojson::value(ConvertToSystemVolume(max_volume, value))));
224
225   Instance::PostMessage(&instance_, response.serialize().c_str());
226 }
227
228 PlatformResult SoundManager::GetSoundMode(std::string* sound_mode_type) {
229   LoggerD("Enter");
230   int isEnableSound = 0;
231   int isEnableVibrate = 0;
232
233   *sound_mode_type = "MUTE";
234
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)));
240   }
241
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)));
247   }
248
249   if (isEnableSound && isEnableVibrate) {
250     LogAndCreateResult(
251         ErrorCode::UNKNOWN_ERR, "Platform has wrong state.",
252         ("Wrong state (sound && vibration)"));
253   }
254
255   if (isEnableSound) {
256     *sound_mode_type = "SOUND";
257   } else if (isEnableVibrate) {
258     *sound_mode_type = "VIBRATE";
259   }
260
261   return PlatformResult(ErrorCode::NO_ERROR);
262 }
263
264 PlatformResult SoundManager::SetVolume(const picojson::object& args) {
265   LoggerD("Enter");
266   const std::string& type = FromJson<std::string>(args, "type");
267   double volume = FromJson<double>(args, "volume");
268
269   LoggerD("SoundType: %s", type.c_str());
270   LoggerD("volume: %f", volume);
271
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.");
276   }
277
278   sound_type_e sound_type;
279   PlatformResult status = SoundManager::StrToPlatformEnum(type, &sound_type);
280   if (status.IsError()) return status;
281
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()));
287   }
288
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);
292
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)));
298   }
299
300   return PlatformResult(ErrorCode::NO_ERROR);
301 }
302
303 PlatformResult SoundManager::GetVolume(const picojson::object& args,
304                                        double* volume) {
305   LoggerD("Enter");
306   const std::string& type = FromJson<std::string>(args, "type");
307   int value = 0;
308
309   sound_type_e type_enum;
310   PlatformResult status = SoundManager::StrToPlatformEnum(type, &type_enum);
311   if (status.IsError()) return status;
312
313   int max_volume;
314   status = GetMaxVolume(type_enum, &max_volume);
315   if (status.IsError()) return status;
316
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)));
322   }
323
324   *volume = ConvertToSystemVolume(max_volume, value);
325   LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
326
327   return PlatformResult(ErrorCode::NO_ERROR);
328 }
329
330 void SoundManager::soundModeChangedCb(keynode_t*, void* user_data)
331 {
332   LoggerD("Enter");
333   if (user_data == nullptr) {
334     LoggerE("Invalid callback data!");
335     return;
336   }
337   SoundManager* self = static_cast<SoundManager*>(user_data);
338
339   std::string soundModeType;
340   PlatformResult status = self->GetSoundMode(&soundModeType);
341
342   if (status.IsSuccess() && self->soundModeListener) {
343     self->soundModeListener->OnSoundModeChange(soundModeType);
344   } else {
345     LoggerE("No SoundModeListener attached");
346   }
347 }
348
349 PlatformResult SoundManager::SetSoundModeChangeListener(
350     SoundManagerSoundModeChangedListener* listener) {
351   LoggerD("Enter");
352   soundModeListener = listener;
353   if (soundModeChangeListening) return PlatformResult(ErrorCode::NO_ERROR);
354
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);
360   }
361
362   return LogAndCreateResult(
363             ErrorCode::UNKNOWN_ERR, "SoundModeChangeListener not set");
364 }
365
366 PlatformResult SoundManager::UnsetSoundModeChangeListener() {
367   LoggerD("Enter");
368   soundModeListener = nullptr;
369   if (!soundModeChangeListening) {
370     return PlatformResult(ErrorCode::NO_ERROR);
371   }
372
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);
378   }
379
380   return LogAndCreateResult(
381             ErrorCode::UNKNOWN_ERR, "SoundModeChangeListener not unset");
382 }
383
384 PlatformResult SoundManager::SetVolumeChangeListener() {
385   LoggerD("Enter");
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);
391         },
392         static_cast<void*>(this));
393
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)));
399     }
400
401     is_volume_change_listener_ = true;
402   }
403
404   return PlatformResult(ErrorCode::NO_ERROR);
405 }
406
407 PlatformResult SoundManager::UnsetVolumeChangeListener() {
408   LoggerD("Enter");
409   if (!is_volume_change_listener_) {
410     return PlatformResult(ErrorCode::NO_ERROR);
411   }
412
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)));
418   }
419
420   is_volume_change_listener_ = false;
421
422   return PlatformResult(ErrorCode::NO_ERROR);
423 }
424
425 void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) {
426   LoggerD("Entered");
427
428   sound_device_list_h device_list = nullptr;
429   sound_device_h device = nullptr;
430
431   picojson::value response = picojson::value(picojson::array());
432   picojson::array& response_array = response.get<picojson::array>();
433
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) {
436     LogAndReportError(
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)));
439     return;
440   }
441
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);
446
447     if (result.IsError()) {
448       LogAndReportError(result, &out);
449       return;
450     }
451     response_array.push_back(val);
452   }
453
454   ReportSuccess(response, out);
455 }
456
457 PlatformResult SoundManager::GetDeviceInfo(sound_device_h device,
458                                            bool is_connected,
459                                            bool check_connection,
460                                            picojson::object* obj) {
461   LoggerD("Entered");
462
463   //get id
464   int id = 0;
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)));
470   }
471   obj->insert(std::make_pair("id", picojson::value(static_cast<double>(id))));
472
473   //get name
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)));
480   }
481   obj->insert(std::make_pair("name", picojson::value(name)));
482
483   //get type
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)));
490   }
491   obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type))));
492
493   //get direction
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)));
500   }
501   obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
502
503   //get state
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)));
510   }
511   obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
512
513   //get connection
514   if (check_connection) {
515     return IsDeviceConnected(type, direction, obj);
516   }
517
518   obj->insert(std::make_pair("isConnected", picojson::value(is_connected)));
519   return PlatformResult(ErrorCode::NO_ERROR);
520 }
521
522 PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type,
523                                                sound_device_io_direction_e direction,
524                                                picojson::object* obj) {
525   LoggerD("Entered");
526
527   sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
528   switch (direction) {
529     case SOUND_DEVICE_IO_DIRECTION_IN:
530       mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK;
531       break;
532     case SOUND_DEVICE_IO_DIRECTION_OUT:
533       mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK;
534       break;
535     case SOUND_DEVICE_IO_DIRECTION_BOTH:
536       mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK;
537       break;
538     default:
539       return LogAndCreateResult(
540                 ErrorCode::UNKNOWN_ERR, "Invalid IO type",
541                 ("Invalid IOType (%d)", direction));
542   }
543
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;
547
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)));
553   }
554
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)));
561     }
562
563     if (type == device_type) {
564       obj->insert(std::make_pair("isConnected", picojson::value(true)));
565       return PlatformResult(ErrorCode::NO_ERROR);
566     }
567   }
568
569   obj->insert(std::make_pair("isConnected", picojson::value(false)));
570   return PlatformResult(ErrorCode::NO_ERROR);
571 }
572
573 void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) {
574   LoggerD("Entered");
575
576   picojson::value response = picojson::value(picojson::object());
577   picojson::object& response_obj = response.get<picojson::object>();
578
579   PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj);
580
581   if (result.IsSuccess()) {
582     response_obj.insert(std::make_pair(
583         "listenerId", picojson::value("SoundDeviceStateChangeCallback")));
584
585     auto call_response = [this, response]()->void {
586       Instance::PostMessage(&instance_, response.serialize().c_str());
587     };
588
589     TaskQueue::GetInstance().Async(call_response);
590   }
591 }
592
593 void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) {
594   LoggerD("Entered");
595   SoundManager* h = static_cast<SoundManager*>(user_data);
596   h->DeviceChangeCB(device, is_connected, false);
597 }
598
599 void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info,
600                               void *user_data) {
601   LoggerD("Entered");
602
603   if (SOUND_DEVICE_CHANGED_INFO_STATE == changed_info) {
604     SoundManager* h = static_cast<SoundManager*>(user_data);
605     h->DeviceChangeCB(device, false, true);
606   }
607 }
608
609 PlatformResult SoundManager::AddDeviceStateChangeListener() {
610   LoggerD("Entered");
611
612   int ret = SOUND_MANAGER_ERROR_NONE;
613   sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
614
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)));
622     }
623
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)));
630     }
631
632     sound_device_change_listener_ = true;
633   }
634
635   return PlatformResult(ErrorCode::NO_ERROR);
636 }
637
638 PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
639   LoggerD("Entered");
640
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)));
647     }
648
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)));
654     }
655
656     sound_device_change_listener_ = false;
657   }
658
659   return PlatformResult(ErrorCode::NO_ERROR);
660 }
661
662 }  // namespace sound
663 }  // namespace extension