- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / audio / audio_service_chromeos.cc
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.
4
5 #include "chrome/browser/extensions/api/audio/audio_service.h"
6
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 "chromeos/dbus/audio_node.h"
13 #include "chromeos/dbus/cras_audio_client.h"
14 #include "chromeos/dbus/dbus_thread_manager.h"
15 #include "content/public/browser/browser_thread.h"
16
17 using content::BrowserThread;
18
19 namespace extensions {
20
21 using api::audio::OutputDeviceInfo;
22 using api::audio::InputDeviceInfo;
23
24 class AudioServiceImpl : public AudioService,
25                          public chromeos::CrasAudioHandler::AudioObserver {
26  public:
27   AudioServiceImpl();
28   virtual ~AudioServiceImpl();
29
30   // Called by listeners to this service to add/remove themselves as observers.
31   virtual void AddObserver(AudioService::Observer* observer) OVERRIDE;
32   virtual void RemoveObserver(AudioService::Observer* observer) OVERRIDE;
33
34   // Start to query audio device information.
35   virtual void StartGetInfo(const GetInfoCallback& callback) OVERRIDE;
36   virtual void SetActiveDevices(const DeviceIdList& device_list) OVERRIDE;
37   virtual bool SetDeviceProperties(const std::string& device_id,
38                                    bool muted,
39                                    int volume,
40                                    int gain) OVERRIDE;
41
42  protected:
43   // chromeos::CrasAudioHandler::AudioObserver overrides.
44   virtual void OnOutputVolumeChanged() OVERRIDE;
45   virtual void OnInputGainChanged() OVERRIDE;
46   virtual void OnOutputMuteChanged() OVERRIDE;
47   virtual void OnInputMuteChanged() OVERRIDE;
48   virtual void OnAudioNodesChanged() OVERRIDE;
49   virtual void OnActiveOutputNodeChanged() OVERRIDE;
50   virtual void OnActiveInputNodeChanged() OVERRIDE;
51
52  private:
53   void NotifyDeviceChanged();
54
55   // Callback for CrasAudioClient::GetNodes().
56   void OnGetNodes(const GetInfoCallback& callback,
57                   const chromeos::AudioNodeList& audio_nodes,
58                   bool success);
59
60   // ErrorCallback for CrasAudioClient::GetNodes().
61   void OnGetNodesError(const std::string& error_name,
62                        const std::string& error_msg);
63
64   bool FindDevice(uint64 id, chromeos::AudioDevice* device);
65   uint64 GetIdFromStr(const std::string& id_str);
66
67   // List of observers.
68   ObserverList<AudioService::Observer> observer_list_;
69
70   chromeos::CrasAudioClient* cras_audio_client_;
71   chromeos::CrasAudioHandler* cras_audio_handler_;
72
73   // Note: This should remain the last member so it'll be destroyed and
74   // invalidate the weak pointers before any other members are destroyed.
75   base::WeakPtrFactory<AudioServiceImpl> weak_ptr_factory_;
76
77   DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl);
78 };
79
80 AudioServiceImpl::AudioServiceImpl()
81     : cras_audio_client_(NULL),
82       cras_audio_handler_(NULL),
83       weak_ptr_factory_(this) {
84   if (chromeos::DBusThreadManager::IsInitialized() &&
85       chromeos::DBusThreadManager::Get()) {
86     cras_audio_client_ =
87         chromeos::DBusThreadManager::Get()->GetCrasAudioClient();
88     if (chromeos::CrasAudioHandler::IsInitialized()) {
89       cras_audio_handler_ = chromeos::CrasAudioHandler::Get();
90       cras_audio_handler_->AddAudioObserver(this);
91     }
92   }
93 }
94
95 AudioServiceImpl::~AudioServiceImpl() {
96   if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) {
97     cras_audio_handler_->RemoveAudioObserver(this);
98   }
99 }
100
101 void AudioServiceImpl::AddObserver(AudioService::Observer* observer) {
102   observer_list_.AddObserver(observer);
103 }
104
105 void AudioServiceImpl::RemoveObserver(AudioService::Observer* observer) {
106   observer_list_.RemoveObserver(observer);
107 }
108
109 void AudioServiceImpl::StartGetInfo(const GetInfoCallback& callback) {
110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111   DCHECK(cras_audio_client_);
112   // TODO(jennyz,rkc): Replace cras_audio_client_ call with CrasAudioHandler
113   // Api call.
114   if (cras_audio_client_)
115     cras_audio_client_->GetNodes(base::Bind(&AudioServiceImpl::OnGetNodes,
116                                             weak_ptr_factory_.GetWeakPtr(),
117                                             callback),
118                                  base::Bind(&AudioServiceImpl::OnGetNodesError,
119                                             weak_ptr_factory_.GetWeakPtr()));
120 }
121
122 void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) {
123   DCHECK(cras_audio_handler_);
124   if (!cras_audio_handler_)
125     return;
126
127   bool input_device_set = false;
128   bool output_device_set = false;
129
130   for (size_t i = 0; i < device_list.size(); ++i) {
131     chromeos::AudioDevice device;
132     bool found = FindDevice(GetIdFromStr(device_list[i]), &device);
133     if (found) {
134       if (device.is_input && !input_device_set) {
135         cras_audio_handler_->SwitchToDevice(device);
136         input_device_set = true;
137       } else if (!device.is_input && !output_device_set) {
138         cras_audio_handler_->SwitchToDevice(device);
139         output_device_set = true;
140       }
141     }
142   }
143 }
144
145 bool AudioServiceImpl::SetDeviceProperties(const std::string& device_id,
146                                            bool muted,
147                                            int volume,
148                                            int gain) {
149   DCHECK(cras_audio_handler_);
150   if (!cras_audio_handler_)
151     return false;
152
153   chromeos::AudioDevice device;
154   bool found = FindDevice(GetIdFromStr(device_id), &device);
155   if (!found)
156     return false;
157
158   cras_audio_handler_->SetMuteForDevice(device.id, muted);
159
160   if (!device.is_input && volume != -1) {
161     cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, volume);
162     return true;
163   } else if (device.is_input && gain != -1) {
164     cras_audio_handler_->SetVolumeGainPercentForDevice(device.id, gain);
165     return true;
166   }
167
168   return false;
169 }
170
171 void AudioServiceImpl::OnGetNodes(const GetInfoCallback& callback,
172                                   const chromeos::AudioNodeList& audio_nodes,
173                                   bool success) {
174   OutputInfo output_info;
175   InputInfo input_info;
176   if (success) {
177     for (chromeos::AudioNodeList::const_iterator iter = audio_nodes.begin();
178         iter != audio_nodes.end(); ++iter) {
179       if (!iter->is_input) {
180         linked_ptr<OutputDeviceInfo> info(new OutputDeviceInfo());
181         info->id = base::Uint64ToString(iter->id);
182         info->name = iter->device_name + ": " + iter->name;
183         info->is_active = iter->active;
184         info->volume = cras_audio_handler_->GetOutputVolumePercentForDevice(
185             iter->id);
186         info->is_muted = cras_audio_handler_->IsOutputMutedForDevice(iter->id);
187         output_info.push_back(info);
188       } else {
189         linked_ptr<InputDeviceInfo> info(new InputDeviceInfo());
190         info->id = base::Uint64ToString(iter->id);
191         info->name = iter->device_name + ": " + iter->name;
192         info->is_active = iter->active;
193         info->gain = cras_audio_handler_->GetInputGainPercentForDevice(
194             iter->id);
195         info->is_muted = cras_audio_handler_->IsInputMutedForDevice(iter->id);
196         input_info.push_back(info);
197       }
198     }
199   }
200
201   DCHECK(!callback.is_null());
202   if (!callback.is_null())
203     callback.Run(output_info, input_info, success);
204 }
205
206 void AudioServiceImpl::OnGetNodesError(const std::string& error_name,
207                                        const std::string& error_msg) {
208 }
209
210 bool AudioServiceImpl::FindDevice(uint64 id, chromeos::AudioDevice* device) {
211   chromeos::AudioDeviceList devices;
212   cras_audio_handler_->GetAudioDevices(&devices);
213
214   for (size_t i = 0; i < devices.size(); ++i) {
215     if (devices[i].id == id) {
216       *device = devices[i];
217       return true;
218     }
219   }
220   return false;
221 }
222
223 uint64 AudioServiceImpl::GetIdFromStr(const std::string& id_str) {
224   uint64 device_id;
225   if (!base::StringToUint64(id_str, &device_id))
226     return 0;
227   else
228     return device_id;
229 }
230
231 void AudioServiceImpl::OnOutputVolumeChanged() {
232   NotifyDeviceChanged();
233 }
234
235 void AudioServiceImpl::OnOutputMuteChanged() {
236   NotifyDeviceChanged();
237 }
238
239 void AudioServiceImpl::OnInputGainChanged() {
240   NotifyDeviceChanged();
241 }
242
243 void AudioServiceImpl::OnInputMuteChanged() {
244   NotifyDeviceChanged();
245 }
246
247 void AudioServiceImpl::OnAudioNodesChanged() {
248   NotifyDeviceChanged();
249 }
250
251 void AudioServiceImpl::OnActiveOutputNodeChanged() {
252   NotifyDeviceChanged();
253 }
254
255 void AudioServiceImpl::OnActiveInputNodeChanged() {
256   NotifyDeviceChanged();
257 }
258
259 void AudioServiceImpl::NotifyDeviceChanged() {
260   FOR_EACH_OBSERVER(AudioService::Observer, observer_list_, OnDeviceChanged());
261 }
262
263 AudioService* AudioService::CreateInstance() {
264   return new AudioServiceImpl;
265 }
266
267 }  // namespace extensions