RTSPSource.cpp revision ec0c597cabf169ca646bcea5faac1bd81ed4484d
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 "RTSPSource" 19#include <utils/Log.h> 20 21#include "RTSPSource.h" 22 23#include "AnotherPacketSource.h" 24#include "MyHandler.h" 25#include "SDPLoader.h" 26 27#include <media/stagefright/MediaDefs.h> 28#include <media/stagefright/MetaData.h> 29 30namespace android { 31 32NuPlayer::RTSPSource::RTSPSource( 33 const sp<AMessage> ¬ify, 34 const char *url, 35 const KeyedVector<String8, String8> *headers, 36 bool uidValid, 37 uid_t uid, 38 bool isSDP) 39 : Source(notify), 40 mURL(url), 41 mUIDValid(uidValid), 42 mUID(uid), 43 mFlags(0), 44 mIsSDP(isSDP), 45 mState(DISCONNECTED), 46 mFinalResult(OK), 47 mDisconnectReplyID(0), 48 mStartingUp(true), 49 mSeekGeneration(0) { 50 if (headers) { 51 mExtraHeaders = *headers; 52 53 ssize_t index = 54 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 55 56 if (index >= 0) { 57 mFlags |= kFlagIncognito; 58 59 mExtraHeaders.removeItemsAt(index); 60 } 61 } 62} 63 64NuPlayer::RTSPSource::~RTSPSource() { 65 mLooper->stop(); 66} 67 68void NuPlayer::RTSPSource::prepareAsync() { 69 if (mLooper == NULL) { 70 mLooper = new ALooper; 71 mLooper->setName("rtsp"); 72 mLooper->start(); 73 74 mReflector = new AHandlerReflector<RTSPSource>(this); 75 mLooper->registerHandler(mReflector); 76 } 77 78 CHECK(mHandler == NULL); 79 CHECK(mSDPLoader == NULL); 80 81 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 82 83 CHECK_EQ(mState, (int)DISCONNECTED); 84 mState = CONNECTING; 85 86 if (mIsSDP) { 87 mSDPLoader = new SDPLoader(notify, 88 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, 89 mUIDValid, mUID); 90 91 mSDPLoader->load( 92 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 93 } else { 94 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); 95 mLooper->registerHandler(mHandler); 96 97 mHandler->connect(); 98 } 99} 100 101void NuPlayer::RTSPSource::start() { 102} 103 104void NuPlayer::RTSPSource::stop() { 105 if (mLooper == NULL) { 106 return; 107 } 108 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); 109 110 sp<AMessage> dummy; 111 msg->postAndAwaitResponse(&dummy); 112} 113 114status_t NuPlayer::RTSPSource::feedMoreTSData() { 115 return mFinalResult; 116} 117 118sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) { 119 sp<AnotherPacketSource> source = getSource(audio); 120 121 if (source == NULL) { 122 return NULL; 123 } 124 125 return source->getFormat(); 126} 127 128bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() { 129 // We're going to buffer at least 2 secs worth data on all tracks before 130 // starting playback (both at startup and after a seek). 131 132 static const int64_t kMinDurationUs = 2000000ll; 133 134 status_t err; 135 int64_t durationUs; 136 if (mAudioTrack != NULL 137 && (durationUs = mAudioTrack->getBufferedDurationUs(&err)) 138 < kMinDurationUs 139 && err == OK) { 140 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", 141 durationUs / 1E6); 142 return false; 143 } 144 145 if (mVideoTrack != NULL 146 && (durationUs = mVideoTrack->getBufferedDurationUs(&err)) 147 < kMinDurationUs 148 && err == OK) { 149 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", 150 durationUs / 1E6); 151 return false; 152 } 153 154 return true; 155} 156 157status_t NuPlayer::RTSPSource::dequeueAccessUnit( 158 bool audio, sp<ABuffer> *accessUnit) { 159 if (mStartingUp) { 160 if (!haveSufficientDataOnAllTracks()) { 161 return -EWOULDBLOCK; 162 } 163 164 mStartingUp = false; 165 } 166 167 sp<AnotherPacketSource> source = getSource(audio); 168 169 if (source == NULL) { 170 return -EWOULDBLOCK; 171 } 172 173 status_t finalResult; 174 if (!source->hasBufferAvailable(&finalResult)) { 175 return finalResult == OK ? -EWOULDBLOCK : finalResult; 176 } 177 178 return source->dequeueAccessUnit(accessUnit); 179} 180 181sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { 182 if (mTSParser != NULL) { 183 sp<MediaSource> source = mTSParser->getSource( 184 audio ? ATSParser::AUDIO : ATSParser::VIDEO); 185 186 return static_cast<AnotherPacketSource *>(source.get()); 187 } 188 189 return audio ? mAudioTrack : mVideoTrack; 190} 191 192status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { 193 *durationUs = 0ll; 194 195 int64_t audioDurationUs; 196 if (mAudioTrack != NULL 197 && mAudioTrack->getFormat()->findInt64( 198 kKeyDuration, &audioDurationUs) 199 && audioDurationUs > *durationUs) { 200 *durationUs = audioDurationUs; 201 } 202 203 int64_t videoDurationUs; 204 if (mVideoTrack != NULL 205 && mVideoTrack->getFormat()->findInt64( 206 kKeyDuration, &videoDurationUs) 207 && videoDurationUs > *durationUs) { 208 *durationUs = videoDurationUs; 209 } 210 211 return OK; 212} 213 214status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { 215 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id()); 216 msg->setInt32("generation", ++mSeekGeneration); 217 msg->setInt64("timeUs", seekTimeUs); 218 msg->post(200000ll); 219 220 return OK; 221} 222 223void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { 224 if (mState != CONNECTED) { 225 return; 226 } 227 228 mState = SEEKING; 229 mHandler->seek(seekTimeUs); 230} 231 232void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { 233 if (msg->what() == kWhatDisconnect) { 234 uint32_t replyID; 235 CHECK(msg->senderAwaitsResponse(&replyID)); 236 237 mDisconnectReplyID = replyID; 238 finishDisconnectIfPossible(); 239 return; 240 } else if (msg->what() == kWhatPerformSeek) { 241 int32_t generation; 242 CHECK(msg->findInt32("generation", &generation)); 243 244 if (generation != mSeekGeneration) { 245 // obsolete. 246 return; 247 } 248 249 int64_t seekTimeUs; 250 CHECK(msg->findInt64("timeUs", &seekTimeUs)); 251 252 performSeek(seekTimeUs); 253 return; 254 } 255 256 CHECK_EQ(msg->what(), (int)kWhatNotify); 257 258 int32_t what; 259 CHECK(msg->findInt32("what", &what)); 260 261 switch (what) { 262 case MyHandler::kWhatConnected: 263 { 264 onConnected(); 265 266 notifyVideoSizeChanged(0, 0); 267 268 uint32_t flags = 0; 269 270 if (mHandler->isSeekable()) { 271 flags = FLAG_CAN_PAUSE | FLAG_CAN_SEEK; 272 273 // Seeking 10secs forward or backward is a very expensive 274 // operation for rtsp, so let's not enable that. 275 // The user can always use the seek bar. 276 } 277 278 notifyFlagsChanged(flags); 279 notifyPrepared(); 280 break; 281 } 282 283 case MyHandler::kWhatDisconnected: 284 { 285 onDisconnected(msg); 286 break; 287 } 288 289 case MyHandler::kWhatSeekDone: 290 { 291 mState = CONNECTED; 292 mStartingUp = true; 293 break; 294 } 295 296 case MyHandler::kWhatAccessUnit: 297 { 298 size_t trackIndex; 299 CHECK(msg->findSize("trackIndex", &trackIndex)); 300 301 if (mTSParser == NULL) { 302 CHECK_LT(trackIndex, mTracks.size()); 303 } else { 304 CHECK_EQ(trackIndex, 0u); 305 } 306 307 sp<ABuffer> accessUnit; 308 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 309 310 int32_t damaged; 311 if (accessUnit->meta()->findInt32("damaged", &damaged) 312 && damaged) { 313 ALOGI("dropping damaged access unit."); 314 break; 315 } 316 317 if (mTSParser != NULL) { 318 size_t offset = 0; 319 status_t err = OK; 320 while (offset + 188 <= accessUnit->size()) { 321 err = mTSParser->feedTSPacket( 322 accessUnit->data() + offset, 188); 323 if (err != OK) { 324 break; 325 } 326 327 offset += 188; 328 } 329 330 if (offset < accessUnit->size()) { 331 err = ERROR_MALFORMED; 332 } 333 334 if (err != OK) { 335 sp<AnotherPacketSource> source = getSource(false /* audio */); 336 if (source != NULL) { 337 source->signalEOS(err); 338 } 339 340 source = getSource(true /* audio */); 341 if (source != NULL) { 342 source->signalEOS(err); 343 } 344 } 345 break; 346 } 347 348 TrackInfo *info = &mTracks.editItemAt(trackIndex); 349 350 sp<AnotherPacketSource> source = info->mSource; 351 if (source != NULL) { 352 uint32_t rtpTime; 353 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); 354 355 if (!info->mNPTMappingValid) { 356 // This is a live stream, we didn't receive any normal 357 // playtime mapping. We won't map to npt time. 358 source->queueAccessUnit(accessUnit); 359 break; 360 } 361 362 int64_t nptUs = 363 ((double)rtpTime - (double)info->mRTPTime) 364 / info->mTimeScale 365 * 1000000ll 366 + info->mNormalPlaytimeUs; 367 368 accessUnit->meta()->setInt64("timeUs", nptUs); 369 370 source->queueAccessUnit(accessUnit); 371 } 372 break; 373 } 374 375 case MyHandler::kWhatEOS: 376 { 377 int32_t finalResult; 378 CHECK(msg->findInt32("finalResult", &finalResult)); 379 CHECK_NE(finalResult, (status_t)OK); 380 381 if (mTSParser != NULL) { 382 sp<AnotherPacketSource> source = getSource(false /* audio */); 383 if (source != NULL) { 384 source->signalEOS(finalResult); 385 } 386 387 source = getSource(true /* audio */); 388 if (source != NULL) { 389 source->signalEOS(finalResult); 390 } 391 392 return; 393 } 394 395 size_t trackIndex; 396 CHECK(msg->findSize("trackIndex", &trackIndex)); 397 CHECK_LT(trackIndex, mTracks.size()); 398 399 TrackInfo *info = &mTracks.editItemAt(trackIndex); 400 sp<AnotherPacketSource> source = info->mSource; 401 if (source != NULL) { 402 source->signalEOS(finalResult); 403 } 404 405 break; 406 } 407 408 case MyHandler::kWhatSeekDiscontinuity: 409 { 410 size_t trackIndex; 411 CHECK(msg->findSize("trackIndex", &trackIndex)); 412 CHECK_LT(trackIndex, mTracks.size()); 413 414 TrackInfo *info = &mTracks.editItemAt(trackIndex); 415 sp<AnotherPacketSource> source = info->mSource; 416 if (source != NULL) { 417 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); 418 } 419 420 break; 421 } 422 423 case MyHandler::kWhatNormalPlayTimeMapping: 424 { 425 size_t trackIndex; 426 CHECK(msg->findSize("trackIndex", &trackIndex)); 427 CHECK_LT(trackIndex, mTracks.size()); 428 429 uint32_t rtpTime; 430 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); 431 432 int64_t nptUs; 433 CHECK(msg->findInt64("nptUs", &nptUs)); 434 435 TrackInfo *info = &mTracks.editItemAt(trackIndex); 436 info->mRTPTime = rtpTime; 437 info->mNormalPlaytimeUs = nptUs; 438 info->mNPTMappingValid = true; 439 break; 440 } 441 442 case SDPLoader::kWhatSDPLoaded: 443 { 444 onSDPLoaded(msg); 445 break; 446 } 447 448 default: 449 TRESPASS(); 450 } 451} 452 453void NuPlayer::RTSPSource::onConnected() { 454 CHECK(mAudioTrack == NULL); 455 CHECK(mVideoTrack == NULL); 456 457 size_t numTracks = mHandler->countTracks(); 458 for (size_t i = 0; i < numTracks; ++i) { 459 int32_t timeScale; 460 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); 461 462 const char *mime; 463 CHECK(format->findCString(kKeyMIMEType, &mime)); 464 465 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 466 // Very special case for MPEG2 Transport Streams. 467 CHECK_EQ(numTracks, 1u); 468 469 mTSParser = new ATSParser; 470 return; 471 } 472 473 bool isAudio = !strncasecmp(mime, "audio/", 6); 474 bool isVideo = !strncasecmp(mime, "video/", 6); 475 476 TrackInfo info; 477 info.mTimeScale = timeScale; 478 info.mRTPTime = 0; 479 info.mNormalPlaytimeUs = 0ll; 480 info.mNPTMappingValid = false; 481 482 if ((isAudio && mAudioTrack == NULL) 483 || (isVideo && mVideoTrack == NULL)) { 484 sp<AnotherPacketSource> source = new AnotherPacketSource(format); 485 486 if (isAudio) { 487 mAudioTrack = source; 488 } else { 489 mVideoTrack = source; 490 } 491 492 info.mSource = source; 493 } 494 495 mTracks.push(info); 496 } 497 498 mState = CONNECTED; 499} 500 501void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) { 502 status_t err; 503 CHECK(msg->findInt32("result", &err)); 504 505 mSDPLoader.clear(); 506 507 if (mDisconnectReplyID != 0) { 508 err = UNKNOWN_ERROR; 509 } 510 511 if (err == OK) { 512 sp<ASessionDescription> desc; 513 sp<RefBase> obj; 514 CHECK(msg->findObject("description", &obj)); 515 desc = static_cast<ASessionDescription *>(obj.get()); 516 517 AString rtspUri; 518 if (!desc->findAttribute(0, "a=control", &rtspUri)) { 519 ALOGE("Unable to find url in SDP"); 520 err = UNKNOWN_ERROR; 521 } else { 522 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 523 524 mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID); 525 mLooper->registerHandler(mHandler); 526 527 mHandler->loadSDP(desc); 528 } 529 } 530 531 if (err != OK) { 532 if (mState == CONNECTING) { 533 // We're still in the preparation phase, signal that it 534 // failed. 535 notifyPrepared(err); 536 } 537 538 mState = DISCONNECTED; 539 mFinalResult = err; 540 541 if (mDisconnectReplyID != 0) { 542 finishDisconnectIfPossible(); 543 } 544 } 545} 546 547void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { 548 status_t err; 549 CHECK(msg->findInt32("result", &err)); 550 CHECK_NE(err, (status_t)OK); 551 552 mLooper->unregisterHandler(mHandler->id()); 553 mHandler.clear(); 554 555 if (mState == CONNECTING) { 556 // We're still in the preparation phase, signal that it 557 // failed. 558 notifyPrepared(err); 559 } 560 561 mState = DISCONNECTED; 562 mFinalResult = err; 563 564 if (mDisconnectReplyID != 0) { 565 finishDisconnectIfPossible(); 566 } 567} 568 569void NuPlayer::RTSPSource::finishDisconnectIfPossible() { 570 if (mState != DISCONNECTED) { 571 if (mHandler != NULL) { 572 mHandler->disconnect(); 573 } else if (mSDPLoader != NULL) { 574 mSDPLoader->cancel(); 575 } 576 return; 577 } 578 579 (new AMessage)->postReply(mDisconnectReplyID); 580 mDisconnectReplyID = 0; 581} 582 583} // namespace android 584