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    if (mLiveSession->isSeekable()) {
262        return mLiveSession->seekTo(seekTimeUs, mode);
263    } else {
264        return INVALID_OPERATION;
265    }
266}
267
268void NuPlayer::HTTPLiveSource::pollForRawData(
269        const sp<AMessage> &msg, int32_t currentGeneration,
270        LiveSession::StreamType fetchType, int32_t pushWhat) {
271
272    int32_t generation;
273    CHECK(msg->findInt32("generation", &generation));
274
275    if (generation != currentGeneration) {
276        return;
277    }
278
279    sp<ABuffer> buffer;
280    while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
281
282        sp<AMessage> notify = dupNotify();
283        notify->setInt32("what", pushWhat);
284        notify->setBuffer("buffer", buffer);
285
286        int64_t timeUs, baseUs, delayUs;
287        CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
288        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
289        delayUs = baseUs + timeUs - ALooper::GetNowUs();
290
291        if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
292            notify->post();
293            msg->post(delayUs > 0ll ? delayUs : 0ll);
294            return;
295        } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
296            if (delayUs < -1000000ll) { // 1 second
297                continue;
298            }
299            notify->post();
300            // push all currently available metadata buffers in each invocation of pollForRawData
301            // continue;
302        } else {
303            TRESPASS();
304        }
305    }
306
307    // try again in 1 second
308    msg->post(1000000ll);
309}
310
311void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
312    switch (msg->what()) {
313        case kWhatSessionNotify:
314        {
315            onSessionNotify(msg);
316            break;
317        }
318
319        case kWhatFetchSubtitleData:
320        {
321            pollForRawData(
322                    msg, mFetchSubtitleDataGeneration,
323                    /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
324                    /* push */ kWhatSubtitleData);
325
326            break;
327        }
328
329        case kWhatFetchMetaData:
330        {
331            if (!mMetadataSelected) {
332                break;
333            }
334
335            pollForRawData(
336                    msg, mFetchMetaDataGeneration,
337                    /* fetch */ LiveSession::STREAMTYPE_METADATA,
338                    /* push */ kWhatTimedMetaData);
339
340            break;
341        }
342
343        default:
344            Source::onMessageReceived(msg);
345            break;
346    }
347}
348
349void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
350    int32_t what;
351    CHECK(msg->findInt32("what", &what));
352
353    switch (what) {
354        case LiveSession::kWhatPrepared:
355        {
356            // notify the current size here if we have it, otherwise report an initial size of (0,0)
357            sp<AMessage> format = getFormat(false /* audio */);
358            int32_t width;
359            int32_t height;
360            if (format != NULL &&
361                    format->findInt32("width", &width) && format->findInt32("height", &height)) {
362                notifyVideoSizeChanged(format);
363            } else {
364                notifyVideoSizeChanged();
365            }
366
367            uint32_t flags = 0;
368            if (mLiveSession->isSeekable()) {
369                flags |= FLAG_CAN_PAUSE;
370                flags |= FLAG_CAN_SEEK;
371                flags |= FLAG_CAN_SEEK_BACKWARD;
372                flags |= FLAG_CAN_SEEK_FORWARD;
373            }
374
375            if (mLiveSession->hasDynamicDuration()) {
376                flags |= FLAG_DYNAMIC_DURATION;
377            }
378
379            notifyFlagsChanged(flags);
380
381            notifyPrepared();
382            break;
383        }
384
385        case LiveSession::kWhatPreparationFailed:
386        {
387            status_t err;
388            CHECK(msg->findInt32("err", &err));
389
390            notifyPrepared(err);
391            break;
392        }
393
394        case LiveSession::kWhatStreamsChanged:
395        {
396            uint32_t changedMask;
397            CHECK(msg->findInt32(
398                        "changedMask", (int32_t *)&changedMask));
399
400            bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
401            bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
402
403            sp<AMessage> reply;
404            CHECK(msg->findMessage("reply", &reply));
405
406            sp<AMessage> notify = dupNotify();
407            notify->setInt32("what", kWhatQueueDecoderShutdown);
408            notify->setInt32("audio", audio);
409            notify->setInt32("video", video);
410            notify->setMessage("reply", reply);
411            notify->post();
412            break;
413        }
414
415        case LiveSession::kWhatBufferingStart:
416        {
417            sp<AMessage> notify = dupNotify();
418            notify->setInt32("what", kWhatPauseOnBufferingStart);
419            notify->post();
420            break;
421        }
422
423        case LiveSession::kWhatBufferingEnd:
424        {
425            sp<AMessage> notify = dupNotify();
426            notify->setInt32("what", kWhatResumeOnBufferingEnd);
427            notify->post();
428            break;
429        }
430
431
432        case LiveSession::kWhatBufferingUpdate:
433        {
434            sp<AMessage> notify = dupNotify();
435            int32_t percentage;
436            CHECK(msg->findInt32("percentage", &percentage));
437            notify->setInt32("what", kWhatBufferingUpdate);
438            notify->setInt32("percentage", percentage);
439            notify->post();
440            break;
441        }
442
443        case LiveSession::kWhatMetadataDetected:
444        {
445            if (!mHasMetadata) {
446                mHasMetadata = true;
447
448                sp<AMessage> notify = dupNotify();
449                // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE
450                notify->setInt32("what", kWhatTimedMetaData);
451                notify->post();
452            }
453            break;
454        }
455
456        case LiveSession::kWhatError:
457        {
458            break;
459        }
460
461        default:
462            TRESPASS();
463    }
464}
465
466}  // namespace android
467
468