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