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     mMemoryDealer = new MemoryDealer(kNumBuffers * kBufferSize);
38     for (size_t i = 0; i < kNumBuffers; ++i) {
39         sp<IMemory> mem = mMemoryDealer->allocate(kBufferSize);
40         CHECK(mem != NULL);
41 
42         mBuffers.push(mem);
43     }
44     mSource->setBuffers(mBuffers);
45 }
46 
start()47 void NuPlayer::NuPlayerStreamListener::start() {
48     for (size_t i = 0; i < kNumBuffers; ++i) {
49         mSource->onBufferAvailable(i);
50     }
51 }
52 
queueBuffer(size_t index,size_t size)53 void NuPlayer::NuPlayerStreamListener::queueBuffer(size_t index, size_t size) {
54     QueueEntry entry;
55     entry.mIsCommand = false;
56     entry.mIndex = index;
57     entry.mSize = size;
58     entry.mOffset = 0;
59 
60     Mutex::Autolock autoLock(mLock);
61     mQueue.push_back(entry);
62 
63     if (mSendDataNotification) {
64         mSendDataNotification = false;
65 
66         if (mTargetHandler != NULL) {
67             (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
68         }
69     }
70 }
71 
issueCommand(Command cmd,bool synchronous,const sp<AMessage> & extra)72 void NuPlayer::NuPlayerStreamListener::issueCommand(
73         Command cmd, bool synchronous, const sp<AMessage> &extra) {
74     CHECK(!synchronous);
75 
76     QueueEntry entry;
77     entry.mIsCommand = true;
78     entry.mCommand = cmd;
79     entry.mExtra = extra;
80 
81     Mutex::Autolock autoLock(mLock);
82     mQueue.push_back(entry);
83 
84     if (mSendDataNotification) {
85         mSendDataNotification = false;
86 
87         if (mTargetHandler != NULL) {
88             (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
89         }
90     }
91 }
92 
read(void * data,size_t size,sp<AMessage> * extra)93 ssize_t NuPlayer::NuPlayerStreamListener::read(
94         void *data, size_t size, sp<AMessage> *extra) {
95     CHECK_GT(size, 0u);
96 
97     extra->clear();
98 
99     Mutex::Autolock autoLock(mLock);
100 
101     if (mEOS) {
102         return 0;
103     }
104 
105     if (mQueue.empty()) {
106         mSendDataNotification = true;
107 
108         return -EWOULDBLOCK;
109     }
110 
111     QueueEntry *entry = &*mQueue.begin();
112 
113     if (entry->mIsCommand) {
114         switch (entry->mCommand) {
115             case EOS:
116             {
117                 mQueue.erase(mQueue.begin());
118                 entry = NULL;
119 
120                 mEOS = true;
121                 return 0;
122             }
123 
124             case DISCONTINUITY:
125             {
126                 *extra = entry->mExtra;
127 
128                 mQueue.erase(mQueue.begin());
129                 entry = NULL;
130 
131                 return INFO_DISCONTINUITY;
132             }
133 
134             default:
135                 TRESPASS();
136                 break;
137         }
138     }
139 
140     size_t copy = entry->mSize;
141     if (copy > size) {
142         copy = size;
143     }
144 
145     if (entry->mIndex >= mBuffers.size()) {
146         return ERROR_MALFORMED;
147     }
148 
149     sp<IMemory> mem = mBuffers.editItemAt(entry->mIndex);
150     if (mem == NULL || mem->size() < copy || mem->size() - copy < entry->mOffset) {
151         return ERROR_MALFORMED;
152     }
153 
154     memcpy(data,
155            (const uint8_t *)mem->unsecurePointer()
156             + entry->mOffset,
157            copy);
158 
159     entry->mOffset += copy;
160     entry->mSize -= copy;
161 
162     if (entry->mSize == 0) {
163         mSource->onBufferAvailable(entry->mIndex);
164         mQueue.erase(mQueue.begin());
165         entry = NULL;
166     }
167 
168     return copy;
169 }
170 
171 }  // namespace android
172