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