Merge "[Filesystem] In case of error invoke callback instead of throwing an exception...
[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/task-queue.h"
24
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.
28 #ifndef VCONF_OK
29 #define VCONF_OK 0
30 #endif
31
32 #include "sound/sound_instance.h"
33 #include "common/logger.h"
34 #include "common/converter.h"
35
36 namespace extension {
37 namespace sound {
38
39 using namespace common;
40 using namespace common::tools;
41
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}};
49
50 PlatformResult SoundManager::StrToPlatformEnum(const std::string& key,
51                                                sound_type_e* sound_type) {
52   LoggerD("Enter");
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);
56   }
57
58   *sound_type = platform_enum_map_.at(key);
59
60   return PlatformResult(ErrorCode::NO_ERROR);
61 }
62
63 PlatformResult SoundManager::PlatformEnumToStr(const sound_type_e value,
64                                                std::string* sound_type) {
65   LoggerD("Enter");
66   for (auto& item : platform_enum_map_) {
67     if (item.second == value) {
68       *sound_type = item.first;
69
70       return PlatformResult(ErrorCode::NO_ERROR);
71     }
72   }
73
74   std::string message =
75       "Platform enum value " + std::to_string(value) + " not found";
76
77   return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message);
78 }
79
80 std::string SoundManager::SoundDeviceTypeToString(sound_device_type_e type) {
81   LoggerD("Enter");
82   switch (type) {
83     case SOUND_DEVICE_BUILTIN_SPEAKER:
84       return "SPEAKER";
85     case SOUND_DEVICE_BUILTIN_RECEIVER:
86       return "RECEIVER";
87     case SOUND_DEVICE_BUILTIN_MIC:
88       return "MIC";
89     case SOUND_DEVICE_AUDIO_JACK:
90       return "AUDIO_JACK";
91     case SOUND_DEVICE_BLUETOOTH:
92       return "BLUETOOTH";
93     case SOUND_DEVICE_HDMI:
94       return "HDMI";
95     case SOUND_DEVICE_MIRRORING:
96       return "MIRRORING";
97     case SOUND_DEVICE_USB_AUDIO:
98       return "USB_AUDIO";
99     default:
100       LoggerE("Invalid sound_device_type_e: %d", type);
101       return "";
102   }
103 }
104
105 std::string SoundManager::SoundIOTypeToString(sound_device_io_direction_e type) {
106   LoggerD("Enter");
107   switch (type) {
108     case SOUND_DEVICE_IO_DIRECTION_IN:
109       return "IN";
110     case SOUND_DEVICE_IO_DIRECTION_OUT:
111       return "OUT";
112     case SOUND_DEVICE_IO_DIRECTION_BOTH:
113       return "BOTH";
114     default:
115       LoggerE("Invalid sound_device_io_direction_e: %d", type);
116       return "";
117   }
118 }
119
120 SoundManager::SoundManager(SoundInstance& instance)
121     : soundModeChangeListening(false),
122       sound_device_change_listener_(false),
123       instance_(instance),
124       soundModeListener(nullptr) {
125   FillMaxVolumeMap();
126 }
127
128 SoundManager::~SoundManager() {
129   LoggerD("Enter");
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!");
134     }
135   }
136
137   if (sound_device_change_listener_) {
138     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_connected_cb()) {
139       LoggerE("Cannot unregister connection listener!");
140     }
141
142     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
143       LoggerE("Cannot unregister information listener!");
144     }
145   }
146
147   if (is_volume_change_listener_) {
148     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_volume_changed_cb()) {
149       LoggerE("Cannot unregister volume listener!");
150     }
151   }
152 }
153
154 void SoundManager::FillMaxVolumeMap() {
155   LoggerD("Enter");
156   int max = 100;
157   int ret;
158
159   for (auto& item : platform_enum_map_) {
160     max = 100;
161
162     ret = sound_manager_get_max_volume(item.second, &max);
163     if (ret != SOUND_MANAGER_ERROR_NONE) {
164       LoggerE("SoundManagerGetMaxVolumeFailed : %d", ret);
165     }
166
167     LoggerD("maxVolume: %d - %d", item.second, max);
168
169     max_volume_map_[item.second] = max;
170   }
171 }
172
173 PlatformResult SoundManager::GetMaxVolume(sound_type_e type, int* max_volume) {
174   LoggerD("Enter");
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());
181
182     return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find maxVolume");
183   }
184
185   *max_volume = it->second;
186
187   return PlatformResult(ErrorCode::NO_ERROR);
188 }
189
190 double SoundManager::ConvertToSystemVolume(int max_volume, int volume) {
191   LoggerD("Enter");
192   return static_cast<double>(volume) / max_volume;
193 }
194
195 void SoundManager::VolumeChangeCallback(sound_type_e type, unsigned int value) {
196   LoggerD("VolumeChangeCallback: type: %d, value: %d", type, value);
197
198   // Prepare response
199   picojson::value response = picojson::value(picojson::object());
200   picojson::object& response_obj = response.get<picojson::object>();
201
202   response_obj.insert(
203       std::make_pair("listenerId", picojson::value("VolumeChangeListener")));
204
205   std::string sound_type;
206   PlatformResult status = PlatformEnumToStr(type, &sound_type);
207   if (status.IsError())
208       return;
209
210   response_obj.insert(
211       std::make_pair("type", picojson::value(sound_type)));
212
213   int max_volume;
214   status = GetMaxVolume(type, &max_volume);
215   if (status.IsError())
216       return;
217
218   response_obj.insert(std::make_pair(
219       "volume",
220       picojson::value(ConvertToSystemVolume(max_volume, value))));
221
222   instance_.PostMessage(response.serialize().c_str());
223 }
224
225 PlatformResult SoundManager::GetSoundMode(std::string* sound_mode_type) {
226   LoggerD("Enter");
227   int isEnableSound = 0;
228   int isEnableVibrate = 0;
229
230   *sound_mode_type = "MUTE";
231
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));
237   }
238
239   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));
245   }
246
247   if (isEnableSound && isEnableVibrate) {
248     LoggerE("Wrong state (sound && vibration)");
249     return PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform has wrong state.");
250   }
251
252   if (isEnableSound) {
253     *sound_mode_type = "SOUND";
254   } else if (isEnableVibrate) {
255     *sound_mode_type = "VIBRATE";
256   }
257
258   return PlatformResult(ErrorCode::NO_ERROR);
259 }
260
261 PlatformResult SoundManager::SetVolume(const picojson::object& args) {
262   LoggerD("Enter");
263   const std::string& type = FromJson<std::string>(args, "type");
264   double volume = FromJson<double>(args, "volume");
265
266   LoggerD("SoundType: %s", type.c_str());
267   LoggerD("volume: %f", volume);
268
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.");
273   }
274
275   sound_type_e sound_type;
276   PlatformResult status = SoundManager::StrToPlatformEnum(type, &sound_type);
277   if (status.IsError()) return status;
278
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");
283   }
284
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);
288
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");
293   }
294
295   return PlatformResult(ErrorCode::NO_ERROR);
296 }
297
298 PlatformResult SoundManager::GetVolume(const picojson::object& args,
299                                        double* volume) {
300   LoggerD("Enter");
301   const std::string& type = FromJson<std::string>(args, "type");
302   int value = 0;
303
304   sound_type_e type_enum;
305   PlatformResult status = SoundManager::StrToPlatformEnum(type, &type_enum);
306   if (status.IsError()) return status;
307
308   int max_volume;
309   status = GetMaxVolume(type_enum, &max_volume);
310   if (status.IsError()) return status;
311
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");
316   }
317
318   *volume = ConvertToSystemVolume(max_volume, value);
319   LoggerD("volume: %lf, maxVolume: %d, value: %d", volume, max_volume, value);
320
321   return PlatformResult(ErrorCode::NO_ERROR);
322 }
323
324 void SoundManager::soundModeChangedCb(keynode_t*, void* user_data)
325 {
326   LoggerD("Enter");
327   if (user_data == nullptr) {
328     LoggerE("Invalid callback data!");
329     return;
330   }
331   SoundManager* self = static_cast<SoundManager*>(user_data);
332
333   std::string soundModeType;
334   PlatformResult status = self->GetSoundMode(&soundModeType);
335
336   if (status.IsSuccess() && self->soundModeListener) {
337     self->soundModeListener->OnSoundModeChange(soundModeType);
338   } else {
339     LoggerE("No SoundModeListener attached");
340   }
341 }
342
343 PlatformResult SoundManager::SetSoundModeChangeListener(
344     SoundManagerSoundModeChangedListener* listener) {
345   LoggerD("Enter");
346   soundModeListener = listener;
347   if (soundModeChangeListening) return PlatformResult(ErrorCode::NO_ERROR);
348
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);
354   }
355
356   LoggerE("SoundModeChangeListener no setted");
357   return PlatformResult(ErrorCode::UNKNOWN_ERR,
358                         "SoundModeChangeListener no setted");
359 }
360
361 PlatformResult SoundManager::UnsetSoundModeChangeListener() {
362   LoggerD("Enter");
363   soundModeListener = nullptr;
364   if (!soundModeChangeListening) {
365     return PlatformResult(ErrorCode::NO_ERROR);
366   }
367
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);
373   }
374
375   LoggerE("SoundModeChangeListener no unsetted");
376   return PlatformResult(ErrorCode::UNKNOWN_ERR,
377                         "SoundModeChangeListener no unsetted");
378 }
379
380 PlatformResult SoundManager::SetVolumeChangeListener() {
381   LoggerD("Enter");
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);
387         },
388         static_cast<void*>(this));
389
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");
394     }
395
396     is_volume_change_listener_ = true;
397   }
398
399   return PlatformResult(ErrorCode::NO_ERROR);
400 }
401
402 PlatformResult SoundManager::UnsetVolumeChangeListener() {
403   LoggerD("Enter");
404   if (!is_volume_change_listener_) {
405     return PlatformResult(ErrorCode::NO_ERROR);
406   }
407
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");
413   }
414
415   is_volume_change_listener_ = false;
416
417   return PlatformResult(ErrorCode::NO_ERROR);
418 }
419
420 void SoundManager::GetDeviceList(sound_device_mask_e mask, picojson::object& out) {
421   LoggerD("Entered");
422
423   int ret = SOUND_MANAGER_ERROR_NONE;
424   sound_device_list_h device_list = nullptr;
425   sound_device_h device = nullptr;
426
427   picojson::value response = picojson::value(picojson::array());
428   picojson::array& response_array = response.get<picojson::array>();
429
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);
433     return;
434   }
435
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);
440
441     if (result.IsError()) {
442       ReportError(result, &out);
443       return;
444     }
445     response_array.push_back(val);
446   }
447
448   ReportSuccess(response, out);
449 }
450
451 PlatformResult SoundManager::GetDeviceInfo(sound_device_h device,
452                                            bool is_connected,
453                                            bool check_connection,
454                                            picojson::object* obj) {
455   LoggerD("Entered");
456
457   int ret = SOUND_MANAGER_ERROR_NONE;
458
459   //get id
460   int id = 0;
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");
464   }
465   obj->insert(std::make_pair("id", picojson::value(static_cast<double>(id))));
466
467   //get name
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");
472   }
473   obj->insert(std::make_pair("name", picojson::value(name)));
474
475   //get type
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");
480   }
481   obj->insert(std::make_pair("device", picojson::value(SoundDeviceTypeToString(type))));
482
483   //get direction
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");
488   }
489   obj->insert(std::make_pair("direction", picojson::value(SoundIOTypeToString(direction))));
490
491   //get state
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");
496   }
497   obj->insert(std::make_pair("isActivated", picojson::value(static_cast<bool>(state))));
498
499   //get connection
500   if (check_connection) {
501     return IsDeviceConnected(type, direction, obj);
502   }
503
504   obj->insert(std::make_pair("isConnected", picojson::value(is_connected)));
505   return PlatformResult(ErrorCode::NO_ERROR);
506 }
507
508 PlatformResult SoundManager::IsDeviceConnected(sound_device_type_e type,
509                                                sound_device_io_direction_e direction,
510                                                picojson::object* obj) {
511   LoggerD("Entered");
512
513   sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
514   switch (direction) {
515     case SOUND_DEVICE_IO_DIRECTION_IN:
516       mask = SOUND_DEVICE_IO_DIRECTION_IN_MASK;
517       break;
518     case SOUND_DEVICE_IO_DIRECTION_OUT:
519       mask = SOUND_DEVICE_IO_DIRECTION_OUT_MASK;
520       break;
521     case SOUND_DEVICE_IO_DIRECTION_BOTH:
522       mask = SOUND_DEVICE_IO_DIRECTION_BOTH_MASK;
523       break;
524     default:
525       LoggerD("Invalid IOType (%d)", direction);
526       return PlatformResult(ErrorCode::UNKNOWN_ERR, "Invalid IO type");
527   }
528
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;
533
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");
537   }
538
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");
543     }
544
545     if (type == device_type) {
546       obj->insert(std::make_pair("isConnected", picojson::value(true)));
547       return PlatformResult(ErrorCode::NO_ERROR);
548     }
549   }
550
551   obj->insert(std::make_pair("isConnected", picojson::value(false)));
552   return PlatformResult(ErrorCode::NO_ERROR);
553 }
554
555 void SoundManager::DeviceChangeCB(sound_device_h device, bool is_connected, bool check_connection) {
556   LoggerD("Entered");
557
558   picojson::value response = picojson::value(picojson::object());
559   picojson::object& response_obj = response.get<picojson::object>();
560
561   PlatformResult result = GetDeviceInfo(device, is_connected, check_connection, &response_obj);
562
563   if (result.IsSuccess()) {
564     response_obj.insert(std::make_pair(
565         "listenerId", picojson::value("SoundDeviceStateChangeCallback")));
566
567     auto call_response = [this, response]()->void {
568       instance_.PostMessage(response.serialize().c_str());
569     };
570
571     TaskQueue::GetInstance().Async(call_response);
572   }
573 }
574
575 void DeviceConnectionChangeCB(sound_device_h device, bool is_connected, void *user_data) {
576   LoggerD("Entered");
577   SoundManager* h = static_cast<SoundManager*>(user_data);
578   h->DeviceChangeCB(device, is_connected, false);
579 }
580
581 void DeviceActivationChangeCB(sound_device_h device, sound_device_changed_info_e changed_info,
582                               void *user_data) {
583   LoggerD("Entered");
584
585   if (SOUND_DEVICE_CHANGED_INFO_STATE == changed_info) {
586     SoundManager* h = static_cast<SoundManager*>(user_data);
587     h->DeviceChangeCB(device, false, true);
588   }
589 }
590
591 PlatformResult SoundManager::AddDeviceStateChangeListener() {
592   LoggerD("Entered");
593
594   int ret = SOUND_MANAGER_ERROR_NONE;
595   sound_device_mask_e mask = SOUND_DEVICE_ALL_MASK;
596
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");
601     }
602
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");
606     }
607
608     sound_device_change_listener_ = true;
609   }
610
611   return PlatformResult(ErrorCode::NO_ERROR);
612 }
613
614 PlatformResult SoundManager::RemoveDeviceStateChangeListener() {
615   LoggerD("Entered");
616
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");
620     }
621
622     if (SOUND_MANAGER_ERROR_NONE != sound_manager_unset_device_information_changed_cb()) {
623       return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unsetting information listener failed");
624     }
625
626     sound_device_change_listener_ = false;
627   }
628
629   return PlatformResult(ErrorCode::NO_ERROR);
630 }
631
632 }  // namespace sound
633 }  // namespace extension