HTTPLiveSource.cpp revision 48fa06d1e80a872c7495804979256e021e566ae0
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
26#include <media/IMediaHTTPService.h>
27#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/AMessage.h>
30#include <media/stagefright/MediaErrors.h>
31#include <media/stagefright/MetaData.h>
32#include <media/stagefright/MediaDefs.h>
33#include <media/stagefright/Utils.h>
34
35// default buffer prepare/ready/underflow marks
36static const int kReadyMarkMs     = 5000;  // 5 seconds
37static const int kPrepareMarkMs   = 1500;  // 1.5 seconds
38static const int kUnderflowMarkMs = 1000;  // 1 second
39
40namespace android {
41
42NuPlayer::HTTPLiveSource::HTTPLiveSource(
43        const sp<AMessage> &notify,
44        const sp<IMediaHTTPService> &httpService,
45        const char *url,
46        const KeyedVector<String8, String8> *headers)
47    : Source(notify),
48      mHTTPService(httpService),
49      mURL(url),
50      mFlags(0),
51      mFinalResult(OK),
52      mOffset(0),
53      mFetchSubtitleDataGeneration(0),
54      mFetchMetaDataGeneration(0),
55      mHasMetadata(false),
56      mMetadataSelected(false) {
57    getDefaultBufferingSettings(&mBufferingSettings);
58    if (headers) {
59        mExtraHeaders = *headers;
60
61        ssize_t index =
62            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
63
64        if (index >= 0) {
65            mFlags |= kFlagIncognito;
66
67            mExtraHeaders.removeItemsAt(index);
68        }
69    }
70}
71
72NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
73    if (mLiveSession != NULL) {
74        mLiveSession->disconnect();
75
76        mLiveLooper->unregisterHandler(mLiveSession->id());
77        mLiveLooper->unregisterHandler(id());
78        mLiveLooper->stop();
79
80        mLiveSession.clear();
81        mLiveLooper.clear();
82    }
83}
84
85status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings(
86            BufferingSettings* buffering /* nonnull */) {
87    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
88    buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
89    buffering->mInitialWatermarkMs = kPrepareMarkMs;
90    buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
91    buffering->mRebufferingWatermarkHighMs = kReadyMarkMs;
92
93    return OK;
94}
95
96status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) {
97    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
98            || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
99            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
100                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
101        return BAD_VALUE;
102    }
103
104    mBufferingSettings = buffering;
105
106    if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
107        mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
108    }
109    if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
110        mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
111        mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
112    }
113
114    if (mLiveSession != NULL) {
115        mLiveSession->setBufferingSettings(mBufferingSettings);
116    }
117
118    return OK;
119}
120
121void NuPlayer::HTTPLiveSource::prepareAsync() {
122    if (mLiveLooper == NULL) {
123        mLiveLooper = new ALooper;
124        mLiveLooper->setName("http live");
125        mLiveLooper->start();
126
127        mLiveLooper->registerHandler(this);
128    }
129
130    sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
131
132    mLiveSession = new LiveSession(
133            notify,
134            (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
135            mHTTPService);
136
137    mLiveLooper->registerHandler(mLiveSession);
138
139    mLiveSession->setBufferingSettings(mBufferingSettings);
140    mLiveSession->connectAsync(
141            mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
142}
143
144void NuPlayer::HTTPLiveSource::start() {
145}
146
147sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
148    sp<MetaData> meta;
149    if (mLiveSession != NULL) {
150        mLiveSession->getStreamFormatMeta(
151                audio ? LiveSession::STREAMTYPE_AUDIO
152                      : LiveSession::STREAMTYPE_VIDEO,
153                &meta);
154    }
155
156    return meta;
157}
158
159sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
160    sp<MetaData> meta;
161    status_t err = -EWOULDBLOCK;
162    if (mLiveSession != NULL) {
163        err = mLiveSession->getStreamFormatMeta(
164                audio ? LiveSession::STREAMTYPE_AUDIO
165                      : LiveSession::STREAMTYPE_VIDEO,
166                &meta);
167    }
168
169    sp<AMessage> format;
170    if (err == -EWOULDBLOCK) {
171        format = new AMessage();
172        format->setInt32("err", err);
173        return format;
174    }
175
176    if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
177        return NULL;
178    }
179    return format;
180}
181
182status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
183    return OK;
184}
185
186status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
187        bool audio, sp<ABuffer> *accessUnit) {
188    return mLiveSession->dequeueAccessUnit(
189            audio ? LiveSession::STREAMTYPE_AUDIO
190                  : LiveSession::STREAMTYPE_VIDEO,
191            accessUnit);
192}
193
194status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
195    return mLiveSession->getDuration(durationUs);
196}
197
198size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
199    return mLiveSession->getTrackCount();
200}
201
202sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
203    return mLiveSession->getTrackInfo(trackIndex);
204}
205
206ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const {
207    if (mLiveSession == NULL) {
208        return -1;
209    } else if (type == MEDIA_TRACK_TYPE_METADATA) {
210        // MEDIA_TRACK_TYPE_METADATA is always last track
211        // mMetadataSelected can only be true when mHasMetadata is true
212        return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1;
213    } else {
214        return mLiveSession->getSelectedTrack(type);
215    }
216}
217
218status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
219    if (mLiveSession == NULL) {
220        return INVALID_OPERATION;
221    }
222
223    status_t err = INVALID_OPERATION;
224    bool postFetchMsg = false, isSub = false;
225    if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
226        err = mLiveSession->selectTrack(trackIndex, select);
227        postFetchMsg = select;
228        isSub = true;
229    } else {
230        // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1)
231        if (mMetadataSelected && !select) {
232            err = OK;
233        } else if (!mMetadataSelected && select) {
234            postFetchMsg = true;
235            err = OK;
236        } else {
237            err = BAD_VALUE; // behave as LiveSession::selectTrack
238        }
239
240        mMetadataSelected = select;
241    }
242
243    if (err == OK) {
244        int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration;
245        generation++;
246        if (postFetchMsg) {
247            int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData;
248            sp<AMessage> msg = new AMessage(what, this);
249            msg->setInt32("generation", generation);
250            msg->post();
251        }
252    }
253
254    // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
255    // selected track, or unselecting a non-selected track. In this case it's an
256    // no-op so we return OK.
257    return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
258}
259
260status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
261    return mLiveSession->seekTo(seekTimeUs, mode);
262}
263
264void NuPlayer::HTTPLiveSource::pollForRawData(
265        const sp<AMessage> &msg, int32_t currentGeneration,
266        LiveSession::StreamType fetchType, int32_t pushWhat) {
267
268    int32_t generation;
269    CHECK(msg->findInt32("generation", &generation));
270
271    if (generation != currentGeneration) {
272        return;
273    }
274
275    sp<ABuffer> buffer;
276    while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
277
278        sp<AMessage> notify = dupNotify();
279        notify->setInt32("what", pushWhat);
280        notify->setBuffer("buffer", buffer);
281
282        int64_t timeUs, baseUs, delayUs;
283        CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
284        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
285        delayUs = baseUs + timeUs - ALooper::GetNowUs();
286
287        if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
288            notify->post();
289            msg->post(delayUs > 0ll ? delayUs : 0ll);
290            return;
291        } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
292            if (delayUs < -1000000ll) { // 1 second
293                continue;
294            }
295            notify->post();
296            // push all currently available metadata buffers in each invocation of pollForRawData
297            // continue;
298        } else {
299            TRESPASS();
300        }
301    }
302
303    // try again in 1 second
304    msg->post(1000000ll);
305}
306
307void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
308    switch (msg->what()) {
309        case kWhatSessionNotify:
310        {
311            onSessionNotify(msg);
312            break;
313        }
314
315        case kWhatFetchSubtitleData:
316        {
317            pollForRawData(
318                    msg, mFetchSubtitleDataGeneration,
319                    /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
320                    /* push */ kWhatSubtitleData);
321
322            break;
323        }
324
325        case kWhatFetchMetaData:
326        {
327            if (!mMetadataSelected) {
328                break;
329            }
330
331            pollForRawData(
332                    msg, mFetchMetaDataGeneration,
333                    /* fetch */ LiveSession::STREAMTYPE_METADATA,
334                    /* push */ kWhatTimedMetaData);
335
336            break;
337        }
338
339        default:
340            Source::onMessageReceived(msg);
341            break;
342    }
343}
344
345void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
346    int32_t what;
347    CHECK(msg->findInt32("what", &what));
348
349    switch (what) {
350        case LiveSession::kWhatPrepared:
351        {
352            // notify the current size here if we have it, otherwise report an initial size of (0,0)
353            sp<AMessage> format = getFormat(false /* audio */);
354            int32_t width;
355            int32_t height;
356            if (format != NULL &&
357                    format->findInt32("width", &width) && format->findInt32("height", &height)) {
358                notifyVideoSizeChanged(format);
359            } else {
360                notifyVideoSizeChanged();
361            }
362
363            uint32_t flags = 0;
364            if (mLiveSession->isSeekable()) {
365                flags |= FLAG_CAN_PAUSE;
366                flags |= FLAG_CAN_SEEK;
367                flags |= FLAG_CAN_SEEK_BACKWARD;
368                flags |= FLAG_CAN_SEEK_FORWARD;
369            }
370
371            if (mLiveSession->hasDynamicDuration()) {
372                flags |= FLAG_DYNAMIC_DURATION;
373            }
374
375            notifyFlagsChanged(flags);
376
377            notifyPrepared();
378            break;
379        }
380
381        case LiveSession::kWhatPreparationFailed:
382        {
383            status_t err;
384            CHECK(msg->findInt32("err", &err));
385
386            notifyPrepared(err);
387            break;
388        }
389
390        case LiveSession::kWhatStreamsChanged:
391        {
392            uint32_t changedMask;
393            CHECK(msg->findInt32(
394                        "changedMask", (int32_t *)&changedMask));
395
396            bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
397            bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
398
399            sp<AMessage> reply;
400            CHECK(msg->findMessage("reply", &reply));
401
402            sp<AMessage> notify = dupNotify();
403            notify->setInt32("what", kWhatQueueDecoderShutdown);
404            notify->setInt32("audio", audio);
405            notify->setInt32("video", video);
406            notify->setMessage("reply", reply);
407            notify->post();
408            break;
409        }
410
411        case LiveSession::kWhatBufferingStart:
412        {
413            sp<AMessage> notify = dupNotify();
414            notify->setInt32("what", kWhatPauseOnBufferingStart);
415            notify->post();
416            break;
417        }
418
419        case LiveSession::kWhatBufferingEnd:
420        {
421            sp<AMessage> notify = dupNotify();
422            notify->setInt32("what", kWhatResumeOnBufferingEnd);
423            notify->post();
424            break;
425        }
426
427
428        case LiveSession::kWhatBufferingUpdate:
429        {
430            sp<AMessage> notify = dupNotify();
431            int32_t percentage;
432            CHECK(msg->findInt32("percentage", &percentage));
433            notify->setInt32("what", kWhatBufferingUpdate);
434            notify->setInt32("percentage", percentage);
435            notify->post();
436            break;
437        }
438
439        case LiveSession::kWhatMetadataDetected:
440        {
441            if (!mHasMetadata) {
442                mHasMetadata = true;
443
444                sp<AMessage> notify = dupNotify();
445                // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE
446                notify->setInt32("what", kWhatTimedMetaData);
447                notify->post();
448            }
449            break;
450        }
451
452        case LiveSession::kWhatError:
453        {
454            break;
455        }
456
457        default:
458            TRESPASS();
459    }
460}
461
462}  // namespace android
463
464