blob: b1901e85639813fc0b91db792df426f82cf628ab [file] [log] [blame]
Byeongjo Parkd157b792019-01-24 20:56:37 +09001/*
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 "RTPSource"
19#include <utils/Log.h>
20
21#include "RTPSource.h"
22
23
24
25
26#include <media/stagefright/MediaDefs.h>
27#include <media/stagefright/MetaData.h>
28#include <string.h>
29
30namespace android {
31
32const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs
33static int32_t kMaxAllowedStaleAccessUnits = 20;
34
35NuPlayer::RTPSource::RTPSource(
36 const sp<AMessage> &notify,
37 const String8& rtpParams)
38 : Source(notify),
39 mRTPParams(rtpParams),
40 mFlags(0),
41 mState(DISCONNECTED),
42 mFinalResult(OK),
43 mBuffering(false),
44 mInPreparationPhase(true),
Kim Sungyeon2c987f12019-03-17 22:04:14 +090045 mRTPConn(new ARTPConnection(ARTPConnection::kViLTEConnection)),
Byeongjo Parkd157b792019-01-24 20:56:37 +090046 mEOSTimeoutAudio(0),
Byeongjo Parkb0225aa2018-04-20 14:00:15 +090047 mEOSTimeoutVideo(0),
48 mLastCVOUpdated(-1) {
Byeongjo Parkd157b792019-01-24 20:56:37 +090049 ALOGD("RTPSource initialized with rtpParams=%s", rtpParams.string());
50}
51
52NuPlayer::RTPSource::~RTPSource() {
53 if (mLooper != NULL) {
54 mLooper->unregisterHandler(id());
55 mLooper->unregisterHandler(mRTPConn->id());
56 mLooper->stop();
57 }
58}
59
60status_t NuPlayer::RTPSource::getBufferingSettings(
61 BufferingSettings* buffering /* nonnull */) {
62 Mutex::Autolock _l(mBufferingSettingsLock);
63 *buffering = mBufferingSettings;
64 return OK;
65}
66
67status_t NuPlayer::RTPSource::setBufferingSettings(const BufferingSettings& buffering) {
68 Mutex::Autolock _l(mBufferingSettingsLock);
69 mBufferingSettings = buffering;
70 return OK;
71}
72
73void NuPlayer::RTPSource::prepareAsync() {
74 if (mLooper == NULL) {
75 mLooper = new ALooper;
76 mLooper->setName("rtp");
77 mLooper->start();
78
79 mLooper->registerHandler(this);
80 mLooper->registerHandler(mRTPConn);
81 }
82
Lajos Molnar19829332020-03-17 08:13:10 -070083 CHECK_EQ(mState, (int)DISCONNECTED);
84 mState = CONNECTING;
85
Byeongjo Parkd157b792019-01-24 20:56:37 +090086 setParameters(mRTPParams);
87
88 TrackInfo *info = NULL;
89 unsigned i;
90 for (i = 0; i < mTracks.size(); i++) {
91 info = &mTracks.editItemAt(i);
92
93 if (info == NULL)
94 break;
95
96 AString sdp;
97 ASessionDescription::SDPStringFactory(sdp, info->mLocalIp,
98 info->mIsAudio, info->mLocalPort, info->mPayloadType, info->mAS, info->mCodecName,
Byeongjo Parkb0225aa2018-04-20 14:00:15 +090099 NULL, info->mWidth, info->mHeight, info->mCVOExtMap);
Byeongjo Parkd157b792019-01-24 20:56:37 +0900100 ALOGD("RTPSource SDP =>\n%s", sdp.c_str());
101
102 sp<ASessionDescription> desc = new ASessionDescription;
103 bool isValidSdp = desc->setTo(sdp.c_str(), sdp.size());
104 ALOGV("RTPSource isValidSdp => %d", isValidSdp);
105
106 int sockRtp, sockRtcp;
107 ARTPConnection::MakeRTPSocketPair(&sockRtp, &sockRtcp, info->mLocalIp, info->mRemoteIp,
Byeongjo Park88068dc2019-03-29 15:04:10 +0900108 info->mLocalPort, info->mRemotePort, info->mSocketNetwork);
Byeongjo Parkd157b792019-01-24 20:56:37 +0900109
110 sp<AMessage> notify = new AMessage('accu', this);
111
112 ALOGV("RTPSource addStream. track-index=%d", i);
113 notify->setSize("trackIndex", i);
114 // index(i) should be started from 1. 0 is reserved for [root]
115 mRTPConn->addStream(sockRtp, sockRtcp, desc, i + 1, notify, false);
Kim Sungyeond2875e92018-03-20 16:51:41 +0900116 mRTPConn->setSelfID(info->mSelfID);
Lajos Molnared809da2020-08-17 16:53:02 -0700117 mRTPConn->setJbTime(
118 (info->mJbTimeMs <= 3000 && info->mJbTimeMs >= 40) ? info->mJbTimeMs : 300);
Byeongjo Parkd157b792019-01-24 20:56:37 +0900119
120 info->mRTPSocket = sockRtp;
121 info->mRTCPSocket = sockRtcp;
122 info->mFirstSeqNumInSegment = 0;
123 info->mNewSegment = true;
124 info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
125 info->mRTPAnchor = 0;
126 info->mNTPAnchorUs = -1;
127 info->mNormalPlayTimeRTP = 0;
128 info->mNormalPlayTimeUs = 0ll;
129
130 // index(i) should be started from 1. 0 is reserved for [root]
131 info->mPacketSource = new APacketSource(desc, i + 1);
132
133 int32_t timeScale;
134 sp<MetaData> format = getTrackFormat(i, &timeScale);
135 sp<AnotherPacketSource> source = new AnotherPacketSource(format);
136
137 if (info->mIsAudio) {
138 mAudioTrack = source;
Byeongjo Park6b0bf0b2019-10-16 16:38:24 +0900139 info->mTimeScale = 16000;
Byeongjo Parkd157b792019-01-24 20:56:37 +0900140 } else {
141 mVideoTrack = source;
Byeongjo Park6b0bf0b2019-10-16 16:38:24 +0900142 info->mTimeScale = 90000;
Byeongjo Parkd157b792019-01-24 20:56:37 +0900143 }
144
145 info->mSource = source;
Byeongjo Park6b0bf0b2019-10-16 16:38:24 +0900146 info->mRTPTime = 0;
147 info->mNormalPlaytimeUs = 0;
148 info->mNPTMappingValid = false;
Byeongjo Parkd157b792019-01-24 20:56:37 +0900149 }
150
Byeongjo Parkd157b792019-01-24 20:56:37 +0900151 if (mInPreparationPhase) {
152 mInPreparationPhase = false;
153 notifyPrepared();
154 }
155}
156
157void NuPlayer::RTPSource::start() {
158}
159
160void NuPlayer::RTPSource::pause() {
161 mState = PAUSED;
162}
163
164void NuPlayer::RTPSource::resume() {
165 mState = CONNECTING;
166}
167
168void NuPlayer::RTPSource::stop() {
169 if (mLooper == NULL) {
170 return;
171 }
172 sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
173
174 sp<AMessage> dummy;
175 msg->postAndAwaitResponse(&dummy);
176}
177
178status_t NuPlayer::RTPSource::feedMoreTSData() {
179 Mutex::Autolock _l(mBufferingLock);
180 return mFinalResult;
181}
182
183sp<MetaData> NuPlayer::RTPSource::getFormatMeta(bool audio) {
184 sp<AnotherPacketSource> source = getSource(audio);
185
186 if (source == NULL) {
187 return NULL;
188 }
189
190 return source->getFormat();
191}
192
193bool NuPlayer::RTPSource::haveSufficientDataOnAllTracks() {
194 // We're going to buffer at least 2 secs worth data on all tracks before
195 // starting playback (both at startup and after a seek).
196
197 static const int64_t kMinDurationUs = 2000000ll;
198
199 int64_t mediaDurationUs = 0;
200 getDuration(&mediaDurationUs);
201 if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
202 || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
203 return true;
204 }
205
206 status_t err;
207 int64_t durationUs;
208 if (mAudioTrack != NULL
209 && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
210 < kMinDurationUs
211 && err == OK) {
212 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
213 durationUs / 1E6);
214 return false;
215 }
216
217 if (mVideoTrack != NULL
218 && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
219 < kMinDurationUs
220 && err == OK) {
221 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
222 durationUs / 1E6);
223 return false;
224 }
225
226 return true;
227}
228
229status_t NuPlayer::RTPSource::dequeueAccessUnit(
230 bool audio, sp<ABuffer> *accessUnit) {
231
232 sp<AnotherPacketSource> source = getSource(audio);
233
234 if (mState == PAUSED) {
235 ALOGV("-EWOULDBLOCK");
236 return -EWOULDBLOCK;
237 }
238
239 status_t finalResult;
240 if (!source->hasBufferAvailable(&finalResult)) {
241 if (finalResult == OK) {
242 int64_t mediaDurationUs = 0;
243 getDuration(&mediaDurationUs);
244 sp<AnotherPacketSource> otherSource = getSource(!audio);
245 status_t otherFinalResult;
246
247 // If other source already signaled EOS, this source should also signal EOS
248 if (otherSource != NULL &&
249 !otherSource->hasBufferAvailable(&otherFinalResult) &&
250 otherFinalResult == ERROR_END_OF_STREAM) {
251 source->signalEOS(ERROR_END_OF_STREAM);
252 return ERROR_END_OF_STREAM;
253 }
254
255 // If this source has detected near end, give it some time to retrieve more
256 // data before signaling EOS
257 if (source->isFinished(mediaDurationUs)) {
258 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
259 if (eosTimeout == 0) {
260 setEOSTimeout(audio, ALooper::GetNowUs());
261 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
262 setEOSTimeout(audio, 0);
263 source->signalEOS(ERROR_END_OF_STREAM);
264 return ERROR_END_OF_STREAM;
265 }
266 return -EWOULDBLOCK;
267 }
268
269 if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
270 // We should not enter buffering mode
271 // if any of the sources already have detected EOS.
272 // TODO: needs to be checked whether below line is needed or not.
273 // startBufferingIfNecessary();
274 }
275
276 return -EWOULDBLOCK;
277 }
278 return finalResult;
279 }
280
281 setEOSTimeout(audio, 0);
282
Byeongjo Parkb0225aa2018-04-20 14:00:15 +0900283 finalResult = source->dequeueAccessUnit(accessUnit);
284 if (finalResult != OK) {
285 return finalResult;
286 }
287
288 int32_t cvo;
Byeongjo Park0aedeb32019-05-20 13:15:04 +0900289 if ((*accessUnit) != NULL && (*accessUnit)->meta()->findInt32("cvo", &cvo) &&
290 cvo != mLastCVOUpdated) {
291 sp<AMessage> msg = new AMessage();
292 msg->setInt32("payload-type", NuPlayer::RTPSource::RTP_CVO);
293 msg->setInt32("cvo", cvo);
Byeongjo Parkb0225aa2018-04-20 14:00:15 +0900294
Byeongjo Park0aedeb32019-05-20 13:15:04 +0900295 sp<AMessage> notify = dupNotify();
296 notify->setInt32("what", kWhatIMSRxNotice);
297 notify->setMessage("message", msg);
298 notify->post();
Byeongjo Parkb0225aa2018-04-20 14:00:15 +0900299
Byeongjo Park0aedeb32019-05-20 13:15:04 +0900300 ALOGV("notify cvo updated (%d)->(%d) to upper layer", mLastCVOUpdated, cvo);
301 mLastCVOUpdated = cvo;
Byeongjo Parkb0225aa2018-04-20 14:00:15 +0900302 }
303
304 return finalResult;
Byeongjo Parkd157b792019-01-24 20:56:37 +0900305}
306
307sp<AnotherPacketSource> NuPlayer::RTPSource::getSource(bool audio) {
308 return audio ? mAudioTrack : mVideoTrack;
309}
310
311void NuPlayer::RTPSource::setEOSTimeout(bool audio, int64_t timeout) {
312 if (audio) {
313 mEOSTimeoutAudio = timeout;
314 } else {
315 mEOSTimeoutVideo = timeout;
316 }
317}
318
319status_t NuPlayer::RTPSource::getDuration(int64_t *durationUs) {
320 *durationUs = 0ll;
321
322 int64_t audioDurationUs;
323 if (mAudioTrack != NULL
324 && mAudioTrack->getFormat()->findInt64(
325 kKeyDuration, &audioDurationUs)
326 && audioDurationUs > *durationUs) {
327 *durationUs = audioDurationUs;
328 }
329
330 int64_t videoDurationUs;
331 if (mVideoTrack != NULL
332 && mVideoTrack->getFormat()->findInt64(
333 kKeyDuration, &videoDurationUs)
334 && videoDurationUs > *durationUs) {
335 *durationUs = videoDurationUs;
336 }
337
338 return OK;
339}
340
341status_t NuPlayer::RTPSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
342 ALOGV("RTPSource::seekTo=%d, mode=%d", (int)seekTimeUs, mode);
343 return OK;
344}
345
346void NuPlayer::RTPSource::schedulePollBuffering() {
347 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
Lajos Molnar19829332020-03-17 08:13:10 -0700348 msg->post(kBufferingPollIntervalUs); // 1 second intervals
Byeongjo Parkd157b792019-01-24 20:56:37 +0900349}
350
351void NuPlayer::RTPSource::onPollBuffering() {
352 schedulePollBuffering();
353}
354
Byeongjo Park6b0bf0b2019-10-16 16:38:24 +0900355bool NuPlayer::RTPSource::isRealTime() const {
356 ALOGD("RTPSource::isRealTime=%d", true);
357 return true;
358}
359
Byeongjo Parkd157b792019-01-24 20:56:37 +0900360void NuPlayer::RTPSource::onMessageReceived(const sp<AMessage> &msg) {
361 ALOGV("onMessageReceived =%d", msg->what());
362
363 switch (msg->what()) {
364 case kWhatAccessUnitComplete:
365 {
366 if (mState == CONNECTING) {
367 mState = CONNECTED;
368 }
369
370 int32_t timeUpdate;
371 //"time-update" raised from ARTPConnection::parseSR()
372 if (msg->findInt32("time-update", &timeUpdate) && timeUpdate) {
373 size_t trackIndex;
374 CHECK(msg->findSize("trackIndex", &trackIndex));
375
376 uint32_t rtpTime;
377 uint64_t ntpTime;
378 CHECK(msg->findInt32("rtp-time", (int32_t *)&rtpTime));
379 CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
380
381 onTimeUpdate(trackIndex, rtpTime, ntpTime);
382 break;
383 }
384
385 int32_t firstRTCP;
386 if (msg->findInt32("first-rtcp", &firstRTCP)) {
387 // There won't be an access unit here, it's just a notification
388 // that the data communication worked since we got the first
389 // rtcp packet.
390 ALOGV("first-rtcp");
391 break;
392 }
393
Kim Sungyeond3c6b322018-03-02 14:41:19 +0900394 int32_t IMSRxNotice;
Byeongjo Park73f6fc82018-08-23 16:19:58 +0900395 if (msg->findInt32("rtcp-event", &IMSRxNotice)) {
Kim Sungyeond3c6b322018-03-02 14:41:19 +0900396 int32_t payloadType, feedbackType;
397 CHECK(msg->findInt32("payload-type", &payloadType));
398 CHECK(msg->findInt32("feedback-type", &feedbackType));
399
400 sp<AMessage> notify = dupNotify();
401 notify->setInt32("what", kWhatIMSRxNotice);
402 notify->setMessage("message", msg);
403 notify->post();
404
405 ALOGV("IMSRxNotice \t\t payload : %d feedback : %d",
406 payloadType, feedbackType);
407 break;
408 }
409
Byeongjo Parkd157b792019-01-24 20:56:37 +0900410 size_t trackIndex;
411 CHECK(msg->findSize("trackIndex", &trackIndex));
412
413 sp<ABuffer> accessUnit;
414 if (msg->findBuffer("access-unit", &accessUnit) == false) {
415 break;
416 }
417
418 int32_t damaged;
419 if (accessUnit->meta()->findInt32("damaged", &damaged)
420 && damaged) {
421 ALOGD("dropping damaged access unit.");
422 break;
423 }
424
Lajos Molnar19829332020-03-17 08:13:10 -0700425 // Implicitly assert on valid trackIndex here, which we ensure by
426 // never removing tracks.
Byeongjo Parkd157b792019-01-24 20:56:37 +0900427 TrackInfo *info = &mTracks.editItemAt(trackIndex);
428
429 sp<AnotherPacketSource> source = info->mSource;
430 if (source != NULL) {
431 uint32_t rtpTime;
432 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
433
434 /* AnotherPacketSource make an assertion if there is no ntp provided
435 RTPSource should provide ntpUs all the times.
436 if (!info->mNPTMappingValid) {
437 // This is a live stream, we didn't receive any normal
438 // playtime mapping. We won't map to npt time.
439 source->queueAccessUnit(accessUnit);
440 break;
441 }
Byeongjo Parkd157b792019-01-24 20:56:37 +0900442
443 int64_t nptUs =
444 ((double)rtpTime - (double)info->mRTPTime)
445 / info->mTimeScale
446 * 1000000ll
447 + info->mNormalPlaytimeUs;
448
Byeongjo Park6b0bf0b2019-10-16 16:38:24 +0900449 */
450 accessUnit->meta()->setInt64("timeUs", ALooper::GetNowUs());
Byeongjo Parkd157b792019-01-24 20:56:37 +0900451
452 source->queueAccessUnit(accessUnit);
453 }
454
455 break;
456 }
457 case kWhatDisconnect:
458 {
459 sp<AReplyToken> replyID;
460 CHECK(msg->senderAwaitsResponse(&replyID));
461
462 for (size_t i = 0; i < mTracks.size(); ++i) {
463 TrackInfo *info = &mTracks.editItemAt(i);
464
465 if (info->mIsAudio) {
466 mAudioTrack->signalEOS(ERROR_END_OF_STREAM);
467 mAudioTrack = NULL;
468 ALOGV("mAudioTrack disconnected");
469 } else {
470 mVideoTrack->signalEOS(ERROR_END_OF_STREAM);
471 mVideoTrack = NULL;
472 ALOGV("mVideoTrack disconnected");
473 }
474
475 mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
476 close(info->mRTPSocket);
477 close(info->mRTCPSocket);
478 }
479
480 mTracks.clear();
481 mFirstAccessUnit = true;
482 mAllTracksHaveTime = false;
483 mNTPAnchorUs = -1;
484 mMediaAnchorUs = -1;
485 mLastMediaTimeUs = -1;
486 mNumAccessUnitsReceived = 0;
487 mReceivedFirstRTCPPacket = false;
488 mReceivedFirstRTPPacket = false;
489 mPausing = false;
490 mPauseGeneration = 0;
491
492 (new AMessage)->postReply(replyID);
493
494 break;
495 }
496 case kWhatPollBuffering:
497 break;
498 default:
499 TRESPASS();
500 }
501}
502
Kim Sungyeon23b23932019-07-18 17:48:32 +0900503void NuPlayer::RTPSource::setTargetBitrate(int32_t bitrate) {
504 mRTPConn->setTargetBitrate(bitrate);
505}
506
Byeongjo Parkd157b792019-01-24 20:56:37 +0900507void NuPlayer::RTPSource::onTimeUpdate(int32_t trackIndex, uint32_t rtpTime, uint64_t ntpTime) {
508 ALOGV("onTimeUpdate track %d, rtpTime = 0x%08x, ntpTime = %#016llx",
509 trackIndex, rtpTime, (long long)ntpTime);
510
Lajos Molnar19829332020-03-17 08:13:10 -0700511 // convert ntpTime in Q32 seconds to microseconds. Note: this will not lose precision
512 // because ntpTimeUs is at most 52 bits (double holds 53 bits)
Byeongjo Parkd157b792019-01-24 20:56:37 +0900513 int64_t ntpTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
514
515 TrackInfo *track = &mTracks.editItemAt(trackIndex);
516
517 track->mRTPAnchor = rtpTime;
518 track->mNTPAnchorUs = ntpTimeUs;
519
520 if (mNTPAnchorUs < 0) {
521 mNTPAnchorUs = ntpTimeUs;
522 mMediaAnchorUs = mLastMediaTimeUs;
523 }
524
525 if (!mAllTracksHaveTime) {
526 bool allTracksHaveTime = (mTracks.size() > 0);
527 for (size_t i = 0; i < mTracks.size(); ++i) {
528 TrackInfo *track = &mTracks.editItemAt(i);
529 if (track->mNTPAnchorUs < 0) {
530 allTracksHaveTime = false;
531 break;
532 }
533 }
534 if (allTracksHaveTime) {
535 mAllTracksHaveTime = true;
536 ALOGI("Time now established for all tracks.");
537 }
538 }
539 if (mAllTracksHaveTime && dataReceivedOnAllChannels()) {
540 // Time is now established, lets start timestamping immediately
541 for (size_t i = 0; i < mTracks.size(); ++i) {
542 TrackInfo *trackInfo = &mTracks.editItemAt(i);
543 while (!trackInfo->mPackets.empty()) {
544 sp<ABuffer> accessUnit = *trackInfo->mPackets.begin();
545 trackInfo->mPackets.erase(trackInfo->mPackets.begin());
546
547 if (addMediaTimestamp(i, trackInfo, accessUnit)) {
548 postQueueAccessUnit(i, accessUnit);
549 }
550 }
551 }
552 }
553}
554
555bool NuPlayer::RTPSource::addMediaTimestamp(
556 int32_t trackIndex, const TrackInfo *track,
557 const sp<ABuffer> &accessUnit) {
558
559 uint32_t rtpTime;
560 CHECK(accessUnit->meta()->findInt32(
561 "rtp-time", (int32_t *)&rtpTime));
562
563 int64_t relRtpTimeUs =
564 (((int64_t)rtpTime - (int64_t)track->mRTPAnchor) * 1000000ll)
565 / track->mTimeScale;
566
567 int64_t ntpTimeUs = track->mNTPAnchorUs + relRtpTimeUs;
568
569 int64_t mediaTimeUs = mMediaAnchorUs + ntpTimeUs - mNTPAnchorUs;
570
571 if (mediaTimeUs > mLastMediaTimeUs) {
572 mLastMediaTimeUs = mediaTimeUs;
573 }
574
575 if (mediaTimeUs < 0) {
576 ALOGV("dropping early accessUnit.");
577 return false;
578 }
579
580 ALOGV("track %d rtpTime=%u mediaTimeUs = %lld us (%.2f secs)",
581 trackIndex, rtpTime, (long long)mediaTimeUs, mediaTimeUs / 1E6);
582
583 accessUnit->meta()->setInt64("timeUs", mediaTimeUs);
584
585 return true;
586}
587
588bool NuPlayer::RTPSource::dataReceivedOnAllChannels() {
589 TrackInfo *track;
590 for (size_t i = 0; i < mTracks.size(); ++i) {
591 track = &mTracks.editItemAt(i);
592 if (track->mPackets.empty()) {
593 return false;
594 }
595 }
596 return true;
597}
598
599void NuPlayer::RTPSource::postQueueAccessUnit(
600 size_t trackIndex, const sp<ABuffer> &accessUnit) {
601 sp<AMessage> msg = new AMessage(kWhatAccessUnit, this);
602 msg->setInt32("what", kWhatAccessUnit);
603 msg->setSize("trackIndex", trackIndex);
604 msg->setBuffer("accessUnit", accessUnit);
605 msg->post();
606}
607
608void NuPlayer::RTPSource::postQueueEOS(size_t trackIndex, status_t finalResult) {
609 sp<AMessage> msg = new AMessage(kWhatEOS, this);
610 msg->setInt32("what", kWhatEOS);
611 msg->setSize("trackIndex", trackIndex);
612 msg->setInt32("finalResult", finalResult);
613 msg->post();
614}
615
616sp<MetaData> NuPlayer::RTPSource::getTrackFormat(size_t index, int32_t *timeScale) {
617 CHECK_GE(index, 0u);
618 CHECK_LT(index, mTracks.size());
619
620 const TrackInfo &info = mTracks.itemAt(index);
621
622 *timeScale = info.mTimeScale;
623
624 return info.mPacketSource->getFormat();
625}
626
627void NuPlayer::RTPSource::onConnected() {
628 ALOGV("onConnected");
629 mState = CONNECTED;
630}
631
632void NuPlayer::RTPSource::onDisconnected(const sp<AMessage> &msg) {
633 if (mState == DISCONNECTED) {
634 return;
635 }
636
637 status_t err;
638 CHECK(msg->findInt32("result", &err));
639 CHECK_NE(err, (status_t)OK);
640
641// mLooper->unregisterHandler(mHandler->id());
642// mHandler.clear();
643
644 if (mState == CONNECTING) {
645 // We're still in the preparation phase, signal that it
646 // failed.
647 notifyPrepared(err);
648 }
649
650 mState = DISCONNECTED;
651// setError(err);
652
653}
654
655status_t NuPlayer::RTPSource::setParameter(const String8 &key, const String8 &value) {
656 ALOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
657
658 bool isAudioKey = key.contains("audio");
659 TrackInfo *info = NULL;
660 for (unsigned i = 0; i < mTracks.size(); ++i) {
661 info = &mTracks.editItemAt(i);
662 if (info != NULL && info->mIsAudio == isAudioKey) {
663 ALOGV("setParameter: %s track (%d) found", isAudioKey ? "audio" : "video" , i);
664 break;
665 }
666 }
667
668 if (info == NULL) {
669 TrackInfo newTrackInfo;
670 newTrackInfo.mIsAudio = isAudioKey;
671 mTracks.push(newTrackInfo);
672 info = &mTracks.editTop();
Lajos Molnared809da2020-08-17 16:53:02 -0700673 info->mJbTimeMs = 300;
Byeongjo Parkd157b792019-01-24 20:56:37 +0900674 }
675
676 if (key == "rtp-param-mime-type") {
677 info->mMimeType = value;
678
679 const char *mime = value.string();
680 const char *delimiter = strchr(mime, '/');
Lajos Molnar19829332020-03-17 08:13:10 -0700681 info->mCodecName = delimiter ? (delimiter + 1) : "<none>";
Byeongjo Parkd157b792019-01-24 20:56:37 +0900682
683 ALOGV("rtp-param-mime-type: mMimeType (%s) => mCodecName (%s)",
Lajos Molnar19829332020-03-17 08:13:10 -0700684 info->mMimeType.string(), info->mCodecName.string());
Byeongjo Parkd157b792019-01-24 20:56:37 +0900685 } else if (key == "video-param-decoder-profile") {
686 info->mCodecProfile = atoi(value);
687 } else if (key == "video-param-decoder-level") {
688 info->mCodecLevel = atoi(value);
689 } else if (key == "video-param-width") {
690 info->mWidth = atoi(value);
691 } else if (key == "video-param-height") {
692 info->mHeight = atoi(value);
693 } else if (key == "rtp-param-local-ip") {
694 info->mLocalIp = value;
695 } else if (key == "rtp-param-local-port") {
696 info->mLocalPort = atoi(value);
697 } else if (key == "rtp-param-remote-ip") {
698 info->mRemoteIp = value;
699 } else if (key == "rtp-param-remote-port") {
700 info->mRemotePort = atoi(value);
701 } else if (key == "rtp-param-payload-type") {
702 info->mPayloadType = atoi(value);
703 } else if (key == "rtp-param-as") {
704 //AS means guaranteed bit rate that negotiated from sdp.
705 info->mAS = atoi(value);
706 } else if (key == "rtp-param-rtp-timeout") {
707 } else if (key == "rtp-param-rtcp-timeout") {
708 } else if (key == "rtp-param-time-scale") {
Kim Sungyeond2875e92018-03-20 16:51:41 +0900709 } else if (key == "rtp-param-self-id") {
710 info->mSelfID = atoi(value);
Byeongjo Parkb0225aa2018-04-20 14:00:15 +0900711 } else if (key == "rtp-param-ext-cvo-extmap") {
712 info->mCVOExtMap = atoi(value);
Byeongjo Park88068dc2019-03-29 15:04:10 +0900713 } else if (key == "rtp-param-set-socket-network") {
714 int64_t networkHandle = atoll(value);
715 setSocketNetwork(networkHandle);
Byeongjo Park7143c072019-09-23 13:31:37 +0900716 } else if (key == "rtp-param-jitter-buffer-time") {
Lajos Molnared809da2020-08-17 16:53:02 -0700717 info->mJbTimeMs = atoi(value);
Byeongjo Parkd157b792019-01-24 20:56:37 +0900718 }
719
720 return OK;
721}
722
723status_t NuPlayer::RTPSource::setParameters(const String8 &params) {
724 ALOGV("setParameters: %s", params.string());
725 const char *cparams = params.string();
726 const char *key_start = cparams;
727 for (;;) {
728 const char *equal_pos = strchr(key_start, '=');
729 if (equal_pos == NULL) {
730 ALOGE("Parameters %s miss a value", cparams);
731 return BAD_VALUE;
732 }
733 String8 key(key_start, equal_pos - key_start);
734 TrimString(&key);
735 if (key.length() == 0) {
736 ALOGE("Parameters %s contains an empty key", cparams);
737 return BAD_VALUE;
738 }
739 const char *value_start = equal_pos + 1;
740 const char *semicolon_pos = strchr(value_start, ';');
741 String8 value;
742 if (semicolon_pos == NULL) {
743 value.setTo(value_start);
744 } else {
745 value.setTo(value_start, semicolon_pos - value_start);
746 }
747 if (setParameter(key, value) != OK) {
748 return BAD_VALUE;
749 }
750 if (semicolon_pos == NULL) {
751 break; // Reaches the end
752 }
753 key_start = semicolon_pos + 1;
754 }
755 return OK;
756}
757
Byeongjo Park88068dc2019-03-29 15:04:10 +0900758void NuPlayer::RTPSource::setSocketNetwork(int64_t networkHandle) {
759 ALOGV("setSocketNetwork: %llu", (unsigned long long)networkHandle);
760
761 TrackInfo *info = NULL;
762 for (size_t i = 0; i < mTracks.size(); ++i) {
763 info = &mTracks.editItemAt(i);
764
765 if (info == NULL)
766 break;
767
768 info->mSocketNetwork = networkHandle;
769 }
770}
771
Byeongjo Parkd157b792019-01-24 20:56:37 +0900772// Trim both leading and trailing whitespace from the given string.
773//static
774void NuPlayer::RTPSource::TrimString(String8 *s) {
775 size_t num_bytes = s->bytes();
776 const char *data = s->string();
777
778 size_t leading_space = 0;
779 while (leading_space < num_bytes && isspace(data[leading_space])) {
780 ++leading_space;
781 }
782
783 size_t i = num_bytes;
784 while (i > leading_space && isspace(data[i - 1])) {
785 --i;
786 }
787
788 s->setTo(String8(&data[leading_space], i - leading_space));
789}
790
791} // namespace android