|
44 | 44 |
|
45 | 45 | // If no access units are received within 5 secs, assume that the rtp |
46 | 46 | // stream has ended and signal end of stream. |
47 | | -static int64_t kAccessUnitTimeoutUs = 5000000ll; |
| 47 | +static int64_t kAccessUnitTimeoutUs = 10000000ll; |
48 | 48 |
|
49 | 49 | // If no access units arrive for the first 10 secs after starting the |
50 | 50 | // stream, assume none ever will and signal EOS or switch transports. |
51 | 51 | static int64_t kStartupTimeoutUs = 10000000ll; |
52 | 52 |
|
| 53 | +static int64_t kDefaultKeepAliveTimeoutUs = 60000000ll; |
| 54 | + |
53 | 55 | namespace android { |
54 | 56 |
|
55 | 57 | static void MakeUserAgentString(AString *s) { |
@@ -130,7 +132,9 @@ struct MyHandler : public AHandler { |
130 | 132 | mTryFakeRTCP(false), |
131 | 133 | mReceivedFirstRTCPPacket(false), |
132 | 134 | mReceivedFirstRTPPacket(false), |
133 | | - mSeekable(false) { |
| 135 | + mSeekable(false), |
| 136 | + mKeepAliveTimeoutUs(kDefaultKeepAliveTimeoutUs), |
| 137 | + mKeepAliveGeneration(0) { |
134 | 138 | mNetLooper->setName("rtsp net"); |
135 | 139 | mNetLooper->start(false /* runOnCallingThread */, |
136 | 140 | false /* canCallJava */, |
@@ -371,6 +375,8 @@ struct MyHandler : public AHandler { |
371 | 375 |
|
372 | 376 | case 'disc': |
373 | 377 | { |
| 378 | + ++mKeepAliveGeneration; |
| 379 | + |
374 | 380 | int32_t reconnect; |
375 | 381 | if (msg->findInt32("reconnect", &reconnect) && reconnect) { |
376 | 382 | sp<AMessage> reply = new AMessage('conn', id()); |
@@ -502,6 +508,34 @@ struct MyHandler : public AHandler { |
502 | 508 | CHECK_GE(i, 0); |
503 | 509 |
|
504 | 510 | mSessionID = response->mHeaders.valueAt(i); |
| 511 | + |
| 512 | + mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs; |
| 513 | + AString timeoutStr; |
| 514 | + if (GetAttribute( |
| 515 | + mSessionID.c_str(), "timeout", &timeoutStr)) { |
| 516 | + char *end; |
| 517 | + unsigned long timeoutSecs = |
| 518 | + strtoul(timeoutStr.c_str(), &end, 10); |
| 519 | + |
| 520 | + if (end == timeoutStr.c_str() || *end != '\0') { |
| 521 | + LOGW("server specified malformed timeout '%s'", |
| 522 | + timeoutStr.c_str()); |
| 523 | + |
| 524 | + mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs; |
| 525 | + } else if (timeoutSecs < 15) { |
| 526 | + LOGW("server specified too short a timeout " |
| 527 | + "(%lu secs), using default.", |
| 528 | + timeoutSecs); |
| 529 | + |
| 530 | + mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs; |
| 531 | + } else { |
| 532 | + mKeepAliveTimeoutUs = timeoutSecs * 1000000ll; |
| 533 | + |
| 534 | + LOGI("server specified timeout of %lu secs.", |
| 535 | + timeoutSecs); |
| 536 | + } |
| 537 | + } |
| 538 | + |
505 | 539 | i = mSessionID.find(";"); |
506 | 540 | if (i >= 0) { |
507 | 541 | // Remove options, i.e. ";timeout=90" |
@@ -555,6 +589,9 @@ struct MyHandler : public AHandler { |
555 | 589 | if (index < mSessionDesc->countTracks()) { |
556 | 590 | setupTrack(index); |
557 | 591 | } else if (mSetupTracksSuccessful) { |
| 592 | + ++mKeepAliveGeneration; |
| 593 | + postKeepAlive(); |
| 594 | + |
558 | 595 | AString request = "PLAY "; |
559 | 596 | request.append(mSessionURL); |
560 | 597 | request.append(" RTSP/1.0\r\n"); |
@@ -606,6 +643,51 @@ struct MyHandler : public AHandler { |
606 | 643 | break; |
607 | 644 | } |
608 | 645 |
|
| 646 | + case 'aliv': |
| 647 | + { |
| 648 | + int32_t generation; |
| 649 | + CHECK(msg->findInt32("generation", &generation)); |
| 650 | + |
| 651 | + if (generation != mKeepAliveGeneration) { |
| 652 | + // obsolete event. |
| 653 | + break; |
| 654 | + } |
| 655 | + |
| 656 | + AString request; |
| 657 | + request.append("OPTIONS "); |
| 658 | + request.append(mSessionURL); |
| 659 | + request.append(" RTSP/1.0\r\n"); |
| 660 | + request.append("Session: "); |
| 661 | + request.append(mSessionID); |
| 662 | + request.append("\r\n"); |
| 663 | + request.append("\r\n"); |
| 664 | + |
| 665 | + sp<AMessage> reply = new AMessage('opts', id()); |
| 666 | + reply->setInt32("generation", mKeepAliveGeneration); |
| 667 | + mConn->sendRequest(request.c_str(), reply); |
| 668 | + break; |
| 669 | + } |
| 670 | + |
| 671 | + case 'opts': |
| 672 | + { |
| 673 | + int32_t result; |
| 674 | + CHECK(msg->findInt32("result", &result)); |
| 675 | + |
| 676 | + LOGI("OPTIONS completed with result %d (%s)", |
| 677 | + result, strerror(-result)); |
| 678 | + |
| 679 | + int32_t generation; |
| 680 | + CHECK(msg->findInt32("generation", &generation)); |
| 681 | + |
| 682 | + if (generation != mKeepAliveGeneration) { |
| 683 | + // obsolete event. |
| 684 | + break; |
| 685 | + } |
| 686 | + |
| 687 | + postKeepAlive(); |
| 688 | + break; |
| 689 | + } |
| 690 | + |
609 | 691 | case 'abor': |
610 | 692 | { |
611 | 693 | for (size_t i = 0; i < mTracks.size(); ++i) { |
@@ -952,6 +1034,12 @@ struct MyHandler : public AHandler { |
952 | 1034 | } |
953 | 1035 | } |
954 | 1036 |
|
| 1037 | + void postKeepAlive() { |
| 1038 | + sp<AMessage> msg = new AMessage('aliv', id()); |
| 1039 | + msg->setInt32("generation", mKeepAliveGeneration); |
| 1040 | + msg->post((mKeepAliveTimeoutUs * 9) / 10); |
| 1041 | + } |
| 1042 | + |
955 | 1043 | void postAccessUnitTimeoutCheck() { |
956 | 1044 | if (mCheckPending) { |
957 | 1045 | return; |
@@ -1120,6 +1208,8 @@ struct MyHandler : public AHandler { |
1120 | 1208 | bool mReceivedFirstRTCPPacket; |
1121 | 1209 | bool mReceivedFirstRTPPacket; |
1122 | 1210 | bool mSeekable; |
| 1211 | + int64_t mKeepAliveTimeoutUs; |
| 1212 | + int32_t mKeepAliveGeneration; |
1123 | 1213 |
|
1124 | 1214 | Vector<TrackInfo> mTracks; |
1125 | 1215 |
|
|
0 commit comments