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 if (mLiveSession->isSeekable()) { 262 return mLiveSession->seekTo(seekTimeUs, mode); 263 } else { 264 return INVALID_OPERATION; 265 } 266} 267 268void NuPlayer::HTTPLiveSource::pollForRawData( 269 const sp<AMessage> &msg, int32_t currentGeneration, 270 LiveSession::StreamType fetchType, int32_t pushWhat) { 271 272 int32_t generation; 273 CHECK(msg->findInt32("generation", &generation)); 274 275 if (generation != currentGeneration) { 276 return; 277 } 278 279 sp<ABuffer> buffer; 280 while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) { 281 282 sp<AMessage> notify = dupNotify(); 283 notify->setInt32("what", pushWhat); 284 notify->setBuffer("buffer", buffer); 285 286 int64_t timeUs, baseUs, delayUs; 287 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 288 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 289 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 290 291 if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) { 292 notify->post(); 293 msg->post(delayUs > 0ll ? delayUs : 0ll); 294 return; 295 } else if (fetchType == LiveSession::STREAMTYPE_METADATA) { 296 if (delayUs < -1000000ll) { // 1 second 297 continue; 298 } 299 notify->post(); 300 // push all currently available metadata buffers in each invocation of pollForRawData 301 // continue; 302 } else { 303 TRESPASS(); 304 } 305 } 306 307 // try again in 1 second 308 msg->post(1000000ll); 309} 310 311void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 312 switch (msg->what()) { 313 case kWhatSessionNotify: 314 { 315 onSessionNotify(msg); 316 break; 317 } 318 319 case kWhatFetchSubtitleData: 320 { 321 pollForRawData( 322 msg, mFetchSubtitleDataGeneration, 323 /* fetch */ LiveSession::STREAMTYPE_SUBTITLES, 324 /* push */ kWhatSubtitleData); 325 326 break; 327 } 328 329 case kWhatFetchMetaData: 330 { 331 if (!mMetadataSelected) { 332 break; 333 } 334 335 pollForRawData( 336 msg, mFetchMetaDataGeneration, 337 /* fetch */ LiveSession::STREAMTYPE_METADATA, 338 /* push */ kWhatTimedMetaData); 339 340 break; 341 } 342 343 default: 344 Source::onMessageReceived(msg); 345 break; 346 } 347} 348 349void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 350 int32_t what; 351 CHECK(msg->findInt32("what", &what)); 352 353 switch (what) { 354 case LiveSession::kWhatPrepared: 355 { 356 // notify the current size here if we have it, otherwise report an initial size of (0,0) 357 sp<AMessage> format = getFormat(false /* audio */); 358 int32_t width; 359 int32_t height; 360 if (format != NULL && 361 format->findInt32("width", &width) && format->findInt32("height", &height)) { 362 notifyVideoSizeChanged(format); 363 } else { 364 notifyVideoSizeChanged(); 365 } 366 367 uint32_t flags = 0; 368 if (mLiveSession->isSeekable()) { 369 flags |= FLAG_CAN_PAUSE; 370 flags |= FLAG_CAN_SEEK; 371 flags |= FLAG_CAN_SEEK_BACKWARD; 372 flags |= FLAG_CAN_SEEK_FORWARD; 373 } 374 375 if (mLiveSession->hasDynamicDuration()) { 376 flags |= FLAG_DYNAMIC_DURATION; 377 } 378 379 notifyFlagsChanged(flags); 380 381 notifyPrepared(); 382 break; 383 } 384 385 case LiveSession::kWhatPreparationFailed: 386 { 387 status_t err; 388 CHECK(msg->findInt32("err", &err)); 389 390 notifyPrepared(err); 391 break; 392 } 393 394 case LiveSession::kWhatStreamsChanged: 395 { 396 uint32_t changedMask; 397 CHECK(msg->findInt32( 398 "changedMask", (int32_t *)&changedMask)); 399 400 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 401 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 402 403 sp<AMessage> reply; 404 CHECK(msg->findMessage("reply", &reply)); 405 406 sp<AMessage> notify = dupNotify(); 407 notify->setInt32("what", kWhatQueueDecoderShutdown); 408 notify->setInt32("audio", audio); 409 notify->setInt32("video", video); 410 notify->setMessage("reply", reply); 411 notify->post(); 412 break; 413 } 414 415 case LiveSession::kWhatBufferingStart: 416 { 417 sp<AMessage> notify = dupNotify(); 418 notify->setInt32("what", kWhatPauseOnBufferingStart); 419 notify->post(); 420 break; 421 } 422 423 case LiveSession::kWhatBufferingEnd: 424 { 425 sp<AMessage> notify = dupNotify(); 426 notify->setInt32("what", kWhatResumeOnBufferingEnd); 427 notify->post(); 428 break; 429 } 430 431 432 case LiveSession::kWhatBufferingUpdate: 433 { 434 sp<AMessage> notify = dupNotify(); 435 int32_t percentage; 436 CHECK(msg->findInt32("percentage", &percentage)); 437 notify->setInt32("what", kWhatBufferingUpdate); 438 notify->setInt32("percentage", percentage); 439 notify->post(); 440 break; 441 } 442 443 case LiveSession::kWhatMetadataDetected: 444 { 445 if (!mHasMetadata) { 446 mHasMetadata = true; 447 448 sp<AMessage> notify = dupNotify(); 449 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE 450 notify->setInt32("what", kWhatTimedMetaData); 451 notify->post(); 452 } 453 break; 454 } 455 456 case LiveSession::kWhatError: 457 { 458 break; 459 } 460 461 default: 462 TRESPASS(); 463 } 464} 465 466} // namespace android 467 468