1 /* 2 * Copyright (C) 2013 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 "MediaHTTP" 19 #include <utils/Log.h> 20 21 #include <media/stagefright/MediaHTTP.h> 22 23 #include <binder/IServiceManager.h> 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/foundation/ALooper.h> 26 #include <media/stagefright/Utils.h> 27 28 #include <media/IMediaHTTPConnection.h> 29 30 namespace android { 31 32 MediaHTTP::MediaHTTP(const sp<IMediaHTTPConnection> &conn) 33 : mInitCheck((conn != NULL) ? OK : NO_INIT), 34 mHTTPConnection(conn), 35 mCachedSizeValid(false), 36 mCachedSize(0ll), 37 mDrmManagerClient(NULL) { 38 } 39 40 MediaHTTP::~MediaHTTP() { 41 clearDRMState_l(); 42 } 43 44 status_t MediaHTTP::connect( 45 const char *uri, 46 const KeyedVector<String8, String8> *headers, 47 off64_t /* offset */) { 48 if (mInitCheck != OK) { 49 return mInitCheck; 50 } 51 52 KeyedVector<String8, String8> extHeaders; 53 if (headers != NULL) { 54 extHeaders = *headers; 55 } 56 57 if (extHeaders.indexOfKey(String8("User-Agent")) < 0) { 58 extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str())); 59 } 60 61 bool success = mHTTPConnection->connect(uri, &extHeaders); 62 63 mLastHeaders = extHeaders; 64 mLastURI = uri; 65 66 mCachedSizeValid = false; 67 68 return success ? OK : UNKNOWN_ERROR; 69 } 70 71 void MediaHTTP::disconnect() { 72 if (mInitCheck != OK) { 73 return; 74 } 75 76 mHTTPConnection->disconnect(); 77 } 78 79 status_t MediaHTTP::initCheck() const { 80 return mInitCheck; 81 } 82 83 ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) { 84 if (mInitCheck != OK) { 85 return mInitCheck; 86 } 87 88 int64_t startTimeUs = ALooper::GetNowUs(); 89 90 size_t numBytesRead = 0; 91 while (numBytesRead < size) { 92 size_t copy = size - numBytesRead; 93 94 if (copy > 64 * 1024) { 95 // limit the buffer sizes transferred across binder boundaries 96 // to avoid spurious transaction failures. 97 copy = 64 * 1024; 98 } 99 100 ssize_t n = mHTTPConnection->readAt( 101 offset + numBytesRead, (uint8_t *)data + numBytesRead, copy); 102 103 if (n < 0) { 104 return n; 105 } else if (n == 0) { 106 break; 107 } 108 109 numBytesRead += n; 110 } 111 112 int64_t delayUs = ALooper::GetNowUs() - startTimeUs; 113 114 addBandwidthMeasurement(numBytesRead, delayUs); 115 116 return numBytesRead; 117 } 118 119 status_t MediaHTTP::getSize(off64_t *size) { 120 if (mInitCheck != OK) { 121 return mInitCheck; 122 } 123 124 // Caching the returned size so that it stays valid even after a 125 // disconnect. NuCachedSource2 relies on this. 126 127 if (!mCachedSizeValid) { 128 mCachedSize = mHTTPConnection->getSize(); 129 mCachedSizeValid = true; 130 } 131 132 *size = mCachedSize; 133 134 return *size < 0 ? *size : static_cast<status_t>(OK); 135 } 136 137 uint32_t MediaHTTP::flags() { 138 return kWantsPrefetching | kIsHTTPBasedSource; 139 } 140 141 status_t MediaHTTP::reconnectAtOffset(off64_t offset) { 142 return connect(mLastURI.c_str(), &mLastHeaders, offset); 143 } 144 145 // DRM... 146 147 sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) { 148 if (mDrmManagerClient == NULL) { 149 mDrmManagerClient = new DrmManagerClient(); 150 } 151 152 if (mDrmManagerClient == NULL) { 153 return NULL; 154 } 155 156 if (mDecryptHandle == NULL) { 157 mDecryptHandle = mDrmManagerClient->openDecryptSession( 158 String8(mLastURI.c_str()), mime); 159 } 160 161 if (mDecryptHandle == NULL) { 162 delete mDrmManagerClient; 163 mDrmManagerClient = NULL; 164 } 165 166 return mDecryptHandle; 167 } 168 169 void MediaHTTP::getDrmInfo( 170 sp<DecryptHandle> &handle, DrmManagerClient **client) { 171 handle = mDecryptHandle; 172 *client = mDrmManagerClient; 173 } 174 175 String8 MediaHTTP::getUri() { 176 if (mInitCheck != OK) { 177 return String8::empty(); 178 } 179 180 String8 uri; 181 if (OK == mHTTPConnection->getUri(&uri)) { 182 return uri; 183 } 184 return String8(mLastURI.c_str()); 185 } 186 187 String8 MediaHTTP::getMIMEType() const { 188 if (mInitCheck != OK) { 189 return String8("application/octet-stream"); 190 } 191 192 String8 mimeType; 193 status_t err = mHTTPConnection->getMIMEType(&mimeType); 194 195 if (err != OK) { 196 return String8("application/octet-stream"); 197 } 198 199 return mimeType; 200 } 201 202 void MediaHTTP::clearDRMState_l() { 203 if (mDecryptHandle != NULL) { 204 // To release mDecryptHandle 205 CHECK(mDrmManagerClient); 206 mDrmManagerClient->closeDecryptSession(mDecryptHandle); 207 mDecryptHandle = NULL; 208 } 209 } 210 211 } // namespace android 212