[Live-devel] PATCH RTSP KeepAlive Support.

Glen Gray glen at lincor.com
Tue Jan 24 12:18:41 PST 2006


Okay guys,

Here is the alternate version of the patch where scheduling is handled 
outside liveMedia by VLC and by using the already present 
getMediaSessionParameter() function.

That function had to be modified to handle a parameterName of NULL. The 
message is constructed differently if there's no parameter to be passed 
and obviously you don't try and parse out any results (apart from he 
acknowledgement of the command).

Hope this is cleaner.

-- 
Glen Gray <glen at lincor.com>              Digital Depot, Thomas Street
Senior Software Engineer                            Dublin 8, Ireland
Lincor Solutions Ltd.                          Ph: +353 (0) 1 4893682

-------------- next part --------------
diff -uNr live/liveMedia/include/RTSPClient.hh live.lincor/liveMedia/include/RTSPClient.hh
--- live/liveMedia/include/RTSPClient.hh	2006-01-05 02:01:01.000000000 +0000
+++ live.lincor/liveMedia/include/RTSPClient.hh	2006-01-24 08:37:02.000000000 +0000
@@ -36,12 +36,14 @@
   static RTSPClient* createNew(UsageEnvironment& env,
 			       int verbosityLevel = 0,
 			       char const* applicationName = NULL,
-			       portNumBits tunnelOverHTTPPortNum = 0);
+			       portNumBits tunnelOverHTTPPortNum = 0,
+                               Boolean serverKeepAlve = False);
   // If "tunnelOverHTTPPortNum" is non-zero, we tunnel RTSP (and RTP)
   // over a HTTP connection with the given port number, using the technique
   // described in Apple's document <http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html>
 
   int socketNum() const { return fInputSocketNum; }
+  long keepAliveTimeout() const { return fKeepAliveTimeout; }
 
   static Boolean lookupByName(UsageEnvironment& env,
 			      char const* sourceName,
@@ -85,7 +87,9 @@
       // If "forceMulticastOnUnspecified" is True (and "streamUsingTCP" is False),
       // then the client will request a multicast stream if the media address
       // in the original SDP response was unspecified (i.e., 0.0.0.0).
-      // Note, however, that not all servers will support this. 
+      // Note, however, that not all servers will support this.
+      // If serverKeepAlive is True, then we'll append "_KA" to our user agent
+      // string and watch out for ";timeout=n" in the "Session:" response 
 
   Boolean playMediaSession(MediaSession& session,
 			   float start = 0.0f, float end = -1.0f,
@@ -153,7 +157,8 @@
 
 private:
   RTSPClient(UsageEnvironment& env, int verbosityLevel,
-	     char const* applicationName, portNumBits tunnelOverHTTPPortNum);
+	     char const* applicationName, portNumBits tunnelOverHTTPPortNum,
+             Boolean serverKeepAlive);
       // called only by createNew();
 
   void reset();
@@ -194,7 +199,7 @@
   int fVerbosityLevel;
   portNumBits fTunnelOverHTTPPortNum;
   char* fUserAgentHeaderStr;
-      unsigned fUserAgentHeaderStrSize;
+  unsigned fUserAgentHeaderStrSize;
   int fInputSocketNum, fOutputSocketNum;
   unsigned fServerAddress;
   static unsigned fCSeq; // sequence number, used in consecutive requests
@@ -220,6 +225,10 @@
 
   // The following is used to deal with Microsoft servers' non-standard use of RTSP:
   Boolean fServerIsMicrosoft;
+
+  // The following is used to determine if we us the KeepAlive session method
+  Boolean fServerKeepAlive;
+  long fKeepAliveTimeout; //Server supplied timeout for session KeepAlive
 };
 
 #endif
