• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
25 
26 #include <media/stagefright/MetaData.h>
27 
28 namespace android {
29 
RTSPSource(const char * url,const KeyedVector<String8,String8> * headers,bool uidValid,uid_t uid)30 NuPlayer::RTSPSource::RTSPSource(
31         const char *url,
32         const KeyedVector<String8, String8> *headers,
33         bool uidValid,
34         uid_t uid)
35     : mURL(url),
36       mUIDValid(uidValid),
37       mUID(uid),
38       mFlags(0),
39       mState(DISCONNECTED),
40       mFinalResult(OK),
41       mDisconnectReplyID(0),
42       mStartingUp(true),
43       mSeekGeneration(0) {
44     if (headers) {
45         mExtraHeaders = *headers;
46 
47         ssize_t index =
48             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
49 
50         if (index >= 0) {
51             mFlags |= kFlagIncognito;
52 
53             mExtraHeaders.removeItemsAt(index);
54         }
55     }
56 }
57 
~RTSPSource()58 NuPlayer::RTSPSource::~RTSPSource() {
59     if (mLooper != NULL) {
60         mLooper->stop();
61     }
62 }
63 
start()64 void NuPlayer::RTSPSource::start() {
65     if (mLooper == NULL) {
66         mLooper = new ALooper;
67         mLooper->setName("rtsp");
68         mLooper->start();
69 
70         mReflector = new AHandlerReflector<RTSPSource>(this);
71         mLooper->registerHandler(mReflector);
72     }
73 
74     CHECK(mHandler == NULL);
75 
76     sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
77 
78     mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
79     mLooper->registerHandler(mHandler);
80 
81     CHECK_EQ(mState, (int)DISCONNECTED);
82     mState = CONNECTING;
83 
84     mHandler->connect();
85 }
86 
stop()87 void NuPlayer::RTSPSource::stop() {
88     sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
89 
90     sp<AMessage> dummy;
91     msg->postAndAwaitResponse(&dummy);
92 }
93 
feedMoreTSData()94 status_t NuPlayer::RTSPSource::feedMoreTSData() {
95     return mFinalResult;
96 }
97 
getFormat(bool audio)98 sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) {
99     sp<AnotherPacketSource> source = getSource(audio);
100 
101     if (source == NULL) {
102         return NULL;
103     }
104 
105     return source->getFormat();
106 }
107 
haveSufficientDataOnAllTracks()108 bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
109     // We're going to buffer at least 2 secs worth data on all tracks before
110     // starting playback (both at startup and after a seek).
111 
112     static const int64_t kMinDurationUs = 2000000ll;
113 
114     status_t err;
115     int64_t durationUs;
116     if (mAudioTrack != NULL
117             && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
118                     < kMinDurationUs
119             && err == OK) {
120         ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
121               durationUs / 1E6);
122         return false;
123     }
124 
125     if (mVideoTrack != NULL
126             && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
127                     < kMinDurationUs
128             && err == OK) {
129         ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
130               durationUs / 1E6);
131         return false;
132     }
133 
134     return true;
135 }
136 
dequeueAccessUnit(bool audio,sp<ABuffer> * accessUnit)137 status_t NuPlayer::RTSPSource::dequeueAccessUnit(
138         bool audio, sp<ABuffer> *accessUnit) {
139     if (mStartingUp) {
140         if (!haveSufficientDataOnAllTracks()) {
141             return -EWOULDBLOCK;
142         }
143 
144         mStartingUp = false;
145     }
146 
147     sp<AnotherPacketSource> source = getSource(audio);
148 
149     if (source == NULL) {
150         return -EWOULDBLOCK;
151     }
152 
153     status_t finalResult;
154     if (!source->hasBufferAvailable(&finalResult)) {
155         return finalResult == OK ? -EWOULDBLOCK : finalResult;
156     }
157 
158     return source->dequeueAccessUnit(accessUnit);
159 }
160 
getSource(bool audio)161 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
162     return audio ? mAudioTrack : mVideoTrack;
163 }
164 
getDuration(int64_t * durationUs)165 status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
166     *durationUs = 0ll;
167 
168     int64_t audioDurationUs;
169     if (mAudioTrack != NULL
170             && mAudioTrack->getFormat()->findInt64(
171                 kKeyDuration, &audioDurationUs)
172             && audioDurationUs > *durationUs) {
173         *durationUs = audioDurationUs;
174     }
175 
176     int64_t videoDurationUs;
177     if (mVideoTrack != NULL
178             && mVideoTrack->getFormat()->findInt64(
179                 kKeyDuration, &videoDurationUs)
180             && videoDurationUs > *durationUs) {
181         *durationUs = videoDurationUs;
182     }
183 
184     return OK;
185 }
186 
seekTo(int64_t seekTimeUs)187 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
188     sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
189     msg->setInt32("generation", ++mSeekGeneration);
190     msg->setInt64("timeUs", seekTimeUs);
191     msg->post(200000ll);
192 
193     return OK;
194 }
195 
performSeek(int64_t seekTimeUs)196 void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
197     if (mState != CONNECTED) {
198         return;
199     }
200 
201     mState = SEEKING;
202     mHandler->seek(seekTimeUs);
203 }
204 
isSeekable()205 bool NuPlayer::RTSPSource::isSeekable() {
206     return true;
207 }
208 
onMessageReceived(const sp<AMessage> & msg)209 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
210     if (msg->what() == kWhatDisconnect) {
211         uint32_t replyID;
212         CHECK(msg->senderAwaitsResponse(&replyID));
213 
214         mDisconnectReplyID = replyID;
215         finishDisconnectIfPossible();
216         return;
217     } else if (msg->what() == kWhatPerformSeek) {
218         int32_t generation;
219         CHECK(msg->findInt32("generation", &generation));
220 
221         if (generation != mSeekGeneration) {
222             // obsolete.
223             return;
224         }
225 
226         int64_t seekTimeUs;
227         CHECK(msg->findInt64("timeUs", &seekTimeUs));
228 
229         performSeek(seekTimeUs);
230         return;
231     }
232 
233     CHECK_EQ(msg->what(), (int)kWhatNotify);
234 
235     int32_t what;
236     CHECK(msg->findInt32("what", &what));
237 
238     switch (what) {
239         case MyHandler::kWhatConnected:
240             onConnected();
241             break;
242 
243         case MyHandler::kWhatDisconnected:
244             onDisconnected(msg);
245             break;
246 
247         case MyHandler::kWhatSeekDone:
248         {
249             mState = CONNECTED;
250             mStartingUp = true;
251             break;
252         }
253 
254         case MyHandler::kWhatAccessUnit:
255         {
256             size_t trackIndex;
257             CHECK(msg->findSize("trackIndex", &trackIndex));
258             CHECK_LT(trackIndex, mTracks.size());
259 
260             sp<ABuffer> accessUnit;
261             CHECK(msg->findBuffer("accessUnit", &accessUnit));
262 
263             int32_t damaged;
264             if (accessUnit->meta()->findInt32("damaged", &damaged)
265                     && damaged) {
266                 ALOGI("dropping damaged access unit.");
267                 break;
268             }
269 
270             TrackInfo *info = &mTracks.editItemAt(trackIndex);
271 
272             sp<AnotherPacketSource> source = info->mSource;
273             if (source != NULL) {
274                 uint32_t rtpTime;
275                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
276 
277                 if (!info->mNPTMappingValid) {
278                     // This is a live stream, we didn't receive any normal
279                     // playtime mapping. We won't map to npt time.
280                     source->queueAccessUnit(accessUnit);
281                     break;
282                 }
283 
284                 int64_t nptUs =
285                     ((double)rtpTime - (double)info->mRTPTime)
286                         / info->mTimeScale
287                         * 1000000ll
288                         + info->mNormalPlaytimeUs;
289 
290                 accessUnit->meta()->setInt64("timeUs", nptUs);
291 
292                 source->queueAccessUnit(accessUnit);
293             }
294             break;
295         }
296 
297         case MyHandler::kWhatEOS:
298         {
299             size_t trackIndex;
300             CHECK(msg->findSize("trackIndex", &trackIndex));
301             CHECK_LT(trackIndex, mTracks.size());
302 
303             int32_t finalResult;
304             CHECK(msg->findInt32("finalResult", &finalResult));
305             CHECK_NE(finalResult, (status_t)OK);
306 
307             TrackInfo *info = &mTracks.editItemAt(trackIndex);
308             sp<AnotherPacketSource> source = info->mSource;
309             if (source != NULL) {
310                 source->signalEOS(finalResult);
311             }
312 
313             break;
314         }
315 
316         case MyHandler::kWhatSeekDiscontinuity:
317         {
318             size_t trackIndex;
319             CHECK(msg->findSize("trackIndex", &trackIndex));
320             CHECK_LT(trackIndex, mTracks.size());
321 
322             TrackInfo *info = &mTracks.editItemAt(trackIndex);
323             sp<AnotherPacketSource> source = info->mSource;
324             if (source != NULL) {
325                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
326             }
327 
328             break;
329         }
330 
331         case MyHandler::kWhatNormalPlayTimeMapping:
332         {
333             size_t trackIndex;
334             CHECK(msg->findSize("trackIndex", &trackIndex));
335             CHECK_LT(trackIndex, mTracks.size());
336 
337             uint32_t rtpTime;
338             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
339 
340             int64_t nptUs;
341             CHECK(msg->findInt64("nptUs", &nptUs));
342 
343             TrackInfo *info = &mTracks.editItemAt(trackIndex);
344             info->mRTPTime = rtpTime;
345             info->mNormalPlaytimeUs = nptUs;
346             info->mNPTMappingValid = true;
347             break;
348         }
349 
350         default:
351             TRESPASS();
352     }
353 }
354 
onConnected()355 void NuPlayer::RTSPSource::onConnected() {
356     CHECK(mAudioTrack == NULL);
357     CHECK(mVideoTrack == NULL);
358 
359     size_t numTracks = mHandler->countTracks();
360     for (size_t i = 0; i < numTracks; ++i) {
361         int32_t timeScale;
362         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
363 
364         const char *mime;
365         CHECK(format->findCString(kKeyMIMEType, &mime));
366 
367         bool isAudio = !strncasecmp(mime, "audio/", 6);
368         bool isVideo = !strncasecmp(mime, "video/", 6);
369 
370         TrackInfo info;
371         info.mTimeScale = timeScale;
372         info.mRTPTime = 0;
373         info.mNormalPlaytimeUs = 0ll;
374         info.mNPTMappingValid = false;
375 
376         if ((isAudio && mAudioTrack == NULL)
377                 || (isVideo && mVideoTrack == NULL)) {
378             sp<AnotherPacketSource> source = new AnotherPacketSource(format);
379 
380             if (isAudio) {
381                 mAudioTrack = source;
382             } else {
383                 mVideoTrack = source;
384             }
385 
386             info.mSource = source;
387         }
388 
389         mTracks.push(info);
390     }
391 
392     mState = CONNECTED;
393 }
394 
onDisconnected(const sp<AMessage> & msg)395 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
396     status_t err;
397     CHECK(msg->findInt32("result", &err));
398     CHECK_NE(err, (status_t)OK);
399 
400     mLooper->unregisterHandler(mHandler->id());
401     mHandler.clear();
402 
403     mState = DISCONNECTED;
404     mFinalResult = err;
405 
406     if (mDisconnectReplyID != 0) {
407         finishDisconnectIfPossible();
408     }
409 }
410 
finishDisconnectIfPossible()411 void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
412     if (mState != DISCONNECTED) {
413         mHandler->disconnect();
414         return;
415     }
416 
417     (new AMessage)->postReply(mDisconnectReplyID);
418     mDisconnectReplyID = 0;
419 }
420 
421 }  // namespace android
422