Hi Ross,

Please would you consider adding this patch (or a variation thereof)
into the source tree.

Currently there is no way to notify the application layer if a socket
send error occurs.
The patch addresses this by allowing the registration of a callback
handler on the RTP sink.

Uses:
We use this functionality in our system to kick clients that have insufficient
bandwidth to sustain the media session.

Testing of the patch:
- The patch has been tested over the period of about two months on an
internal test system
- We only considered the RTSP over TCP use case
- During testing the client's TCP receiver buffer would typically fill first
(after constraining the available network bandwidth), followed by the
TCP send buffer filling on the server, followed by a send failure, at
which point the callback handler is triggered that allows application
developers to handle this if so desired.

Patched against the current version of live555. (2011-09-19) with "diff -Naur".

Best regards,
Ralf
diff -Naur live-orig/liveMedia/include/MultiFramedRTPSink.hh live-new/liveMedia/include/MultiFramedRTPSink.hh
--- live-orig/liveMedia/include/MultiFramedRTPSink.hh	2011-09-20 00:03:06.000000000 +0200
+++ live-new/liveMedia/include/MultiFramedRTPSink.hh	2011-10-04 13:54:49.632475345 +0200
@@ -30,6 +30,14 @@
 public:
   void setPacketSizes(unsigned preferredPacketSize, unsigned maxPacketSize);
 
+  typedef void (onSendErrorFunc)(void* clientData);
+  void setOnSendErrorFunc(onSendErrorFunc* onSendErrorFunc,
+		    void* onSendErrorFuncData)
+  {
+    fOnSendErrorFunc = onSendErrorFunc;
+    fOnSendErrorData = onSendErrorFuncData;
+  }
+
 protected:
   MultiFramedRTPSink(UsageEnvironment& env,
 		     Groupsock* rtpgs, unsigned char rtpPayloadType,
@@ -125,6 +133,9 @@
   unsigned fCurFrameSpecificHeaderSize; // size in bytes of cur frame-specific header
   unsigned fTotalFrameSpecificHeaderSizes; // size of all frame-specific hdrs in pkt
   unsigned fOurMaxPacketSize;
+
+  onSendErrorFunc* fOnSendErrorFunc;
+  void* fOnSendErrorData;
 };
 
 #endif
diff -Naur live-orig/liveMedia/include/RTPInterface.hh live-new/liveMedia/include/RTPInterface.hh
--- live-orig/liveMedia/include/RTPInterface.hh	2011-09-20 00:03:06.000000000 +0200
+++ live-new/liveMedia/include/RTPInterface.hh	2011-10-04 13:54:39.344475346 +0200
@@ -64,7 +64,7 @@
   void removeStreamSocket(int sockNum, unsigned char streamChannelId);
   void setServerRequestAlternativeByteHandler(int socketNum, ServerRequestAlternativeByteHandler* handler, void* clientData);
 
-  void sendPacket(unsigned char* packet, unsigned packetSize);
+  Boolean sendPacket(unsigned char* packet, unsigned packetSize);
   void startNetworkReading(TaskScheduler::BackgroundHandlerProc*
                            handlerProc);
   Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize,
diff -Naur live-orig/liveMedia/MultiFramedRTPSink.cpp live-new/liveMedia/MultiFramedRTPSink.cpp
--- live-orig/liveMedia/MultiFramedRTPSink.cpp	2011-09-20 00:03:06.000000000 +0200
+++ live-new/liveMedia/MultiFramedRTPSink.cpp	2011-10-04 13:54:29.436475347 +0200
@@ -42,7 +42,8 @@
 				       unsigned numChannels)
   : RTPSink(env, rtpGS, rtpPayloadType, rtpTimestampFrequency,
 	    rtpPayloadFormatName, numChannels),
-  fOutBuf(NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False) {
+  fOutBuf(NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False),
+  fOnSendErrorFunc(NULL), fOnSendErrorData(NULL){
   setPacketSizes(1000, 1448);
       // Default max packet size (1500, minus allowance for IP, UDP, UMTP headers)
       // (Also, make it a multiple of 4 bytes, just in case that matters.)
@@ -354,7 +355,15 @@
 #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()))
+    {
+      // if failure handler has been specified, call it
+      if (fOnSendErrorFunc != NULL)
+      {
+        (*fOnSendErrorFunc)(fOnSendErrorData);
+      }
+    }
+
     ++fPacketCount;
     fTotalOctetCount += fOutBuf->curPacketSize();
     fOctetCount += fOutBuf->curPacketSize()
diff -Naur live-orig/liveMedia/RTPInterface.cpp live-new/liveMedia/RTPInterface.cpp
--- live-orig/liveMedia/RTPInterface.cpp	2011-09-20 00:03:06.000000000 +0200
+++ live-new/liveMedia/RTPInterface.cpp	2011-10-04 13:54:17.260475348 +0200
@@ -29,7 +29,7 @@
 // Helper routines and data structures, used to implement
 // sending/receiving RTP/RTCP over a TCP socket:
 
-static void sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
+static Boolean sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
 			   int socketNum, unsigned char streamChannelId);
 
 // Reading RTP-over-TCP is implemented using two levels of hash tables.
@@ -182,16 +182,22 @@
 }
 
 
-void RTPInterface::sendPacket(unsigned char* packet, unsigned packetSize) {
+Boolean RTPInterface::sendPacket(unsigned char* packet, unsigned packetSize) {
+  // This method will now return False if any of the sends fail
+  Boolean success = True;
   // Normal case: Send as a UDP packet:
-  fGS->output(envir(), fGS->ttl(), packet, packetSize);
+  if (!fGS->output(envir(), fGS->ttl(), packet, packetSize)) success = False;
 
   // Also, send over each of our TCP sockets:
   for (tcpStreamRecord* streams = fTCPStreams; streams != NULL;
        streams = streams->fNext) {
-    sendRTPOverTCP(packet, packetSize,
-		   streams->fStreamSocketNum, streams->fStreamChannelId);
+    if (!sendRTPOverTCP(packet, packetSize,
+		   streams->fStreamSocketNum, streams->fStreamChannelId))
+    {
+      success = False;
+    }
   }
+  return success;
 }
 
 void RTPInterface
@@ -267,7 +273,7 @@
 
 ////////// Helper Functions - Implementation /////////
 
-void sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
+Boolean sendRTPOverTCP(unsigned char* packet, unsigned packetSize,
                     int socketNum, unsigned char streamChannelId) {
 #ifdef DEBUG
   fprintf(stderr, "sendRTPOverTCP: %d bytes over channel %d (socket %d)\n",
@@ -291,12 +297,13 @@
     fprintf(stderr, "sendRTPOverTCP: completed\n"); fflush(stderr);
 #endif
 
-    return;
+    return True;
   } while (0);
 
 #ifdef DEBUG
   fprintf(stderr, "sendRTPOverTCP: failed!\n"); fflush(stderr);
 #endif
+  return False;
 }
 
 SocketDescriptor::SocketDescriptor(UsageEnvironment& env, int socketNum)
_______________________________________________
live-devel mailing list
live-devel@lists.live555.com
http://lists.live555.com/mailman/listinfo/live-devel

Reply via email to