svn commit: r7040 - trunk/src/net/java/sip/communicator/impl/neomedia: . device

lubomir_m at dev.java.net lubomir_m at dev.java.net
Fri Apr 23 22:45:41 CEST 2010


Author: lubomir_m
Date: 2010-04-23 20:45:39+0000
New Revision: 7040

Modified:
   trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
   trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
   trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java

Log:
Attempts to fix the following problem: when the remote peer in a video call turns off her video, the UI displaying the remote video remains (and, of course, since the remote peer no longer sends video, the local peer either sees the last received frame or a black rectangle). Also fixes an incorrect stopping of the playback of the remote media.

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java?view=diff&rev=7040&p1=trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java&r1=7039&r2=7040
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java	2010-04-23 20:45:39+0000
@@ -764,7 +764,6 @@
                 if (entry.getValue().getEncoding().equals(encoding))
                     return entry.getKey().byteValue();
             }
-
             return -1;
         }
     }
@@ -871,6 +870,16 @@
     }
 
     /**
+     * Gets the <tt>ZrtpControl</tt> which controls the ZRTP of this stream.
+     *
+     * @return the <tt>ZrtpControl</tt> which controls the ZRTP of this stream
+     */
+    public ZrtpControl getZrtpControl()
+    {
+        return zrtpControl;
+    }
+
+    /**
      * Determines whether this <tt>MediaStream</tt> is set to transmit "silence"
      * instead of the media being fed from its <tt>MediaDevice</tt>. "Silence"
      * for video is understood as video data which is not the captured video
@@ -1206,7 +1215,6 @@
      * media in this instance or {@link MediaDirection#SENDONLY} to only start
      * the capture of media in this instance
      */
