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