summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/httplive/LiveSession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/httplive/LiveSession.cpp')
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp943
1 files changed, 0 insertions, 943 deletions
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
deleted file mode 100644
index 0cddd2e..0000000
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ /dev/null
@@ -1,943 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "LiveSession"
-#include <utils/Log.h>
-
-#include "include/LiveSession.h"
-
-#include "LiveDataSource.h"
-
-#include "include/M3UParser.h"
-#include "include/HTTPBase.h"
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <ctype.h>
-#include <openssl/aes.h>
-#include <openssl/md5.h>
-
-namespace android {
-
-LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
- : mFlags(flags),
- mUIDValid(uidValid),
- mUID(uid),
- mDataSource(new LiveDataSource),
- mHTTPDataSource(
- HTTPBase::Create(
- (mFlags & kFlagIncognito)
- ? HTTPBase::kFlagIncognito
- : 0)),
- mPrevBandwidthIndex(-1),
- mLastPlaylistFetchTimeUs(-1),
- mSeqNumber(-1),
- mSeekTimeUs(-1),
- mNumRetries(0),
- mDurationUs(-1),
- mSeekDone(false),
- mDisconnectPending(false),
- mMonitorQueueGeneration(0),
- mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY) {
- if (mUIDValid) {
- mHTTPDataSource->setUID(mUID);
- }
-}
-
-LiveSession::~LiveSession() {
-}
-
-sp<DataSource> LiveSession::getDataSource() {
- return mDataSource;
-}
-
-void LiveSession::connect(
- const char *url, const KeyedVector<String8, String8> *headers) {
- sp<AMessage> msg = new AMessage(kWhatConnect, id());
- msg->setString("url", url);
-
- if (headers != NULL) {
- msg->setPointer(
- "headers",
- new KeyedVector<String8, String8>(*headers));
- }
-
- msg->post();
-}
-
-void LiveSession::disconnect() {
- Mutex::Autolock autoLock(mLock);
- mDisconnectPending = true;
-
- mHTTPDataSource->disconnect();
-
- (new AMessage(kWhatDisconnect, id()))->post();
-}
-
-void LiveSession::seekTo(int64_t timeUs) {
- Mutex::Autolock autoLock(mLock);
- mSeekDone = false;
-
- sp<AMessage> msg = new AMessage(kWhatSeek, id());
- msg->setInt64("timeUs", timeUs);
- msg->post();
-
- while (!mSeekDone) {
- mCondition.wait(mLock);
- }
-}
-
-void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatConnect:
- onConnect(msg);
- break;
-
- case kWhatDisconnect:
- onDisconnect();
- break;
-
- case kWhatMonitorQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mMonitorQueueGeneration) {
- // Stale event
- break;
- }
-
- onMonitorQueue();
- break;
- }
-
- case kWhatSeek:
- onSeek(msg);
- break;
-
- default:
- TRESPASS();
- break;
- }
-}
-
-// static
-int LiveSession::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) {
- if (a->mBandwidth < b->mBandwidth) {
- return -1;
- } else if (a->mBandwidth == b->mBandwidth) {
- return 0;
- }
-
- return 1;
-}
-
-void LiveSession::onConnect(const sp<AMessage> &msg) {
- AString url;
- CHECK(msg->findString("url", &url));
-
- KeyedVector<String8, String8> *headers = NULL;
- if (!msg->findPointer("headers", (void **)&headers)) {
- mExtraHeaders.clear();
- } else {
- mExtraHeaders = *headers;
-
- delete headers;
- headers = NULL;
- }
-
- if (!(mFlags & kFlagIncognito)) {
- ALOGI("onConnect '%s'", url.c_str());
- } else {
- ALOGI("onConnect <URL suppressed>");
- }
-
- mMasterURL = url;
-
- bool dummy;
- sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &dummy);
-
- if (playlist == NULL) {
- ALOGE("unable to fetch master playlist '%s'.", url.c_str());
-
- mDataSource->queueEOS(ERROR_IO);
- return;
- }
-
- if (playlist->isVariantPlaylist()) {
- for (size_t i = 0; i < playlist->size(); ++i) {
- BandwidthItem item;
-
- sp<AMessage> meta;
- playlist->itemAt(i, &item.mURI, &meta);
-
- unsigned long bandwidth;
- CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
-
- mBandwidthItems.push(item);
- }
-
- CHECK_GT(mBandwidthItems.size(), 0u);
-
- mBandwidthItems.sort(SortByBandwidth);
- }
-
- postMonitorQueue();
-}
-
-void LiveSession::onDisconnect() {
- ALOGI("onDisconnect");
-
- mDataSource->queueEOS(ERROR_END_OF_STREAM);
-
- Mutex::Autolock autoLock(mLock);
- mDisconnectPending = false;
-}
-
-status_t LiveSession::fetchFile(
- const char *url, sp<ABuffer> *out,
- int64_t range_offset, int64_t range_length) {
- *out = NULL;
-
- sp<DataSource> source;
-
- if (!strncasecmp(url, "file://", 7)) {
- source = new FileSource(url + 7);
- } else if (strncasecmp(url, "http://", 7)
- && strncasecmp(url, "https://", 8)) {
- return ERROR_UNSUPPORTED;
- } else {
- {
- Mutex::Autolock autoLock(mLock);
-
- if (mDisconnectPending) {
- return ERROR_IO;
- }
- }
-
- KeyedVector<String8, String8> headers = mExtraHeaders;
- if (range_offset > 0 || range_length >= 0) {
- headers.add(
- String8("Range"),
- String8(
- StringPrintf(
- "bytes=%lld-%s",
- range_offset,
- range_length < 0
- ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str()));
- }
- status_t err = mHTTPDataSource->connect(url, &headers);
-
- if (err != OK) {
- return err;
- }
-
- source = mHTTPDataSource;
- }
-
- off64_t size;
- status_t err = source->getSize(&size);
-
- if (err != OK) {
- size = 65536;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- buffer->setRange(0, 0);
-
- for (;;) {
- size_t bufferRemaining = buffer->capacity() - buffer->size();
-
- if (bufferRemaining == 0) {
- bufferRemaining = 32768;
-
- ALOGV("increasing download buffer to %d bytes",
- buffer->size() + bufferRemaining);
-
- sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
- memcpy(copy->data(), buffer->data(), buffer->size());
- copy->setRange(0, buffer->size());
-
- buffer = copy;
- }
-
- size_t maxBytesToRead = bufferRemaining;
- if (range_length >= 0) {
- int64_t bytesLeftInRange = range_length - buffer->size();
- if (bytesLeftInRange < maxBytesToRead) {
- maxBytesToRead = bytesLeftInRange;
-
- if (bytesLeftInRange == 0) {
- break;
- }
- }
- }
-
- ssize_t n = source->readAt(
- buffer->size(), buffer->data() + buffer->size(),
- maxBytesToRead);
-
- if (n < 0) {
- return n;
- }
-
- if (n == 0) {
- break;
- }
-
- buffer->setRange(0, buffer->size() + (size_t)n);
- }
-
- *out = buffer;
-
- return OK;
-}
-
-sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) {
- *unchanged = false;
-
- sp<ABuffer> buffer;
- status_t err = fetchFile(url, &buffer);
-
- if (err != OK) {
- return NULL;
- }
-
- // MD5 functionality is not available on the simulator, treat all
- // playlists as changed.
-
-#if defined(HAVE_ANDROID_OS)
- uint8_t hash[16];
-
- MD5_CTX m;
- MD5_Init(&m);
- MD5_Update(&m, buffer->data(), buffer->size());
-
- MD5_Final(hash, &m);
-
- if (mPlaylist != NULL && !memcmp(hash, mPlaylistHash, 16)) {
- // playlist unchanged
-
- if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) {
- mRefreshState = (RefreshState)(mRefreshState + 1);
- }
-
- *unchanged = true;
-
- ALOGV("Playlist unchanged, refresh state is now %d",
- (int)mRefreshState);
-
- return NULL;
- }
-
- memcpy(mPlaylistHash, hash, sizeof(hash));
-
- mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
-#endif
-
- sp<M3UParser> playlist =
- new M3UParser(url, buffer->data(), buffer->size());
-
- if (playlist->initCheck() != OK) {
- ALOGE("failed to parse .m3u8 playlist");
-
- return NULL;
- }
-
- return playlist;
-}
-
-static double uniformRand() {
- return (double)rand() / RAND_MAX;
-}
-
-size_t LiveSession::getBandwidthIndex() {
- if (mBandwidthItems.size() == 0) {
- return 0;
- }
-
-#if 1
- int32_t bandwidthBps;
- if (mHTTPDataSource != NULL
- && mHTTPDataSource->estimateBandwidth(&bandwidthBps)) {
- ALOGV("bandwidth estimated at %.2f kbps", bandwidthBps / 1024.0f);
- } else {
- ALOGV("no bandwidth estimate.");
- return 0; // Pick the lowest bandwidth stream by default.
- }
-
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.httplive.max-bw", value, NULL)) {
- char *end;
- long maxBw = strtoul(value, &end, 10);
- if (end > value && *end == '\0') {
- if (maxBw > 0 && bandwidthBps > maxBw) {
- ALOGV("bandwidth capped to %ld bps", maxBw);
- bandwidthBps = maxBw;
- }
- }
- }
-
- // Consider only 80% of the available bandwidth usable.
- bandwidthBps = (bandwidthBps * 8) / 10;
-
- // Pick the highest bandwidth stream below or equal to estimated bandwidth.
-
- size_t index = mBandwidthItems.size() - 1;
- while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth
- > (size_t)bandwidthBps) {
- --index;
- }
-#elif 0
- // Change bandwidth at random()
- size_t index = uniformRand() * mBandwidthItems.size();
-#elif 0
- // There's a 50% chance to stay on the current bandwidth and
- // a 50% chance to switch to the next higher bandwidth (wrapping around
- // to lowest)
- const size_t kMinIndex = 0;
-
- size_t index;
- if (mPrevBandwidthIndex < 0) {
- index = kMinIndex;
- } else if (uniformRand() < 0.5) {
- index = (size_t)mPrevBandwidthIndex;
- } else {
- index = mPrevBandwidthIndex + 1;
- if (index == mBandwidthItems.size()) {
- index = kMinIndex;
- }
- }
-#elif 0
- // Pick the highest bandwidth stream below or equal to 1.2 Mbit/sec
-
- size_t index = mBandwidthItems.size() - 1;
- while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth > 1200000) {
- --index;
- }
-#else
- size_t index = mBandwidthItems.size() - 1; // Highest bandwidth stream
-#endif
-
- return index;
-}
-
-bool LiveSession::timeToRefreshPlaylist(int64_t nowUs) const {
- if (mPlaylist == NULL) {
- CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
- return true;
- }
-
- int32_t targetDurationSecs;
- CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
-
- int64_t targetDurationUs = targetDurationSecs * 1000000ll;
-
- int64_t minPlaylistAgeUs;
-
- switch (mRefreshState) {
- case INITIAL_MINIMUM_RELOAD_DELAY:
- {
- size_t n = mPlaylist->size();
- if (n > 0) {
- sp<AMessage> itemMeta;
- CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta));
-
- int64_t itemDurationUs;
- CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
-
- minPlaylistAgeUs = itemDurationUs;
- break;
- }
-
- // fall through
- }
-
- case FIRST_UNCHANGED_RELOAD_ATTEMPT:
- {
- minPlaylistAgeUs = targetDurationUs / 2;
- break;
- }
-
- case SECOND_UNCHANGED_RELOAD_ATTEMPT:
- {
- minPlaylistAgeUs = (targetDurationUs * 3) / 2;
- break;
- }
-
- case THIRD_UNCHANGED_RELOAD_ATTEMPT:
- {
- minPlaylistAgeUs = targetDurationUs * 3;
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-
- return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs;
-}
-
-void LiveSession::onDownloadNext() {
- size_t bandwidthIndex = getBandwidthIndex();
-
-rinse_repeat:
- int64_t nowUs = ALooper::GetNowUs();
-
- if (mLastPlaylistFetchTimeUs < 0
- || (ssize_t)bandwidthIndex != mPrevBandwidthIndex
- || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) {
- AString url;
- if (mBandwidthItems.size() > 0) {
- url = mBandwidthItems.editItemAt(bandwidthIndex).mURI;
- } else {
- url = mMasterURL;
- }
-
- bool firstTime = (mPlaylist == NULL);
-
- if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
- // If we switch bandwidths, do not pay any heed to whether
- // playlists changed since the last time...
- mPlaylist.clear();
- }
-
- bool unchanged;
- sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged);
- if (playlist == NULL) {
- if (unchanged) {
- // We succeeded in fetching the playlist, but it was
- // unchanged from the last time we tried.
- } else {
- ALOGE("failed to load playlist at url '%s'", url.c_str());
- mDataSource->queueEOS(ERROR_IO);
- return;
- }
- } else {
- mPlaylist = playlist;
- }
-
- if (firstTime) {
- Mutex::Autolock autoLock(mLock);
-
- if (!mPlaylist->isComplete()) {
- mDurationUs = -1;
- } else {
- mDurationUs = 0;
- for (size_t i = 0; i < mPlaylist->size(); ++i) {
- sp<AMessage> itemMeta;
- CHECK(mPlaylist->itemAt(
- i, NULL /* uri */, &itemMeta));
-
- int64_t itemDurationUs;
- CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
-
- mDurationUs += itemDurationUs;
- }
- }
- }
-
- mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
- }
-
- int32_t firstSeqNumberInPlaylist;
- if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
- "media-sequence", &firstSeqNumberInPlaylist)) {
- firstSeqNumberInPlaylist = 0;
- }
-
- bool seekDiscontinuity = false;
- bool explicitDiscontinuity = false;
- bool bandwidthChanged = false;
-
- if (mSeekTimeUs >= 0) {
- if (mPlaylist->isComplete()) {
- size_t index = 0;
- int64_t segmentStartUs = 0;
- while (index < mPlaylist->size()) {
- sp<AMessage> itemMeta;
- CHECK(mPlaylist->itemAt(
- index, NULL /* uri */, &itemMeta));
-
- int64_t itemDurationUs;
- CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
-
- if (mSeekTimeUs < segmentStartUs + itemDurationUs) {
- break;
- }
-
- segmentStartUs += itemDurationUs;
- ++index;
- }
-
- if (index < mPlaylist->size()) {
- int32_t newSeqNumber = firstSeqNumberInPlaylist + index;
-
- if (newSeqNumber != mSeqNumber) {
- ALOGI("seeking to seq no %d", newSeqNumber);
-
- mSeqNumber = newSeqNumber;
-
- mDataSource->reset();
-
- // reseting the data source will have had the
- // side effect of discarding any previously queued
- // bandwidth change discontinuity.
- // Therefore we'll need to treat these seek
- // discontinuities as involving a bandwidth change
- // even if they aren't directly.
- seekDiscontinuity = true;
- bandwidthChanged = true;
- }
- }
- }
-
- mSeekTimeUs = -1;
-
- Mutex::Autolock autoLock(mLock);
- mSeekDone = true;
- mCondition.broadcast();
- }
-
- if (mSeqNumber < 0) {
- mSeqNumber = firstSeqNumberInPlaylist;
- }
-
- int32_t lastSeqNumberInPlaylist =
- firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
-
- if (mSeqNumber < firstSeqNumberInPlaylist
- || mSeqNumber > lastSeqNumberInPlaylist) {
- if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
- // Go back to the previous bandwidth.
-
- ALOGI("new bandwidth does not have the sequence number "
- "we're looking for, switching back to previous bandwidth");
-
- mLastPlaylistFetchTimeUs = -1;
- bandwidthIndex = mPrevBandwidthIndex;
- goto rinse_repeat;
- }
-
- if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
- ++mNumRetries;
-
- if (mSeqNumber > lastSeqNumberInPlaylist) {
- mLastPlaylistFetchTimeUs = -1;
- postMonitorQueue(3000000ll);
- return;
- }
-
- // we've missed the boat, let's start from the lowest sequence
- // number available and signal a discontinuity.
-
- ALOGI("We've missed the boat, restarting playback.");
- mSeqNumber = lastSeqNumberInPlaylist;
- explicitDiscontinuity = true;
-
- // fall through
- } else {
- ALOGE("Cannot find sequence number %d in playlist "
- "(contains %d - %d)",
- mSeqNumber, firstSeqNumberInPlaylist,
- firstSeqNumberInPlaylist + mPlaylist->size() - 1);
-
- mDataSource->queueEOS(ERROR_END_OF_STREAM);
- return;
- }
- }
-
- mNumRetries = 0;
-
- AString uri;
- sp<AMessage> itemMeta;
- CHECK(mPlaylist->itemAt(
- mSeqNumber - firstSeqNumberInPlaylist,
- &uri,
- &itemMeta));
-
- int32_t val;
- if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
- explicitDiscontinuity = true;
- }
-
- int64_t range_offset, range_length;
- if (!itemMeta->findInt64("range-offset", &range_offset)
- || !itemMeta->findInt64("range-length", &range_length)) {
- range_offset = 0;
- range_length = -1;
- }
-
- sp<ABuffer> buffer;
- status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length);
- if (err != OK) {
- ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
- mDataSource->queueEOS(err);
- return;
- }
-
- CHECK(buffer != NULL);
-
- err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
-
- if (err != OK) {
- ALOGE("decryptBuffer failed w/ error %d", err);
-
- mDataSource->queueEOS(err);
- return;
- }
-
- if (buffer->size() == 0 || buffer->data()[0] != 0x47) {
- // Not a transport stream???
-
- ALOGE("This doesn't look like a transport stream...");
-
- mBandwidthItems.removeAt(bandwidthIndex);
-
- if (mBandwidthItems.isEmpty()) {
- mDataSource->queueEOS(ERROR_UNSUPPORTED);
- return;
- }
-
- ALOGI("Retrying with a different bandwidth stream.");
-
- mLastPlaylistFetchTimeUs = -1;
- bandwidthIndex = getBandwidthIndex();
- mPrevBandwidthIndex = bandwidthIndex;
- mSeqNumber = -1;
-
- goto rinse_repeat;
- }
-
- if ((size_t)mPrevBandwidthIndex != bandwidthIndex) {
- bandwidthChanged = true;
- }
-
- if (mPrevBandwidthIndex < 0) {
- // Don't signal a bandwidth change at the very beginning of
- // playback.
- bandwidthChanged = false;
- }
-
- if (seekDiscontinuity || explicitDiscontinuity || bandwidthChanged) {
- // Signal discontinuity.
-
- ALOGI("queueing discontinuity (seek=%d, explicit=%d, bandwidthChanged=%d)",
- seekDiscontinuity, explicitDiscontinuity, bandwidthChanged);
-
- sp<ABuffer> tmp = new ABuffer(188);
- memset(tmp->data(), 0, tmp->size());
-
- // signal a 'hard' discontinuity for explicit or bandwidthChanged.
- tmp->data()[1] = (explicitDiscontinuity || bandwidthChanged) ? 1 : 0;
-
- mDataSource->queueBuffer(tmp);
- }
-
- mDataSource->queueBuffer(buffer);
-
- mPrevBandwidthIndex = bandwidthIndex;
- ++mSeqNumber;
-
- postMonitorQueue();
-}
-
-void LiveSession::onMonitorQueue() {
- if (mSeekTimeUs >= 0
- || mDataSource->countQueuedBuffers() < kMaxNumQueuedFragments) {
- onDownloadNext();
- } else {
- postMonitorQueue(1000000ll);
- }
-}
-
-status_t LiveSession::decryptBuffer(
- size_t playlistIndex, const sp<ABuffer> &buffer) {
- sp<AMessage> itemMeta;
- bool found = false;
- AString method;
-
- for (ssize_t i = playlistIndex; i >= 0; --i) {
- AString uri;
- CHECK(mPlaylist->itemAt(i, &uri, &itemMeta));
-
- if (itemMeta->findString("cipher-method", &method)) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- method = "NONE";
- }
-
- if (method == "NONE") {
- return OK;
- } else if (!(method == "AES-128")) {
- ALOGE("Unsupported cipher method '%s'", method.c_str());
- return ERROR_UNSUPPORTED;
- }
-
- AString keyURI;
- if (!itemMeta->findString("cipher-uri", &keyURI)) {
- ALOGE("Missing key uri");
- return ERROR_MALFORMED;
- }
-
- ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
-
- sp<ABuffer> key;
- if (index >= 0) {
- key = mAESKeyForURI.valueAt(index);
- } else {
- key = new ABuffer(16);
-
- sp<HTTPBase> keySource =
- HTTPBase::Create(
- (mFlags & kFlagIncognito)
- ? HTTPBase::kFlagIncognito
- : 0);
-
- if (mUIDValid) {
- keySource->setUID(mUID);
- }
-
- status_t err =
- keySource->connect(
- keyURI.c_str(),
- mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
-
- if (err == OK) {
- size_t offset = 0;
- while (offset < 16) {
- ssize_t n = keySource->readAt(
- offset, key->data() + offset, 16 - offset);
- if (n <= 0) {
- err = ERROR_IO;
- break;
- }
-
- offset += n;
- }
- }
-
- if (err != OK) {
- ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
- return ERROR_IO;
- }
-
- mAESKeyForURI.add(keyURI, key);
- }
-
- AES_KEY aes_key;
- if (AES_set_decrypt_key(key->data(), 128, &aes_key) != 0) {
- ALOGE("failed to set AES decryption key.");
- return UNKNOWN_ERROR;
- }
-
- unsigned char aes_ivec[16];
-
- AString iv;
- if (itemMeta->findString("cipher-iv", &iv)) {
- if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
- || iv.size() != 16 * 2 + 2) {
- ALOGE("malformed cipher IV '%s'.", iv.c_str());
- return ERROR_MALFORMED;
- }
-
- memset(aes_ivec, 0, sizeof(aes_ivec));
- for (size_t i = 0; i < 16; ++i) {
- char c1 = tolower(iv.c_str()[2 + 2 * i]);
- char c2 = tolower(iv.c_str()[3 + 2 * i]);
- if (!isxdigit(c1) || !isxdigit(c2)) {
- ALOGE("malformed cipher IV '%s'.", iv.c_str());
- return ERROR_MALFORMED;
- }
- uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
- uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
-
- aes_ivec[i] = nibble1 << 4 | nibble2;
- }
- } else {
- memset(aes_ivec, 0, sizeof(aes_ivec));
- aes_ivec[15] = mSeqNumber & 0xff;
- aes_ivec[14] = (mSeqNumber >> 8) & 0xff;
- aes_ivec[13] = (mSeqNumber >> 16) & 0xff;
- aes_ivec[12] = (mSeqNumber >> 24) & 0xff;
- }
-
- AES_cbc_encrypt(
- buffer->data(), buffer->data(), buffer->size(),
- &aes_key, aes_ivec, AES_DECRYPT);
-
- // hexdump(buffer->data(), buffer->size());
-
- size_t n = buffer->size();
- CHECK_GT(n, 0u);
-
- size_t pad = buffer->data()[n - 1];
-
- CHECK_GT(pad, 0u);
- CHECK_LE(pad, 16u);
- CHECK_GE((size_t)n, pad);
- for (size_t i = 0; i < pad; ++i) {
- CHECK_EQ((unsigned)buffer->data()[n - 1 - i], pad);
- }
-
- n -= pad;
-
- buffer->setRange(buffer->offset(), n);
-
- return OK;
-}
-
-void LiveSession::postMonitorQueue(int64_t delayUs) {
- sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
- msg->setInt32("generation", ++mMonitorQueueGeneration);
- msg->post(delayUs);
-}
-
-void LiveSession::onSeek(const sp<AMessage> &msg) {
- int64_t timeUs;
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- mSeekTimeUs = timeUs;
- postMonitorQueue();
-}
-
-status_t LiveSession::getDuration(int64_t *durationUs) {
- Mutex::Autolock autoLock(mLock);
- *durationUs = mDurationUs;
-
- return OK;
-}
-
-bool LiveSession::isSeekable() {
- int64_t durationUs;
- return getDuration(&durationUs) == OK && durationUs >= 0;
-}
-
-} // namespace android
-