blob: d7876477a938896d3efa3716efd504f5b44dd3d8 [file] [log] [blame]
Andreas Huber2bfdd422011-10-11 15:24:07 -07001/*
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 "RTSPSource"
19#include <utils/Log.h>
20
21#include "RTSPSource.h"
22
23#include "AnotherPacketSource.h"
24#include "MyHandler.h"
Oscar Rydhé7a33b772012-02-20 10:15:48 +010025#include "SDPLoader.h"
Andreas Huber2bfdd422011-10-11 15:24:07 -070026
Andreas Hubercfaeeec2012-08-31 10:27:46 -070027#include <media/stagefright/MediaDefs.h>
Andreas Huber2bfdd422011-10-11 15:24:07 -070028#include <media/stagefright/MetaData.h>
29
30namespace android {
31
32NuPlayer::RTSPSource::RTSPSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080033 const sp<AMessage> &notify,
Andreas Huber2bfdd422011-10-11 15:24:07 -070034 const char *url,
35 const KeyedVector<String8, String8> *headers,
36 bool uidValid,
Oscar Rydhé7a33b772012-02-20 10:15:48 +010037 uid_t uid,
38 bool isSDP)
Andreas Huberb5f25f02013-02-05 10:14:26 -080039 : Source(notify),
40 mURL(url),
Andreas Huber2bfdd422011-10-11 15:24:07 -070041 mUIDValid(uidValid),
42 mUID(uid),
43 mFlags(0),
Oscar Rydhé7a33b772012-02-20 10:15:48 +010044 mIsSDP(isSDP),
Andreas Huber2bfdd422011-10-11 15:24:07 -070045 mState(DISCONNECTED),
46 mFinalResult(OK),
Andreas Huberee736e92011-12-08 13:04:50 -080047 mDisconnectReplyID(0),
Andreas Huberbfd4d0d2012-05-17 14:18:50 -070048 mStartingUp(true),
Andreas Huberee736e92011-12-08 13:04:50 -080049 mSeekGeneration(0) {
Andreas Huber2bfdd422011-10-11 15:24:07 -070050 if (headers) {
51 mExtraHeaders = *headers;
52
53 ssize_t index =
54 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
55
56 if (index >= 0) {
57 mFlags |= kFlagIncognito;
58
59 mExtraHeaders.removeItemsAt(index);
60 }
61 }
62}
63
64NuPlayer::RTSPSource::~RTSPSource() {
James Dongf6f0f0e2012-11-16 14:31:15 -080065 mLooper->stop();
Andreas Huber2bfdd422011-10-11 15:24:07 -070066}
67
Andreas Huber9575c962013-02-05 13:59:56 -080068void NuPlayer::RTSPSource::prepareAsync() {
Andreas Huber2bfdd422011-10-11 15:24:07 -070069 if (mLooper == NULL) {
70 mLooper = new ALooper;
71 mLooper->setName("rtsp");
72 mLooper->start();
73
74 mReflector = new AHandlerReflector<RTSPSource>(this);
75 mLooper->registerHandler(mReflector);
76 }
77
78 CHECK(mHandler == NULL);
Oscar Rydhé7a33b772012-02-20 10:15:48 +010079 CHECK(mSDPLoader == NULL);
Andreas Huber2bfdd422011-10-11 15:24:07 -070080
81 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
82
Andreas Huber2bfdd422011-10-11 15:24:07 -070083 CHECK_EQ(mState, (int)DISCONNECTED);
84 mState = CONNECTING;
85
Oscar Rydhé7a33b772012-02-20 10:15:48 +010086 if (mIsSDP) {
87 mSDPLoader = new SDPLoader(notify,
88 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
89 mUIDValid, mUID);
90
Andreas Huber9575c962013-02-05 13:59:56 -080091 mSDPLoader->load(
92 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
Oscar Rydhé7a33b772012-02-20 10:15:48 +010093 } else {
94 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
95 mLooper->registerHandler(mHandler);
96
97 mHandler->connect();
98 }
Andreas Huber9575c962013-02-05 13:59:56 -080099}
100
101void NuPlayer::RTSPSource::start() {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700102}
103
104void NuPlayer::RTSPSource::stop() {
James Dongf6f0f0e2012-11-16 14:31:15 -0800105 if (mLooper == NULL) {
106 return;
107 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700108 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
109
110 sp<AMessage> dummy;
111 msg->postAndAwaitResponse(&dummy);
112}
113
114status_t NuPlayer::RTSPSource::feedMoreTSData() {
115 return mFinalResult;
116}
117
Andreas Huber84066782011-08-16 09:34:26 -0700118sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700119 sp<AnotherPacketSource> source = getSource(audio);
120
121 if (source == NULL) {
122 return NULL;
123 }
124
125 return source->getFormat();
126}
127
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700128bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
129 // We're going to buffer at least 2 secs worth data on all tracks before
130 // starting playback (both at startup and after a seek).
131
132 static const int64_t kMinDurationUs = 2000000ll;
133
134 status_t err;
135 int64_t durationUs;
136 if (mAudioTrack != NULL
137 && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
138 < kMinDurationUs
139 && err == OK) {
140 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
141 durationUs / 1E6);
142 return false;
143 }
144
145 if (mVideoTrack != NULL
146 && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
147 < kMinDurationUs
148 && err == OK) {
149 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
150 durationUs / 1E6);
151 return false;
152 }
153
154 return true;
155}
156
Andreas Huber2bfdd422011-10-11 15:24:07 -0700157status_t NuPlayer::RTSPSource::dequeueAccessUnit(
158 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700159 if (mStartingUp) {
160 if (!haveSufficientDataOnAllTracks()) {
161 return -EWOULDBLOCK;
162 }
163
164 mStartingUp = false;
165 }
166
Andreas Huber2bfdd422011-10-11 15:24:07 -0700167 sp<AnotherPacketSource> source = getSource(audio);
168
169 if (source == NULL) {
170 return -EWOULDBLOCK;
171 }
172
173 status_t finalResult;
174 if (!source->hasBufferAvailable(&finalResult)) {
175 return finalResult == OK ? -EWOULDBLOCK : finalResult;
176 }
177
178 return source->dequeueAccessUnit(accessUnit);
179}
180
181sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700182 if (mTSParser != NULL) {
183 sp<MediaSource> source = mTSParser->getSource(
184 audio ? ATSParser::AUDIO : ATSParser::VIDEO);
185
186 return static_cast<AnotherPacketSource *>(source.get());
187 }
188
Andreas Huber2bfdd422011-10-11 15:24:07 -0700189 return audio ? mAudioTrack : mVideoTrack;
190}
191
192status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
193 *durationUs = 0ll;
194
195 int64_t audioDurationUs;
196 if (mAudioTrack != NULL
197 && mAudioTrack->getFormat()->findInt64(
198 kKeyDuration, &audioDurationUs)
199 && audioDurationUs > *durationUs) {
200 *durationUs = audioDurationUs;
201 }
202
203 int64_t videoDurationUs;
204 if (mVideoTrack != NULL
205 && mVideoTrack->getFormat()->findInt64(
206 kKeyDuration, &videoDurationUs)
207 && videoDurationUs > *durationUs) {
208 *durationUs = videoDurationUs;
209 }
210
211 return OK;
212}
213
214status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
Andreas Huberee736e92011-12-08 13:04:50 -0800215 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
216 msg->setInt32("generation", ++mSeekGeneration);
217 msg->setInt64("timeUs", seekTimeUs);
218 msg->post(200000ll);
219
220 return OK;
221}
222
223void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700224 if (mState != CONNECTED) {
Andreas Huberee736e92011-12-08 13:04:50 -0800225 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700226 }
227
228 mState = SEEKING;
229 mHandler->seek(seekTimeUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700230}
231
Andreas Huber2bfdd422011-10-11 15:24:07 -0700232void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
233 if (msg->what() == kWhatDisconnect) {
234 uint32_t replyID;
235 CHECK(msg->senderAwaitsResponse(&replyID));
236
237 mDisconnectReplyID = replyID;
238 finishDisconnectIfPossible();
239 return;
Andreas Huberee736e92011-12-08 13:04:50 -0800240 } else if (msg->what() == kWhatPerformSeek) {
241 int32_t generation;
242 CHECK(msg->findInt32("generation", &generation));
243
244 if (generation != mSeekGeneration) {
245 // obsolete.
246 return;
247 }
248
249 int64_t seekTimeUs;
250 CHECK(msg->findInt64("timeUs", &seekTimeUs));
251
252 performSeek(seekTimeUs);
253 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700254 }
255
256 CHECK_EQ(msg->what(), (int)kWhatNotify);
257
258 int32_t what;
259 CHECK(msg->findInt32("what", &what));
260
261 switch (what) {
262 case MyHandler::kWhatConnected:
Andreas Huberec0c5972013-02-05 14:47:13 -0800263 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700264 onConnected();
Andreas Huberec0c5972013-02-05 14:47:13 -0800265
266 notifyVideoSizeChanged(0, 0);
267
268 uint32_t flags = 0;
269
270 if (mHandler->isSeekable()) {
271 flags = FLAG_CAN_PAUSE | FLAG_CAN_SEEK;
272
273 // Seeking 10secs forward or backward is a very expensive
274 // operation for rtsp, so let's not enable that.
275 // The user can always use the seek bar.
276 }
277
278 notifyFlagsChanged(flags);
279 notifyPrepared();
Andreas Huber2bfdd422011-10-11 15:24:07 -0700280 break;
Andreas Huberec0c5972013-02-05 14:47:13 -0800281 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700282
283 case MyHandler::kWhatDisconnected:
Andreas Huberec0c5972013-02-05 14:47:13 -0800284 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700285 onDisconnected(msg);
286 break;
Andreas Huberec0c5972013-02-05 14:47:13 -0800287 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700288
289 case MyHandler::kWhatSeekDone:
290 {
291 mState = CONNECTED;
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700292 mStartingUp = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700293 break;
294 }
295
296 case MyHandler::kWhatAccessUnit:
297 {
298 size_t trackIndex;
299 CHECK(msg->findSize("trackIndex", &trackIndex));
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700300
301 if (mTSParser == NULL) {
302 CHECK_LT(trackIndex, mTracks.size());
303 } else {
304 CHECK_EQ(trackIndex, 0u);
305 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700306
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800307 sp<ABuffer> accessUnit;
308 CHECK(msg->findBuffer("accessUnit", &accessUnit));
Andreas Huber2bfdd422011-10-11 15:24:07 -0700309
310 int32_t damaged;
311 if (accessUnit->meta()->findInt32("damaged", &damaged)
312 && damaged) {
Steve Blockdf64d152012-01-04 20:05:49 +0000313 ALOGI("dropping damaged access unit.");
Andreas Huber2bfdd422011-10-11 15:24:07 -0700314 break;
315 }
316
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700317 if (mTSParser != NULL) {
318 size_t offset = 0;
319 status_t err = OK;
320 while (offset + 188 <= accessUnit->size()) {
321 err = mTSParser->feedTSPacket(
322 accessUnit->data() + offset, 188);
323 if (err != OK) {
324 break;
325 }
326
327 offset += 188;
328 }
329
330 if (offset < accessUnit->size()) {
331 err = ERROR_MALFORMED;
332 }
333
334 if (err != OK) {
335 sp<AnotherPacketSource> source = getSource(false /* audio */);
336 if (source != NULL) {
337 source->signalEOS(err);
338 }
339
340 source = getSource(true /* audio */);
341 if (source != NULL) {
342 source->signalEOS(err);
343 }
344 }
345 break;
346 }
347
Andreas Huber1906e5c2011-12-08 12:27:47 -0800348 TrackInfo *info = &mTracks.editItemAt(trackIndex);
349
350 sp<AnotherPacketSource> source = info->mSource;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700351 if (source != NULL) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700352 uint32_t rtpTime;
353 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
354
Andreas Huber1906e5c2011-12-08 12:27:47 -0800355 if (!info->mNPTMappingValid) {
356 // This is a live stream, we didn't receive any normal
Andreas Huberc9d16962012-05-21 11:12:40 -0700357 // playtime mapping. We won't map to npt time.
358 source->queueAccessUnit(accessUnit);
359 break;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800360 }
361
Andreas Huber2bfdd422011-10-11 15:24:07 -0700362 int64_t nptUs =
Andreas Huber1906e5c2011-12-08 12:27:47 -0800363 ((double)rtpTime - (double)info->mRTPTime)
364 / info->mTimeScale
Andreas Huber2bfdd422011-10-11 15:24:07 -0700365 * 1000000ll
Andreas Huber1906e5c2011-12-08 12:27:47 -0800366 + info->mNormalPlaytimeUs;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700367
368 accessUnit->meta()->setInt64("timeUs", nptUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700369
370 source->queueAccessUnit(accessUnit);
371 }
372 break;
373 }
374
375 case MyHandler::kWhatEOS:
376 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700377 int32_t finalResult;
378 CHECK(msg->findInt32("finalResult", &finalResult));
379 CHECK_NE(finalResult, (status_t)OK);
380
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700381 if (mTSParser != NULL) {
382 sp<AnotherPacketSource> source = getSource(false /* audio */);
383 if (source != NULL) {
384 source->signalEOS(finalResult);
385 }
386
387 source = getSource(true /* audio */);
388 if (source != NULL) {
389 source->signalEOS(finalResult);
390 }
391
392 return;
393 }
394
395 size_t trackIndex;
396 CHECK(msg->findSize("trackIndex", &trackIndex));
397 CHECK_LT(trackIndex, mTracks.size());
398
Andreas Huber2bfdd422011-10-11 15:24:07 -0700399 TrackInfo *info = &mTracks.editItemAt(trackIndex);
400 sp<AnotherPacketSource> source = info->mSource;
401 if (source != NULL) {
402 source->signalEOS(finalResult);
403 }
404
405 break;
406 }
407
408 case MyHandler::kWhatSeekDiscontinuity:
409 {
410 size_t trackIndex;
411 CHECK(msg->findSize("trackIndex", &trackIndex));
412 CHECK_LT(trackIndex, mTracks.size());
413
414 TrackInfo *info = &mTracks.editItemAt(trackIndex);
415 sp<AnotherPacketSource> source = info->mSource;
416 if (source != NULL) {
417 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
418 }
419
420 break;
421 }
422
423 case MyHandler::kWhatNormalPlayTimeMapping:
424 {
425 size_t trackIndex;
426 CHECK(msg->findSize("trackIndex", &trackIndex));
427 CHECK_LT(trackIndex, mTracks.size());
428
429 uint32_t rtpTime;
430 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
431
432 int64_t nptUs;
433 CHECK(msg->findInt64("nptUs", &nptUs));
434
435 TrackInfo *info = &mTracks.editItemAt(trackIndex);
436 info->mRTPTime = rtpTime;
437 info->mNormalPlaytimeUs = nptUs;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800438 info->mNPTMappingValid = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700439 break;
440 }
441
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100442 case SDPLoader::kWhatSDPLoaded:
443 {
444 onSDPLoaded(msg);
445 break;
446 }
447
Andreas Huber2bfdd422011-10-11 15:24:07 -0700448 default:
449 TRESPASS();
450 }
451}
452
453void NuPlayer::RTSPSource::onConnected() {
454 CHECK(mAudioTrack == NULL);
455 CHECK(mVideoTrack == NULL);
456
457 size_t numTracks = mHandler->countTracks();
458 for (size_t i = 0; i < numTracks; ++i) {
459 int32_t timeScale;
460 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
461
462 const char *mime;
463 CHECK(format->findCString(kKeyMIMEType, &mime));
464
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700465 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
466 // Very special case for MPEG2 Transport Streams.
467 CHECK_EQ(numTracks, 1u);
468
469 mTSParser = new ATSParser;
470 return;
471 }
472
Andreas Huber2bfdd422011-10-11 15:24:07 -0700473 bool isAudio = !strncasecmp(mime, "audio/", 6);
474 bool isVideo = !strncasecmp(mime, "video/", 6);
475
476 TrackInfo info;
477 info.mTimeScale = timeScale;
478 info.mRTPTime = 0;
479 info.mNormalPlaytimeUs = 0ll;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800480 info.mNPTMappingValid = false;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700481
482 if ((isAudio && mAudioTrack == NULL)
483 || (isVideo && mVideoTrack == NULL)) {
484 sp<AnotherPacketSource> source = new AnotherPacketSource(format);
485
486 if (isAudio) {
487 mAudioTrack = source;
488 } else {
489 mVideoTrack = source;
490 }
491
492 info.mSource = source;
493 }
494
495 mTracks.push(info);
496 }
497
498 mState = CONNECTED;
499}
500
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100501void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
502 status_t err;
503 CHECK(msg->findInt32("result", &err));
504
505 mSDPLoader.clear();
506
507 if (mDisconnectReplyID != 0) {
508 err = UNKNOWN_ERROR;
509 }
510
511 if (err == OK) {
512 sp<ASessionDescription> desc;
513 sp<RefBase> obj;
514 CHECK(msg->findObject("description", &obj));
515 desc = static_cast<ASessionDescription *>(obj.get());
516
517 AString rtspUri;
518 if (!desc->findAttribute(0, "a=control", &rtspUri)) {
519 ALOGE("Unable to find url in SDP");
520 err = UNKNOWN_ERROR;
521 } else {
522 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
523
524 mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
525 mLooper->registerHandler(mHandler);
526
527 mHandler->loadSDP(desc);
528 }
529 }
530
531 if (err != OK) {
Andreas Huberec0c5972013-02-05 14:47:13 -0800532 if (mState == CONNECTING) {
533 // We're still in the preparation phase, signal that it
534 // failed.
535 notifyPrepared(err);
536 }
537
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100538 mState = DISCONNECTED;
539 mFinalResult = err;
540
541 if (mDisconnectReplyID != 0) {
542 finishDisconnectIfPossible();
543 }
544 }
545}
546
Andreas Huber2bfdd422011-10-11 15:24:07 -0700547void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
548 status_t err;
549 CHECK(msg->findInt32("result", &err));
550 CHECK_NE(err, (status_t)OK);
551
552 mLooper->unregisterHandler(mHandler->id());
553 mHandler.clear();
554
Andreas Huberec0c5972013-02-05 14:47:13 -0800555 if (mState == CONNECTING) {
556 // We're still in the preparation phase, signal that it
557 // failed.
558 notifyPrepared(err);
559 }
560
Andreas Huber2bfdd422011-10-11 15:24:07 -0700561 mState = DISCONNECTED;
562 mFinalResult = err;
563
564 if (mDisconnectReplyID != 0) {
565 finishDisconnectIfPossible();
566 }
567}
568
569void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
570 if (mState != DISCONNECTED) {
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100571 if (mHandler != NULL) {
572 mHandler->disconnect();
573 } else if (mSDPLoader != NULL) {
574 mSDPLoader->cancel();
575 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700576 return;
577 }
578
579 (new AMessage)->postReply(mDisconnectReplyID);
580 mDisconnectReplyID = 0;
581}
582
583} // namespace android