HTTPLiveSource.cpp revision 1b86fe063badb5f28c467ade39be0f4008688947
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 "AnotherPacketSource.h"
24#include "LiveDataSource.h"
25#include "LiveSession.h"
26
27#include <media/IMediaHTTPService.h>
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 sp<IMediaHTTPService> &httpService,
39        const char *url,
40        const KeyedVector<String8, String8> *headers,
41        bool uidValid, uid_t uid)
42    : Source(notify),
43      mHTTPService(httpService),
44      mURL(url),
45      mUIDValid(uidValid),
46      mUID(uid),
47      mFlags(0),
48      mFinalResult(OK),
49      mOffset(0),
50      mFetchSubtitleDataGeneration(0) {
51    if (headers) {
52        mExtraHeaders = *headers;
53
54        ssize_t index =
55            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
56
57        if (index >= 0) {
58            mFlags |= kFlagIncognito;
59
60            mExtraHeaders.removeItemsAt(index);
61        }
62    }
63}
64
65NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
66    if (mLiveSession != NULL) {
67        mLiveSession->disconnect();
68        mLiveSession.clear();
69
70        mLiveLooper->stop();
71        mLiveLooper.clear();
72    }
73}
74
75void NuPlayer::HTTPLiveSource::prepareAsync() {
76    mLiveLooper = new ALooper;
77    mLiveLooper->setName("http live");
78    mLiveLooper->start();
79
80    sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
81
82    mLiveSession = new LiveSession(
83            notify,
84            (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
85            mHTTPService,
86            mUIDValid,
87            mUID);
88
89    mLiveLooper->registerHandler(mLiveSession);
90
91    mLiveSession->connectAsync(
92            mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
93}
94
95void NuPlayer::HTTPLiveSource::start() {
96}
97
98sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
99    sp<AMessage> format;
100    status_t err = mLiveSession->getStreamFormat(
101            audio ? LiveSession::STREAMTYPE_AUDIO
102                  : LiveSession::STREAMTYPE_VIDEO,
103            &format);
104
105    if (err != OK) {
106        return NULL;
107    }
108
109    return format;
110}
111
112status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
113    return OK;
114}
115
116status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
117        bool audio, sp<ABuffer> *accessUnit) {
118    return mLiveSession->dequeueAccessUnit(
119            audio ? LiveSession::STREAMTYPE_AUDIO
120                  : LiveSession::STREAMTYPE_VIDEO,
121            accessUnit);
122}
123
124status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
125    return mLiveSession->getDuration(durationUs);
126}
127
128status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
129    return mLiveSession->getTrackInfo(reply);
130}
131
132status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
133    status_t err = mLiveSession->selectTrack(trackIndex, select);
134
135    if (err == OK) {
136        mFetchSubtitleDataGeneration++;
137        if (select) {
138            sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
139            msg->setInt32("generation", mFetchSubtitleDataGeneration);
140            msg->post();
141        }
142    }
143
144    // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
145    // selected track, or unselecting a non-selected track. In this case it's an
146    // no-op so we return OK.
147    return (err == OK || err == BAD_VALUE) ? OK : err;
148}
149
150status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
151    return mLiveSession->seekTo(seekTimeUs);
152}
153
154void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
155    switch (msg->what()) {
156        case kWhatSessionNotify:
157        {
158            onSessionNotify(msg);
159            break;
160        }
161
162        case kWhatFetchSubtitleData:
163        {
164            int32_t generation;
165            CHECK(msg->findInt32("generation", &generation));
166
167            if (generation != mFetchSubtitleDataGeneration) {
168                // stale
169                break;
170            }
171
172            sp<ABuffer> buffer;
173            if (mLiveSession->dequeueAccessUnit(
174                    LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) {
175                sp<AMessage> notify = dupNotify();
176                notify->setInt32("what", kWhatSubtitleData);
177                notify->setBuffer("buffer", buffer);
178                notify->post();
179
180                int64_t timeUs, baseUs, durationUs, delayUs;
181                CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
182                CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
183                CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
184                delayUs = baseUs + timeUs - ALooper::GetNowUs();
185
186                msg->post(delayUs > 0ll ? delayUs : 0ll);
187            } else {
188                // try again in 1 second
189                msg->post(1000000ll);
190            }
191
192            break;
193        }
194
195        default:
196            Source::onMessageReceived(msg);
197            break;
198    }
199}
200
201void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
202    int32_t what;
203    CHECK(msg->findInt32("what", &what));
204
205    switch (what) {
206        case LiveSession::kWhatPrepared:
207        {
208            // notify the current size here if we have it, otherwise report an initial size of (0,0)
209            sp<AMessage> format = getFormat(false /* audio */);
210            int32_t width;
211            int32_t height;
212            if (format != NULL &&
213                    format->findInt32("width", &width) && format->findInt32("height", &height)) {
214                notifyVideoSizeChanged(width, height);
215            } else {
216                notifyVideoSizeChanged(0, 0);
217            }
218
219            uint32_t flags = FLAG_CAN_PAUSE;
220            if (mLiveSession->isSeekable()) {
221                flags |= FLAG_CAN_SEEK;
222                flags |= FLAG_CAN_SEEK_BACKWARD;
223                flags |= FLAG_CAN_SEEK_FORWARD;
224            }
225
226            if (mLiveSession->hasDynamicDuration()) {
227                flags |= FLAG_DYNAMIC_DURATION;
228            }
229
230            notifyFlagsChanged(flags);
231
232            notifyPrepared();
233            break;
234        }
235
236        case LiveSession::kWhatPreparationFailed:
237        {
238            status_t err;
239            CHECK(msg->findInt32("err", &err));
240
241            notifyPrepared(err);
242            break;
243        }
244
245        case LiveSession::kWhatStreamsChanged:
246        {
247            uint32_t changedMask;
248            CHECK(msg->findInt32(
249                        "changedMask", (int32_t *)&changedMask));
250
251            bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
252            bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
253
254            sp<AMessage> reply;
255            CHECK(msg->findMessage("reply", &reply));
256
257            sp<AMessage> notify = dupNotify();
258            notify->setInt32("what", kWhatQueueDecoderShutdown);
259            notify->setInt32("audio", audio);
260            notify->setInt32("video", video);
261            notify->setMessage("reply", reply);
262            notify->post();
263            break;
264        }
265
266        case LiveSession::kWhatError:
267        {
268            break;
269        }
270
271        default:
272            TRESPASS();
273    }
274}
275
276}  // namespace android
277
278