15abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang/*
25abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * Copyright 2015 The Android Open Source Project
35abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
45abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
55abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * you may not use this file except in compliance with the License.
65abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * You may obtain a copy of the License at
75abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
85abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
95abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
105abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * Unless required by applicable law or agreed to in writing, software
115abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
125abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * See the License for the specific language governing permissions and
145abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * limitations under the License.
155abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang */
165abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
175abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang//#define LOG_NDEBUG 0
185abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#define LOG_TAG "HTTPDownloader"
195abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <utils/Log.h>
205abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
215abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include "HTTPDownloader.h"
225abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include "M3UParser.h"
235abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
245abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/IMediaHTTPConnection.h>
255abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/IMediaHTTPService.h>
265abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/stagefright/foundation/ABuffer.h>
275abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/stagefright/foundation/ADebug.h>
285abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/stagefright/MediaHTTP.h>
295abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/stagefright/DataSource.h>
305abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <media/stagefright/FileSource.h>
315abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <openssl/aes.h>
325abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <openssl/md5.h>
335abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include <utils/Mutex.h>
348a414a2b8dc21143e13b9b75980aba68435a8a8eRobert Shih#include <inttypes.h>
355abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
365abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangnamespace android {
375abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
385abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong ZhangHTTPDownloader::HTTPDownloader(
395abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        const sp<IMediaHTTPService> &httpService,
405abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        const KeyedVector<String8, String8> &headers) :
415abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
425abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mExtraHeaders(headers),
435abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mDisconnecting(false) {
445abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
455abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
465abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid HTTPDownloader::reconnect() {
475abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    AutoMutex _l(mLock);
485abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mDisconnecting = false;
495abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid HTTPDownloader::disconnect() {
525abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    {
535abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        AutoMutex _l(mLock);
545abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mDisconnecting = true;
555abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
565abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mHTTPDataSource->disconnect();
575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
585abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
595abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangbool HTTPDownloader::isDisconnecting() {
605abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    AutoMutex _l(mLock);
615abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    return mDisconnecting;
625abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
635abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
645abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang/*
655abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * Illustration of parameters:
665abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
675abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * 0      `range_offset`
685abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * +------------+-------------------------------------------------------+--+--+
695abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * |            |                                 | next block to fetch |  |  |
705abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * |            | `source` handle => `out` buffer |                     |  |  |
715abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * | `url` file |<--------- buffer size --------->|<--- `block_size` -->|  |  |
725abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * |            |<----------- `range_length` / buffer capacity ----------->|  |
735abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * |<------------------------------ file_size ------------------------------->|
745abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
755abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * Special parameter values:
765abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * - range_length == -1 means entire file
775abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang * - block_size == 0 means entire range
785abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang *
795abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang */
805abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangssize_t HTTPDownloader::fetchBlock(
815abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        const char *url, sp<ABuffer> *out,
825abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        int64_t range_offset, int64_t range_length,
835abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        uint32_t block_size, /* download block size */
845abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        String8 *actualUrl,
855abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        bool reconnect /* force connect HTTP when resuing source */) {
865abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (isDisconnecting()) {
875abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        return ERROR_NOT_CONNECTED;
885abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
895abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
905abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    off64_t size;
915abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
925abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (reconnect) {
935abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (!strncasecmp(url, "file://", 7)) {
945abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            mDataSource = new FileSource(url + 7);
955abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        } else if (strncasecmp(url, "http://", 7)
965abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                && strncasecmp(url, "https://", 8)) {
975abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return ERROR_UNSUPPORTED;
985abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        } else {
995abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            KeyedVector<String8, String8> headers = mExtraHeaders;
1005abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            if (range_offset > 0 || range_length >= 0) {
1015abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                headers.add(
1025abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                        String8("Range"),
1035abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                        String8(
1045abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                            AStringPrintf(
1055abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                                "bytes=%lld-%s",
1065abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                                range_offset,
1075abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                                range_length < 0
1085abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                                    ? "" : AStringPrintf("%lld",
1095abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                                            range_offset + range_length - 1).c_str()).c_str()));
1105abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            }
1115abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1125abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            status_t err = mHTTPDataSource->connect(url, &headers);
1135abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1145abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            if (isDisconnecting()) {
1155abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                return ERROR_NOT_CONNECTED;
1165abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            }
1175abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1185abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            if (err != OK) {
1195abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                return err;
1205abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            }
1215abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1225abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            mDataSource = mHTTPDataSource;
1235abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1245abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
1255abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1265abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    status_t getSizeErr = mDataSource->getSize(&size);
1275abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1285abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (isDisconnecting()) {
1295abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        return ERROR_NOT_CONNECTED;
1305abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
1315abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1325abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (getSizeErr != OK) {
1335abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        size = 65536;
1345abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
1355abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1365abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    sp<ABuffer> buffer = *out != NULL ? *out : new ABuffer(size);
1375abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (*out == NULL) {
1385abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        buffer->setRange(0, 0);
1395abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
1405abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1415abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    ssize_t bytesRead = 0;
1425abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    // adjust range_length if only reading partial block
1435abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (block_size > 0 && (range_length == -1 || (int64_t)(buffer->size() + block_size) < range_length)) {
1445abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        range_length = buffer->size() + block_size;
1455abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
1465abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    for (;;) {
1475abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        // Only resize when we don't know the size.
1485abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        size_t bufferRemaining = buffer->capacity() - buffer->size();
1495abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (bufferRemaining == 0 && getSizeErr != OK) {
1505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            size_t bufferIncrement = buffer->size() / 2;
1515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            if (bufferIncrement < 32768) {
1525abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                bufferIncrement = 32768;
1535abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            }
1545abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            bufferRemaining = bufferIncrement;
1555abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1565abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            ALOGV("increasing download buffer to %zu bytes",
1575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                 buffer->size() + bufferRemaining);
1585abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1595abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
1605abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            memcpy(copy->data(), buffer->data(), buffer->size());
1615abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            copy->setRange(0, buffer->size());
1625abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1635abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            buffer = copy;
1645abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1655abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1665abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        size_t maxBytesToRead = bufferRemaining;
1675abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (range_length >= 0) {
1685abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            int64_t bytesLeftInRange = range_length - buffer->size();
1698a414a2b8dc21143e13b9b75980aba68435a8a8eRobert Shih            if (bytesLeftInRange < 0) {
1708a414a2b8dc21143e13b9b75980aba68435a8a8eRobert Shih                ALOGE("range_length %" PRId64 " wrapped around", range_length);
1718a414a2b8dc21143e13b9b75980aba68435a8a8eRobert Shih                return ERROR_OUT_OF_RANGE;
1728a414a2b8dc21143e13b9b75980aba68435a8a8eRobert Shih            } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
1735abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                maxBytesToRead = bytesLeftInRange;
1745abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1755abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                if (bytesLeftInRange == 0) {
1765abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                    break;
1775abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                }
1785abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            }
1795abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1805abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1815abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0)
1825abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        // to help us break out of the loop.
1835abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        ssize_t n = mDataSource->readAt(
1845abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                buffer->size(), buffer->data() + buffer->size(),
1855abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                maxBytesToRead);
1865abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1875abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (isDisconnecting()) {
1885abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return ERROR_NOT_CONNECTED;
1895abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1905abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1915abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (n < 0) {
1925abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return n;
1935abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1945abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1955abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (n == 0) {
1965abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            break;
1975abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
1985abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
1995abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        buffer->setRange(0, buffer->size() + (size_t)n);
2005abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        bytesRead += n;
2015abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
2025abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2035abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    *out = buffer;
2045abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (actualUrl != NULL) {
2055abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        *actualUrl = mDataSource->getUri();
2065abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (actualUrl->isEmpty()) {
2075abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            *actualUrl = url;
2085abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
2095abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
2105abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2115abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    return bytesRead;
2125abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
2135abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2145abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangssize_t HTTPDownloader::fetchFile(
2155abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        const char *url, sp<ABuffer> *out, String8 *actualUrl) {
2165abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    ssize_t err = fetchBlock(url, out, 0, -1, 0, actualUrl, true /* reconnect */);
2175abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2185abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    // close off the connection after use
2195abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mHTTPDataSource->disconnect();
2205abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2215abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    return err;
2225abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
2235abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2245abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangsp<M3UParser> HTTPDownloader::fetchPlaylist(
2255abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        const char *url, uint8_t *curPlaylistHash, bool *unchanged) {
2265abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    ALOGV("fetchPlaylist '%s'", url);
2275abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2285abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    *unchanged = false;
2295abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2305abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    sp<ABuffer> buffer;
2315abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    String8 actualUrl;
2325abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    ssize_t err = fetchFile(url, &buffer, &actualUrl);
2335abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2345abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    // close off the connection after use
2355abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mHTTPDataSource->disconnect();
2365abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2375abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (err <= 0) {
2385abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        return NULL;
2395abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
2405abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2415abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    // MD5 functionality is not available on the simulator, treat all
2425abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    // playlists as changed.
2435abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2449d65efac5bbf88c03f7fa5e95120e2fbae35aa9bElliott Hughes#if defined(__ANDROID__)
2455abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    uint8_t hash[16];
2465abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2475abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    MD5_CTX m;
2485abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    MD5_Init(&m);
2495abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    MD5_Update(&m, buffer->data(), buffer->size());
2505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    MD5_Final(hash, &m);
2525abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2535abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (curPlaylistHash != NULL && !memcmp(hash, curPlaylistHash, 16)) {
2545abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        // playlist unchanged
2555abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        *unchanged = true;
2565abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        return NULL;
2585abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
2595abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#endif
2605abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2615abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    sp<M3UParser> playlist =
2625abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        new M3UParser(actualUrl.string(), buffer->data(), buffer->size());
2635abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2645abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (playlist->initCheck() != OK) {
2655abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        ALOGE("failed to parse .m3u8 playlist");
2665abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2675abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        return NULL;
2685abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
2695abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
270ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong#if defined(__ANDROID__)
271ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong    if (curPlaylistHash != NULL) {
272ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong
273ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong        memcpy(curPlaylistHash, hash, sizeof(hash));
274ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong    }
275ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong#endif
276ff8b02346adfc4df113d9223c326aff81e78b54dJinguang Dong
2775abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    return playlist;
2785abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
2795abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
2805abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}  // namespace android
281