/* * Copyright (C) 2014 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 "NuPlayerDecoderPassThrough" #include #include #include "NuPlayerDecoderPassThrough.h" #include #include #include #include #include #include namespace android { static const int kMaxPendingBuffers = 10; static const int kMaxCachedBytes = 200000; NuPlayer::DecoderPassThrough::DecoderPassThrough( const sp ¬ify) : Decoder(notify), mNotify(notify), mBufferGeneration(0), mReachedEOS(true), mPendingBuffers(0), mCachedBytes(0), mComponentName("pass through decoder") { mDecoderLooper = new ALooper; mDecoderLooper->setName("NuPlayerDecoderPassThrough"); mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); } NuPlayer::DecoderPassThrough::~DecoderPassThrough() { } void NuPlayer::DecoderPassThrough::configure(const sp &format) { sp msg = new AMessage(kWhatConfigure, id()); msg->setMessage("format", format); msg->post(); } void NuPlayer::DecoderPassThrough::init() { mDecoderLooper->registerHandler(this); } void NuPlayer::DecoderPassThrough::signalFlush() { (new AMessage(kWhatFlush, id()))->post(); } void NuPlayer::DecoderPassThrough::signalResume() { (new AMessage(kWhatResume, id()))->post(); } void NuPlayer::DecoderPassThrough::initiateShutdown() { (new AMessage(kWhatShutdown, id()))->post(); } bool NuPlayer::DecoderPassThrough::supportsSeamlessFormatChange( const sp & /* targetFormat */) const { return true; } void NuPlayer::DecoderPassThrough::onConfigure(const sp &format) { ALOGV("[%s] onConfigure", mComponentName.c_str()); mPendingBuffers = 0; mCachedBytes = 0; mReachedEOS = false; ++mBufferGeneration; requestABuffer(); sp notify = mNotify->dup(); notify->setInt32("what", kWhatOutputFormatChanged); notify->setMessage("format", format); notify->post(); } bool NuPlayer::DecoderPassThrough::isStaleReply(const sp &msg) { int32_t generation; CHECK(msg->findInt32("generation", &generation)); return generation != mBufferGeneration; } void NuPlayer::DecoderPassThrough::requestABuffer() { if (mCachedBytes >= kMaxCachedBytes || mReachedEOS) { ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)", mComponentName.c_str(), (mReachedEOS ? 1 : 0), mPendingBuffers, kMaxPendingBuffers); return; } sp reply = new AMessage(kWhatInputBufferFilled, id()); reply->setInt32("generation", mBufferGeneration); sp notify = mNotify->dup(); notify->setInt32("what", kWhatFillThisBuffer); notify->setMessage("reply", reply); notify->post(); mPendingBuffers++; // pending buffers will already result in requestABuffer if (mPendingBuffers < kMaxPendingBuffers) { sp message = new AMessage(kWhatRequestABuffer, id()); message->setInt32("generation", mBufferGeneration); message->post(); } return; } void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( const sp &msg) { if (mReachedEOS) { return; } sp buffer; msg->findBuffer("buffer", &buffer); if (buffer == NULL) { mReachedEOS = true; sp notify = mNotify->dup(); notify->setInt32("what", kWhatEOS); notify->setInt32("err", ERROR_END_OF_STREAM); notify->post(); return; } mCachedBytes += buffer->size(); sp reply = new AMessage(kWhatBufferConsumed, id()); reply->setInt32("generation", mBufferGeneration); reply->setInt32("size", buffer->size()); sp notify = mNotify->dup(); notify->setInt32("what", kWhatDrainThisBuffer); notify->setBuffer("buffer", buffer); notify->setMessage("reply", reply); notify->post(); } void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { mPendingBuffers--; mCachedBytes -= size; requestABuffer(); } void NuPlayer::DecoderPassThrough::onFlush() { ++mBufferGeneration; sp notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); mPendingBuffers = 0; mCachedBytes = 0; mReachedEOS = false; } void NuPlayer::DecoderPassThrough::onShutdown() { ++mBufferGeneration; sp notify = mNotify->dup(); notify->setInt32("what", kWhatShutdownCompleted); notify->post(); mReachedEOS = true; } void NuPlayer::DecoderPassThrough::onMessageReceived(const sp &msg) { ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); switch (msg->what()) { case kWhatConfigure: { sp format; CHECK(msg->findMessage("format", &format)); onConfigure(format); break; } case kWhatRequestABuffer: { if (!isStaleReply(msg)) { requestABuffer(); } break; } case kWhatInputBufferFilled: { if (!isStaleReply(msg)) { onInputBufferFilled(msg); } break; } case kWhatBufferConsumed: { if (!isStaleReply(msg)) { int32_t size; CHECK(msg->findInt32("size", &size)); onBufferConsumed(size); } break; } case kWhatFlush: { onFlush(); break; } case kWhatResume: { requestABuffer(); break; } case kWhatShutdown: { onShutdown(); break; } default: TRESPASS(); break; } } } // namespace android