blob: 323a3a09603ac87b67e302892a60a0900c235a61 [file] [log] [blame]
/*
* Copyright (C) 2011 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 USE_LOG SLAndroidLogLevel_Verbose
#include "sles_allinclusive.h"
#include "android/BufferQueueSource.h"
#include <media/stagefright/MediaDebug.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace android {
const SLuint32 BufferQueueSource::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
sizeof(SLuint32), // item size
SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
};
BufferQueueSource::BufferQueueSource(const void* user, void *context, const void *caller) :
mAndroidBufferQueueSource(NULL),
mStreamToBqOffset(0),
mEosReached(false)
{
if (NULL != user) {
mAndroidBufferQueueSource = &((CAudioPlayer*)user)->mAndroidBufferQueue;
} else {
SL_LOGE("Can't create BufferQueueSource with NULL user");
}
}
BufferQueueSource::~BufferQueueSource() {
SL_LOGD("BufferQueueSource::~BufferQueueSource");
}
//--------------------------------------------------------------------------
status_t BufferQueueSource::initCheck() const {
return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
}
ssize_t BufferQueueSource::readAt(off64_t offset, void *data, size_t size) {
SL_LOGD("BufferQueueSource::readAt(offset=%lld, data=%p, size=%d)", offset, data, size);
if (mEosReached) {
// once EOS has been received from the buffer queue, you can't read anymore
return 0;
}
ssize_t readSize;
slAndroidBufferQueueCallback callback = NULL;
void* pBufferContext, *pBufferData, *callbackPContext;
uint32_t dataSize, dataUsed;
interface_lock_exclusive(mAndroidBufferQueueSource);
if (mAndroidBufferQueueSource->mState.count == 0) {
readSize = 0;
} else {
assert(mAndroidBufferQueueSource->mFront != mAndroidBufferQueueSource->mRear);
AdvancedBufferHeader *oldFront = mAndroidBufferQueueSource->mFront;
AdvancedBufferHeader *newFront = &oldFront[1];
// where to read from
char *pSrc = NULL;
// can this read operation cause us to call the buffer queue callback
// (either because there was a command with no data, or all the data has been consumed)
bool queueCallbackCandidate = false;
// consume events when starting to read data from a buffer for the first time
if (oldFront->mDataSizeConsumed == 0) {
if (oldFront->mItems.mAdtsCmdData.mAdtsCmdCode & ANDROID_ADTSEVENT_EOS) {
mEosReached = true;
// EOS has no associated data
queueCallbackCandidate = true;
}
oldFront->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
}
//assert(mStreamToBqOffset <= offset);
CHECK(mStreamToBqOffset <= offset);
if (offset + size <= mStreamToBqOffset + oldFront->mDataSize) {
pSrc = ((char*)oldFront->mDataBuffer) + (offset - mStreamToBqOffset);
if (offset - mStreamToBqOffset + size == oldFront->mDataSize) {
// consumed buffer entirely
oldFront->mDataSizeConsumed = oldFront->mDataSize;
mStreamToBqOffset += oldFront->mDataSize;
queueCallbackCandidate = true;
// move queue to next buffer
if (newFront == &mAndroidBufferQueueSource->
mBufferArray[mAndroidBufferQueueSource->mNumBuffers + 1]) {
// reached the end, circle back
newFront = mAndroidBufferQueueSource->mBufferArray;
}
mAndroidBufferQueueSource->mFront = newFront;
// update the queue state
mAndroidBufferQueueSource->mState.count--;
mAndroidBufferQueueSource->mState.index++;
SL_LOGV("BufferQueueSource moving to next buffer");
}
}
// consume data: copy to given destination
if (NULL != pSrc) {
memcpy(data, pSrc, size);
readSize = size;
} else {
readSize = 0;
}
if (queueCallbackCandidate) {
// data has been consumed, and the buffer queue state has been updated
// we will notify the client if applicable
if (mAndroidBufferQueueSource->mCallbackEventsMask &
SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
callback = mAndroidBufferQueueSource->mCallback;
// save callback data while under lock
callbackPContext = mAndroidBufferQueueSource->mContext;
pBufferContext = (void *)oldFront->mBufferContext;
pBufferData = (void *)oldFront->mDataBuffer;
dataSize = oldFront->mDataSize;
dataUsed = oldFront->mDataSizeConsumed;
}
}
}
interface_unlock_exclusive(mAndroidBufferQueueSource);
// notify client
if (NULL != callback) {
SLresult result = (*callback)(&mAndroidBufferQueueSource->mItf, callbackPContext,
pBufferContext, pBufferData, dataSize, dataUsed,
// no messages during playback other than marking the buffer as processed
(const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
NB_BUFFEREVENT_ITEM_FIELDS * sizeof(SLuint32) /* itemsLength */ );
if (SL_RESULT_SUCCESS != result) {
// Reserved for future use
SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
}
}
return readSize;
}
status_t BufferQueueSource::getSize(off64_t *size) {
SL_LOGD("BufferQueueSource::getSize()");
// we're streaming, we don't know how much there is
*size = 0;
return OK;
}
} // namespace android