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