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