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 "chrome/browser/extensions/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 "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"
17 using content::BrowserThread
;
19 namespace extensions
{
21 using api::audio::OutputDeviceInfo
;
22 using api::audio::InputDeviceInfo
;
24 class AudioServiceImpl
: public AudioService
,
25 public chromeos::CrasAudioHandler::AudioObserver
{
28 virtual ~AudioServiceImpl();
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
;
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
,
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
;
53 void NotifyDeviceChanged();
55 // Callback for CrasAudioClient::GetNodes().
56 void OnGetNodes(const GetInfoCallback
& callback
,
57 const chromeos::AudioNodeList
& audio_nodes
,
60 // ErrorCallback for CrasAudioClient::GetNodes().
61 void OnGetNodesError(const std::string
& error_name
,
62 const std::string
& error_msg
);
64 bool FindDevice(uint64 id
, chromeos::AudioDevice
* device
);
65 uint64
GetIdFromStr(const std::string
& id_str
);
68 ObserverList
<AudioService::Observer
> observer_list_
;
70 chromeos::CrasAudioClient
* cras_audio_client_
;
71 chromeos::CrasAudioHandler
* cras_audio_handler_
;
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_
;
77 DISALLOW_COPY_AND_ASSIGN(AudioServiceImpl
);
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()) {
87 chromeos::DBusThreadManager::Get()->GetCrasAudioClient();
88 if (chromeos::CrasAudioHandler::IsInitialized()) {
89 cras_audio_handler_
= chromeos::CrasAudioHandler::Get();
90 cras_audio_handler_
->AddAudioObserver(this);
95 AudioServiceImpl::~AudioServiceImpl() {
96 if (cras_audio_handler_
&& chromeos::CrasAudioHandler::IsInitialized()) {
97 cras_audio_handler_
->RemoveAudioObserver(this);
101 void AudioServiceImpl::AddObserver(AudioService::Observer
* observer
) {
102 observer_list_
.AddObserver(observer
);
105 void AudioServiceImpl::RemoveObserver(AudioService::Observer
* observer
) {
106 observer_list_
.RemoveObserver(observer
);
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
114 if (cras_audio_client_
)
115 cras_audio_client_
->GetNodes(base::Bind(&AudioServiceImpl::OnGetNodes
,
116 weak_ptr_factory_
.GetWeakPtr(),
118 base::Bind(&AudioServiceImpl::OnGetNodesError
,
119 weak_ptr_factory_
.GetWeakPtr()));
122 void AudioServiceImpl::SetActiveDevices(const DeviceIdList
& device_list
) {
123 DCHECK(cras_audio_handler_
);
124 if (!cras_audio_handler_
)
127 bool input_device_set
= false;
128 bool output_device_set
= false;
130 for (size_t i
= 0; i
< device_list
.size(); ++i
) {
131 chromeos::AudioDevice device
;
132 bool found
= FindDevice(GetIdFromStr(device_list
[i
]), &device
);
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;
145 bool AudioServiceImpl::SetDeviceProperties(const std::string
& device_id
,
149 DCHECK(cras_audio_handler_
);
150 if (!cras_audio_handler_
)
153 chromeos::AudioDevice device
;
154 bool found
= FindDevice(GetIdFromStr(device_id
), &device
);
158 cras_audio_handler_
->SetMuteForDevice(device
.id
, muted
);
160 if (!device
.is_input
&& volume
!= -1) {
161 cras_audio_handler_
->SetVolumeGainPercentForDevice(device
.id
, volume
);
163 } else if (device
.is_input
&& gain
!= -1) {
164 cras_audio_handler_
->SetVolumeGainPercentForDevice(device
.id
, gain
);
171 void AudioServiceImpl::OnGetNodes(const GetInfoCallback
& callback
,
172 const chromeos::AudioNodeList
& audio_nodes
,
174 OutputInfo output_info
;
175 InputInfo input_info
;
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(
186 info
->is_muted
= cras_audio_handler_
->IsOutputMutedForDevice(iter
->id
);
187 output_info
.push_back(info
);
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(
195 info
->is_muted
= cras_audio_handler_
->IsInputMutedForDevice(iter
->id
);
196 input_info
.push_back(info
);
201 DCHECK(!callback
.is_null());
202 if (!callback
.is_null())
203 callback
.Run(output_info
, input_info
, success
);
206 void AudioServiceImpl::OnGetNodesError(const std::string
& error_name
,
207 const std::string
& error_msg
) {
210 bool AudioServiceImpl::FindDevice(uint64 id
, chromeos::AudioDevice
* device
) {
211 chromeos::AudioDeviceList devices
;
212 cras_audio_handler_
->GetAudioDevices(&devices
);
214 for (size_t i
= 0; i
< devices
.size(); ++i
) {
215 if (devices
[i
].id
== id
) {
216 *device
= devices
[i
];
223 uint64
AudioServiceImpl::GetIdFromStr(const std::string
& id_str
) {
225 if (!base::StringToUint64(id_str
, &device_id
))
231 void AudioServiceImpl::OnOutputVolumeChanged() {
232 NotifyDeviceChanged();
235 void AudioServiceImpl::OnOutputMuteChanged() {
236 NotifyDeviceChanged();
239 void AudioServiceImpl::OnInputGainChanged() {
240 NotifyDeviceChanged();
243 void AudioServiceImpl::OnInputMuteChanged() {
244 NotifyDeviceChanged();
247 void AudioServiceImpl::OnAudioNodesChanged() {
248 NotifyDeviceChanged();
251 void AudioServiceImpl::OnActiveOutputNodeChanged() {
252 NotifyDeviceChanged();
255 void AudioServiceImpl::OnActiveInputNodeChanged() {
256 NotifyDeviceChanged();
259 void AudioServiceImpl::NotifyDeviceChanged() {
260 FOR_EACH_OBSERVER(AudioService::Observer
, observer_list_
, OnDeviceChanged());
263 AudioService
* AudioService::CreateInstance() {
264 return new AudioServiceImpl
;
267 } // namespace extensions