diff -uNr live/liveMedia/RTSPClient.cpp live.lincor/liveMedia/RTSPClient.cpp
--- live/liveMedia/RTSPClient.cpp	2006-01-05 02:01:02.000000000 +0000
+++ live.lincor/liveMedia/RTSPClient.cpp	2006-01-24 11:18:09.000000000 +0000
@@ -73,9 +73,12 @@
 RTSPClient* RTSPClient::createNew(UsageEnvironment& env,
 				  int verbosityLevel,
 				  char const* applicationName,
-				  portNumBits tunnelOverHTTPPortNum) {
+				  portNumBits tunnelOverHTTPPortNum,
+                                  Boolean serverKeepAlive) {
   return new RTSPClient(env, verbosityLevel,
-			applicationName, tunnelOverHTTPPortNum);
+			applicationName, 
+                        tunnelOverHTTPPortNum, 
+                        serverKeepAlive);
 }
 
 Boolean RTSPClient::lookupByName(UsageEnvironment& env,
@@ -99,7 +102,8 @@
 
 RTSPClient::RTSPClient(UsageEnvironment& env,
 		       int verbosityLevel, char const* applicationName,
-		       portNumBits tunnelOverHTTPPortNum)
+		       portNumBits tunnelOverHTTPPortNum,
+                       Boolean serverKeepAlive)
   : Medium(env),
     fVerbosityLevel(verbosityLevel),
     fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum),
@@ -109,7 +113,8 @@
     fRealChallengeStr(NULL), fRealETagStr(NULL),
 #endif
     fServerIsKasenna(False), fKasennaContentType(NULL),
-    fServerIsMicrosoft(False)
+    fServerIsMicrosoft(False),
+    fServerKeepAlive(serverKeepAlive), fKeepAliveTimeout(0)
 {
   fResponseBufferSize = 20000;
   fResponseBuffer = new char[fResponseBufferSize+1];
@@ -118,19 +123,27 @@
   char const* const libName = "LIVE555 Streaming Media v";
   char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
   char const* libPrefix; char const* libSuffix;
-  if (applicationName == NULL || applicationName[0] == '\0') {
-    applicationName = libPrefix = libSuffix = "";
+    
+  if (fServerKeepAlive == False) {
+    if (applicationName == NULL || applicationName[0] == '\0') {
+      applicationName = libPrefix = libSuffix = "";
+    } else {
+      libPrefix = " (";
+      libSuffix = ")";
+    }
+    char const* const formatStr = "User-Agent: %s%s%s%s%s\r\n";
+    unsigned headerSize
+      = strlen(formatStr) + strlen(applicationName) + strlen(libPrefix)
+      + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix);
+    fUserAgentHeaderStr = new char[headerSize];
+    sprintf(fUserAgentHeaderStr, formatStr,
+            applicationName, libPrefix, libName, libVersionStr, libSuffix);
   } else {
-    libPrefix = " (";
-    libSuffix = ")";
+    char const* const formatStr = "User-Agent: VLC_LIVE_PLAYER_KA\r\n";
+    unsigned headerSize = strlen(formatStr);
+    fUserAgentHeaderStr = new char[headerSize];
+    sprintf(fUserAgentHeaderStr, formatStr);
   }
-  char const* const formatStr = "User-Agent: %s%s%s%s%s\r\n";
-  unsigned headerSize
-    = strlen(formatStr) + strlen(applicationName) + strlen(libPrefix)
-    + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix);
-  fUserAgentHeaderStr = new char[headerSize];
-  sprintf(fUserAgentHeaderStr, formatStr,
-	  applicationName, libPrefix, libName, libVersionStr, libSuffix);
   fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr);
 }
 
@@ -942,6 +955,24 @@
       nextLineStart = getLine(lineStart);
 
       if (sscanf(lineStart, "Session: %[^;]", sessionId) == 1) {
+        if (fServerKeepAlive == True) {
+          // If we find a ";timeout=" string in the response, then we are using
+          // the Keep Alive method
+          char *tmp = NULL;
+
+          if ((tmp = strstr (lineStart, "; timeout = ")) != NULL) {
+            char *strTimeout = NULL;
+
+            tmp = strstr (tmp, "=");
+            if (strlen (tmp) > 2) {
+              strTimeout = strDup (tmp+2);
+              fKeepAliveTimeout = strtol (strTimeout, NULL, 10);
+              fKeepAliveTimeout = fKeepAliveTimeout * 1000000;
+              
+              delete[] strTimeout;
+            }
+          } 
+        }
 	subsession.sessionId = strDup(sessionId);
 	delete[] fLastSessionId; fLastSessionId = strDup(sessionId);
 	continue;
@@ -1447,38 +1478,70 @@
     }
 
     // Send the GET_PARAMETER command:
