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