mirror of
https://github.com/rgaufman/live555.git
synced 2026-01-12 00:04:30 +08:00
Add max-inter-packet-gap-time to proxyServer
This commit is contained in:
254
Proxyserver_check_interPacketGap.patch
Normal file
254
Proxyserver_check_interPacketGap.patch
Normal file
@@ -0,0 +1,254 @@
|
||||
diff -pru livemedia.2016.09.22_org/liveMedia/include/ProxyServerMediaSession.hh livemedia.2016.09.22_noprints/liveMedia/include/ProxyServerMediaSession.hh
|
||||
--- livemedia.2016.09.22_org/liveMedia/include/ProxyServerMediaSession.hh 2016-09-23 00:53:55.000000000 +0200
|
||||
+++ livemedia.2016.09.22_noprints/liveMedia/include/ProxyServerMediaSession.hh 2016-10-02 10:06:07.077121273 +0200
|
||||
@@ -43,7 +43,8 @@ class ProxyRTSPClient: public RTSPClient
|
||||
public:
|
||||
ProxyRTSPClient(class ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
- portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer);
|
||||
+ portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
+ unsigned interPacketGapMaxTime = 0);
|
||||
virtual ~ProxyRTSPClient();
|
||||
|
||||
void continueAfterDESCRIBE(char const* sdpDescription);
|
||||
@@ -58,6 +59,8 @@ private:
|
||||
|
||||
void scheduleLivenessCommand();
|
||||
static void sendLivenessCommand(void* clientData);
|
||||
+ void checkInterPacketGaps_();
|
||||
+ static void checkInterPacketGaps(void* clientData);
|
||||
|
||||
void scheduleDESCRIBECommand();
|
||||
static void sendDESCRIBE(void* clientData);
|
||||
@@ -75,8 +78,10 @@ private:
|
||||
class ProxyServerMediaSubsession *fSetupQueueHead, *fSetupQueueTail;
|
||||
unsigned fNumSetupsDone;
|
||||
unsigned fNextDESCRIBEDelay; // in seconds
|
||||
+ unsigned fTotNumPacketsReceived;
|
||||
+ unsigned fInterPacketGapMaxTime; // in seconds
|
||||
Boolean fServerSupportsGetParameter, fLastCommandWasPLAY, fResetOnNextLivenessTest;
|
||||
- TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask;
|
||||
+ TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask, fInterPacketGapsTask;
|
||||
};
|
||||
|
||||
|
||||
@@ -85,13 +90,13 @@ createNewProxyRTSPClientFunc(ProxyServer
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
- int socketNumToServer);
|
||||
+ int socketNumToServer, unsigned interPacketGapMaxTime);
|
||||
ProxyRTSPClient*
|
||||
defaultCreateNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession,
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
- int socketNumToServer);
|
||||
+ int socketNumToServer, unsigned interPacketGapMaxTime);
|
||||
|
||||
class ProxyServerMediaSession: public ServerMediaSession {
|
||||
public:
|
||||
@@ -104,7 +109,8 @@ public:
|
||||
// for streaming the *proxied* (i.e., back-end) stream
|
||||
int verbosityLevel = 0,
|
||||
int socketNumToServer = -1,
|
||||
- MediaTranscodingTable* transcodingTable = NULL);
|
||||
+ MediaTranscodingTable* transcodingTable = NULL,
|
||||
+ unsigned interPacketGapMaxTime = 0);
|
||||
// Hack: "tunnelOverHTTPPortNum" == 0xFFFF (i.e., all-ones) means: Stream RTP/RTCP-over-TCP, but *not* using HTTP
|
||||
// "verbosityLevel" == 1 means display basic proxy setup info; "verbosityLevel" == 2 means display RTSP client protocol also.
|
||||
// If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server.
|
||||
@@ -127,6 +133,7 @@ protected:
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer,
|
||||
MediaTranscodingTable* transcodingTable,
|
||||
+ unsigned interPacketGapMaxTime = 0,
|
||||
createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc
|
||||
= defaultCreateNewProxyRTSPClientFunc,
|
||||
portNumBits initialPortNum = 6970,
|
||||
diff -pru livemedia.2016.09.22_org/liveMedia/ProxyServerMediaSession.cpp livemedia.2016.09.22_noprints/liveMedia/ProxyServerMediaSession.cpp
|
||||
--- livemedia.2016.09.22_org/liveMedia/ProxyServerMediaSession.cpp 2016-09-23 00:53:55.000000000 +0200
|
||||
+++ livemedia.2016.09.22_noprints/liveMedia/ProxyServerMediaSession.cpp 2016-10-02 15:53:35.116204035 +0200
|
||||
@@ -75,9 +75,9 @@ defaultCreateNewProxyRTSPClientFunc(Prox
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
- int socketNumToServer) {
|
||||
+ int socketNumToServer, unsigned interPacketGapMaxTime) {
|
||||
return new ProxyRTSPClient(ourServerMediaSession, rtspURL, username, password,
|
||||
- tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer);
|
||||
+ tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer, interPacketGapMaxTime);
|
||||
}
|
||||
|
||||
ProxyServerMediaSession* ProxyServerMediaSession
|
||||
@@ -85,10 +85,10 @@ ProxyServerMediaSession* ProxyServerMedi
|
||||
char const* inputStreamURL, char const* streamName,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
- MediaTranscodingTable* transcodingTable) {
|
||||
+ MediaTranscodingTable* transcodingTable, unsigned interPacketGapMaxTime) {
|
||||
return new ProxyServerMediaSession(env, ourMediaServer, inputStreamURL, streamName, username, password,
|
||||
tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer,
|
||||
- transcodingTable);
|
||||
+ transcodingTable, interPacketGapMaxTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ ProxyServerMediaSession
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer,
|
||||
MediaTranscodingTable* transcodingTable,
|
||||
+ unsigned interPacketGapMaxTime,
|
||||
createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc,
|
||||
portNumBits initialPortNum, Boolean multiplexRTCPWithRTP)
|
||||
: ServerMediaSession(env, streamName, NULL, NULL, False, NULL),
|
||||
@@ -114,7 +115,7 @@ ProxyServerMediaSession
|
||||
= (*fCreateNewProxyRTSPClientFunc)(*this, inputStreamURL, username, password,
|
||||
tunnelOverHTTPPortNum,
|
||||
verbosityLevel > 0 ? verbosityLevel-1 : verbosityLevel,
|
||||
- socketNumToServer);
|
||||
+ socketNumToServer, interPacketGapMaxTime);
|
||||
ProxyRTSPClient::sendDESCRIBE(fProxyRTSPClient);
|
||||
}
|
||||
|
||||
@@ -243,13 +244,15 @@ UsageEnvironment& operator<<(UsageEnviro
|
||||
|
||||
ProxyRTSPClient::ProxyRTSPClient(ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
- portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer)
|
||||
+ portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
+ unsigned interPacketGapMaxTime)
|
||||
: RTSPClient(ourServerMediaSession.envir(), rtspURL, verbosityLevel, "ProxyRTSPClient",
|
||||
tunnelOverHTTPPortNum == (portNumBits)(~0) ? 0 : tunnelOverHTTPPortNum, socketNumToServer),
|
||||
fOurServerMediaSession(ourServerMediaSession), fOurURL(strDup(rtspURL)), fStreamRTPOverTCP(tunnelOverHTTPPortNum != 0),
|
||||
fSetupQueueHead(NULL), fSetupQueueTail(NULL), fNumSetupsDone(0), fNextDESCRIBEDelay(1),
|
||||
+ fTotNumPacketsReceived(~0), fInterPacketGapMaxTime(interPacketGapMaxTime),
|
||||
fServerSupportsGetParameter(False), fLastCommandWasPLAY(False), fResetOnNextLivenessTest(False),
|
||||
- fLivenessCommandTask(NULL), fDESCRIBECommandTask(NULL), fSubsessionTimerTask(NULL) {
|
||||
+ fLivenessCommandTask(NULL), fDESCRIBECommandTask(NULL), fSubsessionTimerTask(NULL) , fInterPacketGapsTask(NULL) {
|
||||
if (username != NULL && password != NULL) {
|
||||
fOurAuthenticator = new Authenticator(username, password);
|
||||
} else {
|
||||
@@ -261,11 +264,13 @@ void ProxyRTSPClient::reset() {
|
||||
envir().taskScheduler().unscheduleDelayedTask(fLivenessCommandTask); fLivenessCommandTask = NULL;
|
||||
envir().taskScheduler().unscheduleDelayedTask(fDESCRIBECommandTask); fDESCRIBECommandTask = NULL;
|
||||
envir().taskScheduler().unscheduleDelayedTask(fSubsessionTimerTask); fSubsessionTimerTask = NULL;
|
||||
+ envir().taskScheduler().unscheduleDelayedTask(fInterPacketGapsTask); fInterPacketGapsTask = NULL;
|
||||
|
||||
fSetupQueueHead = fSetupQueueTail = NULL;
|
||||
fNumSetupsDone = 0;
|
||||
fNextDESCRIBEDelay = 1;
|
||||
fLastCommandWasPLAY = False;
|
||||
+ fTotNumPacketsReceived = ~0;
|
||||
|
||||
RTSPClient::reset();
|
||||
}
|
||||
@@ -392,6 +397,7 @@ void ProxyRTSPClient::continueAfterPLAY(
|
||||
envir().taskScheduler().rescheduleDelayedTask(fLivenessCommandTask, 0, sendLivenessCommand, this);
|
||||
return;
|
||||
}
|
||||
+ if (fInterPacketGapsTask == NULL) checkInterPacketGaps_();
|
||||
}
|
||||
|
||||
void ProxyRTSPClient::scheduleLivenessCommand() {
|
||||
@@ -432,6 +438,44 @@ void ProxyRTSPClient::sendLivenessComman
|
||||
#endif
|
||||
}
|
||||
|
||||
+void ProxyRTSPClient::checkInterPacketGaps_() {
|
||||
+ if (fInterPacketGapMaxTime == 0) return; // we're not checking
|
||||
+
|
||||
+ // Check each subsession, counting up how many packets have been received:
|
||||
+ unsigned newTotNumPacketsReceived = 0;
|
||||
+
|
||||
+ MediaSubsessionIterator iter(*fOurServerMediaSession.fClientMediaSession);
|
||||
+ MediaSubsession* subsession;
|
||||
+ while ((subsession = iter.next()) != NULL) {
|
||||
+ RTPSource* src = subsession->rtpSource();
|
||||
+ if (src == NULL) continue;
|
||||
+ newTotNumPacketsReceived += src->receptionStatsDB().totNumPacketsReceived();
|
||||
+ }
|
||||
+
|
||||
+ //envir() << *this << "::doLivenessCheck fTotNumPacketsReceived: " << fTotNumPacketsReceived
|
||||
+ // << ", newTotNumPacketsReceived: " << newTotNumPacketsReceived << "\n";
|
||||
+
|
||||
+ if (newTotNumPacketsReceived == fTotNumPacketsReceived) {
|
||||
+ // No additional packets have been received since the last time we
|
||||
+ // checked, so end this stream:
|
||||
+ // *env << "Closing session, because we stopped receiving packets.\n";
|
||||
+ if (fVerbosityLevel > 0) {
|
||||
+ envir() << *this << "::doLivenessCheck last packet received: >" << fInterPacketGapMaxTime
|
||||
+ << " seconds ago. Resetting session\n";
|
||||
+ }
|
||||
+ continueAfterLivenessCommand(1/*hack*/, fServerSupportsGetParameter);
|
||||
+ } else {
|
||||
+ fTotNumPacketsReceived = newTotNumPacketsReceived;
|
||||
+ // Check again, after the specified delay:
|
||||
+ fInterPacketGapsTask = envir().taskScheduler().scheduleDelayedTask(fInterPacketGapMaxTime*MILLION, checkInterPacketGaps, this);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void ProxyRTSPClient::checkInterPacketGaps(void* clientData) {
|
||||
+ ProxyRTSPClient* rtspClient = (ProxyRTSPClient*)clientData;
|
||||
+ rtspClient->checkInterPacketGaps_();
|
||||
+}
|
||||
+
|
||||
void ProxyRTSPClient::scheduleDESCRIBECommand() {
|
||||
// Delay 1s, 2s, 4s, 8s ... 256s until sending the next "DESCRIBE". Then, keep delaying a random time from [256..511] seconds:
|
||||
unsigned secondsToDelay;
|
||||
@@ -621,6 +665,7 @@ void ProxyServerMediaSubsession::closeSt
|
||||
// Send a "PAUSE" for the whole stream.
|
||||
proxyRTSPClient->sendPauseCommand(fClientMediaSubsession.parentSession(), NULL, proxyRTSPClient->auth());
|
||||
proxyRTSPClient->fLastCommandWasPLAY = False;
|
||||
+ envir().taskScheduler().unscheduleDelayedTask(proxyRTSPClient->fInterPacketGapsTask); proxyRTSPClient->fInterPacketGapsTask = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
diff -pru livemedia.2016.09.22_org/proxyServer/live555ProxyServer.cpp livemedia.2016.09.22_noprints/proxyServer/live555ProxyServer.cpp
|
||||
--- livemedia.2016.09.22_org/proxyServer/live555ProxyServer.cpp 2016-09-23 00:53:55.000000000 +0200
|
||||
+++ livemedia.2016.09.22_noprints/proxyServer/live555ProxyServer.cpp 2016-10-02 10:13:18.893102276 +0200
|
||||
@@ -35,6 +35,7 @@ char* password = NULL;
|
||||
Boolean proxyREGISTERRequests = False;
|
||||
char* usernameForREGISTER = NULL;
|
||||
char* passwordForREGISTER = NULL;
|
||||
+unsigned interPacketGapMaxTime = 0;
|
||||
|
||||
static RTSPServer* createRTSPServer(Port port) {
|
||||
if (proxyREGISTERRequests) {
|
||||
@@ -51,6 +52,7 @@ void usage() {
|
||||
<< " [-p <rtspServer-port>]"
|
||||
<< " [-u <username> <password>]"
|
||||
<< " [-R] [-U <username-for-REGISTER> <password-for-REGISTER>]"
|
||||
+ << " [-D <max-inter-packet-gap-time>]"
|
||||
<< " <rtsp-url-1> ... <rtsp-url-n>\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -151,6 +153,19 @@ int main(int argc, char** argv) {
|
||||
break;
|
||||
}
|
||||
|
||||
+ case 'D': { // specify maximum number of seconds to wait for packets:
|
||||
+ if (argc > 2 && argv[2][0] != '-') {
|
||||
+ if (sscanf(argv[2], "%u", &interPacketGapMaxTime) == 1) {
|
||||
+ ++argv; --argc;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // If we get here, the option was specified incorrectly:
|
||||
+ usage();
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
default: {
|
||||
usage();
|
||||
break;
|
||||
@@ -221,7 +236,7 @@ int main(int argc, char** argv) {
|
||||
ServerMediaSession* sms
|
||||
= ProxyServerMediaSession::createNew(*env, rtspServer,
|
||||
proxiedStreamURL, streamName,
|
||||
- username, password, tunnelOverHTTPPortNum, verbosityLevel);
|
||||
+ username, password, tunnelOverHTTPPortNum, verbosityLevel, -1, NULL, interPacketGapMaxTime);
|
||||
rtspServer->addServerMediaSession(sms);
|
||||
|
||||
char* proxyStreamURL = rtspServer->rtspURL(sms);
|
||||
13
README.md
13
README.md
@@ -17,7 +17,7 @@ You will find various executables:
|
||||
|
||||
# Changes to Master
|
||||
|
||||
See modifications.patch to see exactly what was changed compared to vanilla.
|
||||
See modifications.patch and Proxyserver_check_interPacketGap.patch to see exactly what was changed compared to vanilla.
|
||||
|
||||
### Buffer sizes
|
||||
|
||||
@@ -26,4 +26,13 @@ OutPacketBuffer::maxSize is increased to 2,000,000 bytes which makes live555 wor
|
||||
### Force port re-use
|
||||
|
||||
Added -DALLOW_RTSP_SERVER_PORT_REUSE=1 to force reusing existing port (e.g. when restarting the proxy). Please ensure
|
||||
you never run multiple instances of the proxy on the same port!
|
||||
you never run multiple instances of the proxy on the same port!
|
||||
|
||||
### Max Inter Packet Gap Time
|
||||
|
||||
Erik Montnemery wrote a fantastic patch, in his own words: The new functionality is based on the implementation of the same option in openRTSP. When the -D option is used, the proxy server will reset the connection to a 'back end' server if at least one subsession *might* be in state playing, but no data has been received during max-inter-packet-gap-time seconds.
|
||||
|
||||
[-D <max-inter-packet-gap-time>]
|
||||
|
||||
* Note 1: This option does not make sense for all streams. It is useful for IP cameras where the camera should be sending data at all times. As discussed in another thread, there’s no good way for the proxy server code to know exactly what subsession(s) are and are not currently streaming.
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ defaultCreateNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSessi
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer) {
|
||||
int socketNumToServer, unsigned interPacketGapMaxTime) {
|
||||
return new ProxyRTSPClient(ourServerMediaSession, rtspURL, username, password,
|
||||
tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer);
|
||||
tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer, interPacketGapMaxTime);
|
||||
}
|
||||
|
||||
ProxyServerMediaSession* ProxyServerMediaSession
|
||||
@@ -85,10 +85,10 @@ ProxyServerMediaSession* ProxyServerMediaSession
|
||||
char const* inputStreamURL, char const* streamName,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
MediaTranscodingTable* transcodingTable) {
|
||||
MediaTranscodingTable* transcodingTable, unsigned interPacketGapMaxTime) {
|
||||
return new ProxyServerMediaSession(env, ourMediaServer, inputStreamURL, streamName, username, password,
|
||||
tunnelOverHTTPPortNum, verbosityLevel, socketNumToServer,
|
||||
transcodingTable);
|
||||
transcodingTable, interPacketGapMaxTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ ProxyServerMediaSession
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer,
|
||||
MediaTranscodingTable* transcodingTable,
|
||||
unsigned interPacketGapMaxTime,
|
||||
createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc,
|
||||
portNumBits initialPortNum, Boolean multiplexRTCPWithRTP)
|
||||
: ServerMediaSession(env, streamName, NULL, NULL, False, NULL),
|
||||
@@ -114,7 +115,7 @@ ProxyServerMediaSession
|
||||
= (*fCreateNewProxyRTSPClientFunc)(*this, inputStreamURL, username, password,
|
||||
tunnelOverHTTPPortNum,
|
||||
verbosityLevel > 0 ? verbosityLevel-1 : verbosityLevel,
|
||||
socketNumToServer);
|
||||
socketNumToServer, interPacketGapMaxTime);
|
||||
ProxyRTSPClient::sendDESCRIBE(fProxyRTSPClient);
|
||||
}
|
||||
|
||||
@@ -243,13 +244,15 @@ UsageEnvironment& operator<<(UsageEnvironment& env, const ProxyRTSPClient& proxy
|
||||
|
||||
ProxyRTSPClient::ProxyRTSPClient(ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer)
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
unsigned interPacketGapMaxTime)
|
||||
: RTSPClient(ourServerMediaSession.envir(), rtspURL, verbosityLevel, "ProxyRTSPClient",
|
||||
tunnelOverHTTPPortNum == (portNumBits)(~0) ? 0 : tunnelOverHTTPPortNum, socketNumToServer),
|
||||
fOurServerMediaSession(ourServerMediaSession), fOurURL(strDup(rtspURL)), fStreamRTPOverTCP(tunnelOverHTTPPortNum != 0),
|
||||
fSetupQueueHead(NULL), fSetupQueueTail(NULL), fNumSetupsDone(0), fNextDESCRIBEDelay(1),
|
||||
fTotNumPacketsReceived(~0), fInterPacketGapMaxTime(interPacketGapMaxTime),
|
||||
fServerSupportsGetParameter(False), fLastCommandWasPLAY(False), fResetOnNextLivenessTest(False),
|
||||
fLivenessCommandTask(NULL), fDESCRIBECommandTask(NULL), fSubsessionTimerTask(NULL) {
|
||||
fLivenessCommandTask(NULL), fDESCRIBECommandTask(NULL), fSubsessionTimerTask(NULL) , fInterPacketGapsTask(NULL) {
|
||||
if (username != NULL && password != NULL) {
|
||||
fOurAuthenticator = new Authenticator(username, password);
|
||||
} else {
|
||||
@@ -261,11 +264,13 @@ void ProxyRTSPClient::reset() {
|
||||
envir().taskScheduler().unscheduleDelayedTask(fLivenessCommandTask); fLivenessCommandTask = NULL;
|
||||
envir().taskScheduler().unscheduleDelayedTask(fDESCRIBECommandTask); fDESCRIBECommandTask = NULL;
|
||||
envir().taskScheduler().unscheduleDelayedTask(fSubsessionTimerTask); fSubsessionTimerTask = NULL;
|
||||
envir().taskScheduler().unscheduleDelayedTask(fInterPacketGapsTask); fInterPacketGapsTask = NULL;
|
||||
|
||||
fSetupQueueHead = fSetupQueueTail = NULL;
|
||||
fNumSetupsDone = 0;
|
||||
fNextDESCRIBEDelay = 1;
|
||||
fLastCommandWasPLAY = False;
|
||||
fTotNumPacketsReceived = ~0;
|
||||
|
||||
RTSPClient::reset();
|
||||
}
|
||||
@@ -392,6 +397,7 @@ void ProxyRTSPClient::continueAfterPLAY(int resultCode) {
|
||||
envir().taskScheduler().rescheduleDelayedTask(fLivenessCommandTask, 0, sendLivenessCommand, this);
|
||||
return;
|
||||
}
|
||||
if (fInterPacketGapsTask == NULL) checkInterPacketGaps_();
|
||||
}
|
||||
|
||||
void ProxyRTSPClient::scheduleLivenessCommand() {
|
||||
@@ -432,6 +438,44 @@ void ProxyRTSPClient::sendLivenessCommand(void* clientData) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProxyRTSPClient::checkInterPacketGaps_() {
|
||||
if (fInterPacketGapMaxTime == 0) return; // we're not checking
|
||||
|
||||
// Check each subsession, counting up how many packets have been received:
|
||||
unsigned newTotNumPacketsReceived = 0;
|
||||
|
||||
MediaSubsessionIterator iter(*fOurServerMediaSession.fClientMediaSession);
|
||||
MediaSubsession* subsession;
|
||||
while ((subsession = iter.next()) != NULL) {
|
||||
RTPSource* src = subsession->rtpSource();
|
||||
if (src == NULL) continue;
|
||||
newTotNumPacketsReceived += src->receptionStatsDB().totNumPacketsReceived();
|
||||
}
|
||||
|
||||
//envir() << *this << "::doLivenessCheck fTotNumPacketsReceived: " << fTotNumPacketsReceived
|
||||
// << ", newTotNumPacketsReceived: " << newTotNumPacketsReceived << "\n";
|
||||
|
||||
if (newTotNumPacketsReceived == fTotNumPacketsReceived) {
|
||||
// No additional packets have been received since the last time we
|
||||
// checked, so end this stream:
|
||||
// *env << "Closing session, because we stopped receiving packets.\n";
|
||||
if (fVerbosityLevel > 0) {
|
||||
envir() << *this << "::doLivenessCheck last packet received: >" << fInterPacketGapMaxTime
|
||||
<< " seconds ago. Resetting session\n";
|
||||
}
|
||||
continueAfterLivenessCommand(1/*hack*/, fServerSupportsGetParameter);
|
||||
} else {
|
||||
fTotNumPacketsReceived = newTotNumPacketsReceived;
|
||||
// Check again, after the specified delay:
|
||||
fInterPacketGapsTask = envir().taskScheduler().scheduleDelayedTask(fInterPacketGapMaxTime*MILLION, checkInterPacketGaps, this);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyRTSPClient::checkInterPacketGaps(void* clientData) {
|
||||
ProxyRTSPClient* rtspClient = (ProxyRTSPClient*)clientData;
|
||||
rtspClient->checkInterPacketGaps_();
|
||||
}
|
||||
|
||||
void ProxyRTSPClient::scheduleDESCRIBECommand() {
|
||||
// Delay 1s, 2s, 4s, 8s ... 256s until sending the next "DESCRIBE". Then, keep delaying a random time from [256..511] seconds:
|
||||
unsigned secondsToDelay;
|
||||
@@ -621,6 +665,7 @@ void ProxyServerMediaSubsession::closeStreamSource(FramedSource* inputSource) {
|
||||
// Send a "PAUSE" for the whole stream.
|
||||
proxyRTSPClient->sendPauseCommand(fClientMediaSubsession.parentSession(), NULL, proxyRTSPClient->auth());
|
||||
proxyRTSPClient->fLastCommandWasPLAY = False;
|
||||
envir().taskScheduler().unscheduleDelayedTask(proxyRTSPClient->fInterPacketGapsTask); proxyRTSPClient->fInterPacketGapsTask = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ class ProxyRTSPClient: public RTSPClient {
|
||||
public:
|
||||
ProxyRTSPClient(class ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer);
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer,
|
||||
unsigned interPacketGapMaxTime = 0);
|
||||
virtual ~ProxyRTSPClient();
|
||||
|
||||
void continueAfterDESCRIBE(char const* sdpDescription);
|
||||
@@ -58,6 +59,8 @@ private:
|
||||
|
||||
void scheduleLivenessCommand();
|
||||
static void sendLivenessCommand(void* clientData);
|
||||
void checkInterPacketGaps_();
|
||||
static void checkInterPacketGaps(void* clientData);
|
||||
|
||||
void scheduleDESCRIBECommand();
|
||||
static void sendDESCRIBE(void* clientData);
|
||||
@@ -75,8 +78,10 @@ private:
|
||||
class ProxyServerMediaSubsession *fSetupQueueHead, *fSetupQueueTail;
|
||||
unsigned fNumSetupsDone;
|
||||
unsigned fNextDESCRIBEDelay; // in seconds
|
||||
unsigned fTotNumPacketsReceived;
|
||||
unsigned fInterPacketGapMaxTime; // in seconds
|
||||
Boolean fServerSupportsGetParameter, fLastCommandWasPLAY, fResetOnNextLivenessTest;
|
||||
TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask;
|
||||
TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask, fInterPacketGapsTask;
|
||||
};
|
||||
|
||||
|
||||
@@ -85,13 +90,13 @@ createNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession,
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer);
|
||||
int socketNumToServer, unsigned interPacketGapMaxTime);
|
||||
ProxyRTSPClient*
|
||||
defaultCreateNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession,
|
||||
char const* rtspURL,
|
||||
char const* username, char const* password,
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer);
|
||||
int socketNumToServer, unsigned interPacketGapMaxTime);
|
||||
|
||||
class ProxyServerMediaSession: public ServerMediaSession {
|
||||
public:
|
||||
@@ -104,7 +109,8 @@ public:
|
||||
// for streaming the *proxied* (i.e., back-end) stream
|
||||
int verbosityLevel = 0,
|
||||
int socketNumToServer = -1,
|
||||
MediaTranscodingTable* transcodingTable = NULL);
|
||||
MediaTranscodingTable* transcodingTable = NULL,
|
||||
unsigned interPacketGapMaxTime = 0);
|
||||
// Hack: "tunnelOverHTTPPortNum" == 0xFFFF (i.e., all-ones) means: Stream RTP/RTCP-over-TCP, but *not* using HTTP
|
||||
// "verbosityLevel" == 1 means display basic proxy setup info; "verbosityLevel" == 2 means display RTSP client protocol also.
|
||||
// If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server.
|
||||
@@ -127,6 +133,7 @@ protected:
|
||||
portNumBits tunnelOverHTTPPortNum, int verbosityLevel,
|
||||
int socketNumToServer,
|
||||
MediaTranscodingTable* transcodingTable,
|
||||
unsigned interPacketGapMaxTime = 0,
|
||||
createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc
|
||||
= defaultCreateNewProxyRTSPClientFunc,
|
||||
portNumBits initialPortNum = 6970,
|
||||
|
||||
@@ -35,6 +35,7 @@ char* password = NULL;
|
||||
Boolean proxyREGISTERRequests = False;
|
||||
char* usernameForREGISTER = NULL;
|
||||
char* passwordForREGISTER = NULL;
|
||||
unsigned interPacketGapMaxTime = 0;
|
||||
|
||||
static RTSPServer* createRTSPServer(Port port) {
|
||||
if (proxyREGISTERRequests) {
|
||||
@@ -51,6 +52,7 @@ void usage() {
|
||||
<< " [-p <rtspServer-port>]"
|
||||
<< " [-u <username> <password>]"
|
||||
<< " [-R] [-U <username-for-REGISTER> <password-for-REGISTER>]"
|
||||
<< " [-D <max-inter-packet-gap-time>]"
|
||||
<< " <rtsp-url-1> ... <rtsp-url-n>\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -151,6 +153,19 @@ int main(int argc, char** argv) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'D': { // specify maximum number of seconds to wait for packets:
|
||||
if (argc > 2 && argv[2][0] != '-') {
|
||||
if (sscanf(argv[2], "%u", &interPacketGapMaxTime) == 1) {
|
||||
++argv; --argc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, the option was specified incorrectly:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
usage();
|
||||
break;
|
||||
@@ -221,7 +236,7 @@ int main(int argc, char** argv) {
|
||||
ServerMediaSession* sms
|
||||
= ProxyServerMediaSession::createNew(*env, rtspServer,
|
||||
proxiedStreamURL, streamName,
|
||||
username, password, tunnelOverHTTPPortNum, verbosityLevel);
|
||||
username, password, tunnelOverHTTPPortNum, verbosityLevel, -1, NULL, interPacketGapMaxTime);
|
||||
rtspServer->addServerMediaSession(sms);
|
||||
|
||||
char* proxyStreamURL = rtspServer->rtspURL(sms);
|
||||
|
||||
Reference in New Issue
Block a user