From fcc49f357e6a537d2ef9ac398eee09bceaf88a80 Mon Sep 17 00:00:00 2001 From: Sebastien Vincent Date: Thu, 14 Jan 2010 16:31:12 +0000 Subject: [PATCH] Bring back local video in video calls. --- .../impl/neomedia/VideoMediaStreamImpl.java | 27 +++ .../device/VideoMediaDeviceSession.java | 166 ++++++++++++++++++ .../protocol/sip/CallPeerMediaHandler.java | 30 ++++ .../impl/protocol/sip/CallPeerSipImpl.java | 6 +- .../OperationSetVideoTelephonySipImpl.java | 31 +--- .../service/neomedia/VideoMediaStream.java | 12 ++ 6 files changed, 242 insertions(+), 30 deletions(-) diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java index fa55ed597..715e1ebda 100644 --- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java @@ -310,6 +310,33 @@ protected boolean fireVideoEvent( videoNotifierSupport.fireVideoEvent(type, visualComponent, origin); } + /** + * Gets local visual Component of the local peer. + * + * @return visual Component + */ + 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 diff --git a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java index 7a11da63b..38141c525 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java @@ -9,7 +9,9 @@ import java.awt.*; import javax.media.*; +import javax.media.protocol.*; +import net.java.sip.communicator.impl.neomedia.*; import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.neomedia.event.*; import net.java.sip.communicator.util.*; @@ -37,6 +39,11 @@ public class VideoMediaDeviceSession private final VideoNotifierSupport videoNotifierSupport = new VideoNotifierSupport(this); + /** + * Local Player for the local video. + */ + private Player localPlayer = null; + /** * Initializes a new VideoMediaDeviceSession instance which is to * represent the work of a MediaStream with a specific video @@ -69,6 +76,23 @@ public void addVideoListener(VideoListener listener) videoNotifierSupport.addVideoListener(listener); } + /** + * Creates the DataSource that this instance is to read captured + * media from. + * + * @return the DataSource that this instance is to read captured + * media from + */ + @Override + protected DataSource createCaptureDevice() + { + /* create our DataSource as Cloneable so we can both use it + * to display local video and stream to remote peer + */ + DataSource captureDevice = Manager.createCloneableDataSource(getDevice().createOutputDataSource()); + return captureDevice; + } + /** * Asserts that a specific MediaDevice is acceptable to be set as * the MediaDevice of this instance. Makes sure that its @@ -149,6 +173,148 @@ protected boolean fireVideoEvent( videoNotifierSupport.fireVideoEvent(type, visualComponent, origin); } + /** + * Get the local Player if it exists, + * create it otherwise + * @return local Player + */ + private Player getLocalPlayer() + { + DataSource dataSource = ((SourceCloneable)getCaptureDevice()).createClone(); + + /* create local player */ + if (localPlayer == null && dataSource != null) + { + Exception excpt = null; + try + { + localPlayer = Manager.createPlayer(dataSource); + } + catch (Exception ex) + { + excpt = ex; + } + + if(excpt == null) + { + localPlayer.addControllerListener(new ControllerListener() + { + public void controllerUpdate(ControllerEvent event) + { + controllerUpdateForCreateLocalVisualComponent(event); + } + }); + localPlayer.start(); + } + else + { + logger.error("Failed to connect to " + + MediaStreamImpl.toString(dataSource), + excpt); + } + } + + return localPlayer; + } + + /** + * Gets notified about ControllerEvents generated by + * {@link #player}. + * + * @param event the ControllerEvent specifying the + * Controller which is the source of the event and the very type of + * the event + */ + private void controllerUpdateForCreateLocalVisualComponent( + ControllerEvent controllerEvent) + { + if (controllerEvent instanceof RealizeCompleteEvent) + { + Player player = (Player) controllerEvent.getSourceController(); + Component visualComponent = player.getVisualComponent(); + + if (visualComponent != null) + { + if(!fireVideoEvent( + VideoEvent.VIDEO_ADDED, + visualComponent, + VideoEvent.LOCAL)) + { + /* no listener interrested by our event + * free resources + */ + if(player == localPlayer) + { + localPlayer = null; + } + + player.stop(); + player.deallocate(); + player.close(); + } + } + } + } + + /** + * Gets local visual Component of the local peer. + * + * @return visual Component + */ + public Component createLocalVisualComponent() + { + Player player = getLocalPlayer(); + return null; + } + + /** + * Dispose local visual Component of the local peer. + */ + public void disposeLocalVisualComponent() + { + Player player = getLocalPlayer(); + + if(player != null) + { + disposeLocalPlayer(player); + } + } + + /** + * Releases the resources allocated by a specific local Player in the + * course of its execution and prepares it to be garbage collected. If the + * specified Player is rendering video, notifies the + * VideoListeners of this instance that its visual + * Component is to no longer be used by firing a + * {@link VideoEvent#VIDEO_REMOVED} VideoEvent. + * + * @param player the Player to dispose of + * @see MediaDeviceSession#disposePlayer(Player) + */ + protected void disposeLocalPlayer(Player player) + { + /* + * The player is being disposed so let the (interested) listeners know + * its Player#getVisualComponent() (if any) should be released. + */ + Component visualComponent = getVisualComponent(player); + + if(localPlayer == player) + { + localPlayer = null; + } + + player.stop(); + player.deallocate(); + player.close(); + + if (visualComponent != null) + fireVideoEvent( + VideoEvent.VIDEO_REMOVED, + visualComponent, + VideoEvent.LOCAL); + } + /** * Returns the visual Component where video from the remote peer * is being rendered or null if no video is currently rendered. diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandler.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandler.java index afbc87b7a..2115301fa 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandler.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandler.java @@ -344,8 +344,15 @@ public CallPeerMediaHandler(CallPeerSipImpl peer) */ public void setLocalVideoTransmissionEnabled(boolean enabled) { + MediaDirection oldValue = videoDirectionUserPreference; + MediaDirection newValue = null; + videoDirectionUserPreference = enabled ? MediaDirection.SENDRECV : MediaDirection.RECVONLY; + + newValue = videoDirectionUserPreference; + + firePropertyChange(OperationSetVideoTelephony.LOCAL_VIDEO_STREAMING, oldValue, newValue); } /** @@ -1886,6 +1893,29 @@ protected boolean fireVideoEvent( return consumed; } + /** + * Gets local visual Component of the local peer. + * + * @return visual Component + */ + public Component createLocalVisualComponent() + { + return (videoStream == null || !isLocalVideoTransmissionEnabled()) ? null : videoStream.createLocalVisualComponent(); + } + + /** + * Dispose local visual Component of the local peer. + * + * @return visual Component + */ + public void disposeLocalVisualComponent() + { + if(videoStream != null) + { + videoStream.disposeLocalVisualComponent(); + } + } + /** * Gets the visual Component in which video from the remote peer is * currently being rendered or null if there is currently no video diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java index 0a737a3fb..e1dd00e97 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java @@ -1507,9 +1507,9 @@ public void propertyChange(PropertyChangeEvent event) listener.propertyChange(thisEvent); } }; -// getMediaHandler() -// .addPropertyChangeListener( -// mediaHandlerPropertyChangeListener); + getMediaHandler() + .addPropertyChangeListener( + mediaHandlerPropertyChangeListener); } } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetVideoTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetVideoTelephonySipImpl.java index 5e959c16b..2de873459 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetVideoTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetVideoTelephonySipImpl.java @@ -89,26 +89,8 @@ public Component createLocalVisualComponent( VideoListener listener) throws OperationFailedException { - /** - * @todo update to neomedia. - CallSession callSession =((CallPeerSipImpl) peer).getMediaCallSession(); - - if (callSession != null) - { - try - { - return callSession.createLocalVisualComponent(listener); - } - catch (MediaException ex) - { - throw new OperationFailedException( - "Failed to create visual Component for local " - +"video (capture).", - OperationFailedException.INTERNAL_ERROR, ex); - } - } - */ - return null; + CallPeerMediaHandler mediaHandler = ((CallPeerSipImpl) peer).getMediaHandler(); + return mediaHandler.createLocalVisualComponent(); } /** @@ -122,13 +104,8 @@ public Component createLocalVisualComponent( */ public void disposeLocalVisualComponent(CallPeer peer, Component component) { - /** - * @todo update to neomedia. - CallSession callSession =((CallPeerSipImpl) peer).getMediaCallSession(); - - if (callSession != null) - callSession.disposeLocalVisualComponent(component); - */ + CallPeerMediaHandler mediaHandler = ((CallPeerSipImpl) peer).getMediaHandler(); + mediaHandler.disposeLocalVisualComponent(); } /** diff --git a/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java b/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java index b48b57230..b76ec1c79 100644 --- a/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java +++ b/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java @@ -20,6 +20,18 @@ public interface VideoMediaStream extends MediaStream { + /** + * Gets local visual Component of the local peer. + * + * @return visual Component + */ + public Component createLocalVisualComponent(); + + /** + * Dispose local visual Component of the local peer. + */ + public void disposeLocalVisualComponent(); + /** * Returns a reference to the visual Component where video from the * remote peer is being rendered or null if no video is currently