1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "NuPlayerStreamListener" 19#include <utils/Log.h> 20 21#include "NuPlayerStreamListener.h" 22 23#include <binder/MemoryDealer.h> 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/foundation/AMessage.h> 26#include <media/stagefright/MediaErrors.h> 27 28namespace android { 29 30NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener( 31 const sp<IStreamSource> &source, 32 const sp<AHandler> &targetHandler) 33 : mSource(source), 34 mTargetHandler(targetHandler), 35 mEOS(false), 36 mSendDataNotification(true) { 37 mSource->setListener(this); 38 39 mMemoryDealer = new MemoryDealer(kNumBuffers * kBufferSize); 40 for (size_t i = 0; i < kNumBuffers; ++i) { 41 sp<IMemory> mem = mMemoryDealer->allocate(kBufferSize); 42 CHECK(mem != NULL); 43 44 mBuffers.push(mem); 45 } 46 mSource->setBuffers(mBuffers); 47} 48 49void NuPlayer::NuPlayerStreamListener::start() { 50 for (size_t i = 0; i < kNumBuffers; ++i) { 51 mSource->onBufferAvailable(i); 52 } 53} 54 55void NuPlayer::NuPlayerStreamListener::queueBuffer(size_t index, size_t size) { 56 QueueEntry entry; 57 entry.mIsCommand = false; 58 entry.mIndex = index; 59 entry.mSize = size; 60 entry.mOffset = 0; 61 62 Mutex::Autolock autoLock(mLock); 63 mQueue.push_back(entry); 64 65 if (mSendDataNotification) { 66 mSendDataNotification = false; 67 68 if (mTargetHandler != NULL) { 69 (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post(); 70 } 71 } 72} 73 74void NuPlayer::NuPlayerStreamListener::issueCommand( 75 Command cmd, bool synchronous, const sp<AMessage> &extra) { 76 CHECK(!synchronous); 77 78 QueueEntry entry; 79 entry.mIsCommand = true; 80 entry.mCommand = cmd; 81 entry.mExtra = extra; 82 83 Mutex::Autolock autoLock(mLock); 84 mQueue.push_back(entry); 85 86 if (mSendDataNotification) { 87 mSendDataNotification = false; 88 89 if (mTargetHandler != NULL) { 90 (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post(); 91 } 92 } 93} 94 95ssize_t NuPlayer::NuPlayerStreamListener::read( 96 void *data, size_t size, sp<AMessage> *extra) { 97 CHECK_GT(size, 0u); 98 99 extra->clear(); 100 101 Mutex::Autolock autoLock(mLock); 102 103 if (mEOS) { 104 return 0; 105 } 106 107 if (mQueue.empty()) { 108 mSendDataNotification = true; 109 110 return -EWOULDBLOCK; 111 } 112 113 QueueEntry *entry = &*mQueue.begin(); 114 115 if (entry->mIsCommand) { 116 switch (entry->mCommand) { 117 case EOS: 118 { 119 mQueue.erase(mQueue.begin()); 120 entry = NULL; 121 122 mEOS = true; 123 return 0; 124 } 125 126 case DISCONTINUITY: 127 { 128 *extra = entry->mExtra; 129 130 mQueue.erase(mQueue.begin()); 131 entry = NULL; 132 133 return INFO_DISCONTINUITY; 134 } 135 136 default: 137 TRESPASS(); 138 break; 139 } 140 } 141 142 size_t copy = entry->mSize; 143 if (copy > size) { 144 copy = size; 145 } 146 147 if (entry->mIndex >= mBuffers.size()) { 148 return ERROR_MALFORMED; 149 } 150 151 sp<IMemory> mem = mBuffers.editItemAt(entry->mIndex); 152 if (mem == NULL || mem->size() < copy || mem->size() - copy < entry->mOffset) { 153 return ERROR_MALFORMED; 154 } 155 156 memcpy(data, 157 (const uint8_t *)mem->pointer() 158 + entry->mOffset, 159 copy); 160 161 entry->mOffset += copy; 162 entry->mSize -= copy; 163 164 if (entry->mSize == 0) { 165 mSource->onBufferAvailable(entry->mIndex); 166 mQueue.erase(mQueue.begin()); 167 entry = NULL; 168 } 169 170 return copy; 171} 172 173} // namespace android 174