1 /*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cassert>
18 #include <stdint.h>
19 #include <stdlib.h>
20
21 #include "aaudio/AAudioLoader.h"
22 #include "aaudio/AudioStreamAAudio.h"
23 #include "common/AudioClock.h"
24 #include "common/OboeDebug.h"
25 #include "oboe/Utilities.h"
26 #include "AAudioExtensions.h"
27
28 #ifdef __ANDROID__
29 #include <sys/system_properties.h>
30 #include <common/QuirksManager.h>
31
32 #endif
33
34 #ifndef OBOE_FIX_FORCE_STARTING_TO_STARTED
35 // Workaround state problems in AAudio
36 // TODO Which versions does this occur in? Verify fixed in Q.
37 #define OBOE_FIX_FORCE_STARTING_TO_STARTED 1
38 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
39
40 using namespace oboe;
41 AAudioLoader *AudioStreamAAudio::mLibLoader = nullptr;
42
43 // 'C' wrapper for the data callback method
oboe_aaudio_data_callback_proc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)44 static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
45 AAudioStream *stream,
46 void *userData,
47 void *audioData,
48 int32_t numFrames) {
49
50 AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
51 if (oboeStream != nullptr) {
52 return static_cast<aaudio_data_callback_result_t>(
53 oboeStream->callOnAudioReady(stream, audioData, numFrames));
54
55 } else {
56 return static_cast<aaudio_data_callback_result_t>(DataCallbackResult::Stop);
57 }
58 }
59
60 // This runs in its own thread.
61 // Only one of these threads will be launched from internalErrorCallback().
62 // It calls app error callbacks from a static function in case the stream gets deleted.
oboe_aaudio_error_thread_proc(AudioStreamAAudio * oboeStream,Result error)63 static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream,
64 Result error) {
65 LOGD("%s(,%d) - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__, error);
66 AudioStreamErrorCallback *errorCallback = oboeStream->getErrorCallback();
67 if (errorCallback == nullptr) return; // should be impossible
68 bool isErrorHandled = errorCallback->onError(oboeStream, error);
69
70 if (!isErrorHandled) {
71 oboeStream->requestStop();
72 errorCallback->onErrorBeforeClose(oboeStream, error);
73 oboeStream->close();
74 // Warning, oboeStream may get deleted by this callback.
75 errorCallback->onErrorAfterClose(oboeStream, error);
76 }
77 LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__);
78 }
79
80 // This runs in its own thread.
81 // Only one of these threads will be launched from internalErrorCallback().
82 // Prevents deletion of the stream if the app is using AudioStreamBuilder::openSharedStream()
oboe_aaudio_error_thread_proc_shared(std::shared_ptr<AudioStream> sharedStream,Result error)83 static void oboe_aaudio_error_thread_proc_shared(std::shared_ptr<AudioStream> sharedStream,
84 Result error) {
85 AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get());
86 oboe_aaudio_error_thread_proc(oboeStream, error);
87 }
88
89 namespace oboe {
90
91 /*
92 * Create a stream that uses Oboe Audio API.
93 */
AudioStreamAAudio(const AudioStreamBuilder & builder)94 AudioStreamAAudio::AudioStreamAAudio(const AudioStreamBuilder &builder)
95 : AudioStream(builder)
96 , mAAudioStream(nullptr) {
97 mCallbackThreadEnabled.store(false);
98 mLibLoader = AAudioLoader::getInstance();
99 }
100
isSupported()101 bool AudioStreamAAudio::isSupported() {
102 mLibLoader = AAudioLoader::getInstance();
103 int openResult = mLibLoader->open();
104 return openResult == 0;
105 }
106
107 // Static method for the error callback.
108 // We use a method so we can access protected methods on the stream.
109 // Launch a thread to handle the error.
110 // That other thread can safely stop, close and delete the stream.
internalErrorCallback(AAudioStream * stream,void * userData,aaudio_result_t error)111 void AudioStreamAAudio::internalErrorCallback(
112 AAudioStream *stream,
113 void *userData,
114 aaudio_result_t error) {
115 oboe::Result oboeResult = static_cast<Result>(error);
116 AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
117
118 // Coerce the error code if needed to workaround a regression in RQ1A that caused
119 // the wrong code to be passed when headsets plugged in. See b/173928197.
120 if (OboeGlobals::areWorkaroundsEnabled()
121 && getSdkVersion() == __ANDROID_API_R__
122 && oboeResult == oboe::Result::ErrorTimeout) {
123 oboeResult = oboe::Result::ErrorDisconnected;
124 LOGD("%s() ErrorTimeout changed to ErrorDisconnected to fix b/173928197", __func__);
125 }
126
127 oboeStream->mErrorCallbackResult = oboeResult;
128
129 // Prevents deletion of the stream if the app is using AudioStreamBuilder::openStream(shared_ptr)
130 std::shared_ptr<AudioStream> sharedStream = oboeStream->lockWeakThis();
131
132 // These checks should be enough because we assume that the stream close()
133 // will join() any active callback threads and will not allow new callbacks.
134 if (oboeStream->wasErrorCallbackCalled()) { // block extra error callbacks
135 LOGE("%s() multiple error callbacks called!", __func__);
136 } else if (stream != oboeStream->getUnderlyingStream()) {
137 LOGW("%s() stream already closed or closing", __func__); // might happen if there are bugs
138 } else if (sharedStream) {
139 // Handle error on a separate thread using shared pointer.
140 std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream, oboeResult);
141 t.detach();
142 } else {
143 // Handle error on a separate thread.
144 std::thread t(oboe_aaudio_error_thread_proc, oboeStream, oboeResult);
145 t.detach();
146 }
147 }
148
beginPerformanceHintInCallback()149 void AudioStreamAAudio::beginPerformanceHintInCallback() {
150 if (isPerformanceHintEnabled()) {
151 if (!mAdpfOpenAttempted) {
152 int64_t targetDurationNanos = (mFramesPerBurst * 1e9) / getSampleRate();
153 // This has to be called from the callback thread so we get the right TID.
154 int adpfResult = mAdpfWrapper.open(gettid(), targetDurationNanos);
155 if (adpfResult < 0) {
156 LOGW("WARNING ADPF not supported, %d\n", adpfResult);
157 } else {
158 LOGD("ADPF is now active\n");
159 }
160 mAdpfOpenAttempted = true;
161 }
162 mAdpfWrapper.onBeginCallback();
163 } else if (!isPerformanceHintEnabled() && mAdpfOpenAttempted) {
164 LOGD("ADPF closed\n");
165 mAdpfWrapper.close();
166 mAdpfOpenAttempted = false;
167 }
168 }
169
endPerformanceHintInCallback(int32_t numFrames)170 void AudioStreamAAudio::endPerformanceHintInCallback(int32_t numFrames) {
171 if (mAdpfWrapper.isOpen()) {
172 // Scale the measured duration based on numFrames so it is normalized to a full burst.
173 double durationScaler = static_cast<double>(mFramesPerBurst) / numFrames;
174 // Skip this callback if numFrames is very small.
175 // This can happen when buffers wrap around, particularly when doing sample rate conversion.
176 if (durationScaler < 2.0) {
177 mAdpfWrapper.onEndCallback(durationScaler);
178 }
179 }
180 }
181
logUnsupportedAttributes()182 void AudioStreamAAudio::logUnsupportedAttributes() {
183 int sdkVersion = getSdkVersion();
184
185 // These attributes are not supported pre Android "P"
186 if (sdkVersion < __ANDROID_API_P__) {
187 if (mUsage != Usage::Media) {
188 LOGW("Usage [AudioStreamBuilder::setUsage()] "
189 "is not supported on AAudio streams running on pre-Android P versions.");
190 }
191
192 if (mContentType != ContentType::Music) {
193 LOGW("ContentType [AudioStreamBuilder::setContentType()] "
194 "is not supported on AAudio streams running on pre-Android P versions.");
195 }
196
197 if (mSessionId != SessionId::None) {
198 LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
199 "is not supported on AAudio streams running on pre-Android P versions.");
200 }
201 }
202 }
203
open()204 Result AudioStreamAAudio::open() {
205 Result result = Result::OK;
206
207 if (mAAudioStream != nullptr) {
208 return Result::ErrorInvalidState;
209 }
210
211 result = AudioStream::open();
212 if (result != Result::OK) {
213 return result;
214 }
215
216 AAudioStreamBuilder *aaudioBuilder;
217 result = static_cast<Result>(mLibLoader->createStreamBuilder(&aaudioBuilder));
218 if (result != Result::OK) {
219 return result;
220 }
221
222 // Do not set INPUT capacity below 4096 because that prevents us from getting a FAST track
223 // when using the Legacy data path.
224 // If the app requests > 4096 then we allow it but we are less likely to get LowLatency.
225 // See internal bug b/80308183 for more details.
226 // Fixed in Q but let's still clip the capacity because high input capacity
227 // does not increase latency.
228 int32_t capacity = mBufferCapacityInFrames;
229 constexpr int kCapacityRequiredForFastLegacyTrack = 4096; // matches value in AudioFinger
230 if (OboeGlobals::areWorkaroundsEnabled()
231 && mDirection == oboe::Direction::Input
232 && capacity != oboe::Unspecified
233 && capacity < kCapacityRequiredForFastLegacyTrack
234 && mPerformanceMode == oboe::PerformanceMode::LowLatency) {
235 capacity = kCapacityRequiredForFastLegacyTrack;
236 LOGD("AudioStreamAAudio.open() capacity changed from %d to %d for lower latency",
237 static_cast<int>(mBufferCapacityInFrames), capacity);
238 }
239 mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, capacity);
240
241 if (mLibLoader->builder_setSessionId != nullptr) {
242 mLibLoader->builder_setSessionId(aaudioBuilder,
243 static_cast<aaudio_session_id_t>(mSessionId));
244 // Output effects do not support PerformanceMode::LowLatency.
245 if (OboeGlobals::areWorkaroundsEnabled()
246 && mSessionId != SessionId::None
247 && mDirection == oboe::Direction::Output
248 && mPerformanceMode == PerformanceMode::LowLatency) {
249 mPerformanceMode = PerformanceMode::None;
250 LOGD("AudioStreamAAudio.open() performance mode changed to None when session "
251 "id is requested");
252 }
253 }
254
255 // Channel mask was added in SC_V2. Given the corresponding channel count of selected channel
256 // mask may be different from selected channel count, the last set value will be respected.
257 // If channel count is set after channel mask, the previously set channel mask will be cleared.
258 // If channel mask is set after channel count, the channel count will be automatically
259 // calculated from selected channel mask. In that case, only set channel mask when the API
260 // is available and the channel mask is specified.
261 if (mLibLoader->builder_setChannelMask != nullptr && mChannelMask != ChannelMask::Unspecified) {
262 mLibLoader->builder_setChannelMask(aaudioBuilder,
263 static_cast<aaudio_channel_mask_t>(mChannelMask));
264 } else {
265 mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
266 }
267 mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
268 mLibLoader->builder_setDirection(aaudioBuilder, static_cast<aaudio_direction_t>(mDirection));
269 mLibLoader->builder_setFormat(aaudioBuilder, static_cast<aaudio_format_t>(mFormat));
270 mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate);
271 mLibLoader->builder_setSharingMode(aaudioBuilder,
272 static_cast<aaudio_sharing_mode_t>(mSharingMode));
273 mLibLoader->builder_setPerformanceMode(aaudioBuilder,
274 static_cast<aaudio_performance_mode_t>(mPerformanceMode));
275
276 // These were added in P so we have to check for the function pointer.
277 if (mLibLoader->builder_setUsage != nullptr) {
278 mLibLoader->builder_setUsage(aaudioBuilder,
279 static_cast<aaudio_usage_t>(mUsage));
280 }
281
282 if (mLibLoader->builder_setContentType != nullptr) {
283 mLibLoader->builder_setContentType(aaudioBuilder,
284 static_cast<aaudio_content_type_t>(mContentType));
285 }
286
287 if (mLibLoader->builder_setInputPreset != nullptr) {
288 aaudio_input_preset_t inputPreset = mInputPreset;
289 if (getSdkVersion() <= __ANDROID_API_P__ && inputPreset == InputPreset::VoicePerformance) {
290 LOGD("InputPreset::VoicePerformance not supported before Q. Using VoiceRecognition.");
291 inputPreset = InputPreset::VoiceRecognition; // most similar preset
292 }
293 mLibLoader->builder_setInputPreset(aaudioBuilder,
294 static_cast<aaudio_input_preset_t>(inputPreset));
295 }
296
297 // These were added in S so we have to check for the function pointer.
298 if (mLibLoader->builder_setPackageName != nullptr && !mPackageName.empty()) {
299 mLibLoader->builder_setPackageName(aaudioBuilder,
300 mPackageName.c_str());
301 }
302
303 if (mLibLoader->builder_setAttributionTag != nullptr && !mAttributionTag.empty()) {
304 mLibLoader->builder_setAttributionTag(aaudioBuilder,
305 mAttributionTag.c_str());
306 }
307
308 // This was added in Q so we have to check for the function pointer.
309 if (mLibLoader->builder_setAllowedCapturePolicy != nullptr && mDirection == oboe::Direction::Output) {
310 mLibLoader->builder_setAllowedCapturePolicy(aaudioBuilder,
311 static_cast<aaudio_allowed_capture_policy_t>(mAllowedCapturePolicy));
312 }
313
314 if (mLibLoader->builder_setPrivacySensitive != nullptr && mDirection == oboe::Direction::Input
315 && mPrivacySensitiveMode != PrivacySensitiveMode::Unspecified) {
316 mLibLoader->builder_setPrivacySensitive(aaudioBuilder,
317 mPrivacySensitiveMode == PrivacySensitiveMode::Enabled);
318 }
319
320 if (mLibLoader->builder_setIsContentSpatialized != nullptr) {
321 mLibLoader->builder_setIsContentSpatialized(aaudioBuilder, mIsContentSpatialized);
322 }
323
324 if (mLibLoader->builder_setSpatializationBehavior != nullptr) {
325 // Override Unspecified as Never to reduce latency.
326 if (mSpatializationBehavior == SpatializationBehavior::Unspecified) {
327 mSpatializationBehavior = SpatializationBehavior::Never;
328 }
329 mLibLoader->builder_setSpatializationBehavior(aaudioBuilder,
330 static_cast<aaudio_spatialization_behavior_t>(mSpatializationBehavior));
331 } else {
332 mSpatializationBehavior = SpatializationBehavior::Never;
333 }
334
335 if (isDataCallbackSpecified()) {
336 mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
337 mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerDataCallback());
338
339 if (!isErrorCallbackSpecified()) {
340 // The app did not specify a callback so we should specify
341 // our own so the stream gets closed and stopped.
342 mErrorCallback = &mDefaultErrorCallback;
343 }
344 mLibLoader->builder_setErrorCallback(aaudioBuilder, internalErrorCallback, this);
345 }
346 // Else if the data callback is not being used then the write method will return an error
347 // and the app can stop and close the stream.
348
349 // ============= OPEN THE STREAM ================
350 {
351 AAudioStream *stream = nullptr;
352 result = static_cast<Result>(mLibLoader->builder_openStream(aaudioBuilder, &stream));
353 mAAudioStream.store(stream);
354 }
355 if (result != Result::OK) {
356 // Warn developer because ErrorInternal is not very informative.
357 if (result == Result::ErrorInternal && mDirection == Direction::Input) {
358 LOGW("AudioStreamAAudio.open() may have failed due to lack of "
359 "audio recording permission.");
360 }
361 goto error2;
362 }
363
364 // Query and cache the stream properties
365 mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream);
366 mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream);
367 mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream);
368 mFormat = static_cast<AudioFormat>(mLibLoader->stream_getFormat(mAAudioStream));
369 mSharingMode = static_cast<SharingMode>(mLibLoader->stream_getSharingMode(mAAudioStream));
370 mPerformanceMode = static_cast<PerformanceMode>(
371 mLibLoader->stream_getPerformanceMode(mAAudioStream));
372 mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
373 mBufferSizeInFrames = mLibLoader->stream_getBufferSize(mAAudioStream);
374 mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(mAAudioStream);
375
376 // These were added in P so we have to check for the function pointer.
377 if (mLibLoader->stream_getUsage != nullptr) {
378 mUsage = static_cast<Usage>(mLibLoader->stream_getUsage(mAAudioStream));
379 }
380 if (mLibLoader->stream_getContentType != nullptr) {
381 mContentType = static_cast<ContentType>(mLibLoader->stream_getContentType(mAAudioStream));
382 }
383 if (mLibLoader->stream_getInputPreset != nullptr) {
384 mInputPreset = static_cast<InputPreset>(mLibLoader->stream_getInputPreset(mAAudioStream));
385 }
386 if (mLibLoader->stream_getSessionId != nullptr) {
387 mSessionId = static_cast<SessionId>(mLibLoader->stream_getSessionId(mAAudioStream));
388 } else {
389 mSessionId = SessionId::None;
390 }
391
392 // This was added in Q so we have to check for the function pointer.
393 if (mLibLoader->stream_getAllowedCapturePolicy != nullptr && mDirection == oboe::Direction::Output) {
394 mAllowedCapturePolicy = static_cast<AllowedCapturePolicy>(mLibLoader->stream_getAllowedCapturePolicy(mAAudioStream));
395 } else {
396 mAllowedCapturePolicy = AllowedCapturePolicy::Unspecified;
397 }
398
399 if (mLibLoader->stream_isPrivacySensitive != nullptr && mDirection == oboe::Direction::Input) {
400 bool isPrivacySensitive = mLibLoader->stream_isPrivacySensitive(mAAudioStream);
401 mPrivacySensitiveMode = isPrivacySensitive ? PrivacySensitiveMode::Enabled :
402 PrivacySensitiveMode::Disabled;
403 } else {
404 mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
405 }
406
407 if (mLibLoader->stream_getChannelMask != nullptr) {
408 mChannelMask = static_cast<ChannelMask>(mLibLoader->stream_getChannelMask(mAAudioStream));
409 }
410
411 if (mLibLoader->stream_isContentSpatialized != nullptr) {
412 mIsContentSpatialized = mLibLoader->stream_isContentSpatialized(mAAudioStream);
413 }
414
415 if (mLibLoader->stream_getSpatializationBehavior != nullptr) {
416 mSpatializationBehavior = static_cast<SpatializationBehavior>(
417 mLibLoader->stream_getSpatializationBehavior(mAAudioStream));
418 }
419
420 if (mLibLoader->stream_getHardwareChannelCount != nullptr) {
421 mHardwareChannelCount = mLibLoader->stream_getHardwareChannelCount(mAAudioStream);
422 }
423 if (mLibLoader->stream_getHardwareSampleRate != nullptr) {
424 mHardwareSampleRate = mLibLoader->stream_getHardwareSampleRate(mAAudioStream);
425 }
426 if (mLibLoader->stream_getHardwareFormat != nullptr) {
427 mHardwareFormat = static_cast<AudioFormat>(mLibLoader->stream_getHardwareFormat(mAAudioStream));
428 }
429
430 LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d",
431 static_cast<int>(mFormat), static_cast<int>(mSampleRate),
432 static_cast<int>(mBufferCapacityInFrames));
433
434 calculateDefaultDelayBeforeCloseMillis();
435
436 error2:
437 mLibLoader->builder_delete(aaudioBuilder);
438 if (static_cast<int>(result) > 0) {
439 // Possibly due to b/267531411
440 LOGW("AudioStreamAAudio.open: AAudioStream_Open() returned positive error = %d",
441 static_cast<int>(result));
442 if (OboeGlobals::areWorkaroundsEnabled()) {
443 result = Result::ErrorInternal; // Coerce to negative error.
444 }
445 } else {
446 LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s = %d",
447 mLibLoader->convertResultToText(static_cast<aaudio_result_t>(result)),
448 static_cast<int>(result));
449 }
450 return result;
451 }
452
release()453 Result AudioStreamAAudio::release() {
454 if (getSdkVersion() < __ANDROID_API_R__) {
455 return Result::ErrorUnimplemented;
456 }
457
458 // AAudioStream_release() is buggy on Android R.
459 if (OboeGlobals::areWorkaroundsEnabled() && getSdkVersion() == __ANDROID_API_R__) {
460 LOGW("Skipping release() on Android R");
461 return Result::ErrorUnimplemented;
462 }
463
464 std::lock_guard<std::mutex> lock(mLock);
465 AAudioStream *stream = mAAudioStream.load();
466 if (stream != nullptr) {
467 if (OboeGlobals::areWorkaroundsEnabled()) {
468 // Make sure we are really stopped. Do it under mLock
469 // so another thread cannot call requestStart() right before the close.
470 requestStop_l(stream);
471 }
472 return static_cast<Result>(mLibLoader->stream_release(stream));
473 } else {
474 return Result::ErrorClosed;
475 }
476 }
477
close()478 Result AudioStreamAAudio::close() {
479 // Prevent two threads from closing the stream at the same time and crashing.
480 // This could occur, for example, if an application called close() at the same
481 // time that an onError callback was being executed because of a disconnect.
482 std::lock_guard<std::mutex> lock(mLock);
483
484 AudioStream::close();
485
486 AAudioStream *stream = nullptr;
487 {
488 // Wait for any methods using mAAudioStream to finish.
489 std::unique_lock<std::shared_mutex> lock2(mAAudioStreamLock);
490 // Closing will delete *mAAudioStream so we need to null out the pointer atomically.
491 stream = mAAudioStream.exchange(nullptr);
492 }
493 if (stream != nullptr) {
494 if (OboeGlobals::areWorkaroundsEnabled()) {
495 // Make sure we are really stopped. Do it under mLock
496 // so another thread cannot call requestStart() right before the close.
497 requestStop_l(stream);
498 sleepBeforeClose();
499 }
500 return static_cast<Result>(mLibLoader->stream_close(stream));
501 } else {
502 return Result::ErrorClosed;
503 }
504 }
505
oboe_stop_thread_proc(AudioStream * oboeStream)506 static void oboe_stop_thread_proc(AudioStream *oboeStream) {
507 if (oboeStream != nullptr) {
508 oboeStream->requestStop();
509 }
510 }
511
launchStopThread()512 void AudioStreamAAudio::launchStopThread() {
513 // Prevent multiple stop threads from being launched.
514 if (mStopThreadAllowed.exchange(false)) {
515 // Stop this stream on a separate thread
516 std::thread t(oboe_stop_thread_proc, this);
517 t.detach();
518 }
519 }
520
callOnAudioReady(AAudioStream *,void * audioData,int32_t numFrames)521 DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream * /*stream*/,
522 void *audioData,
523 int32_t numFrames) {
524 DataCallbackResult result = fireDataCallback(audioData, numFrames);
525 if (result == DataCallbackResult::Continue) {
526 return result;
527 } else {
528 if (result == DataCallbackResult::Stop) {
529 LOGD("Oboe callback returned DataCallbackResult::Stop");
530 } else {
531 LOGE("Oboe callback returned unexpected value. Error: %d", static_cast<int>(result));
532 }
533
534 // Returning Stop caused various problems before S. See #1230
535 if (OboeGlobals::areWorkaroundsEnabled() && getSdkVersion() <= __ANDROID_API_R__) {
536 launchStopThread();
537 return DataCallbackResult::Continue;
538 } else {
539 return DataCallbackResult::Stop; // OK >= API_S
540 }
541 }
542 }
543
requestStart()544 Result AudioStreamAAudio::requestStart() {
545 std::lock_guard<std::mutex> lock(mLock);
546 AAudioStream *stream = mAAudioStream.load();
547 if (stream != nullptr) {
548 // Avoid state machine errors in O_MR1.
549 if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
550 StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
551 if (state == StreamState::Starting || state == StreamState::Started) {
552 // WARNING: On P, AAudio is returning ErrorInvalidState for Output and OK for Input.
553 return Result::OK;
554 }
555 }
556 if (isDataCallbackSpecified()) {
557 setDataCallbackEnabled(true);
558 }
559 mStopThreadAllowed = true;
560 closePerformanceHint();
561 return static_cast<Result>(mLibLoader->stream_requestStart(stream));
562 } else {
563 return Result::ErrorClosed;
564 }
565 }
566
requestPause()567 Result AudioStreamAAudio::requestPause() {
568 std::lock_guard<std::mutex> lock(mLock);
569 AAudioStream *stream = mAAudioStream.load();
570 if (stream != nullptr) {
571 // Avoid state machine errors in O_MR1.
572 if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
573 StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
574 if (state == StreamState::Pausing || state == StreamState::Paused) {
575 return Result::OK;
576 }
577 }
578 return static_cast<Result>(mLibLoader->stream_requestPause(stream));
579 } else {
580 return Result::ErrorClosed;
581 }
582 }
583
requestFlush()584 Result AudioStreamAAudio::requestFlush() {
585 std::lock_guard<std::mutex> lock(mLock);
586 AAudioStream *stream = mAAudioStream.load();
587 if (stream != nullptr) {
588 // Avoid state machine errors in O_MR1.
589 if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
590 StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
591 if (state == StreamState::Flushing || state == StreamState::Flushed) {
592 return Result::OK;
593 }
594 }
595 return static_cast<Result>(mLibLoader->stream_requestFlush(stream));
596 } else {
597 return Result::ErrorClosed;
598 }
599 }
600
requestStop()601 Result AudioStreamAAudio::requestStop() {
602 std::lock_guard<std::mutex> lock(mLock);
603 AAudioStream *stream = mAAudioStream.load();
604 if (stream != nullptr) {
605 return requestStop_l(stream);
606 } else {
607 return Result::ErrorClosed;
608 }
609 }
610
611 // Call under mLock
requestStop_l(AAudioStream * stream)612 Result AudioStreamAAudio::requestStop_l(AAudioStream *stream) {
613 // Avoid state machine errors in O_MR1.
614 if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
615 StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
616 if (state == StreamState::Stopping || state == StreamState::Stopped) {
617 return Result::OK;
618 }
619 }
620 return static_cast<Result>(mLibLoader->stream_requestStop(stream));
621 }
622
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)623 ResultWithValue<int32_t> AudioStreamAAudio::write(const void *buffer,
624 int32_t numFrames,
625 int64_t timeoutNanoseconds) {
626 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
627 AAudioStream *stream = mAAudioStream.load();
628 if (stream != nullptr) {
629 int32_t result = mLibLoader->stream_write(mAAudioStream, buffer,
630 numFrames, timeoutNanoseconds);
631 return ResultWithValue<int32_t>::createBasedOnSign(result);
632 } else {
633 return ResultWithValue<int32_t>(Result::ErrorClosed);
634 }
635 }
636
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)637 ResultWithValue<int32_t> AudioStreamAAudio::read(void *buffer,
638 int32_t numFrames,
639 int64_t timeoutNanoseconds) {
640 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
641 AAudioStream *stream = mAAudioStream.load();
642 if (stream != nullptr) {
643 int32_t result = mLibLoader->stream_read(mAAudioStream, buffer,
644 numFrames, timeoutNanoseconds);
645 return ResultWithValue<int32_t>::createBasedOnSign(result);
646 } else {
647 return ResultWithValue<int32_t>(Result::ErrorClosed);
648 }
649 }
650
651
652 // AAudioStream_waitForStateChange() can crash if it is waiting on a stream and that stream
653 // is closed from another thread. We do not want to lock the stream for the duration of the call.
654 // So we call AAudioStream_waitForStateChange() with a timeout of zero so that it will not block.
655 // Then we can do our own sleep with the lock unlocked.
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)656 Result AudioStreamAAudio::waitForStateChange(StreamState currentState,
657 StreamState *nextState,
658 int64_t timeoutNanoseconds) {
659 Result oboeResult = Result::ErrorTimeout;
660 int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
661 aaudio_stream_state_t currentAAudioState = static_cast<aaudio_stream_state_t>(currentState);
662
663 aaudio_result_t result = AAUDIO_OK;
664 int64_t timeLeftNanos = timeoutNanoseconds;
665
666 mLock.lock();
667 while (true) {
668 // Do we still have an AAudio stream? If not then stream must have been closed.
669 AAudioStream *stream = mAAudioStream.load();
670 if (stream == nullptr) {
671 if (nextState != nullptr) {
672 *nextState = StreamState::Closed;
673 }
674 oboeResult = Result::ErrorClosed;
675 break;
676 }
677
678 // Update and query state change with no blocking.
679 aaudio_stream_state_t aaudioNextState;
680 result = mLibLoader->stream_waitForStateChange(
681 mAAudioStream,
682 currentAAudioState,
683 &aaudioNextState,
684 0); // timeout=0 for non-blocking
685 // AAudio will return AAUDIO_ERROR_TIMEOUT if timeout=0 and the state does not change.
686 if (result != AAUDIO_OK && result != AAUDIO_ERROR_TIMEOUT) {
687 oboeResult = static_cast<Result>(result);
688 break;
689 }
690 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
691 if (OboeGlobals::areWorkaroundsEnabled()
692 && aaudioNextState == static_cast<aaudio_stream_state_t >(StreamState::Starting)) {
693 aaudioNextState = static_cast<aaudio_stream_state_t >(StreamState::Started);
694 }
695 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
696 if (nextState != nullptr) {
697 *nextState = static_cast<StreamState>(aaudioNextState);
698 }
699 if (currentAAudioState != aaudioNextState) { // state changed?
700 oboeResult = Result::OK;
701 break;
702 }
703
704 // Did we timeout or did user ask for non-blocking?
705 if (timeLeftNanos <= 0) {
706 break;
707 }
708
709 // No change yet so sleep.
710 mLock.unlock(); // Don't sleep while locked.
711 if (sleepTimeNanos > timeLeftNanos) {
712 sleepTimeNanos = timeLeftNanos; // last little bit
713 }
714 AudioClock::sleepForNanos(sleepTimeNanos);
715 timeLeftNanos -= sleepTimeNanos;
716 mLock.lock();
717 }
718
719 mLock.unlock();
720 return oboeResult;
721 }
722
setBufferSizeInFrames(int32_t requestedFrames)723 ResultWithValue<int32_t> AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) {
724 int32_t adjustedFrames = requestedFrames;
725 if (adjustedFrames > mBufferCapacityInFrames) {
726 adjustedFrames = mBufferCapacityInFrames;
727 }
728 // This calls getBufferSize() so avoid recursive lock.
729 adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames);
730
731 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
732 AAudioStream *stream = mAAudioStream.load();
733 if (stream != nullptr) {
734 int32_t newBufferSize = mLibLoader->stream_setBufferSize(mAAudioStream, adjustedFrames);
735 // Cache the result if it's valid
736 if (newBufferSize > 0) mBufferSizeInFrames = newBufferSize;
737 return ResultWithValue<int32_t>::createBasedOnSign(newBufferSize);
738 } else {
739 return ResultWithValue<int32_t>(Result::ErrorClosed);
740 }
741 }
742
getState()743 StreamState AudioStreamAAudio::getState() {
744 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
745 AAudioStream *stream = mAAudioStream.load();
746 if (stream != nullptr) {
747 aaudio_stream_state_t aaudioState = mLibLoader->stream_getState(stream);
748 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
749 if (OboeGlobals::areWorkaroundsEnabled()
750 && aaudioState == AAUDIO_STREAM_STATE_STARTING) {
751 aaudioState = AAUDIO_STREAM_STATE_STARTED;
752 }
753 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
754 return static_cast<StreamState>(aaudioState);
755 } else {
756 return StreamState::Closed;
757 }
758 }
759
getBufferSizeInFrames()760 int32_t AudioStreamAAudio::getBufferSizeInFrames() {
761 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
762 AAudioStream *stream = mAAudioStream.load();
763 if (stream != nullptr) {
764 mBufferSizeInFrames = mLibLoader->stream_getBufferSize(stream);
765 }
766 return mBufferSizeInFrames;
767 }
768
updateFramesRead()769 void AudioStreamAAudio::updateFramesRead() {
770 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
771 AAudioStream *stream = mAAudioStream.load();
772 // Set to 1 for debugging race condition #1180 with mAAudioStream.
773 // See also DEBUG_CLOSE_RACE in OboeTester.
774 // This was left in the code so that we could test the fix again easily in the future.
775 // We could not trigger the race condition without adding these get calls and the sleeps.
776 #define DEBUG_CLOSE_RACE 0
777 #if DEBUG_CLOSE_RACE
778 // This is used when testing race conditions with close().
779 // See DEBUG_CLOSE_RACE in OboeTester
780 AudioClock::sleepForNanos(400 * kNanosPerMillisecond);
781 #endif // DEBUG_CLOSE_RACE
782 if (stream != nullptr) {
783 mFramesRead = mLibLoader->stream_getFramesRead(stream);
784 }
785 }
786
updateFramesWritten()787 void AudioStreamAAudio::updateFramesWritten() {
788 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
789 AAudioStream *stream = mAAudioStream.load();
790 if (stream != nullptr) {
791 mFramesWritten = mLibLoader->stream_getFramesWritten(stream);
792 }
793 }
794
getXRunCount()795 ResultWithValue<int32_t> AudioStreamAAudio::getXRunCount() {
796 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
797 AAudioStream *stream = mAAudioStream.load();
798 if (stream != nullptr) {
799 return ResultWithValue<int32_t>::createBasedOnSign(mLibLoader->stream_getXRunCount(stream));
800 } else {
801 return ResultWithValue<int32_t>(Result::ErrorNull);
802 }
803 }
804
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)805 Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
806 int64_t *framePosition,
807 int64_t *timeNanoseconds) {
808 if (getState() != StreamState::Started) {
809 return Result::ErrorInvalidState;
810 }
811 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
812 AAudioStream *stream = mAAudioStream.load();
813 if (stream != nullptr) {
814 return static_cast<Result>(mLibLoader->stream_getTimestamp(stream, clockId,
815 framePosition, timeNanoseconds));
816 } else {
817 return Result::ErrorNull;
818 }
819 }
820
calculateLatencyMillis()821 ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
822 // Get the time that a known audio frame was presented.
823 int64_t hardwareFrameIndex;
824 int64_t hardwareFrameHardwareTime;
825 auto result = getTimestamp(CLOCK_MONOTONIC,
826 &hardwareFrameIndex,
827 &hardwareFrameHardwareTime);
828 if (result != oboe::Result::OK) {
829 return ResultWithValue<double>(static_cast<Result>(result));
830 }
831
832 // Get counter closest to the app.
833 bool isOutput = (getDirection() == oboe::Direction::Output);
834 int64_t appFrameIndex = isOutput ? getFramesWritten() : getFramesRead();
835
836 // Assume that the next frame will be processed at the current time
837 using namespace std::chrono;
838 int64_t appFrameAppTime =
839 duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();
840
841 // Calculate the number of frames between app and hardware
842 int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex;
843
844 // Calculate the time which the next frame will be or was presented
845 int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / getSampleRate();
846 int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta;
847
848 // The current latency is the difference in time between when the current frame is at
849 // the app and when it is at the hardware.
850 double latencyNanos = static_cast<double>(isOutput
851 ? (appFrameHardwareTime - appFrameAppTime) // hardware is later
852 : (appFrameAppTime - appFrameHardwareTime)); // hardware is earlier
853 double latencyMillis = latencyNanos / kNanosPerMillisecond;
854
855 return ResultWithValue<double>(latencyMillis);
856 }
857
isMMapUsed()858 bool AudioStreamAAudio::isMMapUsed() {
859 std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
860 AAudioStream *stream = mAAudioStream.load();
861 if (stream != nullptr) {
862 return AAudioExtensions::getInstance().isMMapUsed(stream);
863 } else {
864 return false;
865 }
866 }
867
868 } // namespace oboe
869