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