Add include.
[chromium-blink-merge.git] / chromeos / dbus / cras_audio_client.cc
blobb756ee69eae27f488ffd7dcc266296019e63dde0
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 "chromeos/dbus/cras_audio_client.h"
7 #include "base/bind.h"
8 #include "base/format_macros.h"
9 #include "base/strings/stringprintf.h"
10 #include "dbus/bus.h"
11 #include "dbus/message.h"
12 #include "dbus/object_path.h"
13 #include "dbus/object_proxy.h"
14 #include "third_party/cros_system_api/dbus/service_constants.h"
16 namespace chromeos {
18 // Error name if cras dbus call fails with empty ErrorResponse.
19 const char kNoResponseError[] =
20 "org.chromium.cras.Error.NoResponse";
22 // The CrasAudioClient implementation used in production.
23 class CrasAudioClientImpl : public CrasAudioClient {
24 public:
25 CrasAudioClientImpl() : cras_proxy_(NULL), weak_ptr_factory_(this) {}
27 virtual ~CrasAudioClientImpl() {
30 // CrasAudioClient overrides:
31 virtual void AddObserver(Observer* observer) override {
32 observers_.AddObserver(observer);
35 virtual void RemoveObserver(Observer* observer) override {
36 observers_.RemoveObserver(observer);
39 virtual bool HasObserver(Observer* observer) override {
40 return observers_.HasObserver(observer);
43 virtual void GetVolumeState(const GetVolumeStateCallback& callback) override {
44 dbus::MethodCall method_call(cras::kCrasControlInterface,
45 cras::kGetVolumeState);
46 cras_proxy_->CallMethod(
47 &method_call,
48 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
49 base::Bind(&CrasAudioClientImpl::OnGetVolumeState,
50 weak_ptr_factory_.GetWeakPtr(), callback));
53 virtual void GetNodes(const GetNodesCallback& callback,
54 const ErrorCallback& error_callback) override {
55 dbus::MethodCall method_call(cras::kCrasControlInterface,
56 cras::kGetNodes);
57 cras_proxy_->CallMethodWithErrorCallback(
58 &method_call,
59 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
60 base::Bind(&CrasAudioClientImpl::OnGetNodes,
61 weak_ptr_factory_.GetWeakPtr(), callback),
62 base::Bind(&CrasAudioClientImpl::OnError,
63 weak_ptr_factory_.GetWeakPtr(), error_callback));
66 virtual void SetOutputNodeVolume(uint64 node_id, int32 volume) override {
67 dbus::MethodCall method_call(cras::kCrasControlInterface,
68 cras::kSetOutputNodeVolume);
69 dbus::MessageWriter writer(&method_call);
70 writer.AppendUint64(node_id);
71 writer.AppendInt32(volume);
72 cras_proxy_->CallMethod(
73 &method_call,
74 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
75 dbus::ObjectProxy::EmptyResponseCallback());
78 virtual void SetOutputUserMute(bool mute_on) override {
79 dbus::MethodCall method_call(cras::kCrasControlInterface,
80 cras::kSetOutputUserMute);
81 dbus::MessageWriter writer(&method_call);
82 writer.AppendBool(mute_on);
83 cras_proxy_->CallMethod(
84 &method_call,
85 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
86 dbus::ObjectProxy::EmptyResponseCallback());
89 virtual void SetInputNodeGain(uint64 node_id, int32 input_gain) override {
90 dbus::MethodCall method_call(cras::kCrasControlInterface,
91 cras::kSetInputNodeGain);
92 dbus::MessageWriter writer(&method_call);
93 writer.AppendUint64(node_id);
94 writer.AppendInt32(input_gain);
95 cras_proxy_->CallMethod(
96 &method_call,
97 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
98 dbus::ObjectProxy::EmptyResponseCallback());
101 virtual void SetInputMute(bool mute_on) override {
102 dbus::MethodCall method_call(cras::kCrasControlInterface,
103 cras::kSetInputMute);
104 dbus::MessageWriter writer(&method_call);
105 writer.AppendBool(mute_on);
106 cras_proxy_->CallMethod(
107 &method_call,
108 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
109 dbus::ObjectProxy::EmptyResponseCallback());
112 virtual void SetActiveOutputNode(uint64 node_id) override {
113 dbus::MethodCall method_call(cras::kCrasControlInterface,
114 cras::kSetActiveOutputNode);
115 dbus::MessageWriter writer(&method_call);
116 writer.AppendUint64(node_id);
117 cras_proxy_->CallMethod(
118 &method_call,
119 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
120 dbus::ObjectProxy::EmptyResponseCallback());
123 virtual void SetActiveInputNode(uint64 node_id) override {
124 dbus::MethodCall method_call(cras::kCrasControlInterface,
125 cras::kSetActiveInputNode);
126 dbus::MessageWriter writer(&method_call);
127 writer.AppendUint64(node_id);
128 cras_proxy_->CallMethod(
129 &method_call,
130 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
131 dbus::ObjectProxy::EmptyResponseCallback());
134 virtual void AddActiveInputNode(uint64 node_id) override {
135 dbus::MethodCall method_call(cras::kCrasControlInterface,
136 cras::kAddActiveInputNode);
137 dbus::MessageWriter writer(&method_call);
138 writer.AppendUint64(node_id);
139 cras_proxy_->CallMethod(
140 &method_call,
141 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
142 dbus::ObjectProxy::EmptyResponseCallback());
145 virtual void RemoveActiveInputNode(uint64 node_id) override {
146 dbus::MethodCall method_call(cras::kCrasControlInterface,
147 cras::kRemoveActiveInputNode);
148 dbus::MessageWriter writer(&method_call);
149 writer.AppendUint64(node_id);
150 cras_proxy_->CallMethod(
151 &method_call,
152 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
153 dbus::ObjectProxy::EmptyResponseCallback());
156 virtual void AddActiveOutputNode(uint64 node_id) override {
157 dbus::MethodCall method_call(cras::kCrasControlInterface,
158 cras::kAddActiveOutputNode);
159 dbus::MessageWriter writer(&method_call);
160 writer.AppendUint64(node_id);
161 cras_proxy_->CallMethod(&method_call,
162 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
163 dbus::ObjectProxy::EmptyResponseCallback());
166 virtual void RemoveActiveOutputNode(uint64 node_id) override {
167 dbus::MethodCall method_call(cras::kCrasControlInterface,
168 cras::kRemoveActiveOutputNode);
169 dbus::MessageWriter writer(&method_call);
170 writer.AppendUint64(node_id);
171 cras_proxy_->CallMethod(&method_call,
172 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
173 dbus::ObjectProxy::EmptyResponseCallback());
176 virtual void SwapLeftRight(uint64 node_id, bool swap) override {
177 dbus::MethodCall method_call(cras::kCrasControlInterface,
178 cras::kSwapLeftRight);
179 dbus::MessageWriter writer(&method_call);
180 writer.AppendUint64(node_id);
181 writer.AppendBool(swap);
182 cras_proxy_->CallMethod(&method_call,
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
184 dbus::ObjectProxy::EmptyResponseCallback());
187 protected:
188 virtual void Init(dbus::Bus* bus) override {
189 cras_proxy_ = bus->GetObjectProxy(cras::kCrasServiceName,
190 dbus::ObjectPath(cras::kCrasServicePath));
192 // Monitor NameOwnerChanged signal.
193 cras_proxy_->SetNameOwnerChangedCallback(
194 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
195 weak_ptr_factory_.GetWeakPtr()));
197 // Monitor the D-Bus signal for output mute change.
198 cras_proxy_->ConnectToSignal(
199 cras::kCrasControlInterface,
200 cras::kOutputMuteChanged,
201 base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
202 weak_ptr_factory_.GetWeakPtr()),
203 base::Bind(&CrasAudioClientImpl::SignalConnected,
204 weak_ptr_factory_.GetWeakPtr()));
206 // Monitor the D-Bus signal for input mute change.
207 cras_proxy_->ConnectToSignal(
208 cras::kCrasControlInterface,
209 cras::kInputMuteChanged,
210 base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
211 weak_ptr_factory_.GetWeakPtr()),
212 base::Bind(&CrasAudioClientImpl::SignalConnected,
213 weak_ptr_factory_.GetWeakPtr()));
215 // Monitor the D-Bus signal for nodes change.
216 cras_proxy_->ConnectToSignal(
217 cras::kCrasControlInterface,
218 cras::kNodesChanged,
219 base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
220 weak_ptr_factory_.GetWeakPtr()),
221 base::Bind(&CrasAudioClientImpl::SignalConnected,
222 weak_ptr_factory_.GetWeakPtr()));
224 // Monitor the D-Bus signal for active output node change.
225 cras_proxy_->ConnectToSignal(
226 cras::kCrasControlInterface,
227 cras::kActiveOutputNodeChanged,
228 base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
229 weak_ptr_factory_.GetWeakPtr()),
230 base::Bind(&CrasAudioClientImpl::SignalConnected,
231 weak_ptr_factory_.GetWeakPtr()));
233 // Monitor the D-Bus signal for active input node change.
234 cras_proxy_->ConnectToSignal(
235 cras::kCrasControlInterface,
236 cras::kActiveInputNodeChanged,
237 base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
238 weak_ptr_factory_.GetWeakPtr()),
239 base::Bind(&CrasAudioClientImpl::SignalConnected,
240 weak_ptr_factory_.GetWeakPtr()));
243 private:
244 // Called when the cras signal is initially connected.
245 void SignalConnected(const std::string& interface_name,
246 const std::string& signal_name,
247 bool success) {
248 LOG_IF(ERROR, !success)
249 << "Failed to connect to cras signal:" << signal_name;
252 void NameOwnerChangedReceived(const std::string& old_owner,
253 const std::string& new_owner) {
254 FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
257 // Called when a OutputMuteChanged signal is received.
258 void OutputMuteChangedReceived(dbus::Signal* signal) {
259 // Chrome should always call SetOutputUserMute api to set the output
260 // mute state and monitor user_mute state from OutputMuteChanged signal.
261 dbus::MessageReader reader(signal);
262 bool system_mute, user_mute;
263 if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) {
264 LOG(ERROR) << "Error reading signal from cras:"
265 << signal->ToString();
267 FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(user_mute));
270 // Called when a InputMuteChanged signal is received.
271 void InputMuteChangedReceived(dbus::Signal* signal) {
272 dbus::MessageReader reader(signal);
273 bool mute;
274 if (!reader.PopBool(&mute)) {
275 LOG(ERROR) << "Error reading signal from cras:"
276 << signal->ToString();
278 FOR_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
281 void NodesChangedReceived(dbus::Signal* signal) {
282 FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
285 void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
286 dbus::MessageReader reader(signal);
287 uint64 node_id;
288 if (!reader.PopUint64(&node_id)) {
289 LOG(ERROR) << "Error reading signal from cras:"
290 << signal->ToString();
292 FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
295 void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
296 dbus::MessageReader reader(signal);
297 uint64 node_id;
298 if (!reader.PopUint64(&node_id)) {
299 LOG(ERROR) << "Error reading signal from cras:"
300 << signal->ToString();
302 FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
305 void OnGetVolumeState(const GetVolumeStateCallback& callback,
306 dbus::Response* response) {
307 bool success = true;
308 VolumeState volume_state;
309 if (response) {
310 dbus::MessageReader reader(response);
311 if (!reader.PopInt32(&volume_state.output_volume) ||
312 !reader.PopBool(&volume_state.output_system_mute) ||
313 !reader.PopInt32(&volume_state.input_gain) ||
314 !reader.PopBool(&volume_state.input_mute) ||
315 !reader.PopBool(&volume_state.output_user_mute)) {
316 success = false;
317 LOG(ERROR) << "Error reading response from cras: "
318 << response->ToString();
320 } else {
321 success = false;
322 LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
325 callback.Run(volume_state, success);
328 void OnGetNodes(const GetNodesCallback& callback,
329 dbus::Response* response) {
330 bool success = true;
331 AudioNodeList node_list;
332 if (response) {
333 dbus::MessageReader response_reader(response);
334 dbus::MessageReader array_reader(response);
335 while (response_reader.HasMoreData()) {
336 if (!response_reader.PopArray(&array_reader)) {
337 success = false;
338 LOG(ERROR) << "Error reading response from cras: "
339 << response->ToString();
340 break;
343 AudioNode node;
344 if (!GetAudioNode(response, &array_reader, &node)) {
345 success = false;
346 LOG(WARNING) << "Error reading audio node data from cras: "
347 << response->ToString();
348 break;
350 // Filter out the "UNKNOWN" type of audio devices.
351 if (node.type != "UNKNOWN")
352 node_list.push_back(node);
356 if (node_list.empty())
357 return;
359 callback.Run(node_list, success);
362 void OnError(const ErrorCallback& error_callback,
363 dbus::ErrorResponse* response) {
364 // Error response has optional error message argument.
365 std::string error_name;
366 std::string error_message;
367 if (response) {
368 dbus::MessageReader reader(response);
369 error_name = response->GetErrorName();
370 reader.PopString(&error_message);
371 } else {
372 error_name = kNoResponseError;
373 error_message = "";
375 error_callback.Run(error_name, error_message);
378 bool GetAudioNode(dbus::Response* response,
379 dbus::MessageReader* array_reader,
380 AudioNode *node) {
381 while (array_reader->HasMoreData()) {
382 dbus::MessageReader dict_entry_reader(response);
383 dbus::MessageReader value_reader(response);
384 std::string key;
385 if (!array_reader->PopDictEntry(&dict_entry_reader) ||
386 !dict_entry_reader.PopString(&key) ||
387 !dict_entry_reader.PopVariant(&value_reader)) {
388 return false;
391 if (key == cras::kIsInputProperty) {
392 if (!value_reader.PopBool(&node->is_input))
393 return false;
394 } else if (key == cras::kIdProperty) {
395 if (!value_reader.PopUint64(&node->id))
396 return false;
397 } else if (key == cras::kDeviceNameProperty) {
398 if (!value_reader.PopString(&node->device_name))
399 return false;
400 } else if (key == cras::kTypeProperty) {
401 if (!value_reader.PopString(&node->type))
402 return false;
403 } else if (key == cras::kNameProperty) {
404 if (!value_reader.PopString(&node->name))
405 return false;
406 } else if (key == cras::kActiveProperty) {
407 if (!value_reader.PopBool(&node->active))
408 return false;
409 } else if (key == cras::kPluggedTimeProperty) {
410 if (!value_reader.PopUint64(&node->plugged_time))
411 return false;
415 return true;
418 dbus::ObjectProxy* cras_proxy_;
419 ObserverList<Observer> observers_;
421 // Note: This should remain the last member so it'll be destroyed and
422 // invalidate its weak pointers before any other members are destroyed.
423 base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_;
425 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
428 CrasAudioClient::Observer::~Observer() {
431 void CrasAudioClient::Observer::AudioClientRestarted() {
434 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
437 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
440 void CrasAudioClient::Observer::NodesChanged() {
443 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
446 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
449 CrasAudioClient::CrasAudioClient() {
452 CrasAudioClient::~CrasAudioClient() {
455 // static
456 CrasAudioClient* CrasAudioClient::Create() {
457 return new CrasAudioClientImpl();
460 } // namespace chromeos