Home | History | Annotate | Download | only in http
      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     mLastURI = uri;
     62     // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
     63     // as part of the above assignment. Ensure no accidental later use.
     64     uri = NULL;
     65 
     66     bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
     67 
     68     mLastHeaders = extHeaders;
     69 
     70     mCachedSizeValid = false;
     71 
     72     if (success) {
     73         AString sanitized = uriDebugString(mLastURI);
     74         mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
     75     }
     76 
     77     return success ? OK : UNKNOWN_ERROR;
     78 }
     79 
     80 void MediaHTTP::disconnect() {
     81     mName = String8("MediaHTTP(<disconnected>)");
     82     if (mInitCheck != OK) {
     83         return;
     84     }
     85 
     86     mHTTPConnection->disconnect();
     87 }
     88 
     89 status_t MediaHTTP::initCheck() const {
     90     return mInitCheck;
     91 }
     92 
     93 ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
     94     if (mInitCheck != OK) {
     95         return mInitCheck;
     96     }
     97 
     98     int64_t startTimeUs = ALooper::GetNowUs();
     99 
    100     size_t numBytesRead = 0;
    101     while (numBytesRead < size) {
    102         size_t copy = size - numBytesRead;
    103 
    104         if (copy > 64 * 1024) {
    105             // limit the buffer sizes transferred across binder boundaries
    106             // to avoid spurious transaction failures.
    107             copy = 64 * 1024;
    108         }
    109 
    110         ssize_t n = mHTTPConnection->readAt(
    111                 offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
    112 
    113         if (n < 0) {
    114             return n;
    115         } else if (n == 0) {
    116             break;
    117         }
    118 
    119         numBytesRead += n;
    120     }
    121 
    122     int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
    123 
    124     addBandwidthMeasurement(numBytesRead, delayUs);
    125 
    126     return numBytesRead;
    127 }
    128 
    129 status_t MediaHTTP::getSize(off64_t *size) {
    130     if (mInitCheck != OK) {
    131         return mInitCheck;
    132     }
    133 
    134     // Caching the returned size so that it stays valid even after a
    135     // disconnect. NuCachedSource2 relies on this.
    136 
    137     if (!mCachedSizeValid) {
    138         mCachedSize = mHTTPConnection->getSize();
    139         mCachedSizeValid = true;
    140     }
    141 
    142     *size = mCachedSize;
    143 
    144     return *size < 0 ? *size : static_cast<status_t>(OK);
    145 }
    146 
    147 uint32_t MediaHTTP::flags() {
    148     return kWantsPrefetching | kIsHTTPBasedSource;
    149 }
    150 
    151 status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
    152     return connect(mLastURI.c_str(), &mLastHeaders, offset);
    153 }
    154 
    155 // DRM...
    156 
    157 sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
    158     if (mDrmManagerClient == NULL) {
    159         mDrmManagerClient = new DrmManagerClient();
    160     }
    161 
    162     if (mDrmManagerClient == NULL) {
    163         return NULL;
    164     }
    165 
    166     if (mDecryptHandle == NULL) {
    167         mDecryptHandle = mDrmManagerClient->openDecryptSession(
    168                 String8(mLastURI.c_str()), mime);
    169     }
    170 
    171     if (mDecryptHandle == NULL) {
    172         delete mDrmManagerClient;
    173         mDrmManagerClient = NULL;
    174     }
    175 
    176     return mDecryptHandle;
    177 }
    178 
    179 void MediaHTTP::getDrmInfo(
    180         sp<DecryptHandle> &handle, DrmManagerClient **client) {
    181     handle = mDecryptHandle;
    182     *client = mDrmManagerClient;
    183 }
    184 
    185 String8 MediaHTTP::getUri() {
    186     if (mInitCheck != OK) {
    187         return String8::empty();
    188     }
    189 
    190     String8 uri;
    191     if (OK == mHTTPConnection->getUri(&uri)) {
    192         return uri;
    193     }
    194     return String8(mLastURI.c_str());
    195 }
    196 
    197 String8 MediaHTTP::getMIMEType() const {
    198     if (mInitCheck != OK) {
    199         return String8("application/octet-stream");
    200     }
    201 
    202     String8 mimeType;
    203     status_t err = mHTTPConnection->getMIMEType(&mimeType);
    204 
    205     if (err != OK) {
    206         return String8("application/octet-stream");
    207     }
    208 
    209     return mimeType;
    210 }
    211 
    212 void MediaHTTP::clearDRMState_l() {
    213     if (mDecryptHandle != NULL) {
    214         // To release mDecryptHandle
    215         CHECK(mDrmManagerClient);
    216         mDrmManagerClient->closeDecryptSession(mDecryptHandle);
    217         mDecryptHandle = NULL;
    218     }
    219 }
    220 
    221 }  // namespace android
    222