|
|
|
|
@ -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 <tt>Player</tt> for the local video.
|
|
|
|
|
*/
|
|
|
|
|
private Player localPlayer = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes a new <tt>VideoMediaDeviceSession</tt> instance which is to
|
|
|
|
|
* represent the work of a <tt>MediaStream</tt> with a specific video
|
|
|
|
|
@ -69,6 +76,23 @@ public void addVideoListener(VideoListener listener)
|
|
|
|
|
videoNotifierSupport.addVideoListener(listener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates the <tt>DataSource</tt> that this instance is to read captured
|
|
|
|
|
* media from.
|
|
|
|
|
*
|
|
|
|
|
* @return the <tt>DataSource</tt> 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 <tt>MediaDevice</tt> is acceptable to be set as
|
|
|
|
|
* the <tt>MediaDevice</tt> of this instance. Makes sure that its
|
|
|
|
|
@ -149,6 +173,148 @@ protected boolean fireVideoEvent(
|
|
|
|
|
videoNotifierSupport.fireVideoEvent(type, visualComponent, origin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the local <tt>Player</tt> if it exists,
|
|
|
|
|
* create it otherwise
|
|
|
|
|
* @return local <tt>Player</tt>
|
|
|
|
|
*/
|
|
|
|
|
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 <tt>ControllerEvent</tt>s generated by
|
|
|
|
|
* {@link #player}.
|
|
|
|
|
*
|
|
|
|
|
* @param event the <tt>ControllerEvent</tt> specifying the
|
|
|
|
|
* <tt>Controller</tt> 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 <tt>Component</tt> of the local peer.
|
|
|
|
|
*
|
|
|
|
|
* @return visual <tt>Component</tt>
|
|
|
|
|
*/
|
|
|
|
|
public Component createLocalVisualComponent()
|
|
|
|
|
{
|
|
|
|
|
Player player = getLocalPlayer();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dispose local visual <tt>Component</tt> of the local peer.
|
|
|
|
|
*/
|
|
|
|
|
public void disposeLocalVisualComponent()
|
|
|
|
|
{
|
|
|
|
|
Player player = getLocalPlayer();
|
|
|
|
|
|
|
|
|
|
if(player != null)
|
|
|
|
|
{
|
|
|
|
|
disposeLocalPlayer(player);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Releases the resources allocated by a specific local <tt>Player</tt> in the
|
|
|
|
|
* course of its execution and prepares it to be garbage collected. If the
|
|
|
|
|
* specified <tt>Player</tt> is rendering video, notifies the
|
|
|
|
|
* <tt>VideoListener</tt>s of this instance that its visual
|
|
|
|
|
* <tt>Component</tt> is to no longer be used by firing a
|
|
|
|
|
* {@link VideoEvent#VIDEO_REMOVED} <tt>VideoEvent</tt>.
|
|
|
|
|
*
|
|
|
|
|
* @param player the <tt>Player</tt> 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 <tt>Component</tt> where video from the remote peer
|
|
|
|
|
* is being rendered or <tt>null</tt> if no video is currently rendered.
|
|
|
|
|
|