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