/* * 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 #include #include #include "oboe_fifo_FifoControllerBase_android.h" #include "oboe_fifo_FifoController_android.h" #include "oboe_fifo_FifoControllerIndirect_android.h" #include "oboe_fifo_FifoBuffer_android.h" namespace oboe { FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames) : mBytesPerFrame(bytesPerFrame) , mStorage(nullptr) , mFramesReadCount(0) , mFramesUnderrunCount(0) { mFifo = std::make_unique(capacityInFrames); // allocate buffer int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames; mStorage = new uint8_t[bytesPerBuffer]; mStorageOwned = true; } FifoBuffer::FifoBuffer( uint32_t bytesPerFrame, uint32_t capacityInFrames, std::atomic *readCounterAddress, std::atomic *writeCounterAddress, uint8_t *dataStorageAddress ) : mBytesPerFrame(bytesPerFrame) , mStorage(dataStorageAddress) , mFramesReadCount(0) , mFramesUnderrunCount(0) { mFifo = std::make_unique(capacityInFrames, readCounterAddress, writeCounterAddress); mStorage = dataStorageAddress; mStorageOwned = false; } FifoBuffer::~FifoBuffer() { if (mStorageOwned) { delete[] mStorage; } } int32_t FifoBuffer::convertFramesToBytes(int32_t frames) { return frames * mBytesPerFrame; } int32_t FifoBuffer::read(void *buffer, int32_t numFrames) { if (numFrames <= 0) { return 0; } // safe because numFrames is guaranteed positive uint32_t framesToRead = static_cast(numFrames); uint32_t framesAvailable = mFifo->getFullFramesAvailable(); framesToRead = std::min(framesToRead, framesAvailable); uint32_t readIndex = mFifo->getReadIndex(); // ranges 0 to capacity uint8_t *destination = reinterpret_cast(buffer); uint8_t *source = &mStorage[convertFramesToBytes(readIndex)]; if ((readIndex + framesToRead) > mFifo->getFrameCapacity()) { // read in two parts, first part here is at the end of the mStorage buffer int32_t frames1 = static_cast(mFifo->getFrameCapacity() - readIndex); int32_t numBytes = convertFramesToBytes(frames1); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); destination += numBytes; // read second part, which is at the beginning of mStorage source = &mStorage[0]; int32_t frames2 = static_cast(framesToRead - frames1); numBytes = convertFramesToBytes(frames2); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); } else { // just read in one shot int32_t numBytes = convertFramesToBytes(framesToRead); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); } mFifo->advanceReadIndex(framesToRead); return framesToRead; } int32_t FifoBuffer::write(const void *buffer, int32_t numFrames) { if (numFrames <= 0) { return 0; } // Guaranteed positive. uint32_t framesToWrite = static_cast(numFrames); uint32_t framesAvailable = mFifo->getEmptyFramesAvailable(); framesToWrite = std::min(framesToWrite, framesAvailable); uint32_t writeIndex = mFifo->getWriteIndex(); int byteIndex = convertFramesToBytes(writeIndex); const uint8_t *source = reinterpret_cast(buffer); uint8_t *destination = &mStorage[byteIndex]; if ((writeIndex + framesToWrite) > mFifo->getFrameCapacity()) { // write in two parts, first part here int32_t frames1 = static_cast(mFifo->getFrameCapacity() - writeIndex); int32_t numBytes = convertFramesToBytes(frames1); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); // read second part source += convertFramesToBytes(frames1); destination = &mStorage[0]; int frames2 = static_cast(framesToWrite - frames1); numBytes = convertFramesToBytes(frames2); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); } else { // just write in one shot int32_t numBytes = convertFramesToBytes(framesToWrite); if (numBytes < 0) { return static_cast(Result::ErrorOutOfRange); } memcpy(destination, source, static_cast(numBytes)); } mFifo->advanceWriteIndex(framesToWrite); return framesToWrite; } int32_t FifoBuffer::readNow(void *buffer, int32_t numFrames) { int32_t framesRead = read(buffer, numFrames); if (framesRead < 0) { return framesRead; } int32_t framesLeft = numFrames - framesRead; mFramesReadCount += framesRead; mFramesUnderrunCount += framesLeft; // Zero out any samples we could not set. if (framesLeft > 0) { uint8_t *destination = reinterpret_cast(buffer); destination += convertFramesToBytes(framesRead); // point to first byte not set int32_t bytesToZero = convertFramesToBytes(framesLeft); memset(destination, 0, static_cast(bytesToZero)); } return framesRead; } uint32_t FifoBuffer::getBufferCapacityInFrames() const { return mFifo->getFrameCapacity(); } } // namespace oboe