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