/*
* 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;
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