1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
18*ec779b8eSAndroid Build Coastguard Worker
19*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
20*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NuCachedSource2"
21*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #include <datasource/NuCachedSource2.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <datasource/HTTPBase.h>
25*ec779b8eSAndroid Build Coastguard Worker
26*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ADebug.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/AMessage.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaErrors.h>
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker namespace android {
32*ec779b8eSAndroid Build Coastguard Worker
33*ec779b8eSAndroid Build Coastguard Worker struct PageCache {
34*ec779b8eSAndroid Build Coastguard Worker explicit PageCache(size_t pageSize);
35*ec779b8eSAndroid Build Coastguard Worker ~PageCache();
36*ec779b8eSAndroid Build Coastguard Worker
37*ec779b8eSAndroid Build Coastguard Worker struct Page {
38*ec779b8eSAndroid Build Coastguard Worker void *mData;
39*ec779b8eSAndroid Build Coastguard Worker size_t mSize;
40*ec779b8eSAndroid Build Coastguard Worker };
41*ec779b8eSAndroid Build Coastguard Worker
42*ec779b8eSAndroid Build Coastguard Worker Page *acquirePage();
43*ec779b8eSAndroid Build Coastguard Worker void releasePage(Page *page);
44*ec779b8eSAndroid Build Coastguard Worker
45*ec779b8eSAndroid Build Coastguard Worker void appendPage(Page *page);
46*ec779b8eSAndroid Build Coastguard Worker size_t releaseFromStart(size_t maxBytes);
47*ec779b8eSAndroid Build Coastguard Worker
totalSizeandroid::PageCache48*ec779b8eSAndroid Build Coastguard Worker size_t totalSize() const {
49*ec779b8eSAndroid Build Coastguard Worker return mTotalSize;
50*ec779b8eSAndroid Build Coastguard Worker }
51*ec779b8eSAndroid Build Coastguard Worker
52*ec779b8eSAndroid Build Coastguard Worker void copy(size_t from, void *data, size_t size);
53*ec779b8eSAndroid Build Coastguard Worker
54*ec779b8eSAndroid Build Coastguard Worker private:
55*ec779b8eSAndroid Build Coastguard Worker size_t mPageSize;
56*ec779b8eSAndroid Build Coastguard Worker size_t mTotalSize;
57*ec779b8eSAndroid Build Coastguard Worker
58*ec779b8eSAndroid Build Coastguard Worker List<Page *> mActivePages;
59*ec779b8eSAndroid Build Coastguard Worker List<Page *> mFreePages;
60*ec779b8eSAndroid Build Coastguard Worker
61*ec779b8eSAndroid Build Coastguard Worker void freePages(List<Page *> *list);
62*ec779b8eSAndroid Build Coastguard Worker
63*ec779b8eSAndroid Build Coastguard Worker DISALLOW_EVIL_CONSTRUCTORS(PageCache);
64*ec779b8eSAndroid Build Coastguard Worker };
65*ec779b8eSAndroid Build Coastguard Worker
PageCache(size_t pageSize)66*ec779b8eSAndroid Build Coastguard Worker PageCache::PageCache(size_t pageSize)
67*ec779b8eSAndroid Build Coastguard Worker : mPageSize(pageSize),
68*ec779b8eSAndroid Build Coastguard Worker mTotalSize(0) {
69*ec779b8eSAndroid Build Coastguard Worker }
70*ec779b8eSAndroid Build Coastguard Worker
~PageCache()71*ec779b8eSAndroid Build Coastguard Worker PageCache::~PageCache() {
72*ec779b8eSAndroid Build Coastguard Worker freePages(&mActivePages);
73*ec779b8eSAndroid Build Coastguard Worker freePages(&mFreePages);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker
freePages(List<Page * > * list)76*ec779b8eSAndroid Build Coastguard Worker void PageCache::freePages(List<Page *> *list) {
77*ec779b8eSAndroid Build Coastguard Worker List<Page *>::iterator it = list->begin();
78*ec779b8eSAndroid Build Coastguard Worker while (it != list->end()) {
79*ec779b8eSAndroid Build Coastguard Worker Page *page = *it;
80*ec779b8eSAndroid Build Coastguard Worker
81*ec779b8eSAndroid Build Coastguard Worker free(page->mData);
82*ec779b8eSAndroid Build Coastguard Worker delete page;
83*ec779b8eSAndroid Build Coastguard Worker page = NULL;
84*ec779b8eSAndroid Build Coastguard Worker
85*ec779b8eSAndroid Build Coastguard Worker ++it;
86*ec779b8eSAndroid Build Coastguard Worker }
87*ec779b8eSAndroid Build Coastguard Worker }
88*ec779b8eSAndroid Build Coastguard Worker
acquirePage()89*ec779b8eSAndroid Build Coastguard Worker PageCache::Page *PageCache::acquirePage() {
90*ec779b8eSAndroid Build Coastguard Worker if (!mFreePages.empty()) {
91*ec779b8eSAndroid Build Coastguard Worker List<Page *>::iterator it = mFreePages.begin();
92*ec779b8eSAndroid Build Coastguard Worker Page *page = *it;
93*ec779b8eSAndroid Build Coastguard Worker mFreePages.erase(it);
94*ec779b8eSAndroid Build Coastguard Worker
95*ec779b8eSAndroid Build Coastguard Worker return page;
96*ec779b8eSAndroid Build Coastguard Worker }
97*ec779b8eSAndroid Build Coastguard Worker
98*ec779b8eSAndroid Build Coastguard Worker Page *page = new Page;
99*ec779b8eSAndroid Build Coastguard Worker page->mData = malloc(mPageSize);
100*ec779b8eSAndroid Build Coastguard Worker page->mSize = 0;
101*ec779b8eSAndroid Build Coastguard Worker
102*ec779b8eSAndroid Build Coastguard Worker return page;
103*ec779b8eSAndroid Build Coastguard Worker }
104*ec779b8eSAndroid Build Coastguard Worker
releasePage(Page * page)105*ec779b8eSAndroid Build Coastguard Worker void PageCache::releasePage(Page *page) {
106*ec779b8eSAndroid Build Coastguard Worker page->mSize = 0;
107*ec779b8eSAndroid Build Coastguard Worker mFreePages.push_back(page);
108*ec779b8eSAndroid Build Coastguard Worker }
109*ec779b8eSAndroid Build Coastguard Worker
appendPage(Page * page)110*ec779b8eSAndroid Build Coastguard Worker void PageCache::appendPage(Page *page) {
111*ec779b8eSAndroid Build Coastguard Worker mTotalSize += page->mSize;
112*ec779b8eSAndroid Build Coastguard Worker mActivePages.push_back(page);
113*ec779b8eSAndroid Build Coastguard Worker }
114*ec779b8eSAndroid Build Coastguard Worker
releaseFromStart(size_t maxBytes)115*ec779b8eSAndroid Build Coastguard Worker size_t PageCache::releaseFromStart(size_t maxBytes) {
116*ec779b8eSAndroid Build Coastguard Worker size_t bytesReleased = 0;
117*ec779b8eSAndroid Build Coastguard Worker
118*ec779b8eSAndroid Build Coastguard Worker while (maxBytes > 0 && !mActivePages.empty()) {
119*ec779b8eSAndroid Build Coastguard Worker List<Page *>::iterator it = mActivePages.begin();
120*ec779b8eSAndroid Build Coastguard Worker
121*ec779b8eSAndroid Build Coastguard Worker Page *page = *it;
122*ec779b8eSAndroid Build Coastguard Worker
123*ec779b8eSAndroid Build Coastguard Worker if (maxBytes < page->mSize) {
124*ec779b8eSAndroid Build Coastguard Worker break;
125*ec779b8eSAndroid Build Coastguard Worker }
126*ec779b8eSAndroid Build Coastguard Worker
127*ec779b8eSAndroid Build Coastguard Worker mActivePages.erase(it);
128*ec779b8eSAndroid Build Coastguard Worker
129*ec779b8eSAndroid Build Coastguard Worker maxBytes -= page->mSize;
130*ec779b8eSAndroid Build Coastguard Worker bytesReleased += page->mSize;
131*ec779b8eSAndroid Build Coastguard Worker
132*ec779b8eSAndroid Build Coastguard Worker releasePage(page);
133*ec779b8eSAndroid Build Coastguard Worker }
134*ec779b8eSAndroid Build Coastguard Worker
135*ec779b8eSAndroid Build Coastguard Worker mTotalSize -= bytesReleased;
136*ec779b8eSAndroid Build Coastguard Worker return bytesReleased;
137*ec779b8eSAndroid Build Coastguard Worker }
138*ec779b8eSAndroid Build Coastguard Worker
copy(size_t from,void * data,size_t size)139*ec779b8eSAndroid Build Coastguard Worker void PageCache::copy(size_t from, void *data, size_t size) {
140*ec779b8eSAndroid Build Coastguard Worker ALOGV("copy from %zu size %zu", from, size);
141*ec779b8eSAndroid Build Coastguard Worker
142*ec779b8eSAndroid Build Coastguard Worker if (size == 0) {
143*ec779b8eSAndroid Build Coastguard Worker return;
144*ec779b8eSAndroid Build Coastguard Worker }
145*ec779b8eSAndroid Build Coastguard Worker
146*ec779b8eSAndroid Build Coastguard Worker CHECK_LE(from + size, mTotalSize);
147*ec779b8eSAndroid Build Coastguard Worker
148*ec779b8eSAndroid Build Coastguard Worker size_t offset = 0;
149*ec779b8eSAndroid Build Coastguard Worker List<Page *>::iterator it = mActivePages.begin();
150*ec779b8eSAndroid Build Coastguard Worker while (from >= offset + (*it)->mSize) {
151*ec779b8eSAndroid Build Coastguard Worker offset += (*it)->mSize;
152*ec779b8eSAndroid Build Coastguard Worker ++it;
153*ec779b8eSAndroid Build Coastguard Worker }
154*ec779b8eSAndroid Build Coastguard Worker
155*ec779b8eSAndroid Build Coastguard Worker size_t delta = from - offset;
156*ec779b8eSAndroid Build Coastguard Worker size_t avail = (*it)->mSize - delta;
157*ec779b8eSAndroid Build Coastguard Worker
158*ec779b8eSAndroid Build Coastguard Worker if (avail >= size) {
159*ec779b8eSAndroid Build Coastguard Worker memcpy(data, (const uint8_t *)(*it)->mData + delta, size);
160*ec779b8eSAndroid Build Coastguard Worker return;
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker
163*ec779b8eSAndroid Build Coastguard Worker memcpy(data, (const uint8_t *)(*it)->mData + delta, avail);
164*ec779b8eSAndroid Build Coastguard Worker ++it;
165*ec779b8eSAndroid Build Coastguard Worker data = (uint8_t *)data + avail;
166*ec779b8eSAndroid Build Coastguard Worker size -= avail;
167*ec779b8eSAndroid Build Coastguard Worker
168*ec779b8eSAndroid Build Coastguard Worker while (size > 0) {
169*ec779b8eSAndroid Build Coastguard Worker size_t copy = (*it)->mSize;
170*ec779b8eSAndroid Build Coastguard Worker if (copy > size) {
171*ec779b8eSAndroid Build Coastguard Worker copy = size;
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker memcpy(data, (*it)->mData, copy);
174*ec779b8eSAndroid Build Coastguard Worker data = (uint8_t *)data + copy;
175*ec779b8eSAndroid Build Coastguard Worker size -= copy;
176*ec779b8eSAndroid Build Coastguard Worker ++it;
177*ec779b8eSAndroid Build Coastguard Worker }
178*ec779b8eSAndroid Build Coastguard Worker }
179*ec779b8eSAndroid Build Coastguard Worker
180*ec779b8eSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
181*ec779b8eSAndroid Build Coastguard Worker
NuCachedSource2(const sp<DataSource> & source,const char * cacheConfig,bool disconnectAtHighwatermark)182*ec779b8eSAndroid Build Coastguard Worker NuCachedSource2::NuCachedSource2(
183*ec779b8eSAndroid Build Coastguard Worker const sp<DataSource> &source,
184*ec779b8eSAndroid Build Coastguard Worker const char *cacheConfig,
185*ec779b8eSAndroid Build Coastguard Worker bool disconnectAtHighwatermark)
186*ec779b8eSAndroid Build Coastguard Worker : mSource(source),
187*ec779b8eSAndroid Build Coastguard Worker mReflector(new AHandlerReflector<NuCachedSource2>(this)),
188*ec779b8eSAndroid Build Coastguard Worker mLooper(new ALooper),
189*ec779b8eSAndroid Build Coastguard Worker mCache(new PageCache(kPageSize)),
190*ec779b8eSAndroid Build Coastguard Worker mCacheOffset(0),
191*ec779b8eSAndroid Build Coastguard Worker mFinalStatus(OK),
192*ec779b8eSAndroid Build Coastguard Worker mLastAccessPos(0),
193*ec779b8eSAndroid Build Coastguard Worker mFetching(true),
194*ec779b8eSAndroid Build Coastguard Worker mDisconnecting(false),
195*ec779b8eSAndroid Build Coastguard Worker mLastFetchTimeUs(-1),
196*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft(kMaxNumRetries),
197*ec779b8eSAndroid Build Coastguard Worker mHighwaterThresholdBytes(kDefaultHighWaterThreshold),
198*ec779b8eSAndroid Build Coastguard Worker mLowwaterThresholdBytes(kDefaultLowWaterThreshold),
199*ec779b8eSAndroid Build Coastguard Worker mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs),
200*ec779b8eSAndroid Build Coastguard Worker mDisconnectAtHighwatermark(disconnectAtHighwatermark) {
201*ec779b8eSAndroid Build Coastguard Worker // We are NOT going to support disconnect-at-highwatermark indefinitely
202*ec779b8eSAndroid Build Coastguard Worker // and we are not guaranteeing support for client-specified cache
203*ec779b8eSAndroid Build Coastguard Worker // parameters. Both of these are temporary measures to solve a specific
204*ec779b8eSAndroid Build Coastguard Worker // problem that will be solved in a better way going forward.
205*ec779b8eSAndroid Build Coastguard Worker
206*ec779b8eSAndroid Build Coastguard Worker updateCacheParamsFromSystemProperty();
207*ec779b8eSAndroid Build Coastguard Worker
208*ec779b8eSAndroid Build Coastguard Worker if (cacheConfig != NULL) {
209*ec779b8eSAndroid Build Coastguard Worker updateCacheParamsFromString(cacheConfig);
210*ec779b8eSAndroid Build Coastguard Worker }
211*ec779b8eSAndroid Build Coastguard Worker
212*ec779b8eSAndroid Build Coastguard Worker if (mDisconnectAtHighwatermark) {
213*ec779b8eSAndroid Build Coastguard Worker // Makes no sense to disconnect and do keep-alives...
214*ec779b8eSAndroid Build Coastguard Worker mKeepAliveIntervalUs = 0;
215*ec779b8eSAndroid Build Coastguard Worker }
216*ec779b8eSAndroid Build Coastguard Worker
217*ec779b8eSAndroid Build Coastguard Worker mLooper->setName("NuCachedSource2");
218*ec779b8eSAndroid Build Coastguard Worker mLooper->registerHandler(mReflector);
219*ec779b8eSAndroid Build Coastguard Worker
220*ec779b8eSAndroid Build Coastguard Worker // Since it may not be obvious why our looper thread needs to be
221*ec779b8eSAndroid Build Coastguard Worker // able to call into java since it doesn't appear to do so at all...
222*ec779b8eSAndroid Build Coastguard Worker // IMediaHTTPConnection may be (and most likely is) implemented in JAVA
223*ec779b8eSAndroid Build Coastguard Worker // and a local JAVA IBinder will call directly into JNI methods.
224*ec779b8eSAndroid Build Coastguard Worker // So whenever we call DataSource::readAt it may end up in a call to
225*ec779b8eSAndroid Build Coastguard Worker // IMediaHTTPConnection::readAt and therefore call back into JAVA.
226*ec779b8eSAndroid Build Coastguard Worker mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
227*ec779b8eSAndroid Build Coastguard Worker
228*ec779b8eSAndroid Build Coastguard Worker mName = String8::format("NuCachedSource2(%s)", mSource->toString().c_str());
229*ec779b8eSAndroid Build Coastguard Worker }
230*ec779b8eSAndroid Build Coastguard Worker
~NuCachedSource2()231*ec779b8eSAndroid Build Coastguard Worker NuCachedSource2::~NuCachedSource2() {
232*ec779b8eSAndroid Build Coastguard Worker mLooper->stop();
233*ec779b8eSAndroid Build Coastguard Worker mLooper->unregisterHandler(mReflector->id());
234*ec779b8eSAndroid Build Coastguard Worker
235*ec779b8eSAndroid Build Coastguard Worker delete mCache;
236*ec779b8eSAndroid Build Coastguard Worker mCache = NULL;
237*ec779b8eSAndroid Build Coastguard Worker }
238*ec779b8eSAndroid Build Coastguard Worker
239*ec779b8eSAndroid Build Coastguard Worker // static
Create(const sp<DataSource> & source,const char * cacheConfig,bool disconnectAtHighwatermark)240*ec779b8eSAndroid Build Coastguard Worker sp<NuCachedSource2> NuCachedSource2::Create(
241*ec779b8eSAndroid Build Coastguard Worker const sp<DataSource> &source,
242*ec779b8eSAndroid Build Coastguard Worker const char *cacheConfig,
243*ec779b8eSAndroid Build Coastguard Worker bool disconnectAtHighwatermark) {
244*ec779b8eSAndroid Build Coastguard Worker sp<NuCachedSource2> instance = new NuCachedSource2(
245*ec779b8eSAndroid Build Coastguard Worker source, cacheConfig, disconnectAtHighwatermark);
246*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(instance->mLock);
247*ec779b8eSAndroid Build Coastguard Worker (new AMessage(kWhatFetchMore, instance->mReflector))->post();
248*ec779b8eSAndroid Build Coastguard Worker return instance;
249*ec779b8eSAndroid Build Coastguard Worker }
250*ec779b8eSAndroid Build Coastguard Worker
getEstimatedBandwidthKbps(int32_t * kbps)251*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
252*ec779b8eSAndroid Build Coastguard Worker if (mSource->flags() & kIsHTTPBasedSource) {
253*ec779b8eSAndroid Build Coastguard Worker HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
254*ec779b8eSAndroid Build Coastguard Worker return source->getEstimatedBandwidthKbps(kbps);
255*ec779b8eSAndroid Build Coastguard Worker }
256*ec779b8eSAndroid Build Coastguard Worker return ERROR_UNSUPPORTED;
257*ec779b8eSAndroid Build Coastguard Worker }
258*ec779b8eSAndroid Build Coastguard Worker
close()259*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::close() {
260*ec779b8eSAndroid Build Coastguard Worker disconnect();
261*ec779b8eSAndroid Build Coastguard Worker }
262*ec779b8eSAndroid Build Coastguard Worker
disconnect()263*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::disconnect() {
264*ec779b8eSAndroid Build Coastguard Worker if (mSource->flags() & kIsHTTPBasedSource) {
265*ec779b8eSAndroid Build Coastguard Worker ALOGV("disconnecting HTTPBasedSource");
266*ec779b8eSAndroid Build Coastguard Worker
267*ec779b8eSAndroid Build Coastguard Worker {
268*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
269*ec779b8eSAndroid Build Coastguard Worker // set mDisconnecting to true, if a fetch returns after
270*ec779b8eSAndroid Build Coastguard Worker // this, the source will be marked as EOS.
271*ec779b8eSAndroid Build Coastguard Worker mDisconnecting = true;
272*ec779b8eSAndroid Build Coastguard Worker
273*ec779b8eSAndroid Build Coastguard Worker // explicitly signal mCondition so that the pending readAt()
274*ec779b8eSAndroid Build Coastguard Worker // will immediately return
275*ec779b8eSAndroid Build Coastguard Worker mCondition.signal();
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker
278*ec779b8eSAndroid Build Coastguard Worker // explicitly disconnect from the source, to allow any
279*ec779b8eSAndroid Build Coastguard Worker // pending reads to return more promptly
280*ec779b8eSAndroid Build Coastguard Worker static_cast<HTTPBase *>(mSource.get())->disconnect();
281*ec779b8eSAndroid Build Coastguard Worker }
282*ec779b8eSAndroid Build Coastguard Worker }
283*ec779b8eSAndroid Build Coastguard Worker
setCacheStatCollectFreq(int32_t freqMs)284*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) {
285*ec779b8eSAndroid Build Coastguard Worker if (mSource->flags() & kIsHTTPBasedSource) {
286*ec779b8eSAndroid Build Coastguard Worker HTTPBase *source = static_cast<HTTPBase *>(mSource.get());
287*ec779b8eSAndroid Build Coastguard Worker return source->setBandwidthStatCollectFreq(freqMs);
288*ec779b8eSAndroid Build Coastguard Worker }
289*ec779b8eSAndroid Build Coastguard Worker return ERROR_UNSUPPORTED;
290*ec779b8eSAndroid Build Coastguard Worker }
291*ec779b8eSAndroid Build Coastguard Worker
initCheck() const292*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::initCheck() const {
293*ec779b8eSAndroid Build Coastguard Worker return mSource->initCheck();
294*ec779b8eSAndroid Build Coastguard Worker }
295*ec779b8eSAndroid Build Coastguard Worker
getSize(off64_t * size)296*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::getSize(off64_t *size) {
297*ec779b8eSAndroid Build Coastguard Worker return mSource->getSize(size);
298*ec779b8eSAndroid Build Coastguard Worker }
299*ec779b8eSAndroid Build Coastguard Worker
flags()300*ec779b8eSAndroid Build Coastguard Worker uint32_t NuCachedSource2::flags() {
301*ec779b8eSAndroid Build Coastguard Worker // Remove HTTP related flags since NuCachedSource2 is not HTTP-based.
302*ec779b8eSAndroid Build Coastguard Worker uint32_t flags = mSource->flags() & ~(kWantsPrefetching | kIsHTTPBasedSource);
303*ec779b8eSAndroid Build Coastguard Worker return (flags | kIsCachingDataSource);
304*ec779b8eSAndroid Build Coastguard Worker }
305*ec779b8eSAndroid Build Coastguard Worker
onMessageReceived(const sp<AMessage> & msg)306*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) {
307*ec779b8eSAndroid Build Coastguard Worker switch (msg->what()) {
308*ec779b8eSAndroid Build Coastguard Worker case kWhatFetchMore:
309*ec779b8eSAndroid Build Coastguard Worker {
310*ec779b8eSAndroid Build Coastguard Worker onFetch();
311*ec779b8eSAndroid Build Coastguard Worker break;
312*ec779b8eSAndroid Build Coastguard Worker }
313*ec779b8eSAndroid Build Coastguard Worker
314*ec779b8eSAndroid Build Coastguard Worker case kWhatRead:
315*ec779b8eSAndroid Build Coastguard Worker {
316*ec779b8eSAndroid Build Coastguard Worker onRead(msg);
317*ec779b8eSAndroid Build Coastguard Worker break;
318*ec779b8eSAndroid Build Coastguard Worker }
319*ec779b8eSAndroid Build Coastguard Worker
320*ec779b8eSAndroid Build Coastguard Worker default:
321*ec779b8eSAndroid Build Coastguard Worker TRESPASS();
322*ec779b8eSAndroid Build Coastguard Worker }
323*ec779b8eSAndroid Build Coastguard Worker }
324*ec779b8eSAndroid Build Coastguard Worker
fetchInternal()325*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::fetchInternal() {
326*ec779b8eSAndroid Build Coastguard Worker ALOGV("fetchInternal");
327*ec779b8eSAndroid Build Coastguard Worker
328*ec779b8eSAndroid Build Coastguard Worker bool reconnect = false;
329*ec779b8eSAndroid Build Coastguard Worker
330*ec779b8eSAndroid Build Coastguard Worker {
331*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
332*ec779b8eSAndroid Build Coastguard Worker CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
333*ec779b8eSAndroid Build Coastguard Worker
334*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK) {
335*ec779b8eSAndroid Build Coastguard Worker --mNumRetriesLeft;
336*ec779b8eSAndroid Build Coastguard Worker
337*ec779b8eSAndroid Build Coastguard Worker reconnect = true;
338*ec779b8eSAndroid Build Coastguard Worker }
339*ec779b8eSAndroid Build Coastguard Worker }
340*ec779b8eSAndroid Build Coastguard Worker
341*ec779b8eSAndroid Build Coastguard Worker if (reconnect) {
342*ec779b8eSAndroid Build Coastguard Worker status_t err =
343*ec779b8eSAndroid Build Coastguard Worker mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
344*ec779b8eSAndroid Build Coastguard Worker
345*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
346*ec779b8eSAndroid Build Coastguard Worker
347*ec779b8eSAndroid Build Coastguard Worker if (mDisconnecting) {
348*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = 0;
349*ec779b8eSAndroid Build Coastguard Worker mFinalStatus = ERROR_END_OF_STREAM;
350*ec779b8eSAndroid Build Coastguard Worker return;
351*ec779b8eSAndroid Build Coastguard Worker } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
352*ec779b8eSAndroid Build Coastguard Worker // These are errors that are not likely to go away even if we
353*ec779b8eSAndroid Build Coastguard Worker // retry, i.e. the server doesn't support range requests or similar.
354*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = 0;
355*ec779b8eSAndroid Build Coastguard Worker return;
356*ec779b8eSAndroid Build Coastguard Worker } else if (err != OK) {
357*ec779b8eSAndroid Build Coastguard Worker ALOGI("The attempt to reconnect failed, %d retries remaining",
358*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft);
359*ec779b8eSAndroid Build Coastguard Worker
360*ec779b8eSAndroid Build Coastguard Worker return;
361*ec779b8eSAndroid Build Coastguard Worker }
362*ec779b8eSAndroid Build Coastguard Worker }
363*ec779b8eSAndroid Build Coastguard Worker
364*ec779b8eSAndroid Build Coastguard Worker PageCache::Page *page = mCache->acquirePage();
365*ec779b8eSAndroid Build Coastguard Worker
366*ec779b8eSAndroid Build Coastguard Worker ssize_t n = mSource->readAt(
367*ec779b8eSAndroid Build Coastguard Worker mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
368*ec779b8eSAndroid Build Coastguard Worker
369*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
370*ec779b8eSAndroid Build Coastguard Worker
371*ec779b8eSAndroid Build Coastguard Worker if (n == 0 || mDisconnecting) {
372*ec779b8eSAndroid Build Coastguard Worker ALOGI("caching reached eos.");
373*ec779b8eSAndroid Build Coastguard Worker
374*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = 0;
375*ec779b8eSAndroid Build Coastguard Worker mFinalStatus = ERROR_END_OF_STREAM;
376*ec779b8eSAndroid Build Coastguard Worker
377*ec779b8eSAndroid Build Coastguard Worker mCache->releasePage(page);
378*ec779b8eSAndroid Build Coastguard Worker } else if (n < 0) {
379*ec779b8eSAndroid Build Coastguard Worker mFinalStatus = n;
380*ec779b8eSAndroid Build Coastguard Worker if (n == ERROR_UNSUPPORTED || n == -EPIPE) {
381*ec779b8eSAndroid Build Coastguard Worker // These are errors that are not likely to go away even if we
382*ec779b8eSAndroid Build Coastguard Worker // retry, i.e. the server doesn't support range requests or similar.
383*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = 0;
384*ec779b8eSAndroid Build Coastguard Worker }
385*ec779b8eSAndroid Build Coastguard Worker
386*ec779b8eSAndroid Build Coastguard Worker ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft);
387*ec779b8eSAndroid Build Coastguard Worker mCache->releasePage(page);
388*ec779b8eSAndroid Build Coastguard Worker } else {
389*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK) {
390*ec779b8eSAndroid Build Coastguard Worker ALOGI("retrying a previously failed read succeeded.");
391*ec779b8eSAndroid Build Coastguard Worker }
392*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = kMaxNumRetries;
393*ec779b8eSAndroid Build Coastguard Worker mFinalStatus = OK;
394*ec779b8eSAndroid Build Coastguard Worker
395*ec779b8eSAndroid Build Coastguard Worker page->mSize = n;
396*ec779b8eSAndroid Build Coastguard Worker mCache->appendPage(page);
397*ec779b8eSAndroid Build Coastguard Worker }
398*ec779b8eSAndroid Build Coastguard Worker }
399*ec779b8eSAndroid Build Coastguard Worker
onFetch()400*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::onFetch() {
401*ec779b8eSAndroid Build Coastguard Worker ALOGV("onFetch");
402*ec779b8eSAndroid Build Coastguard Worker
403*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK && mNumRetriesLeft == 0) {
404*ec779b8eSAndroid Build Coastguard Worker ALOGV("EOS reached, done prefetching for now");
405*ec779b8eSAndroid Build Coastguard Worker mFetching = false;
406*ec779b8eSAndroid Build Coastguard Worker }
407*ec779b8eSAndroid Build Coastguard Worker
408*ec779b8eSAndroid Build Coastguard Worker bool keepAlive =
409*ec779b8eSAndroid Build Coastguard Worker !mFetching
410*ec779b8eSAndroid Build Coastguard Worker && mFinalStatus == OK
411*ec779b8eSAndroid Build Coastguard Worker && mKeepAliveIntervalUs > 0
412*ec779b8eSAndroid Build Coastguard Worker && ALooper::GetNowUs() >= mLastFetchTimeUs + mKeepAliveIntervalUs;
413*ec779b8eSAndroid Build Coastguard Worker
414*ec779b8eSAndroid Build Coastguard Worker if (mFetching || keepAlive) {
415*ec779b8eSAndroid Build Coastguard Worker if (keepAlive) {
416*ec779b8eSAndroid Build Coastguard Worker ALOGI("Keep alive");
417*ec779b8eSAndroid Build Coastguard Worker }
418*ec779b8eSAndroid Build Coastguard Worker
419*ec779b8eSAndroid Build Coastguard Worker fetchInternal();
420*ec779b8eSAndroid Build Coastguard Worker
421*ec779b8eSAndroid Build Coastguard Worker mLastFetchTimeUs = ALooper::GetNowUs();
422*ec779b8eSAndroid Build Coastguard Worker
423*ec779b8eSAndroid Build Coastguard Worker if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) {
424*ec779b8eSAndroid Build Coastguard Worker ALOGI("Cache full, done prefetching for now");
425*ec779b8eSAndroid Build Coastguard Worker mFetching = false;
426*ec779b8eSAndroid Build Coastguard Worker
427*ec779b8eSAndroid Build Coastguard Worker if (mDisconnectAtHighwatermark
428*ec779b8eSAndroid Build Coastguard Worker && (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
429*ec779b8eSAndroid Build Coastguard Worker ALOGV("Disconnecting at high watermark");
430*ec779b8eSAndroid Build Coastguard Worker static_cast<HTTPBase *>(mSource.get())->disconnect();
431*ec779b8eSAndroid Build Coastguard Worker mFinalStatus = -EAGAIN;
432*ec779b8eSAndroid Build Coastguard Worker }
433*ec779b8eSAndroid Build Coastguard Worker }
434*ec779b8eSAndroid Build Coastguard Worker } else {
435*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
436*ec779b8eSAndroid Build Coastguard Worker restartPrefetcherIfNecessary_l();
437*ec779b8eSAndroid Build Coastguard Worker }
438*ec779b8eSAndroid Build Coastguard Worker
439*ec779b8eSAndroid Build Coastguard Worker int64_t delayUs;
440*ec779b8eSAndroid Build Coastguard Worker if (mFetching) {
441*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK && mNumRetriesLeft > 0) {
442*ec779b8eSAndroid Build Coastguard Worker // We failed this time and will try again in 3 seconds.
443*ec779b8eSAndroid Build Coastguard Worker delayUs = 3000000LL;
444*ec779b8eSAndroid Build Coastguard Worker } else {
445*ec779b8eSAndroid Build Coastguard Worker delayUs = 0;
446*ec779b8eSAndroid Build Coastguard Worker }
447*ec779b8eSAndroid Build Coastguard Worker } else {
448*ec779b8eSAndroid Build Coastguard Worker delayUs = 100000LL;
449*ec779b8eSAndroid Build Coastguard Worker }
450*ec779b8eSAndroid Build Coastguard Worker
451*ec779b8eSAndroid Build Coastguard Worker (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
452*ec779b8eSAndroid Build Coastguard Worker }
453*ec779b8eSAndroid Build Coastguard Worker
onRead(const sp<AMessage> & msg)454*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::onRead(const sp<AMessage> &msg) {
455*ec779b8eSAndroid Build Coastguard Worker ALOGV("onRead");
456*ec779b8eSAndroid Build Coastguard Worker
457*ec779b8eSAndroid Build Coastguard Worker int64_t offset;
458*ec779b8eSAndroid Build Coastguard Worker CHECK(msg->findInt64("offset", &offset));
459*ec779b8eSAndroid Build Coastguard Worker
460*ec779b8eSAndroid Build Coastguard Worker void *data;
461*ec779b8eSAndroid Build Coastguard Worker CHECK(msg->findPointer("data", &data));
462*ec779b8eSAndroid Build Coastguard Worker
463*ec779b8eSAndroid Build Coastguard Worker size_t size;
464*ec779b8eSAndroid Build Coastguard Worker CHECK(msg->findSize("size", &size));
465*ec779b8eSAndroid Build Coastguard Worker
466*ec779b8eSAndroid Build Coastguard Worker ssize_t result = readInternal(offset, data, size);
467*ec779b8eSAndroid Build Coastguard Worker
468*ec779b8eSAndroid Build Coastguard Worker if (result == -EAGAIN) {
469*ec779b8eSAndroid Build Coastguard Worker msg->post(50000);
470*ec779b8eSAndroid Build Coastguard Worker return;
471*ec779b8eSAndroid Build Coastguard Worker }
472*ec779b8eSAndroid Build Coastguard Worker
473*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
474*ec779b8eSAndroid Build Coastguard Worker if (mDisconnecting) {
475*ec779b8eSAndroid Build Coastguard Worker mCondition.signal();
476*ec779b8eSAndroid Build Coastguard Worker return;
477*ec779b8eSAndroid Build Coastguard Worker }
478*ec779b8eSAndroid Build Coastguard Worker
479*ec779b8eSAndroid Build Coastguard Worker CHECK(mAsyncResult == NULL);
480*ec779b8eSAndroid Build Coastguard Worker
481*ec779b8eSAndroid Build Coastguard Worker mAsyncResult = new AMessage;
482*ec779b8eSAndroid Build Coastguard Worker mAsyncResult->setInt32("result", result);
483*ec779b8eSAndroid Build Coastguard Worker
484*ec779b8eSAndroid Build Coastguard Worker mCondition.signal();
485*ec779b8eSAndroid Build Coastguard Worker }
486*ec779b8eSAndroid Build Coastguard Worker
restartPrefetcherIfNecessary_l(bool ignoreLowWaterThreshold,bool force)487*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::restartPrefetcherIfNecessary_l(
488*ec779b8eSAndroid Build Coastguard Worker bool ignoreLowWaterThreshold, bool force) {
489*ec779b8eSAndroid Build Coastguard Worker static const size_t kGrayArea = 1024 * 1024;
490*ec779b8eSAndroid Build Coastguard Worker
491*ec779b8eSAndroid Build Coastguard Worker if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
492*ec779b8eSAndroid Build Coastguard Worker return;
493*ec779b8eSAndroid Build Coastguard Worker }
494*ec779b8eSAndroid Build Coastguard Worker
495*ec779b8eSAndroid Build Coastguard Worker if (!ignoreLowWaterThreshold && !force
496*ec779b8eSAndroid Build Coastguard Worker && mCacheOffset + mCache->totalSize() - mLastAccessPos
497*ec779b8eSAndroid Build Coastguard Worker >= mLowwaterThresholdBytes) {
498*ec779b8eSAndroid Build Coastguard Worker return;
499*ec779b8eSAndroid Build Coastguard Worker }
500*ec779b8eSAndroid Build Coastguard Worker
501*ec779b8eSAndroid Build Coastguard Worker size_t maxBytes = mLastAccessPos - mCacheOffset;
502*ec779b8eSAndroid Build Coastguard Worker
503*ec779b8eSAndroid Build Coastguard Worker if (!force) {
504*ec779b8eSAndroid Build Coastguard Worker if (maxBytes < kGrayArea) {
505*ec779b8eSAndroid Build Coastguard Worker return;
506*ec779b8eSAndroid Build Coastguard Worker }
507*ec779b8eSAndroid Build Coastguard Worker
508*ec779b8eSAndroid Build Coastguard Worker maxBytes -= kGrayArea;
509*ec779b8eSAndroid Build Coastguard Worker }
510*ec779b8eSAndroid Build Coastguard Worker
511*ec779b8eSAndroid Build Coastguard Worker size_t actualBytes = mCache->releaseFromStart(maxBytes);
512*ec779b8eSAndroid Build Coastguard Worker mCacheOffset += actualBytes;
513*ec779b8eSAndroid Build Coastguard Worker
514*ec779b8eSAndroid Build Coastguard Worker ALOGI("restarting prefetcher, totalSize = %zu", mCache->totalSize());
515*ec779b8eSAndroid Build Coastguard Worker mFetching = true;
516*ec779b8eSAndroid Build Coastguard Worker }
517*ec779b8eSAndroid Build Coastguard Worker
readAt(off64_t offset,void * data,size_t size)518*ec779b8eSAndroid Build Coastguard Worker ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
519*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoSerializer(mSerializer);
520*ec779b8eSAndroid Build Coastguard Worker
521*ec779b8eSAndroid Build Coastguard Worker ALOGV("readAt offset %lld, size %zu", (long long)offset, size);
522*ec779b8eSAndroid Build Coastguard Worker
523*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
524*ec779b8eSAndroid Build Coastguard Worker if (mDisconnecting) {
525*ec779b8eSAndroid Build Coastguard Worker return ERROR_END_OF_STREAM;
526*ec779b8eSAndroid Build Coastguard Worker }
527*ec779b8eSAndroid Build Coastguard Worker
528*ec779b8eSAndroid Build Coastguard Worker // If the request can be completely satisfied from the cache, do so.
529*ec779b8eSAndroid Build Coastguard Worker
530*ec779b8eSAndroid Build Coastguard Worker if (offset >= mCacheOffset
531*ec779b8eSAndroid Build Coastguard Worker && offset + size <= mCacheOffset + mCache->totalSize()) {
532*ec779b8eSAndroid Build Coastguard Worker size_t delta = offset - mCacheOffset;
533*ec779b8eSAndroid Build Coastguard Worker mCache->copy(delta, data, size);
534*ec779b8eSAndroid Build Coastguard Worker
535*ec779b8eSAndroid Build Coastguard Worker mLastAccessPos = offset + size;
536*ec779b8eSAndroid Build Coastguard Worker
537*ec779b8eSAndroid Build Coastguard Worker return size;
538*ec779b8eSAndroid Build Coastguard Worker }
539*ec779b8eSAndroid Build Coastguard Worker
540*ec779b8eSAndroid Build Coastguard Worker sp<AMessage> msg = new AMessage(kWhatRead, mReflector);
541*ec779b8eSAndroid Build Coastguard Worker msg->setInt64("offset", offset);
542*ec779b8eSAndroid Build Coastguard Worker msg->setPointer("data", data);
543*ec779b8eSAndroid Build Coastguard Worker msg->setSize("size", size);
544*ec779b8eSAndroid Build Coastguard Worker
545*ec779b8eSAndroid Build Coastguard Worker CHECK(mAsyncResult == NULL);
546*ec779b8eSAndroid Build Coastguard Worker msg->post();
547*ec779b8eSAndroid Build Coastguard Worker
548*ec779b8eSAndroid Build Coastguard Worker while (mAsyncResult == NULL && !mDisconnecting) {
549*ec779b8eSAndroid Build Coastguard Worker mCondition.wait(mLock);
550*ec779b8eSAndroid Build Coastguard Worker }
551*ec779b8eSAndroid Build Coastguard Worker
552*ec779b8eSAndroid Build Coastguard Worker if (mDisconnecting) {
553*ec779b8eSAndroid Build Coastguard Worker mAsyncResult.clear();
554*ec779b8eSAndroid Build Coastguard Worker return ERROR_END_OF_STREAM;
555*ec779b8eSAndroid Build Coastguard Worker }
556*ec779b8eSAndroid Build Coastguard Worker
557*ec779b8eSAndroid Build Coastguard Worker int32_t result;
558*ec779b8eSAndroid Build Coastguard Worker CHECK(mAsyncResult->findInt32("result", &result));
559*ec779b8eSAndroid Build Coastguard Worker
560*ec779b8eSAndroid Build Coastguard Worker mAsyncResult.clear();
561*ec779b8eSAndroid Build Coastguard Worker
562*ec779b8eSAndroid Build Coastguard Worker if (result > 0) {
563*ec779b8eSAndroid Build Coastguard Worker mLastAccessPos = offset + result;
564*ec779b8eSAndroid Build Coastguard Worker }
565*ec779b8eSAndroid Build Coastguard Worker
566*ec779b8eSAndroid Build Coastguard Worker return (ssize_t)result;
567*ec779b8eSAndroid Build Coastguard Worker }
568*ec779b8eSAndroid Build Coastguard Worker
cachedSize()569*ec779b8eSAndroid Build Coastguard Worker size_t NuCachedSource2::cachedSize() {
570*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
571*ec779b8eSAndroid Build Coastguard Worker return mCacheOffset + mCache->totalSize();
572*ec779b8eSAndroid Build Coastguard Worker }
573*ec779b8eSAndroid Build Coastguard Worker
getAvailableSize(off64_t offset,off64_t * size)574*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
575*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
576*ec779b8eSAndroid Build Coastguard Worker status_t finalStatus = UNKNOWN_ERROR;
577*ec779b8eSAndroid Build Coastguard Worker *size = approxDataRemaining_l(offset, &finalStatus);
578*ec779b8eSAndroid Build Coastguard Worker return finalStatus;
579*ec779b8eSAndroid Build Coastguard Worker }
580*ec779b8eSAndroid Build Coastguard Worker
approxDataRemaining(status_t * finalStatus) const581*ec779b8eSAndroid Build Coastguard Worker size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
582*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
583*ec779b8eSAndroid Build Coastguard Worker return approxDataRemaining_l(mLastAccessPos, finalStatus);
584*ec779b8eSAndroid Build Coastguard Worker }
585*ec779b8eSAndroid Build Coastguard Worker
approxDataRemaining_l(off64_t offset,status_t * finalStatus) const586*ec779b8eSAndroid Build Coastguard Worker size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
587*ec779b8eSAndroid Build Coastguard Worker *finalStatus = mFinalStatus;
588*ec779b8eSAndroid Build Coastguard Worker
589*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK && mNumRetriesLeft > 0) {
590*ec779b8eSAndroid Build Coastguard Worker // Pretend that everything is fine until we're out of retries.
591*ec779b8eSAndroid Build Coastguard Worker *finalStatus = OK;
592*ec779b8eSAndroid Build Coastguard Worker }
593*ec779b8eSAndroid Build Coastguard Worker
594*ec779b8eSAndroid Build Coastguard Worker offset = offset >= 0 ? offset : mLastAccessPos;
595*ec779b8eSAndroid Build Coastguard Worker off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
596*ec779b8eSAndroid Build Coastguard Worker if (offset < lastBytePosCached) {
597*ec779b8eSAndroid Build Coastguard Worker return lastBytePosCached - offset;
598*ec779b8eSAndroid Build Coastguard Worker }
599*ec779b8eSAndroid Build Coastguard Worker return 0;
600*ec779b8eSAndroid Build Coastguard Worker }
601*ec779b8eSAndroid Build Coastguard Worker
readInternal(off64_t offset,void * data,size_t size)602*ec779b8eSAndroid Build Coastguard Worker ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
603*ec779b8eSAndroid Build Coastguard Worker CHECK_LE(size, (size_t)mHighwaterThresholdBytes);
604*ec779b8eSAndroid Build Coastguard Worker
605*ec779b8eSAndroid Build Coastguard Worker ALOGV("readInternal offset %lld size %zu", (long long)offset, size);
606*ec779b8eSAndroid Build Coastguard Worker
607*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
608*ec779b8eSAndroid Build Coastguard Worker
609*ec779b8eSAndroid Build Coastguard Worker // If we're disconnecting, return EOS and don't access *data pointer.
610*ec779b8eSAndroid Build Coastguard Worker // data could be on the stack of the caller to NuCachedSource2::readAt(),
611*ec779b8eSAndroid Build Coastguard Worker // which may have exited already.
612*ec779b8eSAndroid Build Coastguard Worker if (mDisconnecting) {
613*ec779b8eSAndroid Build Coastguard Worker return ERROR_END_OF_STREAM;
614*ec779b8eSAndroid Build Coastguard Worker }
615*ec779b8eSAndroid Build Coastguard Worker
616*ec779b8eSAndroid Build Coastguard Worker if (!mFetching) {
617*ec779b8eSAndroid Build Coastguard Worker mLastAccessPos = offset;
618*ec779b8eSAndroid Build Coastguard Worker restartPrefetcherIfNecessary_l(
619*ec779b8eSAndroid Build Coastguard Worker false, // ignoreLowWaterThreshold
620*ec779b8eSAndroid Build Coastguard Worker true); // force
621*ec779b8eSAndroid Build Coastguard Worker }
622*ec779b8eSAndroid Build Coastguard Worker
623*ec779b8eSAndroid Build Coastguard Worker if (offset < mCacheOffset
624*ec779b8eSAndroid Build Coastguard Worker || offset >= (off64_t)(mCacheOffset + mCache->totalSize())) {
625*ec779b8eSAndroid Build Coastguard Worker static const off64_t kPadding = 256 * 1024;
626*ec779b8eSAndroid Build Coastguard Worker
627*ec779b8eSAndroid Build Coastguard Worker // In the presence of multiple decoded streams, once of them will
628*ec779b8eSAndroid Build Coastguard Worker // trigger this seek request, the other one will request data "nearby"
629*ec779b8eSAndroid Build Coastguard Worker // soon, adjust the seek position so that that subsequent request
630*ec779b8eSAndroid Build Coastguard Worker // does not trigger another seek.
631*ec779b8eSAndroid Build Coastguard Worker off64_t seekOffset = (offset > kPadding) ? offset - kPadding : 0;
632*ec779b8eSAndroid Build Coastguard Worker
633*ec779b8eSAndroid Build Coastguard Worker seekInternal_l(seekOffset);
634*ec779b8eSAndroid Build Coastguard Worker }
635*ec779b8eSAndroid Build Coastguard Worker
636*ec779b8eSAndroid Build Coastguard Worker size_t delta = offset - mCacheOffset;
637*ec779b8eSAndroid Build Coastguard Worker
638*ec779b8eSAndroid Build Coastguard Worker if (mFinalStatus != OK && mNumRetriesLeft == 0) {
639*ec779b8eSAndroid Build Coastguard Worker if (delta >= mCache->totalSize()) {
640*ec779b8eSAndroid Build Coastguard Worker return mFinalStatus;
641*ec779b8eSAndroid Build Coastguard Worker }
642*ec779b8eSAndroid Build Coastguard Worker
643*ec779b8eSAndroid Build Coastguard Worker size_t avail = mCache->totalSize() - delta;
644*ec779b8eSAndroid Build Coastguard Worker
645*ec779b8eSAndroid Build Coastguard Worker if (avail > size) {
646*ec779b8eSAndroid Build Coastguard Worker avail = size;
647*ec779b8eSAndroid Build Coastguard Worker }
648*ec779b8eSAndroid Build Coastguard Worker
649*ec779b8eSAndroid Build Coastguard Worker mCache->copy(delta, data, avail);
650*ec779b8eSAndroid Build Coastguard Worker
651*ec779b8eSAndroid Build Coastguard Worker return avail;
652*ec779b8eSAndroid Build Coastguard Worker }
653*ec779b8eSAndroid Build Coastguard Worker
654*ec779b8eSAndroid Build Coastguard Worker if (offset + size <= mCacheOffset + mCache->totalSize()) {
655*ec779b8eSAndroid Build Coastguard Worker mCache->copy(delta, data, size);
656*ec779b8eSAndroid Build Coastguard Worker
657*ec779b8eSAndroid Build Coastguard Worker return size;
658*ec779b8eSAndroid Build Coastguard Worker }
659*ec779b8eSAndroid Build Coastguard Worker
660*ec779b8eSAndroid Build Coastguard Worker ALOGV("deferring read");
661*ec779b8eSAndroid Build Coastguard Worker
662*ec779b8eSAndroid Build Coastguard Worker return -EAGAIN;
663*ec779b8eSAndroid Build Coastguard Worker }
664*ec779b8eSAndroid Build Coastguard Worker
seekInternal_l(off64_t offset)665*ec779b8eSAndroid Build Coastguard Worker status_t NuCachedSource2::seekInternal_l(off64_t offset) {
666*ec779b8eSAndroid Build Coastguard Worker mLastAccessPos = offset;
667*ec779b8eSAndroid Build Coastguard Worker
668*ec779b8eSAndroid Build Coastguard Worker if (offset >= mCacheOffset
669*ec779b8eSAndroid Build Coastguard Worker && offset <= (off64_t)(mCacheOffset + mCache->totalSize())) {
670*ec779b8eSAndroid Build Coastguard Worker return OK;
671*ec779b8eSAndroid Build Coastguard Worker }
672*ec779b8eSAndroid Build Coastguard Worker
673*ec779b8eSAndroid Build Coastguard Worker ALOGI("new range: offset= %lld", (long long)offset);
674*ec779b8eSAndroid Build Coastguard Worker
675*ec779b8eSAndroid Build Coastguard Worker mCacheOffset = offset;
676*ec779b8eSAndroid Build Coastguard Worker
677*ec779b8eSAndroid Build Coastguard Worker size_t totalSize = mCache->totalSize();
678*ec779b8eSAndroid Build Coastguard Worker CHECK_EQ(mCache->releaseFromStart(totalSize), totalSize);
679*ec779b8eSAndroid Build Coastguard Worker
680*ec779b8eSAndroid Build Coastguard Worker mNumRetriesLeft = kMaxNumRetries;
681*ec779b8eSAndroid Build Coastguard Worker mFetching = true;
682*ec779b8eSAndroid Build Coastguard Worker
683*ec779b8eSAndroid Build Coastguard Worker return OK;
684*ec779b8eSAndroid Build Coastguard Worker }
685*ec779b8eSAndroid Build Coastguard Worker
resumeFetchingIfNecessary()686*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::resumeFetchingIfNecessary() {
687*ec779b8eSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mLock);
688*ec779b8eSAndroid Build Coastguard Worker
689*ec779b8eSAndroid Build Coastguard Worker restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
690*ec779b8eSAndroid Build Coastguard Worker }
691*ec779b8eSAndroid Build Coastguard Worker
getUri()692*ec779b8eSAndroid Build Coastguard Worker String8 NuCachedSource2::getUri() {
693*ec779b8eSAndroid Build Coastguard Worker return mSource->getUri();
694*ec779b8eSAndroid Build Coastguard Worker }
695*ec779b8eSAndroid Build Coastguard Worker
getMIMEType() const696*ec779b8eSAndroid Build Coastguard Worker String8 NuCachedSource2::getMIMEType() const {
697*ec779b8eSAndroid Build Coastguard Worker return mSource->getMIMEType();
698*ec779b8eSAndroid Build Coastguard Worker }
699*ec779b8eSAndroid Build Coastguard Worker
updateCacheParamsFromSystemProperty()700*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::updateCacheParamsFromSystemProperty() {
701*ec779b8eSAndroid Build Coastguard Worker char value[PROPERTY_VALUE_MAX];
702*ec779b8eSAndroid Build Coastguard Worker if (!property_get("media.stagefright.cache-params", value, NULL)) {
703*ec779b8eSAndroid Build Coastguard Worker return;
704*ec779b8eSAndroid Build Coastguard Worker }
705*ec779b8eSAndroid Build Coastguard Worker
706*ec779b8eSAndroid Build Coastguard Worker updateCacheParamsFromString(value);
707*ec779b8eSAndroid Build Coastguard Worker }
708*ec779b8eSAndroid Build Coastguard Worker
updateCacheParamsFromString(const char * s)709*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::updateCacheParamsFromString(const char *s) {
710*ec779b8eSAndroid Build Coastguard Worker ssize_t lowwaterMarkKb, highwaterMarkKb;
711*ec779b8eSAndroid Build Coastguard Worker int keepAliveSecs;
712*ec779b8eSAndroid Build Coastguard Worker
713*ec779b8eSAndroid Build Coastguard Worker if (sscanf(s, "%zd/%zd/%d",
714*ec779b8eSAndroid Build Coastguard Worker &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
715*ec779b8eSAndroid Build Coastguard Worker ALOGE("Failed to parse cache parameters from '%s'.", s);
716*ec779b8eSAndroid Build Coastguard Worker return;
717*ec779b8eSAndroid Build Coastguard Worker }
718*ec779b8eSAndroid Build Coastguard Worker
719*ec779b8eSAndroid Build Coastguard Worker if (lowwaterMarkKb >= 0) {
720*ec779b8eSAndroid Build Coastguard Worker mLowwaterThresholdBytes = lowwaterMarkKb * 1024;
721*ec779b8eSAndroid Build Coastguard Worker } else {
722*ec779b8eSAndroid Build Coastguard Worker mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
723*ec779b8eSAndroid Build Coastguard Worker }
724*ec779b8eSAndroid Build Coastguard Worker
725*ec779b8eSAndroid Build Coastguard Worker if (highwaterMarkKb >= 0) {
726*ec779b8eSAndroid Build Coastguard Worker mHighwaterThresholdBytes = highwaterMarkKb * 1024;
727*ec779b8eSAndroid Build Coastguard Worker } else {
728*ec779b8eSAndroid Build Coastguard Worker mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
729*ec779b8eSAndroid Build Coastguard Worker }
730*ec779b8eSAndroid Build Coastguard Worker
731*ec779b8eSAndroid Build Coastguard Worker if (mLowwaterThresholdBytes >= mHighwaterThresholdBytes) {
732*ec779b8eSAndroid Build Coastguard Worker ALOGE("Illegal low/highwater marks specified, reverting to defaults.");
733*ec779b8eSAndroid Build Coastguard Worker
734*ec779b8eSAndroid Build Coastguard Worker mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
735*ec779b8eSAndroid Build Coastguard Worker mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
736*ec779b8eSAndroid Build Coastguard Worker }
737*ec779b8eSAndroid Build Coastguard Worker
738*ec779b8eSAndroid Build Coastguard Worker if (keepAliveSecs >= 0) {
739*ec779b8eSAndroid Build Coastguard Worker mKeepAliveIntervalUs = keepAliveSecs * 1000000LL;
740*ec779b8eSAndroid Build Coastguard Worker } else {
741*ec779b8eSAndroid Build Coastguard Worker mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
742*ec779b8eSAndroid Build Coastguard Worker }
743*ec779b8eSAndroid Build Coastguard Worker
744*ec779b8eSAndroid Build Coastguard Worker ALOGV("lowwater = %zu bytes, highwater = %zu bytes, keepalive = %lld us",
745*ec779b8eSAndroid Build Coastguard Worker mLowwaterThresholdBytes,
746*ec779b8eSAndroid Build Coastguard Worker mHighwaterThresholdBytes,
747*ec779b8eSAndroid Build Coastguard Worker (long long)mKeepAliveIntervalUs);
748*ec779b8eSAndroid Build Coastguard Worker }
749*ec779b8eSAndroid Build Coastguard Worker
750*ec779b8eSAndroid Build Coastguard Worker // static
RemoveCacheSpecificHeaders(KeyedVector<String8,String8> * headers,String8 * cacheConfig,bool * disconnectAtHighwatermark)751*ec779b8eSAndroid Build Coastguard Worker void NuCachedSource2::RemoveCacheSpecificHeaders(
752*ec779b8eSAndroid Build Coastguard Worker KeyedVector<String8, String8> *headers,
753*ec779b8eSAndroid Build Coastguard Worker String8 *cacheConfig,
754*ec779b8eSAndroid Build Coastguard Worker bool *disconnectAtHighwatermark) {
755*ec779b8eSAndroid Build Coastguard Worker *cacheConfig = String8();
756*ec779b8eSAndroid Build Coastguard Worker *disconnectAtHighwatermark = false;
757*ec779b8eSAndroid Build Coastguard Worker
758*ec779b8eSAndroid Build Coastguard Worker if (headers == NULL) {
759*ec779b8eSAndroid Build Coastguard Worker return;
760*ec779b8eSAndroid Build Coastguard Worker }
761*ec779b8eSAndroid Build Coastguard Worker
762*ec779b8eSAndroid Build Coastguard Worker ssize_t index;
763*ec779b8eSAndroid Build Coastguard Worker if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) {
764*ec779b8eSAndroid Build Coastguard Worker *cacheConfig = headers->valueAt(index);
765*ec779b8eSAndroid Build Coastguard Worker
766*ec779b8eSAndroid Build Coastguard Worker headers->removeItemsAt(index);
767*ec779b8eSAndroid Build Coastguard Worker
768*ec779b8eSAndroid Build Coastguard Worker ALOGV("Using special cache config '%s'", cacheConfig->c_str());
769*ec779b8eSAndroid Build Coastguard Worker }
770*ec779b8eSAndroid Build Coastguard Worker
771*ec779b8eSAndroid Build Coastguard Worker if ((index = headers->indexOfKey(
772*ec779b8eSAndroid Build Coastguard Worker String8("x-disconnect-at-highwatermark"))) >= 0) {
773*ec779b8eSAndroid Build Coastguard Worker *disconnectAtHighwatermark = true;
774*ec779b8eSAndroid Build Coastguard Worker headers->removeItemsAt(index);
775*ec779b8eSAndroid Build Coastguard Worker
776*ec779b8eSAndroid Build Coastguard Worker ALOGV("Client requested disconnection at highwater mark");
777*ec779b8eSAndroid Build Coastguard Worker }
778*ec779b8eSAndroid Build Coastguard Worker }
779*ec779b8eSAndroid Build Coastguard Worker
780*ec779b8eSAndroid Build Coastguard Worker } // namespace android
781