blob: 0b6d1a301b2b5107673c09ad7c24d0a49aab6f31 [file] [log] [blame]
/*
* 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 "oboe/Oboe.h"
#include "opensles/AudioStreamBuffered.h"
#include "common/AudioClock.h"
namespace oboe {
/*
* AudioStream with a FifoBuffer
*/
AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder)
: AudioStream(builder) {
}
AudioStreamBuffered::~AudioStreamBuffered() {
delete mFifoBuffer;
}
Result AudioStreamBuffered::finishOpen() {
// If the caller does not provide a callback use our own internal
// callback that reads data from the FIFO.
if (getCallback() == nullptr) {
LOGD("AudioStreamBuffered(): new FifoBuffer(bytesPerFrame=%d", getBytesPerFrame());
// FIFO is configured with the same format and channels as the stream.
mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size?
// Create a callback that reads from the FIFO
mInternalCallback = std::unique_ptr<AudioStreamBufferedCallback>(new AudioStreamBufferedCallback(this));
mStreamCallback = mInternalCallback.get();
LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback);
}
return Result::OK;
}
// TODO: This method should return a tuple of Result,int32_t where the
// 2nd return param is the frames written. Maybe not!
int32_t AudioStreamBuffered::write(const void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds)
{
int32_t result = 0;
uint8_t *source = (uint8_t *)buffer;
int32_t framesLeft = numFrames;
while(framesLeft > 0 && result >= 0) {
result = mFifoBuffer->write(source, framesLeft);
LOGD("AudioStreamBuffered::%s(): wrote %d / %d frames to FIFO, [0] = %f",
__func__, result, framesLeft, ((float *)source)[0]);
if (result > 0) {
source += mFifoBuffer->convertFramesToBytes(result);
incrementFramesWritten(result);
framesLeft -= result;
}
if (framesLeft > 0 && result >= 0) {
int64_t wakeTimeNanos = mFifoBuffer->getNextReadTime(getSampleRate());
// TODO use timeoutNanoseconds
AudioClock::sleepUntilNanoTime(wakeTimeNanos);
}
}
return result;
}
// Read from the FIFO that was written by the callback.
int32_t AudioStreamBuffered::read(void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds)
{
static int readCount = 0;
int32_t result = 0;
uint8_t *destination = (uint8_t *)buffer;
int32_t framesLeft = numFrames;
while(framesLeft > 0 && result >= 0) {
result = mFifoBuffer->read(destination, framesLeft);
LOGD("AudioStreamBuffered::%s(): read %d/%d frames from FIFO, #%d",
__func__, result, framesLeft, readCount);
if (result > 0) {
destination += mFifoBuffer->convertFramesToBytes(result);
incrementFramesRead(result);
framesLeft -= result;
readCount++;
}
if (framesLeft > 0 && result >= 0) {
// FIXME use proper timing model, borrow one from AAudio
// TODO use timeoutNanoseconds
AudioClock::sleepForNanos(4 * kNanosPerMillisecond);
}
}
return result;
}
Result AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames)
{
if (mFifoBuffer != nullptr) {
if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) {
requestedFrames = mFifoBuffer->getBufferCapacityInFrames();
}
mFifoBuffer->setThresholdFrames(requestedFrames);
return Result::OK;
} else {
return Result::ErrorUnimplemented;
}
}
int32_t AudioStreamBuffered::getBufferSizeInFrames() const {
if (mFifoBuffer != nullptr) {
return mFifoBuffer->getThresholdFrames();
} else {
return AudioStream::getBufferSizeInFrames();
}
}
int32_t AudioStreamBuffered::getBufferCapacityInFrames() const {
if (mFifoBuffer != nullptr) {
return mFifoBuffer->getBufferCapacityInFrames(); // Maybe set mBufferCapacity in constructor
} else {
return AudioStream::getBufferCapacityInFrames();
}
}
} // namespace oboe