| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 1 | /* | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 2 |  * Copyright 2017 The Android Open Source Project | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 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 | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 18 | #define LOG_TAG "RTSPSource2" | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 19 | #include <utils/Log.h> | 
 | 20 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 21 | #include "RTSPSource2.h" | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 22 |  | 
 | 23 | #include "AnotherPacketSource.h" | 
 | 24 | #include "MyHandler.h" | 
 | 25 | #include "SDPLoader.h" | 
 | 26 |  | 
 | 27 | #include <media/MediaHTTPService.h> | 
 | 28 | #include <media/stagefright/MediaDefs.h> | 
 | 29 | #include <media/stagefright/MetaData.h> | 
 | 30 |  | 
 | 31 | namespace android { | 
 | 32 |  | 
 | 33 | const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs | 
 | 34 |  | 
 | 35 | // Default Buffer Underflow/Prepare/StartServer/Overflow Marks | 
 | 36 | static const int kUnderflowMarkMs   =  1000;  // 1 second | 
 | 37 | static const int kPrepareMarkMs     =  3000;  // 3 seconds | 
 | 38 | //static const int kStartServerMarkMs =  5000; | 
 | 39 | static const int kOverflowMarkMs    = 10000;  // 10 seconds | 
 | 40 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 41 | NuPlayer2::RTSPSource2::RTSPSource2( | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 42 |         const sp<AMessage> ¬ify, | 
 | 43 |         const sp<MediaHTTPService> &httpService, | 
 | 44 |         const char *url, | 
 | 45 |         const KeyedVector<String8, String8> *headers, | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 46 |         uid_t uid, | 
 | 47 |         bool isSDP) | 
 | 48 |     : Source(notify), | 
 | 49 |       mHTTPService(httpService), | 
 | 50 |       mURL(url), | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 51 |       mUID(uid), | 
 | 52 |       mFlags(0), | 
 | 53 |       mIsSDP(isSDP), | 
 | 54 |       mState(DISCONNECTED), | 
 | 55 |       mFinalResult(OK), | 
 | 56 |       mDisconnectReplyID(0), | 
 | 57 |       mBuffering(false), | 
 | 58 |       mInPreparationPhase(true), | 
 | 59 |       mEOSPending(false), | 
 | 60 |       mSeekGeneration(0), | 
 | 61 |       mEOSTimeoutAudio(0), | 
 | 62 |       mEOSTimeoutVideo(0) { | 
 | 63 |     mBufferingSettings.mInitialMarkMs = kPrepareMarkMs; | 
 | 64 |     mBufferingSettings.mResumePlaybackMarkMs = kOverflowMarkMs; | 
 | 65 |     if (headers) { | 
 | 66 |         mExtraHeaders = *headers; | 
 | 67 |  | 
 | 68 |         ssize_t index = | 
 | 69 |             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); | 
 | 70 |  | 
 | 71 |         if (index >= 0) { | 
 | 72 |             mFlags |= kFlagIncognito; | 
 | 73 |  | 
 | 74 |             mExtraHeaders.removeItemsAt(index); | 
 | 75 |         } | 
 | 76 |     } | 
 | 77 | } | 
 | 78 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 79 | NuPlayer2::RTSPSource2::~RTSPSource2() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 80 |     if (mLooper != NULL) { | 
 | 81 |         mLooper->unregisterHandler(id()); | 
 | 82 |         mLooper->stop(); | 
 | 83 |     } | 
 | 84 | } | 
 | 85 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 86 | status_t NuPlayer2::RTSPSource2::getBufferingSettings( | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 87 |             BufferingSettings* buffering /* nonnull */) { | 
 | 88 |     Mutex::Autolock _l(mBufferingSettingsLock); | 
 | 89 |     *buffering = mBufferingSettings; | 
 | 90 |     return OK; | 
 | 91 | } | 
 | 92 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 93 | status_t NuPlayer2::RTSPSource2::setBufferingSettings(const BufferingSettings& buffering) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 94 |     Mutex::Autolock _l(mBufferingSettingsLock); | 
 | 95 |     mBufferingSettings = buffering; | 
 | 96 |     return OK; | 
 | 97 | } | 
 | 98 |  | 
