From 14b49cac7f1df51bdea98bdbb6700d14921584a3 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Thu, 8 Apr 2010 10:53:09 +0000 Subject: [PATCH] Fixes a stopping of the remote video/dropping of all remote packets occurring when the received RTP sequence number rewinds. --- .../impl/neomedia/AudioMediaStreamImpl.java | 46 ++++++ .../impl/neomedia/MediaStreamImpl.java | 51 +++--- .../impl/neomedia/VideoMediaStreamImpl.java | 145 ++++++++++-------- .../codec/video/h264/DePacketizer.java | 19 ++- 4 files changed, 156 insertions(+), 105 deletions(-) diff --git a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java index bfdaf5a57..405055599 100644 --- a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java @@ -7,6 +7,7 @@ package net.java.sip.communicator.impl.neomedia; import javax.media.*; +import javax.media.control.*; import javax.media.format.*; import javax.media.rtp.*; @@ -99,6 +100,51 @@ public AudioMediaStreamImpl(StreamConnector connector, this.dtmfTransfrmEngine = new DtmfTransformEngine(this); } + /** + * Performs any optional configuration on the BufferControl of the + * specified RTPManager which is to be used as the + * RTPManager of this MediaStreamImpl. + * + * @param rtpManager the RTPManager which is to be used by this + * MediaStreamImpl + * @param bufferControl the BufferControl of rtpManager on + * which any optional configuration is to be performed + */ + @Override + protected void configureRTPManagerBufferControl( + RTPManager rtpManager, + BufferControl bufferControl) + { + /* + * It appears that if we don't do this managers don't play. You can try + * some other buffer size to see if you can get better smoothness. + */ + String bufferLengthStr + = NeomediaActivator.getConfigurationService() + .getString(PROPERTY_NAME_RECEIVE_BUFFER_LENGTH); + long bufferLength = 100; + + try + { + if ((bufferLengthStr != null) && (bufferLengthStr.length() > 0)) + bufferLength = Long.parseLong(bufferLengthStr); + } + catch (NumberFormatException nfe) + { + logger.warn( + bufferLengthStr + + " is not a valid receive buffer length/long value", + nfe); + } + + bufferLength = bufferControl.setBufferLength(bufferLength); + if (logger.isTraceEnabled()) + logger.trace("Set receiver buffer length to " + bufferLength); + + bufferControl.setEnabledThreshold(true); + bufferControl.setMinimumThreshold(100); + } + /** * A stub that allows audio oriented streams to create and keep a reference * to a DtmfTransformEngine. diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java index 570166e3b..0aba6a68b 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java @@ -52,7 +52,7 @@ public class MediaStreamImpl /** * The name of the property indicating the length of our receive buffer. */ - private static final String PROPERTY_NAME_RECEIVE_BUFFER_LENGTH + protected static final String PROPERTY_NAME_RECEIVE_BUFFER_LENGTH = "net.java.sip.communicator.impl.neomedia.RECEIVE_BUFFER_LENGTH"; /** @@ -228,6 +228,23 @@ public MediaStreamImpl(StreamConnector connector, MediaDevice device, rtpConnector.setEngine(engineChain); } + /** + * Performs any optional configuration on the BufferControl of the + * specified RTPManager which is to be used as the + * RTPManager of this MediaStreamImpl. Allows extenders to + * override. + * + * @param rtpManager the RTPManager which is to be used by this + * MediaStreamImpl + * @param bufferControl the BufferControl of rtpManager on + * which any optional configuration is to be performed + */ + protected void configureRTPManagerBufferControl( + RTPManager rtpManager, + BufferControl bufferControl) + { + } + /** * Creates a chain of transform engines for use with this stream. Note * that this is the only place where the TransformEngineChain is @@ -816,41 +833,11 @@ private RTPManager getRTPManager() rtpManager.addSendStreamListener(this); rtpManager.addSessionListener(this); - /* - * It appears that if we don't do this managers don't play. You can - * try out some other buffer size to see if you can get better - * smoothness. - */ BufferControl bc = (BufferControl) rtpManager.getControl(BufferControl.class.getName()); if (bc != null) - { - String buffStr - = NeomediaActivator - .getConfigurationService() - .getString(PROPERTY_NAME_RECEIVE_BUFFER_LENGTH); - long buff = 100; - - try - { - if ((buffStr != null) && (buffStr.length() > 0)) - buff = Long.parseLong(buffStr); - } - catch (NumberFormatException nfe) - { - logger - .warn( - buffStr - + " is not a valid receive buffer/long value", - nfe); - } - - buff = bc.setBufferLength(buff); - logger.trace("set receiver buffer len to " + buff); - bc.setEnabledThreshold(true); - bc.setMinimumThreshold(100); - } + configureRTPManagerBufferControl(rtpManager, bc); //Emil: if you replace this method with another init method make //sure you check that the line below still works. diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java index 07559dc02..c8e2dcd10 100644 --- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java @@ -240,35 +240,6 @@ public VideoMediaStreamImpl(StreamConnector connector, MediaDevice device, super(connector, device, zrtpControl); } - /** - * Set negociated output size. - * - * @param size output size of video stream - */ - public void setOutputSize(Dimension size) - { - outputSize = size; - } - - /** - * Sets the MediaDevice that this stream should use to play back - * and capture media. - *

