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