| Wei Jia | f01e312 | 2018-10-18 11:49:44 -0700 | [diff] [blame^] | 99 | // TODO: fetch data starting from |startTimeUs| | 
 | 100 | void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 101 |     if (mIsSDP && mHTTPService == NULL) { | 
 | 102 |         notifyPrepared(BAD_VALUE); | 
 | 103 |         return; | 
 | 104 |     } | 
 | 105 |  | 
 | 106 |     if (mLooper == NULL) { | 
 | 107 |         mLooper = new ALooper; | 
 | 108 |         mLooper->setName("rtsp"); | 
 | 109 |         mLooper->start(); | 
 | 110 |  | 
 | 111 |         mLooper->registerHandler(this); | 
 | 112 |     } | 
 | 113 |  | 
 | 114 |     CHECK(mHandler == NULL); | 
 | 115 |     CHECK(mSDPLoader == NULL); | 
 | 116 |  | 
 | 117 |     sp<AMessage> notify = new AMessage(kWhatNotify, this); | 
 | 118 |  | 
 | 119 |     CHECK_EQ(mState, (int)DISCONNECTED); | 
 | 120 |     mState = CONNECTING; | 
 | 121 |  | 
 | 122 |     if (mIsSDP) { | 
 | 123 |         mSDPLoader = new SDPLoader(notify, | 
 | 124 |                 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, | 
 | 125 |                 mHTTPService); | 
 | 126 |  | 
 | 127 |         mSDPLoader->load( | 
 | 128 |                 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); | 
 | 129 |     } else { | 
| Wei Jia | 003fdb5 | 2018-02-06 14:44:32 -0800 | [diff] [blame] | 130 |         mHandler = new MyHandler(mURL.c_str(), notify, true /* uidValid */, mUID); | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 131 |         mLooper->registerHandler(mHandler); | 
 | 132 |  | 
 | 133 |         mHandler->connect(); | 
 | 134 |     } | 
 | 135 |  | 
 | 136 |     startBufferingIfNecessary(); | 
 | 137 | } | 
 | 138 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 139 | void NuPlayer2::RTSPSource2::start() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 140 | } | 
 | 141 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 142 | void NuPlayer2::RTSPSource2::stop() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 143 |     if (mLooper == NULL) { | 
 | 144 |         return; | 
 | 145 |     } | 
 | 146 |     sp<AMessage> msg = new AMessage(kWhatDisconnect, this); | 
 | 147 |  | 
 | 148 |     sp<AMessage> dummy; | 
 | 149 |     msg->postAndAwaitResponse(&dummy); | 
 | 150 | } | 
 | 151 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 152 | status_t NuPlayer2::RTSPSource2::feedMoreTSData() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 153 |     Mutex::Autolock _l(mBufferingLock); | 
 | 154 |     return mFinalResult; | 
 | 155 | } | 
 | 156 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 157 | sp<MetaData> NuPlayer2::RTSPSource2::getFormatMeta(bool audio) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 158 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 159 |  | 
 | 160 |     if (source == NULL) { | 
 | 161 |         return NULL; | 
 | 162 |     } | 
 | 163 |  | 
 | 164 |     return source->getFormat(); | 
 | 165 | } | 
 | 166 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 167 | bool NuPlayer2::RTSPSource2::haveSufficientDataOnAllTracks() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 168 |     // We're going to buffer at least 2 secs worth data on all tracks before | 
 | 169 |     // starting playback (both at startup and after a seek). | 
 | 170 |  | 
 | 171 |     static const int64_t kMinDurationUs = 2000000ll; | 
 | 172 |  | 
 | 173 |     int64_t mediaDurationUs = 0; | 
 | 174 |     getDuration(&mediaDurationUs); | 
 | 175 |     if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs)) | 
 | 176 |             || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) { | 
 | 177 |         return true; | 
 | 178 |     } | 
 | 179 |  | 
 | 180 |     status_t err; | 
 | 181 |     int64_t durationUs; | 
 | 182 |     if (mAudioTrack != NULL | 
 | 183 |             && (durationUs = mAudioTrack->getBufferedDurationUs(&err)) | 
 | 184 |                     < kMinDurationUs | 
 | 185 |             && err == OK) { | 
 | 186 |         ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", | 
 | 187 |               durationUs / 1E6); | 
 | 188 |         return false; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     if (mVideoTrack != NULL | 
 | 192 |             && (durationUs = mVideoTrack->getBufferedDurationUs(&err)) | 
 | 193 |                     < kMinDurationUs | 
 | 194 |             && err == OK) { | 
 | 195 |         ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", | 
 | 196 |               durationUs / 1E6); | 
 | 197 |         return false; | 
 | 198 |     } | 
 | 199 |  | 
 | 200 |     return true; | 
 | 201 | } | 
 | 202 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 203 | status_t NuPlayer2::RTSPSource2::dequeueAccessUnit( | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 204 |         bool audio, sp<ABuffer> *accessUnit) { | 
 | 205 |     if (!stopBufferingIfNecessary()) { | 
 | 206 |         return -EWOULDBLOCK; | 
 | 207 |     } | 
 | 208 |  | 
 | 209 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 210 |  | 
 | 211 |     if (source == NULL) { | 
 | 212 |         return -EWOULDBLOCK; | 
 | 213 |     } | 
 | 214 |  | 
 | 215 |     status_t finalResult; | 
 | 216 |     if (!source->hasBufferAvailable(&finalResult)) { | 
 | 217 |         if (finalResult == OK) { | 
 | 218 |  | 
 | 219 |             // If other source already signaled EOS, this source should also return EOS | 
 | 220 |             if (sourceReachedEOS(!audio)) { | 
 | 221 |                 return ERROR_END_OF_STREAM; | 
 | 222 |             } | 
 | 223 |  | 
 | 224 |             // If this source has detected near end, give it some time to retrieve more | 
 | 225 |             // data before returning EOS | 
 | 226 |             int64_t mediaDurationUs = 0; | 
 | 227 |             getDuration(&mediaDurationUs); | 
 | 228 |             if (source->isFinished(mediaDurationUs)) { | 
 | 229 |                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo; | 
 | 230 |                 if (eosTimeout == 0) { | 
 | 231 |                     setEOSTimeout(audio, ALooper::GetNowUs()); | 
 | 232 |                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) { | 
 | 233 |                     setEOSTimeout(audio, 0); | 
 | 234 |                     return ERROR_END_OF_STREAM; | 
 | 235 |                 } | 
 | 236 |                 return -EWOULDBLOCK; | 
 | 237 |             } | 
 | 238 |  | 
 | 239 |             if (!sourceNearEOS(!audio)) { | 
 | 240 |                 // We should not enter buffering mode | 
 | 241 |                 // if any of the sources already have detected EOS. | 
 | 242 |                 startBufferingIfNecessary(); | 
 | 243 |             } | 
 | 244 |  | 
 | 245 |             return -EWOULDBLOCK; | 
 | 246 |         } | 
 | 247 |         return finalResult; | 
 | 248 |     } | 
 | 249 |  | 
 | 250 |     setEOSTimeout(audio, 0); | 
 | 251 |  | 
 | 252 |     return source->dequeueAccessUnit(accessUnit); | 
 | 253 | } | 
 | 254 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 255 | sp<AnotherPacketSource> NuPlayer2::RTSPSource2::getSource(bool audio) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 256 |     if (mTSParser != NULL) { | 
 | 257 |         sp<MediaSource> source = mTSParser->getSource( | 
 | 258 |                 audio ? ATSParser::AUDIO : ATSParser::VIDEO); | 
 | 259 |  | 
 | 260 |         return static_cast<AnotherPacketSource *>(source.get()); | 
 | 261 |     } | 
 | 262 |  | 
 | 263 |     return audio ? mAudioTrack : mVideoTrack; | 
 | 264 | } | 
 | 265 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 266 | void NuPlayer2::RTSPSource2::setEOSTimeout(bool audio, int64_t timeout) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 267 |     if (audio) { | 
 | 268 |         mEOSTimeoutAudio = timeout; | 
 | 269 |     } else { | 
 | 270 |         mEOSTimeoutVideo = timeout; | 
 | 271 |     } | 
 | 272 | } | 
 | 273 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 274 | status_t NuPlayer2::RTSPSource2::getDuration(int64_t *durationUs) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 275 |     *durationUs = -1ll; | 
 | 276 |  | 
 | 277 |     int64_t audioDurationUs; | 
 | 278 |     if (mAudioTrack != NULL | 
 | 279 |             && mAudioTrack->getFormat()->findInt64( | 
 | 280 |                 kKeyDuration, &audioDurationUs) | 
 | 281 |             && audioDurationUs > *durationUs) { | 
 | 282 |         *durationUs = audioDurationUs; | 
 | 283 |     } | 
 | 284 |  | 
 | 285 |     int64_t videoDurationUs; | 
 | 286 |     if (mVideoTrack != NULL | 
 | 287 |             && mVideoTrack->getFormat()->findInt64( | 
 | 288 |                 kKeyDuration, &videoDurationUs) | 
 | 289 |             && videoDurationUs > *durationUs) { | 
 | 290 |         *durationUs = videoDurationUs; | 
 | 291 |     } | 
 | 292 |  | 
 | 293 |     return OK; | 
 | 294 | } | 
 | 295 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 296 | status_t NuPlayer2::RTSPSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 297 |     sp<AMessage> msg = new AMessage(kWhatPerformSeek, this); | 
 | 298 |     msg->setInt32("generation", ++mSeekGeneration); | 
 | 299 |     msg->setInt64("timeUs", seekTimeUs); | 
 | 300 |     msg->setInt32("mode", mode); | 
 | 301 |  | 
 | 302 |     sp<AMessage> response; | 
 | 303 |     status_t err = msg->postAndAwaitResponse(&response); | 
 | 304 |     if (err == OK && response != NULL) { | 
 | 305 |         CHECK(response->findInt32("err", &err)); | 
 | 306 |     } | 
 | 307 |  | 
 | 308 |     return err; | 
 | 309 | } | 
 | 310 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 311 | void NuPlayer2::RTSPSource2::performSeek(int64_t seekTimeUs) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 312 |     if (mState != CONNECTED) { | 
 | 313 |         finishSeek(INVALID_OPERATION); | 
 | 314 |         return; | 
 | 315 |     } | 
 | 316 |  | 
 | 317 |     mState = SEEKING; | 
 | 318 |     mHandler->seek(seekTimeUs); | 
 | 319 |     mEOSPending = false; | 
 | 320 | } | 
 | 321 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 322 | void NuPlayer2::RTSPSource2::schedulePollBuffering() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 323 |     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); | 
 | 324 |     msg->post(1000000ll); // 1 second intervals | 
 | 325 | } | 
 | 326 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 327 | void NuPlayer2::RTSPSource2::checkBuffering( | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 328 |         bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) { | 
 | 329 |     size_t numTracks = mTracks.size(); | 
 | 330 |     size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount; | 
 | 331 |     preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0; | 
 | 332 |  | 
 | 333 |     size_t count = numTracks; | 
 | 334 |     for (size_t i = 0; i < count; ++i) { | 
 | 335 |         status_t finalResult; | 
 | 336 |         TrackInfo *info = &mTracks.editItemAt(i); | 
 | 337 |         sp<AnotherPacketSource> src = info->mSource; | 
 | 338 |         if (src == NULL) { | 
 | 339 |             --numTracks; | 
 | 340 |             continue; | 
 | 341 |         } | 
 | 342 |         int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult); | 
 | 343 |  | 
 | 344 |         int64_t initialMarkUs; | 
 | 345 |         int64_t maxRebufferingMarkUs; | 
 | 346 |         { | 
 | 347 |             Mutex::Autolock _l(mBufferingSettingsLock); | 
 | 348 |             initialMarkUs = mBufferingSettings.mInitialMarkMs * 1000ll; | 
 | 349 |             // TODO: maxRebufferingMarkUs could be larger than | 
 | 350 |             // mBufferingSettings.mResumePlaybackMarkMs * 1000ll. | 
 | 351 |             maxRebufferingMarkUs = mBufferingSettings.mResumePlaybackMarkMs * 1000ll; | 
 | 352 |         } | 
 | 353 |         // isFinished when duration is 0 checks for EOS result only | 
 | 354 |         if (bufferedDurationUs > initialMarkUs | 
 | 355 |                 || src->isFinished(/* duration */ 0)) { | 
 | 356 |             ++preparedCount; | 
 | 357 |         } | 
 | 358 |  | 
 | 359 |         if (src->isFinished(/* duration */ 0)) { | 
 | 360 |             ++overflowCount; | 
 | 361 |             ++finishedCount; | 
 | 362 |         } else { | 
 | 363 |             // TODO: redefine kUnderflowMarkMs to a fair value, | 
 | 364 |             if (bufferedDurationUs < kUnderflowMarkMs * 1000) { | 
 | 365 |                 ++underflowCount; | 
 | 366 |             } | 
 | 367 |             if (bufferedDurationUs > maxRebufferingMarkUs) { | 
 | 368 |                 ++overflowCount; | 
 | 369 |             } | 
 | 370 |             int64_t startServerMarkUs = | 
 | 371 |                     (kUnderflowMarkMs * 1000ll + maxRebufferingMarkUs) / 2; | 
 | 372 |             if (bufferedDurationUs < startServerMarkUs) { | 
 | 373 |                 ++startCount; | 
 | 374 |             } | 
 | 375 |         } | 
 | 376 |     } | 
 | 377 |  | 
 | 378 |     *prepared    = (preparedCount == numTracks); | 
 | 379 |     *underflow   = (underflowCount > 0); | 
 | 380 |     *overflow    = (overflowCount == numTracks); | 
 | 381 |     *startServer = (startCount > 0); | 
 | 382 |     *finished    = (finishedCount > 0); | 
 | 383 | } | 
 | 384 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 385 | void NuPlayer2::RTSPSource2::onPollBuffering() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 386 |     bool prepared, underflow, overflow, startServer, finished; | 
 | 387 |     checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished); | 
 | 388 |  | 
 | 389 |     if (prepared && mInPreparationPhase) { | 
 | 390 |         mInPreparationPhase = false; | 
 | 391 |         notifyPrepared(); | 
 | 392 |     } | 
 | 393 |  | 
 | 394 |     if (!mInPreparationPhase && underflow) { | 
 | 395 |         startBufferingIfNecessary(); | 
 | 396 |     } | 
 | 397 |  | 
 | 398 |     if (haveSufficientDataOnAllTracks()) { | 
 | 399 |         stopBufferingIfNecessary(); | 
 | 400 |     } | 
 | 401 |  | 
 | 402 |     if (overflow && mHandler != NULL) { | 
 | 403 |         mHandler->pause(); | 
 | 404 |     } | 
 | 405 |  | 
 | 406 |     if (startServer && mHandler != NULL) { | 
 | 407 |         mHandler->resume(); | 
 | 408 |     } | 
 | 409 |  | 
 | 410 |     if (finished && mHandler != NULL) { | 
 | 411 |         mHandler->cancelAccessUnitTimeoutCheck(); | 
 | 412 |     } | 
 | 413 |  | 
 | 414 |     schedulePollBuffering(); | 
 | 415 | } | 
 | 416 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 417 | void NuPlayer2::RTSPSource2::signalSourceEOS(status_t result) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 418 |     const bool audio = true; | 
 | 419 |     const bool video = false; | 
 | 420 |  | 
 | 421 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 422 |     if (source != NULL) { | 
 | 423 |         source->signalEOS(result); | 
 | 424 |     } | 
 | 425 |  | 
 | 426 |     source = getSource(video); | 
 | 427 |     if (source != NULL) { | 
 | 428 |         source->signalEOS(result); | 
 | 429 |     } | 
 | 430 | } | 
 | 431 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 432 | bool NuPlayer2::RTSPSource2::sourceReachedEOS(bool audio) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 433 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 434 |     status_t finalResult; | 
 | 435 |     return (source != NULL && | 
 | 436 |             !source->hasBufferAvailable(&finalResult) && | 
 | 437 |             finalResult == ERROR_END_OF_STREAM); | 
 | 438 | } | 
 | 439 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 440 | bool NuPlayer2::RTSPSource2::sourceNearEOS(bool audio) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 441 |     sp<AnotherPacketSource> source = getSource(audio); | 
 | 442 |     int64_t mediaDurationUs = 0; | 
 | 443 |     getDuration(&mediaDurationUs); | 
 | 444 |     return (source != NULL && source->isFinished(mediaDurationUs)); | 
 | 445 | } | 
 | 446 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 447 | void NuPlayer2::RTSPSource2::onSignalEOS(const sp<AMessage> &msg) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 448 |     int32_t generation; | 
 | 449 |     CHECK(msg->findInt32("generation", &generation)); | 
 | 450 |  | 
 | 451 |     if (generation != mSeekGeneration) { | 
 | 452 |         return; | 
 | 453 |     } | 
 | 454 |  | 
 | 455 |     if (mEOSPending) { | 
 | 456 |         signalSourceEOS(ERROR_END_OF_STREAM); | 
 | 457 |         mEOSPending = false; | 
 | 458 |     } | 
 | 459 | } | 
 | 460 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 461 | void NuPlayer2::RTSPSource2::postSourceEOSIfNecessary() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 462 |     const bool audio = true; | 
 | 463 |     const bool video = false; | 
 | 464 |     // If a source has detected near end, give it some time to retrieve more | 
 | 465 |     // data before signaling EOS | 
 | 466 |     if (sourceNearEOS(audio) || sourceNearEOS(video)) { | 
 | 467 |         if (!mEOSPending) { | 
 | 468 |             sp<AMessage> msg = new AMessage(kWhatSignalEOS, this); | 
 | 469 |             msg->setInt32("generation", mSeekGeneration); | 
 | 470 |             msg->post(kNearEOSTimeoutUs); | 
 | 471 |             mEOSPending = true; | 
 | 472 |         } | 
 | 473 |     } | 
 | 474 | } | 
 | 475 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 476 | void NuPlayer2::RTSPSource2::onMessageReceived(const sp<AMessage> &msg) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 477 |     if (msg->what() == kWhatDisconnect) { | 
 | 478 |         sp<AReplyToken> replyID; | 
 | 479 |         CHECK(msg->senderAwaitsResponse(&replyID)); | 
 | 480 |  | 
 | 481 |         mDisconnectReplyID = replyID; | 
 | 482 |         finishDisconnectIfPossible(); | 
 | 483 |         return; | 
 | 484 |     } else if (msg->what() == kWhatPerformSeek) { | 
 | 485 |         int32_t generation; | 
 | 486 |         CHECK(msg->findInt32("generation", &generation)); | 
 | 487 |         CHECK(msg->senderAwaitsResponse(&mSeekReplyID)); | 
 | 488 |  | 
 | 489 |         if (generation != mSeekGeneration) { | 
 | 490 |             // obsolete. | 
 | 491 |             finishSeek(OK); | 
 | 492 |             return; | 
 | 493 |         } | 
 | 494 |  | 
 | 495 |         int64_t seekTimeUs; | 
 | 496 |         int32_t mode; | 
 | 497 |         CHECK(msg->findInt64("timeUs", &seekTimeUs)); | 
 | 498 |         CHECK(msg->findInt32("mode", &mode)); | 
 | 499 |  | 
 | 500 |         // TODO: add "mode" to performSeek. | 
 | 501 |         performSeek(seekTimeUs/*, (MediaPlayer2SeekMode)mode */); | 
 | 502 |         return; | 
 | 503 |     } else if (msg->what() == kWhatPollBuffering) { | 
 | 504 |         onPollBuffering(); | 
 | 505 |         return; | 
 | 506 |     } else if (msg->what() == kWhatSignalEOS) { | 
 | 507 |         onSignalEOS(msg); | 
 | 508 |         return; | 
 | 509 |     } | 
 | 510 |  | 
 | 511 |     CHECK_EQ(msg->what(), kWhatNotify); | 
 | 512 |  | 
 | 513 |     int32_t what; | 
 | 514 |     CHECK(msg->findInt32("what", &what)); | 
 | 515 |  | 
 | 516 |     switch (what) { | 
 | 517 |         case MyHandler::kWhatConnected: | 
 | 518 |         { | 
 | 519 |             onConnected(); | 
 | 520 |  | 
 | 521 |             notifyVideoSizeChanged(); | 
 | 522 |  | 
 | 523 |             uint32_t flags = 0; | 
 | 524 |  | 
 | 525 |             if (mHandler->isSeekable()) { | 
 | 526 |                 flags = FLAG_CAN_PAUSE | 
 | 527 |                         | FLAG_CAN_SEEK | 
 | 528 |                         | FLAG_CAN_SEEK_BACKWARD | 
 | 529 |                         | FLAG_CAN_SEEK_FORWARD; | 
 | 530 |             } | 
 | 531 |  | 
 | 532 |             notifyFlagsChanged(flags); | 
 | 533 |             schedulePollBuffering(); | 
 | 534 |             break; | 
 | 535 |         } | 
 | 536 |  | 
 | 537 |         case MyHandler::kWhatDisconnected: | 
 | 538 |         { | 
 | 539 |             onDisconnected(msg); | 
 | 540 |             break; | 
 | 541 |         } | 
 | 542 |  | 
 | 543 |         case MyHandler::kWhatSeekDone: | 
 | 544 |         { | 
 | 545 |             mState = CONNECTED; | 
 | 546 |             // Unblock seekTo here in case we attempted to seek in a live stream | 
 | 547 |             finishSeek(OK); | 
 | 548 |             break; | 
 | 549 |         } | 
 | 550 |  | 
 | 551 |         case MyHandler::kWhatSeekPaused: | 
 | 552 |         { | 
 | 553 |             sp<AnotherPacketSource> source = getSource(true /* audio */); | 
 | 554 |             if (source != NULL) { | 
 | 555 |                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE, | 
 | 556 |                         /* extra */ NULL, | 
 | 557 |                         /* discard */ true); | 
 | 558 |             } | 
 | 559 |             source = getSource(false /* video */); | 
 | 560 |             if (source != NULL) { | 
 | 561 |                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE, | 
 | 562 |                         /* extra */ NULL, | 
 | 563 |                         /* discard */ true); | 
 | 564 |             }; | 
 | 565 |  | 
 | 566 |             status_t err = OK; | 
 | 567 |             msg->findInt32("err", &err); | 
 | 568 |  | 
 | 569 |             if (err == OK) { | 
 | 570 |                 int64_t timeUs; | 
 | 571 |                 CHECK(msg->findInt64("time", &timeUs)); | 
 | 572 |                 mHandler->continueSeekAfterPause(timeUs); | 
 | 573 |             } else { | 
 | 574 |                 finishSeek(err); | 
 | 575 |             } | 
 | 576 |             break; | 
 | 577 |         } | 
 | 578 |  | 
 | 579 |         case MyHandler::kWhatAccessUnit: | 
 | 580 |         { | 
 | 581 |             size_t trackIndex; | 
 | 582 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 583 |  | 
 | 584 |             if (mTSParser == NULL) { | 
 | 585 |                 CHECK_LT(trackIndex, mTracks.size()); | 
 | 586 |             } else { | 
 | 587 |                 CHECK_EQ(trackIndex, 0u); | 
 | 588 |             } | 
 | 589 |  | 
 | 590 |             sp<ABuffer> accessUnit; | 
 | 591 |             CHECK(msg->findBuffer("accessUnit", &accessUnit)); | 
 | 592 |  | 
 | 593 |             int32_t damaged; | 
 | 594 |             if (accessUnit->meta()->findInt32("damaged", &damaged) | 
 | 595 |                     && damaged) { | 
 | 596 |                 ALOGI("dropping damaged access unit."); | 
 | 597 |                 break; | 
 | 598 |             } | 
 | 599 |  | 
 | 600 |             if (mTSParser != NULL) { | 
 | 601 |                 size_t offset = 0; | 
 | 602 |                 status_t err = OK; | 
 | 603 |                 while (offset + 188 <= accessUnit->size()) { | 
 | 604 |                     err = mTSParser->feedTSPacket( | 
 | 605 |                             accessUnit->data() + offset, 188); | 
 | 606 |                     if (err != OK) { | 
 | 607 |                         break; | 
 | 608 |                     } | 
 | 609 |  | 
 | 610 |                     offset += 188; | 
 | 611 |                 } | 
 | 612 |  | 
 | 613 |                 if (offset < accessUnit->size()) { | 
 | 614 |                     err = ERROR_MALFORMED; | 
 | 615 |                 } | 
 | 616 |  | 
 | 617 |                 if (err != OK) { | 
 | 618 |                     signalSourceEOS(err); | 
 | 619 |                 } | 
 | 620 |  | 
 | 621 |                 postSourceEOSIfNecessary(); | 
 | 622 |                 break; | 
 | 623 |             } | 
 | 624 |  | 
 | 625 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 626 |  | 
 | 627 |             sp<AnotherPacketSource> source = info->mSource; | 
 | 628 |             if (source != NULL) { | 
 | 629 |                 uint32_t rtpTime; | 
 | 630 |                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); | 
 | 631 |  | 
 | 632 |                 if (!info->mNPTMappingValid) { | 
 | 633 |                     // This is a live stream, we didn't receive any normal | 
 | 634 |                     // playtime mapping. We won't map to npt time. | 
 | 635 |                     source->queueAccessUnit(accessUnit); | 
 | 636 |                     break; | 
 | 637 |                 } | 
 | 638 |  | 
 | 639 |                 int64_t nptUs = | 
 | 640 |                     ((double)rtpTime - (double)info->mRTPTime) | 
 | 641 |                         / info->mTimeScale | 
 | 642 |                         * 1000000ll | 
 | 643 |                         + info->mNormalPlaytimeUs; | 
 | 644 |  | 
 | 645 |                 accessUnit->meta()->setInt64("timeUs", nptUs); | 
 | 646 |  | 
 | 647 |                 source->queueAccessUnit(accessUnit); | 
 | 648 |             } | 
 | 649 |             postSourceEOSIfNecessary(); | 
 | 650 |             break; | 
 | 651 |         } | 
 | 652 |  | 
 | 653 |         case MyHandler::kWhatEOS: | 
 | 654 |         { | 
 | 655 |             int32_t finalResult; | 
 | 656 |             CHECK(msg->findInt32("finalResult", &finalResult)); | 
 | 657 |             CHECK_NE(finalResult, (status_t)OK); | 
 | 658 |  | 
 | 659 |             if (mTSParser != NULL) { | 
 | 660 |                 signalSourceEOS(finalResult); | 
 | 661 |             } | 
 | 662 |  | 
 | 663 |             size_t trackIndex; | 
 | 664 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 665 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 666 |  | 
 | 667 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 668 |             sp<AnotherPacketSource> source = info->mSource; | 
 | 669 |             if (source != NULL) { | 
 | 670 |                 source->signalEOS(finalResult); | 
 | 671 |             } | 
 | 672 |  | 
 | 673 |             break; | 
 | 674 |         } | 
 | 675 |  | 
 | 676 |         case MyHandler::kWhatSeekDiscontinuity: | 
 | 677 |         { | 
 | 678 |             size_t trackIndex; | 
 | 679 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 680 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 681 |  | 
 | 682 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 683 |             sp<AnotherPacketSource> source = info->mSource; | 
 | 684 |             if (source != NULL) { | 
 | 685 |                 source->queueDiscontinuity( | 
 | 686 |                         ATSParser::DISCONTINUITY_TIME, | 
 | 687 |                         NULL, | 
 | 688 |                         true /* discard */); | 
 | 689 |             } | 
 | 690 |  | 
 | 691 |             break; | 
 | 692 |         } | 
 | 693 |  | 
 | 694 |         case MyHandler::kWhatNormalPlayTimeMapping: | 
 | 695 |         { | 
 | 696 |             size_t trackIndex; | 
 | 697 |             CHECK(msg->findSize("trackIndex", &trackIndex)); | 
 | 698 |             CHECK_LT(trackIndex, mTracks.size()); | 
 | 699 |  | 
 | 700 |             uint32_t rtpTime; | 
 | 701 |             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); | 
 | 702 |  | 
 | 703 |             int64_t nptUs; | 
 | 704 |             CHECK(msg->findInt64("nptUs", &nptUs)); | 
 | 705 |  | 
 | 706 |             TrackInfo *info = &mTracks.editItemAt(trackIndex); | 
 | 707 |             info->mRTPTime = rtpTime; | 
 | 708 |             info->mNormalPlaytimeUs = nptUs; | 
 | 709 |             info->mNPTMappingValid = true; | 
 | 710 |             break; | 
 | 711 |         } | 
 | 712 |  | 
 | 713 |         case SDPLoader::kWhatSDPLoaded: | 
 | 714 |         { | 
 | 715 |             onSDPLoaded(msg); | 
 | 716 |             break; | 
 | 717 |         } | 
 | 718 |  | 
 | 719 |         default: | 
 | 720 |             TRESPASS(); | 
 | 721 |     } | 
 | 722 | } | 
 | 723 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 724 | void NuPlayer2::RTSPSource2::onConnected() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 725 |     CHECK(mAudioTrack == NULL); | 
 | 726 |     CHECK(mVideoTrack == NULL); | 
 | 727 |  | 
 | 728 |     size_t numTracks = mHandler->countTracks(); | 
 | 729 |     for (size_t i = 0; i < numTracks; ++i) { | 
 | 730 |         int32_t timeScale; | 
 | 731 |         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); | 
 | 732 |  | 
 | 733 |         const char *mime; | 
 | 734 |         CHECK(format->findCString(kKeyMIMEType, &mime)); | 
 | 735 |  | 
 | 736 |         if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { | 
 | 737 |             // Very special case for MPEG2 Transport Streams. | 
 | 738 |             CHECK_EQ(numTracks, 1u); | 
 | 739 |  | 
 | 740 |             mTSParser = new ATSParser; | 
 | 741 |             return; | 
 | 742 |         } | 
 | 743 |  | 
 | 744 |         bool isAudio = !strncasecmp(mime, "audio/", 6); | 
 | 745 |         bool isVideo = !strncasecmp(mime, "video/", 6); | 
 | 746 |  | 
 | 747 |         TrackInfo info; | 
 | 748 |         info.mTimeScale = timeScale; | 
 | 749 |         info.mRTPTime = 0; | 
 | 750 |         info.mNormalPlaytimeUs = 0ll; | 
 | 751 |         info.mNPTMappingValid = false; | 
 | 752 |  | 
 | 753 |         if ((isAudio && mAudioTrack == NULL) | 
 | 754 |                 || (isVideo && mVideoTrack == NULL)) { | 
 | 755 |             sp<AnotherPacketSource> source = new AnotherPacketSource(format); | 
 | 756 |  | 
 | 757 |             if (isAudio) { | 
 | 758 |                 mAudioTrack = source; | 
 | 759 |             } else { | 
 | 760 |                 mVideoTrack = source; | 
 | 761 |             } | 
 | 762 |  | 
 | 763 |             info.mSource = source; | 
 | 764 |         } | 
 | 765 |  | 
 | 766 |         mTracks.push(info); | 
 | 767 |     } | 
 | 768 |  | 
 | 769 |     mState = CONNECTED; | 
 | 770 | } | 
 | 771 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 772 | void NuPlayer2::RTSPSource2::onSDPLoaded(const sp<AMessage> &msg) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 773 |     status_t err; | 
 | 774 |     CHECK(msg->findInt32("result", &err)); | 
 | 775 |  | 
 | 776 |     mSDPLoader.clear(); | 
 | 777 |  | 
 | 778 |     if (mDisconnectReplyID != 0) { | 
 | 779 |         err = UNKNOWN_ERROR; | 
 | 780 |     } | 
 | 781 |  | 
 | 782 |     if (err == OK) { | 
 | 783 |         sp<ASessionDescription> desc; | 
 | 784 |         sp<RefBase> obj; | 
 | 785 |         CHECK(msg->findObject("description", &obj)); | 
 | 786 |         desc = static_cast<ASessionDescription *>(obj.get()); | 
 | 787 |  | 
 | 788 |         AString rtspUri; | 
 | 789 |         if (!desc->findAttribute(0, "a=control", &rtspUri)) { | 
 | 790 |             ALOGE("Unable to find url in SDP"); | 
 | 791 |             err = UNKNOWN_ERROR; | 
 | 792 |         } else { | 
 | 793 |             sp<AMessage> notify = new AMessage(kWhatNotify, this); | 
 | 794 |  | 
| Wei Jia | 003fdb5 | 2018-02-06 14:44:32 -0800 | [diff] [blame] | 795 |             mHandler = new MyHandler(rtspUri.c_str(), notify, true /* uidValid */, mUID); | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 796 |             mLooper->registerHandler(mHandler); | 
 | 797 |  | 
 | 798 |             mHandler->loadSDP(desc); | 
 | 799 |         } | 
 | 800 |     } | 
 | 801 |  | 
 | 802 |     if (err != OK) { | 
 | 803 |         if (mState == CONNECTING) { | 
 | 804 |             // We're still in the preparation phase, signal that it | 
 | 805 |             // failed. | 
 | 806 |             notifyPrepared(err); | 
 | 807 |         } | 
 | 808 |  | 
 | 809 |         mState = DISCONNECTED; | 
 | 810 |         setError(err); | 
 | 811 |  | 
 | 812 |         if (mDisconnectReplyID != 0) { | 
 | 813 |             finishDisconnectIfPossible(); | 
 | 814 |         } | 
 | 815 |     } | 
 | 816 | } | 
 | 817 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 818 | void NuPlayer2::RTSPSource2::onDisconnected(const sp<AMessage> &msg) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 819 |     if (mState == DISCONNECTED) { | 
 | 820 |         return; | 
 | 821 |     } | 
 | 822 |  | 
 | 823 |     status_t err; | 
 | 824 |     CHECK(msg->findInt32("result", &err)); | 
 | 825 |     CHECK_NE(err, (status_t)OK); | 
 | 826 |  | 
 | 827 |     mLooper->unregisterHandler(mHandler->id()); | 
 | 828 |     mHandler.clear(); | 
 | 829 |  | 
 | 830 |     if (mState == CONNECTING) { | 
 | 831 |         // We're still in the preparation phase, signal that it | 
 | 832 |         // failed. | 
 | 833 |         notifyPrepared(err); | 
 | 834 |     } | 
 | 835 |  | 
 | 836 |     mState = DISCONNECTED; | 
 | 837 |     setError(err); | 
 | 838 |  | 
 | 839 |     if (mDisconnectReplyID != 0) { | 
 | 840 |         finishDisconnectIfPossible(); | 
 | 841 |     } | 
 | 842 | } | 
 | 843 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 844 | void NuPlayer2::RTSPSource2::finishDisconnectIfPossible() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 845 |     if (mState != DISCONNECTED) { | 
 | 846 |         if (mHandler != NULL) { | 
 | 847 |             mHandler->disconnect(); | 
 | 848 |         } else if (mSDPLoader != NULL) { | 
 | 849 |             mSDPLoader->cancel(); | 
 | 850 |         } | 
 | 851 |         return; | 
 | 852 |     } | 
 | 853 |  | 
 | 854 |     (new AMessage)->postReply(mDisconnectReplyID); | 
 | 855 |     mDisconnectReplyID = 0; | 
 | 856 | } | 
 | 857 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 858 | void NuPlayer2::RTSPSource2::setError(status_t err) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 859 |     Mutex::Autolock _l(mBufferingLock); | 
 | 860 |     mFinalResult = err; | 
 | 861 | } | 
 | 862 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 863 | void NuPlayer2::RTSPSource2::startBufferingIfNecessary() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 864 |     Mutex::Autolock _l(mBufferingLock); | 
 | 865 |  | 
 | 866 |     if (!mBuffering) { | 
 | 867 |         mBuffering = true; | 
 | 868 |  | 
 | 869 |         sp<AMessage> notify = dupNotify(); | 
 | 870 |         notify->setInt32("what", kWhatPauseOnBufferingStart); | 
 | 871 |         notify->post(); | 
 | 872 |     } | 
 | 873 | } | 
 | 874 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 875 | bool NuPlayer2::RTSPSource2::stopBufferingIfNecessary() { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 876 |     Mutex::Autolock _l(mBufferingLock); | 
 | 877 |  | 
 | 878 |     if (mBuffering) { | 
 | 879 |         if (!haveSufficientDataOnAllTracks()) { | 
 | 880 |             return false; | 
 | 881 |         } | 
 | 882 |  | 
 | 883 |         mBuffering = false; | 
 | 884 |  | 
 | 885 |         sp<AMessage> notify = dupNotify(); | 
 | 886 |         notify->setInt32("what", kWhatResumeOnBufferingEnd); | 
 | 887 |         notify->post(); | 
 | 888 |     } | 
 | 889 |  | 
 | 890 |     return true; | 
 | 891 | } | 
 | 892 |  | 
| Wei Jia | 2409c87 | 2018-02-02 10:34:33 -0800 | [diff] [blame] | 893 | void NuPlayer2::RTSPSource2::finishSeek(status_t err) { | 
| Wei Jia | 53692fa | 2017-12-11 10:33:46 -0800 | [diff] [blame] | 894 |     if (mSeekReplyID == NULL) { | 
 | 895 |         return; | 
 | 896 |     } | 
 | 897 |     sp<AMessage> seekReply = new AMessage; | 
 | 898 |     seekReply->setInt32("err", err); | 
 | 899 |     seekReply->postReply(mSeekReplyID); | 
 | 900 |     mSeekReplyID = NULL; | 
 | 901 | } | 
 | 902 |  | 
 | 903 | }  // namespace android |