Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / chromeos / dbus / cras_audio_client.cc
blobec20ea721d73875a645862079482abdf4ff5c9d5
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 "dbus/bus.h"
9 #include "dbus/message.h"
10 #include "dbus/object_path.h"
11 #include "dbus/object_proxy.h"
12 #include "third_party/cros_system_api/dbus/service_constants.h"
14 namespace chromeos {
16 // The CrasAudioClient implementation used in production.
17 class CrasAudioClientImpl : public CrasAudioClient {
18 public:
19 explicit CrasAudioClientImpl(dbus::Bus* bus)
20 : cras_proxy_(NULL),
21 weak_ptr_factory_(this) {
22 cras_proxy_ = bus->GetObjectProxy(
23 cras::kCrasServiceName,
24 dbus::ObjectPath(cras::kCrasServicePath));
26 // Monitor NameOwnerChanged signal.
27 cras_proxy_->SetNameOwnerChangedCallback(
28 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
29 weak_ptr_factory_.GetWeakPtr()));
31 // Monitor the D-Bus signal for output volume change.
32 cras_proxy_->ConnectToSignal(
33 cras::kCrasControlInterface,
34 cras::kOutputVolumeChanged,
35 base::Bind(&CrasAudioClientImpl::OutputVolumeChangedReceived,
36 weak_ptr_factory_.GetWeakPtr()),
37 base::Bind(&CrasAudioClientImpl::SignalConnected,
38 weak_ptr_factory_.GetWeakPtr()));
40 // Monitor the D-Bus signal for output mute change.
41 cras_proxy_->ConnectToSignal(
42 cras::kCrasControlInterface,
43 cras::kOutputMuteChanged,
44 base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
45 weak_ptr_factory_.GetWeakPtr()),
46 base::Bind(&CrasAudioClientImpl::SignalConnected,
47 weak_ptr_factory_.GetWeakPtr()));
49 // Monitor the D-Bus signal for input gain change.
50 cras_proxy_->ConnectToSignal(
51 cras::kCrasControlInterface,
52 cras::kInputGainChanged,
53 base::Bind(&CrasAudioClientImpl::InputGainChangedReceived,
54 weak_ptr_factory_.GetWeakPtr()),
55 base::Bind(&CrasAudioClientImpl::SignalConnected,
56 weak_ptr_factory_.GetWeakPtr()));
58 // Monitor the D-Bus signal for input mute change.
59 cras_proxy_->ConnectToSignal(
60 cras::kCrasControlInterface,
61 cras::kInputMuteChanged,
62 base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
63 weak_ptr_factory_.GetWeakPtr()),
64 base::Bind(&CrasAudioClientImpl::SignalConnected,
65 weak_ptr_factory_.GetWeakPtr()));
67 // Monitor the D-Bus signal for nodes change.
68 cras_proxy_->ConnectToSignal(
69 cras::kCrasControlInterface,
70 cras::kNodesChanged,
71 base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
72 weak_ptr_factory_.GetWeakPtr()),
73 base::Bind(&CrasAudioClientImpl::SignalConnected,
74 weak_ptr_factory_.GetWeakPtr()));
76 // Monitor the D-Bus signal for active output node change.
77 cras_proxy_->ConnectToSignal(
78 cras::kCrasControlInterface,
79 cras::kActiveOutputNodeChanged,
80 base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
81 weak_ptr_factory_.GetWeakPtr()),
82 base::Bind(&CrasAudioClientImpl::SignalConnected,
83 weak_ptr_factory_.GetWeakPtr()));
85 // Monitor the D-Bus signal for active input node change.
86 cras_proxy_->ConnectToSignal(
87 cras::kCrasControlInterface,
88 cras::kActiveInputNodeChanged,
89 base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
90 weak_ptr_factory_.GetWeakPtr()),
91 base::Bind(&CrasAudioClientImpl::SignalConnected,
92 weak_ptr_factory_.GetWeakPtr()));
95 virtual ~CrasAudioClientImpl() {
98 // CrasAudioClient overrides:
99 virtual void AddObserver(Observer* observer) OVERRIDE {
100 observers_.AddObserver(observer);
103 virtual void RemoveObserver(Observer* observer) OVERRIDE {
104 observers_.RemoveObserver(observer);
107 virtual bool HasObserver(Observer* observer) OVERRIDE {
108 return observers_.HasObserver(observer);
111 virtual void GetVolumeState(const GetVolumeStateCallback& callback) OVERRIDE {
112 dbus::MethodCall method_call(cras::kCrasControlInterface,
113 cras::kGetVolumeState);
114 cras_proxy_->CallMethod(
115 &method_call,
116 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
117 base::Bind(&CrasAudioClientImpl::OnGetVolumeState,
118 weak_ptr_factory_.GetWeakPtr(), callback));
121 virtual void GetNodes(const GetNodesCallback& callback) OVERRIDE {
122 dbus::MethodCall method_call(cras::kCrasControlInterface,
123 cras::kGetNodes);
124 cras_proxy_->CallMethod(
125 &method_call,
126 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
127 base::Bind(&CrasAudioClientImpl::OnGetNodes,
128 weak_ptr_factory_.GetWeakPtr(), callback));
131 virtual void SetOutputVolume(int32 volume) OVERRIDE {
132 dbus::MethodCall method_call(cras::kCrasControlInterface,
133 cras::kSetOutputVolume);
134 dbus::MessageWriter writer(&method_call);
135 writer.AppendInt32(volume);
136 cras_proxy_->CallMethod(
137 &method_call,
138 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
139 dbus::ObjectProxy::EmptyResponseCallback());
142 virtual void SetOutputMute(bool mute_on) OVERRIDE {
143 dbus::MethodCall method_call(cras::kCrasControlInterface,
144 cras::kSetOutputMute);
145 dbus::MessageWriter writer(&method_call);
146 writer.AppendBool(mute_on);
147 cras_proxy_->CallMethod(
148 &method_call,
149 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
150 dbus::ObjectProxy::EmptyResponseCallback());
153 virtual void SetInputGain(int32 input_gain) OVERRIDE {
154 dbus::MethodCall method_call(cras::kCrasControlInterface,
155 cras::kSetInputGain);
156 dbus::MessageWriter writer(&method_call);
157 writer.AppendInt32(input_gain);
158 cras_proxy_->CallMethod(
159 &method_call,
160 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
161 dbus::ObjectProxy::EmptyResponseCallback());
164 virtual void SetInputMute(bool mute_on) OVERRIDE {
165 dbus::MethodCall method_call(cras::kCrasControlInterface,
166 cras::kSetInputMute);
167 dbus::MessageWriter writer(&method_call);
168 writer.AppendBool(mute_on);
169 cras_proxy_->CallMethod(
170 &method_call,
171 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
172 dbus::ObjectProxy::EmptyResponseCallback());
175 virtual void SetActiveOutputNode(uint64 node_id) OVERRIDE {
176 dbus::MethodCall method_call(cras::kCrasControlInterface,
177 cras::kSetActiveOutputNode);
178 dbus::MessageWriter writer(&method_call);
179 writer.AppendUint64(node_id);
180 cras_proxy_->CallMethod(
181 &method_call,
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
183 dbus::ObjectProxy::EmptyResponseCallback());
186 virtual void SetActiveInputNode(uint64 node_id) OVERRIDE {
187 dbus::MethodCall method_call(cras::kCrasControlInterface,
188 cras::kSetActiveInputNode);
189 dbus::MessageWriter writer(&method_call);
190 writer.AppendUint64(node_id);
191 cras_proxy_->CallMethod(
192 &method_call,
193 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
194 dbus::ObjectProxy::EmptyResponseCallback());
197 private:
198 // Called when the cras signal is initially connected.
199 void SignalConnected(const std::string& interface_name,
200 const std::string& signal_name,
201 bool success) {
202 LOG_IF(ERROR, !success)
203 << "Failed to connect to cras signal:" << signal_name;
206 void NameOwnerChangedReceived(dbus::Signal* signal) {
207 FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
210 // Called when a OutputVolumeChanged signal is received.
211 void OutputVolumeChangedReceived(dbus::Signal* signal) {
212 dbus::MessageReader reader(signal);
213 int32 volume;
214 if (!reader.PopInt32(&volume)) {
215 LOG(ERROR) << "Error reading signal from cras:"
216 << signal->ToString();
218 FOR_EACH_OBSERVER(Observer, observers_, OutputVolumeChanged(volume));
221 // Called when a OutputMuteChanged signal is received.
222 void OutputMuteChangedReceived(dbus::Signal* signal) {
223 dbus::MessageReader reader(signal);
224 bool mute;
225 if (!reader.PopBool(&mute)) {
226 LOG(ERROR) << "Error reading signal from cras:"
227 << signal->ToString();
229 FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(mute));
232 // Called when a InputGainChanged signal is received.
233 void InputGainChangedReceived(dbus::Signal* signal) {
234 dbus::MessageReader reader(signal);
235 int32 gain;
236 if (!reader.PopInt32(&gain)) {
237 LOG(ERROR) << "Error reading signal from cras:"
238 << signal->ToString();
240 FOR_EACH_OBSERVER(Observer, observers_, InputGainChanged(gain));
243 // Called when a InputMuteChanged signal is received.
244 void InputMuteChangedReceived(dbus::Signal* signal) {
245 dbus::MessageReader reader(signal);
246 bool mute;
247 if (!reader.PopBool(&mute)) {
248 LOG(ERROR) << "Error reading signal from cras:"
249 << signal->ToString();
251 FOR_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
254 void NodesChangedReceived(dbus::Signal* signal) {
255 FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
258 void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
259 dbus::MessageReader reader(signal);
260 uint64 node_id;
261 if (!reader.PopUint64(&node_id)) {
262 LOG(ERROR) << "Error reading signal from cras:"
263 << signal->ToString();
265 FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
268 void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
269 dbus::MessageReader reader(signal);
270 uint64 node_id;
271 if (!reader.PopUint64(&node_id)) {
272 LOG(ERROR) << "Error reading signal from cras:"
273 << signal->ToString();
275 FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
278 void OnGetVolumeState(const GetVolumeStateCallback& callback,
279 dbus::Response* response) {
280 bool success = true;
281 VolumeState volume_state;
282 if (response) {
283 dbus::MessageReader reader(response);
284 if (!reader.PopInt32(&volume_state.output_volume) ||
285 !reader.PopBool(&volume_state.output_mute) ||
286 !reader.PopInt32(&volume_state.input_gain) ||
287 !reader.PopBool(&volume_state.input_mute)) {
288 success = false;
289 LOG(ERROR) << "Error reading response from cras: "
290 << response->ToString();
292 } else {
293 success = false;
294 LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
297 callback.Run(volume_state, success);
300 void OnGetNodes(const GetNodesCallback& callback,
301 dbus::Response* response) {
302 bool success = true;
303 AudioNodeList node_list;
304 if (response) {
305 dbus::MessageReader response_reader(response);
306 dbus::MessageReader array_reader(response);
307 while (response_reader.HasMoreData()) {
308 if (!response_reader.PopArray(&array_reader)) {
309 success = false;
310 LOG(ERROR) << "Error reading response from cras: "
311 << response->ToString();
312 break;
315 AudioNode node;
316 if (!GetAudioNode(response, &array_reader, &node)) {
317 success = false;
318 LOG(WARNING) << "Error reading audio node data from cras: "
319 << response->ToString();
320 break;
323 node_list.push_back(node);
325 } else {
326 success = false;
327 LOG(ERROR) << "Error calling " << cras::kGetNodes;
330 callback.Run(node_list, success);
333 bool GetAudioNode(dbus::Response* response,
334 dbus::MessageReader* array_reader,
335 AudioNode *node) {
336 while (array_reader->HasMoreData()) {
337 dbus::MessageReader dict_entry_reader(response);
338 dbus::MessageReader value_reader(response);
339 std::string key;
340 if (!array_reader->PopDictEntry(&dict_entry_reader) ||
341 !dict_entry_reader.PopString(&key) ||
342 !dict_entry_reader.PopVariant(&value_reader)) {
343 return false;
346 if (key == cras::kIsInputProperty) {
347 if (!value_reader.PopBool(&node->is_input))
348 return false;
349 } else if (key == cras::kIdProperty) {
350 if (!value_reader.PopUint64(&node->id))
351 return false;
352 } else if (key == cras::kDeviceNameProperty) {
353 if (!value_reader.PopString(&node->device_name))
354 return false;
355 } else if (key == cras::kTypeProperty) {
356 if (!value_reader.PopString(&node->type))
357 return false;
358 } else if (key == cras::kNameProperty) {
359 if (!value_reader.PopString(&node->name))
360 return false;
361 } else if (key == cras::kActiveProperty) {
362 if (!value_reader.PopBool(&node->active))
363 return false;
364 } else if (key == cras::kPluggedTimeProperty) {
365 if (!value_reader.PopUint64(&node->plugged_time))
366 return false;
370 return true;
373 dbus::ObjectProxy* cras_proxy_;
374 ObserverList<Observer> observers_;
376 // Note: This should remain the last member so it'll be destroyed and
377 // invalidate its weak pointers before any other members are destroyed.
378 base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_;
380 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
383 // The CrasAudioClient implementation used on Linux desktop,
384 // which does nothing.
385 class CrasAudioClientStubImpl : public CrasAudioClient {
386 public:
387 CrasAudioClientStubImpl() {
388 VLOG(1) << "CrasAudioClientStubImpl is created";
390 // Fake audio output nodes.
391 AudioNode node_1;
392 node_1.is_input = false;
393 node_1.id = 10001;
394 node_1.device_name = "Fake Speaker";
395 node_1.type = "INTERNAL_SPEAKER";
396 node_1.name = "Speaker";
397 node_1.active = false;
398 node_list_.push_back(node_1);
400 AudioNode node_2;
401 node_2.is_input = false;
402 node_2.id = 10002;
403 node_2.device_name = "Fake Headphone";
404 node_2.type = "HEADPHONE";
405 node_2.name = "Headphone";
406 node_2.active = true;
407 node_list_.push_back(node_2);
408 active_output_node_id_ = node_2.id;
410 AudioNode node_3;
411 node_3.is_input = false;
412 node_3.id = 10003;
413 node_3.device_name = "Fake Audio Output";
414 node_3.type = "BLUETOOTH";
415 node_3.name = "Bluetooth Headphone";
416 node_3.active = false;
417 node_list_.push_back(node_3);
419 // Fake audio input ndoes
420 AudioNode node_4;
421 node_4.is_input = true;
422 node_4.id = 10004;
423 node_4.device_name = "Fake Internal Mic";
424 node_4.type = "INTERNAL_MIC";
425 node_4.name = "Internal Mic";
426 node_4.active = false;
427 node_list_.push_back(node_4);
429 AudioNode node_5;
430 node_5.is_input = true;
431 node_5.id = 10005;
432 node_5.device_name = "Fake Internal Mic";
433 node_5.type = "USB";
434 node_5.name = "USB Mic";
435 node_5.active = true;
436 node_list_.push_back(node_5);
437 active_input_node_id_ = node_5.id;
439 virtual ~CrasAudioClientStubImpl() {
442 // CrasAudioClient overrides:
443 // TODO(jennyz): Implement the observers and callbacks in the stub for UI
444 // testing.
445 virtual void AddObserver(Observer* observer) OVERRIDE {
446 observers_.AddObserver(observer);
449 virtual void RemoveObserver(Observer* observer) OVERRIDE {
450 observers_.RemoveObserver(observer);
453 virtual bool HasObserver(Observer* observer) OVERRIDE {
454 return observers_.HasObserver(observer);
457 virtual void GetVolumeState(const GetVolumeStateCallback& callback) OVERRIDE {
458 callback.Run(volume_state_, true);
461 virtual void GetNodes(const GetNodesCallback& callback)OVERRIDE {
462 callback.Run(node_list_, true);
465 virtual void SetOutputVolume(int32 volume) OVERRIDE {
466 volume_state_.output_volume = volume;
467 FOR_EACH_OBSERVER(Observer,
468 observers_,
469 OutputVolumeChanged(volume_state_.output_volume));
472 virtual void SetOutputMute(bool mute_on) OVERRIDE {
473 volume_state_.output_mute = mute_on;
474 FOR_EACH_OBSERVER(Observer,
475 observers_,
476 OutputMuteChanged(volume_state_.output_mute));
479 virtual void SetInputGain(int32 input_gain) OVERRIDE {
480 volume_state_.input_gain = input_gain;
481 FOR_EACH_OBSERVER(Observer,
482 observers_,
483 InputGainChanged(volume_state_.input_gain));
486 virtual void SetInputMute(bool mute_on) OVERRIDE {
487 volume_state_.input_mute = mute_on;
488 FOR_EACH_OBSERVER(Observer,
489 observers_,
490 InputMuteChanged(volume_state_.input_mute));
493 virtual void SetActiveOutputNode(uint64 node_id) OVERRIDE {
494 if (active_output_node_id_ == node_id)
495 return;
497 for (size_t i = 0; i < node_list_.size(); ++i) {
498 if (node_list_[i].id == active_output_node_id_)
499 node_list_[i].active = false;
500 else if (node_list_[i].id == node_id)
501 node_list_[i].active = true;
503 active_output_node_id_ = node_id;
504 FOR_EACH_OBSERVER(Observer,
505 observers_,
506 ActiveOutputNodeChanged(node_id));
509 virtual void SetActiveInputNode(uint64 node_id) OVERRIDE {
510 if (active_input_node_id_ == node_id)
511 return;
513 for (size_t i = 0; i < node_list_.size(); ++i) {
514 if (node_list_[i].id == active_input_node_id_)
515 node_list_[i].active = false;
516 else if (node_list_[i].id == node_id)
517 node_list_[i].active = true;
519 active_input_node_id_ = node_id;
520 FOR_EACH_OBSERVER(Observer,
521 observers_,
522 ActiveInputNodeChanged(node_id));
525 private:
526 VolumeState volume_state_;
527 AudioNodeList node_list_;
528 uint64 active_input_node_id_;
529 uint64 active_output_node_id_;
530 ObserverList<Observer> observers_;
532 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientStubImpl);
535 CrasAudioClient::Observer::~Observer() {
538 void CrasAudioClient::Observer::AudioClientRestarted() {
541 void CrasAudioClient::Observer::OutputVolumeChanged(int32 volume) {
544 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
547 void CrasAudioClient::Observer::InputGainChanged(int gain) {
550 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
553 void CrasAudioClient::Observer::NodesChanged() {
556 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
559 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
562 CrasAudioClient::CrasAudioClient() {
565 CrasAudioClient::~CrasAudioClient() {
568 // static
569 CrasAudioClient* CrasAudioClient::Create(
570 DBusClientImplementationType type,
571 dbus::Bus* bus) {
572 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
573 return new CrasAudioClientImpl(bus);
575 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
576 return new CrasAudioClientStubImpl();
579 } // namespace chromeos