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