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> ¬ify,
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