LiveSession.cpp revision 53ae1640ffbfc690962f7f94694b02680c6f66cb
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 41namespace android { 42 43LiveSession::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 68LiveSession::~LiveSession() { 69} 70 71sp<DataSource> LiveSession::getDataSource() { 72 return mDataSource; 73} 74 75void 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 89void LiveSession::disconnect() { 90 Mutex::Autolock autoLock(mLock); 91 mDisconnectPending = true; 92 93 mHTTPDataSource->disconnect(); 94 95 (new AMessage(kWhatDisconnect, id()))->post(); 96} 97 98void 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 111void 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 146int 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 156void 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 205void LiveSession::onDisconnect() { 206 ALOGI("onDisconnect"); 207 208 mDataSource->queueEOS(ERROR_END_OF_STREAM); 209 210 Mutex::Autolock autoLock(mLock); 211 mDisconnectPending = false; 212} 213 214status_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 313sp<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 367static double uniformRand() { 368 return (double)rand() / RAND_MAX; 369} 370 371size_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 442bool 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 499void LiveSession::onDownloadNext() { 500 size_t bandwidthIndex = getBandwidthIndex(); 501 502rinse_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 763void LiveSession::onMonitorQueue() { 764 if (mSeekTimeUs >= 0 765 || mDataSource->countQueuedBuffers() < kMaxNumQueuedFragments) { 766 onDownloadNext(); 767 } else { 768 postMonitorQueue(1000000ll); 769 } 770} 771 772status_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 912void LiveSession::postMonitorQueue(int64_t delayUs) { 913 sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id()); 914 msg->setInt32("generation", ++mMonitorQueueGeneration); 915 msg->post(delayUs); 916} 917 918void LiveSession::onSeek(const sp<AMessage> &msg) { 919 int64_t timeUs; 920 CHECK(msg->findInt64("timeUs", &timeUs)); 921 922 mSeekTimeUs = timeUs; 923 postMonitorQueue(); 924} 925 926status_t LiveSession::getDuration(int64_t *durationUs) { 927 Mutex::Autolock autoLock(mLock); 928 *durationUs = mDurationUs; 929 930 return OK; 931} 932 933bool LiveSession::isSeekable() { 934 int64_t durationUs; 935 return getDuration(&durationUs) == OK && durationUs >= 0; 936} 937 938} // namespace android 939 940