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