From faf387ce0c01040fa92f568d9fff484b655ee554 Mon Sep 17 00:00:00 2001
From: Boris Grozev <boris@jitsi.org>
Date: Thu, 13 Mar 2014 19:21:23 +0100
Subject: [PATCH] Filters RTP packets in accord with the MediaStream direction.
 Fixes problems with new ReceiveStream-s being created while on hold.

---
 .../impl/neomedia/AbstractRTPConnector.java   | 60 +++++++++++++++++++
 .../jitsi/impl/neomedia/MediaStreamImpl.java  |  7 +++
 .../neomedia/RTPConnectorInputStream.java     | 24 +++++++-
 .../neomedia/RTPConnectorOutputStream.java    | 27 +++++++++
 4 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/src/org/jitsi/impl/neomedia/AbstractRTPConnector.java b/src/org/jitsi/impl/neomedia/AbstractRTPConnector.java
index 86b254eb..b2dc565c 100755
--- a/src/org/jitsi/impl/neomedia/AbstractRTPConnector.java
+++ b/src/org/jitsi/impl/neomedia/AbstractRTPConnector.java
@@ -12,6 +12,7 @@
 import javax.media.rtp.*;
 
 import org.jitsi.service.neomedia.*;
+import org.jitsi.util.*;
 
 /**
  * Provides a base/default implementation of <tt>RTPConnector</tt> which has
@@ -20,10 +21,18 @@
  *
  * @author Bing SU (nova.su@gmail.com)
  * @author Lyubomir Marinov
+ * @author Boris Grozev
  */
 public abstract class AbstractRTPConnector
     implements RTPConnector
 {
+    /**
+     * The <tt>Logger</tt> used by the <tt>AbstractRTPConnector</tt> class
+     * and its instances to print debug information.
+     */
+    private static final Logger logger
+            = Logger.getLogger(AbstractRTPConnector.class);
+
     /**
      * The pair of datagram sockets for RTP and RTCP traffic that this instance
      * uses in the form of a <tt>StreamConnector</tt>.
@@ -412,4 +421,55 @@ public void setSendBufferSize(int size)
     {
         // Nothing should be done here :-)
     }
+
+    /**
+     * Configures this <tt>AbstractRTPConnector</tt> to allow RTP in the
+     * specified direction. That is, enables/disables the input and output data
+     * streams according to <tt>direction</tt>.
+     *
+     * Note that the control (RTCP) streams are not affected (they are always
+     * kept enabled).
+     *
+     * @param direction Specifies how to configure the data streams of this
+     * <tt>AbstractRTPConnector</tt>. The input stream will be enabled or
+     * disabled depending on whether <tt>direction</tt> allows receiving. The
+     * output stream will be enabled or disabled depending on whether
+     * <tt>direction</tt> allows sending.
+     */
+    public void setDirection(MediaDirection direction)
+    {
+        boolean receive = direction.allowsReceiving();
+        boolean send = direction.allowsSending();
+
+        if (logger.isDebugEnabled())
+            logger.debug("setDirection " + direction);
+
+        try
+        {
+            // forcing the stream to be created causes problems
+            RTPConnectorInputStream dataInputStream = getDataInputStream(false);
+            if(dataInputStream != null)
+                dataInputStream.setEnabled(receive);
+        }
+        catch (IOException ioe)
+        {
+            logger.error("Failed to " + (receive ? "enable" : "disable")
+                    + " data input stream.");
+        }
+
+        try
+        {
+            // forcing the stream to be created causes problems
+            RTPConnectorOutputStream dataOutputStream
+                    = getDataOutputStream(false);
+            if (dataOutputStream != null)
+                dataOutputStream.setEnabled(send);
+        }
+        catch (IOException ioe)
+        {
+            logger.error("Failed to " + (send ? "enable" : "disable")
+                                 + " data output stream.");
+
+        }
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/MediaStreamImpl.java b/src/org/jitsi/impl/neomedia/MediaStreamImpl.java
index ddb4dbff..0329dd8d 100644
--- a/src/org/jitsi/impl/neomedia/MediaStreamImpl.java
+++ b/src/org/jitsi/impl/neomedia/MediaStreamImpl.java
@@ -1806,6 +1806,13 @@ public void setDirection(MediaDirection direction)
         }
         if (started)
             start(this.direction);
+
+        // make sure that RTP is filtered in accord with the direction of this
+        // MediaStream, so that we don't have to worry about, for example,
+        // new ReceiveStream-s being created while in sendonly/inactive.
+        AbstractRTPConnector connector = getRTPConnector();
+        if (connector != null)
+            connector.setDirection(direction);
     }
 
     /**
diff --git a/src/org/jitsi/impl/neomedia/RTPConnectorInputStream.java b/src/org/jitsi/impl/neomedia/RTPConnectorInputStream.java
index 501162f6..1a6d19a6 100755
--- a/src/org/jitsi/impl/neomedia/RTPConnectorInputStream.java
+++ b/src/org/jitsi/impl/neomedia/RTPConnectorInputStream.java
@@ -114,6 +114,12 @@ public abstract class RTPConnectorInputStream
      */
     private SourceTransferHandler transferHandler;
 
