• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 #ifdef __ANDROID__
28 #include <sys/system_properties.h>
29 #include <common/QuirksManager.h>
30 
31 #endif
32 
33 #ifndef OBOE_FIX_FORCE_STARTING_TO_STARTED
34 // Workaround state problems in AAudio
35 // TODO Which versions does this occur in? Verify fixed in Q.
36 #define OBOE_FIX_FORCE_STARTING_TO_STARTED 1
37 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
38 
39 using namespace oboe;
40 AAudioLoader *AudioStreamAAudio::mLibLoader = nullptr;
41 
42 // 'C' wrapper for the data callback method
oboe_aaudio_data_callback_proc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)43 static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
44         AAudioStream *stream,
45         void *userData,
46         void *audioData,
47         int32_t numFrames) {
48 
49     AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
50     if (oboeStream != nullptr) {
51         return static_cast<aaudio_data_callback_result_t>(
52                 oboeStream->callOnAudioReady(stream, audioData, numFrames));
53 
54     } else {
55         return static_cast<aaudio_data_callback_result_t>(DataCallbackResult::Stop);
56     }
57 }
58 
59 // This runs in its own thread.
60 // Only one of these threads will be launched from internalErrorCallback().
61 // It calls app error callbacks from a static function in case the stream gets deleted.
oboe_aaudio_error_thread_proc(AudioStreamAAudio * oboeStream,Result error)62 static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream,
63                                           Result error) {
64     LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__);
65     oboeStream->requestStop();
66     if (oboeStream->getCallback() != nullptr) {
67         oboeStream->getCallback()->onErrorBeforeClose(oboeStream, error);
68     }
69     oboeStream->close();
70     if (oboeStream->getCallback() != nullptr) {
71         // Warning, oboeStream may get deleted by this callback.
72         oboeStream->getCallback()->onErrorAfterClose(oboeStream, error);
73     }
74     LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__);
75 }
76 
77 // This runs in its own thread.
78 // Only one of these threads will be launched from internalErrorCallback().
79 // 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)80 static void oboe_aaudio_error_thread_proc_shared(std::shared_ptr<AudioStream> sharedStream,
81                                           Result error) {
82     AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get());
83     oboe_aaudio_error_thread_proc(oboeStream, error);
84 }
85 
86 namespace oboe {
87 
88 /*
89  * Create a stream that uses Oboe Audio API.
90  */
AudioStreamAAudio(const AudioStreamBuilder & builder)91 AudioStreamAAudio::AudioStreamAAudio(const AudioStreamBuilder &builder)
92     : AudioStream(builder)
93     , mAAudioStream(nullptr) {
94     mCallbackThreadEnabled.store(false);
95     isSupported();
96 }
97 
isSupported()98 bool AudioStreamAAudio::isSupported() {
99     mLibLoader = AAudioLoader::getInstance();
100     int openResult = mLibLoader->open();
101     return openResult == 0;
102 }
103 
104 // Static 'C' wrapper for the error callback method.
105 // Launch a thread to handle the error.
106 // That other thread can safely stop, close and delete the stream.
internalErrorCallback(AAudioStream * stream,void * userData,aaudio_result_t error)107 void AudioStreamAAudio::internalErrorCallback(
108         AAudioStream *stream,
109         void *userData,
110         aaudio_result_t error) {
111     AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
112 
113     // Prevents deletion of the stream if the app is using AudioStreamBuilder::openStream(shared_ptr)
114     std::shared_ptr<AudioStream> sharedStream = oboeStream->lockWeakThis();
115 
116     // These checks should be enough because we assume that the stream close()
117     // will join() any active callback threads and will not allow new callbacks.
118     if (oboeStream->wasErrorCallbackCalled()) { // block extra error callbacks
119         LOGE("%s() multiple error callbacks called!", __func__);
120     } else if (stream != oboeStream->getUnderlyingStream()) {
121         LOGW("%s() stream already closed or closing", __func__); // can happen if there are bugs
122     } else if (sharedStream) {
123         // Handle error on a separate thread using shared pointer.
124         std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream,
125                       static_cast<Result>(error));
126         t.detach();
127     } else {
128         // Handle error on a separate thread.
129         std::thread t(oboe_aaudio_error_thread_proc, oboeStream,
130                       static_cast<Result>(error));
131         t.detach();
132     }
133 }
134 
logUnsupportedAttributes()135 void AudioStreamAAudio::logUnsupportedAttributes() {
136     int sdkVersion = getSdkVersion();
137 
138     // These attributes are not supported pre Android "P"
139     if (sdkVersion < __ANDROID_API_P__) {
140         if (mUsage != Usage::Media) {
141             LOGW("Usage [AudioStreamBuilder::setUsage()] "
142                  "is not supported on AAudio streams running on pre-Android P versions.");
143         }
144 
145         if (mContentType != ContentType::Music) {
146             LOGW("ContentType [AudioStreamBuilder::setContentType()] "
147                  "is not supported on AAudio streams running on pre-Android P versions.");
148         }
149 
150         if (mSessionId != SessionId::None) {
151             LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
152                  "is not supported on AAudio streams running on pre-Android P versions.");
153         }
154     }
155 }
156 
open()157 Result AudioStreamAAudio::open() {
158     Result result = Result::OK;
159 
160     if (mAAudioStream != nullptr) {
161         return Result::ErrorInvalidState;
162     }
163 
164     result = AudioStream::open();
165     if (result != Result::OK) {
166         return result;
167     }
168 
169     AAudioStreamBuilder *aaudioBuilder;
170     result = static_cast<Result>(mLibLoader->createStreamBuilder(&aaudioBuilder));
171     if (result != Result::OK) {
172         return result;
173     }
174 
175     // Do not set INPUT capacity below 4096 because that prevents us from getting a FAST track
176     // when using the Legacy data path.
177     // If the app requests > 4096 then we allow it but we are less likely to get LowLatency.
178     // See internal bug b/80308183 for more details.
179     // Fixed in Q but let's still clip the capacity because high input capacity
180     // does not increase latency.
181     int32_t capacity = mBufferCapacityInFrames;
182     constexpr int kCapacityRequiredForFastLegacyTrack = 4096; // matches value in AudioFinger
183     if (OboeGlobals::areWorkaroundsEnabled()
184             && mDirection == oboe::Direction::Input
185             && capacity != oboe::Unspecified
186             && capacity < kCapacityRequiredForFastLegacyTrack
187             && mPerformanceMode == oboe::PerformanceMode::LowLatency) {
188         capacity = kCapacityRequiredForFastLegacyTrack;
189         LOGD("AudioStreamAAudio.open() capacity changed from %d to %d for lower latency",
190              static_cast<int>(mBufferCapacityInFrames), capacity);
191     }
192     mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, capacity);
193 
194     mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
195     mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
196     mLibLoader->builder_setDirection(aaudioBuilder, static_cast<aaudio_direction_t>(mDirection));
197     mLibLoader->builder_setFormat(aaudioBuilder, static_cast<aaudio_format_t>(mFormat));
198     mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate);
199     mLibLoader->builder_setSharingMode(aaudioBuilder,
200                                        static_cast<aaudio_sharing_mode_t>(mSharingMode));
201     mLibLoader->builder_setPerformanceMode(aaudioBuilder,
202                                            static_cast<aaudio_performance_mode_t>(mPerformanceMode));
203 
204     // These were added in P so we have to check for the function pointer.
205     if (mLibLoader->builder_setUsage != nullptr) {
206         mLibLoader->builder_setUsage(aaudioBuilder,
207                                      static_cast<aaudio_usage_t>(mUsage));
208     }
209 
210     if (mLibLoader->builder_setContentType != nullptr) {
211         mLibLoader->builder_setContentType(aaudioBuilder,
212                                            static_cast<aaudio_content_type_t>(mContentType));
213     }
214 
215     if (mLibLoader->builder_setInputPreset != nullptr) {
216         mLibLoader->builder_setInputPreset(aaudioBuilder,
217                                            static_cast<aaudio_input_preset_t>(mInputPreset));
218     }
219 
220     if (mLibLoader->builder_setSessionId != nullptr) {
221         mLibLoader->builder_setSessionId(aaudioBuilder,
222                                          static_cast<aaudio_session_id_t>(mSessionId));
223     }
224 
225     // TODO get more parameters from the builder?
226 
227     if (mStreamCallback != nullptr) {
228         mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
229         mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerCallback());
230         // If the data callback is not being used then the write method will return an error
231         // and the app can stop and close the stream.
232         mLibLoader->builder_setErrorCallback(aaudioBuilder, internalErrorCallback, this);
233     }
234 
235     // ============= OPEN THE STREAM ================
236     {
237         AAudioStream *stream = nullptr;
238         result = static_cast<Result>(mLibLoader->builder_openStream(aaudioBuilder, &stream));
239         mAAudioStream.store(stream);
240     }
241     if (result != Result::OK) {
242         // Warn developer because ErrorInternal is not very informative.
243         if (result == Result::ErrorInternal && mDirection == Direction::Input) {
244             LOGW("AudioStreamAAudio.open() may have failed due to lack of "
245                  "audio recording permission.");
246         }
247         goto error2;
248     }
249 
250     // Query and cache the stream properties
251     mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream);
252     mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream);
253     mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream);
254     mFormat = static_cast<AudioFormat>(mLibLoader->stream_getFormat(mAAudioStream));
255     mSharingMode = static_cast<SharingMode>(mLibLoader->stream_getSharingMode(mAAudioStream));
256     mPerformanceMode = static_cast<PerformanceMode>(
257             mLibLoader->stream_getPerformanceMode(mAAudioStream));
258     mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
259     mBufferSizeInFrames = mLibLoader->stream_getBufferSize(mAAudioStream);
260 
261     // These were added in P so we have to check for the function pointer.
262     if (mLibLoader->stream_getUsage != nullptr) {
263         mUsage = static_cast<Usage>(mLibLoader->stream_getUsage(mAAudioStream));
264     }
265     if (mLibLoader->stream_getContentType != nullptr) {
266         mContentType = static_cast<ContentType>(mLibLoader->stream_getContentType(mAAudioStream));
267     }
268     if (mLibLoader->stream_getInputPreset != nullptr) {
269         mInputPreset = static_cast<InputPreset>(mLibLoader->stream_getInputPreset(mAAudioStream));
270     }
271     if (mLibLoader->stream_getSessionId != nullptr) {
272         mSessionId = static_cast<SessionId>(mLibLoader->stream_getSessionId(mAAudioStream));
273     } else {
274         mSessionId = SessionId::None;
275     }
276 
277     LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d",
278             static_cast<int>(mFormat), static_cast<int>(mSampleRate),
279             static_cast<int>(mBufferCapacityInFrames));
280 
281 error2:
282     mLibLoader->builder_delete(aaudioBuilder);
283     LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s",
284          mLibLoader->convertResultToText(static_cast<aaudio_result_t>(result)));
285     return result;
286 }
287 
close()288 Result AudioStreamAAudio::close() {
289     // Prevent two threads from closing the stream at the same time and crashing.
290     // This could occur, for example, if an application called close() at the same
291     // time that an onError callback was being executed because of a disconnect.
292     std::lock_guard<std::mutex> lock(mLock);
293 
294     AudioStream::close();
295 
296     // This will delete the AAudio stream object so we need to null out the pointer.
297     AAudioStream *stream = mAAudioStream.exchange(nullptr);
298     if (stream != nullptr) {
299         if (OboeGlobals::areWorkaroundsEnabled()) {
300             // Make sure we are really stopped. Do it under mLock
301             // so another thread cannot call requestStart() right before the close.
302             requestStop_l(stream);
303             // Sometimes a callback can occur shortly after a stream has been stopped and
304             // even after a close! If the stream has been closed then the callback
305             // can access memory that has been freed. That causes a crash.
306             // This seems to be more likely in Android P or earlier.
307             // But it can also occur in later versions.
308             usleep(kDelayBeforeCloseMillis * 1000);
309         }
310         return static_cast<Result>(mLibLoader->stream_close(stream));
311     } else {
312         return Result::ErrorClosed;
313     }
314 }
315 
callOnAudioReady(AAudioStream * stream,void * audioData,int32_t numFrames)316 DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream,
317                                                                  void *audioData,
318                                                                  int32_t numFrames) {
319     DataCallbackResult result = fireDataCallback(audioData, numFrames);
320     if (result == DataCallbackResult::Continue) {
321         return result;
322     } else {
323         if (result == DataCallbackResult::Stop) {
324             LOGD("Oboe callback returned DataCallbackResult::Stop");
325         } else {
326             LOGE("Oboe callback returned unexpected value = %d", result);
327         }
328 
329         if (getSdkVersion() <= __ANDROID_API_P__) {
330             launchStopThread();
331             if (isMMapUsed()) {
332                 return DataCallbackResult::Stop;
333             } else {
334                 // Legacy stream <= API_P cannot be restarted after returning Stop.
335                 return DataCallbackResult::Continue;
336             }
337         } else {
338             return DataCallbackResult::Stop; // OK >= API_Q
339         }
340     }
341 }
342 
requestStart()343 Result AudioStreamAAudio::requestStart() {
344     std::lock_guard<std::mutex> lock(mLock);
345     AAudioStream *stream = mAAudioStream.load();
346     if (stream != nullptr) {
347         // Avoid state machine errors in O_MR1.
348         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
349             StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
350             if (state == StreamState::Starting || state == StreamState::Started) {
351                 // WARNING: On P, AAudio is returning ErrorInvalidState for Output and OK for Input.
352                 return Result::OK;
353             }
354         }
355         if (mStreamCallback != nullptr) { // Was a callback requested?
356             setDataCallbackEnabled(true);
357         }
358         return static_cast<Result>(mLibLoader->stream_requestStart(stream));
359     } else {
360         return Result::ErrorClosed;
361     }
362 }
363 
requestPause()364 Result AudioStreamAAudio::requestPause() {
365     std::lock_guard<std::mutex> lock(mLock);
366     AAudioStream *stream = mAAudioStream.load();
367     if (stream != nullptr) {
368         // Avoid state machine errors in O_MR1.
369         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
370             StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
371             if (state == StreamState::Pausing || state == StreamState::Paused) {
372                 return Result::OK;
373             }
374         }
375         return static_cast<Result>(mLibLoader->stream_requestPause(stream));
376     } else {
377         return Result::ErrorClosed;
378     }
379 }
380 
requestFlush()381 Result AudioStreamAAudio::requestFlush() {
382     std::lock_guard<std::mutex> lock(mLock);
383     AAudioStream *stream = mAAudioStream.load();
384     if (stream != nullptr) {
385         // Avoid state machine errors in O_MR1.
386         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
387             StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
388             if (state == StreamState::Flushing || state == StreamState::Flushed) {
389                 return Result::OK;
390             }
391         }
392         return static_cast<Result>(mLibLoader->stream_requestFlush(stream));
393     } else {
394         return Result::ErrorClosed;
395     }
396 }
397 
requestStop()398 Result AudioStreamAAudio::requestStop() {
399     std::lock_guard<std::mutex> lock(mLock);
400     AAudioStream *stream = mAAudioStream.load();
401     if (stream != nullptr) {
402         return requestStop_l(stream);
403     } else {
404         return Result::ErrorClosed;
405     }
406 }
407 
408 // Call under mLock
requestStop_l(AAudioStream * stream)409 Result AudioStreamAAudio::requestStop_l(AAudioStream *stream) {
410     // Avoid state machine errors in O_MR1.
411     if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
412         StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
413         if (state == StreamState::Stopping || state == StreamState::Stopped) {
414             return Result::OK;
415         }
416     }
417     return static_cast<Result>(mLibLoader->stream_requestStop(stream));
418 }
419 
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)420 ResultWithValue<int32_t>   AudioStreamAAudio::write(const void *buffer,
421                                      int32_t numFrames,
422                                      int64_t timeoutNanoseconds) {
423     AAudioStream *stream = mAAudioStream.load();
424     if (stream != nullptr) {
425         int32_t result = mLibLoader->stream_write(mAAudioStream, buffer,
426                                                   numFrames, timeoutNanoseconds);
427         return ResultWithValue<int32_t>::createBasedOnSign(result);
428     } else {
429         return ResultWithValue<int32_t>(Result::ErrorClosed);
430     }
431 }
432 
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)433 ResultWithValue<int32_t>   AudioStreamAAudio::read(void *buffer,
434                                  int32_t numFrames,
435                                  int64_t timeoutNanoseconds) {
436     AAudioStream *stream = mAAudioStream.load();
437     if (stream != nullptr) {
438         int32_t result = mLibLoader->stream_read(mAAudioStream, buffer,
439                                                  numFrames, timeoutNanoseconds);
440         return ResultWithValue<int32_t>::createBasedOnSign(result);
441     } else {
442         return ResultWithValue<int32_t>(Result::ErrorClosed);
443     }
444 }
445 
446 
447 // AAudioStream_waitForStateChange() can crash if it is waiting on a stream and that stream
448 // is closed from another thread.  We do not want to lock the stream for the duration of the call.
449 // So we call AAudioStream_waitForStateChange() with a timeout of zero so that it will not block.
450 // Then we can do our own sleep with the lock unlocked.
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)451 Result AudioStreamAAudio::waitForStateChange(StreamState currentState,
452                                         StreamState *nextState,
453                                         int64_t timeoutNanoseconds) {
454     Result oboeResult = Result::ErrorTimeout;
455     int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
456     aaudio_stream_state_t currentAAudioState = static_cast<aaudio_stream_state_t>(currentState);
457 
458     aaudio_result_t result = AAUDIO_OK;
459     int64_t timeLeftNanos = timeoutNanoseconds;
460 
461     mLock.lock();
462     while (true) {
463         // Do we still have an AAudio stream? If not then stream must have been closed.
464         AAudioStream *stream = mAAudioStream.load();
465         if (stream == nullptr) {
466             if (nextState != nullptr) {
467                 *nextState = StreamState::Closed;
468             }
469             oboeResult = Result::ErrorClosed;
470             break;
471         }
472 
473         // Update and query state change with no blocking.
474         aaudio_stream_state_t aaudioNextState;
475         result = mLibLoader->stream_waitForStateChange(
476                 mAAudioStream,
477                 currentAAudioState,
478                 &aaudioNextState,
479                 0); // timeout=0 for non-blocking
480         // AAudio will return AAUDIO_ERROR_TIMEOUT if timeout=0 and the state does not change.
481         if (result != AAUDIO_OK && result != AAUDIO_ERROR_TIMEOUT) {
482             oboeResult = static_cast<Result>(result);
483             break;
484         }
485 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
486         if (OboeGlobals::areWorkaroundsEnabled()
487             && aaudioNextState == static_cast<aaudio_stream_state_t >(StreamState::Starting)) {
488             aaudioNextState = static_cast<aaudio_stream_state_t >(StreamState::Started);
489         }
490 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
491         if (nextState != nullptr) {
492             *nextState = static_cast<StreamState>(aaudioNextState);
493         }
494         if (currentAAudioState != aaudioNextState) { // state changed?
495             oboeResult = Result::OK;
496             break;
497         }
498 
499         // Did we timeout or did user ask for non-blocking?
500         if (timeLeftNanos <= 0) {
501             break;
502         }
503 
504         // No change yet so sleep.
505         mLock.unlock(); // Don't sleep while locked.
506         if (sleepTimeNanos > timeLeftNanos) {
507             sleepTimeNanos = timeLeftNanos; // last little bit
508         }
509         AudioClock::sleepForNanos(sleepTimeNanos);
510         timeLeftNanos -= sleepTimeNanos;
511         mLock.lock();
512     }
513 
514     mLock.unlock();
515     return oboeResult;
516 }
517 
setBufferSizeInFrames(int32_t requestedFrames)518 ResultWithValue<int32_t> AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) {
519 
520     AAudioStream *stream = mAAudioStream.load();
521 
522     if (stream != nullptr) {
523         int32_t adjustedFrames = requestedFrames;
524         if (adjustedFrames > mBufferCapacityInFrames) {
525             adjustedFrames = mBufferCapacityInFrames;
526         }
527         adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames);
528 
529         int32_t newBufferSize = mLibLoader->stream_setBufferSize(mAAudioStream, adjustedFrames);
530 
531         // Cache the result if it's valid
532         if (newBufferSize > 0) mBufferSizeInFrames = newBufferSize;
533 
534         return ResultWithValue<int32_t>::createBasedOnSign(newBufferSize);
535 
536     } else {
537         return ResultWithValue<int32_t>(Result::ErrorClosed);
538     }
539 }
540 
getState() const541 StreamState AudioStreamAAudio::getState() const {
542     AAudioStream *stream = mAAudioStream.load();
543     if (stream != nullptr) {
544         aaudio_stream_state_t aaudioState = mLibLoader->stream_getState(stream);
545 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
546         if (OboeGlobals::areWorkaroundsEnabled()
547             && aaudioState == AAUDIO_STREAM_STATE_STARTING) {
548             aaudioState = AAUDIO_STREAM_STATE_STARTED;
549         }
550 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
551         return static_cast<StreamState>(aaudioState);
552     } else {
553         return StreamState::Closed;
554     }
555 }
556 
getBufferSizeInFrames()557 int32_t AudioStreamAAudio::getBufferSizeInFrames() {
558     AAudioStream *stream = mAAudioStream.load();
559     if (stream != nullptr) {
560         mBufferSizeInFrames = mLibLoader->stream_getBufferSize(stream);
561     }
562     return mBufferSizeInFrames;
563 }
564 
getFramesPerBurst()565 int32_t AudioStreamAAudio::getFramesPerBurst() {
566     AAudioStream *stream = mAAudioStream.load();
567     if (stream != nullptr) {
568         mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(stream);
569     }
570     return mFramesPerBurst;
571 }
572 
updateFramesRead()573 void AudioStreamAAudio::updateFramesRead() {
574     AAudioStream *stream = mAAudioStream.load();
575     if (stream != nullptr) {
576         mFramesRead = mLibLoader->stream_getFramesRead(stream);
577     }
578 }
579 
updateFramesWritten()580 void AudioStreamAAudio::updateFramesWritten() {
581     AAudioStream *stream = mAAudioStream.load();
582     if (stream != nullptr) {
583         mFramesWritten = mLibLoader->stream_getFramesWritten(stream);
584     }
585 }
586 
getXRunCount() const587 ResultWithValue<int32_t> AudioStreamAAudio::getXRunCount() const {
588     AAudioStream *stream = mAAudioStream.load();
589     if (stream != nullptr) {
590         return ResultWithValue<int32_t>::createBasedOnSign(mLibLoader->stream_getXRunCount(stream));
591     } else {
592         return ResultWithValue<int32_t>(Result::ErrorNull);
593     }
594 }
595 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)596 Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
597                                    int64_t *framePosition,
598                                    int64_t *timeNanoseconds) {
599     AAudioStream *stream = mAAudioStream.load();
600     if (stream != nullptr) {
601         if (getState() != StreamState::Started) {
602             return Result::ErrorInvalidState;
603         }
604         return static_cast<Result>(mLibLoader->stream_getTimestamp(stream, clockId,
605                                                framePosition, timeNanoseconds));
606     } else {
607         return Result::ErrorNull;
608     }
609 }
610 
calculateLatencyMillis()611 ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
612     AAudioStream *stream = mAAudioStream.load();
613     if (stream == nullptr) {
614         return ResultWithValue<double>(Result::ErrorClosed);
615     }
616 
617     // Get the time that a known audio frame was presented.
618     int64_t hardwareFrameIndex;
619     int64_t hardwareFrameHardwareTime;
620     auto result = getTimestamp(CLOCK_MONOTONIC,
621                                &hardwareFrameIndex,
622                                &hardwareFrameHardwareTime);
623     if (result != oboe::Result::OK) {
624         return ResultWithValue<double>(static_cast<Result>(result));
625     }
626 
627     // Get counter closest to the app.
628     bool isOutput = (getDirection() == oboe::Direction::Output);
629     int64_t appFrameIndex = isOutput ? getFramesWritten() : getFramesRead();
630 
631     // Assume that the next frame will be processed at the current time
632     using namespace std::chrono;
633     int64_t appFrameAppTime =
634             duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();
635 
636     // Calculate the number of frames between app and hardware
637     int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex;
638 
639     // Calculate the time which the next frame will be or was presented
640     int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / getSampleRate();
641     int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta;
642 
643     // The current latency is the difference in time between when the current frame is at
644     // the app and when it is at the hardware.
645     double latencyNanos = static_cast<double>(isOutput
646                           ? (appFrameHardwareTime - appFrameAppTime) // hardware is later
647                           : (appFrameAppTime - appFrameHardwareTime)); // hardware is earlier
648     double latencyMillis = latencyNanos / kNanosPerMillisecond;
649 
650     return ResultWithValue<double>(latencyMillis);
651 }
652 
isMMapUsed()653 bool AudioStreamAAudio::isMMapUsed() {
654     AAudioStream *stream = mAAudioStream.load();
655     if (stream != nullptr) {
656         return mLibLoader->stream_isMMapUsed(stream);
657     } else {
658         return false;
659     }
660 }
661 
662 } // namespace oboe
663