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