[Live-devel] Slow connection problem with RTP over RTSP/TCP

mproxi at orangemail.sk mproxi at orangemail.sk
Wed Nov 18 15:18:26 PST 2009


Hello,

I have tested LIVE555 and I found one problem. Clients connecting to live server over slow network have problems receiving data with RTSP TCP encapsulation turned on. If bitrate of the video is bigger, than available network bandwidth, Live server discards packed randomly. This keeps network busy sending data, but client receives few or none whole 
frames.

I found problem in function sendRTPOverTCP in file RTPInterface.cpp. If send() function is unable to send data, because OS buffer is full, it simply discards rest of the data. This is not very good solution, because it waste bandwidth and breaks frames. On some video sources and for some type of application it is possible to reduce framerate, so you can watch video on slow network. It is better to send whole frame, then 
skip some frames and again send whole frame.

My solution for this problem is to try to repeat send for the same data, if there was no space for them in OS buffers. I tried to determine, if it is possible to send data with function select() and then send them or schedule this data for sending in another time. This solution is valid only with sources, that can change framerate, like web camera, it does not help with file sources that much, except it seems to be more stable for them on slow networks.

I found out that this solution also helps with really big frames, which were not send sometime even on LAN.

I do not know how to make proper patch file, so you can test it with live.2009.11.12.tar.gz. I attached some diff file generated by svn, with my changes. Maybe someone will find this information useful.

Martin

Index: .liveMediaincludeRTPInterface.hh
===================================================================
--- .liveMediaincludeRTPInterface.hh
+++ .liveMediaincludeRTPInterface.hh
@@ -63,7 +63,7 @@
 
   void setClientSession(void* clientSession){rtspClientSession = clientSession;}
 
-  void sendPacket(unsigned char* packet, unsigned packetSize);
+  int sendPacket(unsigned char* packet, unsigned packetSize);
   void startNetworkReading(TaskScheduler::BackgroundHandlerProc*
                            handlerProc);
   bool handleRead(unsigned char* buffer, unsigned bufferMaxSize,
Index: .liveMediaincludeMultiFramedRTPSink.hh
===================================================================
--- .liveMediaincludeMultiFramedRTPSink.hh
+++ .liveMediaincludeMultiFramedRTPSink.hh
@@ -99,6 +99,7 @@
   void sendPacketIfNecessary();
   static void sendNext(void* firstArg);
   friend void sendNext(void*);
+  static void sendThisAgain(void* firstArg);
 
   static void afterGettingFrame(void* clientData,
 				unsigned numBytesRead, unsigned numTruncatedBytes,
Index: .liveMediaRTPInterface.cpp
===================================================================
--- .liveMediaRTPInterface.cpp
+++ .liveMediaRTPInterface.cpp
@@ -34,7 +34,7 @@
 // Helper routines and data structures, used to implement
 // sendingreceiving RTPRTCP over a TCP socket:
 
-static void sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
+static int sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
 			   int socketNum, unsigned char streamChannelId);
 
 // Reading RTP-over-TCP is implemented using two levels of hash tables.
@@ -166,16 +166,18 @@
   }
 }
 
-void RTPInterface::sendPacket(unsigned char* packet, unsigned packetSize) {
+int RTPInterface::sendPacket(unsigned char* packet, unsigned packetSize) {
   // Normal case: Send as a UDP packet:
   fGS->output(envir(), fGS->ttl(), packet, packetSize);
+  int iSend = packetSize;
 
   // Also, send over each of our TCP sockets:
   for (tcpStreamRecord* streams = fTCPStreams; streams != NULL;
        streams = streams->fNext) {
-    sendRTPOverTCP(packet, packetSize,
+    iSend = sendRTPOverTCP(packet, packetSize,
 		   streams->fStreamSocketNum, streams->fStreamChannelId);
   }
+ return iSend;
 }
 
 void RTPInterface
@@ -256,7 +258,7 @@
 
 ////////// Helper Functions - Implementation ////////
 
-void sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
+int sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
                     int socketNum, unsigned char streamChannelId) {
 #ifdef DEBUG
   fprintf(stderr, "sendRTPOverTCP: %d bytes over channel %d (socket %d)n",
@@ -265,6 +267,21 @@
   // Send RTP over TCP, using the encoding defined in
   // RFC 2326, section 10.12:
   do {
+
+    //This code is trying to check if we are able to send data over TCP
+    //in some case we cannot send data, because winows buffers are full of our previous data
+    fd_set wrts;
+	struct timeval timeout;
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 1;
+	FD_ZERO(&wrts);
+	FD_SET(socketNum,&wrts);
+	select(NULL, NULL, &wrts, NULL, &timeout);
+	if (!FD_ISSET(socketNum, &wrts))
+	{
+		return 0;
+	}
+
     char const dollar = '$';
     if (send(socketNum, &dollar, 1, 0) != 1) break;
     if (send(socketNum, (char*)&streamChannelId, 1, 0) != 1) break;
@@ -280,13 +297,17 @@
     fprintf(stderr, "sendRTPOverTCP: completedn"); fflush(stderr);
 #endif
 
-    return;
+    if (packetSize != 0)
+		return packetSize;
+	else
+		return 1;
   } while (0);
 
   RTPOverTCP_OK = false; // HACK #####
 #ifdef DEBUG
   fprintf(stderr, "sendRTPOverTCP: failed!n"); fflush(stderr);
 #endif
+  return -1;
 }
 
 SocketDescriptor::SocketDescriptor(UsageEnvironment& env, int socketNum)
Index: .liveMediaMultiFramedRTPSink.cpp
===================================================================
--- .liveMediaMultiFramedRTPSink.cpp
+++ .liveMediaMultiFramedRTPSink.cpp
@@ -357,7 +357,12 @@
 #ifdef TEST_LOSS
     if ((our_random()%10) != 0) // simulate 10% packet loss #####
 #endif
-    fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize());
+    if (fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize()) == 0)
+	{
+		//if I was unable to send data through TCP, try to send them later
+		nextTask() = envir().taskScheduler().scheduleDelayedTask (100, (TaskFunc*)sendThisAgain, this);
+		return;
+	}
     ++fPacketCount;
     fTotalOctetCount += fOutBuf->curPacketSize();
     fOctetCount += fOutBuf->curPacketSize()
@@ -411,6 +416,12 @@
   sink->buildAndSendPacket(false);
 }
 
+// The following is called after TCP was unable to send data
+void MultiFramedRTPSink::sendThisAgain(void* firstArg) {
+  MultiFramedRTPSink* sink = (MultiFramedRTPSink*)firstArg;
+  sink->sendPacketIfNecessary();
+}
+
 void MultiFramedRTPSink::ourHandleClosure(void* clientData) {
   MultiFramedRTPSink* sink = (MultiFramedRTPSink*)clientData;
   // There are no frames left, but we may have a partially built packet
-------------- next part --------------
A non-text attachment was scrubbed...
Name: live.diff
Type: application/octet-stream
Size: 5019 bytes
Desc: not available
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20091118/75c128ca/attachment.obj>


More information about the live-devel mailing list