| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 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" | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 25 | #include "SDPLoader.h" | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 26 |  | 
| Andreas Huber | 1b86fe0 | 2014-01-29 11:13:26 -0800 | [diff] [blame] | 27 | #include <media/IMediaHTTPService.h> | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 28 | #include <media/stagefright/MediaDefs.h> | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 29 | #include <media/stagefright/MetaData.h> | 
 | 30 |  | 
 | 31 | namespace android { | 
 | 32 |  | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 33 | const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs | 
 | 34 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 35 | NuPlayer::RTSPSource::RTSPSource( | 
| Andreas Huber | 5ab368a | 2013-02-05 10:14:26 -0800 | [diff] [blame] | 36 |         const sp<AMessage> ¬ify, | 
| Andreas Huber | 1b86fe0 | 2014-01-29 11:13:26 -0800 | [diff] [blame] | 37 |         const sp<IMediaHTTPService> &httpService, | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 38 |         const char *url, | 
 | 39 |         const KeyedVector<String8, String8> *headers, | 
 | 40 |         bool uidValid, | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 41 |         uid_t uid, | 
 | 42 |         bool isSDP) | 
| Andreas Huber | 5ab368a | 2013-02-05 10:14:26 -0800 | [diff] [blame] | 43 |     : Source(notify), | 
| Andreas Huber | 1b86fe0 | 2014-01-29 11:13:26 -0800 | [diff] [blame] | 44 |       mHTTPService(httpService), | 
| Andreas Huber | 5ab368a | 2013-02-05 10:14:26 -0800 | [diff] [blame] | 45 |       mURL(url), | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 46 |       mUIDValid(uidValid), | 
 | 47 |       mUID(uid), | 
 | 48 |       mFlags(0), | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 49 |       mIsSDP(isSDP), | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 50 |       mState(DISCONNECTED), | 
 | 51 |       mFinalResult(OK), | 
| Andreas Huber | ee736e9 | 2011-12-08 13:04:50 -0800 | [diff] [blame] | 52 |       mDisconnectReplyID(0), | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 53 |       mBuffering(false), | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 54 |       mSeekGeneration(0), | 
 | 55 |       mEOSTimeoutAudio(0), | 
 | 56 |       mEOSTimeoutVideo(0) { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 57 |     if (headers) { | 
 | 58 |         mExtraHeaders = *headers; | 
 | 59 |  | 
 | 60 |         ssize_t index = | 
 | 61 |             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); | 
 | 62 |  | 
 | 63 |         if (index >= 0) { | 
 | 64 |             mFlags |= kFlagIncognito; | 
 | 65 |  | 
 | 66 |             mExtraHeaders.removeItemsAt(index); | 
 | 67 |         } | 
 | 68 |     } | 
 | 69 | } | 
 | 70 |  | 
 | 71 | NuPlayer::RTSPSource::~RTSPSource() { | 
| Andreas Huber | 602f5bb | 2013-04-15 16:18:56 -0700 | [diff] [blame] | 72 |     if (mLooper != NULL) { | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 73 |         mLooper->unregisterHandler(id()); | 
| Andreas Huber | 602f5bb | 2013-04-15 16:18:56 -0700 | [diff] [blame] | 74 |         mLooper->stop(); | 
 | 75 |     } | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 76 | } | 
 | 77 |  | 
