1 /*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "sdk/android/src/jni/audio_device/aaudio_wrapper.h"
12
13 #include "rtc_base/logging.h"
14 #include "rtc_base/strings/string_builder.h"
15 #include "rtc_base/time_utils.h"
16
17 #define LOG_ON_ERROR(op) \
18 do { \
19 aaudio_result_t result = (op); \
20 if (result != AAUDIO_OK) { \
21 RTC_LOG(LS_ERROR) << #op << ": " << AAudio_convertResultToText(result); \
22 } \
23 } while (0)
24
25 #define RETURN_ON_ERROR(op, ...) \
26 do { \
27 aaudio_result_t result = (op); \
28 if (result != AAUDIO_OK) { \
29 RTC_LOG(LS_ERROR) << #op << ": " << AAudio_convertResultToText(result); \
30 return __VA_ARGS__; \
31 } \
32 } while (0)
33
34 namespace webrtc {
35
36 namespace jni {
37
38 namespace {
39
DirectionToString(aaudio_direction_t direction)40 const char* DirectionToString(aaudio_direction_t direction) {
41 switch (direction) {
42 case AAUDIO_DIRECTION_OUTPUT:
43 return "OUTPUT";
44 case AAUDIO_DIRECTION_INPUT:
45 return "INPUT";
46 default:
47 return "UNKNOWN";
48 }
49 }
50
SharingModeToString(aaudio_sharing_mode_t mode)51 const char* SharingModeToString(aaudio_sharing_mode_t mode) {
52 switch (mode) {
53 case AAUDIO_SHARING_MODE_EXCLUSIVE:
54 return "EXCLUSIVE";
55 case AAUDIO_SHARING_MODE_SHARED:
56 return "SHARED";
57 default:
58 return "UNKNOWN";
59 }
60 }
61
PerformanceModeToString(aaudio_performance_mode_t mode)62 const char* PerformanceModeToString(aaudio_performance_mode_t mode) {
63 switch (mode) {
64 case AAUDIO_PERFORMANCE_MODE_NONE:
65 return "NONE";
66 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
67 return "POWER_SAVING";
68 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
69 return "LOW_LATENCY";
70 default:
71 return "UNKNOWN";
72 }
73 }
74
FormatToString(int32_t id)75 const char* FormatToString(int32_t id) {
76 switch (id) {
77 case AAUDIO_FORMAT_INVALID:
78 return "INVALID";
79 case AAUDIO_FORMAT_UNSPECIFIED:
80 return "UNSPECIFIED";
81 case AAUDIO_FORMAT_PCM_I16:
82 return "PCM_I16";
83 case AAUDIO_FORMAT_PCM_FLOAT:
84 return "FLOAT";
85 default:
86 return "UNKNOWN";
87 }
88 }
89
ErrorCallback(AAudioStream * stream,void * user_data,aaudio_result_t error)90 void ErrorCallback(AAudioStream* stream,
91 void* user_data,
92 aaudio_result_t error) {
93 RTC_DCHECK(user_data);
94 AAudioWrapper* aaudio_wrapper = reinterpret_cast<AAudioWrapper*>(user_data);
95 RTC_LOG(LS_WARNING) << "ErrorCallback: "
96 << DirectionToString(aaudio_wrapper->direction());
97 RTC_DCHECK(aaudio_wrapper->observer());
98 aaudio_wrapper->observer()->OnErrorCallback(error);
99 }
100
DataCallback(AAudioStream * stream,void * user_data,void * audio_data,int32_t num_frames)101 aaudio_data_callback_result_t DataCallback(AAudioStream* stream,
102 void* user_data,
103 void* audio_data,
104 int32_t num_frames) {
105 RTC_DCHECK(user_data);
106 RTC_DCHECK(audio_data);
107 AAudioWrapper* aaudio_wrapper = reinterpret_cast<AAudioWrapper*>(user_data);
108 RTC_DCHECK(aaudio_wrapper->observer());
109 return aaudio_wrapper->observer()->OnDataCallback(audio_data, num_frames);
110 }
111
112 // Wraps the stream builder object to ensure that it is released properly when
113 // the stream builder goes out of scope.
114 class ScopedStreamBuilder {
115 public:
ScopedStreamBuilder()116 ScopedStreamBuilder() {
117 LOG_ON_ERROR(AAudio_createStreamBuilder(&builder_));
118 RTC_DCHECK(builder_);
119 }
~ScopedStreamBuilder()120 ~ScopedStreamBuilder() {
121 if (builder_) {
122 LOG_ON_ERROR(AAudioStreamBuilder_delete(builder_));
123 }
124 }
125
get() const126 AAudioStreamBuilder* get() const { return builder_; }
127
128 private:
129 AAudioStreamBuilder* builder_ = nullptr;
130 };
131
132 } // namespace
133
AAudioWrapper(const AudioParameters & audio_parameters,aaudio_direction_t direction,AAudioObserverInterface * observer)134 AAudioWrapper::AAudioWrapper(const AudioParameters& audio_parameters,
135 aaudio_direction_t direction,
136 AAudioObserverInterface* observer)
137 : audio_parameters_(audio_parameters),
138 direction_(direction),
139 observer_(observer) {
140 RTC_LOG(LS_INFO) << "ctor";
141 RTC_DCHECK(observer_);
142 aaudio_thread_checker_.Detach();
143 RTC_LOG(LS_INFO) << audio_parameters_.ToString();
144 }
145
~AAudioWrapper()146 AAudioWrapper::~AAudioWrapper() {
147 RTC_LOG(LS_INFO) << "dtor";
148 RTC_DCHECK(thread_checker_.IsCurrent());
149 RTC_DCHECK(!stream_);
150 }
151
Init()152 bool AAudioWrapper::Init() {
153 RTC_LOG(LS_INFO) << "Init";
154 RTC_DCHECK(thread_checker_.IsCurrent());
155 // Creates a stream builder which can be used to open an audio stream.
156 ScopedStreamBuilder builder;
157 // Configures the stream builder using audio parameters given at construction.
158 SetStreamConfiguration(builder.get());
159 // Opens a stream based on options in the stream builder.
160 if (!OpenStream(builder.get())) {
161 return false;
162 }
163 // Ensures that the opened stream could activate the requested settings.
164 if (!VerifyStreamConfiguration()) {
165 return false;
166 }
167 // Optimizes the buffer scheme for lowest possible latency and creates
168 // additional buffer logic to match the 10ms buffer size used in WebRTC.
169 if (!OptimizeBuffers()) {
170 return false;
171 }
172 LogStreamState();
173 return true;
174 }
175
Start()176 bool AAudioWrapper::Start() {
177 RTC_LOG(LS_INFO) << "Start";
178 RTC_DCHECK(thread_checker_.IsCurrent());
179 // TODO(henrika): this state check might not be needed.
180 aaudio_stream_state_t current_state = AAudioStream_getState(stream_);
181 if (current_state != AAUDIO_STREAM_STATE_OPEN) {
182 RTC_LOG(LS_ERROR) << "Invalid state: "
183 << AAudio_convertStreamStateToText(current_state);
184 return false;
185 }
186 // Asynchronous request for the stream to start.
187 RETURN_ON_ERROR(AAudioStream_requestStart(stream_), false);
188 LogStreamState();
189 return true;
190 }
191
Stop()192 bool AAudioWrapper::Stop() {
193 RTC_LOG(LS_INFO) << "Stop: " << DirectionToString(direction());
194 RTC_DCHECK(thread_checker_.IsCurrent());
195 // Asynchronous request for the stream to stop.
196 RETURN_ON_ERROR(AAudioStream_requestStop(stream_), false);
197 CloseStream();
198 aaudio_thread_checker_.Detach();
199 return true;
200 }
201
EstimateLatencyMillis() const202 double AAudioWrapper::EstimateLatencyMillis() const {
203 RTC_DCHECK(stream_);
204 double latency_millis = 0.0;
205 if (direction() == AAUDIO_DIRECTION_INPUT) {
206 // For input streams. Best guess we can do is to use the current burst size
207 // as delay estimate.
208 latency_millis = static_cast<double>(frames_per_burst()) / sample_rate() *
209 rtc::kNumMillisecsPerSec;
210 } else {
211 int64_t existing_frame_index;
212 int64_t existing_frame_presentation_time;
213 // Get the time at which a particular frame was presented to audio hardware.
214 aaudio_result_t result = AAudioStream_getTimestamp(
215 stream_, CLOCK_MONOTONIC, &existing_frame_index,
216 &existing_frame_presentation_time);
217 // Results are only valid when the stream is in AAUDIO_STREAM_STATE_STARTED.
218 if (result == AAUDIO_OK) {
219 // Get write index for next audio frame.
220 int64_t next_frame_index = frames_written();
221 // Number of frames between next frame and the existing frame.
222 int64_t frame_index_delta = next_frame_index - existing_frame_index;
223 // Assume the next frame will be written now.
224 int64_t next_frame_write_time = rtc::TimeNanos();
225 // Calculate time when next frame will be presented to the hardware taking
226 // sample rate into account.
227 int64_t frame_time_delta =
228 (frame_index_delta * rtc::kNumNanosecsPerSec) / sample_rate();
229 int64_t next_frame_presentation_time =
230 existing_frame_presentation_time + frame_time_delta;
231 // Derive a latency estimate given results above.
232 latency_millis = static_cast<double>(next_frame_presentation_time -
233 next_frame_write_time) /
234 rtc::kNumNanosecsPerMillisec;
235 }
236 }
237 return latency_millis;
238 }
239
240 // Returns new buffer size or a negative error value if buffer size could not
241 // be increased.
IncreaseOutputBufferSize()242 bool AAudioWrapper::IncreaseOutputBufferSize() {
243 RTC_LOG(LS_INFO) << "IncreaseBufferSize";
244 RTC_DCHECK(stream_);
245 RTC_DCHECK(aaudio_thread_checker_.IsCurrent());
246 RTC_DCHECK_EQ(direction(), AAUDIO_DIRECTION_OUTPUT);
247 aaudio_result_t buffer_size = AAudioStream_getBufferSizeInFrames(stream_);
248 // Try to increase size of buffer with one burst to reduce risk of underrun.
249 buffer_size += frames_per_burst();
250 // Verify that the new buffer size is not larger than max capacity.
251 // TODO(henrika): keep track of case when we reach the capacity limit.
252 const int32_t max_buffer_size = buffer_capacity_in_frames();
253 if (buffer_size > max_buffer_size) {
254 RTC_LOG(LS_ERROR) << "Required buffer size (" << buffer_size
255 << ") is higher than max: " << max_buffer_size;
256 return false;
257 }
258 RTC_LOG(LS_INFO) << "Updating buffer size to: " << buffer_size
259 << " (max=" << max_buffer_size << ")";
260 buffer_size = AAudioStream_setBufferSizeInFrames(stream_, buffer_size);
261 if (buffer_size < 0) {
262 RTC_LOG(LS_ERROR) << "Failed to change buffer size: "
263 << AAudio_convertResultToText(buffer_size);
264 return false;
265 }
266 RTC_LOG(LS_INFO) << "Buffer size changed to: " << buffer_size;
267 return true;
268 }
269
ClearInputStream(void * audio_data,int32_t num_frames)270 void AAudioWrapper::ClearInputStream(void* audio_data, int32_t num_frames) {
271 RTC_LOG(LS_INFO) << "ClearInputStream";
272 RTC_DCHECK(stream_);
273 RTC_DCHECK(aaudio_thread_checker_.IsCurrent());
274 RTC_DCHECK_EQ(direction(), AAUDIO_DIRECTION_INPUT);
275 aaudio_result_t cleared_frames = 0;
276 do {
277 cleared_frames = AAudioStream_read(stream_, audio_data, num_frames, 0);
278 } while (cleared_frames > 0);
279 }
280
observer() const281 AAudioObserverInterface* AAudioWrapper::observer() const {
282 return observer_;
283 }
284
audio_parameters() const285 AudioParameters AAudioWrapper::audio_parameters() const {
286 return audio_parameters_;
287 }
288
samples_per_frame() const289 int32_t AAudioWrapper::samples_per_frame() const {
290 RTC_DCHECK(stream_);
291 return AAudioStream_getSamplesPerFrame(stream_);
292 }
293
buffer_size_in_frames() const294 int32_t AAudioWrapper::buffer_size_in_frames() const {
295 RTC_DCHECK(stream_);
296 return AAudioStream_getBufferSizeInFrames(stream_);
297 }
298
buffer_capacity_in_frames() const299 int32_t AAudioWrapper::buffer_capacity_in_frames() const {
300 RTC_DCHECK(stream_);
301 return AAudioStream_getBufferCapacityInFrames(stream_);
302 }
303
device_id() const304 int32_t AAudioWrapper::device_id() const {
305 RTC_DCHECK(stream_);
306 return AAudioStream_getDeviceId(stream_);
307 }
308
xrun_count() const309 int32_t AAudioWrapper::xrun_count() const {
310 RTC_DCHECK(stream_);
311 return AAudioStream_getXRunCount(stream_);
312 }
313
format() const314 int32_t AAudioWrapper::format() const {
315 RTC_DCHECK(stream_);
316 return AAudioStream_getFormat(stream_);
317 }
318
sample_rate() const319 int32_t AAudioWrapper::sample_rate() const {
320 RTC_DCHECK(stream_);
321 return AAudioStream_getSampleRate(stream_);
322 }
323
channel_count() const324 int32_t AAudioWrapper::channel_count() const {
325 RTC_DCHECK(stream_);
326 return AAudioStream_getChannelCount(stream_);
327 }
328
frames_per_callback() const329 int32_t AAudioWrapper::frames_per_callback() const {
330 RTC_DCHECK(stream_);
331 return AAudioStream_getFramesPerDataCallback(stream_);
332 }
333
sharing_mode() const334 aaudio_sharing_mode_t AAudioWrapper::sharing_mode() const {
335 RTC_DCHECK(stream_);
336 return AAudioStream_getSharingMode(stream_);
337 }
338
performance_mode() const339 aaudio_performance_mode_t AAudioWrapper::performance_mode() const {
340 RTC_DCHECK(stream_);
341 return AAudioStream_getPerformanceMode(stream_);
342 }
343
stream_state() const344 aaudio_stream_state_t AAudioWrapper::stream_state() const {
345 RTC_DCHECK(stream_);
346 return AAudioStream_getState(stream_);
347 }
348
frames_written() const349 int64_t AAudioWrapper::frames_written() const {
350 RTC_DCHECK(stream_);
351 return AAudioStream_getFramesWritten(stream_);
352 }
353
frames_read() const354 int64_t AAudioWrapper::frames_read() const {
355 RTC_DCHECK(stream_);
356 return AAudioStream_getFramesRead(stream_);
357 }
358
SetStreamConfiguration(AAudioStreamBuilder * builder)359 void AAudioWrapper::SetStreamConfiguration(AAudioStreamBuilder* builder) {
360 RTC_LOG(LS_INFO) << "SetStreamConfiguration";
361 RTC_DCHECK(builder);
362 RTC_DCHECK(thread_checker_.IsCurrent());
363 // Request usage of default primary output/input device.
364 // TODO(henrika): verify that default device follows Java APIs.
365 // https://developer.android.com/reference/android/media/AudioDeviceInfo.html.
366 AAudioStreamBuilder_setDeviceId(builder, AAUDIO_UNSPECIFIED);
367 // Use preferred sample rate given by the audio parameters.
368 AAudioStreamBuilder_setSampleRate(builder, audio_parameters().sample_rate());
369 // Use preferred channel configuration given by the audio parameters.
370 AAudioStreamBuilder_setChannelCount(builder, audio_parameters().channels());
371 // Always use 16-bit PCM audio sample format.
372 AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_I16);
373 // TODO(henrika): investigate effect of using AAUDIO_SHARING_MODE_EXCLUSIVE.
374 // Ask for exclusive mode since this will give us the lowest possible latency.
375 // If exclusive mode isn't available, shared mode will be used instead.
376 AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_SHARED);
377 // Use the direction that was given at construction.
378 AAudioStreamBuilder_setDirection(builder, direction_);
379 // TODO(henrika): investigate performance using different performance modes.
380 AAudioStreamBuilder_setPerformanceMode(builder,
381 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
382 // Given that WebRTC applications require low latency, our audio stream uses
383 // an asynchronous callback function to transfer data to and from the
384 // application. AAudio executes the callback in a higher-priority thread that
385 // has better performance.
386 AAudioStreamBuilder_setDataCallback(builder, DataCallback, this);
387 // Request that AAudio calls this functions if any error occurs on a callback
388 // thread.
389 AAudioStreamBuilder_setErrorCallback(builder, ErrorCallback, this);
390 }
391
OpenStream(AAudioStreamBuilder * builder)392 bool AAudioWrapper::OpenStream(AAudioStreamBuilder* builder) {
393 RTC_LOG(LS_INFO) << "OpenStream";
394 RTC_DCHECK(builder);
395 AAudioStream* stream = nullptr;
396 RETURN_ON_ERROR(AAudioStreamBuilder_openStream(builder, &stream), false);
397 stream_ = stream;
398 LogStreamConfiguration();
399 return true;
400 }
401
CloseStream()402 void AAudioWrapper::CloseStream() {
403 RTC_LOG(LS_INFO) << "CloseStream";
404 RTC_DCHECK(stream_);
405 LOG_ON_ERROR(AAudioStream_close(stream_));
406 stream_ = nullptr;
407 }
408
LogStreamConfiguration()409 void AAudioWrapper::LogStreamConfiguration() {
410 RTC_DCHECK(stream_);
411 char ss_buf[1024];
412 rtc::SimpleStringBuilder ss(ss_buf);
413 ss << "Stream Configuration: ";
414 ss << "sample rate=" << sample_rate() << ", channels=" << channel_count();
415 ss << ", samples per frame=" << samples_per_frame();
416 ss << ", format=" << FormatToString(format());
417 ss << ", sharing mode=" << SharingModeToString(sharing_mode());
418 ss << ", performance mode=" << PerformanceModeToString(performance_mode());
419 ss << ", direction=" << DirectionToString(direction());
420 ss << ", device id=" << AAudioStream_getDeviceId(stream_);
421 ss << ", frames per callback=" << frames_per_callback();
422 RTC_LOG(LS_INFO) << ss.str();
423 }
424
LogStreamState()425 void AAudioWrapper::LogStreamState() {
426 RTC_LOG(LS_INFO) << "AAudio stream state: "
427 << AAudio_convertStreamStateToText(stream_state());
428 }
429
VerifyStreamConfiguration()430 bool AAudioWrapper::VerifyStreamConfiguration() {
431 RTC_LOG(LS_INFO) << "VerifyStreamConfiguration";
432 RTC_DCHECK(stream_);
433 // TODO(henrika): should we verify device ID as well?
434 if (AAudioStream_getSampleRate(stream_) != audio_parameters().sample_rate()) {
435 RTC_LOG(LS_ERROR) << "Stream unable to use requested sample rate";
436 return false;
437 }
438 if (AAudioStream_getChannelCount(stream_) !=
439 static_cast<int32_t>(audio_parameters().channels())) {
440 RTC_LOG(LS_ERROR) << "Stream unable to use requested channel count";
441 return false;
442 }
443 if (AAudioStream_getFormat(stream_) != AAUDIO_FORMAT_PCM_I16) {
444 RTC_LOG(LS_ERROR) << "Stream unable to use requested format";
445 return false;
446 }
447 if (AAudioStream_getSharingMode(stream_) != AAUDIO_SHARING_MODE_SHARED) {
448 RTC_LOG(LS_ERROR) << "Stream unable to use requested sharing mode";
449 return false;
450 }
451 if (AAudioStream_getPerformanceMode(stream_) !=
452 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
453 RTC_LOG(LS_ERROR) << "Stream unable to use requested performance mode";
454 return false;
455 }
456 if (AAudioStream_getDirection(stream_) != direction()) {
457 RTC_LOG(LS_ERROR) << "Stream direction could not be set";
458 return false;
459 }
460 if (AAudioStream_getSamplesPerFrame(stream_) !=
461 static_cast<int32_t>(audio_parameters().channels())) {
462 RTC_LOG(LS_ERROR) << "Invalid number of samples per frame";
463 return false;
464 }
465 return true;
466 }
467
OptimizeBuffers()468 bool AAudioWrapper::OptimizeBuffers() {
469 RTC_LOG(LS_INFO) << "OptimizeBuffers";
470 RTC_DCHECK(stream_);
471 // Maximum number of frames that can be filled without blocking.
472 RTC_LOG(LS_INFO) << "max buffer capacity in frames: "
473 << buffer_capacity_in_frames();
474 // Query the number of frames that the application should read or write at
475 // one time for optimal performance.
476 int32_t frames_per_burst = AAudioStream_getFramesPerBurst(stream_);
477 RTC_LOG(LS_INFO) << "frames per burst for optimal performance: "
478 << frames_per_burst;
479 frames_per_burst_ = frames_per_burst;
480 if (direction() == AAUDIO_DIRECTION_INPUT) {
481 // There is no point in calling setBufferSizeInFrames() for input streams
482 // since it has no effect on the performance (latency in this case).
483 return true;
484 }
485 // Set buffer size to same as burst size to guarantee lowest possible latency.
486 // This size might change for output streams if underruns are detected and
487 // automatic buffer adjustment is enabled.
488 AAudioStream_setBufferSizeInFrames(stream_, frames_per_burst);
489 int32_t buffer_size = AAudioStream_getBufferSizeInFrames(stream_);
490 if (buffer_size != frames_per_burst) {
491 RTC_LOG(LS_ERROR) << "Failed to use optimal buffer burst size";
492 return false;
493 }
494 // Maximum number of frames that can be filled without blocking.
495 RTC_LOG(LS_INFO) << "buffer burst size in frames: " << buffer_size;
496 return true;
497 }
498
499 } // namespace jni
500
501 } // namespace webrtc
502