Home | History | Annotate | Download | only in httplive
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "LiveSession"
     19 #include <utils/Log.h>
     20 
     21 #include "include/LiveSession.h"
     22 
     23 #include "LiveDataSource.h"
     24 
     25 #include "include/M3UParser.h"
     26 #include "include/HTTPBase.h"
     27 
     28 #include <cutils/properties.h>
     29 #include <media/stagefright/foundation/hexdump.h>
     30 #include <media/stagefright/foundation/ABuffer.h>
     31 #include <media/stagefright/foundation/ADebug.h>
     32 #include <media/stagefright/foundation/AMessage.h>
     33 #include <media/stagefright/DataSource.h>
     34 #include <media/stagefright/FileSource.h>
     35 #include <media/stagefright/MediaErrors.h>
     36 
     37 #include <ctype.h>
     38 #include <openssl/aes.h>
     39 #include <openssl/md5.h>
     40 
     41 namespace android {
     42 
     43 LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
     44     : mFlags(flags),
     45       mUIDValid(uidValid),
     46       mUID(uid),
     47       mDataSource(new LiveDataSource),
     48       mHTTPDataSource(
     49               HTTPBase::Create(
     50                   (mFlags & kFlagIncognito)
     51                     ? HTTPBase::kFlagIncognito
     52                     : 0)),
     53       mPrevBandwidthIndex(-1),
     54       mLastPlaylistFetchTimeUs(-1),
     55       mSeqNumber(-1),
     56       mSeekTimeUs(-1),
     57       mNumRetries(0),
     58       mDurationUs(-1),
     59       mSeekDone(false),
     60       mDisconnectPending(false),
     61       mMonitorQueueGeneration(0),
     62       mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY) {
     63     if (mUIDValid) {
     64         mHTTPDataSource->setUID(mUID);
     65     }
     66 }
     67 
     68 LiveSession::~LiveSession() {
     69 }
     70 
     71 sp<DataSource> LiveSession::getDataSource() {
     72     return mDataSource;
     73 }
     74 
     75 void LiveSession::connect(
     76         const char *url, const KeyedVector<String8, String8> *headers) {
     77     sp<AMessage> msg = new AMessage(kWhatConnect, id());
     78     msg->setString("url", url);
     79 
     80     if (headers != NULL) {
     81         msg->setPointer(
     82                 "headers",
     83                 new KeyedVector<String8, String8>(*headers));
     84     }
     85 
     86     msg->post();
     87 }
     88 
     89 void LiveSession::disconnect() {
     90     Mutex::Autolock autoLock(mLock);
     91     mDisconnectPending = true;
     92 
     93     mHTTPDataSource->disconnect();
     94 
     95     (new AMessage(kWhatDisconnect, id()))->post();
     96 }
     97 
     98 void LiveSession::seekTo(int64_t timeUs) {
     99     Mutex::Autolock autoLock(mLock);
    100     mSeekDone = false;
    101 
    102     sp<AMessage> msg = new AMessage(kWhatSeek, id());
    103     msg->setInt64("timeUs", timeUs);
    104     msg->post();
    105 
    106     while (!mSeekDone) {
    107         mCondition.wait(mLock);
    108     }
    109 }
    110 
    111 void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
    112     switch (msg->what()) {
    113         case kWhatConnect:
    114             onConnect(msg);
    115             break;
    116 
    117         case kWhatDisconnect:
    118             onDisconnect();
    119             break;
    120 
    121         case kWhatMonitorQueue:
    122         {
    123             int32_t generation;
    124             CHECK(msg->findInt32("generation", &generation));
    125 
    126             if (generation != mMonitorQueueGeneration) {
    127                 // Stale event
    128                 break;
    129             }
    130 
    131             onMonitorQueue();
    132             break;
    133         }
    134 
    135         case kWhatSeek:
    136             onSeek(msg);
    137             break;
    138 
    139         default:
    140             TRESPASS();
    141             break;
    142     }
    143 }
    144 
    145 // static
    146 int LiveSession::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) {
    147     if (a->mBandwidth < b->mBandwidth) {
    148         return -1;
    149     } else if (a->mBandwidth == b->mBandwidth) {
    150         return 0;
    151     }
    152 
    153     return 1;
    154 }
    155 
    156 void LiveSession::onConnect(const sp<AMessage> &msg) {
    157     AString url;
    158     CHECK(msg->findString("url", &url));
    159 
    160     KeyedVector<String8, String8> *headers = NULL;
    161     if (!msg->findPointer("headers", (void **)&headers)) {
    162         mExtraHeaders.clear();
    163     } else {
    164         mExtraHeaders = *headers;
    165 
    166         delete headers;
    167         headers = NULL;
    168     }
    169 
    170     if (!(mFlags & kFlagIncognito)) {
    171         ALOGI("onConnect '%s'", url.c_str());
    172     } else {
    173         ALOGI("onConnect <URL suppressed>");
    174     }
    175 
    176     mMasterURL = url;
    177 
    178     bool dummy;
    179     sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &dummy);
    180 
    181     if (playlist == NULL) {
    182         ALOGE("unable to fetch master playlist '%s'.", url.c_str());
    183 
    184         mDataSource->queueEOS(ERROR_IO);
    185         return;
    186     }
    187 
    188     if (playlist->isVariantPlaylist()) {
    189         for (size_t i = 0; i < playlist->size(); ++i) {
    190             BandwidthItem item;
    191 
    192             sp<AMessage> meta;
    193             playlist->itemAt(i, &item.mURI, &meta);
    194 
    195             unsigned long bandwidth;
    196             CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
    197 
    198             mBandwidthItems.push(item);
    199         }
    200 
    201         CHECK_GT(mBandwidthItems.size(), 0u);
    202 
    203         mBandwidthItems.sort(SortByBandwidth);
    204     }
    205 
    206     postMonitorQueue();
    207 }
    208 
    209 void LiveSession::onDisconnect() {
    210     ALOGI("onDisconnect");
    211 
    212     mDataSource->queueEOS(ERROR_END_OF_STREAM);
    213 
    214     Mutex::Autolock autoLock(mLock);
    215     mDisconnectPending = false;
    216 }
    217 
    218 status_t LiveSession::fetchFile(
    219         const char *url, sp<ABuffer> *out,
    220         int64_t range_offset, int64_t range_length) {
    221     *out = NULL;
    222 
    223     sp<DataSource> source;
    224 
    225     if (!strncasecmp(url, "file://", 7)) {
    226         source = new FileSource(url + 7);
    227     } else if (strncasecmp(url, "http://", 7)
    228             && strncasecmp(url, "https://", 8)) {
    229         return ERROR_UNSUPPORTED;
    230     } else {
    231         {
    232             Mutex::Autolock autoLock(mLock);
    233 
    234             if (mDisconnectPending) {
    235                 return ERROR_IO;
    236             }
    237         }
    238 
    239         KeyedVector<String8, String8> headers = mExtraHeaders;
    240         if (range_offset > 0 || range_length >= 0) {
    241             headers.add(
    242                     String8("Range"),
    243                     String8(
    244                         StringPrintf(
    245                             "bytes=%lld-%s",
    246                             range_offset,
    247                             range_length < 0
    248                                 ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str()));
    249         }
    250         status_t err = mHTTPDataSource->connect(url, &headers);
    251 
    252         if (err != OK) {
    253             return err;
    254         }
    255 
    256         source = mHTTPDataSource;
    257     }
    258 
    259     off64_t size;
    260     status_t err = source->getSize(&size);
    261 
    262     if (err != OK) {
    263         size = 65536;
    264     }
    265 
    266     sp<ABuffer> buffer = new ABuffer(size);
    267     buffer->setRange(0, 0);
    268 
    269     for (;;) {
    270         size_t bufferRemaining = buffer->capacity() - buffer->size();
    271 
    272         if (bufferRemaining == 0) {
    273             bufferRemaining = 32768;
    274 
    275             ALOGV("increasing download buffer to %d bytes",
    276                  buffer->size() + bufferRemaining);
    277 
    278             sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
    279             memcpy(copy->data(), buffer->data(), buffer->size());
    280             copy->setRange(0, buffer->size());
    281 
    282             buffer = copy;
    283         }
    284 
    285         size_t maxBytesToRead = bufferRemaining;
    286         if (range_length >= 0) {
    287             int64_t bytesLeftInRange = range_length - buffer->size();
    288             if (bytesLeftInRange < maxBytesToRead) {
    289                 maxBytesToRead = bytesLeftInRange;
    290 
    291                 if (bytesLeftInRange == 0) {
    292                     break;
    293                 }
    294             }
    295         }
    296 
    297         ssize_t n = source->readAt(
    298                 buffer->size(), buffer->data() + buffer->size(),
    299                 maxBytesToRead);
    300 
    301         if (n < 0) {
    302             return n;
    303         }
    304 
    305         if (n == 0) {
    306             break;
    307         }
    308 
    309         buffer->setRange(0, buffer->size() + (size_t)n);
    310     }
    311 
    312     *out = buffer;
    313 
    314     return OK;
    315 }
    316 
    317 sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) {
    318     *unchanged = false;
    319 
    320     sp<ABuffer> buffer;
    321     status_t err = fetchFile(url, &buffer);
    322 
    323     if (err != OK) {
    324         return NULL;
    325     }
    326 
    327     // MD5 functionality is not available on the simulator, treat all
    328     // playlists as changed.
    329 
    330 #if defined(HAVE_ANDROID_OS)
    331     uint8_t hash[16];
    332 
    333     MD5_CTX m;
    334     MD5_Init(&m);
    335     MD5_Update(&m, buffer->data(), buffer->size());
    336 
    337     MD5_Final(hash, &m);
    338 
    339     if (mPlaylist != NULL && !memcmp(hash, mPlaylistHash, 16)) {
    340         // playlist unchanged
    341 
    342         if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) {
    343             mRefreshState = (RefreshState)(mRefreshState + 1);
    344         }
    345 
    346         *unchanged = true;
    347 
    348         ALOGV("Playlist unchanged, refresh state is now %d",
    349              (int)mRefreshState);
    350 
    351         return NULL;
    352     }
    353 
    354     memcpy(mPlaylistHash, hash, sizeof(hash));
    355 
    356     mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
    357 #endif
    358 
    359     sp<M3UParser> playlist =
    360         new M3UParser(url, buffer->data(), buffer->size());
    361 
    362     if (playlist->initCheck() != OK) {
    363         ALOGE("failed to parse .m3u8 playlist");
    364 
    365         return NULL;
    366     }
    367 
    368     return playlist;
    369 }
    370 
    371 static double uniformRand() {
    372     return (double)rand() / RAND_MAX;
    373 }
    374 
    375 size_t LiveSession::getBandwidthIndex() {
    376     if (mBandwidthItems.size() == 0) {
    377         return 0;
    378     }
    379 
    380 #if 1
    381     int32_t bandwidthBps;
    382     if (mHTTPDataSource != NULL
    383             && mHTTPDataSource->estimateBandwidth(&bandwidthBps)) {
    384         ALOGV("bandwidth estimated at %.2f kbps", bandwidthBps / 1024.0f);
    385     } else {
    386         ALOGV("no bandwidth estimate.");
    387         return 0;  // Pick the lowest bandwidth stream by default.
    388     }
    389 
    390     char value[PROPERTY_VALUE_MAX];
    391     if (property_get("media.httplive.max-bw", value, NULL)) {
    392         char *end;
    393         long maxBw = strtoul(value, &end, 10);
    394         if (end > value && *end == '\0') {
    395             if (maxBw > 0 && bandwidthBps > maxBw) {
    396                 ALOGV("bandwidth capped to %ld bps", maxBw);
    397                 bandwidthBps = maxBw;
    398             }
    399         }
    400     }
    401 
    402     // Consider only 80% of the available bandwidth usable.
    403     bandwidthBps = (bandwidthBps * 8) / 10;
    404 
    405     // Pick the highest bandwidth stream below or equal to estimated bandwidth.
    406 
    407     size_t index = mBandwidthItems.size() - 1;
    408     while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth
    409                             > (size_t)bandwidthBps) {
    410         --index;
    411     }
    412 #elif 0
    413     // Change bandwidth at random()
    414     size_t index = uniformRand() * mBandwidthItems.size();
    415 #elif 0
    416     // There's a 50% chance to stay on the current bandwidth and
    417     // a 50% chance to switch to the next higher bandwidth (wrapping around
    418     // to lowest)
    419     const size_t kMinIndex = 0;
    420 
    421     size_t index;
    422     if (mPrevBandwidthIndex < 0) {
    423         index = kMinIndex;
    424     } else if (uniformRand() < 0.5) {
    425         index = (size_t)mPrevBandwidthIndex;
    426     } else {
    427         index = mPrevBandwidthIndex + 1;
    428         if (index == mBandwidthItems.size()) {
    429             index = kMinIndex;
    430         }
    431     }
    432 #elif 0
    433     // Pick the highest bandwidth stream below or equal to 1.2 Mbit/sec
    434 
    435     size_t index = mBandwidthItems.size() - 1;
    436     while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth > 1200000) {
    437         --index;
    438     }
    439 #else
    440     size_t index = mBandwidthItems.size() - 1;  // Highest bandwidth stream
    441 #endif
    442 
    443     return index;
    444 }
    445 
    446 bool LiveSession::timeToRefreshPlaylist(int64_t nowUs) const {
    447     if (mPlaylist == NULL) {
    448         CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
    449         return true;
    450     }
    451 
    452     int32_t targetDurationSecs;
    453     CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
    454 
    455     int64_t targetDurationUs = targetDurationSecs * 1000000ll;
    456 
    457     int64_t minPlaylistAgeUs;
    458 
    459     switch (mRefreshState) {
    460         case INITIAL_MINIMUM_RELOAD_DELAY:
    461         {
    462             size_t n = mPlaylist->size();
    463             if (n > 0) {
    464                 sp<AMessage> itemMeta;
    465                 CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta));
    466 
    467                 int64_t itemDurationUs;
    468                 CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
    469 
    470                 minPlaylistAgeUs = itemDurationUs;
    471                 break;
    472             }
    473 
    474             // fall through
    475         }
    476 
    477         case FIRST_UNCHANGED_RELOAD_ATTEMPT:
    478         {
    479             minPlaylistAgeUs = targetDurationUs / 2;
    480             break;
    481         }
    482 
    483         case SECOND_UNCHANGED_RELOAD_ATTEMPT:
    484         {
    485             minPlaylistAgeUs = (targetDurationUs * 3) / 2;
    486             break;
    487         }
    488 
    489         case THIRD_UNCHANGED_RELOAD_ATTEMPT:
    490         {
    491             minPlaylistAgeUs = targetDurationUs * 3;
    492             break;
    493         }
    494 
    495         default:
    496             TRESPASS();
    497             break;
    498     }
    499 
    500     return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs;
    501 }
    502 
    503 void LiveSession::onDownloadNext() {
    504     size_t bandwidthIndex = getBandwidthIndex();
    505 
    506 rinse_repeat:
    507     int64_t nowUs = ALooper::GetNowUs();
    508 
    509     if (mLastPlaylistFetchTimeUs < 0
    510             || (ssize_t)bandwidthIndex != mPrevBandwidthIndex
    511             || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) {
    512         AString url;
    513         if (mBandwidthItems.size() > 0) {
    514             url = mBandwidthItems.editItemAt(bandwidthIndex).mURI;
    515         } else {
    516             url = mMasterURL;
    517         }
    518 
    519         bool firstTime = (mPlaylist == NULL);
    520 
    521         if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
    522             // If we switch bandwidths, do not pay any heed to whether
    523             // playlists changed since the last time...
    524             mPlaylist.clear();
    525         }
    526 
    527         bool unchanged;
    528         sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged);
    529         if (playlist == NULL) {
    530             if (unchanged) {
    531                 // We succeeded in fetching the playlist, but it was
    532                 // unchanged from the last time we tried.
    533             } else {
    534                 ALOGE("failed to load playlist at url '%s'", url.c_str());
    535                 mDataSource->queueEOS(ERROR_IO);
    536                 return;
    537             }
    538         } else {
    539             mPlaylist = playlist;
    540         }
    541 
    542         if (firstTime) {
    543             Mutex::Autolock autoLock(mLock);
    544 
    545             if (!mPlaylist->isComplete()) {
    546                 mDurationUs = -1;
    547             } else {
    548                 mDurationUs = 0;
    549                 for (size_t i = 0; i < mPlaylist->size(); ++i) {
    550                     sp<AMessage> itemMeta;
    551                     CHECK(mPlaylist->itemAt(
    552                                 i, NULL /* uri */, &itemMeta));
    553 
    554                     int64_t itemDurationUs;
    555                     CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
    556 
    557                     mDurationUs += itemDurationUs;
    558                 }
    559             }
    560         }
    561 
    562         mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
    563     }
    564 
    565     int32_t firstSeqNumberInPlaylist;
    566     if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
    567                 "media-sequence", &firstSeqNumberInPlaylist)) {
    568         firstSeqNumberInPlaylist = 0;
    569     }
    570 
    571     bool seekDiscontinuity = false;
    572     bool explicitDiscontinuity = false;
    573     bool bandwidthChanged = false;
    574 
    575     if (mSeekTimeUs >= 0) {
    576         if (mPlaylist->isComplete()) {
    577             size_t index = 0;
    578             int64_t segmentStartUs = 0;
    579             while (index < mPlaylist->size()) {
    580                 sp<AMessage> itemMeta;
    581                 CHECK(mPlaylist->itemAt(
    582                             index, NULL /* uri */, &itemMeta));
    583 
    584                 int64_t itemDurationUs;
    585                 CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
    586 
    587                 if (mSeekTimeUs < segmentStartUs + itemDurationUs) {
    588                     break;
    589                 }
    590 
    591                 segmentStartUs += itemDurationUs;
    592                 ++index;
    593             }
    594 
    595             if (index < mPlaylist->size()) {
    596                 int32_t newSeqNumber = firstSeqNumberInPlaylist + index;
    597 
    598                 if (newSeqNumber != mSeqNumber) {
    599                     ALOGI("seeking to seq no %d", newSeqNumber);
    600 
    601                     mSeqNumber = newSeqNumber;
    602 
    603                     mDataSource->reset();
    604 
    605                     // reseting the data source will have had the
    606                     // side effect of discarding any previously queued
    607                     // bandwidth change discontinuity.
    608                     // Therefore we'll need to treat these seek
    609                     // discontinuities as involving a bandwidth change
    610                     // even if they aren't directly.
    611                     seekDiscontinuity = true;
    612                     bandwidthChanged = true;
    613                 }
    614             }
    615         }
    616 
    617         mSeekTimeUs = -1;
    618 
    619         Mutex::Autolock autoLock(mLock);
    620         mSeekDone = true;
    621         mCondition.broadcast();
    622     }
    623 
    624     if (mSeqNumber < 0) {
    625         mSeqNumber = firstSeqNumberInPlaylist;
    626     }
    627 
    628     int32_t lastSeqNumberInPlaylist =
    629         firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
    630 
    631     if (mSeqNumber < firstSeqNumberInPlaylist
    632             || mSeqNumber > lastSeqNumberInPlaylist) {
    633         if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
    634             // Go back to the previous bandwidth.
    635 
    636             ALOGI("new bandwidth does not have the sequence number "
    637                  "we're looking for, switching back to previous bandwidth");
    638 
    639             mLastPlaylistFetchTimeUs = -1;
    640             bandwidthIndex = mPrevBandwidthIndex;
    641             goto rinse_repeat;
    642         }
    643 
    644         if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
    645             ++mNumRetries;
    646 
    647             if (mSeqNumber > lastSeqNumberInPlaylist) {
    648                 mLastPlaylistFetchTimeUs = -1;
    649                 postMonitorQueue(3000000ll);
    650                 return;
    651             }
    652 
    653             // we've missed the boat, let's start from the lowest sequence
    654             // number available and signal a discontinuity.
    655 
    656             ALOGI("We've missed the boat, restarting playback.");
    657             mSeqNumber = lastSeqNumberInPlaylist;
    658             explicitDiscontinuity = true;
    659 
    660             // fall through
    661         } else {
    662             ALOGE("Cannot find sequence number %d in playlist "
    663                  "(contains %d - %d)",
    664                  mSeqNumber, firstSeqNumberInPlaylist,
    665                  firstSeqNumberInPlaylist + mPlaylist->size() - 1);
    666 
    667             mDataSource->queueEOS(ERROR_END_OF_STREAM);
    668             return;
    669         }
    670     }
    671 
    672     mNumRetries = 0;
    673 
    674     AString uri;
    675     sp<AMessage> itemMeta;
    676     CHECK(mPlaylist->itemAt(
    677                 mSeqNumber - firstSeqNumberInPlaylist,
    678                 &uri,
    679                 &itemMeta));
    680 
    681     int32_t val;
    682     if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
    683         explicitDiscontinuity = true;
    684     }
    685 
    686     int64_t range_offset, range_length;
    687     if (!itemMeta->findInt64("range-offset", &range_offset)
    688             || !itemMeta->findInt64("range-length", &range_length)) {
    689         range_offset = 0;
    690         range_length = -1;
    691     }
    692 
    693     sp<ABuffer> buffer;
    694     status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length);
    695     if (err != OK) {
    696         ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
    697         mDataSource->queueEOS(err);
    698         return;
    699     }
    700 
    701     CHECK(buffer != NULL);
    702 
    703     err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
    704 
    705     if (err != OK) {
    706         ALOGE("decryptBuffer failed w/ error %d", err);
    707 
    708         mDataSource->queueEOS(err);
    709         return;
    710     }
    711 
    712     if (buffer->size() == 0 || buffer->data()[0] != 0x47) {
    713         // Not a transport stream???
    714 
    715         ALOGE("This doesn't look like a transport stream...");
    716 
    717         mBandwidthItems.removeAt(bandwidthIndex);
    718 
    719         if (mBandwidthItems.isEmpty()) {
    720             mDataSource->queueEOS(ERROR_UNSUPPORTED);
    721             return;
    722         }
    723 
    724         ALOGI("Retrying with a different bandwidth stream.");
    725 
    726         mLastPlaylistFetchTimeUs = -1;
    727         bandwidthIndex = getBandwidthIndex();
    728         mPrevBandwidthIndex = bandwidthIndex;
    729         mSeqNumber = -1;
    730 
    731         goto rinse_repeat;
    732     }
    733 
    734     if ((size_t)mPrevBandwidthIndex != bandwidthIndex) {
    735         bandwidthChanged = true;
    736     }
    737 
    738     if (mPrevBandwidthIndex < 0) {
    739         // Don't signal a bandwidth change at the very beginning of
    740         // playback.
    741         bandwidthChanged = false;
    742     }
    743 
    744     if (seekDiscontinuity || explicitDiscontinuity || bandwidthChanged) {
    745         // Signal discontinuity.
    746 
    747         ALOGI("queueing discontinuity (seek=%d, explicit=%d, bandwidthChanged=%d)",
    748              seekDiscontinuity, explicitDiscontinuity, bandwidthChanged);
    749 
    750         sp<ABuffer> tmp = new ABuffer(188);
    751         memset(tmp->data(), 0, tmp->size());
    752 
    753         // signal a 'hard' discontinuity for explicit or bandwidthChanged.
    754         tmp->data()[1] = (explicitDiscontinuity || bandwidthChanged) ? 1 : 0;
    755 
    756         mDataSource->queueBuffer(tmp);
    757     }
    758 
    759     mDataSource->queueBuffer(buffer);
    760 
    761     mPrevBandwidthIndex = bandwidthIndex;
    762     ++mSeqNumber;
    763 
    764     postMonitorQueue();
    765 }
    766 
    767 void LiveSession::onMonitorQueue() {
    768     if (mSeekTimeUs >= 0
    769             || mDataSource->countQueuedBuffers() < kMaxNumQueuedFragments) {
    770         onDownloadNext();
    771     } else {
    772         postMonitorQueue(1000000ll);
    773     }
    774 }
    775 
    776 status_t LiveSession::decryptBuffer(
    777         size_t playlistIndex, const sp<ABuffer> &buffer) {
    778     sp<AMessage> itemMeta;
    779     bool found = false;
    780     AString method;
    781 
    782     for (ssize_t i = playlistIndex; i >= 0; --i) {
    783         AString uri;
    784         CHECK(mPlaylist->itemAt(i, &uri, &itemMeta));
    785 
    786         if (itemMeta->findString("cipher-method", &method)) {
    787             found = true;
    788             break;
    789         }
    790     }
    791 
    792     if (!found) {
    793         method = "NONE";
    794     }
    795 
    796     if (method == "NONE") {
    797         return OK;
    798     } else if (!(method == "AES-128")) {
    799         ALOGE("Unsupported cipher method '%s'", method.c_str());
    800         return ERROR_UNSUPPORTED;
    801     }
    802 
    803     AString keyURI;
    804     if (!itemMeta->findString("cipher-uri", &keyURI)) {
    805         ALOGE("Missing key uri");
    806         return ERROR_MALFORMED;
    807     }
    808 
    809     ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
    810 
    811     sp<ABuffer> key;
    812     if (index >= 0) {
    813         key = mAESKeyForURI.valueAt(index);
    814     } else {
    815         key = new ABuffer(16);
    816 
    817         sp<HTTPBase> keySource =
    818               HTTPBase::Create(
    819                   (mFlags & kFlagIncognito)
    820                     ? HTTPBase::kFlagIncognito
    821                     : 0);
    822 
    823         if (mUIDValid) {
    824             keySource->setUID(mUID);
    825         }
    826 
    827         status_t err =
    828             keySource->connect(
    829                     keyURI.c_str(),
    830                     mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
    831 
    832         if (err == OK) {
    833             size_t offset = 0;
    834             while (offset < 16) {
    835                 ssize_t n = keySource->readAt(
    836                         offset, key->data() + offset, 16 - offset);
    837                 if (n <= 0) {
    838                     err = ERROR_IO;
    839                     break;
    840                 }
    841 
    842                 offset += n;
    843             }
    844         }
    845 
    846         if (err != OK) {
    847             ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
    848             return ERROR_IO;
    849         }
    850 
    851         mAESKeyForURI.add(keyURI, key);
    852     }
    853 
    854     AES_KEY aes_key;
    855     if (AES_set_decrypt_key(key->data(), 128, &aes_key) != 0) {
    856         ALOGE("failed to set AES decryption key.");
    857         return UNKNOWN_ERROR;
    858     }
    859 
    860     unsigned char aes_ivec[16];
    861 
    862     AString iv;
    863     if (itemMeta->findString("cipher-iv", &iv)) {
    864         if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
    865                 || iv.size() != 16 * 2 + 2) {
    866             ALOGE("malformed cipher IV '%s'.", iv.c_str());
    867             return ERROR_MALFORMED;
    868         }
    869 
    870         memset(aes_ivec, 0, sizeof(aes_ivec));
    871         for (size_t i = 0; i < 16; ++i) {
    872             char c1 = tolower(iv.c_str()[2 + 2 * i]);
    873             char c2 = tolower(iv.c_str()[3 + 2 * i]);
    874             if (!isxdigit(c1) || !isxdigit(c2)) {
    875                 ALOGE("malformed cipher IV '%s'.", iv.c_str());
    876                 return ERROR_MALFORMED;
    877             }
    878             uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
    879             uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
    880 
    881             aes_ivec[i] = nibble1 << 4 | nibble2;
    882         }
    883     } else {
    884         memset(aes_ivec, 0, sizeof(aes_ivec));
    885         aes_ivec[15] = mSeqNumber & 0xff;
    886         aes_ivec[14] = (mSeqNumber >> 8) & 0xff;
    887         aes_ivec[13] = (mSeqNumber >> 16) & 0xff;
    888         aes_ivec[12] = (mSeqNumber >> 24) & 0xff;
    889     }
    890 
    891     AES_cbc_encrypt(
    892             buffer->data(), buffer->data(), buffer->size(),
    893             &aes_key, aes_ivec, AES_DECRYPT);
    894 
    895     // hexdump(buffer->data(), buffer->size());
    896 
    897     size_t n = buffer->size();
    898     CHECK_GT(n, 0u);
    899 
    900     size_t pad = buffer->data()[n - 1];
    901 
    902     CHECK_GT(pad, 0u);
    903     CHECK_LE(pad, 16u);
    904     CHECK_GE((size_t)n, pad);
    905     for (size_t i = 0; i < pad; ++i) {
    906         CHECK_EQ((unsigned)buffer->data()[n - 1 - i], pad);
    907     }
    908 
    909     n -= pad;
    910 
    911     buffer->setRange(buffer->offset(), n);
    912 
    913     return OK;
    914 }
    915 
    916 void LiveSession::postMonitorQueue(int64_t delayUs) {
    917     sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
    918     msg->setInt32("generation", ++mMonitorQueueGeneration);
    919     msg->post(delayUs);
    920 }
    921 
    922 void LiveSession::onSeek(const sp<AMessage> &msg) {
    923     int64_t timeUs;
    924     CHECK(msg->findInt64("timeUs", &timeUs));
    925 
    926     mSeekTimeUs = timeUs;
    927     postMonitorQueue();
    928 }
    929 
    930 status_t LiveSession::getDuration(int64_t *durationUs) {
    931     Mutex::Autolock autoLock(mLock);
    932     *durationUs = mDurationUs;
    933 
    934     return OK;
    935 }
    936 
    937 bool LiveSession::isSeekable() {
    938     int64_t durationUs;
    939     return getDuration(&durationUs) == OK && durationUs >= 0;
    940 }
    941 
    942 }  // namespace android
    943 
    944