1 // Copyright 2017 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 "services/audio/public/cpp/audio_system_to_service_adapter.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/check_op.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/notreached.h"
13 #include "base/trace_event/trace_event.h"
14 #include "media/audio/audio_device_description.h"
15 #include "mojo/public/cpp/bindings/callback_helpers.h"
16
17 namespace audio {
18
19 namespace {
20
21 using OnAudioParamsCallback = media::AudioSystem::OnAudioParamsCallback;
22 using OnDeviceIdCallback = media::AudioSystem::OnDeviceIdCallback;
23 using OnInputDeviceInfoCallback = media::AudioSystem::OnInputDeviceInfoCallback;
24 using OnBoolCallback = media::AudioSystem::OnBoolCallback;
25 using OnDeviceDescriptionsCallback =
26 media::AudioSystem::OnDeviceDescriptionsCallback;
27 using media::AudioParameters;
28
ToTraceId(base::TimeTicks time)29 int64_t ToTraceId(base::TimeTicks time) {
30 return (time - base::TimeTicks()).InNanoseconds();
31 }
32
ParamsToString(base::Optional<AudioParameters> params)33 std::string ParamsToString(base::Optional<AudioParameters> params) {
34 return params ? params->AsHumanReadableString() : "nullopt";
35 }
36
37 enum Action {
38 kGetInputStreamParameters,
39 kGetOutputStreamParameters,
40 kHasInputDevices,
41 kHasOutputDevices,
42 kGetInputDeviceDescriptions,
43 kGetOutputDeviceDescriptions,
44 kGetAssociatedOutputDeviceID,
45 kGetInputDeviceInfo
46 };
47
48 enum StreamType { kInput, kOutput };
49
GetTraceEvent(Action action)50 const char* GetTraceEvent(Action action) {
51 switch (action) {
52 case kGetInputStreamParameters:
53 return "AudioSystemToServiceAdapter::GetInputStreamParameters";
54 case kGetOutputStreamParameters:
55 return "AudioSystemToServiceAdapter::GetOutputStreamParameters";
56 case kHasInputDevices:
57 return "AudioSystemToServiceAdapter::HasInputDevices";
58 case kHasOutputDevices:
59 return "AudioSystemToServiceAdapter::HasOutputDevices";
60 case kGetInputDeviceDescriptions:
61 return "AudioSystemToServiceAdapter::GetInputDeviceDescriptions";
62 case kGetOutputDeviceDescriptions:
63 return "AudioSystemToServiceAdapter::GetOutputDeviceDescriptions";
64 case kGetAssociatedOutputDeviceID:
65 return "AudioSystemToServiceAdapter::GetAssociatedOutputDeviceID";
66 case kGetInputDeviceInfo:
67 return "AudioSystemToServiceAdapter::GetInputDeviceInfo";
68 }
69 NOTREACHED();
70 }
71
WrapGetStreamParametersReply(StreamType stream_type,const std::string & device_id,OnAudioParamsCallback on_params_callback)72 OnAudioParamsCallback WrapGetStreamParametersReply(
73 StreamType stream_type,
74 const std::string& device_id,
75 OnAudioParamsCallback on_params_callback) {
76 const Action action = (stream_type == kInput) ? kGetInputStreamParameters
77 : kGetOutputStreamParameters;
78 const base::TimeTicks start_time = base::TimeTicks::Now();
79 TRACE_EVENT_ASYNC_BEGIN1("audio", GetTraceEvent(action),
80 ToTraceId(start_time), "device id", device_id);
81
82 return base::BindOnce(
83 [](Action action, base::TimeTicks start_time,
84 OnAudioParamsCallback on_params_callback,
85 const base::Optional<media::AudioParameters>& params) {
86 TRACE_EVENT_ASYNC_END1("audio", GetTraceEvent(action),
87 ToTraceId(start_time), "params",
88 ParamsToString(params));
89 std::move(on_params_callback).Run(params);
90 },
91 action, start_time, std::move(on_params_callback));
92 }
93
WrapHasDevicesReply(StreamType stream_type,OnBoolCallback on_has_devices_callback)94 OnBoolCallback WrapHasDevicesReply(StreamType stream_type,
95 OnBoolCallback on_has_devices_callback) {
96 const Action action =
97 (stream_type == kInput) ? kHasInputDevices : kHasOutputDevices;
98 const base::TimeTicks start_time = base::TimeTicks::Now();
99 TRACE_EVENT_ASYNC_BEGIN0("audio", GetTraceEvent(action),
100 ToTraceId(start_time));
101
102 return base::BindOnce(
103 [](Action action, base::TimeTicks start_time,
104 OnBoolCallback on_has_devices_callback, bool answer) {
105 TRACE_EVENT_ASYNC_END1("audio", GetTraceEvent(action),
106 ToTraceId(start_time), "answer", answer);
107 std::move(on_has_devices_callback).Run(answer);
108 },
109 action, start_time, std::move(on_has_devices_callback));
110 }
111
WrapGetDeviceDescriptionsReply(StreamType stream_type,OnDeviceDescriptionsCallback on_descriptions_callback)112 OnDeviceDescriptionsCallback WrapGetDeviceDescriptionsReply(
113 StreamType stream_type,
114 OnDeviceDescriptionsCallback on_descriptions_callback) {
115 const Action action = (stream_type == kInput) ? kGetInputDeviceDescriptions
116 : kGetOutputDeviceDescriptions;
117 const base::TimeTicks start_time = base::TimeTicks::Now();
118 TRACE_EVENT_ASYNC_BEGIN0("audio", GetTraceEvent(action),
119 ToTraceId(start_time));
120
121 return base::BindOnce(
122 [](Action action, base::TimeTicks start_time,
123 OnDeviceDescriptionsCallback on_descriptions_callback,
124 media::AudioDeviceDescriptions descriptions) {
125 TRACE_EVENT_ASYNC_END1("audio", GetTraceEvent(action),
126 ToTraceId(start_time), "device count",
127 descriptions.size());
128 std::move(on_descriptions_callback).Run(std::move(descriptions));
129 },
130 action, start_time, std::move(on_descriptions_callback));
131 }
132
WrapGetAssociatedOutputDeviceIDReply(const std::string & input_device_id,OnDeviceIdCallback on_device_id_callback)133 OnDeviceIdCallback WrapGetAssociatedOutputDeviceIDReply(
134 const std::string& input_device_id,
135 OnDeviceIdCallback on_device_id_callback) {
136 const base::TimeTicks start_time = base::TimeTicks::Now();
137 TRACE_EVENT_ASYNC_BEGIN1("audio", GetTraceEvent(kGetAssociatedOutputDeviceID),
138 ToTraceId(start_time), "input_device_id",
139 input_device_id);
140
141 return base::BindOnce(
142 [](base::TimeTicks start_time, OnDeviceIdCallback on_device_id_callback,
143 const base::Optional<std::string>& answer) {
144 TRACE_EVENT_ASYNC_END1(
145 "audio", GetTraceEvent(kGetAssociatedOutputDeviceID),
146 ToTraceId(start_time), "answer", answer.value_or("nullopt"));
147 std::move(on_device_id_callback).Run(answer);
148 },
149 start_time, std::move(on_device_id_callback));
150 }
151
WrapGetInputDeviceInfoReply(const std::string & input_device_id,OnInputDeviceInfoCallback on_input_device_info_callback)152 OnInputDeviceInfoCallback WrapGetInputDeviceInfoReply(
153 const std::string& input_device_id,
154 OnInputDeviceInfoCallback on_input_device_info_callback) {
155 const base::TimeTicks start_time = base::TimeTicks::Now();
156 TRACE_EVENT_ASYNC_BEGIN1("audio", GetTraceEvent(kGetInputDeviceInfo),
157 ToTraceId(start_time), "input_device_id",
158 input_device_id);
159
160 return base::BindOnce(
161 [](base::TimeTicks start_time,
162 OnInputDeviceInfoCallback on_input_device_info_callback,
163 const base::Optional<AudioParameters>& params,
164 const base::Optional<std::string>& associated_output_device_id) {
165 TRACE_EVENT_ASYNC_END2(
166 "audio", GetTraceEvent(kGetInputDeviceInfo), ToTraceId(start_time),
167 "params", ParamsToString(params), "associated_output_device_id",
168 associated_output_device_id.value_or("nullopt"));
169 std::move(on_input_device_info_callback)
170 .Run(params, associated_output_device_id);
171 },
172 start_time, std::move(on_input_device_info_callback));
173 }
174
175 } // namespace
176
AudioSystemToServiceAdapter(SystemInfoBinder system_info_binder,base::TimeDelta disconnect_timeout)177 AudioSystemToServiceAdapter::AudioSystemToServiceAdapter(
178 SystemInfoBinder system_info_binder,
179 base::TimeDelta disconnect_timeout)
180 : system_info_binder_(std::move(system_info_binder)),
181 disconnect_timeout_(disconnect_timeout) {
182 DCHECK(system_info_binder_);
183 DETACH_FROM_THREAD(thread_checker_);
184 }
185
AudioSystemToServiceAdapter(SystemInfoBinder system_info_binder)186 AudioSystemToServiceAdapter::AudioSystemToServiceAdapter(
187 SystemInfoBinder system_info_binder)
188 : AudioSystemToServiceAdapter(std::move(system_info_binder),
189 base::TimeDelta()) {}
190
~AudioSystemToServiceAdapter()191 AudioSystemToServiceAdapter::~AudioSystemToServiceAdapter() {
192 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
193 if (system_info_.is_bound()) {
194 TRACE_EVENT_NESTABLE_ASYNC_END1("audio",
195 "AudioSystemToServiceAdapter bound", this,
196 "disconnect reason", "destroyed");
197 }
198 }
199
GetInputStreamParameters(const std::string & device_id,OnAudioParamsCallback on_params_callback)200 void AudioSystemToServiceAdapter::GetInputStreamParameters(
201 const std::string& device_id,
202 OnAudioParamsCallback on_params_callback) {
203 GetSystemInfo()->GetInputStreamParameters(
204 device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
205 WrapGetStreamParametersReply(
206 kInput, device_id, std::move(on_params_callback)),
207 base::nullopt));
208 }
209
GetOutputStreamParameters(const std::string & device_id,OnAudioParamsCallback on_params_callback)210 void AudioSystemToServiceAdapter::GetOutputStreamParameters(
211 const std::string& device_id,
212 OnAudioParamsCallback on_params_callback) {
213 GetSystemInfo()->GetOutputStreamParameters(
214 device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
215 WrapGetStreamParametersReply(
216 kOutput, device_id, std::move(on_params_callback)),
217 base::nullopt));
218 }
219
HasInputDevices(OnBoolCallback on_has_devices_callback)220 void AudioSystemToServiceAdapter::HasInputDevices(
221 OnBoolCallback on_has_devices_callback) {
222 GetSystemInfo()->HasInputDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
223 WrapHasDevicesReply(kInput, std::move(on_has_devices_callback)), false));
224 }
225
HasOutputDevices(OnBoolCallback on_has_devices_callback)226 void AudioSystemToServiceAdapter::HasOutputDevices(
227 OnBoolCallback on_has_devices_callback) {
228 GetSystemInfo()->HasOutputDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
229 WrapHasDevicesReply(kOutput, std::move(on_has_devices_callback)), false));
230 }
231
GetDeviceDescriptions(bool for_input,OnDeviceDescriptionsCallback on_descriptions_callback)232 void AudioSystemToServiceAdapter::GetDeviceDescriptions(
233 bool for_input,
234 OnDeviceDescriptionsCallback on_descriptions_callback) {
235 auto reply_callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
236 WrapCallbackWithDeviceNameLocalization(
237 std::move(on_descriptions_callback)),
238 media::AudioDeviceDescriptions());
239 if (for_input)
240 GetSystemInfo()->GetInputDeviceDescriptions(
241 WrapGetDeviceDescriptionsReply(kInput, std::move(reply_callback)));
242 else
243 GetSystemInfo()->GetOutputDeviceDescriptions(
244 WrapGetDeviceDescriptionsReply(kOutput, std::move(reply_callback)));
245 }
246
GetAssociatedOutputDeviceID(const std::string & input_device_id,OnDeviceIdCallback on_device_id_callback)247 void AudioSystemToServiceAdapter::GetAssociatedOutputDeviceID(
248 const std::string& input_device_id,
249 OnDeviceIdCallback on_device_id_callback) {
250 GetSystemInfo()->GetAssociatedOutputDeviceID(
251 input_device_id,
252 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
253 WrapGetAssociatedOutputDeviceIDReply(
254 input_device_id, std::move(on_device_id_callback)),
255 base::nullopt));
256 }
257
GetInputDeviceInfo(const std::string & input_device_id,OnInputDeviceInfoCallback on_input_device_info_callback)258 void AudioSystemToServiceAdapter::GetInputDeviceInfo(
259 const std::string& input_device_id,
260 OnInputDeviceInfoCallback on_input_device_info_callback) {
261 GetSystemInfo()->GetInputDeviceInfo(
262 input_device_id,
263 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
264 WrapGetInputDeviceInfoReply(input_device_id,
265 std::move(on_input_device_info_callback)),
266 base::nullopt, base::nullopt));
267 }
268
GetSystemInfo()269 mojom::SystemInfo* AudioSystemToServiceAdapter::GetSystemInfo() {
270 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
271 if (!system_info_) {
272 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
273 "audio", "AudioSystemToServiceAdapter bound", this);
274 system_info_binder_.Run(system_info_.BindNewPipeAndPassReceiver());
275 system_info_.set_disconnect_handler(
276 base::BindOnce(&AudioSystemToServiceAdapter::OnConnectionError,
277 base::Unretained(this)));
278 if (!disconnect_timeout_.is_zero())
279 system_info_.reset_on_idle_timeout(disconnect_timeout_);
280 }
281
282 return system_info_.get();
283 }
284
OnConnectionError()285 void AudioSystemToServiceAdapter::OnConnectionError() {
286 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
287 TRACE_EVENT_NESTABLE_ASYNC_END1("audio", "AudioSystemToServiceAdapter bound",
288 this, "disconnect reason",
289 "connection error");
290 system_info_.reset();
291 }
292
293 } // namespace audio
294