- * Note: Also resets any previous direction set with - * {@link #setDirection(MediaDirection)} to the direction of the specified - * MediaDevice. - *

- * - * @param device the MediaDevice that this stream should use to - * play back and capture media - * @see MediaStream#setDevice(MediaDevice) - */ - public void setDevice(MediaDevice device) - { - super.setDevice(device); - ((VideoMediaDeviceSession)deviceSession).setOutputSize(outputSize); - } - /** * Adds a specific VideoListener to this VideoMediaStream * in order to receive notifications when visual/video Components @@ -288,6 +259,46 @@ public void addVideoListener(VideoListener listener) videoNotifierSupport.addVideoListener(listener); } + /** + * Performs any optional configuration on the BufferControl of the + * specified RTPManager which is to be used as the + * RTPManager of this MediaStreamImpl. + * + * @param rtpManager the RTPManager which is to be used by this + * MediaStreamImpl + * @param bufferControl the BufferControl of rtpManager on + * which any optional configuration is to be performed + */ + @Override + protected void configureRTPManagerBufferControl( + RTPManager rtpManager, + BufferControl bufferControl) + { + bufferControl.setBufferLength(BufferControl.MAX_VALUE); + } + + /** + * Creates the visual Component depicting the video being streamed + * from the local peer to the remote peer. + * + * @return the visual Component depicting the video being streamed + * from the local peer to the remote peer if it was immediately created or + * null if it was not immediately created and it is to be delivered + * to the currently registered VideoListeners in a + * VideoEvent with type {@link VideoEvent#VIDEO_ADDED} and origin + * {@link VideoEvent#LOCAL} + */ + public Component createLocalVisualComponent() + { + MediaDeviceSession deviceSession = getDeviceSession(); + + return + (deviceSession instanceof VideoMediaDeviceSession) + ? ((VideoMediaDeviceSession) deviceSession) + .createLocalVisualComponent() + : null; + } + /** * Notifies this MediaStream that the MediaDevice (and * respectively the MediaDeviceSession with it) which this instance @@ -364,6 +375,18 @@ public void videoUpdate(VideoEvent e) } } + /** + * Disposes of the visual Component of the local peer. + */ + public void disposeLocalVisualComponent() + { + MediaDeviceSession deviceSession = getDeviceSession(); + + if(deviceSession instanceof VideoMediaDeviceSession) + ((VideoMediaDeviceSession) deviceSession) + .disposeLocalVisualComponent(); + } + /** * Notifies the VideoListeners registered with this * VideoMediaStream about a specific type of change in the @@ -411,40 +434,6 @@ protected void fireVideoEvent(VideoEvent event) videoNotifierSupport.fireVideoEvent(event); } - /** - * Creates the visual Component depicting the video being streamed - * from the local peer to the remote peer. - * - * @return the visual Component depicting the video being streamed - * from the local peer to the remote peer if it was immediately created or - * null if it was not immediately created and it is to be delivered - * to the currently registered VideoListeners in a - * VideoEvent with type {@link VideoEvent#VIDEO_ADDED} and origin - * {@link VideoEvent#LOCAL} - */ - public Component createLocalVisualComponent() - { - MediaDeviceSession deviceSession = getDeviceSession(); - - return - (deviceSession instanceof VideoMediaDeviceSession) - ? ((VideoMediaDeviceSession) deviceSession) - .createLocalVisualComponent() - : null; - } - - /** - * Dispose local visual Component of the local peer. - */ - public void disposeLocalVisualComponent() - { - MediaDeviceSession deviceSession = getDeviceSession(); - - if(deviceSession instanceof VideoMediaDeviceSession) - ((VideoMediaDeviceSession) deviceSession) - .disposeLocalVisualComponent(); - } - /** * Returns a reference to the visual Component where video from the * remote peer is being rendered or null if no video is currently @@ -501,4 +490,34 @@ public void removeVideoListener(VideoListener listener) { videoNotifierSupport.removeVideoListener(listener); } + + /** + * Sets the MediaDevice that this stream should use to play back + * and capture media. + *

+ * Note: Also resets any previous direction set with + * {@link #setDirection(MediaDirection)} to the direction of the specified + * MediaDevice. + *

+ * + * @param device the MediaDevice that this stream should use to + * play back and capture media + * @see MediaStream#setDevice(MediaDevice) + */ + public void setDevice(MediaDevice device) + { + super.setDevice(device); + + ((VideoMediaDeviceSession)deviceSession).setOutputSize(outputSize); + } + + /** + * Set negociated output size. + * + * @param size output size of video stream + */ + public void setOutputSize(Dimension size) + { + outputSize = size; + } } diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java index f1a36bd3d..61a8507d5 100644 --- a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java +++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java @@ -228,22 +228,21 @@ protected int doProcess(Buffer inBuffer, Buffer outBuffer) if ((lastSequenceNumber != -1) && ((sequenceNumber - lastSequenceNumber) != 1)) { + /* + * Even if (the new) sequenceNumber is less than lastSequenceNumber, + * we have to use it because the received sequence numbers may have + * reached their maximum value and wrapped around starting from + * their minimum value again. + */ if (logger.isTraceEnabled()) logger.trace( - "Dropping RTP packets upto sequenceNumber " + "Dropped RTP packets upto sequenceNumber " + lastSequenceNumber + " and continuing with sequenceNumber " + sequenceNumber); - + // Reset. fuaStartedAndNotEnded = false; - if (sequenceNumber <= lastSequenceNumber) - { - // Drop the input Buffer. - outBuffer.setDiscard(true); - return BUFFER_PROCESSED_OK; - } - else - outBuffer.setLength(0); // Reset. + outBuffer.setLength(0); } lastSequenceNumber = sequenceNumber;