| /* |
| * Copyright (C) 2012 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. |
| */ |
| |
| #define LOG_TAG "SourceAudioBufferProvider" |
| //#define LOG_NDEBUG 0 |
| |
| #include <utils/Log.h> |
| #include <media/nbaio/SourceAudioBufferProvider.h> |
| |
| namespace android { |
| |
| SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) : |
| mSource(source), |
| // mFrameSize below |
| mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0) |
| { |
| ALOG_ASSERT(source != 0); |
| |
| // negotiate with source |
| NBAIO_Format counterOffers[1]; |
| size_t numCounterOffers = 1; |
| [[maybe_unused]] ssize_t index = source->negotiate(NULL, 0, counterOffers, numCounterOffers); |
| ALOG_ASSERT(index == (ssize_t) NEGOTIATE && numCounterOffers > 0); |
| numCounterOffers = 0; |
| index = source->negotiate(counterOffers, 1, NULL, numCounterOffers); |
| ALOG_ASSERT(index == 0); |
| mFrameSize = Format_frameSize(source->format()); |
| } |
| |
| SourceAudioBufferProvider::~SourceAudioBufferProvider() |
| { |
| free(mAllocated); |
| } |
| |
| status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer) |
| { |
| ALOG_ASSERT(buffer != NULL && buffer->frameCount > 0 && mGetCount == 0); |
| // any leftover data available? |
| if (mRemaining > 0) { |
| ALOG_ASSERT(mOffset + mRemaining <= mSize); |
| if (mRemaining < buffer->frameCount) { |
| buffer->frameCount = mRemaining; |
| } |
| buffer->raw = (char *) mAllocated + (mOffset * mFrameSize); |
| mGetCount = buffer->frameCount; |
| return OK; |
| } |
| // do we need to reallocate? |
| if (buffer->frameCount > mSize) { |
| free(mAllocated); |
| // Android convention is to _not_ check the return value of malloc and friends. |
| // But in this case the calloc() can also fail due to integer overflow, |
| // so we check and recover. |
| mAllocated = calloc(buffer->frameCount, mFrameSize); |
| if (mAllocated == NULL) { |
| mSize = 0; |
| goto fail; |
| } |
| mSize = buffer->frameCount; |
| } |
| { |
| // read from source |
| ssize_t actual = mSource->read(mAllocated, buffer->frameCount); |
| if (actual > 0) { |
| ALOG_ASSERT((size_t) actual <= buffer->frameCount); |
| mOffset = 0; |
| mRemaining = actual; |
| buffer->raw = mAllocated; |
| buffer->frameCount = actual; |
| mGetCount = actual; |
| return OK; |
| } |
| } |
| fail: |
| buffer->raw = NULL; |
| buffer->frameCount = 0; |
| mGetCount = 0; |
| return NOT_ENOUGH_DATA; |
| } |
| |
| void SourceAudioBufferProvider::releaseBuffer(Buffer *buffer) |
| { |
| ALOG_ASSERT((buffer != NULL) && |
| (buffer->raw == (char *) mAllocated + (mOffset * mFrameSize)) && |
| (buffer->frameCount <= mGetCount) && |
| (mGetCount <= mRemaining) && |
| (mOffset + mRemaining <= mSize)); |
| mOffset += buffer->frameCount; |
| mRemaining -= buffer->frameCount; |
| mFramesReleased += buffer->frameCount; |
| buffer->raw = NULL; |
| buffer->frameCount = 0; |
| mGetCount = 0; |
| } |
| |
| size_t SourceAudioBufferProvider::framesReady() const |
| { |
| ssize_t avail = mSource->availableToRead(); |
| return avail < 0 ? 0 : (size_t) avail; |
| } |
| |
| int64_t SourceAudioBufferProvider::framesReleased() const |
| { |
| return mFramesReleased; |
| } |
| |
| void SourceAudioBufferProvider::onTimestamp(const ExtendedTimestamp ×tamp) |
| { |
| mSource->onTimestamp(timestamp); |
| } |
| |
| } // namespace android |