blob: 30355893381954cd7201ad90e6fbfc998ebb5411 [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
68void NuPlayer::RTSPSource::start() {
69 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
91 mSDPLoader->load(mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
92 } else {
93 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
94 mLooper->registerHandler(mHandler);
95
96 mHandler->connect();
97 }
Andreas Huber2bfdd422011-10-11 15:24:07 -070098}
99
100void NuPlayer::RTSPSource::stop() {
James Dongf6f0f0e2012-11-16 14:31:15 -0800101 if (mLooper == NULL) {
102 return;
103 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700104 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
105
106 sp<AMessage> dummy;
107 msg->postAndAwaitResponse(&dummy);
108}
109
110status_t NuPlayer::RTSPSource::feedMoreTSData() {
111 return mFinalResult;
112}
113
Andreas Huber84066782011-08-16 09:34:26 -0700114sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700115 sp<AnotherPacketSource> source = getSource(audio);
116
117 if (source == NULL) {
118 return NULL;
119 }
120
121 return source->getFormat();
122}
123
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700124bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
125 // We're going to buffer at least 2 secs worth data on all tracks before
126 // starting playback (both at startup and after a seek).
127
128 static const int64_t kMinDurationUs = 2000000ll;
129
130 status_t err;
131 int64_t durationUs;
132 if (mAudioTrack != NULL
133 && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
134 < kMinDurationUs
135 && err == OK) {
136 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
137 durationUs / 1E6);
138 return false;
139 }
140
141 if (mVideoTrack != NULL
142 && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
143 < kMinDurationUs
144 && err == OK) {
145 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
146 durationUs / 1E6);
147 return false;
148 }
149
150 return true;
151}
152
Andreas Huber2bfdd422011-10-11 15:24:07 -0700153status_t NuPlayer::RTSPSource::dequeueAccessUnit(
154 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700155 if (mStartingUp) {
156 if (!haveSufficientDataOnAllTracks()) {
157 return -EWOULDBLOCK;
158 }
159
160 mStartingUp = false;
161 }
162
Andreas Huber2bfdd422011-10-11 15:24:07 -0700163 sp<AnotherPacketSource> source = getSource(audio);
164
165 if (source == NULL) {
166 return -EWOULDBLOCK;
167 }
168
169 status_t finalResult;
170 if (!source->hasBufferAvailable(&finalResult)) {
171 return finalResult == OK ? -EWOULDBLOCK : finalResult;
172 }
173
174 return source->dequeueAccessUnit(accessUnit);
175}
176
177sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700178 if (mTSParser != NULL) {
179 sp<MediaSource> source = mTSParser->getSource(
180 audio ? ATSParser::AUDIO : ATSParser::VIDEO);
181
182 return static_cast<AnotherPacketSource *>(source.get());
183 }
184
Andreas Huber2bfdd422011-10-11 15:24:07 -0700185 return audio ? mAudioTrack : mVideoTrack;
186}
187
188status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
189 *durationUs = 0ll;
190
191 int64_t audioDurationUs;
192 if (mAudioTrack != NULL
193 && mAudioTrack->getFormat()->findInt64(
194 kKeyDuration, &audioDurationUs)
195 && audioDurationUs > *durationUs) {
196 *durationUs = audioDurationUs;
197 }
198
199 int64_t videoDurationUs;
200 if (mVideoTrack != NULL
201 && mVideoTrack->getFormat()->findInt64(
202 kKeyDuration, &videoDurationUs)
203 && videoDurationUs > *durationUs) {
204 *durationUs = videoDurationUs;
205 }
206
207 return OK;
208}
209
210status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
Andreas Huberee736e92011-12-08 13:04:50 -0800211 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
212 msg->setInt32("generation", ++mSeekGeneration);
213 msg->setInt64("timeUs", seekTimeUs);
214 msg->post(200000ll);
215
216 return OK;
217}
218
219void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700220 if (mState != CONNECTED) {
Andreas Huberee736e92011-12-08 13:04:50 -0800221 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700222 }
223
224 mState = SEEKING;
225 mHandler->seek(seekTimeUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700226}
227
Andreas Huberb7c8e912012-11-27 15:02:53 -0800228uint32_t NuPlayer::RTSPSource::flags() const {
229 return FLAG_SEEKABLE;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700230}
231
232void 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:
263 onConnected();
264 break;
265
266 case MyHandler::kWhatDisconnected:
267 onDisconnected(msg);
268 break;
269
270 case MyHandler::kWhatSeekDone:
271 {
272 mState = CONNECTED;
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700273 mStartingUp = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700274 break;
275 }
276
277 case MyHandler::kWhatAccessUnit:
278 {
279 size_t trackIndex;
280 CHECK(msg->findSize("trackIndex", &trackIndex));
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700281
282 if (mTSParser == NULL) {
283 CHECK_LT(trackIndex, mTracks.size());
284 } else {
285 CHECK_EQ(trackIndex, 0u);
286 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700287
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800288 sp<ABuffer> accessUnit;
289 CHECK(msg->findBuffer("accessUnit", &accessUnit));
Andreas Huber2bfdd422011-10-11 15:24:07 -0700290
291 int32_t damaged;
292 if (accessUnit->meta()->findInt32("damaged", &damaged)
293 && damaged) {
Steve Blockdf64d152012-01-04 20:05:49 +0000294 ALOGI("dropping damaged access unit.");
Andreas Huber2bfdd422011-10-11 15:24:07 -0700295 break;
296 }
297
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700298 if (mTSParser != NULL) {
299 size_t offset = 0;
300 status_t err = OK;
301 while (offset + 188 <= accessUnit->size()) {
302 err = mTSParser->feedTSPacket(
303 accessUnit->data() + offset, 188);
304 if (err != OK) {
305 break;
306 }
307
308 offset += 188;
309 }
310
311 if (offset < accessUnit->size()) {
312 err = ERROR_MALFORMED;
313 }
314
315 if (err != OK) {
316 sp<AnotherPacketSource> source = getSource(false /* audio */);
317 if (source != NULL) {
318 source->signalEOS(err);
319 }
320
321 source = getSource(true /* audio */);
322 if (source != NULL) {
323 source->signalEOS(err);
324 }
325 }
326 break;
327 }
328
Andreas Huber1906e5c2011-12-08 12:27:47 -0800329 TrackInfo *info = &mTracks.editItemAt(trackIndex);
330
331 sp<AnotherPacketSource> source = info->mSource;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700332 if (source != NULL) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700333 uint32_t rtpTime;
334 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
335
Andreas Huber1906e5c2011-12-08 12:27:47 -0800336 if (!info->mNPTMappingValid) {
337 // This is a live stream, we didn't receive any normal
Andreas Huberc9d16962012-05-21 11:12:40 -0700338 // playtime mapping. We won't map to npt time.
339 source->queueAccessUnit(accessUnit);
340 break;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800341 }
342
Andreas Huber2bfdd422011-10-11 15:24:07 -0700343 int64_t nptUs =
Andreas Huber1906e5c2011-12-08 12:27:47 -0800344 ((double)rtpTime - (double)info->mRTPTime)
345 / info->mTimeScale
Andreas Huber2bfdd422011-10-11 15:24:07 -0700346 * 1000000ll
Andreas Huber1906e5c2011-12-08 12:27:47 -0800347 + info->mNormalPlaytimeUs;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700348
349 accessUnit->meta()->setInt64("timeUs", nptUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700350
351 source->queueAccessUnit(accessUnit);
352 }
353 break;
354 }
355
356 case MyHandler::kWhatEOS:
357 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700358 int32_t finalResult;
359 CHECK(msg->findInt32("finalResult", &finalResult));
360 CHECK_NE(finalResult, (status_t)OK);
361
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700362 if (mTSParser != NULL) {
363 sp<AnotherPacketSource> source = getSource(false /* audio */);
364 if (source != NULL) {
365 source->signalEOS(finalResult);
366 }
367
368 source = getSource(true /* audio */);
369 if (source != NULL) {
370 source->signalEOS(finalResult);
371 }
372
373 return;
374 }
375
376 size_t trackIndex;
377 CHECK(msg->findSize("trackIndex", &trackIndex));
378 CHECK_LT(trackIndex, mTracks.size());
379
Andreas Huber2bfdd422011-10-11 15:24:07 -0700380 TrackInfo *info = &mTracks.editItemAt(trackIndex);
381 sp<AnotherPacketSource> source = info->mSource;
382 if (source != NULL) {
383 source->signalEOS(finalResult);
384 }
385
386 break;
387 }
388
389 case MyHandler::kWhatSeekDiscontinuity:
390 {
391 size_t trackIndex;
392 CHECK(msg->findSize("trackIndex", &trackIndex));
393 CHECK_LT(trackIndex, mTracks.size());
394
395 TrackInfo *info = &mTracks.editItemAt(trackIndex);
396 sp<AnotherPacketSource> source = info->mSource;
397 if (source != NULL) {
398 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
399 }
400
401 break;
402 }
403
404 case MyHandler::kWhatNormalPlayTimeMapping:
405 {
406 size_t trackIndex;
407 CHECK(msg->findSize("trackIndex", &trackIndex));
408 CHECK_LT(trackIndex, mTracks.size());
409
410 uint32_t rtpTime;
411 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
412
413 int64_t nptUs;
414 CHECK(msg->findInt64("nptUs", &nptUs));
415
416 TrackInfo *info = &mTracks.editItemAt(trackIndex);
417 info->mRTPTime = rtpTime;
418 info->mNormalPlaytimeUs = nptUs;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800419 info->mNPTMappingValid = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700420 break;
421 }
422
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100423 case SDPLoader::kWhatSDPLoaded:
424 {
425 onSDPLoaded(msg);
426 break;
427 }
428
Andreas Huber2bfdd422011-10-11 15:24:07 -0700429 default:
430 TRESPASS();
431 }
432}
433
434void NuPlayer::RTSPSource::onConnected() {
435 CHECK(mAudioTrack == NULL);
436 CHECK(mVideoTrack == NULL);
437
438 size_t numTracks = mHandler->countTracks();
439 for (size_t i = 0; i < numTracks; ++i) {
440 int32_t timeScale;
441 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
442
443 const char *mime;
444 CHECK(format->findCString(kKeyMIMEType, &mime));
445
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700446 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
447 // Very special case for MPEG2 Transport Streams.
448 CHECK_EQ(numTracks, 1u);
449
450 mTSParser = new ATSParser;
451 return;
452 }
453
Andreas Huber2bfdd422011-10-11 15:24:07 -0700454 bool isAudio = !strncasecmp(mime, "audio/", 6);
455 bool isVideo = !strncasecmp(mime, "video/", 6);
456
457 TrackInfo info;
458 info.mTimeScale = timeScale;
459 info.mRTPTime = 0;
460 info.mNormalPlaytimeUs = 0ll;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800461 info.mNPTMappingValid = false;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700462
463 if ((isAudio && mAudioTrack == NULL)
464 || (isVideo && mVideoTrack == NULL)) {
465 sp<AnotherPacketSource> source = new AnotherPacketSource(format);
466
467 if (isAudio) {
468 mAudioTrack = source;
469 } else {
470 mVideoTrack = source;
471 }
472
473 info.mSource = source;
474 }
475
476 mTracks.push(info);
477 }
478
479 mState = CONNECTED;
480}
481
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100482void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
483 status_t err;
484 CHECK(msg->findInt32("result", &err));
485
486 mSDPLoader.clear();
487
488 if (mDisconnectReplyID != 0) {
489 err = UNKNOWN_ERROR;
490 }
491
492 if (err == OK) {
493 sp<ASessionDescription> desc;
494 sp<RefBase> obj;
495 CHECK(msg->findObject("description", &obj));
496 desc = static_cast<ASessionDescription *>(obj.get());
497
498 AString rtspUri;
499 if (!desc->findAttribute(0, "a=control", &rtspUri)) {
500 ALOGE("Unable to find url in SDP");
501 err = UNKNOWN_ERROR;
502 } else {
503 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
504
505 mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
506 mLooper->registerHandler(mHandler);
507
508 mHandler->loadSDP(desc);
509 }
510 }
511
512 if (err != OK) {
513 mState = DISCONNECTED;
514 mFinalResult = err;
515
516 if (mDisconnectReplyID != 0) {
517 finishDisconnectIfPossible();
518 }
519 }
520}
521
Andreas Huber2bfdd422011-10-11 15:24:07 -0700522void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
523 status_t err;
524 CHECK(msg->findInt32("result", &err));
525 CHECK_NE(err, (status_t)OK);
526
527 mLooper->unregisterHandler(mHandler->id());
528 mHandler.clear();
529
530 mState = DISCONNECTED;
531 mFinalResult = err;
532
533 if (mDisconnectReplyID != 0) {
534 finishDisconnectIfPossible();
535 }
536}
537
538void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
539 if (mState != DISCONNECTED) {
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100540 if (mHandler != NULL) {
541 mHandler->disconnect();
542 } else if (mSDPLoader != NULL) {
543 mSDPLoader->cancel();
544 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700545 return;
546 }
547
548 (new AMessage)->postReply(mDisconnectReplyID);
549 mDisconnectReplyID = 0;
550}
551
552} // namespace android