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