+    // This command can be used to retrieve info from the server. It can also
+    // be used as a Keep Alive message to the server (message has no body)
     // First, construct an authenticator string:
     char* authenticatorStr
       = createAuthenticatorString(&fCurrentAuthenticator,
 				  "GET_PARAMETER", fBaseURL);
 
-    char* const cmdFmt =
-      "GET_PARAMETER %s RTSP/1.0\r\n"
-      "CSeq: %d\r\n"
-      "Session: %s\r\n"
-      "%s"
-      "%s"
-      "Content-type: text/parameters\r\n"
-      "Content-length: %d\r\n\r\n"
-      "%s\r\n"
-      "\r\n";
-
-    unsigned cmdSize = strlen(cmdFmt)
-      + strlen(fBaseURL)
-      + 20 /* max int len */
-      + strlen(fLastSessionId)
-      + strlen(authenticatorStr)
-      + fUserAgentHeaderStrSize
-      + strlen(parameterName);
-    cmd = new char[cmdSize];
-    sprintf(cmd, cmdFmt,
-	    fBaseURL,
-	    ++fCSeq,
-	    fLastSessionId,
-	    authenticatorStr,
-	    fUserAgentHeaderStr,
-            strlen(parameterName)+2,
-	    parameterName);
+    if (parameterName != NULL) {
+      // If we recieved a parameterName string, then we are looking for
+      // info from the server.
+      char* const cmdFmt =
+        "GET_PARAMETER %s RTSP/1.0\r\n"
+        "CSeq: %d\r\n"
+        "Session: %s\r\n"
+        "%s"
+        "%s"
+        "Content-type: text/parameters\r\n"
+        "Content-length: %d\r\n\r\n"
+        "%s\r\n"
+        "\r\n";
+
+      unsigned cmdSize = strlen(cmdFmt)
+        + strlen(fBaseURL)
+        + 20 /* max int len */
+        + strlen(fLastSessionId)
+        + strlen(authenticatorStr)
+        + fUserAgentHeaderStrSize
+        + strlen(parameterName);
+
+      cmd = new char[cmdSize];
+      sprintf(cmd, cmdFmt,
+              fBaseURL,
+              ++fCSeq,
+              fLastSessionId,
+              authenticatorStr,
+              fUserAgentHeaderStr,
+              strlen(parameterName)+2,
+              parameterName);
+    } else {
+      // If we recieved a NULL parameterName string, then we are need to
+      // construct a message with no body. Most likely a Keep Alive message.
+      char* const cmdFmt =
+        "GET_PARAMETER %s RTSP/1.0\r\n"
+        "CSeq: %d\r\n"
+        "Session: %s\r\n"
+        "%s"
+        "%s"
+        "\r\n";
+
+      unsigned cmdSize = strlen(cmdFmt)
+        + strlen(fBaseURL)
+        + 20 /* max int len */
+        + strlen(fLastSessionId)
+        + strlen(authenticatorStr)
+        + fUserAgentHeaderStrSize;
+
+      cmd = new char[cmdSize];
+      sprintf(cmd, cmdFmt,
+              fBaseURL,
+              ++fCSeq,
+              fLastSessionId,
+              authenticatorStr,
+              fUserAgentHeaderStr);
+    }
     delete[] authenticatorStr;
 
     if (!sendRequest(cmd, "GET_PARAMETER")) break;
@@ -1573,8 +1636,10 @@
       }
     }
 
-    if (!parseGetParameterHeader(bodyStart, parameterName, parameterValue)) 
-      break;
+    if (parameterName != NULL) {
+      if (!parseGetParameterHeader(bodyStart, parameterName, parameterValue)) 
+        break;
+    }
 
     delete[] cmd;
     return True;
@@ -2379,3 +2444,4 @@
   delete[] cmd;
   return False;
 }
+


More information about the live-devel mailing list