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