-    @SuppressWarnings("unchecked")
     private void start(MediaDirection direction)
     {
         if (direction == null)
@@ -1230,46 +1238,7 @@
                 && ((startedDirection == null)
                         || !startedDirection.allowsReceiving()))
         {
-            RTPManager rtpManager = getRTPManager();
-            Iterable<ReceiveStream> receiveStreams;
-
-            try
-            {
-                receiveStreams = rtpManager.getReceiveStreams();
-            }
-            catch (Exception e)
-            {
-                /*
-                 * it appears that in early call states, when there are no
-                 * streams this method could throw a null pointer exception.
-                 * Make sure we handle it gracefully
-                 */
-                logger.trace("Failed to retrieve receive streams", e);
-                receiveStreams = null;
-            }
-
-            if (receiveStreams != null)
-                for (ReceiveStream receiveStream : receiveStreams)
-                    try
-                    {
-                        DataSource receiveStreamDataSource
-                            = receiveStream.getDataSource();
-
-                        /*
-                         * For an unknown reason, the stream DataSource can be
-                         * null at the end of the Call after re-INVITEs have
-                         * been handled.
-                         */
-                        if (receiveStreamDataSource != null)
-                            receiveStreamDataSource.start();
-                    }
-                    catch (IOException ioe)
-                    {
-                        logger
-                            .warn(
-                                "Failed to start stream " + receiveStream,
-                                ioe);
-                    }
+            startReceiveStreams();
 
             getDeviceSession().start(MediaDirection.RECVONLY);
 
@@ -1281,8 +1250,65 @@
     }
 
     /**
+     * Starts the <tt>ReceiveStream</tt>s that this instance is receiving from
+     * its remote peer. By design, a <tt>MediaStream</tt> instance is associated
+     * with a single <tt>ReceiveStream</tt> at a time. However, the
+     * <tt>ReceiveStream</tt>s are created by <tt>RTPManager</tt> and it tracks
+     * multiple <tt>ReceiveStream</tt>s. In practice, the <tt>RTPManager</tt> of
+     * this <tt>MediaStreamImpl</tt> will have a single <tt>ReceiveStream</tt>
+     * in its list.
+     */
+    @SuppressWarnings("unchecked")
+    private void startReceiveStreams()
+    {
+        RTPManager rtpManager = getRTPManager();
+        Iterable<ReceiveStream> receiveStreams;
+
+        try
+        {
+            receiveStreams = rtpManager.getReceiveStreams();
+        }
+        catch (Exception ex)
+        {
+            /*
+             * It appears that in early call states when there are no streams, a
+             * NullPointerException could be thrown. Make sure we handle it
+             * gracefully.
+             */
+            logger.trace("Failed to retrieve receive streams", ex);
+            receiveStreams = null;
+        }
+
+        if (receiveStreams != null)
+        {
+            for (ReceiveStream receiveStream : receiveStreams)
+            {
+                try
+                {
+                    DataSource receiveStreamDataSource
+                        = receiveStream.getDataSource();
+
+                    /*
+                     * For an unknown reason, the stream DataSource can be null
+                     * at the end of the Call after re-INVITEs have been
+                     * handled.
+                     */
+                    if (receiveStreamDataSource != null)
+                        receiveStreamDataSource.start();
+                }
+                catch (IOException ioex)
+                {
+                    logger.warn(
+                            "Failed to start stream " + receiveStream,
+                            ioex);
+                }
+            }
+        }
+    }
+
+    /**
      * Starts the <tt>SendStream</tt>s of the <tt>RTPManager</tt> of this
-     * <tt>MediaStream</tt>.
+     * <tt>MediaStreamImpl</tt>.
      */
     private void startSendStreams()
     {
@@ -1300,7 +1326,9 @@
         Iterable<SendStream> sendStreams = rtpManager.getSendStreams();
 
         if (sendStreams != null)
+        {
             for (SendStream sendStream : sendStreams)
+            {
                 try
                 {
                     // TODO Are we sure we want to connect here?
@@ -1309,17 +1337,19 @@
                     sendStream.getDataSource().start();
 
                     if (logger.isTraceEnabled())
-                        logger
-                            .trace(
-                                "Started SendStream"
-                                    + " with hashCode "
+                    {
+                        logger.trace(
+                                "Started SendStream with hashCode "
                                     + sendStream.hashCode());
+                    }
                 }
                 catch (IOException ioe)
                 {
                     logger
                         .warn("Failed to start stream " + sendStream, ioe);
                 }
+            }
+        }
     }
 
     /**
@@ -1344,7 +1374,6 @@
      * media in this instance or {@link MediaDirection#SENDONLY} to only stop
      * the capture of media in this instance
      */
-    @SuppressWarnings("unchecked")
     private void stop(MediaDirection direction)
     {
         if (direction == null)
@@ -1374,45 +1403,7 @@
             && (MediaDirection.SENDRECV.equals(startedDirection)
                     || MediaDirection.RECVONLY.equals(startedDirection)))
         {
-            Iterable<ReceiveStream> receiveStreams;
-
-            try
-            {
-                receiveStreams = rtpManager.getReceiveStreams();
-            }
-            catch (Exception e)
-            {
-                /*
-                 * it appears that in early call states, when there are no
-                 * streams this method could throw a null pointer exception.
-                 * Make sure we handle it gracefully
-                 */
-                logger.trace("Failed to retrieve receive streams", e);
-                receiveStreams = null;
-            }
-
-            if (receiveStreams != null)
-                for (ReceiveStream receiveStream : receiveStreams)
-                    try
-                    {
-                        DataSource receiveStreamDataSource
-                            = receiveStream.getDataSource();
-
-                        /*
-                         * For an unknown reason, the stream DataSource can be
-                         * null at the end of the Call after re-INVITEs have
-                         * been handled.
-                         */
-                        if (receiveStreamDataSource != null)
-                            receiveStreamDataSource.stop();
-                    }
-                    catch (IOException ioe)
-                    {
-                        logger
-                            .warn(
-                                "Failed to stop stream " + receiveStream,
-                                ioe);
-                    }
+            stopReceiveStreams();
 
             if (deviceSession != null)
                 deviceSession.stop(MediaDirection.RECVONLY);
@@ -1425,7 +1416,61 @@
     }
 
     /**
-     * Stops the <tt>SendStream</tt> that this instance is sending to its
+     * Stops the <tt>ReceiveStream</tt>s that this instance is receiving from
+     * its remote peer. By design, a <tt>MediaStream</tt> instance is associated
+     * with a single <tt>ReceiveStream</tt> at a time. However, the
+     * <tt>ReceiveStream</tt>s are created by <tt>RTPManager</tt> and it tracks
+     * multiple <tt>ReceiveStream</tt>s. In practice, the <tt>RTPManager</tt> of
+     * this <tt>MediaStreamImpl</tt> will have a single <tt>ReceiveStream</tt>
+     * in its list.
+     */
+    @SuppressWarnings("unchecked")
+    private void stopReceiveStreams()
+    {
+        Iterable<ReceiveStream> receiveStreams;
+
+        try
+        {
+            receiveStreams = rtpManager.getReceiveStreams();
+        }
+        catch (Exception ex)
+        {
+            /*
+             * It appears that in early call states when there are no streams, a
+             * NullPointerException could be thrown. Make sure we handle it
+             * gracefully.
+             */
+            logger.trace("Failed to retrieve receive streams", ex);
+            receiveStreams = null;
+        }
+
+        if (receiveStreams != null)
+        {
+            for (ReceiveStream receiveStream : receiveStreams)
+            {
+                try
+                {
+                    DataSource receiveStreamDataSource
+                        = receiveStream.getDataSource();
+
+                    /*
+                     * For an unknown reason, the stream DataSource can be null
+                     * at the end of the Call after re-INVITEs have been
+                     * handled.
+                     */
+                    if (receiveStreamDataSource != null)
+                        receiveStreamDataSource.stop();
+                }
+                catch (IOException ioex)
+                {
+                    logger.warn("Failed to stop stream " + receiveStream, ioex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Stops the <tt>SendStream</tt>s that this instance is sending to its
      * remote peer and optionally closes them.
      *
      * @param close <tt>true</tt> to close the <tt>SendStream</tt>s that this
@@ -1549,10 +1594,11 @@
                 long receiveStreamSSRC = receiveStream.getSSRC();
 
                 if (logger.isTraceEnabled())
-                    logger
-                        .trace(
+                {
+                    logger.trace(
                             "Received new ReceiveStream with ssrc "
                                 + receiveStreamSSRC);
+                }
 
                 setRemoteSourceID(receiveStreamSSRC);
 
@@ -1575,6 +1621,7 @@
             ReceiveStream receiveStream = event.getReceiveStream();
 
             if (receiveStream != null)
+            {
                 synchronized (receiveStreamSyncRoot)
                 {
                     if (this.receiveStream == receiveStream)
@@ -1587,6 +1634,7 @@
                             deviceSession.setReceiveStream(null);
                     }
                 }
+            }
         }
     }
 
@@ -1686,13 +1734,4 @@
 
         return remoteSsrcList;
     }
-
-    /**
-     * The <tt>ZrtpControl</tt> which controls the ZRTP for the current stream.
-     * @return the <tt>ZrtpControl</tt> for the current stream.
-     */
-    public ZrtpControl getZrtpControl()
-    {
-        return zrtpControl;
-    }
 }

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java?view=diff&rev=7040&p1=trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java&r1=7039&r2=7040
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java	2010-04-23 20:45:39+0000
@@ -1519,15 +1519,48 @@
         if (direction == null)
             throw new NullPointerException("direction");
 
+        MediaDirection oldValue = startedDirection;
+
         startedDirection = startedDirection.or(direction);
+        if (!oldValue.equals(startedDirection))
+            startedDirectionChanged(oldValue, startedDirection);
+    }
 
-        if (startedDirection.allowsSending())
+    /**
+     * Notifies this instance that the value of its <tt>startedDirection</tt>
+     * property has changed from a specific <tt>oldValue</tt> to a specific
+     * <tt>newValue</tt>. Allows extenders to override and perform additional
+     * processing of the change. Overriding implementations must call this
+     * implementation in order to ensure the proper execution of this
+     * <tt>MediaDeviceSession</tt>.
+     *
+     * @param oldValue the <tt>MediaDirection</tt> which used to be the value of
+     * the <tt>startedDirection</tt> property of this instance
+     * @param newValue the <tt>MediaDirection</tt> which is the value of the
+     * <tt>startedDirection</tt> property of this instance
+     */
+    protected void startedDirectionChanged(
+            MediaDirection oldValue,
+            MediaDirection newValue)
+    {
+        if (newValue.allowsSending())
         {
             Processor processor = getProcessor();
 
             if (processor != null)
                 startProcessorInAccordWithDirection(processor);
         }
+        else if ((processor != null)
+                    && (processor.getState() > Processor.Configured))
+        {
+            processor.stop();
+            if (logger.isTraceEnabled())
+            {
+                logger.trace(
+                        "Stopped Processor with hashCode "
+                            + processor.hashCode());
+            }
+        }
     }
 
     /**
@@ -1564,6 +1597,8 @@
         if (direction == null)
             throw new NullPointerException("direction");
 
+        MediaDirection oldValue = startedDirection;
+
         switch (startedDirection)
         {
         case SENDRECV:
@@ -1593,17 +1628,8 @@
             throw new IllegalArgumentException("direction");
         }
 
-        if (startedDirection.allowsSending())
-            if ((processor != null)
-                    && (processor.getState() > Processor.Configured))
-            {
-                processor.stop();
-                if (logger.isTraceEnabled())
-                    logger
-                        .trace(
-                            "Stopped Processor with hashCode "
-                                + processor.hashCode());
-            }
+        if (!oldValue.equals(startedDirection))
+            startedDirectionChanged(oldValue, startedDirection);
     }
 
     /**

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java?view=diff&rev=7040&p1=trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java&r1=7039&r2=7040
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java	2010-04-23 20:45:39+0000
@@ -249,10 +249,12 @@
         super.disposePlayer(player);
 
         if (visualComponent != null)
+        {
             fireVideoEvent(
                 VideoEvent.VIDEO_REMOVED,
                 visualComponent,
                 VideoEvent.REMOTE);
+        }
     }
 
     /**
@@ -279,12 +281,13 @@
             int origin)
     {
         if (logger.isTraceEnabled())
-            logger
-                .trace(
+        {
+            logger.trace(
                     "Firing VideoEvent with type "
                         + VideoEvent.typeToString(type)
                         + " and origin "
                         + VideoEvent.originToString(origin));
+        }
 
         return
             videoNotifierSupport.fireVideoEvent(type, visualComponent, origin);
@@ -570,9 +573,22 @@
      */
     public Component getVisualComponent()
     {
-        Player player = getPlayer();
+        Component visualComponent = null;
+
+        /*
+         * When we know (through means such as SDP) that we don't want to
+         * receive, it doesn't make sense to wait for the remote peer to
+         * acknowledge our desire. So we'll just stop depicting the video of the
+         * remote peer regarldess of whether it stops or continues its sending.
+         */
+        if (getStartedDirection().allowsReceiving())
+        {
+            Player player = getPlayer();
 
-        return (player == null) ? null : getVisualComponent(player);
+            if (player != null)
+                visualComponent = getVisualComponent(player);
+        }
+        return visualComponent;
     }
 
     /**
@@ -1067,30 +1083,29 @@
             TrackControl trackControl,
             Format format)
     {
-        Codec codecs[] = null;
         JNIEncoder encoder = null;
         SwScaler scaler = null;
-        int nbCodec = 0;
+        int codecCount = 0;
 
-        /* for H264 we will monitor RTCP feedback
-         * for example if we receive a PLI/FIR message,
-         * we will send a keyframe
+        /* For H.264 we will monitor RTCP feedback. For example, if we receive a
+         * PLI/FIR message, we will send a keyframe.
          */
         if(format.getEncoding().equals("h264/rtp") && usePLI)
         {
             encoder = new JNIEncoder();
 
-            /* encoder need to be notified of RTCP feedback message */
+            // The H.264 encoder needs to be notified of RTCP feedback message.
             try
             {
-                ((ControlTransformInputStream)rtpConnector.
-                    getControlInputStream()).addRTCPFeedbackListener(encoder);
+                ((ControlTransformInputStream)rtpConnector
+                        .getControlInputStream())
+                    .addRTCPFeedbackListener(encoder);
             }
             catch(Exception e)
             {
                 logger.error("Error cannot get RTCP input stream", e);
             }
-            nbCodec++;
+            codecCount++;
         }
 
         if(outputSize != null)
@@ -1101,37 +1116,98 @@
              */
             scaler = new SwScaler();
             scaler.setOutputSize(outputSize);
-            nbCodec++;
+            codecCount++;
         }
 
