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