RTSPSource.cpp revision 840667883fd09d44015716d79bc3ac4d60edc0f0
19d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes/* 29d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * Copyright (C) 2010 The Android Open Source Project 39d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * 49d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 59d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * you may not use this file except in compliance with the License. 69d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * You may obtain a copy of the License at 79d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * 89d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 99d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * 109d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * Unless required by applicable law or agreed to in writing, software 119d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 129d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * See the License for the specific language governing permissions and 149d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes * limitations under the License. 159d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes */ 169d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 179d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes//#define LOG_NDEBUG 0 189d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#define LOG_TAG "RTSPSource" 199d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#include <utils/Log.h> 209d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 219d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#include "RTSPSource.h" 229d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 239d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#include "AnotherPacketSource.h" 249d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#include "MyHandler.h" 259d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 269d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes#include <media/stagefright/MetaData.h> 279d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 289d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughesnamespace android { 299d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 309d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott HughesNuPlayer::RTSPSource::RTSPSource( 31c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes const char *url, 32c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes const KeyedVector<String8, String8> *headers, 33eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes bool uidValid, 34eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes uid_t uid) 359d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes : mURL(url), 36c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mUIDValid(uidValid), 37c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mUID(uid), 389d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mFlags(0), 399d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mState(DISCONNECTED), 409d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mFinalResult(OK), 419d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mDisconnectReplyID(0), 429d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mStartingUp(true), 439d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mSeekGeneration(0) { 449d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes if (headers) { 459d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mExtraHeaders = *headers; 469d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 479d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes ssize_t index = 489d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 499d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 509d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes if (index >= 0) { 519d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mFlags |= kFlagIncognito; 529d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 539d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mExtraHeaders.removeItemsAt(index); 549d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes } 559d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes } 56c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes} 579d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 589d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott HughesNuPlayer::RTSPSource::~RTSPSource() { 599d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes if (mLooper != NULL) { 609d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mLooper->stop(); 619d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes } 629d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes} 639d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes 649d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughesvoid NuPlayer::RTSPSource::start() { 659d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes if (mLooper == NULL) { 669d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mLooper = new ALooper; 679d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mLooper->setName("rtsp"); 68c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mLooper->start(); 692a0b873065edb304fa2d1c54f8de663ea638b8abElliott Hughes 709d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes mReflector = new AHandlerReflector<RTSPSource>(this); 71c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mLooper->registerHandler(mReflector); 72c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes } 73c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 74c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes CHECK(mHandler == NULL); 75c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 76c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 77c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 78c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); 79c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mLooper->registerHandler(mHandler); 80c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 81c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes CHECK_EQ(mState, (int)DISCONNECTED); 82c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mState = CONNECTING; 83c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 84c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes mHandler->connect(); 85c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes} 86c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 87c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesvoid NuPlayer::RTSPSource::stop() { 88c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); 89c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 90c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes sp<AMessage> dummy; 91c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes msg->postAndAwaitResponse(&dummy); 92c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes} 93c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 94c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesstatus_t NuPlayer::RTSPSource::feedMoreTSData() { 95c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes return mFinalResult; 96c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes} 97c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 98c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughessp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) { 99c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes sp<AnotherPacketSource> source = getSource(audio); 100c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 101c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes if (source == NULL) { 102c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes return NULL; 103c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes } 104c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes 105c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes return source->getFormat(); 106c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes} 107 108bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() { 109 // We're going to buffer at least 2 secs worth data on all tracks before 110 // starting playback (both at startup and after a seek). 111 112 static const int64_t kMinDurationUs = 2000000ll; 113 114 status_t err; 115 int64_t durationUs; 116 if (mAudioTrack != NULL 117 && (durationUs = mAudioTrack->getBufferedDurationUs(&err)) 118 < kMinDurationUs 119 && err == OK) { 120 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", 121 durationUs / 1E6); 122 return false; 123 } 124 125 if (mVideoTrack != NULL 126 && (durationUs = mVideoTrack->getBufferedDurationUs(&err)) 127 < kMinDurationUs 128 && err == OK) { 129 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", 130 durationUs / 1E6); 131 return false; 132 } 133 134 return true; 135} 136 137status_t NuPlayer::RTSPSource::dequeueAccessUnit( 138 bool audio, sp<ABuffer> *accessUnit) { 139 if (mStartingUp) { 140 if (!haveSufficientDataOnAllTracks()) { 141 return -EWOULDBLOCK; 142 } 143 144 mStartingUp = false; 145 } 146 147 sp<AnotherPacketSource> source = getSource(audio); 148 149 if (source == NULL) { 150 return -EWOULDBLOCK; 151 } 152 153 status_t finalResult; 154 if (!source->hasBufferAvailable(&finalResult)) { 155 return finalResult == OK ? -EWOULDBLOCK : finalResult; 156 } 157 158 return source->dequeueAccessUnit(accessUnit); 159} 160 161sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { 162 return audio ? mAudioTrack : mVideoTrack; 163} 164 165status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { 166 *durationUs = 0ll; 167 168 int64_t audioDurationUs; 169 if (mAudioTrack != NULL 170 && mAudioTrack->getFormat()->findInt64( 171 kKeyDuration, &audioDurationUs) 172 && audioDurationUs > *durationUs) { 173 *durationUs = audioDurationUs; 174 } 175 176 int64_t videoDurationUs; 177 if (mVideoTrack != NULL 178 && mVideoTrack->getFormat()->findInt64( 179 kKeyDuration, &videoDurationUs) 180 && videoDurationUs > *durationUs) { 181 *durationUs = videoDurationUs; 182 } 183 184 return OK; 185} 186 187status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { 188 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id()); 189 msg->setInt32("generation", ++mSeekGeneration); 190 msg->setInt64("timeUs", seekTimeUs); 191 msg->post(200000ll); 192 193 return OK; 194} 195 196void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { 197 if (mState != CONNECTED) { 198 return; 199 } 200 201 mState = SEEKING; 202 mHandler->seek(seekTimeUs); 203} 204 205bool NuPlayer::RTSPSource::isSeekable() { 206 return true; 207} 208 209void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { 210 if (msg->what() == kWhatDisconnect) { 211 uint32_t replyID; 212 CHECK(msg->senderAwaitsResponse(&replyID)); 213 214 mDisconnectReplyID = replyID; 215 finishDisconnectIfPossible(); 216 return; 217 } else if (msg->what() == kWhatPerformSeek) { 218 int32_t generation; 219 CHECK(msg->findInt32("generation", &generation)); 220 221 if (generation != mSeekGeneration) { 222 // obsolete. 223 return; 224 } 225 226 int64_t seekTimeUs; 227 CHECK(msg->findInt64("timeUs", &seekTimeUs)); 228 229 performSeek(seekTimeUs); 230 return; 231 } 232 233 CHECK_EQ(msg->what(), (int)kWhatNotify); 234 235 int32_t what; 236 CHECK(msg->findInt32("what", &what)); 237 238 switch (what) { 239 case MyHandler::kWhatConnected: 240 onConnected(); 241 break; 242 243 case MyHandler::kWhatDisconnected: 244 onDisconnected(msg); 245 break; 246 247 case MyHandler::kWhatSeekDone: 248 { 249 mState = CONNECTED; 250 mStartingUp = true; 251 break; 252 } 253 254 case MyHandler::kWhatAccessUnit: 255 { 256 size_t trackIndex; 257 CHECK(msg->findSize("trackIndex", &trackIndex)); 258 CHECK_LT(trackIndex, mTracks.size()); 259 260 sp<ABuffer> accessUnit; 261 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 262 263 int32_t damaged; 264 if (accessUnit->meta()->findInt32("damaged", &damaged) 265 && damaged) { 266 ALOGI("dropping damaged access unit."); 267 break; 268 } 269 270 TrackInfo *info = &mTracks.editItemAt(trackIndex); 271 272 sp<AnotherPacketSource> source = info->mSource; 273 if (source != NULL) { 274 uint32_t rtpTime; 275 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); 276 277 if (!info->mNPTMappingValid) { 278 // This is a live stream, we didn't receive any normal 279 // playtime mapping. We won't map to npt time. 280 source->queueAccessUnit(accessUnit); 281 break; 282 } 283 284 int64_t nptUs = 285 ((double)rtpTime - (double)info->mRTPTime) 286 / info->mTimeScale 287 * 1000000ll 288 + info->mNormalPlaytimeUs; 289 290 accessUnit->meta()->setInt64("timeUs", nptUs); 291 292 source->queueAccessUnit(accessUnit); 293 } 294 break; 295 } 296 297 case MyHandler::kWhatEOS: 298 { 299 size_t trackIndex; 300 CHECK(msg->findSize("trackIndex", &trackIndex)); 301 CHECK_LT(trackIndex, mTracks.size()); 302 303 int32_t finalResult; 304 CHECK(msg->findInt32("finalResult", &finalResult)); 305 CHECK_NE(finalResult, (status_t)OK); 306 307 TrackInfo *info = &mTracks.editItemAt(trackIndex); 308 sp<AnotherPacketSource> source = info->mSource; 309 if (source != NULL) { 310 source->signalEOS(finalResult); 311 } 312 313 break; 314 } 315 316 case MyHandler::kWhatSeekDiscontinuity: 317 { 318 size_t trackIndex; 319 CHECK(msg->findSize("trackIndex", &trackIndex)); 320 CHECK_LT(trackIndex, mTracks.size()); 321 322 TrackInfo *info = &mTracks.editItemAt(trackIndex); 323 sp<AnotherPacketSource> source = info->mSource; 324 if (source != NULL) { 325 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); 326 } 327 328 break; 329 } 330 331 case MyHandler::kWhatNormalPlayTimeMapping: 332 { 333 size_t trackIndex; 334 CHECK(msg->findSize("trackIndex", &trackIndex)); 335 CHECK_LT(trackIndex, mTracks.size()); 336 337 uint32_t rtpTime; 338 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); 339 340 int64_t nptUs; 341 CHECK(msg->findInt64("nptUs", &nptUs)); 342 343 TrackInfo *info = &mTracks.editItemAt(trackIndex); 344 info->mRTPTime = rtpTime; 345 info->mNormalPlaytimeUs = nptUs; 346 info->mNPTMappingValid = true; 347 break; 348 } 349 350 default: 351 TRESPASS(); 352 } 353} 354 355void NuPlayer::RTSPSource::onConnected() { 356 CHECK(mAudioTrack == NULL); 357 CHECK(mVideoTrack == NULL); 358 359 size_t numTracks = mHandler->countTracks(); 360 for (size_t i = 0; i < numTracks; ++i) { 361 int32_t timeScale; 362 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); 363 364 const char *mime; 365 CHECK(format->findCString(kKeyMIMEType, &mime)); 366 367 bool isAudio = !strncasecmp(mime, "audio/", 6); 368 bool isVideo = !strncasecmp(mime, "video/", 6); 369 370 TrackInfo info; 371 info.mTimeScale = timeScale; 372 info.mRTPTime = 0; 373 info.mNormalPlaytimeUs = 0ll; 374 info.mNPTMappingValid = false; 375 376 if ((isAudio && mAudioTrack == NULL) 377 || (isVideo && mVideoTrack == NULL)) { 378 sp<AnotherPacketSource> source = new AnotherPacketSource(format); 379 380 if (isAudio) { 381 mAudioTrack = source; 382 } else { 383 mVideoTrack = source; 384 } 385 386 info.mSource = source; 387 } 388 389 mTracks.push(info); 390 } 391 392 mState = CONNECTED; 393} 394 395void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { 396 status_t err; 397 CHECK(msg->findInt32("result", &err)); 398 CHECK_NE(err, (status_t)OK); 399 400 mLooper->unregisterHandler(mHandler->id()); 401 mHandler.clear(); 402 403 mState = DISCONNECTED; 404 mFinalResult = err; 405 406 if (mDisconnectReplyID != 0) { 407 finishDisconnectIfPossible(); 408 } 409} 410 411void NuPlayer::RTSPSource::finishDisconnectIfPossible() { 412 if (mState != DISCONNECTED) { 413 mHandler->disconnect(); 414 return; 415 } 416 417 (new AMessage)->postReply(mDisconnectReplyID); 418 mDisconnectReplyID = 0; 419} 420 421} // namespace android 422