/* * Copyright (C) 2010 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_NDEBUG 0 #define LOG_TAG "NuPlayerStreamListener" #include #include "NuPlayerStreamListener.h" #include #include #include #include namespace android { NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener( const sp &source, const sp &targetHandler) : mSource(source), mTargetHandler(targetHandler), mEOS(false), mSendDataNotification(true) { mSource->setListener(this); mMemoryDealer = new MemoryDealer(kNumBuffers * kBufferSize); for (size_t i = 0; i < kNumBuffers; ++i) { sp mem = mMemoryDealer->allocate(kBufferSize); CHECK(mem != NULL); mBuffers.push(mem); } mSource->setBuffers(mBuffers); } void NuPlayer::NuPlayerStreamListener::start() { for (size_t i = 0; i < kNumBuffers; ++i) { mSource->onBufferAvailable(i); } } void NuPlayer::NuPlayerStreamListener::queueBuffer(size_t index, size_t size) { QueueEntry entry; entry.mIsCommand = false; entry.mIndex = index; entry.mSize = size; entry.mOffset = 0; Mutex::Autolock autoLock(mLock); mQueue.push_back(entry); if (mSendDataNotification) { mSendDataNotification = false; if (mTargetHandler != NULL) { (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post(); } } } void NuPlayer::NuPlayerStreamListener::issueCommand( Command cmd, bool synchronous, const sp &extra) { CHECK(!synchronous); QueueEntry entry; entry.mIsCommand = true; entry.mCommand = cmd; entry.mExtra = extra; Mutex::Autolock autoLock(mLock); mQueue.push_back(entry); if (mSendDataNotification) { mSendDataNotification = false; if (mTargetHandler != NULL) { (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post(); } } } ssize_t NuPlayer::NuPlayerStreamListener::read( void *data, size_t size, sp *extra) { CHECK_GT(size, 0u); extra->clear(); Mutex::Autolock autoLock(mLock); if (mEOS) { return 0; } if (mQueue.empty()) { mSendDataNotification = true; return -EWOULDBLOCK; } QueueEntry *entry = &*mQueue.begin(); if (entry->mIsCommand) { switch (entry->mCommand) { case EOS: { mQueue.erase(mQueue.begin()); entry = NULL; mEOS = true; return 0; } case DISCONTINUITY: { *extra = entry->mExtra; mQueue.erase(mQueue.begin()); entry = NULL; return INFO_DISCONTINUITY; } default: TRESPASS(); break; } } size_t copy = entry->mSize; if (copy > size) { copy = size; } if (entry->mIndex >= mBuffers.size()) { return ERROR_MALFORMED; } sp mem = mBuffers.editItemAt(entry->mIndex); if (mem == NULL || mem->size() < copy || mem->size() - copy < entry->mOffset) { return ERROR_MALFORMED; } memcpy(data, (const uint8_t *)mem->pointer() + entry->mOffset, copy); entry->mOffset += copy; entry->mSize -= copy; if (entry->mSize == 0) { mSource->onBufferAvailable(entry->mIndex); mQueue.erase(mQueue.begin()); entry = NULL; } return copy; } } // namespace android