+    /**
+     * Whether this <tt>RTPConnectorInputStream</tt> is enabled or disabled.
+     * While disabled, the stream does not accept any packets.
+     */
+    private boolean enabled = true;
+
     /**
      * Initializes a new <tt>RTPConnectorInputStream</tt> which is to receive
      * packet data from a specific UDP socket.
@@ -476,7 +482,9 @@ public void run()
                 = getDatagramPacketFilters();
             boolean accept;
 
-            if (datagramPacketFilters == null)
+            if (!enabled)
+                accept = false;
+            else if (datagramPacketFilters == null)
                 accept = true;
             else
             {
@@ -648,4 +656,18 @@ public synchronized void addDatagramPacketFilter(
             datagramPacketFilters = newDatagramPacketFilters;
         }
     }
+
+    /**
+     * Enables or disables this <tt>RTPConnectorInputStream</tt>.
+     * While the stream is disabled, it does not accept any packets.
+     *
+     * @param enabled <tt>true</tt> to enable, <tt>false</tt> to disable.
+     */
+    public void setEnabled(boolean enabled)
+    {
+        if (logger.isDebugEnabled())
+            logger.debug("setEnabled: " + enabled);
+
+        this.enabled = enabled;
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/RTPConnectorOutputStream.java b/src/org/jitsi/impl/neomedia/RTPConnectorOutputStream.java
index 24ca5dea..6ed59026 100755
--- a/src/org/jitsi/impl/neomedia/RTPConnectorOutputStream.java
+++ b/src/org/jitsi/impl/neomedia/RTPConnectorOutputStream.java
@@ -80,6 +80,13 @@ public abstract class RTPConnectorOutputStream
      */
     private long numberOfPackets = 0;
 
+    /**
+     * Whether this <tt>RTPConnectorOutputStream</tt> is enabled or disabled.
+     * While the stream is disabled, it suppresses actually sending any packets
+     * via {@link #send(RawPacket)}.
+     */
+    private boolean enabled = true;
+
     /**
      * Initializes a new <tt>RTPConnectorOutputStream</tt> which is to send
      * packet data out through a specific socket.
@@ -363,6 +370,11 @@ public int write(byte[] buffer, int offset, int length)
         if (logger.isDebugEnabled() && targets.isEmpty())
             logger.debug("Write called without targets!", new Throwable());
 
+        // no need to handle the buffer at all, if we are disabled, but simulate
+        // a successful operation.
+        if (!enabled)
+            return length;
+
         // get the array of RawPackets we need to send
         RawPacket[] pkts = createRawPacket(buffer, offset, length);
         boolean fail = false;
@@ -630,4 +642,19 @@ public void write(RawPacket packet)
             while (true);
         }
     }
+
+    /**
+     * Enables or disables this <tt>RTPConnectorOutputStream</tt>.
+     * While the stream is disabled, it suppresses actually sending any packets
+     * via {@link #send(RawPacket)}.
+     *
+     * @param enabled <tt>true</tt> to enable, <tt>false</tt> to disable.
+     */
+    public void setEnabled(boolean enabled)
+    {
+        if (logger.isDebugEnabled())
+            logger.debug("setEnabled: " + enabled);
+
+        this.enabled = enabled;
+    }
 }
-- 
GitLab