xref: /aosp_15_r20/external/oboe/src/aaudio/AudioStreamAAudio.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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