blob: 05e62013fc7d132ead3e5aaa58711ceaad276d67 [file] [log] [blame]
Andreas Huber5bc087c2010-12-23 10:27:40 -08001/*
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
Andreas Huber5bc087c2010-12-23 10:27:40 -080023#include "AnotherPacketSource.h"
24#include "LiveDataSource.h"
Andreas Huber5bc087c2010-12-23 10:27:40 -080025
Andreas Huber1b86fe02014-01-29 11:13:26 -080026#include <media/IMediaHTTPService.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080027#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>
Robert Shih08528432015-04-08 09:06:54 -070032#include <media/stagefright/MediaDefs.h>
Robert Shiha83eebb2016-10-13 15:10:42 -070033#include <media/stagefright/Utils.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080034
Wei Jia48fa06d2016-12-20 15:30:49 -080035// default buffer prepare/ready/underflow marks
36static const int kReadyMarkMs = 5000; // 5 seconds
37static const int kPrepareMarkMs = 1500; // 1.5 seconds
38static const int kUnderflowMarkMs = 1000; // 1 second
39
Andreas Huber5bc087c2010-12-23 10:27:40 -080040namespace android {
41
Andreas Huberad0d9c92011-04-19 11:50:27 -070042NuPlayer::HTTPLiveSource::HTTPLiveSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080043 const sp<AMessage> &notify,
Andreas Huber1b86fe02014-01-29 11:13:26 -080044 const sp<IMediaHTTPService> &httpService,
Andreas Huberad0d9c92011-04-19 11:50:27 -070045 const char *url,
Andreas Huber81e68442014-02-05 11:52:33 -080046 const KeyedVector<String8, String8> *headers)
Andreas Huberb5f25f02013-02-05 10:14:26 -080047 : Source(notify),
Andreas Huber1b86fe02014-01-29 11:13:26 -080048 mHTTPService(httpService),
Andreas Huberb5f25f02013-02-05 10:14:26 -080049 mURL(url),
Andreas Huberad0d9c92011-04-19 11:50:27 -070050 mFlags(0),
Andreas Hubereac68ba2011-09-27 12:12:25 -070051 mFinalResult(OK),
Chong Zhangdcb89b32013-08-06 09:44:47 -070052 mOffset(0),
Robert Shih08528432015-04-08 09:06:54 -070053 mFetchSubtitleDataGeneration(0),
54 mFetchMetaDataGeneration(0),
55 mHasMetadata(false),
56 mMetadataSelected(false) {
Wei Jia48fa06d2016-12-20 15:30:49 -080057 getDefaultBufferingSettings(&mBufferingSettings);
Andreas Huberad0d9c92011-04-19 11:50:27 -070058 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 }
Andreas Huber5bc087c2010-12-23 10:27:40 -080070}
71
72NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
Andreas Huber2048d0c2011-07-15 16:25:41 -070073 if (mLiveSession != NULL) {
74 mLiveSession->disconnect();
Andreas Huber14f76722013-01-15 09:04:18 -080075
Chong Zhang1228d6b2014-08-12 21:25:48 -070076 mLiveLooper->unregisterHandler(mLiveSession->id());
77 mLiveLooper->unregisterHandler(id());
Andreas Huber2048d0c2011-07-15 16:25:41 -070078 mLiveLooper->stop();
Chong Zhang1228d6b2014-08-12 21:25:48 -070079
80 mLiveSession.clear();
Andreas Huber14f76722013-01-15 09:04:18 -080081 mLiveLooper.clear();
Andreas Huber2048d0c2011-07-15 16:25:41 -070082 }
Andreas Huber5bc087c2010-12-23 10:27:40 -080083}
84
Wei Jia48fa06d2016-12-20 15:30:49 -080085status_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
96status_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
Andreas Huber9575c962013-02-05 13:59:56 -0800121void NuPlayer::HTTPLiveSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700122 if (mLiveLooper == NULL) {
123 mLiveLooper = new ALooper;
124 mLiveLooper->setName("http live");
125 mLiveLooper->start();
126
127 mLiveLooper->registerHandler(this);
128 }
Andreas Huber5bc087c2010-12-23 10:27:40 -0800129
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800130 sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
Andreas Huber0df36ec2013-02-06 10:44:39 -0800131
Andreas Huber7314fa12011-02-24 14:42:48 -0800132 mLiveSession = new LiveSession(
Andreas Huber0df36ec2013-02-06 10:44:39 -0800133 notify,
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700134 (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
Andreas Huber81e68442014-02-05 11:52:33 -0800135 mHTTPService);
Andreas Huber7314fa12011-02-24 14:42:48 -0800136
Andreas Huber5bc087c2010-12-23 10:27:40 -0800137 mLiveLooper->registerHandler(mLiveSession);
138
Wei Jia48fa06d2016-12-20 15:30:49 -0800139 mLiveSession->setBufferingSettings(mBufferingSettings);
Andreas Huber14f76722013-01-15 09:04:18 -0800140 mLiveSession->connectAsync(
Andreas Huberad0d9c92011-04-19 11:50:27 -0700141 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
Andreas Huber9575c962013-02-05 13:59:56 -0800142}
143
144void NuPlayer::HTTPLiveSource::start() {
Andreas Huber5bc087c2010-12-23 10:27:40 -0800145}
146
Robert Shiha83eebb2016-10-13 15:10:42 -0700147sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
148 sp<MetaData> meta;
Robert Shih7350b052015-10-01 15:50:14 -0700149 if (mLiveSession != NULL) {
Robert Shiha83eebb2016-10-13 15:10:42 -0700150 mLiveSession->getStreamFormatMeta(
Robert Shih7350b052015-10-01 15:50:14 -0700151 audio ? LiveSession::STREAMTYPE_AUDIO
152 : LiveSession::STREAMTYPE_VIDEO,
Robert Shiha83eebb2016-10-13 15:10:42 -0700153 &meta);
Robert Shih1098d872014-11-06 13:58:48 -0800154 }
155
Robert Shiha83eebb2016-10-13 15:10:42 -0700156 return meta;
157}
158
159sp<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;
Robert Shih7350b052015-10-01 15:50:14 -0700170 if (err == -EWOULDBLOCK) {
171 format = new AMessage();
172 format->setInt32("err", err);
173 return format;
174 }
Andreas Huber5bc087c2010-12-23 10:27:40 -0800175
Robert Shiha83eebb2016-10-13 15:10:42 -0700176 if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
Andreas Huber5bc087c2010-12-23 10:27:40 -0800177 return NULL;
178 }
Andreas Huber14f76722013-01-15 09:04:18 -0800179 return format;
Andreas Huber5bc087c2010-12-23 10:27:40 -0800180}
181
Andreas Hubereac68ba2011-09-27 12:12:25 -0700182status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
Andreas Hubereac68ba2011-09-27 12:12:25 -0700183 return OK;
Andreas Huber5bc087c2010-12-23 10:27:40 -0800184}
185
186status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
187 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huber14f76722013-01-15 09:04:18 -0800188 return mLiveSession->dequeueAccessUnit(
189 audio ? LiveSession::STREAMTYPE_AUDIO
190 : LiveSession::STREAMTYPE_VIDEO,
191 accessUnit);
Andreas Huber5bc087c2010-12-23 10:27:40 -0800192}
193
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800194status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
195 return mLiveSession->getDuration(durationUs);
196}
197
Chong Zhang404fced2014-06-11 14:45:31 -0700198size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
199 return mLiveSession->getTrackCount();
200}
201
202sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
203 return mLiveSession->getTrackInfo(trackIndex);
Chong Zhangdcb89b32013-08-06 09:44:47 -0700204}
205
Robert Shih89bf2522014-07-29 19:25:10 -0700206ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const {
207 if (mLiveSession == NULL) {
208 return -1;
Robert Shih08528432015-04-08 09:06:54 -0700209 } 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;
Robert Shih89bf2522014-07-29 19:25:10 -0700213 } else {
214 return mLiveSession->getSelectedTrack(type);
215 }
216}
217
Robert Shih6ffb1fd2014-10-29 16:24:32 -0700218status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
Robert Shih08528432015-04-08 09:06:54 -0700219 if (mLiveSession == NULL) {
220 return INVALID_OPERATION;
221 }
222
223 status_t err = INVALID_OPERATION;
224 bool postFetchMsg = false, isSub = false;
Robert Shih055404e2015-05-15 10:12:21 -0700225 if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
Robert Shih08528432015-04-08 09:06:54 -0700226 err = mLiveSession->selectTrack(trackIndex, select);
227 postFetchMsg = select;
228 isSub = true;
229 } else {
Robert Shih055404e2015-05-15 10:12:21 -0700230 // 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
Robert Shih08528432015-04-08 09:06:54 -0700238 }
Robert Shih055404e2015-05-15 10:12:21 -0700239
240 mMetadataSelected = select;
Robert Shih08528432015-04-08 09:06:54 -0700241 }
Chong Zhangdcb89b32013-08-06 09:44:47 -0700242
243 if (err == OK) {
Robert Shih08528432015-04-08 09:06:54 -0700244 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);
Chong Zhangdcb89b32013-08-06 09:44:47 -0700250 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.
Andreas Huber84333e02014-02-07 15:36:10 -0800257 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
Chong Zhangdcb89b32013-08-06 09:44:47 -0700258}
259
Wei Jiac5de0912016-11-18 10:22:14 -0800260status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
261 return mLiveSession->seekTo(seekTimeUs, mode);
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800262}
263
Robert Shih08528432015-04-08 09:06:54 -0700264void NuPlayer::HTTPLiveSource::pollForRawData(
265 const sp<AMessage> &msg, int32_t currentGeneration,
266 LiveSession::StreamType fetchType, int32_t pushWhat) {
267
268 int32_t generation;
269 CHECK(msg->findInt32("generation", &generation));
270
271 if (generation != currentGeneration) {
272 return;
273 }
274
275 sp<ABuffer> buffer;
276 while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
277
278 sp<AMessage> notify = dupNotify();
279 notify->setInt32("what", pushWhat);
280 notify->setBuffer("buffer", buffer);
281
282 int64_t timeUs, baseUs, delayUs;
283 CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
284 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
285 delayUs = baseUs + timeUs - ALooper::GetNowUs();
286
287 if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
288 notify->post();
289 msg->post(delayUs > 0ll ? delayUs : 0ll);
290 return;
291 } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
292 if (delayUs < -1000000ll) { // 1 second
293 continue;
294 }
295 notify->post();
296 // push all currently available metadata buffers in each invocation of pollForRawData
297 // continue;
298 } else {
299 TRESPASS();
300 }
301 }
302
303 // try again in 1 second
304 msg->post(1000000ll);
305}
306
Andreas Huber0df36ec2013-02-06 10:44:39 -0800307void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
308 switch (msg->what()) {
309 case kWhatSessionNotify:
310 {
311 onSessionNotify(msg);
312 break;
313 }
314
Chong Zhangdcb89b32013-08-06 09:44:47 -0700315 case kWhatFetchSubtitleData:
316 {
Robert Shih08528432015-04-08 09:06:54 -0700317 pollForRawData(
318 msg, mFetchSubtitleDataGeneration,
319 /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
320 /* push */ kWhatSubtitleData);
Chong Zhangdcb89b32013-08-06 09:44:47 -0700321
Robert Shih08528432015-04-08 09:06:54 -0700322 break;
323 }
324
325 case kWhatFetchMetaData:
326 {
327 if (!mMetadataSelected) {
Chong Zhangdcb89b32013-08-06 09:44:47 -0700328 break;
329 }
330
Robert Shih08528432015-04-08 09:06:54 -0700331 pollForRawData(
332 msg, mFetchMetaDataGeneration,
333 /* fetch */ LiveSession::STREAMTYPE_METADATA,
334 /* push */ kWhatTimedMetaData);
Chong Zhangdcb89b32013-08-06 09:44:47 -0700335
336 break;
337 }
338
Andreas Huber0df36ec2013-02-06 10:44:39 -0800339 default:
340 Source::onMessageReceived(msg);
341 break;
342 }
343}
344
345void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
346 int32_t what;
347 CHECK(msg->findInt32("what", &what));
348
349 switch (what) {
350 case LiveSession::kWhatPrepared:
351 {
Marco Nelissen3e518fd2013-11-01 10:33:18 -0700352 // notify the current size here if we have it, otherwise report an initial size of (0,0)
353 sp<AMessage> format = getFormat(false /* audio */);
354 int32_t width;
355 int32_t height;
356 if (format != NULL &&
357 format->findInt32("width", &width) && format->findInt32("height", &height)) {
Chong Zhangced1c2f2014-08-08 15:22:35 -0700358 notifyVideoSizeChanged(format);
Marco Nelissen3e518fd2013-11-01 10:33:18 -0700359 } else {
Chong Zhangced1c2f2014-08-08 15:22:35 -0700360 notifyVideoSizeChanged();
Marco Nelissen3e518fd2013-11-01 10:33:18 -0700361 }
Andreas Huber0df36ec2013-02-06 10:44:39 -0800362
Roger1 Jonssonf9dee0c2013-10-11 08:43:35 +0200363 uint32_t flags = 0;
Andreas Huber0df36ec2013-02-06 10:44:39 -0800364 if (mLiveSession->isSeekable()) {
Roger1 Jonssonf9dee0c2013-10-11 08:43:35 +0200365 flags |= FLAG_CAN_PAUSE;
Andreas Huber0df36ec2013-02-06 10:44:39 -0800366 flags |= FLAG_CAN_SEEK;
367 flags |= FLAG_CAN_SEEK_BACKWARD;
368 flags |= FLAG_CAN_SEEK_FORWARD;
369 }
370
371 if (mLiveSession->hasDynamicDuration()) {
372 flags |= FLAG_DYNAMIC_DURATION;
373 }
374
375 notifyFlagsChanged(flags);
376
377 notifyPrepared();
378 break;
379 }
380
381 case LiveSession::kWhatPreparationFailed:
382 {
383 status_t err;
384 CHECK(msg->findInt32("err", &err));
385
386 notifyPrepared(err);
387 break;
388 }
389
Andreas Huber14f76722013-01-15 09:04:18 -0800390 case LiveSession::kWhatStreamsChanged:
391 {
392 uint32_t changedMask;
393 CHECK(msg->findInt32(
394 "changedMask", (int32_t *)&changedMask));
395
396 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
397 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
398
399 sp<AMessage> reply;
400 CHECK(msg->findMessage("reply", &reply));
401
402 sp<AMessage> notify = dupNotify();
403 notify->setInt32("what", kWhatQueueDecoderShutdown);
404 notify->setInt32("audio", audio);
405 notify->setInt32("video", video);
406 notify->setMessage("reply", reply);
407 notify->post();
408 break;
409 }
410
Chong Zhang7c870802015-03-17 16:27:56 -0700411 case LiveSession::kWhatBufferingStart:
412 {
413 sp<AMessage> notify = dupNotify();
414 notify->setInt32("what", kWhatPauseOnBufferingStart);
415 notify->post();
416 break;
417 }
418
419 case LiveSession::kWhatBufferingEnd:
420 {
421 sp<AMessage> notify = dupNotify();
422 notify->setInt32("what", kWhatResumeOnBufferingEnd);
423 notify->post();
424 break;
425 }
426
427
428 case LiveSession::kWhatBufferingUpdate:
429 {
430 sp<AMessage> notify = dupNotify();
431 int32_t percentage;
432 CHECK(msg->findInt32("percentage", &percentage));
433 notify->setInt32("what", kWhatBufferingUpdate);
434 notify->setInt32("percentage", percentage);
435 notify->post();
436 break;
437 }
438
Robert Shih08528432015-04-08 09:06:54 -0700439 case LiveSession::kWhatMetadataDetected:
440 {
441 if (!mHasMetadata) {
442 mHasMetadata = true;
443
444 sp<AMessage> notify = dupNotify();
445 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE
446 notify->setInt32("what", kWhatTimedMetaData);
447 notify->post();
448 }
449 break;
450 }
451
Andreas Huber14f76722013-01-15 09:04:18 -0800452 case LiveSession::kWhatError:
453 {
454 break;
455 }
456
Andreas Huber0df36ec2013-02-06 10:44:39 -0800457 default:
458 TRESPASS();
459 }
460}
461
Andreas Huber5bc087c2010-12-23 10:27:40 -0800462} // namespace android
463