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