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> ¬ify,
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