blob: e4d72d9268d29d6a8a3af8c7f016cfcbd0d71a37 [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é81dd60e2012-02-20 10:15:48 +010025#include "SDPLoader.h"
Andreas Huber2bfdd422011-10-11 15:24:07 -070026
Andreas Huber49694682012-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 Huber5ab368a2013-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é81dd60e2012-02-20 10:15:48 +010037 uid_t uid,
38 bool isSDP)
Andreas Huber5ab368a2013-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é81dd60e2012-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 Dong58341812012-11-16 14:31:15 -080065 mLooper->stop();
Andreas Huber2bfdd422011-10-11 15:24:07 -070066}
67
Andreas Huber57cea552013-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é81dd60e2012-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é81dd60e2012-02-20 10:15:48 +010086 if (mIsSDP) {
87 mSDPLoader = new SDPLoader(notify,
88 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
89 mUIDValid, mUID);
90
Andreas Huber57cea552013-02-05 13:59:56 -080091 mSDPLoader->load(
92 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
Oscar Rydhé81dd60e2012-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 Huber57cea552013-02-05 13:59:56 -080099
100 notifyVideoSizeChanged(0, 0);
101
102 notifyFlagsChanged(
103 FLAG_CAN_PAUSE
104 | FLAG_CAN_SEEK_BACKWARD
105 | FLAG_CAN_SEEK_FORWARD
106 | FLAG_CAN_SEEK);
107
108 notifyPrepared();
109}
110
111void NuPlayer::RTSPSource::start() {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700112}
113
114void NuPlayer::RTSPSource::stop() {
James Dong58341812012-11-16 14:31:15 -0800115 if (mLooper == NULL) {
116 return;
117 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700118 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
119
120 sp<AMessage> dummy;
121 msg->postAndAwaitResponse(&dummy);
122}
123
124status_t NuPlayer::RTSPSource::feedMoreTSData() {
125 return mFinalResult;
126}
127
Andreas Huber84066782011-08-16 09:34:26 -0700128sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700129 sp<AnotherPacketSource> source = getSource(audio);
130
131 if (source == NULL) {
132 return NULL;
133 }
134
135 return source->getFormat();
136}
137
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700138bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
139 // We're going to buffer at least 2 secs worth data on all tracks before
140 // starting playback (both at startup and after a seek).
141
142 static const int64_t kMinDurationUs = 2000000ll;
143
144 status_t err;
145 int64_t durationUs;
146 if (mAudioTrack != NULL
147 && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
148 < kMinDurationUs
149 && err == OK) {
150 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
151 durationUs / 1E6);
152 return false;
153 }
154
155 if (mVideoTrack != NULL
156 && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
157 < kMinDurationUs
158 && err == OK) {
159 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
160 durationUs / 1E6);
161 return false;
162 }
163
164 return true;
165}
166
Andreas Huber2bfdd422011-10-11 15:24:07 -0700167status_t NuPlayer::RTSPSource::dequeueAccessUnit(
168 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700169 if (mStartingUp) {
170 if (!haveSufficientDataOnAllTracks()) {
171 return -EWOULDBLOCK;
172 }
173
174 mStartingUp = false;
175 }
176
Andreas Huber2bfdd422011-10-11 15:24:07 -0700177 sp<AnotherPacketSource> source = getSource(audio);
178
179 if (source == NULL) {
180 return -EWOULDBLOCK;
181 }
182
183 status_t finalResult;
184 if (!source->hasBufferAvailable(&finalResult)) {
185 return finalResult == OK ? -EWOULDBLOCK : finalResult;
186 }
187
188 return source->dequeueAccessUnit(accessUnit);
189}
190
191sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
Andreas Huber49694682012-08-31 10:27:46 -0700192 if (mTSParser != NULL) {
193 sp<MediaSource> source = mTSParser->getSource(
194 audio ? ATSParser::AUDIO : ATSParser::VIDEO);
195
196 return static_cast<AnotherPacketSource *>(source.get());
197 }
198
Andreas Huber2bfdd422011-10-11 15:24:07 -0700199 return audio ? mAudioTrack : mVideoTrack;
200}
201
202status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
203 *durationUs = 0ll;
204
205 int64_t audioDurationUs;
206 if (mAudioTrack != NULL
207 && mAudioTrack->getFormat()->findInt64(
208 kKeyDuration, &audioDurationUs)
209 && audioDurationUs > *durationUs) {
210 *durationUs = audioDurationUs;
211 }
212
213 int64_t videoDurationUs;
214 if (mVideoTrack != NULL
215 && mVideoTrack->getFormat()->findInt64(
216 kKeyDuration, &videoDurationUs)
217 && videoDurationUs > *durationUs) {
218 *durationUs = videoDurationUs;
219 }
220
221 return OK;
222}
223
224status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
Andreas Huberee736e92011-12-08 13:04:50 -0800225 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
226 msg->setInt32("generation", ++mSeekGeneration);
227 msg->setInt64("timeUs", seekTimeUs);
228 msg->post(200000ll);
229
230 return OK;
231}
232
233void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700234 if (mState != CONNECTED) {
Andreas Huberee736e92011-12-08 13:04:50 -0800235 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700236 }
237
238 mState = SEEKING;
239 mHandler->seek(seekTimeUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700240}
241
Andreas Huber2bfdd422011-10-11 15:24:07 -0700242void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
243 if (msg->what() == kWhatDisconnect) {
244 uint32_t replyID;
245 CHECK(msg->senderAwaitsResponse(&replyID));
246
247 mDisconnectReplyID = replyID;
248 finishDisconnectIfPossible();
249 return;
Andreas Huberee736e92011-12-08 13:04:50 -0800250 } else if (msg->what() == kWhatPerformSeek) {
251 int32_t generation;
252 CHECK(msg->findInt32("generation", &generation));
253
254 if (generation != mSeekGeneration) {
255 // obsolete.
256 return;
257 }
258
259 int64_t seekTimeUs;
260 CHECK(msg->findInt64("timeUs", &seekTimeUs));
261
262 performSeek(seekTimeUs);
263 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700264 }
265
266 CHECK_EQ(msg->what(), (int)kWhatNotify);
267
268 int32_t what;
269 CHECK(msg->findInt32("what", &what));
270
271 switch (what) {
272 case MyHandler::kWhatConnected:
273 onConnected();
274 break;
275
276 case MyHandler::kWhatDisconnected:
277 onDisconnected(msg);
278 break;
279
280 case MyHandler::kWhatSeekDone:
281 {
282 mState = CONNECTED;
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700283 mStartingUp = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700284 break;
285 }
286
287 case MyHandler::kWhatAccessUnit:
288 {
289 size_t trackIndex;
290 CHECK(msg->findSize("trackIndex", &trackIndex));
Andreas Huber49694682012-08-31 10:27:46 -0700291
292 if (mTSParser == NULL) {
293 CHECK_LT(trackIndex, mTracks.size());
294 } else {
295 CHECK_EQ(trackIndex, 0u);
296 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700297
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800298 sp<ABuffer> accessUnit;
299 CHECK(msg->findBuffer("accessUnit", &accessUnit));
Andreas Huber2bfdd422011-10-11 15:24:07 -0700300
301 int32_t damaged;
302 if (accessUnit->meta()->findInt32("damaged", &damaged)
303 && damaged) {
Steve Blockdf64d152012-01-04 20:05:49 +0000304 ALOGI("dropping damaged access unit.");
Andreas Huber2bfdd422011-10-11 15:24:07 -0700305 break;
306 }
307
Andreas Huber49694682012-08-31 10:27:46 -0700308 if (mTSParser != NULL) {
309 size_t offset = 0;
310 status_t err = OK;
311 while (offset + 188 <= accessUnit->size()) {
312 err = mTSParser->feedTSPacket(
313 accessUnit->data() + offset, 188);
314 if (err != OK) {
315 break;
316 }
317
318 offset += 188;
319 }
320
321 if (offset < accessUnit->size()) {
322 err = ERROR_MALFORMED;
323 }
324
325 if (err != OK) {
326 sp<AnotherPacketSource> source = getSource(false /* audio */);
327 if (source != NULL) {
328 source->signalEOS(err);
329 }
330
331 source = getSource(true /* audio */);
332 if (source != NULL) {
333 source->signalEOS(err);
334 }
335 }
336 break;
337 }
338
Andreas Huber1906e5c2011-12-08 12:27:47 -0800339 TrackInfo *info = &mTracks.editItemAt(trackIndex);
340
341 sp<AnotherPacketSource> source = info->mSource;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700342 if (source != NULL) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700343 uint32_t rtpTime;
344 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
345
Andreas Huber1906e5c2011-12-08 12:27:47 -0800346 if (!info->mNPTMappingValid) {
347 // This is a live stream, we didn't receive any normal
Andreas Huberc9d16962012-05-21 11:12:40 -0700348 // playtime mapping. We won't map to npt time.
349 source->queueAccessUnit(accessUnit);
350 break;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800351 }
352
Andreas Huber2bfdd422011-10-11 15:24:07 -0700353 int64_t nptUs =
Andreas Huber1906e5c2011-12-08 12:27:47 -0800354 ((double)rtpTime - (double)info->mRTPTime)
355 / info->mTimeScale
Andreas Huber2bfdd422011-10-11 15:24:07 -0700356 * 1000000ll
Andreas Huber1906e5c2011-12-08 12:27:47 -0800357 + info->mNormalPlaytimeUs;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700358
359 accessUnit->meta()->setInt64("timeUs", nptUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700360
361 source->queueAccessUnit(accessUnit);
362 }
363 break;
364 }
365
366 case MyHandler::kWhatEOS:
367 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700368 int32_t finalResult;
369 CHECK(msg->findInt32("finalResult", &finalResult));
370 CHECK_NE(finalResult, (status_t)OK);
371
Andreas Huber49694682012-08-31 10:27:46 -0700372 if (mTSParser != NULL) {
373 sp<AnotherPacketSource> source = getSource(false /* audio */);
374 if (source != NULL) {
375 source->signalEOS(finalResult);
376 }
377
378 source = getSource(true /* audio */);
379 if (source != NULL) {
380 source->signalEOS(finalResult);
381 }
382
383 return;
384 }
385
386 size_t trackIndex;
387 CHECK(msg->findSize("trackIndex", &trackIndex));
388 CHECK_LT(trackIndex, mTracks.size());
389
Andreas Huber2bfdd422011-10-11 15:24:07 -0700390 TrackInfo *info = &mTracks.editItemAt(trackIndex);
391 sp<AnotherPacketSource> source = info->mSource;
392 if (source != NULL) {
393 source->signalEOS(finalResult);
394 }
395
396 break;
397 }
398
399 case MyHandler::kWhatSeekDiscontinuity:
400 {
401 size_t trackIndex;
402 CHECK(msg->findSize("trackIndex", &trackIndex));
403 CHECK_LT(trackIndex, mTracks.size());
404
405 TrackInfo *info = &mTracks.editItemAt(trackIndex);
406 sp<AnotherPacketSource> source = info->mSource;
407 if (source != NULL) {
408 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
409 }
410
411 break;
412 }
413
414 case MyHandler::kWhatNormalPlayTimeMapping:
415 {
416 size_t trackIndex;
417 CHECK(msg->findSize("trackIndex", &trackIndex));
418 CHECK_LT(trackIndex, mTracks.size());
419
420 uint32_t rtpTime;
421 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
422
423 int64_t nptUs;
424 CHECK(msg->findInt64("nptUs", &nptUs));
425
426 TrackInfo *info = &mTracks.editItemAt(trackIndex);
427 info->mRTPTime = rtpTime;
428 info->mNormalPlaytimeUs = nptUs;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800429 info->mNPTMappingValid = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700430 break;
431 }
432
Oscar Rydhé81dd60e2012-02-20 10:15:48 +0100433 case SDPLoader::kWhatSDPLoaded:
434 {
435 onSDPLoaded(msg);
436 break;
437 }
438
Andreas Huber2bfdd422011-10-11 15:24:07 -0700439 default:
440 TRESPASS();
441 }
442}
443
444void NuPlayer::RTSPSource::onConnected() {
445 CHECK(mAudioTrack == NULL);
446 CHECK(mVideoTrack == NULL);
447
448 size_t numTracks = mHandler->countTracks();
449 for (size_t i = 0; i < numTracks; ++i) {
450 int32_t timeScale;
451 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
452
453 const char *mime;
454 CHECK(format->findCString(kKeyMIMEType, &mime));
455
Andreas Huber49694682012-08-31 10:27:46 -0700456 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
457 // Very special case for MPEG2 Transport Streams.
458 CHECK_EQ(numTracks, 1u);
459
460 mTSParser = new ATSParser;
461 return;
462 }
463
Andreas Huber2bfdd422011-10-11 15:24:07 -0700464 bool isAudio = !strncasecmp(mime, "audio/", 6);
465 bool isVideo = !strncasecmp(mime, "video/", 6);
466
467 TrackInfo info;
468 info.mTimeScale = timeScale;
469 info.mRTPTime = 0;
470 info.mNormalPlaytimeUs = 0ll;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800471 info.mNPTMappingValid = false;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700472
473 if ((isAudio && mAudioTrack == NULL)
474 || (isVideo && mVideoTrack == NULL)) {
475 sp<AnotherPacketSource> source = new AnotherPacketSource(format);
476
477 if (isAudio) {
478 mAudioTrack = source;
479 } else {
480 mVideoTrack = source;
481 }
482
483 info.mSource = source;
484 }
485
486 mTracks.push(info);
487 }
488
489 mState = CONNECTED;
490}
491
Oscar Rydhé81dd60e2012-02-20 10:15:48 +0100492void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
493 status_t err;
494 CHECK(msg->findInt32("result", &err));
495
496 mSDPLoader.clear();
497
498 if (mDisconnectReplyID != 0) {
499 err = UNKNOWN_ERROR;
500 }
501
502 if (err == OK) {
503 sp<ASessionDescription> desc;
504 sp<RefBase> obj;
505 CHECK(msg->findObject("description", &obj));
506 desc = static_cast<ASessionDescription *>(obj.get());
507
508 AString rtspUri;
509 if (!desc->findAttribute(0, "a=control", &rtspUri)) {
510 ALOGE("Unable to find url in SDP");
511 err = UNKNOWN_ERROR;
512 } else {
513 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
514
515 mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
516 mLooper->registerHandler(mHandler);
517
518 mHandler->loadSDP(desc);
519 }
520 }
521
522 if (err != OK) {
523 mState = DISCONNECTED;
524 mFinalResult = err;
525
526 if (mDisconnectReplyID != 0) {
527 finishDisconnectIfPossible();
528 }
529 }
530}
531
Andreas Huber2bfdd422011-10-11 15:24:07 -0700532void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
533 status_t err;
534 CHECK(msg->findInt32("result", &err));
535 CHECK_NE(err, (status_t)OK);
536
537 mLooper->unregisterHandler(mHandler->id());
538 mHandler.clear();
539
540 mState = DISCONNECTED;
541 mFinalResult = err;
542
543 if (mDisconnectReplyID != 0) {
544 finishDisconnectIfPossible();
545 }
546}
547
548void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
549 if (mState != DISCONNECTED) {
Oscar Rydhé81dd60e2012-02-20 10:15:48 +0100550 if (mHandler != NULL) {
551 mHandler->disconnect();
552 } else if (mSDPLoader != NULL) {
553 mSDPLoader->cancel();
554 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700555 return;
556 }
557
558 (new AMessage)->postReply(mDisconnectReplyID);
559 mDisconnectReplyID = 0;
560}
561
562} // namespace android