HTTPLiveSource.cpp revision 0df36ec3303c2c6bf9b42c07945ac8bd234153f3
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 "HTTPLiveSource"
19#include <utils/Log.h>
20
21#include "HTTPLiveSource.h"
22
23#include "ATSParser.h"
24#include "AnotherPacketSource.h"
25#include "LiveDataSource.h"
26#include "LiveSession.h"
27
28#include <media/stagefright/foundation/ABuffer.h>
29#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MetaData.h>
33
34namespace android {
35
36NuPlayer::HTTPLiveSource::HTTPLiveSource(
37        const sp<AMessage> &notify,
38        const char *url,
39        const KeyedVector<String8, String8> *headers,
40        bool uidValid, uid_t uid)
41    : Source(notify),
42      mURL(url),
43      mUIDValid(uidValid),
44      mUID(uid),
45      mFlags(0),
46      mFinalResult(OK),
47      mOffset(0) {
48    if (headers) {
49        mExtraHeaders = *headers;
50
51        ssize_t index =
52            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
53
54        if (index >= 0) {
55            mFlags |= kFlagIncognito;
56
57            mExtraHeaders.removeItemsAt(index);
58        }
59    }
60}
61
62NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
63    if (mLiveSession != NULL) {
64        mLiveSession->disconnect();
65        mLiveLooper->stop();
66    }
67}
68
69void NuPlayer::HTTPLiveSource::prepareAsync() {
70    mLiveLooper = new ALooper;
71    mLiveLooper->setName("http live");
72    mLiveLooper->start();
73
74    sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
75
76    mLiveSession = new LiveSession(
77            notify,
78            (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
79            mUIDValid, mUID);
80
81    mLiveLooper->registerHandler(mLiveSession);
82
83    mLiveSession->connect(
84            mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
85
86    mTSParser = new ATSParser;
87}
88
89void NuPlayer::HTTPLiveSource::start() {
90}
91
92sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
93    ATSParser::SourceType type =
94        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
95
96    sp<AnotherPacketSource> source =
97        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
98
99    if (source == NULL) {
100        return NULL;
101    }
102
103    return source->getFormat();
104}
105
106status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
107    if (mFinalResult != OK) {
108        return mFinalResult;
109    }
110
111    sp<LiveDataSource> source =
112        static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());
113
114    for (int32_t i = 0; i < 50; ++i) {
115        char buffer[188];
116        ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));
117
118        if (n == -EWOULDBLOCK) {
119            break;
120        } else if (n < 0) {
121            if (n != ERROR_END_OF_STREAM) {
122                ALOGI("input data EOS reached, error %ld", n);
123            } else {
124                ALOGI("input data EOS reached.");
125            }
126            mTSParser->signalEOS(n);
127            mFinalResult = n;
128            break;
129        } else {
130            if (buffer[0] == 0x00) {
131                // XXX legacy
132
133                uint8_t type = buffer[1];
134
135                sp<AMessage> extra = new AMessage;
136
137                if (type & 2) {
138                    int64_t mediaTimeUs;
139                    memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
140
141                    extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
142                }
143
144                mTSParser->signalDiscontinuity(
145                        ((type & 1) == 0)
146                            ? ATSParser::DISCONTINUITY_SEEK
147                            : ATSParser::DISCONTINUITY_FORMATCHANGE,
148                        extra);
149            } else {
150                status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
151
152                if (err != OK) {
153                    ALOGE("TS Parser returned error %d", err);
154                    mTSParser->signalEOS(err);
155                    mFinalResult = err;
156                    break;
157                }
158            }
159
160            mOffset += n;
161        }
162    }
163
164    return OK;
165}
166
167status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
168        bool audio, sp<ABuffer> *accessUnit) {
169    ATSParser::SourceType type =
170        audio ? ATSParser::AUDIO : ATSParser::VIDEO;
171
172    sp<AnotherPacketSource> source =
173        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
174
175    if (source == NULL) {
176        return -EWOULDBLOCK;
177    }
178
179    status_t finalResult;
180    if (!source->hasBufferAvailable(&finalResult)) {
181        return finalResult == OK ? -EWOULDBLOCK : finalResult;
182    }
183
184    return source->dequeueAccessUnit(accessUnit);
185}
186
187status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
188    return mLiveSession->getDuration(durationUs);
189}
190
191status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
192    // We need to make sure we're not seeking until we have seen the very first
193    // PTS timestamp in the whole stream (from the beginning of the stream).
194    while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) {
195        usleep(100000);
196    }
197
198    mLiveSession->seekTo(seekTimeUs);
199
200    return OK;
201}
202
203void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
204    switch (msg->what()) {
205        case kWhatSessionNotify:
206        {
207            onSessionNotify(msg);
208            break;
209        }
210
211        default:
212            Source::onMessageReceived(msg);
213            break;
214    }
215}
216
217void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
218    int32_t what;
219    CHECK(msg->findInt32("what", &what));
220
221    switch (what) {
222        case LiveSession::kWhatPrepared:
223        {
224            notifyVideoSizeChanged(0, 0);
225
226            uint32_t flags = FLAG_CAN_PAUSE;
227            if (mLiveSession->isSeekable()) {
228                flags |= FLAG_CAN_SEEK;
229                flags |= FLAG_CAN_SEEK_BACKWARD;
230                flags |= FLAG_CAN_SEEK_FORWARD;
231            }
232
233            if (mLiveSession->hasDynamicDuration()) {
234                flags |= FLAG_DYNAMIC_DURATION;
235            }
236
237            notifyFlagsChanged(flags);
238
239            notifyPrepared();
240            break;
241        }
242
243        case LiveSession::kWhatPreparationFailed:
244        {
245            status_t err;
246            CHECK(msg->findInt32("err", &err));
247
248            notifyPrepared(err);
249            break;
250        }
251
252        default:
253            TRESPASS();
254    }
255}
256
257}  // namespace android
258
259