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
36 static const int kReadyMarkMs     = 5000;  // 5 seconds
37 static const int kPrepareMarkMs   = 1500;  // 1.5 seconds
38 static const int kUnderflowMarkMs = 1000;  // 1 second
39 
40 namespace android {
41 
HTTPLiveSource(const sp<AMessage> & notify,const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)42 NuPlayer::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 
~HTTPLiveSource()72 NuPlayer::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 
getDefaultBufferingSettings(BufferingSettings * buffering)85 status_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 
setBufferingSettings(const BufferingSettings & buffering)96 status_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 
prepareAsync()121 void 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 
start()144 void NuPlayer::HTTPLiveSource::start() {
145 }
146 
getFormatMeta(bool audio)147 sp<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 
getFormat(bool audio)159 sp<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 
feedMoreTSData()182 status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
183     return OK;
184 }
185 
dequeueAccessUnit(bool audio,sp<ABuffer> * accessUnit)186 status_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 
getDuration(int64_t * durationUs)194 status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
195     return mLiveSession->getDuration(durationUs);
196 }
197 
getTrackCount() const198 size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
199     return mLiveSession->getTrackCount();
200 }
201 
getTrackInfo(size_t trackIndex) const202 sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
203     return mLiveSession->getTrackInfo(trackIndex);
204 }
205 
getSelectedTrack(media_track_type type) const206 ssize_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 
selectTrack(size_t trackIndex,bool select,int64_t)218 status_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 
seekTo(int64_t seekTimeUs,MediaPlayerSeekMode mode)260 status_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 
pollForRawData(const sp<AMessage> & msg,int32_t currentGeneration,LiveSession::StreamType fetchType,int32_t pushWhat)268 void 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 
onMessageReceived(const sp<AMessage> & msg)311 void 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 
onSessionNotify(const sp<AMessage> & msg)349 void 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