• 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 #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() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__);
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 
logUnsupportedAttributes()149 void AudioStreamAAudio::logUnsupportedAttributes() {
150     int sdkVersion = getSdkVersion();
151 
152     // These attributes are not supported pre Android "P"
153     if (sdkVersion < __ANDROID_API_P__) {
154         if (mUsage != Usage::Media) {
155             LOGW("Usage [AudioStreamBuilder::setUsage()] "
156                  "is not supported on AAudio streams running on pre-Android P versions.");
157         }
158 
159         if (mContentType != ContentType::Music) {
160             LOGW("ContentType [AudioStreamBuilder::setContentType()] "
161                  "is not supported on AAudio streams running on pre-Android P versions.");
162         }
163 
164         if (mSessionId != SessionId::None) {
165             LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
166                  "is not supported on AAudio streams running on pre-Android P versions.");
167         }
168     }
169 }
170 
open()171 Result AudioStreamAAudio::open() {
172     Result result = Result::OK;
173 
174     if (mAAudioStream != nullptr) {
175         return Result::ErrorInvalidState;
176     }
177 
178     result = AudioStream::open();
179     if (result != Result::OK) {
180         return result;
181     }
182 
183     AAudioStreamBuilder *aaudioBuilder;
184     result = static_cast<Result>(mLibLoader->createStreamBuilder(&aaudioBuilder));
185     if (result != Result::OK) {
186         return result;
187     }
188 
189     // Do not set INPUT capacity below 4096 because that prevents us from getting a FAST track
190     // when using the Legacy data path.
191     // If the app requests > 4096 then we allow it but we are less likely to get LowLatency.
192     // See internal bug b/80308183 for more details.
193     // Fixed in Q but let's still clip the capacity because high input capacity
194     // does not increase latency.
195     int32_t capacity = mBufferCapacityInFrames;
196     constexpr int kCapacityRequiredForFastLegacyTrack = 4096; // matches value in AudioFinger
197     if (OboeGlobals::areWorkaroundsEnabled()
198             && mDirection == oboe::Direction::Input
199             && capacity != oboe::Unspecified
200             && capacity < kCapacityRequiredForFastLegacyTrack
201             && mPerformanceMode == oboe::PerformanceMode::LowLatency) {
202         capacity = kCapacityRequiredForFastLegacyTrack;
203         LOGD("AudioStreamAAudio.open() capacity changed from %d to %d for lower latency",
204              static_cast<int>(mBufferCapacityInFrames), capacity);
205     }
206     mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, capacity);
207 
208     mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
209     mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
210     mLibLoader->builder_setDirection(aaudioBuilder, static_cast<aaudio_direction_t>(mDirection));
211     mLibLoader->builder_setFormat(aaudioBuilder, static_cast<aaudio_format_t>(mFormat));
212     mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate);
213     mLibLoader->builder_setSharingMode(aaudioBuilder,
214                                        static_cast<aaudio_sharing_mode_t>(mSharingMode));
215     mLibLoader->builder_setPerformanceMode(aaudioBuilder,
216                                            static_cast<aaudio_performance_mode_t>(mPerformanceMode));
217 
218     // These were added in P so we have to check for the function pointer.
219     if (mLibLoader->builder_setUsage != nullptr) {
220         mLibLoader->builder_setUsage(aaudioBuilder,
221                                      static_cast<aaudio_usage_t>(mUsage));
222     }
223 
224     if (mLibLoader->builder_setContentType != nullptr) {
225         mLibLoader->builder_setContentType(aaudioBuilder,
226                                            static_cast<aaudio_content_type_t>(mContentType));
227     }
228 
229     if (mLibLoader->builder_setInputPreset != nullptr) {
230         aaudio_input_preset_t inputPreset = mInputPreset;
231         if (getSdkVersion() <= __ANDROID_API_P__ && inputPreset == InputPreset::VoicePerformance) {
232             LOGD("InputPreset::VoicePerformance not supported before Q. Using VoiceRecognition.");
233             inputPreset = InputPreset::VoiceRecognition; // most similar preset
234         }
235         mLibLoader->builder_setInputPreset(aaudioBuilder,
236                                            static_cast<aaudio_input_preset_t>(inputPreset));
237     }
238 
239     if (mLibLoader->builder_setSessionId != nullptr) {
240         mLibLoader->builder_setSessionId(aaudioBuilder,
241                                          static_cast<aaudio_session_id_t>(mSessionId));
242     }
243 
244     // TODO get more parameters from the builder?
245 
246     if (isDataCallbackSpecified()) {
247         mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
248         mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerDataCallback());
249 
250         if (!isErrorCallbackSpecified()) {
251             // The app did not specify a callback so we should specify
252             // our own so the stream gets closed and stopped.
253             mErrorCallback = &mDefaultErrorCallback;
254         }
255         mLibLoader->builder_setErrorCallback(aaudioBuilder, internalErrorCallback, this);
256     }
257     // Else if the data callback is not being used then the write method will return an error
258     // and the app can stop and close the stream.
259 
260     // ============= OPEN THE STREAM ================
261     {
262         AAudioStream *stream = nullptr;
263         result = static_cast<Result>(mLibLoader->builder_openStream(aaudioBuilder, &stream));
264         mAAudioStream.store(stream);
265     }
266     if (result != Result::OK) {
267         // Warn developer because ErrorInternal is not very informative.
268         if (result == Result::ErrorInternal && mDirection == Direction::Input) {
269             LOGW("AudioStreamAAudio.open() may have failed due to lack of "
270                  "audio recording permission.");
271         }
272         goto error2;
273     }
274 
275     // Query and cache the stream properties
276     mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream);
277     mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream);
278     mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream);
279     mFormat = static_cast<AudioFormat>(mLibLoader->stream_getFormat(mAAudioStream));
280     mSharingMode = static_cast<SharingMode>(mLibLoader->stream_getSharingMode(mAAudioStream));
281     mPerformanceMode = static_cast<PerformanceMode>(
282             mLibLoader->stream_getPerformanceMode(mAAudioStream));
283     mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
284     mBufferSizeInFrames = mLibLoader->stream_getBufferSize(mAAudioStream);
285 
286     // These were added in P so we have to check for the function pointer.
287     if (mLibLoader->stream_getUsage != nullptr) {
288         mUsage = static_cast<Usage>(mLibLoader->stream_getUsage(mAAudioStream));
289     }
290     if (mLibLoader->stream_getContentType != nullptr) {
291         mContentType = static_cast<ContentType>(mLibLoader->stream_getContentType(mAAudioStream));
292     }
293     if (mLibLoader->stream_getInputPreset != nullptr) {
294         mInputPreset = static_cast<InputPreset>(mLibLoader->stream_getInputPreset(mAAudioStream));
295     }
296     if (mLibLoader->stream_getSessionId != nullptr) {
297         mSessionId = static_cast<SessionId>(mLibLoader->stream_getSessionId(mAAudioStream));
298     } else {
299         mSessionId = SessionId::None;
300     }
301 
302     LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d",
303             static_cast<int>(mFormat), static_cast<int>(mSampleRate),
304             static_cast<int>(mBufferCapacityInFrames));
305 
306 error2:
307     mLibLoader->builder_delete(aaudioBuilder);
308     LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s",
309          mLibLoader->convertResultToText(static_cast<aaudio_result_t>(result)));
310     return result;
311 }
312 
close()313 Result AudioStreamAAudio::close() {
314     // Prevent two threads from closing the stream at the same time and crashing.
315     // This could occur, for example, if an application called close() at the same
316     // time that an onError callback was being executed because of a disconnect.
317     std::lock_guard<std::mutex> lock(mLock);
318 
319     AudioStream::close();
320 
321     // This will delete the AAudio stream object so we need to null out the pointer.
322     AAudioStream *stream = mAAudioStream.exchange(nullptr);
323     if (stream != nullptr) {
324         if (OboeGlobals::areWorkaroundsEnabled()) {
325             // Make sure we are really stopped. Do it under mLock
326             // so another thread cannot call requestStart() right before the close.
327             requestStop_l(stream);
328             // Sometimes a callback can occur shortly after a stream has been stopped and
329             // even after a close! If the stream has been closed then the callback
330             // can access memory that has been freed. That causes a crash.
331             // This seems to be more likely in Android P or earlier.
332             // But it can also occur in later versions.
333             usleep(kDelayBeforeCloseMillis * 1000);
334         }
335         return static_cast<Result>(mLibLoader->stream_close(stream));
336     } else {
337         return Result::ErrorClosed;
338     }
339 }
340 
callOnAudioReady(AAudioStream * stream,void * audioData,int32_t numFrames)341 DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream,
342                                                                  void *audioData,
343                                                                  int32_t numFrames) {
344     DataCallbackResult result = fireDataCallback(audioData, numFrames);
345     if (result == DataCallbackResult::Continue) {
346         return result;
347     } else {
348         if (result == DataCallbackResult::Stop) {
349             LOGD("Oboe callback returned DataCallbackResult::Stop");
350         } else {
351             LOGE("Oboe callback returned unexpected value = %d", result);
352         }
353 
354         if (getSdkVersion() <= __ANDROID_API_P__) {
355             launchStopThread();
356             if (isMMapUsed()) {
357                 return DataCallbackResult::Stop;
358             } else {
359                 // Legacy stream <= API_P cannot be restarted after returning Stop.
360                 return DataCallbackResult::Continue;
361             }
362         } else {
363             return DataCallbackResult::Stop; // OK >= API_Q
364         }
365     }
366 }
367 
requestStart()368 Result AudioStreamAAudio::requestStart() {
369     std::lock_guard<std::mutex> lock(mLock);
370     AAudioStream *stream = mAAudioStream.load();
371     if (stream != nullptr) {
372         // Avoid state machine errors in O_MR1.
373         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
374             StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
375             if (state == StreamState::Starting || state == StreamState::Started) {
376                 // WARNING: On P, AAudio is returning ErrorInvalidState for Output and OK for Input.
377                 return Result::OK;
378             }
379         }
380         if (isDataCallbackSpecified()) {
381             setDataCallbackEnabled(true);
382         }
383         return static_cast<Result>(mLibLoader->stream_requestStart(stream));
384     } else {
385         return Result::ErrorClosed;
386     }
387 }
388 
requestPause()389 Result AudioStreamAAudio::requestPause() {
390     std::lock_guard<std::mutex> lock(mLock);
391     AAudioStream *stream = mAAudioStream.load();
392     if (stream != nullptr) {
393         // Avoid state machine errors in O_MR1.
394         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
395             StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
396             if (state == StreamState::Pausing || state == StreamState::Paused) {
397                 return Result::OK;
398             }
399         }
400         return static_cast<Result>(mLibLoader->stream_requestPause(stream));
401     } else {
402         return Result::ErrorClosed;
403     }
404 }
405 
requestFlush()406 Result AudioStreamAAudio::requestFlush() {
407     std::lock_guard<std::mutex> lock(mLock);
408     AAudioStream *stream = mAAudioStream.load();
409     if (stream != nullptr) {
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::Flushing || state == StreamState::Flushed) {
414                 return Result::OK;
415             }
416         }
417         return static_cast<Result>(mLibLoader->stream_requestFlush(stream));
418     } else {
419         return Result::ErrorClosed;
420     }
421 }
422 
requestStop()423 Result AudioStreamAAudio::requestStop() {
424     std::lock_guard<std::mutex> lock(mLock);
425     AAudioStream *stream = mAAudioStream.load();
426     if (stream != nullptr) {
427         return requestStop_l(stream);
428     } else {
429         return Result::ErrorClosed;
430     }
431 }
432 
433 // Call under mLock
requestStop_l(AAudioStream * stream)434 Result AudioStreamAAudio::requestStop_l(AAudioStream *stream) {
435     // Avoid state machine errors in O_MR1.
436     if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
437         StreamState state = static_cast<StreamState>(mLibLoader->stream_getState(stream));
438         if (state == StreamState::Stopping || state == StreamState::Stopped) {
439             return Result::OK;
440         }
441     }
442     return static_cast<Result>(mLibLoader->stream_requestStop(stream));
443 }
444 
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)445 ResultWithValue<int32_t>   AudioStreamAAudio::write(const void *buffer,
446                                      int32_t numFrames,
447                                      int64_t timeoutNanoseconds) {
448     AAudioStream *stream = mAAudioStream.load();
449     if (stream != nullptr) {
450         int32_t result = mLibLoader->stream_write(mAAudioStream, buffer,
451                                                   numFrames, timeoutNanoseconds);
452         return ResultWithValue<int32_t>::createBasedOnSign(result);
453     } else {
454         return ResultWithValue<int32_t>(Result::ErrorClosed);
455     }
456 }
457 
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)458 ResultWithValue<int32_t>   AudioStreamAAudio::read(void *buffer,
459                                  int32_t numFrames,
460                                  int64_t timeoutNanoseconds) {
461     AAudioStream *stream = mAAudioStream.load();
462     if (stream != nullptr) {
463         int32_t result = mLibLoader->stream_read(mAAudioStream, buffer,
464                                                  numFrames, timeoutNanoseconds);
465         return ResultWithValue<int32_t>::createBasedOnSign(result);
466     } else {
467         return ResultWithValue<int32_t>(Result::ErrorClosed);
468     }
469 }
470 
471 
472 // AAudioStream_waitForStateChange() can crash if it is waiting on a stream and that stream
473 // is closed from another thread.  We do not want to lock the stream for the duration of the call.
474 // So we call AAudioStream_waitForStateChange() with a timeout of zero so that it will not block.
475 // Then we can do our own sleep with the lock unlocked.
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)476 Result AudioStreamAAudio::waitForStateChange(StreamState currentState,
477                                         StreamState *nextState,
478                                         int64_t timeoutNanoseconds) {
479     Result oboeResult = Result::ErrorTimeout;
480     int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
481     aaudio_stream_state_t currentAAudioState = static_cast<aaudio_stream_state_t>(currentState);
482 
483     aaudio_result_t result = AAUDIO_OK;
484     int64_t timeLeftNanos = timeoutNanoseconds;
485 
486     mLock.lock();
487     while (true) {
488         // Do we still have an AAudio stream? If not then stream must have been closed.
489         AAudioStream *stream = mAAudioStream.load();
490         if (stream == nullptr) {
491             if (nextState != nullptr) {
492                 *nextState = StreamState::Closed;
493             }
494             oboeResult = Result::ErrorClosed;
495             break;
496         }
497 
498         // Update and query state change with no blocking.
499         aaudio_stream_state_t aaudioNextState;
500         result = mLibLoader->stream_waitForStateChange(
501                 mAAudioStream,
502                 currentAAudioState,
503                 &aaudioNextState,
504                 0); // timeout=0 for non-blocking
505         // AAudio will return AAUDIO_ERROR_TIMEOUT if timeout=0 and the state does not change.
506         if (result != AAUDIO_OK && result != AAUDIO_ERROR_TIMEOUT) {
507             oboeResult = static_cast<Result>(result);
508             break;
509         }
510 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
511         if (OboeGlobals::areWorkaroundsEnabled()
512             && aaudioNextState == static_cast<aaudio_stream_state_t >(StreamState::Starting)) {
513             aaudioNextState = static_cast<aaudio_stream_state_t >(StreamState::Started);
514         }
515 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
516         if (nextState != nullptr) {
517             *nextState = static_cast<StreamState>(aaudioNextState);
518         }
519         if (currentAAudioState != aaudioNextState) { // state changed?
520             oboeResult = Result::OK;
521             break;
522         }
523 
524         // Did we timeout or did user ask for non-blocking?
525         if (timeLeftNanos <= 0) {
526             break;
527         }
528 
529         // No change yet so sleep.
530         mLock.unlock(); // Don't sleep while locked.
531         if (sleepTimeNanos > timeLeftNanos) {
532             sleepTimeNanos = timeLeftNanos; // last little bit
533         }
534         AudioClock::sleepForNanos(sleepTimeNanos);
535         timeLeftNanos -= sleepTimeNanos;
536         mLock.lock();
537     }
538 
539     mLock.unlock();
540     return oboeResult;
541 }
542 
setBufferSizeInFrames(int32_t requestedFrames)543 ResultWithValue<int32_t> AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) {
544 
545     AAudioStream *stream = mAAudioStream.load();
546 
547     if (stream != nullptr) {
548         int32_t adjustedFrames = requestedFrames;
549         if (adjustedFrames > mBufferCapacityInFrames) {
550             adjustedFrames = mBufferCapacityInFrames;
551         }
552         adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames);
553 
554         int32_t newBufferSize = mLibLoader->stream_setBufferSize(mAAudioStream, adjustedFrames);
555 
556         // Cache the result if it's valid
557         if (newBufferSize > 0) mBufferSizeInFrames = newBufferSize;
558 
559         return ResultWithValue<int32_t>::createBasedOnSign(newBufferSize);
560 
561     } else {
562         return ResultWithValue<int32_t>(Result::ErrorClosed);
563     }
564 }
565 
getState() const566 StreamState AudioStreamAAudio::getState() const {
567     AAudioStream *stream = mAAudioStream.load();
568     if (stream != nullptr) {
569         aaudio_stream_state_t aaudioState = mLibLoader->stream_getState(stream);
570 #if OBOE_FIX_FORCE_STARTING_TO_STARTED
571         if (OboeGlobals::areWorkaroundsEnabled()
572             && aaudioState == AAUDIO_STREAM_STATE_STARTING) {
573             aaudioState = AAUDIO_STREAM_STATE_STARTED;
574         }
575 #endif // OBOE_FIX_FORCE_STARTING_TO_STARTED
576         return static_cast<StreamState>(aaudioState);
577     } else {
578         return StreamState::Closed;
579     }
580 }
581 
getBufferSizeInFrames()582 int32_t AudioStreamAAudio::getBufferSizeInFrames() {
583     AAudioStream *stream = mAAudioStream.load();
584     if (stream != nullptr) {
585         mBufferSizeInFrames = mLibLoader->stream_getBufferSize(stream);
586     }
587     return mBufferSizeInFrames;
588 }
589 
getFramesPerBurst()590 int32_t AudioStreamAAudio::getFramesPerBurst() {
591     AAudioStream *stream = mAAudioStream.load();
592     if (stream != nullptr) {
593         mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(stream);
594     }
595     return mFramesPerBurst;
596 }
597 
updateFramesRead()598 void AudioStreamAAudio::updateFramesRead() {
599     AAudioStream *stream = mAAudioStream.load();
600     if (stream != nullptr) {
601         mFramesRead = mLibLoader->stream_getFramesRead(stream);
602     }
603 }
604 
updateFramesWritten()605 void AudioStreamAAudio::updateFramesWritten() {
606     AAudioStream *stream = mAAudioStream.load();
607     if (stream != nullptr) {
608         mFramesWritten = mLibLoader->stream_getFramesWritten(stream);
609     }
610 }
611 
getXRunCount() const612 ResultWithValue<int32_t> AudioStreamAAudio::getXRunCount() const {
613     AAudioStream *stream = mAAudioStream.load();
614     if (stream != nullptr) {
615         return ResultWithValue<int32_t>::createBasedOnSign(mLibLoader->stream_getXRunCount(stream));
616     } else {
617         return ResultWithValue<int32_t>(Result::ErrorNull);
618     }
619 }
620 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)621 Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
622                                    int64_t *framePosition,
623                                    int64_t *timeNanoseconds) {
624     AAudioStream *stream = mAAudioStream.load();
625     if (stream != nullptr) {
626         if (getState() != StreamState::Started) {
627             return Result::ErrorInvalidState;
628         }
629         return static_cast<Result>(mLibLoader->stream_getTimestamp(stream, clockId,
630                                                framePosition, timeNanoseconds));
631     } else {
632         return Result::ErrorNull;
633     }
634 }
635 
calculateLatencyMillis()636 ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
637     AAudioStream *stream = mAAudioStream.load();
638     if (stream == nullptr) {
639         return ResultWithValue<double>(Result::ErrorClosed);
640     }
641 
642     // Get the time that a known audio frame was presented.
643     int64_t hardwareFrameIndex;
644     int64_t hardwareFrameHardwareTime;
645     auto result = getTimestamp(CLOCK_MONOTONIC,
646                                &hardwareFrameIndex,
647                                &hardwareFrameHardwareTime);
648     if (result != oboe::Result::OK) {
649         return ResultWithValue<double>(static_cast<Result>(result));
650     }
651 
652     // Get counter closest to the app.
653     bool isOutput = (getDirection() == oboe::Direction::Output);
654     int64_t appFrameIndex = isOutput ? getFramesWritten() : getFramesRead();
655 
656     // Assume that the next frame will be processed at the current time
657     using namespace std::chrono;
658     int64_t appFrameAppTime =
659             duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();
660 
661     // Calculate the number of frames between app and hardware
662     int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex;
663 
664     // Calculate the time which the next frame will be or was presented
665     int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / getSampleRate();
666     int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta;
667 
668     // The current latency is the difference in time between when the current frame is at
669     // the app and when it is at the hardware.
670     double latencyNanos = static_cast<double>(isOutput
671                           ? (appFrameHardwareTime - appFrameAppTime) // hardware is later
672                           : (appFrameAppTime - appFrameHardwareTime)); // hardware is earlier
673     double latencyMillis = latencyNanos / kNanosPerMillisecond;
674 
675     return ResultWithValue<double>(latencyMillis);
676 }
677 
isMMapUsed()678 bool AudioStreamAAudio::isMMapUsed() {
679     AAudioStream *stream = mAAudioStream.load();
680     if (stream != nullptr) {
681         return AAudioExtensions::getInstance().isMMapUsed(stream);
682     } else {
683         return false;
684     }
685 }
686 
687 } // namespace oboe
688