1/* 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 28#include <cutils/properties.h> // for property_get 29 30namespace android { 31 32ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags) 33 : mFlags(flags), 34 mState(DISCONNECTED), 35 mDelegate(new SfDelegate), 36 mCurrentOffset(0), 37 mIOResult(OK), 38 mContentSize(-1), 39 mDecryptHandle(NULL), 40 mDrmManagerClient(NULL) { 41 mDelegate->setOwner(this); 42} 43 44ChromiumHTTPDataSource::~ChromiumHTTPDataSource() { 45 disconnect(); 46 47 delete mDelegate; 48 mDelegate = NULL; 49 50 clearDRMState_l(); 51 52 if (mDrmManagerClient != NULL) { 53 delete mDrmManagerClient; 54 mDrmManagerClient = NULL; 55 } 56} 57 58status_t ChromiumHTTPDataSource::connect( 59 const char *uri, 60 const KeyedVector<String8, String8> *headers, 61 off64_t offset) { 62 Mutex::Autolock autoLock(mLock); 63 64 uid_t uid; 65 if (getUID(&uid)) { 66 mDelegate->setUID(uid); 67 } 68 LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid); 69 70 return connect_l(uri, headers, offset); 71} 72 73status_t ChromiumHTTPDataSource::connect_l( 74 const char *uri, 75 const KeyedVector<String8, String8> *headers, 76 off64_t offset) { 77 if (mState != DISCONNECTED) { 78 disconnect_l(); 79 } 80 81 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, 82 "connect to <URL suppressed> @%lld", offset); 83 84 mURI = uri; 85 mContentType = String8("application/octet-stream"); 86 87 if (headers != NULL) { 88 mHeaders = *headers; 89 } else { 90 mHeaders.clear(); 91 } 92 93 mState = CONNECTING; 94 mContentSize = -1; 95 mCurrentOffset = offset; 96 97 mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset); 98 99 while (mState == CONNECTING || mState == DISCONNECTING) { 100 mCondition.wait(mLock); 101 } 102 103 return mState == CONNECTED ? OK : mIOResult; 104} 105 106void ChromiumHTTPDataSource::onConnectionEstablished( 107 int64_t contentSize, const char *contentType) { 108 Mutex::Autolock autoLock(mLock); 109 110 if (mState != CONNECTING) { 111 // We may have initiated disconnection. 112 CHECK_EQ(mState, DISCONNECTING); 113 return; 114 } 115 116 mState = CONNECTED; 117 mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; 118 mContentType = String8(contentType); 119 mCondition.broadcast(); 120} 121 122void ChromiumHTTPDataSource::onConnectionFailed(status_t err) { 123 Mutex::Autolock autoLock(mLock); 124 mState = DISCONNECTED; 125 mCondition.broadcast(); 126 127 // mURI.clear(); 128 129 mIOResult = err; 130} 131 132void ChromiumHTTPDataSource::disconnect() { 133 Mutex::Autolock autoLock(mLock); 134 disconnect_l(); 135} 136 137void ChromiumHTTPDataSource::disconnect_l() { 138 if (mState == DISCONNECTED) { 139 return; 140 } 141 142 mState = DISCONNECTING; 143 mIOResult = -EINTR; 144 145 mDelegate->initiateDisconnect(); 146 147 while (mState == DISCONNECTING) { 148 mCondition.wait(mLock); 149 } 150 151 CHECK_EQ((int)mState, (int)DISCONNECTED); 152} 153 154status_t ChromiumHTTPDataSource::initCheck() const { 155 Mutex::Autolock autoLock(mLock); 156 157 return mState == CONNECTED ? OK : NO_INIT; 158} 159 160ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { 161 Mutex::Autolock autoLock(mLock); 162 163 if (mState != CONNECTED) { 164 return INVALID_OPERATION; 165 } 166 167#if 0 168 char value[PROPERTY_VALUE_MAX]; 169 if (property_get("media.stagefright.disable-net", value, 0) 170 && (!strcasecmp(value, "true") || !strcmp(value, "1"))) { 171 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down."); 172 disconnect_l(); 173 return ERROR_IO; 174 } 175#endif 176 177 if (offset != mCurrentOffset) { 178 AString tmp = mURI; 179 KeyedVector<String8, String8> tmpHeaders = mHeaders; 180 181 disconnect_l(); 182 183 status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset); 184 185 if (err != OK) { 186 return err; 187 } 188 } 189 190 mState = READING; 191 192 int64_t startTimeUs = ALooper::GetNowUs(); 193 194 mDelegate->initiateRead(data, size); 195 196 while (mState == READING) { 197 mCondition.wait(mLock); 198 } 199 200 if (mIOResult < OK) { 201 return mIOResult; 202 } 203 204 if (mState == CONNECTED) { 205 int64_t delayUs = ALooper::GetNowUs() - startTimeUs; 206 207 // The read operation was successful, mIOResult contains 208 // the number of bytes read. 209 addBandwidthMeasurement(mIOResult, delayUs); 210 211 mCurrentOffset += mIOResult; 212 return mIOResult; 213 } 214 215 return ERROR_IO; 216} 217 218void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) { 219 Mutex::Autolock autoLock(mLock); 220 221 mIOResult = size; 222 223 if (mState == READING) { 224 mState = CONNECTED; 225 mCondition.broadcast(); 226 } 227} 228 229status_t ChromiumHTTPDataSource::getSize(off64_t *size) { 230 Mutex::Autolock autoLock(mLock); 231 232 if (mContentSize < 0) { 233 return ERROR_UNSUPPORTED; 234 } 235 236 *size = mContentSize; 237 238 return OK; 239} 240 241uint32_t ChromiumHTTPDataSource::flags() { 242 return kWantsPrefetching | kIsHTTPBasedSource; 243} 244 245// static 246void ChromiumHTTPDataSource::InitiateRead( 247 ChromiumHTTPDataSource *me, void *data, size_t size) { 248 me->initiateRead(data, size); 249} 250 251void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) { 252 mDelegate->initiateRead(data, size); 253} 254 255void ChromiumHTTPDataSource::onDisconnectComplete() { 256 Mutex::Autolock autoLock(mLock); 257 CHECK_EQ((int)mState, (int)DISCONNECTING); 258 259 mState = DISCONNECTED; 260 // mURI.clear(); 261 mIOResult = -ENOTCONN; 262 263 mCondition.broadcast(); 264} 265 266sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization(const char* mime) { 267 Mutex::Autolock autoLock(mLock); 268 269 if (mDrmManagerClient == NULL) { 270 mDrmManagerClient = new DrmManagerClient(); 271 } 272 273 if (mDrmManagerClient == NULL) { 274 return NULL; 275 } 276 277 if (mDecryptHandle == NULL) { 278 /* Note if redirect occurs, mUri is the redirect uri instead of the 279 * original one 280 */ 281 mDecryptHandle = mDrmManagerClient->openDecryptSession( 282 String8(mURI.c_str()), mime); 283 } 284 285 if (mDecryptHandle == NULL) { 286 delete mDrmManagerClient; 287 mDrmManagerClient = NULL; 288 } 289 290 return mDecryptHandle; 291} 292 293void ChromiumHTTPDataSource::getDrmInfo( 294 sp<DecryptHandle> &handle, DrmManagerClient **client) { 295 Mutex::Autolock autoLock(mLock); 296 297 handle = mDecryptHandle; 298 *client = mDrmManagerClient; 299} 300 301String8 ChromiumHTTPDataSource::getUri() { 302 Mutex::Autolock autoLock(mLock); 303 304 return String8(mURI.c_str()); 305} 306 307String8 ChromiumHTTPDataSource::getMIMEType() const { 308 Mutex::Autolock autoLock(mLock); 309 310 return mContentType; 311} 312 313void ChromiumHTTPDataSource::clearDRMState_l() { 314 if (mDecryptHandle != NULL) { 315 // To release mDecryptHandle 316 CHECK(mDrmManagerClient); 317 mDrmManagerClient->closeDecryptSession(mDecryptHandle); 318 mDecryptHandle = NULL; 319 } 320} 321 322status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) { 323 Mutex::Autolock autoLock(mLock); 324 325 if (mURI.empty()) { 326 return INVALID_OPERATION; 327 } 328 329 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting..."); 330 status_t err = connect_l(mURI.c_str(), &mHeaders, offset); 331 if (err != OK) { 332 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err); 333 } 334 335 return err; 336} 337 338} // namespace android 339 340