Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 822a489e authored by Robert Shih's avatar Robert Shih Committed by Lajos Molnar
Browse files

LiveSession: Add support for block-by-block fetchFile.

Bug: 11854054
Change-Id: I4025ba7fab8fab2e0c720f73894e908fd98a43d8
parent 7e50e1c0
Loading
Loading
Loading
Loading
+63 −34
Original line number Diff line number Diff line
@@ -512,15 +512,36 @@ sp<PlaylistFetcher> LiveSession::addFetcher(const char *uri) {
    return info.mFetcher;
}

/*
 * Illustration of parameters:
 *
 * 0      `range_offset`
 * +------------+-------------------------------------------------------+--+--+
 * |            |                                 | next block to fetch |  |  |
 * |            | `source` handle => `out` buffer |                     |  |  |
 * | `url` file |<--------- buffer size --------->|<--- `block_size` -->|  |  |
 * |            |<----------- `range_length` / buffer capacity ----------->|  |
 * |<------------------------------ file_size ------------------------------->|
 *
 * Special parameter values:
 * - range_length == -1 means entire file
 * - block_size == 0 means entire range
 *
 */
status_t LiveSession::fetchFile(
        const char *url, sp<ABuffer> *out,
        int64_t range_offset, int64_t range_length) {
    *out = NULL;

    sp<DataSource> source;
        int64_t range_offset, int64_t range_length,
        uint32_t block_size, /* download block size */
        sp<DataSource> *source /* to return and reuse source */) {
    off64_t size;
    sp<DataSource> temp_source;
    if (source == NULL) {
        source = &temp_source;
    }

    if (*source == NULL) {
        if (!strncasecmp(url, "file://", 7)) {
        source = new FileSource(url + 7);
            *source = new FileSource(url + 7);
        } else if (strncasecmp(url, "http://", 7)
                && strncasecmp(url, "https://", 8)) {
            return ERROR_UNSUPPORTED;
@@ -534,7 +555,8 @@ status_t LiveSession::fetchFile(
                                "bytes=%lld-%s",
                                range_offset,
                                range_length < 0
                                ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str()));
                                    ? "" : StringPrintf("%lld",
                                            range_offset + range_length - 1).c_str()).c_str()));
            }
            status_t err = mHTTPDataSource->connect(url, &headers);

@@ -542,23 +564,28 @@ status_t LiveSession::fetchFile(
                return err;
            }

        source = mHTTPDataSource;
            *source = mHTTPDataSource;
        }
    }

    off64_t size;
    status_t err = source->getSize(&size);

    if (err != OK) {
    status_t getSizeErr = (*source)->getSize(&size);
    if (getSizeErr != OK) {
        size = 65536;
    }

    sp<ABuffer> buffer = new ABuffer(size);
    sp<ABuffer> buffer = *out != NULL ? *out : new ABuffer(size);
    if (*out == NULL) {
        buffer->setRange(0, 0);
    }

    // adjust range_length if only reading partial block
    if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) {
        range_length = buffer->size() + block_size;
    }
    for (;;) {
        // Only resize when we don't know the size.
        size_t bufferRemaining = buffer->capacity() - buffer->size();

        if (bufferRemaining == 0) {
        if (bufferRemaining == 0 && getSizeErr != OK) {
            bufferRemaining = 32768;

            ALOGV("increasing download buffer to %d bytes",
@@ -583,7 +610,9 @@ status_t LiveSession::fetchFile(
            }
        }

        ssize_t n = source->readAt(
        // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0)
        // to help us break out of the loop.
        ssize_t n = (*source)->readAt(
                buffer->size(), buffer->data() + buffer->size(),
                maxBytesToRead);

+17 −1
Original line number Diff line number Diff line
@@ -145,9 +145,25 @@ private:
    status_t onSeek(const sp<AMessage> &msg);
    void onFinishDisconnect2();

    // If given a non-zero block_size (default 0), it is used to cap the number of
    // bytes read in from the DataSource. If given a non-NULL buffer, new content
    // is read into the end.
    //
    // The DataSource we read from is responsible for signaling error or EOF to help us
    // break out of the read loop. The DataSource can be returned to the caller, so
    // that the caller can reuse it for subsequent fetches (within the initially
    // requested range).
    //
    // For reused HTTP sources, the caller must download a file sequentially without
    // any overlaps or gaps to prevent reconnection.
    status_t fetchFile(
            const char *url, sp<ABuffer> *out,
            int64_t range_offset = 0, int64_t range_length = -1);
            /* request/open a file starting at range_offset for range_length bytes */
            int64_t range_offset = 0, int64_t range_length = -1,
            /* download block size */
            uint32_t block_size = 0,
            /* reuse DataSource if doing partial fetch */
            sp<DataSource> *source = NULL);

    sp<M3UParser> fetchPlaylist(
            const char *url, uint8_t *curPlaylistHash, bool *unchanged);