| Andreas Huber | 57cea55 | 2013-02-05 13:59:56 -0800 | [diff] [blame] | 78 | void NuPlayer::RTSPSource::prepareAsync() { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 79 |     if (mLooper == NULL) { | 
 | 80 |         mLooper = new ALooper; | 
 | 81 |         mLooper->setName("rtsp"); | 
 | 82 |         mLooper->start(); | 
 | 83 |  | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 84 |         mLooper->registerHandler(this); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 85 |     } | 
 | 86 |  | 
 | 87 |     CHECK(mHandler == NULL); | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 88 |     CHECK(mSDPLoader == NULL); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 89 |  | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 90 |     sp<AMessage> notify = new AMessage(kWhatNotify, id()); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 91 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 92 |     CHECK_EQ(mState, (int)DISCONNECTED); | 
 | 93 |     mState = CONNECTING; | 
 | 94 |  | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 95 |     if (mIsSDP) { | 
 | 96 |         mSDPLoader = new SDPLoader(notify, | 
 | 97 |                 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, | 
| Andreas Huber | 81e6844 | 2014-02-05 11:52:33 -0800 | [diff] [blame] | 98 |                 mHTTPService); | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 99 |  | 
| Andreas Huber | 57cea55 | 2013-02-05 13:59:56 -0800 | [diff] [blame] | 100 |         mSDPLoader->load( | 
 | 101 |                 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 102 |     } else { | 
 | 103 |         mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); | 
 | 104 |         mLooper->registerHandler(mHandler); | 
 | 105 |  | 
 | 106 |         mHandler->connect(); | 
 | 107 |     } | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 108 |  | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 109 |     startBufferingIfNecessary(); | 
| Andreas Huber | 57cea55 | 2013-02-05 13:59:56 -0800 | [diff] [blame] | 110 | } | 
 | 111 |  | 
 | 112 | void NuPlayer::RTSPSource::start() { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 113 | } | 
 | 114 |  | 
 | 115 | void NuPlayer::RTSPSource::stop() { | 
| James Dong | 5834181 | 2012-11-16 14:31:15 -0800 | [diff] [blame] | 116 |     if (mLooper == NULL) { | 
 | 117 |         return; | 
 | 118 |     } | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 119 |     sp<AMessage> msg = new AMessage(kWhatDisconnect, id()); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 120 |  | 
 | 121 |     sp<AMessage> dummy; | 
 | 122 |     msg->postAndAwaitResponse(&dummy); | 
 | 123 | } | 
 | 124 |  | 
| Roger Jönsson | 46d13e3 | 2013-01-21 17:15:45 +0100 | [diff] [blame] | 125 | void NuPlayer::RTSPSource::pause() { | 
 | 126 |     int64_t mediaDurationUs = 0; | 
 | 127 |     getDuration(&mediaDurationUs); | 
 | 128 |     for (size_t index = 0; index < mTracks.size(); index++) { | 
 | 129 |         TrackInfo *info = &mTracks.editItemAt(index); | 
 | 130 |         sp<AnotherPacketSource> source = info->mSource; | 
 | 131 |  | 
 | 132 |         // Check if EOS or ERROR is received | 
 | 133 |         if (source != NULL && source->isFinished(mediaDurationUs)) { | 
 | 134 |             return; | 
 | 135 |         } | 
 | 136 |     } | 
 | 137 |     mHandler->pause(); | 
 | 138 | } | 
 | 139 |  | 
 | 140 | void NuPlayer::RTSPSource::resume() { | 
 | 141 |     mHandler->resume(); | 
 | 142 | } | 
 | 143 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 144 | status_t NuPlayer::RTSPSource::feedMoreTSData() { | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 145 |     Mutex::Autolock _l(mBufferingLock); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 146 |     return mFinalResult; | 
 | 147 | } | 
 | 148 |  | 
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 149 | sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 150 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 151 |  | 
 | 152 |     if (source == NULL) { | 
 | 153 |         return NULL; | 
 | 154 |     } | 
 | 155 |  | 
 | 156 |     return source->getFormat(); | 
 | 157 | } | 
 | 158 |  | 
| Andreas Huber | bfd4d0d | 2012-05-17 14:18:50 -0700 | [diff] [blame] | 159 | bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() { | 
 | 160 |     // We're going to buffer at least 2 secs worth data on all tracks before | 
 | 161 |     // starting playback (both at startup and after a seek). | 
 | 162 |  | 
 | 163 |     static const int64_t kMinDurationUs = 2000000ll; | 
 | 164 |  | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 165 |     int64_t mediaDurationUs = 0; | 
 | 166 |     getDuration(&mediaDurationUs); | 
 | 167 |     if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs)) | 
 | 168 |             || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) { | 
 | 169 |         return true; | 
 | 170 |     } | 
 | 171 |  | 
