blob: 1096717ff464153a0a207451d4c61b7528dcc76d [file] [log] [blame]
Andreas Huber5f5719e2011-03-08 15:59:28 -08001/*
2 * Copyright (C) 2011 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 "ChromiumHTTPDataSource"
19#include <media/stagefright/foundation/ADebug.h>
20
21#include "include/ChromiumHTTPDataSource.h"
22
23#include <media/stagefright/foundation/ALooper.h>
24#include <media/stagefright/MediaErrors.h>
25
26#include "support.h"
27
28namespace android {
29
30ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
31 : mFlags(flags),
32 mState(DISCONNECTED),
33 mDelegate(new SfDelegate),
34 mCurrentOffset(0),
35 mIOResult(OK),
36 mContentSize(-1),
37 mNumBandwidthHistoryItems(0),
38 mTotalTransferTimeUs(0),
39 mTotalTransferBytes(0),
40 mDecryptHandle(NULL),
41 mDrmManagerClient(NULL) {
42 mDelegate->setOwner(this);
43}
44
45ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
46 disconnect();
47
48 delete mDelegate;
49 mDelegate = NULL;
50
51 if (mDrmManagerClient != NULL) {
52 delete mDrmManagerClient;
53 mDrmManagerClient = NULL;
54 }
55}
56
57status_t ChromiumHTTPDataSource::connect(
58 const char *uri,
59 const KeyedVector<String8, String8> *headers,
60 off64_t offset) {
61 Mutex::Autolock autoLock(mLock);
62
63 return connect_l(uri, headers, offset);
64}
65
66status_t ChromiumHTTPDataSource::connect_l(
67 const char *uri,
68 const KeyedVector<String8, String8> *headers,
69 off64_t offset) {
70 if (mState != DISCONNECTED) {
71 disconnect_l();
72 }
73
74 if (!(mFlags & kFlagIncognito)) {
75 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset);
76 } else {
77 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
78 "connect to <URL suppressed> @%lld", offset);
79 }
80
81 mURI = uri;
Andreas Hubera2e57ca2011-03-30 11:15:27 -070082 mContentType = String8("application/octet-stream");
Andreas Huber5f5719e2011-03-08 15:59:28 -080083
84 if (headers != NULL) {
85 mHeaders = *headers;
86 } else {
87 mHeaders.clear();
88 }
89
90 mState = CONNECTING;
91 mContentSize = -1;
92 mCurrentOffset = offset;
93
94 mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset);
95
96 while (mState == CONNECTING) {
97 mCondition.wait(mLock);
98 }
99
100 return mState == CONNECTED ? OK : mIOResult;
101}
102
Andreas Hubera2e57ca2011-03-30 11:15:27 -0700103void ChromiumHTTPDataSource::onConnectionEstablished(
104 int64_t contentSize, const char *contentType) {
Andreas Huber5f5719e2011-03-08 15:59:28 -0800105 Mutex::Autolock autoLock(mLock);
106 mState = CONNECTED;
107 mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset;
Andreas Hubera2e57ca2011-03-30 11:15:27 -0700108 mContentType = String8(contentType);
Andreas Huber5f5719e2011-03-08 15:59:28 -0800109 mCondition.broadcast();
110}
111
112void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
113 Mutex::Autolock autoLock(mLock);
114 mState = DISCONNECTED;
115 mCondition.broadcast();
116
117 mURI.clear();
118
119 mIOResult = err;
120
121 clearDRMState_l();
122}
123
124void ChromiumHTTPDataSource::disconnect() {
125 Mutex::Autolock autoLock(mLock);
126 disconnect_l();
127}
128
129void ChromiumHTTPDataSource::disconnect_l() {
130 if (mState == DISCONNECTED) {
131 return;
132 }
133
134 mState = DISCONNECTING;
135 mIOResult = -EINTR;
136
137 mDelegate->initiateDisconnect();
138
139 while (mState == DISCONNECTING) {
140 mCondition.wait(mLock);
141 }
142
143 CHECK_EQ((int)mState, (int)DISCONNECTED);
144}
145
146status_t ChromiumHTTPDataSource::initCheck() const {
147 Mutex::Autolock autoLock(mLock);
148
149 return mState == CONNECTED ? OK : NO_INIT;
150}
151
152ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
153 Mutex::Autolock autoLock(mLock);
154
155 if (mState != CONNECTED) {
156 return ERROR_NOT_CONNECTED;
157 }
158
159 if (offset != mCurrentOffset) {
160 AString tmp = mURI;
161 KeyedVector<String8, String8> tmpHeaders = mHeaders;
162
163 disconnect_l();
164
165 status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset);
166
167 if (err != OK) {
168 return err;
169 }
170 }
171
172 mState = READING;
173
174 int64_t startTimeUs = ALooper::GetNowUs();
175
176 mDelegate->initiateRead(data, size);
177
178 while (mState == READING) {
179 mCondition.wait(mLock);
180 }
181
182 if (mIOResult < OK) {
183 return mIOResult;
184 }
185
186 if (mState == CONNECTED) {
187 int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
188
189 // The read operation was successful, mIOResult contains
190 // the number of bytes read.
191 addBandwidthMeasurement_l(mIOResult, delayUs);
192
193 mCurrentOffset += mIOResult;
194 return mIOResult;
195 }
196
197 return ERROR_IO;
198}
199
200void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) {
201 Mutex::Autolock autoLock(mLock);
202
203 mIOResult = size;
204
205 if (mState == READING) {
206 mState = CONNECTED;
207 mCondition.broadcast();
208 }
209}
210
211status_t ChromiumHTTPDataSource::getSize(off64_t *size) {
212 Mutex::Autolock autoLock(mLock);
213
214 if (mContentSize < 0) {
215 return ERROR_UNSUPPORTED;
216 }
217
218 *size = mContentSize;
219
220 return OK;
221}
222
223uint32_t ChromiumHTTPDataSource::flags() {
224 return kWantsPrefetching;
225}
226
227// static
228void ChromiumHTTPDataSource::InitiateRead(
229 ChromiumHTTPDataSource *me, void *data, size_t size) {
230 me->initiateRead(data, size);
231}
232
233void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) {
234 mDelegate->initiateRead(data, size);
235}
236
237void ChromiumHTTPDataSource::onDisconnectComplete() {
238 Mutex::Autolock autoLock(mLock);
239 CHECK_EQ((int)mState, (int)DISCONNECTING);
240
241 mState = DISCONNECTED;
242 mURI.clear();
243
244 mCondition.broadcast();
245
246 clearDRMState_l();
247}
248
249void ChromiumHTTPDataSource::addBandwidthMeasurement_l(
250 size_t numBytes, int64_t delayUs) {
251 BandwidthEntry entry;
252 entry.mDelayUs = delayUs;
253 entry.mNumBytes = numBytes;
254 mTotalTransferTimeUs += delayUs;
255 mTotalTransferBytes += numBytes;
256
257 mBandwidthHistory.push_back(entry);
258 if (++mNumBandwidthHistoryItems > 100) {
259 BandwidthEntry *entry = &*mBandwidthHistory.begin();
260 mTotalTransferTimeUs -= entry->mDelayUs;
261 mTotalTransferBytes -= entry->mNumBytes;
262 mBandwidthHistory.erase(mBandwidthHistory.begin());
263 --mNumBandwidthHistoryItems;
264 }
265}
266
267bool ChromiumHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
268 Mutex::Autolock autoLock(mLock);
269
270 if (mNumBandwidthHistoryItems < 2) {
271 return false;
272 }
273
274 *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
275
276 return true;
277}
278
Gloria Wangae775272011-02-24 16:40:57 -0800279sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
Andreas Huber5f5719e2011-03-08 15:59:28 -0800280 Mutex::Autolock autoLock(mLock);
281
282 if (mDrmManagerClient == NULL) {
283 mDrmManagerClient = new DrmManagerClient();
284 }
285
286 if (mDrmManagerClient == NULL) {
287 return NULL;
288 }
289
290 if (mDecryptHandle == NULL) {
291 /* Note if redirect occurs, mUri is the redirect uri instead of the
292 * original one
293 */
294 mDecryptHandle = mDrmManagerClient->openDecryptSession(
295 String8(mURI.c_str()));
296 }
297
298 if (mDecryptHandle == NULL) {
299 delete mDrmManagerClient;
300 mDrmManagerClient = NULL;
301 }
302
303 return mDecryptHandle;
304}
305
306void ChromiumHTTPDataSource::getDrmInfo(
Gloria Wangae775272011-02-24 16:40:57 -0800307 sp<DecryptHandle> &handle, DrmManagerClient **client) {
Andreas Huber5f5719e2011-03-08 15:59:28 -0800308 Mutex::Autolock autoLock(mLock);
309
Gloria Wangae775272011-02-24 16:40:57 -0800310 handle = mDecryptHandle;
Andreas Huber5f5719e2011-03-08 15:59:28 -0800311 *client = mDrmManagerClient;
312}
313
314String8 ChromiumHTTPDataSource::getUri() {
315 Mutex::Autolock autoLock(mLock);
316
317 return String8(mURI.c_str());
318}
319
Andreas Hubera2e57ca2011-03-30 11:15:27 -0700320String8 ChromiumHTTPDataSource::getMIMEType() const {
321 Mutex::Autolock autoLock(mLock);
322
323 return mContentType;
324}
325
Andreas Huber5f5719e2011-03-08 15:59:28 -0800326void ChromiumHTTPDataSource::clearDRMState_l() {
327 if (mDecryptHandle != NULL) {
328 // To release mDecryptHandle
329 CHECK(mDrmManagerClient);
330 mDrmManagerClient->closeDecryptSession(mDecryptHandle);
331 mDecryptHandle = NULL;
332 }
333}
334
335} // namespace android
336