HTTPLiveSource.cpp revision 48fa06d1e80a872c7495804979256e021e566ae0
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 "HTTPLiveSource" 19#include <utils/Log.h> 20 21#include "HTTPLiveSource.h" 22 23#include "AnotherPacketSource.h" 24#include "LiveDataSource.h" 25 26#include <media/IMediaHTTPService.h> 27#include <media/stagefright/foundation/ABuffer.h> 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/MediaErrors.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/MediaDefs.h> 33#include <media/stagefright/Utils.h> 34 35// default buffer prepare/ready/underflow marks 36static const int kReadyMarkMs = 5000; // 5 seconds 37static const int kPrepareMarkMs = 1500; // 1.5 seconds 38static const int kUnderflowMarkMs = 1000; // 1 second 39 40namespace android { 41 42NuPlayer::HTTPLiveSource::HTTPLiveSource( 43 const sp<AMessage> ¬ify, 44 const sp<IMediaHTTPService> &httpService, 45 const char *url, 46 const KeyedVector<String8, String8> *headers) 47 : Source(notify), 48 mHTTPService(httpService), 49 mURL(url), 50 mFlags(0), 51 mFinalResult(OK), 52 mOffset(0), 53 mFetchSubtitleDataGeneration(0), 54 mFetchMetaDataGeneration(0), 55 mHasMetadata(false), 56 mMetadataSelected(false) { 57 getDefaultBufferingSettings(&mBufferingSettings); 58 if (headers) { 59 mExtraHeaders = *headers; 60 61 ssize_t index = 62 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 63 64 if (index >= 0) { 65 mFlags |= kFlagIncognito; 66 67 mExtraHeaders.removeItemsAt(index); 68 } 69 } 70} 71 72NuPlayer::HTTPLiveSource::~HTTPLiveSource() { 73 if (mLiveSession != NULL) { 74 mLiveSession->disconnect(); 75 76 mLiveLooper->unregisterHandler(mLiveSession->id()); 77 mLiveLooper->unregisterHandler(id()); 78 mLiveLooper->stop(); 79 80 mLiveSession.clear(); 81 mLiveLooper.clear(); 82 } 83} 84 85status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings( 86 BufferingSettings* buffering /* nonnull */) { 87 buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY; 88 buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY; 89 buffering->mInitialWatermarkMs = kPrepareMarkMs; 90 buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs; 91 buffering->mRebufferingWatermarkHighMs = kReadyMarkMs; 92 93 return OK; 94} 95 96status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) { 97 if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode) 98 || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode) 99 || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode) 100 && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) { 101 return BAD_VALUE; 102 } 103 104 mBufferingSettings = buffering; 105 106 if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) { 107 mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark; 108 } 109 if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) { 110 mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark; 111 mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX; 112 } 113 114 if (mLiveSession != NULL) { 115 mLiveSession->setBufferingSettings(mBufferingSettings); 116 } 117 118 return OK; 119} 120 121void NuPlayer::HTTPLiveSource::prepareAsync() { 122 if (mLiveLooper == NULL) { 123 mLiveLooper = new ALooper; 124 mLiveLooper->setName("http live"); 125 mLiveLooper->start(); 126 127 mLiveLooper->registerHandler(this); 128 } 129 130 sp<AMessage> notify = new AMessage(kWhatSessionNotify, this); 131 132 mLiveSession = new LiveSession( 133 notify, 134 (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, 135 mHTTPService); 136 137 mLiveLooper->registerHandler(mLiveSession); 138 139 mLiveSession->setBufferingSettings(mBufferingSettings); 140 mLiveSession->connectAsync( 141 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 142} 143 144void NuPlayer::HTTPLiveSource::start() { 145} 146 147sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) { 148 sp<MetaData> meta; 149 if (mLiveSession != NULL) { 150 mLiveSession->getStreamFormatMeta( 151 audio ? LiveSession::STREAMTYPE_AUDIO 152 : LiveSession::STREAMTYPE_VIDEO, 153 &meta); 154 } 155 156 return meta; 157} 158 159sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) { 160 sp<MetaData> meta; 161 status_t err = -EWOULDBLOCK; 162 if (mLiveSession != NULL) { 163 err = mLiveSession->getStreamFormatMeta( 164 audio ? LiveSession::STREAMTYPE_AUDIO 165 : LiveSession::STREAMTYPE_VIDEO, 166 &meta); 167 } 168 169 sp<AMessage> format; 170 if (err == -EWOULDBLOCK) { 171 format = new AMessage(); 172 format->setInt32("err", err); 173 return format; 174 } 175 176 if (err != OK || convertMetaDataToMessage(meta, &format) != OK) { 177 return NULL; 178 } 179 return format; 180} 181 182status_t NuPlayer::HTTPLiveSource::feedMoreTSData() { 183 return OK; 184} 185 186status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit( 187 bool audio, sp<ABuffer> *accessUnit) { 188 return mLiveSession->dequeueAccessUnit( 189 audio ? LiveSession::STREAMTYPE_AUDIO 190 : LiveSession::STREAMTYPE_VIDEO, 191 accessUnit); 192} 193 194status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { 195 return mLiveSession->getDuration(durationUs); 196} 197 198size_t NuPlayer::HTTPLiveSource::getTrackCount() const { 199 return mLiveSession->getTrackCount(); 200} 201 202sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { 203 return mLiveSession->getTrackInfo(trackIndex); 204} 205 206ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const { 207 if (mLiveSession == NULL) { 208 return -1; 209 } else if (type == MEDIA_TRACK_TYPE_METADATA) { 210 // MEDIA_TRACK_TYPE_METADATA is always last track 211 // mMetadataSelected can only be true when mHasMetadata is true 212 return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1; 213 } else { 214 return mLiveSession->getSelectedTrack(type); 215 } 216} 217 218status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) { 219 if (mLiveSession == NULL) { 220 return INVALID_OPERATION; 221 } 222 223 status_t err = INVALID_OPERATION; 224 bool postFetchMsg = false, isSub = false; 225 if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) { 226 err = mLiveSession->selectTrack(trackIndex, select); 227 postFetchMsg = select; 228 isSub = true; 229 } else { 230 // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1) 231 if (mMetadataSelected && !select) { 232 err = OK; 233 } else if (!mMetadataSelected && select) { 234 postFetchMsg = true; 235 err = OK; 236 } else { 237 err = BAD_VALUE; // behave as LiveSession::selectTrack 238 } 239 240 mMetadataSelected = select; 241 } 242 243 if (err == OK) { 244 int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration; 245 generation++; 246 if (postFetchMsg) { 247 int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData; 248 sp<AMessage> msg = new AMessage(what, this); 249 msg->setInt32("generation", generation); 250 msg->post(); 251 } 252 } 253 254 // LiveSession::selectTrack returns BAD_VALUE when selecting the currently 255 // selected track, or unselecting a non-selected track. In this case it's an 256 // no-op so we return OK. 257 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; 258} 259 260status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) { 261 return mLiveSession->seekTo(seekTimeUs, mode); 262} 263 264void NuPlayer::HTTPLiveSource::pollForRawData( 265 const sp<AMessage> &msg, int32_t currentGeneration, 266 LiveSession::StreamType fetchType, int32_t pushWhat) { 267 268 int32_t generation; 269 CHECK(msg->findInt32("generation", &generation)); 270 271 if (generation != currentGeneration) { 272 return; 273 } 274 275 sp<ABuffer> buffer; 276 while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) { 277 278 sp<AMessage> notify = dupNotify(); 279 notify->setInt32("what", pushWhat); 280 notify->setBuffer("buffer", buffer); 281 282 int64_t timeUs, baseUs, delayUs; 283 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 284 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 285 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 286 287 if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) { 288 notify->post(); 289 msg->post(delayUs > 0ll ? delayUs : 0ll); 290 return; 291 } else if (fetchType == LiveSession::STREAMTYPE_METADATA) { 292 if (delayUs < -1000000ll) { // 1 second 293 continue; 294 } 295 notify->post(); 296 // push all currently available metadata buffers in each invocation of pollForRawData 297 // continue; 298 } else { 299 TRESPASS(); 300 } 301 } 302 303 // try again in 1 second 304 msg->post(1000000ll); 305} 306 307void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 308 switch (msg->what()) { 309 case kWhatSessionNotify: 310 { 311 onSessionNotify(msg); 312 break; 313 } 314 315 case kWhatFetchSubtitleData: 316 { 317 pollForRawData( 318 msg, mFetchSubtitleDataGeneration, 319 /* fetch */ LiveSession::STREAMTYPE_SUBTITLES, 320 /* push */ kWhatSubtitleData); 321 322 break; 323 } 324 325 case kWhatFetchMetaData: 326 { 327 if (!mMetadataSelected) { 328 break; 329 } 330 331 pollForRawData( 332 msg, mFetchMetaDataGeneration, 333 /* fetch */ LiveSession::STREAMTYPE_METADATA, 334 /* push */ kWhatTimedMetaData); 335 336 break; 337 } 338 339 default: 340 Source::onMessageReceived(msg); 341 break; 342 } 343} 344 345void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 346 int32_t what; 347 CHECK(msg->findInt32("what", &what)); 348 349 switch (what) { 350 case LiveSession::kWhatPrepared: 351 { 352 // notify the current size here if we have it, otherwise report an initial size of (0,0) 353 sp<AMessage> format = getFormat(false /* audio */); 354 int32_t width; 355 int32_t height; 356 if (format != NULL && 357 format->findInt32("width", &width) && format->findInt32("height", &height)) { 358 notifyVideoSizeChanged(format); 359 } else { 360 notifyVideoSizeChanged(); 361 } 362 363 uint32_t flags = 0; 364 if (mLiveSession->isSeekable()) { 365 flags |= FLAG_CAN_PAUSE; 366 flags |= FLAG_CAN_SEEK; 367 flags |= FLAG_CAN_SEEK_BACKWARD; 368 flags |= FLAG_CAN_SEEK_FORWARD; 369 } 370 371 if (mLiveSession->hasDynamicDuration()) { 372 flags |= FLAG_DYNAMIC_DURATION; 373 } 374 375 notifyFlagsChanged(flags); 376 377 notifyPrepared(); 378 break; 379 } 380 381 case LiveSession::kWhatPreparationFailed: 382 { 383 status_t err; 384 CHECK(msg->findInt32("err", &err)); 385 386 notifyPrepared(err); 387 break; 388 } 389 390 case LiveSession::kWhatStreamsChanged: 391 { 392 uint32_t changedMask; 393 CHECK(msg->findInt32( 394 "changedMask", (int32_t *)&changedMask)); 395 396 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 397 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 398 399 sp<AMessage> reply; 400 CHECK(msg->findMessage("reply", &reply)); 401 402 sp<AMessage> notify = dupNotify(); 403 notify->setInt32("what", kWhatQueueDecoderShutdown); 404 notify->setInt32("audio", audio); 405 notify->setInt32("video", video); 406 notify->setMessage("reply", reply); 407 notify->post(); 408 break; 409 } 410 411 case LiveSession::kWhatBufferingStart: 412 { 413 sp<AMessage> notify = dupNotify(); 414 notify->setInt32("what", kWhatPauseOnBufferingStart); 415 notify->post(); 416 break; 417 } 418 419 case LiveSession::kWhatBufferingEnd: 420 { 421 sp<AMessage> notify = dupNotify(); 422 notify->setInt32("what", kWhatResumeOnBufferingEnd); 423 notify->post(); 424 break; 425 } 426 427 428 case LiveSession::kWhatBufferingUpdate: 429 { 430 sp<AMessage> notify = dupNotify(); 431 int32_t percentage; 432 CHECK(msg->findInt32("percentage", &percentage)); 433 notify->setInt32("what", kWhatBufferingUpdate); 434 notify->setInt32("percentage", percentage); 435 notify->post(); 436 break; 437 } 438 439 case LiveSession::kWhatMetadataDetected: 440 { 441 if (!mHasMetadata) { 442 mHasMetadata = true; 443 444 sp<AMessage> notify = dupNotify(); 445 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE 446 notify->setInt32("what", kWhatTimedMetaData); 447 notify->post(); 448 } 449 break; 450 } 451 452 case LiveSession::kWhatError: 453 { 454 break; 455 } 456 457 default: 458 TRESPASS(); 459 } 460} 461 462} // namespace android 463 464