RTSPSource.cpp revision f6f0f0e313f4d4dc7035e842270cd31303bd91e7
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
26#include <media/stagefright/MediaDefs.h>
27#include <media/stagefright/MetaData.h>
28
29namespace android {
30
31NuPlayer::RTSPSource::RTSPSource(
32        const char *url,
33        const KeyedVector<String8, String8> *headers,
34        bool uidValid,
35        uid_t uid)
36    : mURL(url),
37      mUIDValid(uidValid),
38      mUID(uid),
39      mFlags(0),
40      mState(DISCONNECTED),
41      mFinalResult(OK),
42      mDisconnectReplyID(0),
43      mStartingUp(true),
44      mSeekGeneration(0) {
45    if (headers) {
46        mExtraHeaders = *headers;
47
48        ssize_t index =
49            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
50
51        if (index >= 0) {
52            mFlags |= kFlagIncognito;
53
54            mExtraHeaders.removeItemsAt(index);
55        }
56    }
57}
58
59NuPlayer::RTSPSource::~RTSPSource() {
60   mLooper->stop();
61}
62
63void NuPlayer::RTSPSource::start() {
64    if (mLooper == NULL) {
65        mLooper = new ALooper;
66        mLooper->setName("rtsp");
67        mLooper->start();
68
69        mReflector = new AHandlerReflector<RTSPSource>(this);
70        mLooper->registerHandler(mReflector);
71    }
72
73    CHECK(mHandler == NULL);
74
75    sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
76
77    mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
78    mLooper->registerHandler(mHandler);
79
80    CHECK_EQ(mState, (int)DISCONNECTED);
81    mState = CONNECTING;
82
83    mHandler->connect();
84}
85
86void NuPlayer::RTSPSource::stop() {
87    if (mLooper == NULL) {
88        return;
89    }
90    sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
91
92    sp<AMessage> dummy;
93    msg->postAndAwaitResponse(&dummy);
94}
95
96status_t NuPlayer::RTSPSource::feedMoreTSData() {
97    return mFinalResult;
98}
99
100sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
101    sp<AnotherPacketSource> source = getSource(audio);
102
103    if (source == NULL) {
104        return NULL;
105    }
106
107    return source->getFormat();
108}
109
110bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
111    // We're going to buffer at least 2 secs worth data on all tracks before
112    // starting playback (both at startup and after a seek).
113
114    static const int64_t kMinDurationUs = 2000000ll;
115
116    status_t err;
117    int64_t durationUs;
118    if (mAudioTrack != NULL
119            && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
120                    < kMinDurationUs
121            && err == OK) {
122        ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
123              durationUs / 1E6);
124        return false;
125    }
126
127    if (mVideoTrack != NULL
128            && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
129                    < kMinDurationUs
130            && err == OK) {
131        ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
132              durationUs / 1E6);
133        return false;
134    }
135
136    return true;
137}
138
139status_t NuPlayer::RTSPSource::dequeueAccessUnit(
140        bool audio, sp<ABuffer> *accessUnit) {
141    if (mStartingUp) {
142        if (!haveSufficientDataOnAllTracks()) {
143            return -EWOULDBLOCK;
144        }
145
146        mStartingUp = false;
147    }
148
149    sp<AnotherPacketSource> source = getSource(audio);
150
151    if (source == NULL) {
152        return -EWOULDBLOCK;
153    }
154
155    status_t finalResult;
156    if (!source->hasBufferAvailable(&finalResult)) {
157        return finalResult == OK ? -EWOULDBLOCK : finalResult;
158    }
159
160    return source->dequeueAccessUnit(accessUnit);
161}
162
163sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
164    if (mTSParser != NULL) {
165        sp<MediaSource> source = mTSParser->getSource(
166                audio ? ATSParser::AUDIO : ATSParser::VIDEO);
167
168        return static_cast<AnotherPacketSource *>(source.get());
169    }
170
171    return audio ? mAudioTrack : mVideoTrack;
172}
173
174status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
175    *durationUs = 0ll;
176
177    int64_t audioDurationUs;
178    if (mAudioTrack != NULL
179            && mAudioTrack->getFormat()->findInt64(
180                kKeyDuration, &audioDurationUs)
181            && audioDurationUs > *durationUs) {
182        *durationUs = audioDurationUs;
183    }
184
185    int64_t videoDurationUs;
186    if (mVideoTrack != NULL
187            && mVideoTrack->getFormat()->findInt64(
188                kKeyDuration, &videoDurationUs)
189            && videoDurationUs > *durationUs) {
190        *durationUs = videoDurationUs;
191    }
192
193    return OK;
194}
195
196status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
197    sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
198    msg->setInt32("generation", ++mSeekGeneration);
199    msg->setInt64("timeUs", seekTimeUs);
200    msg->post(200000ll);
201
202    return OK;
203}
204
205void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
206    if (mState != CONNECTED) {
207        return;
208    }
209
210    mState = SEEKING;
211    mHandler->seek(seekTimeUs);
212}
213
214bool NuPlayer::RTSPSource::isSeekable() {
215    return true;
216}
217
218void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
219    if (msg->what() == kWhatDisconnect) {
220        uint32_t replyID;
221        CHECK(msg->senderAwaitsResponse(&replyID));
222
223        mDisconnectReplyID = replyID;
224        finishDisconnectIfPossible();
225        return;
226    } else if (msg->what() == kWhatPerformSeek) {
227        int32_t generation;
228        CHECK(msg->findInt32("generation", &generation));
229
230        if (generation != mSeekGeneration) {
231            // obsolete.
232            return;
233        }
234
235        int64_t seekTimeUs;
236        CHECK(msg->findInt64("timeUs", &seekTimeUs));
237
238        performSeek(seekTimeUs);
239        return;
240    }
241
242    CHECK_EQ(msg->what(), (int)kWhatNotify);
243
244    int32_t what;
245    CHECK(msg->findInt32("what", &what));
246
247    switch (what) {
248        case MyHandler::kWhatConnected:
249            onConnected();
250            break;
251
252        case MyHandler::kWhatDisconnected:
253            onDisconnected(msg);
254            break;
255
256        case MyHandler::kWhatSeekDone:
257        {
258            mState = CONNECTED;
259            mStartingUp = true;
260            break;
261        }
262
263        case MyHandler::kWhatAccessUnit:
264        {
265            size_t trackIndex;
266            CHECK(msg->findSize("trackIndex", &trackIndex));
267
268            if (mTSParser == NULL) {
269                CHECK_LT(trackIndex, mTracks.size());
270            } else {
271                CHECK_EQ(trackIndex, 0u);
272            }
273
274            sp<ABuffer> accessUnit;
275            CHECK(msg->findBuffer("accessUnit", &accessUnit));
276
277            int32_t damaged;
278            if (accessUnit->meta()->findInt32("damaged", &damaged)
279                    && damaged) {
280                ALOGI("dropping damaged access unit.");
281                break;
282            }
283
284            if (mTSParser != NULL) {
285                size_t offset = 0;
286                status_t err = OK;
287                while (offset + 188 <= accessUnit->size()) {
288                    err = mTSParser->feedTSPacket(
289                            accessUnit->data() + offset, 188);
290                    if (err != OK) {
291                        break;
292                    }
293
294                    offset += 188;
295                }
296
297                if (offset < accessUnit->size()) {
298                    err = ERROR_MALFORMED;
299                }
300
301                if (err != OK) {
302                    sp<AnotherPacketSource> source = getSource(false /* audio */);
303                    if (source != NULL) {
304                        source->signalEOS(err);
305                    }
306
307                    source = getSource(true /* audio */);
308                    if (source != NULL) {
309                        source->signalEOS(err);
310                    }
311                }
312                break;
313            }
314
315            TrackInfo *info = &mTracks.editItemAt(trackIndex);
316
317            sp<AnotherPacketSource> source = info->mSource;
318            if (source != NULL) {
319                uint32_t rtpTime;
320                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
321
322                if (!info->mNPTMappingValid) {
323                    // This is a live stream, we didn't receive any normal
324                    // playtime mapping. We won't map to npt time.
325                    source->queueAccessUnit(accessUnit);
326                    break;
327                }
328
329                int64_t nptUs =
330                    ((double)rtpTime - (double)info->mRTPTime)
331                        / info->mTimeScale
332                        * 1000000ll
333                        + info->mNormalPlaytimeUs;
334
335                accessUnit->meta()->setInt64("timeUs", nptUs);
336
337                source->queueAccessUnit(accessUnit);
338            }
339            break;
340        }
341
342        case MyHandler::kWhatEOS:
343        {
344            int32_t finalResult;
345            CHECK(msg->findInt32("finalResult", &finalResult));
346            CHECK_NE(finalResult, (status_t)OK);
347
348            if (mTSParser != NULL) {
349                sp<AnotherPacketSource> source = getSource(false /* audio */);
350                if (source != NULL) {
351                    source->signalEOS(finalResult);
352                }
353
354                source = getSource(true /* audio */);
355                if (source != NULL) {
356                    source->signalEOS(finalResult);
357                }
358
359                return;
360            }
361
362            size_t trackIndex;
363            CHECK(msg->findSize("trackIndex", &trackIndex));
364            CHECK_LT(trackIndex, mTracks.size());
365
366            TrackInfo *info = &mTracks.editItemAt(trackIndex);
367            sp<AnotherPacketSource> source = info->mSource;
368            if (source != NULL) {
369                source->signalEOS(finalResult);
370            }
371
372            break;
373        }
374
375        case MyHandler::kWhatSeekDiscontinuity:
376        {
377            size_t trackIndex;
378            CHECK(msg->findSize("trackIndex", &trackIndex));
379            CHECK_LT(trackIndex, mTracks.size());
380
381            TrackInfo *info = &mTracks.editItemAt(trackIndex);
382            sp<AnotherPacketSource> source = info->mSource;
383            if (source != NULL) {
384                source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
385            }
386
387            break;
388        }
389
390        case MyHandler::kWhatNormalPlayTimeMapping:
391        {
392            size_t trackIndex;
393            CHECK(msg->findSize("trackIndex", &trackIndex));
394            CHECK_LT(trackIndex, mTracks.size());
395
396            uint32_t rtpTime;
397            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
398
399            int64_t nptUs;
400            CHECK(msg->findInt64("nptUs", &nptUs));
401
402            TrackInfo *info = &mTracks.editItemAt(trackIndex);
403            info->mRTPTime = rtpTime;
404            info->mNormalPlaytimeUs = nptUs;
405            info->mNPTMappingValid = true;
406            break;
407        }
408
409        default:
410            TRESPASS();
411    }
412}
413
414void NuPlayer::RTSPSource::onConnected() {
415    CHECK(mAudioTrack == NULL);
416    CHECK(mVideoTrack == NULL);
417
418    size_t numTracks = mHandler->countTracks();
419    for (size_t i = 0; i < numTracks; ++i) {
420        int32_t timeScale;
421        sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
422
423        const char *mime;
424        CHECK(format->findCString(kKeyMIMEType, &mime));
425
426        if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
427            // Very special case for MPEG2 Transport Streams.
428            CHECK_EQ(numTracks, 1u);
429
430            mTSParser = new ATSParser;
431            return;
432        }
433
434        bool isAudio = !strncasecmp(mime, "audio/", 6);
435        bool isVideo = !strncasecmp(mime, "video/", 6);
436
437        TrackInfo info;
438        info.mTimeScale = timeScale;
439        info.mRTPTime = 0;
440        info.mNormalPlaytimeUs = 0ll;
441        info.mNPTMappingValid = false;
442
443        if ((isAudio && mAudioTrack == NULL)
444                || (isVideo && mVideoTrack == NULL)) {
445            sp<AnotherPacketSource> source = new AnotherPacketSource(format);
446
447            if (isAudio) {
448                mAudioTrack = source;
449            } else {
450                mVideoTrack = source;
451            }
452
453            info.mSource = source;
454        }
455
456        mTracks.push(info);
457    }
458
459    mState = CONNECTED;
460}
461
462void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
463    status_t err;
464    CHECK(msg->findInt32("result", &err));
465    CHECK_NE(err, (status_t)OK);
466
467    mLooper->unregisterHandler(mHandler->id());
468    mHandler.clear();
469
470    mState = DISCONNECTED;
471    mFinalResult = err;
472
473    if (mDisconnectReplyID != 0) {
474        finishDisconnectIfPossible();
475    }
476}
477
478void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
479    if (mState != DISCONNECTED) {
480        mHandler->disconnect();
481        return;
482    }
483
484    (new AMessage)->postReply(mDisconnectReplyID);
485    mDisconnectReplyID = 0;
486}
487
488}  // namespace android
489