LiveSession.cpp revision ab8a0badb8fb1e294dacf2eb6a891439f348aff9
1a44153c1a57202fb538659eb50706e60454d6273Andreas Huber/* 2a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * Copyright (C) 2010 The Android Open Source Project 3a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * 4a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * you may not use this file except in compliance with the License. 6a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * You may obtain a copy of the License at 7a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * 8a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * 10a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * Unless required by applicable law or agreed to in writing, software 11a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * See the License for the specific language governing permissions and 14a44153c1a57202fb538659eb50706e60454d6273Andreas Huber * limitations under the License. 15a44153c1a57202fb538659eb50706e60454d6273Andreas Huber */ 16a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 17a44153c1a57202fb538659eb50706e60454d6273Andreas Huber//#define LOG_NDEBUG 0 18a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#define LOG_TAG "LiveSession" 19a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <utils/Log.h> 20a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 21a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include "include/LiveSession.h" 22a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 23a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include "LiveDataSource.h" 24a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 25a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include "include/M3UParser.h" 26a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include "include/NuHTTPDataSource.h" 27a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 28a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <cutils/properties.h> 29a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/foundation/hexdump.h> 30a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/foundation/ABuffer.h> 31a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/foundation/ADebug.h> 32a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/foundation/AMessage.h> 33a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/DataSource.h> 34a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/FileSource.h> 35a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <media/stagefright/MediaErrors.h> 36a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 37a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <ctype.h> 38a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#include <openssl/aes.h> 39a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 40a44153c1a57202fb538659eb50706e60454d6273Andreas Hubernamespace android { 41a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 42a44153c1a57202fb538659eb50706e60454d6273Andreas Huberconst int64_t LiveSession::kMaxPlaylistAgeUs = 15000000ll; 43a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 44a44153c1a57202fb538659eb50706e60454d6273Andreas HuberLiveSession::LiveSession() 45a44153c1a57202fb538659eb50706e60454d6273Andreas Huber : mDataSource(new LiveDataSource), 46a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mHTTPDataSource(new NuHTTPDataSource), 47a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mPrevBandwidthIndex(-1), 48a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mLastPlaylistFetchTimeUs(-1), 49a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeqNumber(-1), 50a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekTimeUs(-1), 51a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mNumRetries(0), 52a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDurationUs(-1), 53a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekDone(false), 54ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber mDisconnectPending(false), 55a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mMonitorQueueGeneration(0) { 56a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 57a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 58a44153c1a57202fb538659eb50706e60454d6273Andreas HuberLiveSession::~LiveSession() { 59a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 60a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 61a44153c1a57202fb538659eb50706e60454d6273Andreas Hubersp<DataSource> LiveSession::getDataSource() { 62a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return mDataSource; 63a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 64a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 65a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::connect(const char *url) { 66a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> msg = new AMessage(kWhatConnect, id()); 67a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->setString("url", url); 68a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->post(); 69a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 70a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 71a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::disconnect() { 72ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber Mutex::Autolock autoLock(mLock); 73ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber mDisconnectPending = true; 74ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 75ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber mHTTPDataSource->disconnect(); 76ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 77a44153c1a57202fb538659eb50706e60454d6273Andreas Huber (new AMessage(kWhatDisconnect, id()))->post(); 78a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 79a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 80a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::seekTo(int64_t timeUs) { 81a44153c1a57202fb538659eb50706e60454d6273Andreas Huber Mutex::Autolock autoLock(mLock); 82a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekDone = false; 83a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 84a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> msg = new AMessage(kWhatSeek, id()); 85a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->setInt64("timeUs", timeUs); 86a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->post(); 87a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 88a44153c1a57202fb538659eb50706e60454d6273Andreas Huber while (!mSeekDone) { 89a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mCondition.wait(mLock); 90a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 91a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 92a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 93a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onMessageReceived(const sp<AMessage> &msg) { 94a44153c1a57202fb538659eb50706e60454d6273Andreas Huber switch (msg->what()) { 95a44153c1a57202fb538659eb50706e60454d6273Andreas Huber case kWhatConnect: 96a44153c1a57202fb538659eb50706e60454d6273Andreas Huber onConnect(msg); 97a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 98a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 99a44153c1a57202fb538659eb50706e60454d6273Andreas Huber case kWhatDisconnect: 100a44153c1a57202fb538659eb50706e60454d6273Andreas Huber onDisconnect(); 101a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 102a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 103a44153c1a57202fb538659eb50706e60454d6273Andreas Huber case kWhatMonitorQueue: 104a44153c1a57202fb538659eb50706e60454d6273Andreas Huber { 105a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t generation; 106a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(msg->findInt32("generation", &generation)); 107a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 108a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (generation != mMonitorQueueGeneration) { 109a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Stale event 110a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 111a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 112a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 113a44153c1a57202fb538659eb50706e60454d6273Andreas Huber onMonitorQueue(); 114a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 115a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 116a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 117a44153c1a57202fb538659eb50706e60454d6273Andreas Huber case kWhatSeek: 118a44153c1a57202fb538659eb50706e60454d6273Andreas Huber onSeek(msg); 119a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 120a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 121a44153c1a57202fb538659eb50706e60454d6273Andreas Huber default: 122a44153c1a57202fb538659eb50706e60454d6273Andreas Huber TRESPASS(); 123a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 124a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 125a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 126a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 127a44153c1a57202fb538659eb50706e60454d6273Andreas Huber// static 128a44153c1a57202fb538659eb50706e60454d6273Andreas Huberint LiveSession::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) { 129a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (a->mBandwidth < b->mBandwidth) { 130a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return -1; 131a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else if (a->mBandwidth == b->mBandwidth) { 132a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return 0; 133a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 134a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 135a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return 1; 136a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 137a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 138a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onConnect(const sp<AMessage> &msg) { 139a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString url; 140a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(msg->findString("url", &url)); 141a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 142a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGI("onConnect '%s'", url.c_str()); 143a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 144a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mMasterURL = url; 145a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 146a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<M3UParser> playlist = fetchPlaylist(url.c_str()); 147ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 148ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber if (playlist == NULL) { 149ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber LOGE("unable to fetch master playlist '%s'.", url.c_str()); 150ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 151ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber mDataSource->queueEOS(ERROR_IO); 152ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber return; 153ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber } 154a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 155a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (playlist->isVariantPlaylist()) { 156a44153c1a57202fb538659eb50706e60454d6273Andreas Huber for (size_t i = 0; i < playlist->size(); ++i) { 157a44153c1a57202fb538659eb50706e60454d6273Andreas Huber BandwidthItem item; 158a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 159a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> meta; 160a44153c1a57202fb538659eb50706e60454d6273Andreas Huber playlist->itemAt(i, &item.mURI, &meta); 161a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 162a44153c1a57202fb538659eb50706e60454d6273Andreas Huber unsigned long bandwidth; 163a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth)); 164a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 165a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mBandwidthItems.push(item); 166a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 167a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 168a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_GT(mBandwidthItems.size(), 0u); 169a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 170a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mBandwidthItems.sort(SortByBandwidth); 171a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 1725bc087c573c70c84c6a39946457590b42d392a33Andreas Huber char value[PROPERTY_VALUE_MAX]; 1734b197e1ffe46eb73ebdb80efc984bfde336b8e92Andreas Huber if (property_get("media.httplive.disable-nuplayer", value, NULL) 1744b197e1ffe46eb73ebdb80efc984bfde336b8e92Andreas Huber && (!strcasecmp(value, "true") || !strcmp(value, "1"))) { 1755bc087c573c70c84c6a39946457590b42d392a33Andreas Huber // The "legacy" player cannot deal with audio format changes, 1765bc087c573c70c84c6a39946457590b42d392a33Andreas Huber // some streams use different audio encoding parameters for 1775bc087c573c70c84c6a39946457590b42d392a33Andreas Huber // their lowest bandwidth stream. 1785bc087c573c70c84c6a39946457590b42d392a33Andreas Huber if (mBandwidthItems.size() > 1) { 1795bc087c573c70c84c6a39946457590b42d392a33Andreas Huber // XXX Remove the lowest bitrate stream for now... 1805bc087c573c70c84c6a39946457590b42d392a33Andreas Huber mBandwidthItems.removeAt(0); 1815bc087c573c70c84c6a39946457590b42d392a33Andreas Huber } 182a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 183a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 184a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 185a44153c1a57202fb538659eb50706e60454d6273Andreas Huber postMonitorQueue(); 186a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 187a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 188a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onDisconnect() { 189a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGI("onDisconnect"); 190a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 191a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDataSource->queueEOS(ERROR_END_OF_STREAM); 192ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 193ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber Mutex::Autolock autoLock(mLock); 194ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber mDisconnectPending = false; 195a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 196a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 197a44153c1a57202fb538659eb50706e60454d6273Andreas Huberstatus_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { 198a44153c1a57202fb538659eb50706e60454d6273Andreas Huber *out = NULL; 199a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 200a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<DataSource> source; 201a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 202a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!strncasecmp(url, "file://", 7)) { 203a44153c1a57202fb538659eb50706e60454d6273Andreas Huber source = new FileSource(url + 7); 204df42f949c8bd05b81d94633767514fff88f52062Andreas Huber } else if (strncasecmp(url, "http://", 7)) { 205df42f949c8bd05b81d94633767514fff88f52062Andreas Huber return ERROR_UNSUPPORTED; 206a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 207ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber { 208ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber Mutex::Autolock autoLock(mLock); 209ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 210ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber if (mDisconnectPending) { 211ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber return ERROR_IO; 212ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber } 213ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber } 214ab8a0badb8fb1e294dacf2eb6a891439f348aff9Andreas Huber 215a44153c1a57202fb538659eb50706e60454d6273Andreas Huber status_t err = mHTTPDataSource->connect(url); 216a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 217a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (err != OK) { 218a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return err; 219a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 220a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 221a44153c1a57202fb538659eb50706e60454d6273Andreas Huber source = mHTTPDataSource; 222a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 223a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 224a44153c1a57202fb538659eb50706e60454d6273Andreas Huber off64_t size; 225a44153c1a57202fb538659eb50706e60454d6273Andreas Huber status_t err = source->getSize(&size); 226a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 227a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (err != OK) { 228a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size = 65536; 229a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 230a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 231a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> buffer = new ABuffer(size); 232a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->setRange(0, 0); 233a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 234a44153c1a57202fb538659eb50706e60454d6273Andreas Huber for (;;) { 235a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t bufferRemaining = buffer->capacity() - buffer->size(); 236a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 237a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (bufferRemaining == 0) { 238a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bufferRemaining = 32768; 239a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 240a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGV("increasing download buffer to %d bytes", 241a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->size() + bufferRemaining); 242a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 243a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining); 244a44153c1a57202fb538659eb50706e60454d6273Andreas Huber memcpy(copy->data(), buffer->data(), buffer->size()); 245a44153c1a57202fb538659eb50706e60454d6273Andreas Huber copy->setRange(0, buffer->size()); 246a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 247a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer = copy; 248a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 249a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 250a44153c1a57202fb538659eb50706e60454d6273Andreas Huber ssize_t n = source->readAt( 251a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->size(), buffer->data() + buffer->size(), 252a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bufferRemaining); 253a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 254a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (n < 0) { 25520ad3a341a96e7746015ccb7369fa567897e11f6Andreas Huber return n; 256a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 257a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 258a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (n == 0) { 259a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 260a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 261a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 262a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->setRange(0, buffer->size() + (size_t)n); 263a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 264a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 265a44153c1a57202fb538659eb50706e60454d6273Andreas Huber *out = buffer; 266a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 267a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return OK; 268a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 269a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 270a44153c1a57202fb538659eb50706e60454d6273Andreas Hubersp<M3UParser> LiveSession::fetchPlaylist(const char *url) { 271a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> buffer; 272a44153c1a57202fb538659eb50706e60454d6273Andreas Huber status_t err = fetchFile(url, &buffer); 273a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 274a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (err != OK) { 275a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return NULL; 276a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 277a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 278a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<M3UParser> playlist = 279a44153c1a57202fb538659eb50706e60454d6273Andreas Huber new M3UParser(url, buffer->data(), buffer->size()); 280a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 281a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (playlist->initCheck() != OK) { 282a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return NULL; 283a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 284a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 285a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return playlist; 286a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 287a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 288a44153c1a57202fb538659eb50706e60454d6273Andreas Huberstatic double uniformRand() { 289a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return (double)rand() / RAND_MAX; 290a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 291a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 292a44153c1a57202fb538659eb50706e60454d6273Andreas Hubersize_t LiveSession::getBandwidthIndex() { 293a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mBandwidthItems.size() == 0) { 294a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return 0; 295a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 296a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 297a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#if 1 298a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t bandwidthBps; 299a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mHTTPDataSource != NULL 300a44153c1a57202fb538659eb50706e60454d6273Andreas Huber && mHTTPDataSource->estimateBandwidth(&bandwidthBps)) { 301a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGV("bandwidth estimated at %.2f kbps", bandwidthBps / 1024.0f); 302a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 303a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGV("no bandwidth estimate."); 304a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return 0; // Pick the lowest bandwidth stream by default. 305a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 306a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 307a44153c1a57202fb538659eb50706e60454d6273Andreas Huber char value[PROPERTY_VALUE_MAX]; 308a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (property_get("media.httplive.max-bw", value, NULL)) { 309a44153c1a57202fb538659eb50706e60454d6273Andreas Huber char *end; 310a44153c1a57202fb538659eb50706e60454d6273Andreas Huber long maxBw = strtoul(value, &end, 10); 311a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (end > value && *end == '\0') { 312a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (maxBw > 0 && bandwidthBps > maxBw) { 313a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGV("bandwidth capped to %ld bps", maxBw); 314a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bandwidthBps = maxBw; 315a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 316a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 317a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 318a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 319a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Consider only 80% of the available bandwidth usable. 320a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bandwidthBps = (bandwidthBps * 8) / 10; 321a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 322a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Pick the highest bandwidth stream below or equal to estimated bandwidth. 323a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 324a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t index = mBandwidthItems.size() - 1; 325a44153c1a57202fb538659eb50706e60454d6273Andreas Huber while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth 326a44153c1a57202fb538659eb50706e60454d6273Andreas Huber > (size_t)bandwidthBps) { 327a44153c1a57202fb538659eb50706e60454d6273Andreas Huber --index; 328a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 329a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#elif 0 330a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Change bandwidth at random() 331a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t index = uniformRand() * mBandwidthItems.size(); 332a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#elif 0 333a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // There's a 50% chance to stay on the current bandwidth and 334a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // a 50% chance to switch to the next higher bandwidth (wrapping around 335a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // to lowest) 336a44153c1a57202fb538659eb50706e60454d6273Andreas Huber const size_t kMinIndex = 0; 337a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 338a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t index; 339a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mPrevBandwidthIndex < 0) { 340a44153c1a57202fb538659eb50706e60454d6273Andreas Huber index = kMinIndex; 341a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else if (uniformRand() < 0.5) { 342a44153c1a57202fb538659eb50706e60454d6273Andreas Huber index = (size_t)mPrevBandwidthIndex; 343a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 344a44153c1a57202fb538659eb50706e60454d6273Andreas Huber index = mPrevBandwidthIndex + 1; 345a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (index == mBandwidthItems.size()) { 346a44153c1a57202fb538659eb50706e60454d6273Andreas Huber index = kMinIndex; 347a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 348a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 349a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#elif 0 350a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Pick the highest bandwidth stream below or equal to 1.2 Mbit/sec 351a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 352a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t index = mBandwidthItems.size() - 1; 353a44153c1a57202fb538659eb50706e60454d6273Andreas Huber while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth > 1200000) { 354a44153c1a57202fb538659eb50706e60454d6273Andreas Huber --index; 355a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 356a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#else 357a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t index = mBandwidthItems.size() - 1; // Highest bandwidth stream 358a44153c1a57202fb538659eb50706e60454d6273Andreas Huber#endif 359a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 360a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return index; 361a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 362a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 363a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onDownloadNext() { 364a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t bandwidthIndex = getBandwidthIndex(); 365a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 366aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huberrinse_repeat: 367a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int64_t nowUs = ALooper::GetNowUs(); 368a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 369a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mLastPlaylistFetchTimeUs < 0 370a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || (ssize_t)bandwidthIndex != mPrevBandwidthIndex 371a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || (!mPlaylist->isComplete() 372a44153c1a57202fb538659eb50706e60454d6273Andreas Huber && mLastPlaylistFetchTimeUs + kMaxPlaylistAgeUs <= nowUs)) { 373a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString url; 374a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mBandwidthItems.size() > 0) { 375a44153c1a57202fb538659eb50706e60454d6273Andreas Huber url = mBandwidthItems.editItemAt(bandwidthIndex).mURI; 376a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 377a44153c1a57202fb538659eb50706e60454d6273Andreas Huber url = mMasterURL; 378a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 379a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 380a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bool firstTime = (mPlaylist == NULL); 381a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 382a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mPlaylist = fetchPlaylist(url.c_str()); 3836e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber if (mPlaylist == NULL) { 3846e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber LOGE("failed to load playlist at url '%s'", url.c_str()); 3856e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber mDataSource->queueEOS(ERROR_IO); 3866e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber return; 3876e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber } 388a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 389a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (firstTime) { 390a44153c1a57202fb538659eb50706e60454d6273Andreas Huber Mutex::Autolock autoLock(mLock); 391a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 392a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t targetDuration; 393a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!mPlaylist->isComplete() 394a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || !mPlaylist->meta()->findInt32( 395a44153c1a57202fb538659eb50706e60454d6273Andreas Huber "target-duration", &targetDuration)) { 396a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDurationUs = -1; 397a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 398a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDurationUs = 1000000ll * targetDuration * mPlaylist->size(); 399a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 400a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 401a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 402a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mLastPlaylistFetchTimeUs = ALooper::GetNowUs(); 403a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 404a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 405a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t firstSeqNumberInPlaylist; 406a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32( 407a44153c1a57202fb538659eb50706e60454d6273Andreas Huber "media-sequence", &firstSeqNumberInPlaylist)) { 408a44153c1a57202fb538659eb50706e60454d6273Andreas Huber firstSeqNumberInPlaylist = 0; 409a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 410a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 411a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bool explicitDiscontinuity = false; 41222fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber bool bandwidthChanged = false; 413a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 414a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mSeekTimeUs >= 0) { 415a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t targetDuration; 416a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mPlaylist->isComplete() && 417a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mPlaylist->meta()->findInt32( 418a44153c1a57202fb538659eb50706e60454d6273Andreas Huber "target-duration", &targetDuration)) { 419a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int64_t seekTimeSecs = (mSeekTimeUs + 500000ll) / 1000000ll; 420a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int64_t index = seekTimeSecs / targetDuration; 421a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 422a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (index >= 0 && index < mPlaylist->size()) { 42343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber int32_t newSeqNumber = firstSeqNumberInPlaylist + index; 424a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 42543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber if (newSeqNumber != mSeqNumber) { 42643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber LOGI("seeking to seq no %d", newSeqNumber); 42743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 42843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber mSeqNumber = newSeqNumber; 42943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 43043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber mDataSource->reset(); 43143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 43222fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // reseting the data source will have had the 43322fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // side effect of discarding any previously queued 43422fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // bandwidth change discontinuity. 43522fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // Therefore we'll need to treat these explicit 43622fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // discontinuities as involving a bandwidth change 43722fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // even if they aren't directly. 43843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber explicitDiscontinuity = true; 43922fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber bandwidthChanged = true; 44043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber } 441a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 442a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 443a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 444a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekTimeUs = -1; 445a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 446a44153c1a57202fb538659eb50706e60454d6273Andreas Huber Mutex::Autolock autoLock(mLock); 447a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekDone = true; 448a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mCondition.broadcast(); 449a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 450a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 451a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mSeqNumber < 0) { 452a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mPlaylist->isComplete()) { 453a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeqNumber = firstSeqNumberInPlaylist; 454a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 455a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeqNumber = firstSeqNumberInPlaylist + mPlaylist->size() / 2; 456a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 457a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 458a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 459a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t lastSeqNumberInPlaylist = 460a44153c1a57202fb538659eb50706e60454d6273Andreas Huber firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1; 461a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 462a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mSeqNumber < firstSeqNumberInPlaylist 463a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || mSeqNumber > lastSeqNumberInPlaylist) { 46488b7ad413c4b6d08697069b18488641d6ce31fd3Andreas Huber if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) { 465aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber // Go back to the previous bandwidth. 466aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber 467aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber LOGI("new bandwidth does not have the sequence number " 468aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber "we're looking for, switching back to previous bandwidth"); 469aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber 470aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber mLastPlaylistFetchTimeUs = -1; 471aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber bandwidthIndex = mPrevBandwidthIndex; 472aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber goto rinse_repeat; 473aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber } 474aea5aff45a1af14e249ac311f0a128a621a7d13eAndreas Huber 475a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!mPlaylist->isComplete() 476a44153c1a57202fb538659eb50706e60454d6273Andreas Huber && mSeqNumber > lastSeqNumberInPlaylist 477a44153c1a57202fb538659eb50706e60454d6273Andreas Huber && mNumRetries < kMaxNumRetries) { 478a44153c1a57202fb538659eb50706e60454d6273Andreas Huber ++mNumRetries; 479a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 480a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mLastPlaylistFetchTimeUs = -1; 4815bc087c573c70c84c6a39946457590b42d392a33Andreas Huber postMonitorQueue(3000000ll); 482a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return; 483a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 484a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 485a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("Cannot find sequence number %d in playlist " 486a44153c1a57202fb538659eb50706e60454d6273Andreas Huber "(contains %d - %d)", 487a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeqNumber, firstSeqNumberInPlaylist, 488a44153c1a57202fb538659eb50706e60454d6273Andreas Huber firstSeqNumberInPlaylist + mPlaylist->size() - 1); 489a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 490a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDataSource->queueEOS(ERROR_END_OF_STREAM); 491a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return; 492a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 493a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 494a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mNumRetries = 0; 495a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 496a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString uri; 497a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> itemMeta; 498a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(mPlaylist->itemAt( 499a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeqNumber - firstSeqNumberInPlaylist, 500a44153c1a57202fb538659eb50706e60454d6273Andreas Huber &uri, 501a44153c1a57202fb538659eb50706e60454d6273Andreas Huber &itemMeta)); 502a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 503a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int32_t val; 504a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (itemMeta->findInt32("discontinuity", &val) && val != 0) { 505a44153c1a57202fb538659eb50706e60454d6273Andreas Huber explicitDiscontinuity = true; 506a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 507a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 508a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> buffer; 509a44153c1a57202fb538659eb50706e60454d6273Andreas Huber status_t err = fetchFile(uri.c_str(), &buffer); 5106e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber if (err != OK) { 5116e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber LOGE("failed to fetch .ts segment at url '%s'", uri.c_str()); 5126e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber mDataSource->queueEOS(err); 5136e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber return; 5146e6b1cae2bac1b78205cefab8e4e9e9538982965Andreas Huber } 515a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 51643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber CHECK(buffer != NULL); 51743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 51888b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer); 51988b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber 52088b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber if (err != OK) { 52188b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber LOGE("decryptBuffer failed w/ error %d", err); 52288b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber 52388b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber mDataSource->queueEOS(err); 52488b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber return; 52588b348910a607ae399bcd693dd42a231d98da2c9Andreas Huber } 526a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 527a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (buffer->size() == 0 || buffer->data()[0] != 0x47) { 528a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Not a transport stream??? 529a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 530a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("This doesn't look like a transport stream..."); 531a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 532bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber mBandwidthItems.removeAt(bandwidthIndex); 533bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber 534bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber if (mBandwidthItems.isEmpty()) { 535bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber mDataSource->queueEOS(ERROR_UNSUPPORTED); 536bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber return; 537bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber } 538bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber 539bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber LOGI("Retrying with a different bandwidth stream."); 540bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber 541bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber mLastPlaylistFetchTimeUs = -1; 542bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber bandwidthIndex = getBandwidthIndex(); 543bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber mPrevBandwidthIndex = bandwidthIndex; 544bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber mSeqNumber = -1; 545bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber 546bc7f5b2e56107cfeaeeab13cf8979379e3c2f139Andreas Huber goto rinse_repeat; 547a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 548a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 54922fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber if ((size_t)mPrevBandwidthIndex != bandwidthIndex) { 55022fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber bandwidthChanged = true; 55122fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber } 55222fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber 55322fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber if (mPrevBandwidthIndex < 0) { 55422fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // Don't signal a bandwidth change at the very beginning of 55522fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber // playback. 55622fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber bandwidthChanged = false; 55722fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber } 5583831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber 5593831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber if (explicitDiscontinuity || bandwidthChanged) { 560a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // Signal discontinuity. 561a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 56243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber LOGI("queueing discontinuity (explicit=%d, bandwidthChanged=%d)", 56343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber explicitDiscontinuity, bandwidthChanged); 56443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 565a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> tmp = new ABuffer(188); 566a44153c1a57202fb538659eb50706e60454d6273Andreas Huber memset(tmp->data(), 0, tmp->size()); 5673831a066bcf1019864a94d2bc7b4c9241efc5c22Andreas Huber tmp->data()[1] = bandwidthChanged; 568a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 569a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDataSource->queueBuffer(tmp); 570a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 571a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 572a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mDataSource->queueBuffer(buffer); 573a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 574a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mPrevBandwidthIndex = bandwidthIndex; 575a44153c1a57202fb538659eb50706e60454d6273Andreas Huber ++mSeqNumber; 576a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 577a44153c1a57202fb538659eb50706e60454d6273Andreas Huber postMonitorQueue(); 578a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 579a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 580a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onMonitorQueue() { 581a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (mSeekTimeUs >= 0 582a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || mDataSource->countQueuedBuffers() < kMaxNumQueuedFragments) { 583a44153c1a57202fb538659eb50706e60454d6273Andreas Huber onDownloadNext(); 584a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 585a44153c1a57202fb538659eb50706e60454d6273Andreas Huber postMonitorQueue(1000000ll); 586a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 587a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 588a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 589a44153c1a57202fb538659eb50706e60454d6273Andreas Huberstatus_t LiveSession::decryptBuffer( 590a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t playlistIndex, const sp<ABuffer> &buffer) { 591a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> itemMeta; 592a44153c1a57202fb538659eb50706e60454d6273Andreas Huber bool found = false; 593a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString method; 594a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 595a44153c1a57202fb538659eb50706e60454d6273Andreas Huber for (ssize_t i = playlistIndex; i >= 0; --i) { 596a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString uri; 597a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(mPlaylist->itemAt(i, &uri, &itemMeta)); 598a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 599a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (itemMeta->findString("cipher-method", &method)) { 600a44153c1a57202fb538659eb50706e60454d6273Andreas Huber found = true; 601a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 602a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 603a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 604a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 605a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!found) { 606a44153c1a57202fb538659eb50706e60454d6273Andreas Huber method = "NONE"; 607a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 608a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 609a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (method == "NONE") { 610a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return OK; 611a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else if (!(method == "AES-128")) { 612a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("Unsupported cipher method '%s'", method.c_str()); 613a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return ERROR_UNSUPPORTED; 614a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 615a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 616a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString keyURI; 617a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!itemMeta->findString("cipher-uri", &keyURI)) { 618a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("Missing key uri"); 619a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return ERROR_MALFORMED; 620a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 621a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 622a44153c1a57202fb538659eb50706e60454d6273Andreas Huber ssize_t index = mAESKeyForURI.indexOfKey(keyURI); 623a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 624a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<ABuffer> key; 625a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (index >= 0) { 626a44153c1a57202fb538659eb50706e60454d6273Andreas Huber key = mAESKeyForURI.valueAt(index); 627a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 628a44153c1a57202fb538659eb50706e60454d6273Andreas Huber key = new ABuffer(16); 629a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 630a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<NuHTTPDataSource> keySource = new NuHTTPDataSource; 631a44153c1a57202fb538659eb50706e60454d6273Andreas Huber status_t err = keySource->connect(keyURI.c_str()); 632a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 633a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (err == OK) { 634a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t offset = 0; 635a44153c1a57202fb538659eb50706e60454d6273Andreas Huber while (offset < 16) { 636a44153c1a57202fb538659eb50706e60454d6273Andreas Huber ssize_t n = keySource->readAt( 637a44153c1a57202fb538659eb50706e60454d6273Andreas Huber offset, key->data() + offset, 16 - offset); 638a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (n <= 0) { 639a44153c1a57202fb538659eb50706e60454d6273Andreas Huber err = ERROR_IO; 640a44153c1a57202fb538659eb50706e60454d6273Andreas Huber break; 641a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 642a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 643a44153c1a57202fb538659eb50706e60454d6273Andreas Huber offset += n; 644a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 645a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 646a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 647a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (err != OK) { 648a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("failed to fetch cipher key from '%s'.", keyURI.c_str()); 649a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return ERROR_IO; 650a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 651a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 652a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mAESKeyForURI.add(keyURI, key); 653a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 654a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 655a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AES_KEY aes_key; 656a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (AES_set_decrypt_key(key->data(), 128, &aes_key) != 0) { 657a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("failed to set AES decryption key."); 658a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return UNKNOWN_ERROR; 659a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 660a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 661a44153c1a57202fb538659eb50706e60454d6273Andreas Huber unsigned char aes_ivec[16]; 662a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 663a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AString iv; 664a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (itemMeta->findString("cipher-iv", &iv)) { 665a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if ((!iv.startsWith("0x") && !iv.startsWith("0X")) 666a44153c1a57202fb538659eb50706e60454d6273Andreas Huber || iv.size() != 16 * 2 + 2) { 667a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("malformed cipher IV '%s'.", iv.c_str()); 668a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return ERROR_MALFORMED; 669a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 670a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 671a44153c1a57202fb538659eb50706e60454d6273Andreas Huber memset(aes_ivec, 0, sizeof(aes_ivec)); 672a44153c1a57202fb538659eb50706e60454d6273Andreas Huber for (size_t i = 0; i < 16; ++i) { 673a44153c1a57202fb538659eb50706e60454d6273Andreas Huber char c1 = tolower(iv.c_str()[2 + 2 * i]); 674a44153c1a57202fb538659eb50706e60454d6273Andreas Huber char c2 = tolower(iv.c_str()[3 + 2 * i]); 675a44153c1a57202fb538659eb50706e60454d6273Andreas Huber if (!isxdigit(c1) || !isxdigit(c2)) { 676a44153c1a57202fb538659eb50706e60454d6273Andreas Huber LOGE("malformed cipher IV '%s'.", iv.c_str()); 677a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return ERROR_MALFORMED; 678a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 679a44153c1a57202fb538659eb50706e60454d6273Andreas Huber uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10; 680a44153c1a57202fb538659eb50706e60454d6273Andreas Huber uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10; 681a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 682a44153c1a57202fb538659eb50706e60454d6273Andreas Huber aes_ivec[i] = nibble1 << 4 | nibble2; 683a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 684a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } else { 685a44153c1a57202fb538659eb50706e60454d6273Andreas Huber memset(aes_ivec, 0, sizeof(aes_ivec)); 686a44153c1a57202fb538659eb50706e60454d6273Andreas Huber aes_ivec[15] = mSeqNumber & 0xff; 687a44153c1a57202fb538659eb50706e60454d6273Andreas Huber aes_ivec[14] = (mSeqNumber >> 8) & 0xff; 688a44153c1a57202fb538659eb50706e60454d6273Andreas Huber aes_ivec[13] = (mSeqNumber >> 16) & 0xff; 689a44153c1a57202fb538659eb50706e60454d6273Andreas Huber aes_ivec[12] = (mSeqNumber >> 24) & 0xff; 690a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 691a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 692a44153c1a57202fb538659eb50706e60454d6273Andreas Huber AES_cbc_encrypt( 693a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->data(), buffer->data(), buffer->size(), 694a44153c1a57202fb538659eb50706e60454d6273Andreas Huber &aes_key, aes_ivec, AES_DECRYPT); 695a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 696a44153c1a57202fb538659eb50706e60454d6273Andreas Huber // hexdump(buffer->data(), buffer->size()); 697a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 698a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t n = buffer->size(); 699a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_GT(n, 0u); 700a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 701a44153c1a57202fb538659eb50706e60454d6273Andreas Huber size_t pad = buffer->data()[n - 1]; 702a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 703a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_GT(pad, 0u); 704a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_LE(pad, 16u); 705a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_GE((size_t)n, pad); 706a44153c1a57202fb538659eb50706e60454d6273Andreas Huber for (size_t i = 0; i < pad; ++i) { 707a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK_EQ((unsigned)buffer->data()[n - 1 - i], pad); 708a44153c1a57202fb538659eb50706e60454d6273Andreas Huber } 709a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 710a44153c1a57202fb538659eb50706e60454d6273Andreas Huber n -= pad; 711a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 712a44153c1a57202fb538659eb50706e60454d6273Andreas Huber buffer->setRange(buffer->offset(), n); 713a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 714a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return OK; 715a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 716a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 717a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::postMonitorQueue(int64_t delayUs) { 718a44153c1a57202fb538659eb50706e60454d6273Andreas Huber sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id()); 719a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->setInt32("generation", ++mMonitorQueueGeneration); 720a44153c1a57202fb538659eb50706e60454d6273Andreas Huber msg->post(delayUs); 721a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 722a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 723a44153c1a57202fb538659eb50706e60454d6273Andreas Hubervoid LiveSession::onSeek(const sp<AMessage> &msg) { 724a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int64_t timeUs; 725a44153c1a57202fb538659eb50706e60454d6273Andreas Huber CHECK(msg->findInt64("timeUs", &timeUs)); 726a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 727a44153c1a57202fb538659eb50706e60454d6273Andreas Huber mSeekTimeUs = timeUs; 728a44153c1a57202fb538659eb50706e60454d6273Andreas Huber postMonitorQueue(); 729a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 730a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 731a44153c1a57202fb538659eb50706e60454d6273Andreas Huberstatus_t LiveSession::getDuration(int64_t *durationUs) { 732a44153c1a57202fb538659eb50706e60454d6273Andreas Huber Mutex::Autolock autoLock(mLock); 733a44153c1a57202fb538659eb50706e60454d6273Andreas Huber *durationUs = mDurationUs; 734a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 735a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return OK; 736a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 737a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 738a44153c1a57202fb538659eb50706e60454d6273Andreas Huberbool LiveSession::isSeekable() { 739a44153c1a57202fb538659eb50706e60454d6273Andreas Huber int64_t durationUs; 740a44153c1a57202fb538659eb50706e60454d6273Andreas Huber return getDuration(&durationUs) == OK && durationUs >= 0; 741a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} 742a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 743a44153c1a57202fb538659eb50706e60454d6273Andreas Huber} // namespace android 744a44153c1a57202fb538659eb50706e60454d6273Andreas Huber 745