Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / audio / audio_service_chromeos.cc
blob33ad9bd7f2d5f0be8306baef9fd281898e561123
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/audio/audio_service.h"
7 #include "base/callback.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "chromeos/audio/audio_device.h"
11 #include "chromeos/audio/cras_audio_handler.h"
12 #include "content/public/browser/browser_thread.h"
14 using content::BrowserThread;
16 namespace extensions {
18 using api::audio::OutputDeviceInfo;
19 using api::audio::InputDeviceInfo;
20 using api::audio::AudioDeviceInfo;
22 class AudioServiceImpl : public AudioService,
23 public chromeos::CrasAudioHandler::AudioObserver {
24 public:
25 AudioServiceImpl();
26 ~AudioServiceImpl() override;
28 // Called by listeners to this service to add/remove themselves as observers.
29 void AddObserver(AudioService::Observer* observer) override;
30 void RemoveObserver(AudioService::Observer* observer) override;
32 // Start to query audio device information.
33 void StartGetInfo(const GetInfoCallback& callback) override;
34 void SetActiveDevices(const DeviceIdList& device_list) override;
35 bool SetDeviceProperties(const std::string& device_id,
36 bool muted,
37 int volume,
38 int gain) override;
40 protected:
41 // chromeos::CrasAudioHandler::AudioObserver overrides.
42 void OnOutputNodeVolumeChanged(uint64_t id, int volume) override;
43 void OnInputNodeGainChanged(uint64_t id, int gain) override;
44 void OnOutputMuteChanged(bool mute_on, bool system_adjust) override;
45 void OnInputMuteChanged(bool mute_on) override;
46 void OnAudioNodesChanged() override;
47 void OnActiveOutputNodeChanged() override;
48 void OnActiveInputNodeChanged() override;
50 private:
51 void NotifyDeviceChanged();
52 void NotifyLevelChanged(uint64_t id, int level);
53 void NotifyMuteChanged(bool is_input, bool is_muted);
54 void NotifyDevicesChanged();
56 bool FindDevice(uint64_t id, chromeos::AudioDevice* device);
57 uint64_t GetIdFromStr(const std::string& id_str);
59 // List of observers.
60 base::ObserverList<AudioService::Observer> observer_list_;
62 chromeos::CrasAudioHandler* cras_audio_handler_;
64 // Note: This should remain the last member so it'll be destroyed and
65 // invalidate the weak pointers before any other members are destroyed.
66 base::WeakPtrFactory<AudioServiceImpl> weak_ptr_factory_;
68 DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl);
71 AudioServiceImpl::AudioServiceImpl()
72 : cras_audio_handler_(NULL),
73 weak_ptr_factory_(this) {
74 if (chromeos::CrasAudioHandler::IsInitialized()) {
75 cras_audio_handler_ = chromeos::CrasAudioHandler::Get();
76 cras_audio_handler_->AddAudioObserver(this);
80 AudioServiceImpl::~AudioServiceImpl() {
81 if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) {
82 cras_audio_handler_->RemoveAudioObserver(this);
86 void AudioServiceImpl::AddObserver(AudioService::Observer* observer) {
87 observer_list_.AddObserver(observer);
90 void AudioServiceImpl::RemoveObserver(AudioService::Observer* observer) {
91 observer_list_.RemoveObserver(observer);
94 void AudioServiceImpl::StartGetInfo(const GetInfoCallback& callback) {
95 DCHECK_CURRENTLY_ON(BrowserThread::UI);
96 DCHECK(cras_audio_handler_);
97 DCHECK(!callback.is_null());
99 if (callback.is_null())
100 return;
102 OutputInfo output_info;
103 InputInfo input_info;
104 if (!cras_audio_handler_) {
105 callback.Run(output_info, input_info, false);
106 return;
109 chromeos::AudioDeviceList devices;
110 cras_audio_handler_->GetAudioDevices(&devices);
111 for (size_t i = 0; i < devices.size(); ++i) {
112 if (!devices[i].is_input) {
113 linked_ptr<OutputDeviceInfo> info(new OutputDeviceInfo());
114 info->id = base::Uint64ToString(devices[i].id);
115 info->name = devices[i].device_name + ": " + devices[i].display_name;
116 info->is_active = devices[i].active;
117 info->volume =
118 cras_audio_handler_->GetOutputVolumePercentForDevice(devices[i].id);
119 info->is_muted =
120 cras_audio_handler_->IsOutputMutedForDevice(devices[i].id);
121 output_info.push_back(info);
122 } else {
123 linked_ptr<InputDeviceInfo> info(new InputDeviceInfo());
124 info->id = base::Uint64ToString(devices[i].id);
125 info->name = devices[i].device_name + ": " + devices[i].display_name;
126 info->is_active = devices[i].active;
127 info->gain =
128 cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id);
129 info->is_muted =
130 cras_audio_handler_->IsInputMutedForDevice(devices[i].id);
131 input_info.push_back(info);
134 callback.Run(output_info, input_info, true);
137 void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) {
138 DCHECK(cras_audio_handler_);
139 if (!cras_audio_handler_)
140 return;
142 chromeos::CrasAudioHandler::NodeIdList id_list;
143 for (size_t i = 0; i < device_list.size(); ++i) {
144 chromeos::AudioDevice device;
145 if (FindDevice(GetIdFromStr(device_list[i]), &device))
146 id_list.push_back(device.id);
148 cras_audio_handler_->ChangeActiveNodes(id_list);
151 bool AudioServiceImpl::SetDeviceProperties(const std::string& device_id,
152 bool muted,
153 int volume,
154 int gain) {
155 DCHECK(cras_audio_handler_);
156 if (!cras_audio_handler_)
157 return false;
159 chromeos::AudioDevice device;
160 bool found = FindDevice(GetIdFromStr(device_id), &device);
161 if (!found)
162 return false;
164 cras_audio_handler_->SetMuteForDevice(device.id, muted);
166 if (!device.is_input && volume != -1) {
167 cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, volume);
168 return true;
169 } else if (device.is_input && gain != -1) {
170 cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, gain);
171 return true;
174 return false;
177 bool AudioServiceImpl::FindDevice(uint64_t id, chromeos::AudioDevice* device) {
178 chromeos::AudioDeviceList devices;
179 cras_audio_handler_->GetAudioDevices(&devices);
181 for (size_t i = 0; i < devices.size(); ++i) {
182 if (devices[i].id == id) {
183 *device = devices[i];
184 return true;
187 return false;
190 uint64_t AudioServiceImpl::GetIdFromStr(const std::string& id_str) {
191 uint64_t device_id;
192 if (!base::StringToUint64(id_str, &device_id))
193 return 0;
194 else
195 return device_id;
198 void AudioServiceImpl::OnOutputNodeVolumeChanged(uint64_t id, int volume) {
199 NotifyLevelChanged(id, volume);
202 void AudioServiceImpl::OnOutputMuteChanged(bool mute_on, bool system_adjust) {
203 NotifyMuteChanged(false, mute_on);
206 void AudioServiceImpl::OnInputNodeGainChanged(uint64_t id, int gain) {
207 NotifyLevelChanged(id, gain);
210 void AudioServiceImpl::OnInputMuteChanged(bool mute_on) {
211 NotifyMuteChanged(true, mute_on);
214 void AudioServiceImpl::OnAudioNodesChanged() {
215 NotifyDevicesChanged();
218 void AudioServiceImpl::OnActiveOutputNodeChanged() {
219 NotifyDeviceChanged();
222 void AudioServiceImpl::OnActiveInputNodeChanged() {
223 NotifyDeviceChanged();
226 void AudioServiceImpl::NotifyDeviceChanged() {
227 FOR_EACH_OBSERVER(AudioService::Observer, observer_list_, OnDeviceChanged());
230 void AudioServiceImpl::NotifyLevelChanged(uint64_t id, int level) {
231 FOR_EACH_OBSERVER(AudioService::Observer, observer_list_,
232 OnLevelChanged(base::Uint64ToString(id), level));
234 // Notify DeviceChanged event for backward compatibility.
235 // TODO(jennyz): remove this code when the old version of hotrod retires.
236 NotifyDeviceChanged();
239 void AudioServiceImpl::NotifyMuteChanged(bool is_input, bool is_muted) {
240 FOR_EACH_OBSERVER(AudioService::Observer, observer_list_,
241 OnMuteChanged(is_input, is_muted));
243 // Notify DeviceChanged event for backward compatibility.
244 // TODO(jennyz): remove this code when the old version of hotrod retires.
245 NotifyDeviceChanged();
248 void AudioServiceImpl::NotifyDevicesChanged() {
249 DCHECK_CURRENTLY_ON(BrowserThread::UI);
250 DCHECK(cras_audio_handler_);
252 DeviceInfoList devices_info_list;
253 chromeos::AudioDeviceList devices;
254 cras_audio_handler_->GetAudioDevices(&devices);
255 for (size_t i = 0; i < devices.size(); ++i) {
256 linked_ptr<AudioDeviceInfo> info(new AudioDeviceInfo());
257 info->id = base::Uint64ToString(devices[i].id);
258 info->is_input = devices[i].is_input;
259 info->device_type = chromeos::AudioDevice::GetTypeString(devices[i].type);
260 info->display_name = devices[i].display_name;
261 info->device_name = devices[i].device_name;
262 info->is_active = devices[i].active;
263 info->is_muted =
264 devices[i].is_input
265 ? cras_audio_handler_->IsInputMutedForDevice(devices[i].id)
266 : cras_audio_handler_->IsOutputMutedForDevice(devices[i].id);
267 info->level =
268 devices[i].is_input
269 ? cras_audio_handler_->GetOutputVolumePercentForDevice(
270 devices[i].id)
271 : cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id);
272 // TODO(jennyz): Set stable_device_id once it is implemented.
273 // See crbug.com/466768.
275 devices_info_list.push_back(info);
278 FOR_EACH_OBSERVER(AudioService::Observer, observer_list_,
279 OnDevicesChanged(devices_info_list));
281 // Notify DeviceChanged event for backward compatibility.
282 // TODO(jennyz): remove this code when the old version of hotrod retires.
283 NotifyDeviceChanged();
286 AudioService* AudioService::CreateInstance() {
287 return new AudioServiceImpl;
290 } // namespace extensions