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