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 26 #include <media/stagefright/MetaData.h> 27 28 namespace android { 29 30 NuPlayer::RTSPSource::RTSPSource( 31 const char *url, 32 const KeyedVector<String8, String8> *headers, 33 bool uidValid, 34 uid_t uid) 35 : mURL(url), 36 mUIDValid(uidValid), 37 mUID(uid), 38 mFlags(0), 39 mState(DISCONNECTED), 40 mFinalResult(OK), 41 mDisconnectReplyID(0), 42 mSeekGeneration(0) { 43 if (headers) { 44 mExtraHeaders = *headers; 45 46 ssize_t index = 47 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 48 49 if (index >= 0) { 50 mFlags |= kFlagIncognito; 51 52 mExtraHeaders.removeItemsAt(index); 53 } 54 } 55 } 56 57 NuPlayer::RTSPSource::~RTSPSource() { 58 if (mLooper != NULL) { 59 mLooper->stop(); 60 } 61 } 62 63 void NuPlayer::RTSPSource::start() { 64 if (mLooper == NULL) { 65 mLooper = new ALooper; 66 mLooper->setName("rtsp"); 67 mLooper->start(); 68 69 mReflector = new AHandlerReflector<RTSPSource>(this); 70 mLooper->registerHandler(mReflector); 71 } 72 73 CHECK(mHandler == NULL); 74 75 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 76 77 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); 78 mLooper->registerHandler(mHandler); 79 80 CHECK_EQ(mState, (int)DISCONNECTED); 81 mState = CONNECTING; 82 83 mHandler->connect(); 84 } 85 86 void NuPlayer::RTSPSource::stop() { 87 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); 88 89 sp<AMessage> dummy; 90 msg->postAndAwaitResponse(&dummy); 91 } 92 93 status_t NuPlayer::RTSPSource::feedMoreTSData() { 94 return mFinalResult; 95 } 96 97 sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) { 98 sp<AnotherPacketSource> source = getSource(audio); 99 100 if (source == NULL) { 101 return NULL; 102 } 103 104 return source->getFormat(); 105 } 106 107 status_t NuPlayer::RTSPSource::dequeueAccessUnit( 108 bool audio, sp<ABuffer> *accessUnit) { 109 sp<AnotherPacketSource> source = getSource(audio); 110 111 if (source == NULL) { 112 return -EWOULDBLOCK; 113 } 114 115 status_t finalResult; 116 if (!source->hasBufferAvailable(&finalResult)) { 117 return finalResult == OK ? -EWOULDBLOCK : finalResult; 118 } 119 120 return source->dequeueAccessUnit(accessUnit); 121 } 122 123 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { 124 return audio ? mAudioTrack : mVideoTrack; 125 } 126 127 status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { 128 *durationUs = 0ll; 129 130 int64_t audioDurationUs; 131 if (mAudioTrack != NULL 132 && mAudioTrack->getFormat()->findInt64( 133 kKeyDuration, &audioDurationUs) 134 && audioDurationUs > *durationUs) { 135 *durationUs = audioDurationUs; 136 } 137 138 int64_t videoDurationUs; 139 if (mVideoTrack != NULL 140 && mVideoTrack->getFormat()->findInt64( 141 kKeyDuration, &videoDurationUs) 142 && videoDurationUs > *durationUs) { 143 *durationUs = videoDurationUs; 144 } 145 146 return OK; 147 } 148 149 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { 150 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id()); 151 msg->setInt32("generation", ++mSeekGeneration); 152 msg->setInt64("timeUs", seekTimeUs); 153 msg->post(200000ll); 154 155 return OK; 156 } 157 158 void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { 159 if (mState != CONNECTED) { 160 return; 161 } 162 163 mState = SEEKING; 164 mHandler->seek(seekTimeUs); 165 } 166 167 bool NuPlayer::RTSPSource::isSeekable() { 168 return true; 169 } 170 171 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { 172 if (msg->what() == kWhatDisconnect) { 173 uint32_t replyID; 174 CHECK(msg->senderAwaitsResponse(&replyID)); 175 176 mDisconnectReplyID = replyID; 177 finishDisconnectIfPossible(); 178 return; 179 } else if (msg->what() == kWhatPerformSeek) { 180 int32_t generation; 181 CHECK(msg->findInt32("generation", &generation)); 182 183 if (generation != mSeekGeneration) { 184 // obsolete. 185 return; 186 } 187 188 int64_t seekTimeUs; 189 CHECK(msg->findInt64("timeUs", &seekTimeUs)); 190 191 performSeek(seekTimeUs); 192 return; 193 } 194 195 CHECK_EQ(msg->what(), (int)kWhatNotify); 196 197 int32_t what; 198 CHECK(msg->findInt32("what", &what)); 199 200 switch (what) { 201 case MyHandler::kWhatConnected: 202 onConnected(); 203 break; 204 205 case MyHandler::kWhatDisconnected: 206 onDisconnected(msg); 207 break; 208 209 case MyHandler::kWhatSeekDone: 210 { 211 mState = CONNECTED; 212 break; 213 } 214 215 case MyHandler::kWhatAccessUnit: 216 { 217 size_t trackIndex; 218 CHECK(msg->findSize("trackIndex", &trackIndex)); 219 CHECK_LT(trackIndex, mTracks.size()); 220 221 sp<RefBase> obj; 222 CHECK(msg->findObject("accessUnit", &obj)); 223 224 sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); 225 226 int32_t damaged; 227 if (accessUnit->meta()->findInt32("damaged", &damaged) 228 && damaged) { 229 LOGI("dropping damaged access unit."); 230 break; 231 } 232 233 TrackInfo *info = &mTracks.editItemAt(trackIndex); 234 235 sp<AnotherPacketSource> source = info->mSource; 236 if (source != NULL) { 237 uint32_t rtpTime; 238 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); 239 240 if (!info->mNPTMappingValid) { 241 // This is a live stream, we didn't receive any normal 242 // playtime mapping. Assume the first packets correspond 243 // to time 0. 244 245 LOGV("This is a live stream, assuming time = 0"); 246 247 info->mRTPTime = rtpTime; 248 info->mNormalPlaytimeUs = 0ll; 249 info->mNPTMappingValid = true; 250 } 251 252 int64_t nptUs = 253 ((double)rtpTime - (double)info->mRTPTime) 254 / info->mTimeScale 255 * 1000000ll 256 + info->mNormalPlaytimeUs; 257 258 accessUnit->meta()->setInt64("timeUs", nptUs); 259 260 source->queueAccessUnit(accessUnit); 261 } 262 break; 263 } 264 265 case MyHandler::kWhatEOS: 266 { 267 size_t trackIndex; 268 CHECK(msg->findSize("trackIndex", &trackIndex)); 269 CHECK_LT(trackIndex, mTracks.size()); 270 271 int32_t finalResult; 272 CHECK(msg->findInt32("finalResult", &finalResult)); 273 CHECK_NE(finalResult, (status_t)OK); 274 275 TrackInfo *info = &mTracks.editItemAt(trackIndex); 276 sp<AnotherPacketSource> source = info->mSource; 277 if (source != NULL) { 278 source->signalEOS(finalResult); 279 } 280 281 break; 282 } 283 284 case MyHandler::kWhatSeekDiscontinuity: 285 { 286 size_t trackIndex; 287 CHECK(msg->findSize("trackIndex", &trackIndex)); 288 CHECK_LT(trackIndex, mTracks.size()); 289 290 TrackInfo *info = &mTracks.editItemAt(trackIndex); 291 sp<AnotherPacketSource> source = info->mSource; 292 if (source != NULL) { 293 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); 294 } 295 296 break; 297 } 298 299 case MyHandler::kWhatNormalPlayTimeMapping: 300 { 301 size_t trackIndex; 302 CHECK(msg->findSize("trackIndex", &trackIndex)); 303 CHECK_LT(trackIndex, mTracks.size()); 304 305 uint32_t rtpTime; 306 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); 307 308 int64_t nptUs; 309 CHECK(msg->findInt64("nptUs", &nptUs)); 310 311 TrackInfo *info = &mTracks.editItemAt(trackIndex); 312 info->mRTPTime = rtpTime; 313 info->mNormalPlaytimeUs = nptUs; 314 info->mNPTMappingValid = true; 315 break; 316 } 317 318 default: 319 TRESPASS(); 320 } 321 } 322 323 void NuPlayer::RTSPSource::onConnected() { 324 CHECK(mAudioTrack == NULL); 325 CHECK(mVideoTrack == NULL); 326 327 size_t numTracks = mHandler->countTracks(); 328 for (size_t i = 0; i < numTracks; ++i) { 329 int32_t timeScale; 330 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); 331 332 const char *mime; 333 CHECK(format->findCString(kKeyMIMEType, &mime)); 334 335 bool isAudio = !strncasecmp(mime, "audio/", 6); 336 bool isVideo = !strncasecmp(mime, "video/", 6); 337 338 TrackInfo info; 339 info.mTimeScale = timeScale; 340 info.mRTPTime = 0; 341 info.mNormalPlaytimeUs = 0ll; 342 info.mNPTMappingValid = false; 343 344 if ((isAudio && mAudioTrack == NULL) 345 || (isVideo && mVideoTrack == NULL)) { 346 sp<AnotherPacketSource> source = new AnotherPacketSource(format); 347 348 if (isAudio) { 349 mAudioTrack = source; 350 } else { 351 mVideoTrack = source; 352 } 353 354 info.mSource = source; 355 } 356 357 mTracks.push(info); 358 } 359 360 mState = CONNECTED; 361 } 362 363 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { 364 status_t err; 365 CHECK(msg->findInt32("result", &err)); 366 CHECK_NE(err, (status_t)OK); 367 368 mLooper->unregisterHandler(mHandler->id()); 369 mHandler.clear(); 370 371 mState = DISCONNECTED; 372 mFinalResult = err; 373 374 if (mDisconnectReplyID != 0) { 375 finishDisconnectIfPossible(); 376 } 377 } 378 379 void NuPlayer::RTSPSource::finishDisconnectIfPossible() { 380 if (mState != DISCONNECTED) { 381 mHandler->disconnect(); 382 return; 383 } 384 385 (new AMessage)->postReply(mDisconnectReplyID); 386 mDisconnectReplyID = 0; 387 } 388 389 } // namespace android 390