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