| Andreas Huber | bfd4d0d | 2012-05-17 14:18:50 -0700 | [diff] [blame] | 172 |     status_t err; | 
 | 173 |     int64_t durationUs; | 
 | 174 |     if (mAudioTrack != NULL | 
 | 175 |             && (durationUs = mAudioTrack->getBufferedDurationUs(&err)) | 
 | 176 |                     < kMinDurationUs | 
 | 177 |             && err == OK) { | 
 | 178 |         ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", | 
 | 179 |               durationUs / 1E6); | 
 | 180 |         return false; | 
 | 181 |     } | 
 | 182 |  | 
 | 183 |     if (mVideoTrack != NULL | 
 | 184 |             && (durationUs = mVideoTrack->getBufferedDurationUs(&err)) | 
 | 185 |                     < kMinDurationUs | 
 | 186 |             && err == OK) { | 
 | 187 |         ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", | 
 | 188 |               durationUs / 1E6); | 
 | 189 |         return false; | 
 | 190 |     } | 
 | 191 |  | 
 | 192 |     return true; | 
 | 193 | } | 
 | 194 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 195 | status_t NuPlayer::RTSPSource::dequeueAccessUnit( | 
 | 196 |         bool audio, sp<ABuffer> *accessUnit) { | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 197 |     if (!stopBufferingIfNecessary()) { | 
 | 198 |         return -EWOULDBLOCK; | 
| Andreas Huber | bfd4d0d | 2012-05-17 14:18:50 -0700 | [diff] [blame] | 199 |     } | 
 | 200 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 201 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 202 |  | 
 | 203 |     if (source == NULL) { | 
 | 204 |         return -EWOULDBLOCK; | 
 | 205 |     } | 
 | 206 |  | 
 | 207 |     status_t finalResult; | 
 | 208 |     if (!source->hasBufferAvailable(&finalResult)) { | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 209 |         if (finalResult == OK) { | 
 | 210 |             int64_t mediaDurationUs = 0; | 
 | 211 |             getDuration(&mediaDurationUs); | 
 | 212 |             sp<AnotherPacketSource> otherSource = getSource(!audio); | 
 | 213 |             status_t otherFinalResult; | 
 | 214 |  | 
 | 215 |             // If other source already signaled EOS, this source should also signal EOS | 
 | 216 |             if (otherSource != NULL && | 
 | 217 |                     !otherSource->hasBufferAvailable(&otherFinalResult) && | 
 | 218 |                     otherFinalResult == ERROR_END_OF_STREAM) { | 
 | 219 |                 source->signalEOS(ERROR_END_OF_STREAM); | 
 | 220 |                 return ERROR_END_OF_STREAM; | 
 | 221 |             } | 
 | 222 |  | 
 | 223 |             // If this source has detected near end, give it some time to retrieve more | 
 | 224 |             // data before signaling EOS | 
 | 225 |             if (source->isFinished(mediaDurationUs)) { | 
 | 226 |                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo; | 
 | 227 |                 if (eosTimeout == 0) { | 
 | 228 |                     setEOSTimeout(audio, ALooper::GetNowUs()); | 
 | 229 |                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) { | 
 | 230 |                     setEOSTimeout(audio, 0); | 
 | 231 |                     source->signalEOS(ERROR_END_OF_STREAM); | 
 | 232 |                     return ERROR_END_OF_STREAM; | 
 | 233 |                 } | 
 | 234 |                 return -EWOULDBLOCK; | 
 | 235 |             } | 
 | 236 |  | 
 | 237 |             if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) { | 
 | 238 |                 // We should not enter buffering mode | 
 | 239 |                 // if any of the sources already have detected EOS. | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 240 |                 startBufferingIfNecessary(); | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 241 |             } | 
 | 242 |  | 
 | 243 |             return -EWOULDBLOCK; | 
 | 244 |         } | 
 | 245 |         return finalResult; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 246 |     } | 
 | 247 |  | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 248 |     setEOSTimeout(audio, 0); | 
 | 249 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 250 |     return source->dequeueAccessUnit(accessUnit); | 
 | 251 | } | 
 | 252 |  | 
 | 253 | sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 254 |     if (mTSParser != NULL) { | 
 | 255 |         sp<MediaSource> source = mTSParser->getSource( | 
 | 256 |                 audio ? ATSParser::AUDIO : ATSParser::VIDEO); | 
 | 257 |  | 
 | 258 |         return static_cast<AnotherPacketSource *>(source.get()); | 
 | 259 |     } | 
 | 260 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 261 |     return audio ? mAudioTrack : mVideoTrack; | 
 | 262 | } | 
 | 263 |  | 
