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