aboutsummaryrefslogtreecommitdiff
path: root/externals/oboe/src/common/AudioStream.cpp
diff options
context:
space:
mode:
authorswurl <swurl@swurl.xyz>2025-05-31 02:33:02 -0400
committerswurl <swurl@swurl.xyz>2025-05-31 02:33:02 -0400
commit6c655321e6b04b8648802e296bb5ca11d290ae68 (patch)
tree5c906511e4a2910ce8b806bb9d763b524c28619e /externals/oboe/src/common/AudioStream.cpp
parentc0cceff365f754f8859f4c9a0362ebdba7ea388b (diff)
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'externals/oboe/src/common/AudioStream.cpp')
-rw-r--r--externals/oboe/src/common/AudioStream.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/externals/oboe/src/common/AudioStream.cpp b/externals/oboe/src/common/AudioStream.cpp
new file mode 100644
index 0000000000..5eb4e4629e
--- /dev/null
+++ b/externals/oboe/src/common/AudioStream.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <thread>
+
+#include "oboe/AudioClock.h"
+#include "oboe/AudioStream.h"
+#include "oboe/Utilities.h"
+#include "OboeDebug.h"
+
+namespace oboe {
+
+/*
+ * AudioStream
+ */
+AudioStream::AudioStream(const AudioStreamBuilder &builder)
+ : AudioStreamBase(builder) {
+ LOGD("Constructor for AudioStream at %p", this);
+}
+
+AudioStream::~AudioStream() {
+ // This is to help debug use after free bugs.
+ LOGD("Destructor for AudioStream at %p", this);
+}
+
+Result AudioStream::close() {
+ closePerformanceHint();
+ // Update local counters so they can be read after the close.
+ updateFramesWritten();
+ updateFramesRead();
+ return Result::OK;
+}
+
+// Call this from fireDataCallback() if you want to monitor CPU scheduler.
+void AudioStream::checkScheduler() {
+ int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread
+ if (scheduler != mPreviousScheduler) {
+ LOGD("AudioStream::%s() scheduler = %s", __func__,
+ ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" :
+ ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" :
+ ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN")))
+ );
+ mPreviousScheduler = scheduler;
+ }
+}
+
+DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFrames) {
+ if (!isDataCallbackEnabled()) {
+ LOGW("AudioStream::%s() called with data callback disabled!", __func__);
+ return DataCallbackResult::Stop; // Should not be getting called
+ }
+
+ beginPerformanceHintInCallback();
+
+ // Call the app to do the work.
+ DataCallbackResult result;
+ if (mDataCallback) {
+ result = mDataCallback->onAudioReady(this, audioData, numFrames);
+ } else {
+ result = onDefaultCallback(audioData, numFrames);
+ }
+ // On Oreo, we might get called after returning stop.
+ // So block that here.
+ setDataCallbackEnabled(result == DataCallbackResult::Continue);
+
+ endPerformanceHintInCallback(numFrames);
+
+ return result;
+}
+
+Result AudioStream::waitForStateTransition(StreamState startingState,
+ StreamState endingState,
+ int64_t timeoutNanoseconds)
+{
+ StreamState state;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ state = getState();
+ if (state == StreamState::Closed) {
+ return Result::ErrorClosed;
+ } else if (state == StreamState::Disconnected) {
+ return Result::ErrorDisconnected;
+ }
+ }
+
+ StreamState nextState = state;
+ // TODO Should this be a while()?!
+ if (state == startingState && state != endingState) {
+ Result result = waitForStateChange(state, &nextState, timeoutNanoseconds);
+ if (result != Result::OK) {
+ return result;
+ }
+ }
+
+ if (nextState != endingState) {
+ return Result::ErrorInvalidState;
+ } else {
+ return Result::OK;
+ }
+}
+
+Result AudioStream::start(int64_t timeoutNanoseconds)
+{
+ Result result = requestStart();
+ if (result != Result::OK) return result;
+ if (timeoutNanoseconds <= 0) return result;
+ result = waitForStateTransition(StreamState::Starting,
+ StreamState::Started, timeoutNanoseconds);
+ if (result != Result::OK) {
+ LOGE("AudioStream::%s() timed out before moving from STARTING to STARTED", __func__);
+ }
+ return result;
+}
+
+Result AudioStream::pause(int64_t timeoutNanoseconds)
+{
+ Result result = requestPause();
+ if (result != Result::OK) return result;
+ if (timeoutNanoseconds <= 0) return result;
+ return waitForStateTransition(StreamState::Pausing,
+ StreamState::Paused, timeoutNanoseconds);
+}
+
+Result AudioStream::flush(int64_t timeoutNanoseconds)
+{
+ Result result = requestFlush();
+ if (result != Result::OK) return result;
+ if (timeoutNanoseconds <= 0) return result;
+ return waitForStateTransition(StreamState::Flushing,
+ StreamState::Flushed, timeoutNanoseconds);
+}
+
+Result AudioStream::stop(int64_t timeoutNanoseconds)
+{
+ Result result = requestStop();
+ if (result != Result::OK) return result;
+ if (timeoutNanoseconds <= 0) return result;
+ return waitForStateTransition(StreamState::Stopping,
+ StreamState::Stopped, timeoutNanoseconds);
+}
+
+int32_t AudioStream::getBytesPerSample() const {
+ return convertFormatToSizeInBytes(mFormat);
+}
+
+int64_t AudioStream::getFramesRead() {
+ updateFramesRead();
+ return mFramesRead;
+}
+
+int64_t AudioStream::getFramesWritten() {
+ updateFramesWritten();
+ return mFramesWritten;
+}
+
+ResultWithValue<int32_t> AudioStream::getAvailableFrames() {
+ int64_t readCounter = getFramesRead();
+ if (readCounter < 0) return ResultWithValue<int32_t>::createBasedOnSign(readCounter);
+ int64_t writeCounter = getFramesWritten();
+ if (writeCounter < 0) return ResultWithValue<int32_t>::createBasedOnSign(writeCounter);
+ int32_t framesAvailable = writeCounter - readCounter;
+ return ResultWithValue<int32_t>(framesAvailable);
+}
+
+ResultWithValue<int32_t> AudioStream::waitForAvailableFrames(int32_t numFrames,
+ int64_t timeoutNanoseconds) {
+ if (numFrames == 0) return Result::OK;
+ if (numFrames < 0) return Result::ErrorOutOfRange;
+
+ // Make sure we don't try to wait for more frames than the buffer can hold.
+ // Subtract framesPerBurst because this is often called from a callback
+ // and we don't want to be sleeping if the buffer is close to overflowing.
+ const int32_t maxAvailableFrames = getBufferCapacityInFrames() - getFramesPerBurst();
+ numFrames = std::min(numFrames, maxAvailableFrames);
+ // The capacity should never be less than one burst. But clip to zero just in case.
+ numFrames = std::max(0, numFrames);
+
+ int64_t framesAvailable = 0;
+ int64_t burstInNanos = getFramesPerBurst() * kNanosPerSecond / getSampleRate();
+ bool ready = false;
+ int64_t deadline = AudioClock::getNanoseconds() + timeoutNanoseconds;
+ do {
+ ResultWithValue<int32_t> result = getAvailableFrames();
+ if (!result) return result;
+ framesAvailable = result.value();
+ ready = (framesAvailable >= numFrames);
+ if (!ready) {
+ int64_t now = AudioClock::getNanoseconds();
+ if (now > deadline) break;
+ AudioClock::sleepForNanos(burstInNanos);
+ }
+ } while (!ready);
+ return (!ready)
+ ? ResultWithValue<int32_t>(Result::ErrorTimeout)
+ : ResultWithValue<int32_t>(framesAvailable);
+}
+
+ResultWithValue<FrameTimestamp> AudioStream::getTimestamp(clockid_t clockId) {
+ FrameTimestamp frame;
+ Result result = getTimestamp(clockId, &frame.position, &frame.timestamp);
+ if (result == Result::OK){
+ return ResultWithValue<FrameTimestamp>(frame);
+ } else {
+ return ResultWithValue<FrameTimestamp>(static_cast<Result>(result));
+ }
+}
+
+void AudioStream::calculateDefaultDelayBeforeCloseMillis() {
+ // Calculate delay time before close based on burst duration.
+ // Start with a burst duration then add 1 msec as a safety margin.
+ mDelayBeforeCloseMillis = std::max(kMinDelayBeforeCloseMillis,
+ 1 + ((mFramesPerBurst * 1000) / getSampleRate()));
+ LOGD("calculateDefaultDelayBeforeCloseMillis() default = %d",
+ static_cast<int>(mDelayBeforeCloseMillis));
+}
+
+} // namespace oboe