| Roger Jönsson | cfc3083 | 2013-01-21 16:26:41 +0100 | [diff] [blame] | 264 | void NuPlayer::RTSPSource::setEOSTimeout(bool audio, int64_t timeout) { | 
 | 265 |     if (audio) { | 
 | 266 |         mEOSTimeoutAudio = timeout; | 
 | 267 |     } else { | 
 | 268 |         mEOSTimeoutVideo = timeout; | 
 | 269 |     } | 
 | 270 | } | 
 | 271 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 272 | status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { | 
 | 273 |     *durationUs = 0ll; | 
 | 274 |  | 
 | 275 |     int64_t audioDurationUs; | 
 | 276 |     if (mAudioTrack != NULL | 
 | 277 |             && mAudioTrack->getFormat()->findInt64( | 
 | 278 |                 kKeyDuration, &audioDurationUs) | 
 | 279 |             && audioDurationUs > *durationUs) { | 
 | 280 |         *durationUs = audioDurationUs; | 
 | 281 |     } | 
 | 282 |  | 
 | 283 |     int64_t videoDurationUs; | 
 | 284 |     if (mVideoTrack != NULL | 
 | 285 |             && mVideoTrack->getFormat()->findInt64( | 
 | 286 |                 kKeyDuration, &videoDurationUs) | 
 | 287 |             && videoDurationUs > *durationUs) { | 
 | 288 |         *durationUs = videoDurationUs; | 
 | 289 |     } | 
 | 290 |  | 
 | 291 |     return OK; | 
 | 292 | } | 
 | 293 |  | 
 | 294 | status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 295 |     sp<AMessage> msg = new AMessage(kWhatPerformSeek, id()); | 
