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