-        codecs = new Codec[nbCodec];
-        nbCodec = 0;
+        Codec[] codecs = new Codec[codecCount];
 
+        codecCount = 0;
         if(scaler != null)
-        {
-            codecs[nbCodec] = scaler;
-            nbCodec++;
-        }
-
+            codecs[codecCount++] = scaler;
         if(encoder != null)
+            codecs[codecCount++] = encoder;
+
+        if (codecCount != 0)
         {
-            codecs[nbCodec] = encoder;
+            /* Add our custom SwScaler and possibly RTCP aware codec to the
+             * codec chain so that it will be used instead of default.
+             */
+            try
+            {
+                trackControl.setCodecChain(codecs);
+            }
+            catch(UnsupportedPlugInException upiex)
+            {
+                logger.error(
+                        "Failed to add SwScaler/JNIEncoder to codec chain",
+                        upiex);
+            }
         }
 
-        /* Add our custom SwScaler and possibly RTCP aware codec to the codec
-         * chain so that it will be
-         * used instead of default.
+        return super.setProcessorFormat(trackControl, format);
+    }
+
+    /**
+     * Notifies this instance that the value of its <tt>startedDirection</tt>
+     * property has changed from a specific <tt>oldValue</tt> to a specific
+     * <tt>newValue</tt>.
+     *
+     * @param oldValue the <tt>MediaDirection</tt> which used to be the value of
+     * the <tt>startedDirection</tt> property of this instance
+     * @param newValue the <tt>MediaDirection</tt> which is the value of the
+     * <tt>startedDirection</tt> property of this instance
+     */
+    @Override
+    protected void startedDirectionChanged(
+            MediaDirection oldValue,
+            MediaDirection newValue)
+    {
+        super.startedDirectionChanged(oldValue, newValue);
+
+        Player player = getPlayer();
+
+        if (player == null)
+            return;
+
+        int state = player.getState();
+
+        /*
+         * The visual Component of a Player is safe to access and, respectively,
+         * report through a VideoEvent only when the Player is Realized.
          */
-        try
+        if (state < Player.Realized)
+            return;
+
+        if (newValue.allowsReceiving())
         {
-            trackControl.setCodecChain(codecs);
+            if (state != Player.Started)
+            {
+                player.start();
+
+                Component visualComponent = getVisualComponent(player);
+
+                if (visualComponent != null)
+                {
+                    fireVideoEvent(
+                        VideoEvent.VIDEO_ADDED,
+                        visualComponent,
+                        VideoEvent.REMOTE);
+                }
+            }
         }
-        catch(UnsupportedPlugInException upiex)
+        else if (state > Processor.Configured)
         {
-            logger.error("Failed to add SwScaler/JNIEncoder to codec chain",
-                    upiex);
-        }
+            Component visualComponent = getVisualComponent(player);
 
-        return super.setProcessorFormat(trackControl, format);
+            player.stop();
+
+            if (visualComponent != null)
+            {
+                fireVideoEvent(
+                    VideoEvent.VIDEO_REMOVED,
+                    visualComponent,
+                    VideoEvent.REMOTE);
+            }
+        }
     }
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe at sip-communicator.dev.java.net
For additional commands, e-mail: commits-help at sip-communicator.dev.java.net





More information about the commits mailing list