| Andreas Huber | ee736e9 | 2011-12-08 13:04:50 -0800 | [diff] [blame] | 296 |     msg->setInt32("generation", ++mSeekGeneration); | 
 | 297 |     msg->setInt64("timeUs", seekTimeUs); | 
 | 298 |     msg->post(200000ll); | 
 | 299 |  | 
 | 300 |     return OK; | 
 | 301 | } | 
 | 302 |  | 
 | 303 | void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 304 |     if (mState != CONNECTED) { | 
| Andreas Huber | ee736e9 | 2011-12-08 13:04:50 -0800 | [diff] [blame] | 305 |         return; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 306 |     } | 
 | 307 |  | 
 | 308 |     mState = SEEKING; | 
 | 309 |     mHandler->seek(seekTimeUs); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 310 | } | 
 | 311 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 312 | void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { | 
 | 313 |     if (msg->what() == kWhatDisconnect) { | 
 | 314 |         uint32_t replyID; | 
 | 315 |         CHECK(msg->senderAwaitsResponse(&replyID)); | 
 | 316 |  | 
 | 317 |         mDisconnectReplyID = replyID; | 
 | 318 |         finishDisconnectIfPossible(); | 
 | 319 |         return; | 
| Andreas Huber | ee736e9 | 2011-12-08 13:04:50 -0800 | [diff] [blame] | 320 |     } else if (msg->what() == kWhatPerformSeek) { | 
 | 321 |         int32_t generation; | 
 | 322 |         CHECK(msg->findInt32("generation", &generation)); | 
 | 323 |  | 
 | 324 |         if (generation != mSeekGeneration) { | 
 | 325 |             // obsolete. | 
 | 326 |             return; | 
 | 327 |         } | 
 | 328 |  | 
 | 329 |         int64_t seekTimeUs; | 
 | 330 |         CHECK(msg->findInt64("timeUs", &seekTimeUs)); | 
 | 331 |  | 
 | 332 |         performSeek(seekTimeUs); | 
 | 333 |         return; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 334 |     } | 
 | 335 |  | 
 | 336 |     CHECK_EQ(msg->what(), (int)kWhatNotify); | 
 | 337 |  | 
 | 338 |     int32_t what; | 
 | 339 |     CHECK(msg->findInt32("what", &what)); | 
 | 340 |  | 
 | 341 |     switch (what) { | 
 | 342 |         case MyHandler::kWhatConnected: | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 343 |         { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 344 |             onConnected(); | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 345 |  | 
| Chong Zhang | ced1c2f | 2014-08-08 15:22:35 -0700 | [diff] [blame] | 346 |             notifyVideoSizeChanged(); | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 347 |  | 
 | 348 |             uint32_t flags = 0; | 
 | 349 |  | 
 | 350 |             if (mHandler->isSeekable()) { | 
| Chong Zhang | 4b7069d | 2013-09-11 12:52:43 -0700 | [diff] [blame] | 351 |                 flags = FLAG_CAN_PAUSE | 
 | 352 |                         | FLAG_CAN_SEEK | 
 | 353 |                         | FLAG_CAN_SEEK_BACKWARD | 
 | 354 |                         | FLAG_CAN_SEEK_FORWARD; | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 355 |             } | 
 | 356 |  | 
 | 357 |             notifyFlagsChanged(flags); | 
 | 358 |             notifyPrepared(); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 359 |             break; | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 360 |         } | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 361 |  | 
 | 362 |         case MyHandler::kWhatDisconnected: | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 363 |         { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 364 |             onDisconnected(msg); | 
 | 365 |             break; | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 366 |         } | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 367 |  | 
 | 368 |         case MyHandler::kWhatSeekDone: | 
 | 369 |         { | 
 | 370 |             mState = CONNECTED; | 
 | 371 |             break; | 
 | 372 |         } | 
 | 373 |  | 
 | 374 |         case MyHandler::kWhatAccessUnit: | 
 | 375 |         { | 
 | 376 |             size_t trackIndex; | 
 | 377 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 378 |  | 
 | 379 |             if (mTSParser == NULL) { | 
 | 380 |                 CHECK_LT(trackIndex, mTracks.size()); | 
 | 381 |             } else { | 
 | 382 |                 CHECK_EQ(trackIndex, 0u); | 
 | 383 |             } | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 384 |  | 
| Andreas Huber | 2d8bedd | 2012-02-21 14:38:23 -0800 | [diff] [blame] | 385 |             sp<ABuffer> accessUnit; | 
 | 386 |             CHECK(msg->findBuffer("accessUnit", &accessUnit)); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 387 |  | 
 | 388 |             int32_t damaged; | 
 | 389 |             if (accessUnit->meta()->findInt32("damaged", &damaged) | 
 | 390 |                     && damaged) { | 
| Steve Block | df64d15 | 2012-01-04 20:05:49 +0000 | [diff] [blame] | 391 |                 ALOGI("dropping damaged access unit."); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 392 |                 break; | 
 | 393 |             } | 
 | 394 |  | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 395 |             if (mTSParser != NULL) { | 
 | 396 |                 size_t offset = 0; | 
 | 397 |                 status_t err = OK; | 
 | 398 |                 while (offset + 188 <= accessUnit->size()) { | 
 | 399 |                     err = mTSParser->feedTSPacket( | 
 | 400 |                             accessUnit->data() + offset, 188); | 
 | 401 |                     if (err != OK) { | 
 | 402 |                         break; | 
 | 403 |                     } | 
 | 404 |  | 
 | 405 |                     offset += 188; | 
 | 406 |                 } | 
 | 407 |  | 
 | 408 |                 if (offset < accessUnit->size()) { | 
 | 409 |                     err = ERROR_MALFORMED; | 
 | 410 |                 } | 
 | 411 |  | 
 | 412 |                 if (err != OK) { | 
 | 413 |                     sp<AnotherPacketSource> source = getSource(false /* audio */); | 
 | 414 |                     if (source != NULL) { | 
 | 415 |                         source->signalEOS(err); | 
 | 416 |                     } | 
 | 417 |  | 
 | 418 |                     source = getSource(true /* audio */); | 
 | 419 |                     if (source != NULL) { | 
 | 420 |                         source->signalEOS(err); | 
 | 421 |                     } | 
 | 422 |                 } | 
 | 423 |                 break; | 
 | 424 |             } | 
 | 425 |  | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 426 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 427 |  | 
 | 428 |             sp<AnotherPacketSource> source = info->mSource; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 429 |             if (source != NULL) { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 430 |                 uint32_t rtpTime; | 
 | 431 |                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); | 
 | 432 |  | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 433 |                 if (!info->mNPTMappingValid) { | 
 | 434 |                     // This is a live stream, we didn't receive any normal | 
| Andreas Huber | c9d1696 | 2012-05-21 11:12:40 -0700 | [diff] [blame] | 435 |                     // playtime mapping. We won't map to npt time. | 
 | 436 |                     source->queueAccessUnit(accessUnit); | 
 | 437 |                     break; | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 438 |                 } | 
 | 439 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 440 |                 int64_t nptUs = | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 441 |                     ((double)rtpTime - (double)info->mRTPTime) | 
 | 442 |                         / info->mTimeScale | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 443 |                         * 1000000ll | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 444 |                         + info->mNormalPlaytimeUs; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 445 |  | 
 | 446 |                 accessUnit->meta()->setInt64("timeUs", nptUs); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 447 |  | 
 | 448 |                 source->queueAccessUnit(accessUnit); | 
 | 449 |             } | 
 | 450 |             break; | 
 | 451 |         } | 
 | 452 |  | 
 | 453 |         case MyHandler::kWhatEOS: | 
 | 454 |         { | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 455 |             int32_t finalResult; | 
 | 456 |             CHECK(msg->findInt32("finalResult", &finalResult)); | 
 | 457 |             CHECK_NE(finalResult, (status_t)OK); | 
 | 458 |  | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 459 |             if (mTSParser != NULL) { | 
 | 460 |                 sp<AnotherPacketSource> source = getSource(false /* audio */); | 
 | 461 |                 if (source != NULL) { | 
 | 462 |                     source->signalEOS(finalResult); | 
 | 463 |                 } | 
 | 464 |  | 
 | 465 |                 source = getSource(true /* audio */); | 
 | 466 |                 if (source != NULL) { | 
 | 467 |                     source->signalEOS(finalResult); | 
 | 468 |                 } | 
 | 469 |  | 
 | 470 |                 return; | 
 | 471 |             } | 
 | 472 |  | 
 | 473 |             size_t trackIndex; | 
 | 474 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 475 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 476 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 477 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 478 |             sp<AnotherPacketSource> source = info->mSource; | 
 | 479 |             if (source != NULL) { | 
 | 480 |                 source->signalEOS(finalResult); | 
 | 481 |             } | 
 | 482 |  | 
 | 483 |             break; | 
 | 484 |         } | 
 | 485 |  | 
 | 486 |         case MyHandler::kWhatSeekDiscontinuity: | 
 | 487 |         { | 
 | 488 |             size_t trackIndex; | 
 | 489 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 490 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 491 |  | 
 | 492 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 493 |             sp<AnotherPacketSource> source = info->mSource; | 
 | 494 |             if (source != NULL) { | 
| Chong Zhang | 632740c | 2014-06-26 13:03:47 -0700 | [diff] [blame] | 495 |                 source->queueDiscontinuity( | 
| Wei Jia | fef808d | 2014-10-31 17:57:05 -0700 | [diff] [blame] | 496 |                         ATSParser::DISCONTINUITY_TIME, | 
| Chong Zhang | 632740c | 2014-06-26 13:03:47 -0700 | [diff] [blame] | 497 |                         NULL, | 
 | 498 |                         true /* discard */); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 499 |             } | 
 | 500 |  | 
 | 501 |             break; | 
 | 502 |         } | 
 | 503 |  | 
 | 504 |         case MyHandler::kWhatNormalPlayTimeMapping: | 
 | 505 |         { | 
 | 506 |             size_t trackIndex; | 
 | 507 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 508 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 509 |  | 
 | 510 |             uint32_t rtpTime; | 
 | 511 |             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); | 
 | 512 |  | 
 | 513 |             int64_t nptUs; | 
 | 514 |             CHECK(msg->findInt64("nptUs", &nptUs)); | 
 | 515 |  | 
 | 516 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 517 |             info->mRTPTime = rtpTime; | 
 | 518 |             info->mNormalPlaytimeUs = nptUs; | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 519 |             info->mNPTMappingValid = true; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 520 |             break; | 
 | 521 |         } | 
 | 522 |  | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 523 |         case SDPLoader::kWhatSDPLoaded: | 
 | 524 |         { | 
 | 525 |             onSDPLoaded(msg); | 
 | 526 |             break; | 
 | 527 |         } | 
 | 528 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 529 |         default: | 
 | 530 |             TRESPASS(); | 
 | 531 |     } | 
 | 532 | } | 
 | 533 |  | 
 | 534 | void NuPlayer::RTSPSource::onConnected() { | 
 | 535 |     CHECK(mAudioTrack == NULL); | 
 | 536 |     CHECK(mVideoTrack == NULL); | 
 | 537 |  | 
 | 538 |     size_t numTracks = mHandler->countTracks(); | 
 | 539 |     for (size_t i = 0; i < numTracks; ++i) { | 
 | 540 |         int32_t timeScale; | 
 | 541 |         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); | 
 | 542 |  | 
 | 543 |         const char *mime; | 
 | 544 |         CHECK(format->findCString(kKeyMIMEType, &mime)); | 
 | 545 |  | 
| Andreas Huber | 4969468 | 2012-08-31 10:27:46 -0700 | [diff] [blame] | 546 |         if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { | 
 | 547 |             // Very special case for MPEG2 Transport Streams. | 
 | 548 |             CHECK_EQ(numTracks, 1u); | 
 | 549 |  | 
 | 550 |             mTSParser = new ATSParser; | 
 | 551 |             return; | 
 | 552 |         } | 
 | 553 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 554 |         bool isAudio = !strncasecmp(mime, "audio/", 6); | 
 | 555 |         bool isVideo = !strncasecmp(mime, "video/", 6); | 
 | 556 |  | 
 | 557 |         TrackInfo info; | 
 | 558 |         info.mTimeScale = timeScale; | 
 | 559 |         info.mRTPTime = 0; | 
 | 560 |         info.mNormalPlaytimeUs = 0ll; | 
| Andreas Huber | 1906e5c | 2011-12-08 12:27:47 -0800 | [diff] [blame] | 561 |         info.mNPTMappingValid = false; | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 562 |  | 
 | 563 |         if ((isAudio && mAudioTrack == NULL) | 
 | 564 |                 || (isVideo && mVideoTrack == NULL)) { | 
 | 565 |             sp<AnotherPacketSource> source = new AnotherPacketSource(format); | 
 | 566 |  | 
 | 567 |             if (isAudio) { | 
 | 568 |                 mAudioTrack = source; | 
 | 569 |             } else { | 
 | 570 |                 mVideoTrack = source; | 
 | 571 |             } | 
 | 572 |  | 
 | 573 |             info.mSource = source; | 
 | 574 |         } | 
 | 575 |  | 
 | 576 |         mTracks.push(info); | 
 | 577 |     } | 
 | 578 |  | 
 | 579 |     mState = CONNECTED; | 
 | 580 | } | 
 | 581 |  | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 582 | void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) { | 
 | 583 |     status_t err; | 
 | 584 |     CHECK(msg->findInt32("result", &err)); | 
 | 585 |  | 
 | 586 |     mSDPLoader.clear(); | 
 | 587 |  | 
 | 588 |     if (mDisconnectReplyID != 0) { | 
 | 589 |         err = UNKNOWN_ERROR; | 
 | 590 |     } | 
 | 591 |  | 
 | 592 |     if (err == OK) { | 
 | 593 |         sp<ASessionDescription> desc; | 
 | 594 |         sp<RefBase> obj; | 
 | 595 |         CHECK(msg->findObject("description", &obj)); | 
 | 596 |         desc = static_cast<ASessionDescription *>(obj.get()); | 
 | 597 |  | 
 | 598 |         AString rtspUri; | 
 | 599 |         if (!desc->findAttribute(0, "a=control", &rtspUri)) { | 
 | 600 |             ALOGE("Unable to find url in SDP"); | 
 | 601 |             err = UNKNOWN_ERROR; | 
 | 602 |         } else { | 
| Chong Zhang | 1228d6b | 2014-08-12 21:25:48 -0700 | [diff] [blame] | 603 |             sp<AMessage> notify = new AMessage(kWhatNotify, id()); | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 604 |  | 
 | 605 |             mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID); | 
 | 606 |             mLooper->registerHandler(mHandler); | 
 | 607 |  | 
 | 608 |             mHandler->loadSDP(desc); | 
 | 609 |         } | 
 | 610 |     } | 
 | 611 |  | 
 | 612 |     if (err != OK) { | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 613 |         if (mState == CONNECTING) { | 
 | 614 |             // We're still in the preparation phase, signal that it | 
 | 615 |             // failed. | 
 | 616 |             notifyPrepared(err); | 
 | 617 |         } | 
 | 618 |  | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 619 |         mState = DISCONNECTED; | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 620 |         setError(err); | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 621 |  | 
 | 622 |         if (mDisconnectReplyID != 0) { | 
 | 623 |             finishDisconnectIfPossible(); | 
 | 624 |         } | 
 | 625 |     } | 
 | 626 | } | 
 | 627 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 628 | void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { | 
| Fredrik Rosin | 0ad03bc | 2013-03-06 13:42:53 +0100 | [diff] [blame] | 629 |     if (mState == DISCONNECTED) { | 
 | 630 |         return; | 
 | 631 |     } | 
 | 632 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 633 |     status_t err; | 
 | 634 |     CHECK(msg->findInt32("result", &err)); | 
 | 635 |     CHECK_NE(err, (status_t)OK); | 
 | 636 |  | 
 | 637 |     mLooper->unregisterHandler(mHandler->id()); | 
 | 638 |     mHandler.clear(); | 
 | 639 |  | 
| Andreas Huber | 7f475c3 | 2013-02-05 14:47:13 -0800 | [diff] [blame] | 640 |     if (mState == CONNECTING) { | 
 | 641 |         // We're still in the preparation phase, signal that it | 
 | 642 |         // failed. | 
 | 643 |         notifyPrepared(err); | 
 | 644 |     } | 
 | 645 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 646 |     mState = DISCONNECTED; | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 647 |     setError(err); | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 648 |  | 
 | 649 |     if (mDisconnectReplyID != 0) { | 
 | 650 |         finishDisconnectIfPossible(); | 
 | 651 |     } | 
 | 652 | } | 
 | 653 |  | 
 | 654 | void NuPlayer::RTSPSource::finishDisconnectIfPossible() { | 
 | 655 |     if (mState != DISCONNECTED) { | 
| Oscar Rydhé | 81dd60e | 2012-02-20 10:15:48 +0100 | [diff] [blame] | 656 |         if (mHandler != NULL) { | 
 | 657 |             mHandler->disconnect(); | 
 | 658 |         } else if (mSDPLoader != NULL) { | 
 | 659 |             mSDPLoader->cancel(); | 
 | 660 |         } | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 661 |         return; | 
 | 662 |     } | 
 | 663 |  | 
 | 664 |     (new AMessage)->postReply(mDisconnectReplyID); | 
 | 665 |     mDisconnectReplyID = 0; | 
 | 666 | } | 
 | 667 |  | 
