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
28 namespace android {
29
NuPlayerStreamListener(const sp<IStreamSource> & source,const sp<AHandler> & targetHandler)30 NuPlayer::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
start()49 void NuPlayer::NuPlayerStreamListener::start() {
50 for (size_t i = 0; i < kNumBuffers; ++i) {
51 mSource->onBufferAvailable(i);
52 }
53 }
54
queueBuffer(size_t index,size_t size)55 void 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
issueCommand(Command cmd,bool synchronous,const sp<AMessage> & extra)74 void 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
read(void * data,size_t size,sp<AMessage> * extra)95 ssize_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