Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / chromeos / dbus / cras_audio_client.cc
blobe70ba2ac358a2a0bc4a6e235029ed622e201b620
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 ~CrasAudioClientImpl() override {}
29 // CrasAudioClient overrides:
30 void AddObserver(Observer* observer) override {
31 observers_.AddObserver(observer);
34 void RemoveObserver(Observer* observer) override {
35 observers_.RemoveObserver(observer);
38 bool HasObserver(const Observer* observer) const override {
39 return observers_.HasObserver(observer);
42 void GetVolumeState(const GetVolumeStateCallback& callback) override {
43 dbus::MethodCall method_call(cras::kCrasControlInterface,
44 cras::kGetVolumeState);
45 cras_proxy_->CallMethod(
46 &method_call,
47 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
48 base::Bind(&CrasAudioClientImpl::OnGetVolumeState,
49 weak_ptr_factory_.GetWeakPtr(), callback));
52 void GetNodes(const GetNodesCallback& callback,
53 const ErrorCallback& error_callback) override {
54 dbus::MethodCall method_call(cras::kCrasControlInterface,
55 cras::kGetNodes);
56 cras_proxy_->CallMethodWithErrorCallback(
57 &method_call,
58 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
59 base::Bind(&CrasAudioClientImpl::OnGetNodes,
60 weak_ptr_factory_.GetWeakPtr(), callback),
61 base::Bind(&CrasAudioClientImpl::OnError,
62 weak_ptr_factory_.GetWeakPtr(), error_callback));
65 void SetOutputNodeVolume(uint64 node_id, int32 volume) override {
66 dbus::MethodCall method_call(cras::kCrasControlInterface,
67 cras::kSetOutputNodeVolume);
68 dbus::MessageWriter writer(&method_call);
69 writer.AppendUint64(node_id);
70 writer.AppendInt32(volume);
71 cras_proxy_->CallMethod(
72 &method_call,
73 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
74 dbus::ObjectProxy::EmptyResponseCallback());
77 void SetOutputUserMute(bool mute_on) override {
78 dbus::MethodCall method_call(cras::kCrasControlInterface,
79 cras::kSetOutputUserMute);
80 dbus::MessageWriter writer(&method_call);
81 writer.AppendBool(mute_on);
82 cras_proxy_->CallMethod(
83 &method_call,
84 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
85 dbus::ObjectProxy::EmptyResponseCallback());
88 void SetInputNodeGain(uint64 node_id, int32 input_gain) override {
89 dbus::MethodCall method_call(cras::kCrasControlInterface,
90 cras::kSetInputNodeGain);
91 dbus::MessageWriter writer(&method_call);
92 writer.AppendUint64(node_id);
93 writer.AppendInt32(input_gain);
94 cras_proxy_->CallMethod(
95 &method_call,
96 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
97 dbus::ObjectProxy::EmptyResponseCallback());
100 void SetInputMute(bool mute_on) override {
101 dbus::MethodCall method_call(cras::kCrasControlInterface,
102 cras::kSetInputMute);
103 dbus::MessageWriter writer(&method_call);
104 writer.AppendBool(mute_on);
105 cras_proxy_->CallMethod(
106 &method_call,
107 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
108 dbus::ObjectProxy::EmptyResponseCallback());
111 void SetActiveOutputNode(uint64 node_id) override {
112 dbus::MethodCall method_call(cras::kCrasControlInterface,
113 cras::kSetActiveOutputNode);
114 dbus::MessageWriter writer(&method_call);
115 writer.AppendUint64(node_id);
116 cras_proxy_->CallMethod(
117 &method_call,
118 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
119 dbus::ObjectProxy::EmptyResponseCallback());
122 void SetActiveInputNode(uint64 node_id) override {
123 dbus::MethodCall method_call(cras::kCrasControlInterface,
124 cras::kSetActiveInputNode);
125 dbus::MessageWriter writer(&method_call);
126 writer.AppendUint64(node_id);
127 cras_proxy_->CallMethod(
128 &method_call,
129 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
130 dbus::ObjectProxy::EmptyResponseCallback());
133 void AddActiveInputNode(uint64 node_id) override {
134 dbus::MethodCall method_call(cras::kCrasControlInterface,
135 cras::kAddActiveInputNode);
136 dbus::MessageWriter writer(&method_call);
137 writer.AppendUint64(node_id);
138 cras_proxy_->CallMethod(
139 &method_call,
140 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
141 dbus::ObjectProxy::EmptyResponseCallback());
144 void RemoveActiveInputNode(uint64 node_id) override {
145 dbus::MethodCall method_call(cras::kCrasControlInterface,
146 cras::kRemoveActiveInputNode);
147 dbus::MessageWriter writer(&method_call);
148 writer.AppendUint64(node_id);
149 cras_proxy_->CallMethod(
150 &method_call,
151 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
152 dbus::ObjectProxy::EmptyResponseCallback());
155 void AddActiveOutputNode(uint64 node_id) override {
156 dbus::MethodCall method_call(cras::kCrasControlInterface,
157 cras::kAddActiveOutputNode);
158 dbus::MessageWriter writer(&method_call);
159 writer.AppendUint64(node_id);
160 cras_proxy_->CallMethod(&method_call,
161 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
162 dbus::ObjectProxy::EmptyResponseCallback());
165 void RemoveActiveOutputNode(uint64 node_id) override {
166 dbus::MethodCall method_call(cras::kCrasControlInterface,
167 cras::kRemoveActiveOutputNode);
168 dbus::MessageWriter writer(&method_call);
169 writer.AppendUint64(node_id);
170 cras_proxy_->CallMethod(&method_call,
171 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
172 dbus::ObjectProxy::EmptyResponseCallback());
175 void SwapLeftRight(uint64 node_id, bool swap) override {
176 dbus::MethodCall method_call(cras::kCrasControlInterface,
177 cras::kSwapLeftRight);
178 dbus::MessageWriter writer(&method_call);
179 writer.AppendUint64(node_id);
180 writer.AppendBool(swap);
181 cras_proxy_->CallMethod(&method_call,
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
183 dbus::ObjectProxy::EmptyResponseCallback());
186 protected:
187 void Init(dbus::Bus* bus) override {
188 cras_proxy_ = bus->GetObjectProxy(cras::kCrasServiceName,
189 dbus::ObjectPath(cras::kCrasServicePath));
191 // Monitor NameOwnerChanged signal.
192 cras_proxy_->SetNameOwnerChangedCallback(
193 base::Bind(&CrasAudioClientImpl::NameOwnerChangedReceived,
194 weak_ptr_factory_.GetWeakPtr()));
196 // Monitor the D-Bus signal for output mute change.
197 cras_proxy_->ConnectToSignal(
198 cras::kCrasControlInterface,
199 cras::kOutputMuteChanged,
200 base::Bind(&CrasAudioClientImpl::OutputMuteChangedReceived,
201 weak_ptr_factory_.GetWeakPtr()),
202 base::Bind(&CrasAudioClientImpl::SignalConnected,
203 weak_ptr_factory_.GetWeakPtr()));
205 // Monitor the D-Bus signal for input mute change.
206 cras_proxy_->ConnectToSignal(
207 cras::kCrasControlInterface,
208 cras::kInputMuteChanged,
209 base::Bind(&CrasAudioClientImpl::InputMuteChangedReceived,
210 weak_ptr_factory_.GetWeakPtr()),
211 base::Bind(&CrasAudioClientImpl::SignalConnected,
212 weak_ptr_factory_.GetWeakPtr()));
214 // Monitor the D-Bus signal for nodes change.
215 cras_proxy_->ConnectToSignal(
216 cras::kCrasControlInterface,
217 cras::kNodesChanged,
218 base::Bind(&CrasAudioClientImpl::NodesChangedReceived,
219 weak_ptr_factory_.GetWeakPtr()),
220 base::Bind(&CrasAudioClientImpl::SignalConnected,
221 weak_ptr_factory_.GetWeakPtr()));
223 // Monitor the D-Bus signal for active output node change.
224 cras_proxy_->ConnectToSignal(
225 cras::kCrasControlInterface,
226 cras::kActiveOutputNodeChanged,
227 base::Bind(&CrasAudioClientImpl::ActiveOutputNodeChangedReceived,
228 weak_ptr_factory_.GetWeakPtr()),
229 base::Bind(&CrasAudioClientImpl::SignalConnected,
230 weak_ptr_factory_.GetWeakPtr()));
232 // Monitor the D-Bus signal for active input node change.
233 cras_proxy_->ConnectToSignal(
234 cras::kCrasControlInterface,
235 cras::kActiveInputNodeChanged,
236 base::Bind(&CrasAudioClientImpl::ActiveInputNodeChangedReceived,
237 weak_ptr_factory_.GetWeakPtr()),
238 base::Bind(&CrasAudioClientImpl::SignalConnected,
239 weak_ptr_factory_.GetWeakPtr()));
242 private:
243 // Called when the cras signal is initially connected.
244 void SignalConnected(const std::string& interface_name,
245 const std::string& signal_name,
246 bool success) {
247 LOG_IF(ERROR, !success)
248 << "Failed to connect to cras signal:" << signal_name;
251 void NameOwnerChangedReceived(const std::string& old_owner,
252 const std::string& new_owner) {
253 FOR_EACH_OBSERVER(Observer, observers_, AudioClientRestarted());
256 // Called when a OutputMuteChanged signal is received.
257 void OutputMuteChangedReceived(dbus::Signal* signal) {
258 // Chrome should always call SetOutputUserMute api to set the output
259 // mute state and monitor user_mute state from OutputMuteChanged signal.
260 dbus::MessageReader reader(signal);
261 bool system_mute, user_mute;
262 if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) {
263 LOG(ERROR) << "Error reading signal from cras:"
264 << signal->ToString();
266 FOR_EACH_OBSERVER(Observer, observers_, OutputMuteChanged(user_mute));
269 // Called when a InputMuteChanged signal is received.
270 void InputMuteChangedReceived(dbus::Signal* signal) {
271 dbus::MessageReader reader(signal);
272 bool mute;
273 if (!reader.PopBool(&mute)) {
274 LOG(ERROR) << "Error reading signal from cras:"
275 << signal->ToString();
277 FOR_EACH_OBSERVER(Observer, observers_, InputMuteChanged(mute));
280 void NodesChangedReceived(dbus::Signal* signal) {
281 FOR_EACH_OBSERVER(Observer, observers_, NodesChanged());
284 void ActiveOutputNodeChangedReceived(dbus::Signal* signal) {
285 dbus::MessageReader reader(signal);
286 uint64 node_id;
287 if (!reader.PopUint64(&node_id)) {
288 LOG(ERROR) << "Error reading signal from cras:"
289 << signal->ToString();
291 FOR_EACH_OBSERVER(Observer, observers_, ActiveOutputNodeChanged(node_id));
294 void ActiveInputNodeChangedReceived(dbus::Signal* signal) {
295 dbus::MessageReader reader(signal);
296 uint64 node_id;
297 if (!reader.PopUint64(&node_id)) {
298 LOG(ERROR) << "Error reading signal from cras:"
299 << signal->ToString();
301 FOR_EACH_OBSERVER(Observer, observers_, ActiveInputNodeChanged(node_id));
304 void OnGetVolumeState(const GetVolumeStateCallback& callback,
305 dbus::Response* response) {
306 bool success = true;
307 VolumeState volume_state;
308 if (response) {
309 dbus::MessageReader reader(response);
310 if (!reader.PopInt32(&volume_state.output_volume) ||
311 !reader.PopBool(&volume_state.output_system_mute) ||
312 !reader.PopInt32(&volume_state.input_gain) ||
313 !reader.PopBool(&volume_state.input_mute) ||
314 !reader.PopBool(&volume_state.output_user_mute)) {
315 success = false;
316 LOG(ERROR) << "Error reading response from cras: "
317 << response->ToString();
319 } else {
320 success = false;
321 LOG(ERROR) << "Error calling " << cras::kGetVolumeState;
324 callback.Run(volume_state, success);
327 void OnGetNodes(const GetNodesCallback& callback,
328 dbus::Response* response) {
329 bool success = true;
330 AudioNodeList node_list;
331 if (response) {
332 dbus::MessageReader response_reader(response);
333 dbus::MessageReader array_reader(response);
334 while (response_reader.HasMoreData()) {
335 if (!response_reader.PopArray(&array_reader)) {
336 success = false;
337 LOG(ERROR) << "Error reading response from cras: "
338 << response->ToString();
339 break;
342 AudioNode node;
343 if (!GetAudioNode(response, &array_reader, &node)) {
344 success = false;
345 LOG(WARNING) << "Error reading audio node data from cras: "
346 << response->ToString();
347 break;
349 // Filter out the "UNKNOWN" type of audio devices.
350 if (node.type != "UNKNOWN")
351 node_list.push_back(node);
355 if (node_list.empty())
356 return;
358 callback.Run(node_list, success);
361 void OnError(const ErrorCallback& error_callback,
362 dbus::ErrorResponse* response) {
363 // Error response has optional error message argument.
364 std::string error_name;
365 std::string error_message;
366 if (response) {
367 dbus::MessageReader reader(response);
368 error_name = response->GetErrorName();
369 reader.PopString(&error_message);
370 } else {
371 error_name = kNoResponseError;
372 error_message = "";
374 error_callback.Run(error_name, error_message);
377 bool GetAudioNode(dbus::Response* response,
378 dbus::MessageReader* array_reader,
379 AudioNode *node) {
380 while (array_reader->HasMoreData()) {
381 dbus::MessageReader dict_entry_reader(response);
382 dbus::MessageReader value_reader(response);
383 std::string key;
384 if (!array_reader->PopDictEntry(&dict_entry_reader) ||
385 !dict_entry_reader.PopString(&key) ||
386 !dict_entry_reader.PopVariant(&value_reader)) {
387 return false;
390 if (key == cras::kIsInputProperty) {
391 if (!value_reader.PopBool(&node->is_input))
392 return false;
393 } else if (key == cras::kIdProperty) {
394 if (!value_reader.PopUint64(&node->id))
395 return false;
396 } else if (key == cras::kDeviceNameProperty) {
397 if (!value_reader.PopString(&node->device_name))
398 return false;
399 } else if (key == cras::kTypeProperty) {
400 if (!value_reader.PopString(&node->type))
401 return false;
402 } else if (key == cras::kNameProperty) {
403 if (!value_reader.PopString(&node->name))
404 return false;
405 } else if (key == cras::kActiveProperty) {
406 if (!value_reader.PopBool(&node->active))
407 return false;
408 } else if (key == cras::kPluggedTimeProperty) {
409 if (!value_reader.PopUint64(&node->plugged_time))
410 return false;
414 return true;
417 dbus::ObjectProxy* cras_proxy_;
418 ObserverList<Observer> observers_;
420 // Note: This should remain the last member so it'll be destroyed and
421 // invalidate its weak pointers before any other members are destroyed.
422 base::WeakPtrFactory<CrasAudioClientImpl> weak_ptr_factory_;
424 DISALLOW_COPY_AND_ASSIGN(CrasAudioClientImpl);
427 CrasAudioClient::Observer::~Observer() {
430 void CrasAudioClient::Observer::AudioClientRestarted() {
433 void CrasAudioClient::Observer::OutputMuteChanged(bool mute_on) {
436 void CrasAudioClient::Observer::InputMuteChanged(bool mute_on) {
439 void CrasAudioClient::Observer::NodesChanged() {
442 void CrasAudioClient::Observer::ActiveOutputNodeChanged(uint64 node_id){
445 void CrasAudioClient::Observer::ActiveInputNodeChanged(uint64 node_id) {
448 CrasAudioClient::CrasAudioClient() {
451 CrasAudioClient::~CrasAudioClient() {
454 // static
455 CrasAudioClient* CrasAudioClient::Create() {
456 return new CrasAudioClientImpl();
459 } // namespace chromeos