diff options
Diffstat (limited to 'externals/oboe/src/opensles/AudioStreamBuffered.cpp')
| -rw-r--r-- | externals/oboe/src/opensles/AudioStreamBuffered.cpp | 285 |
1 files changed, 0 insertions, 285 deletions
diff --git a/externals/oboe/src/opensles/AudioStreamBuffered.cpp b/externals/oboe/src/opensles/AudioStreamBuffered.cpp deleted file mode 100644 index d608f20681..0000000000 --- a/externals/oboe/src/opensles/AudioStreamBuffered.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2016 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 <memory> - -#include "oboe/Oboe.h" - -#include "common/OboeDebug.h" -#include "oboe/AudioClock.h" -#include "opensles/AudioStreamBuffered.h" - -namespace oboe { - -constexpr int kDefaultBurstsPerBuffer = 16; // arbitrary, allows dynamic latency tuning -constexpr int kMinBurstsPerBuffer = 4; // arbitrary, allows dynamic latency tuning -constexpr int kMinFramesPerBuffer = 48 * 32; // arbitrary - -/* - * AudioStream with a FifoBuffer - */ -AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder) - : AudioStream(builder) { -} - -void AudioStreamBuffered::allocateFifo() { - // If the caller does not provide a callback use our own internal - // callback that reads data from the FIFO. - if (usingFIFO()) { - // FIFO is configured with the same format and channels as the stream. - int32_t capacityFrames = getBufferCapacityInFrames(); - if (capacityFrames == oboe::kUnspecified) { - capacityFrames = getFramesPerBurst() * kDefaultBurstsPerBuffer; - } else { - int32_t minFramesPerBufferByBursts = getFramesPerBurst() * kMinBurstsPerBuffer; - if (capacityFrames <= minFramesPerBufferByBursts) { - capacityFrames = minFramesPerBufferByBursts; - } else { - capacityFrames = std::max(kMinFramesPerBuffer, capacityFrames); - // round up to nearest burst - int32_t numBursts = (capacityFrames + getFramesPerBurst() - 1) - / getFramesPerBurst(); - capacityFrames = numBursts * getFramesPerBurst(); - } - } - - mFifoBuffer = std::make_unique<FifoBuffer>(getBytesPerFrame(), capacityFrames); - mBufferCapacityInFrames = capacityFrames; - mBufferSizeInFrames = mBufferCapacityInFrames; - } -} - -void AudioStreamBuffered::updateFramesWritten() { - if (mFifoBuffer) { - mFramesWritten = static_cast<int64_t>(mFifoBuffer->getWriteCounter()); - } // or else it will get updated by processBufferCallback() -} - -void AudioStreamBuffered::updateFramesRead() { - if (mFifoBuffer) { - mFramesRead = static_cast<int64_t>(mFifoBuffer->getReadCounter()); - } // or else it will get updated by processBufferCallback() -} - -// This is called by the OpenSL ES callback to read or write the back end of the FIFO. -DataCallbackResult AudioStreamBuffered::onDefaultCallback(void *audioData, int numFrames) { - int32_t framesTransferred = 0; - - if (getDirection() == oboe::Direction::Output) { - // Read from the FIFO and write to audioData, clear part of buffer if not enough data. - framesTransferred = mFifoBuffer->readNow(audioData, numFrames); - } else { - // Read from audioData and write to the FIFO - framesTransferred = mFifoBuffer->write(audioData, numFrames); // There is no writeNow() - } - - if (framesTransferred < numFrames) { - LOGD("AudioStreamBuffered::%s(): xrun! framesTransferred = %d, numFrames = %d", - __func__, framesTransferred, numFrames); - // TODO If we do not allow FIFO to wrap then our timestamps will drift when there is an XRun! - incrementXRunCount(); - } - markCallbackTime(static_cast<int32_t>(numFrames)); // so foreground knows how long to wait. - return DataCallbackResult::Continue; -} - -void AudioStreamBuffered::markCallbackTime(int32_t numFrames) { - mLastBackgroundSize = numFrames; - mBackgroundRanAtNanoseconds = AudioClock::getNanoseconds(); -} - -int64_t AudioStreamBuffered::predictNextCallbackTime() { - if (mBackgroundRanAtNanoseconds == 0) { - return 0; - } - int64_t nanosPerBuffer = (kNanosPerSecond * mLastBackgroundSize) / getSampleRate(); - const int64_t margin = 200 * kNanosPerMicrosecond; // arbitrary delay so we wake up just after - return mBackgroundRanAtNanoseconds + nanosPerBuffer + margin; -} - -// Common code for read/write. -// @return Result::OK with frames read/written, or Result::Error* -ResultWithValue<int32_t> AudioStreamBuffered::transfer( - void *readBuffer, - const void *writeBuffer, - int32_t numFrames, - int64_t timeoutNanoseconds) { - // Validate arguments. - if (readBuffer != nullptr && writeBuffer != nullptr) { - LOGE("AudioStreamBuffered::%s(): both buffers are not NULL", __func__); - return ResultWithValue<int32_t>(Result::ErrorInternal); - } - if (getDirection() == Direction::Input && readBuffer == nullptr) { - LOGE("AudioStreamBuffered::%s(): readBuffer is NULL", __func__); - return ResultWithValue<int32_t>(Result::ErrorNull); - } - if (getDirection() == Direction::Output && writeBuffer == nullptr) { - LOGE("AudioStreamBuffered::%s(): writeBuffer is NULL", __func__); - return ResultWithValue<int32_t>(Result::ErrorNull); - } - if (numFrames < 0) { - LOGE("AudioStreamBuffered::%s(): numFrames is negative", __func__); - return ResultWithValue<int32_t>(Result::ErrorOutOfRange); - } else if (numFrames == 0) { - return ResultWithValue<int32_t>(numFrames); - } - if (timeoutNanoseconds < 0) { - LOGE("AudioStreamBuffered::%s(): timeoutNanoseconds is negative", __func__); - return ResultWithValue<int32_t>(Result::ErrorOutOfRange); - } - - int32_t result = 0; - uint8_t *readData = reinterpret_cast<uint8_t *>(readBuffer); - const uint8_t *writeData = reinterpret_cast<const uint8_t *>(writeBuffer); - int32_t framesLeft = numFrames; - int64_t timeToQuit = 0; - bool repeat = true; - - // Calculate when to timeout. - if (timeoutNanoseconds > 0) { - timeToQuit = AudioClock::getNanoseconds() + timeoutNanoseconds; - } - - // Loop until we get the data, or we have an error, or we timeout. - do { - // read or write - if (getDirection() == Direction::Input) { - result = mFifoBuffer->read(readData, framesLeft); - if (result > 0) { - readData += mFifoBuffer->convertFramesToBytes(result); - framesLeft -= result; - } - } else { - // between zero and capacity - uint32_t fullFrames = mFifoBuffer->getFullFramesAvailable(); - // Do not write above threshold size. - int32_t emptyFrames = getBufferSizeInFrames() - static_cast<int32_t>(fullFrames); - int32_t framesToWrite = std::max(0, std::min(framesLeft, emptyFrames)); - result = mFifoBuffer->write(writeData, framesToWrite); - if (result > 0) { - writeData += mFifoBuffer->convertFramesToBytes(result); - framesLeft -= result; - } - } - - // If we need more data then sleep and try again. - if (framesLeft > 0 && result >= 0 && timeoutNanoseconds > 0) { - int64_t timeNow = AudioClock::getNanoseconds(); - if (timeNow >= timeToQuit) { - LOGE("AudioStreamBuffered::%s(): TIMEOUT", __func__); - repeat = false; // TIMEOUT - } else { - // Figure out how long to sleep. - int64_t sleepForNanos; - int64_t wakeTimeNanos = predictNextCallbackTime(); - if (wakeTimeNanos <= 0) { - // No estimate available. Sleep for one burst. - sleepForNanos = (getFramesPerBurst() * kNanosPerSecond) / getSampleRate(); - } else { - // Don't sleep past timeout. - if (wakeTimeNanos > timeToQuit) { - wakeTimeNanos = timeToQuit; - } - sleepForNanos = wakeTimeNanos - timeNow; - // Avoid rapid loop with no sleep. - const int64_t minSleepTime = kNanosPerMillisecond; // arbitrary - if (sleepForNanos < minSleepTime) { - sleepForNanos = minSleepTime; - } - } - - AudioClock::sleepForNanos(sleepForNanos); - } - - } else { - repeat = false; - } - } while(repeat); - - if (result < 0) { - return ResultWithValue<int32_t>(static_cast<Result>(result)); - } else { - int32_t framesWritten = numFrames - framesLeft; - return ResultWithValue<int32_t>(framesWritten); - } -} - -// Write to the FIFO so the callback can read from it. -ResultWithValue<int32_t> AudioStreamBuffered::write(const void *buffer, - int32_t numFrames, - int64_t timeoutNanoseconds) { - if (getState() == StreamState::Closed){ - return ResultWithValue<int32_t>(Result::ErrorClosed); - } - - if (getDirection() == Direction::Input) { - return ResultWithValue<int32_t>(Result::ErrorUnavailable); // TODO review, better error code? - } - Result result = updateServiceFrameCounter(); - if (result != Result::OK) return ResultWithValue<int32_t>(static_cast<Result>(result)); - return transfer(nullptr, buffer, numFrames, timeoutNanoseconds); -} - -// Read data from the FIFO that was written by the callback. -ResultWithValue<int32_t> AudioStreamBuffered::read(void *buffer, - int32_t numFrames, - int64_t timeoutNanoseconds) { - if (getState() == StreamState::Closed){ - return ResultWithValue<int32_t>(Result::ErrorClosed); - } - - if (getDirection() == Direction::Output) { - return ResultWithValue<int32_t>(Result::ErrorUnavailable); // TODO review, better error code? - } - Result result = updateServiceFrameCounter(); - if (result != Result::OK) return ResultWithValue<int32_t>(static_cast<Result>(result)); - return transfer(buffer, nullptr, numFrames, timeoutNanoseconds); -} - -// Only supported when we are not using a callback. -ResultWithValue<int32_t> AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames) -{ - if (getState() == StreamState::Closed){ - return ResultWithValue<int32_t>(Result::ErrorClosed); - } - - if (!mFifoBuffer) { - return ResultWithValue<int32_t>(Result::ErrorUnimplemented); - } - - if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) { - requestedFrames = mFifoBuffer->getBufferCapacityInFrames(); - } else if (requestedFrames < getFramesPerBurst()) { - requestedFrames = getFramesPerBurst(); - } - mBufferSizeInFrames = requestedFrames; - return ResultWithValue<int32_t>(requestedFrames); -} - -int32_t AudioStreamBuffered::getBufferCapacityInFrames() const { - if (mFifoBuffer) { - return mFifoBuffer->getBufferCapacityInFrames(); - } else { - return AudioStream::getBufferCapacityInFrames(); - } -} - -bool AudioStreamBuffered::isXRunCountSupported() const { - // XRun count is only supported if we're using blocking I/O (not callbacks) - return (!isDataCallbackSpecified()); -} - -} // namespace oboe |
