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