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