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