Skip to content

Commit

Permalink
Add max-inter-packet-gap-time to proxyServer
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Gaufman committed Oct 12, 2016
1 parent 7aaacef commit c32916d
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 15 deletions.
254 changes: 254 additions & 0 deletions Proxyserver_check_interPacketGap.patch
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.

Loading

0 comments on commit c32916d

Please sign in to comment.