| Chong Zhang | 180d1b9 | 2014-12-02 18:35:35 -0800 | [diff] [blame^] | 668 | void NuPlayer::RTSPSource::setError(status_t err) { | 
 | 669 |     Mutex::Autolock _l(mBufferingLock); | 
 | 670 |     mFinalResult = err; | 
 | 671 | } | 
 | 672 |  | 
 | 673 | void NuPlayer::RTSPSource::startBufferingIfNecessary() { | 
 | 674 |     Mutex::Autolock _l(mBufferingLock); | 
 | 675 |  | 
 | 676 |     if (!mBuffering) { | 
 | 677 |         mBuffering = true; | 
 | 678 |  | 
 | 679 |         sp<AMessage> notify = dupNotify(); | 
 | 680 |         notify->setInt32("what", kWhatBufferingStart); | 
 | 681 |         notify->post(); | 
 | 682 |     } | 
 | 683 | } | 
 | 684 |  | 
 | 685 | bool NuPlayer::RTSPSource::stopBufferingIfNecessary() { | 
 | 686 |     Mutex::Autolock _l(mBufferingLock); | 
 | 687 |  | 
 | 688 |     if (mBuffering) { | 
 | 689 |         if (!haveSufficientDataOnAllTracks()) { | 
 | 690 |             return false; | 
 | 691 |         } | 
 | 692 |  | 
 | 693 |         mBuffering = false; | 
 | 694 |  | 
 | 695 |         sp<AMessage> notify = dupNotify(); | 
 | 696 |         notify->setInt32("what", kWhatBufferingEnd); | 
 | 697 |         notify->post(); | 
 | 698 |     } | 
 | 699 |  | 
 | 700 |     return true; | 
 | 701 | } | 
 | 702 |  | 
 | 703 |  | 
| Andreas Huber | 2bfdd42 | 2011-10-11 15:24:07 -0700 | [diff] [blame] | 704 | }  // namespace android |