aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java
diff options
context:
space:
mode:
authorLyubomir Marinov <lyubomir.marinov@jitsi.org>2011-07-26 19:09:24 +0000
committerLyubomir Marinov <lyubomir.marinov@jitsi.org>2011-07-26 19:09:24 +0000
commite46f74f442136d50bb98e1f62041d10087b272e1 (patch)
treeb0329164afddab6b3d16bb92f60769f1d1bb655b /src/net/java
parent95be6b19ee71f612aa53c30f07241ba3e19d0db0 (diff)
downloadjitsi-e46f74f442136d50bb98e1f62041d10087b272e1.zip
jitsi-e46f74f442136d50bb98e1f62041d10087b272e1.tar.gz
jitsi-e46f74f442136d50bb98e1f62041d10087b272e1.tar.bz2
Addresses a possible deadlock in video calls.
Diffstat (limited to 'src/net/java')
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java31
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java10
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java35
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/device/ImageStreamingAuto.java36
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java42
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java57
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopSharingServerSipImpl.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopStreamingSipImpl.java49
-rw-r--r--src/net/java/sip/communicator/service/neomedia/event/VideoNotifierSupport.java261
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java30
12 files changed, 381 insertions, 185 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
index 1489881..7435ef1 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
@@ -787,26 +787,27 @@ public class OneToOneCallPeerPanel
logger.trace("UI video event received originated in: "
+ event.getOrigin() + " and is of type: " + event.getType());
- synchronized (videoContainers)
+ if ((event != null) && !event.isConsumed())
{
- if ((event != null) && !event.isConsumed())
- {
- Component video = event.getVisualComponent();
+ int origin = event.getOrigin();
+ Component video = event.getVisualComponent();
+ synchronized (videoContainers)
+ {
switch (event.getType())
{
case VideoEvent.VIDEO_ADDED:
- if(event.getOrigin() == VideoEvent.LOCAL)
+ if (origin == VideoEvent.LOCAL)
{
this.localVideo = video;
this.closeButton = new CloseButton();
}
- else if(event.getOrigin() == VideoEvent.REMOTE)
+ else if (origin == VideoEvent.REMOTE)
{
this.remoteVideo = video;
}
- addMouseListeners(event.getOrigin());
+ addMouseListeners(origin);
/*
* Let the creator of the local visual Component know it
@@ -816,16 +817,18 @@ public class OneToOneCallPeerPanel
break;
case VideoEvent.VIDEO_REMOVED:
- if (event.getOrigin() == VideoEvent.LOCAL &&
- localVideo == video)
+ if (origin == VideoEvent.LOCAL)
{
- this.localVideo = null;
- this.closeButton = null;
+ if (localVideo == video)
+ {
+ this.localVideo = null;
+ this.closeButton = null;
+ }
}
- else if(event.getOrigin() == VideoEvent.REMOTE &&
- remoteVideo == video)
+ else if (origin == VideoEvent.REMOTE)
{
- this.remoteVideo = null;
+ if (remoteVideo == video)
+ this.remoteVideo = null;
}
break;
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
index 313e755..3f85d06 100644
--- a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
@@ -272,7 +272,7 @@ public class MediaServiceImpl
break;
case VIDEO:
captureDeviceInfo
- = getDeviceConfiguration().getVideoCaptureDevice(useCase);
+ = getDeviceConfiguration().getVideoCaptureDevice(useCase);
break;
default:
captureDeviceInfo = null;
@@ -314,10 +314,12 @@ public class MediaServiceImpl
}
}
- //Don't use the device in case the user has disabled all codecs for that
- //kind of media.
+ /*
+ * Don't use the device in case the user has disabled all codecs for
+ * that kind of media.
+ */
if ((defaultDevice != null)
- && (defaultDevice.getSupportedFormats().isEmpty()))
+ && (defaultDevice.getSupportedFormats().isEmpty()))
{
defaultDevice = null;
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
index 3fafa9e..8f51a76 100644
--- a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java
@@ -1392,7 +1392,7 @@ public class MediaStreamImpl
deviceSessionPropertyChangeListener);
// keep player active
- deviceSession.setDisposePlayerWhenClose(false);
+ deviceSession.setDisposePlayerOnClose(false);
deviceSession.close();
deviceSession = null;
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
index 8a1a0f7..a769354 100644
--- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
@@ -236,9 +236,18 @@ public class VideoMediaStreamImpl
/**
* The facility which aids this instance in managing a list of
* <tt>VideoListener</tt>s and firing <tt>VideoEvent</tt>s to them.
+ * <p>
+ * Since the <tt>videoNotifierSupport</tt> of this
+ * <tt>VideoMediaStreamImpl</tt> just forwards the <tt>VideoEvent</tt>s of
+ * the associated <tt>VideoMediaDeviceSession</tt> at the time of this
+ * writing, it does not make sense to have <tt>videoNotifierSupport</tt>
+ * executing asynchronously because it does not know whether it has to wait
+ * for the delivery of the <tt>VideoEvent</tt>s and thus it has to default
+ * to waiting anyway.
+ * </p>
*/
private final VideoNotifierSupport videoNotifierSupport
- = new VideoNotifierSupport(this);
+ = new VideoNotifierSupport(this, true);
/**
* Initializes a new <tt>VideoMediaStreamImpl</tt> instance which will use
@@ -408,7 +417,8 @@ public class VideoMediaStreamImpl
if (fireVideoEvent(
e.getType(),
e.getVisualComponent(),
- e.getOrigin()))
+ e.getOrigin(),
+ true))
e.consume();
}
@@ -429,7 +439,7 @@ public class VideoMediaStreamImpl
public void videoUpdate(VideoEvent e)
{
- fireVideoEvent(e);
+ fireVideoEvent(e, true);
}
};
}
@@ -480,6 +490,9 @@ public class VideoMediaStreamImpl
* @param origin {@link VideoEvent#LOCAL} if the origin of the video is
* local (e.g. it is being locally captured); {@link VideoEvent#REMOTE} if
* the origin of the video is remote (e.g. a remote peer is streaming it)
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
* @return <tt>true</tt> if this event and, more specifically, the visual
* <tt>Component</tt> it describes have been consumed and should be
* considered owned, referenced (which is important because
@@ -487,9 +500,8 @@ public class VideoMediaStreamImpl
* otherwise, <tt>false</tt>
*/
protected boolean fireVideoEvent(
- int type,
- Component visualComponent,
- int origin)
+ int type, Component visualComponent, int origin,
+ boolean wait)
{
if (logger.isTraceEnabled())
logger
@@ -500,7 +512,9 @@ public class VideoMediaStreamImpl
+ VideoEvent.originToString(origin));
return
- videoNotifierSupport.fireVideoEvent(type, visualComponent, origin);
+ videoNotifierSupport.fireVideoEvent(
+ type, visualComponent, origin,
+ wait);
}
/**
@@ -509,10 +523,13 @@ public class VideoMediaStreamImpl
*
* @param event the <tt>VideoEvent</tt> to be fired to the
* <tt>VideoListener</tt>s registered with this instance
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
*/
- protected void fireVideoEvent(VideoEvent event)
+ protected void fireVideoEvent(VideoEvent event, boolean wait)
{
- videoNotifierSupport.fireVideoEvent(event);
+ videoNotifierSupport.fireVideoEvent(event, wait);
}
/**
diff --git a/src/net/java/sip/communicator/impl/neomedia/device/ImageStreamingAuto.java b/src/net/java/sip/communicator/impl/neomedia/device/ImageStreamingAuto.java
index 2765772..fb2db9b 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/ImageStreamingAuto.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/ImageStreamingAuto.java
@@ -76,37 +76,33 @@ public class ImageStreamingAuto
for(ScreenDevice screen : screens)
{
Dimension size = screenSize != null ? screenSize : screen.getSize();
-
- Format formats[]= new Format[]
- {
- new AVFrameFormat(
- size,
- Format.NOT_SPECIFIED,
- FFmpeg.PIX_FMT_ARGB,
- Format.NOT_SPECIFIED),
- new RGBFormat(
- size, // size
- Format.NOT_SPECIFIED, // maxDataLength
- Format.byteArray, // dataType
- Format.NOT_SPECIFIED, // frameRate
- 32, // bitsPerPixel
- 2 /* red */, 3 /* green */, 4 /* blue */)
- };
-
+ Format formats[]
+ = new Format[]
+ {
+ new AVFrameFormat(
+ size,
+ Format.NOT_SPECIFIED,
+ FFmpeg.PIX_FMT_ARGB,
+ Format.NOT_SPECIFIED),
+ new RGBFormat(
+ size, // size
+ Format.NOT_SPECIFIED, // maxDataLength
+ Format.byteArray, // dataType
+ Format.NOT_SPECIFIED, // frameRate
+ 32, // bitsPerPixel
+ 2 /* red */, 3 /* green */, 4 /* blue */)
+ };
CaptureDeviceInfo devInfo
= new CaptureDeviceInfo(
name + " " + i,
new MediaLocator(LOCATOR_PROTOCOL + ":" + i),
formats);
- /* add to JMF device manager */
CaptureDeviceManager.addDevice(devInfo);
i++;
if(multipleMonitorOneScreen)
- {
break;
- }
}
CaptureDeviceManager.commit();
diff --git a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
index 986d21e..d3301b9 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java
@@ -174,9 +174,9 @@ public class MediaDeviceSession
private MediaDirection startedDirection = MediaDirection.INACTIVE;
/**
- * If the player have to be disposed when we #close() this instance.
+ * If the player have to be disposed when we {@link #close()} this instance.
*/
- private boolean disposePlayerWhenClose = true;
+ private boolean disposePlayerOnClose = true;
/**
* Whether output size has changed after latest processor config.
@@ -204,9 +204,9 @@ public class MediaDeviceSession
*
* @param dispose value to set
*/
- public void setDisposePlayerWhenClose(boolean dispose)
+ public void setDisposePlayerOnClose(boolean dispose)
{
- disposePlayerWhenClose = dispose;
+ disposePlayerOnClose = dispose;
}
/**
@@ -337,11 +337,9 @@ public class MediaDeviceSession
disconnectCaptureDevice();
closeProcessor();
- if(disposePlayerWhenClose)
- {
- // playback
+ // playback
+ if (disposePlayerOnClose)
disposePlayer();
- }
}
/**
@@ -363,8 +361,16 @@ public class MediaDeviceSession
if (processor.getState() == Processor.Realized)
{
- DataSource dataOutput = processor.getDataOutput();
+ DataSource dataOutput;
+ try
+ {
+ dataOutput = processor.getDataOutput();
+ }
+ catch (NotRealizedError nre)
+ {
+ dataOutput = null;
+ }
if (dataOutput != null)
dataOutput.disconnect();
}
@@ -590,11 +596,23 @@ public class MediaDeviceSession
*/
private void disposePlayer()
{
+ Player player;
+
synchronized (playbackSyncRoot)
{
- if (player != null)
- disposePlayer(player);
+ /*
+ * If #disposePlayer(Player) is just executed inside the
+ * synchronized block protected by #playbackSyncRoot, it practically
+ * locks the rest of the state protected by the same synchronization
+ * root. But that is not necessary because #disposePlayer(Player)
+ * will protect #player when necessary. Anyway, the change from the
+ * described behavior to the current one has been made while solving
+ * a deadlock.
+ */
+ player = this.player;
}
+ if (player != null)
+ disposePlayer(player);
}
/**
@@ -1815,7 +1833,7 @@ public class MediaDeviceSession
*/
protected void transferRenderingSession(MediaDeviceSession session)
{
- if(session.disposePlayerWhenClose)
+ if (session.disposePlayerOnClose)
{
logger.error("Cannot tranfer rendering session if " +
"MediaDeviceSession has closed it");
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 a20f1fd..af09bba 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java
@@ -115,7 +115,7 @@ public class VideoMediaDeviceSession
* <tt>VideoListener</tt>s and firing <tt>VideoEvent</tt>s to them.
*/
private final VideoNotifierSupport videoNotifierSupport
- = new VideoNotifierSupport(this);
+ = new VideoNotifierSupport(this, false);
/**
* Initializes a new <tt>VideoMediaDeviceSession</tt> instance which is to
@@ -291,9 +291,8 @@ public class VideoMediaDeviceSession
if (visualComponent != null)
{
fireVideoEvent(
- VideoEvent.VIDEO_REMOVED,
- visualComponent,
- VideoEvent.REMOTE);
+ VideoEvent.VIDEO_REMOVED, visualComponent, VideoEvent.REMOTE,
+ false);
}
}
@@ -309,6 +308,9 @@ public class VideoMediaDeviceSession
* @param origin {@link VideoEvent#LOCAL} if the origin of the video is
* local (e.g. it is being locally captured); {@link VideoEvent#REMOTE} if
* the origin of the video is remote (e.g. a remote peer is streaming it)
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
* @return <tt>true</tt> if this event and, more specifically, the visual
* <tt>Component</tt> it describes have been consumed and should be
* considered owned, referenced (which is important because
@@ -316,9 +318,8 @@ public class VideoMediaDeviceSession
* otherwise, <tt>false</tt>
*/
protected boolean fireVideoEvent(
- int type,
- Component visualComponent,
- int origin)
+ int type, Component visualComponent, int origin,
+ boolean wait)
{
if (logger.isTraceEnabled())
{
@@ -330,7 +331,9 @@ public class VideoMediaDeviceSession
}
return
- videoNotifierSupport.fireVideoEvent(type, visualComponent, origin);
+ videoNotifierSupport.fireVideoEvent(
+ type, visualComponent, origin,
+ wait);
}
/**
@@ -339,10 +342,13 @@ public class VideoMediaDeviceSession
*
* @param videoEvent the <tt>VideoEvent</tt> to be fired to the
* <tt>VideoListener</tt>s registered with this instance
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
*/
- protected void fireVideoEvent(VideoEvent videoEvent)
+ protected void fireVideoEvent(VideoEvent videoEvent, boolean wait)
{
- videoNotifierSupport.fireVideoEvent(videoEvent);
+ videoNotifierSupport.fireVideoEvent(videoEvent, wait);
}
/**
@@ -498,7 +504,8 @@ public class VideoMediaDeviceSession
if (fireVideoEvent(
VideoEvent.VIDEO_ADDED,
visualComponent,
- VideoEvent.LOCAL))
+ VideoEvent.LOCAL,
+ true))
{
localVisualComponentConsumed(visualComponent, player);
}
@@ -648,7 +655,9 @@ public class VideoMediaDeviceSession
*/
canvas.setName(DESKTOP_STREAMING_ICON);
- fireVideoEvent(VideoEvent.VIDEO_ADDED, canvas, VideoEvent.LOCAL);
+ fireVideoEvent(
+ VideoEvent.VIDEO_ADDED, canvas, VideoEvent.LOCAL,
+ false);
}
return canvas;
}
@@ -669,9 +678,8 @@ public class VideoMediaDeviceSession
&& DESKTOP_STREAMING_ICON.equals(component.getName()))
{
fireVideoEvent(
- VideoEvent.VIDEO_REMOVED,
- component,
- VideoEvent.LOCAL);
+ VideoEvent.VIDEO_REMOVED, component, VideoEvent.LOCAL,
+ false);
return;
}
@@ -709,9 +717,8 @@ public class VideoMediaDeviceSession
if (visualComponent != null)
fireVideoEvent(
- VideoEvent.VIDEO_REMOVED,
- visualComponent,
- VideoEvent.LOCAL);
+ VideoEvent.VIDEO_REMOVED, visualComponent, VideoEvent.LOCAL,
+ false);
}
/**
@@ -942,9 +949,8 @@ public class VideoMediaDeviceSession
});
fireVideoEvent(
- VideoEvent.VIDEO_ADDED,
- visualComponent,
- VideoEvent.REMOTE);
+ VideoEvent.VIDEO_ADDED, visualComponent, VideoEvent.REMOTE,
+ false);
}
}
@@ -991,7 +997,8 @@ public class VideoMediaDeviceSession
visualComponent,
SizeChangeVideoEvent.REMOTE,
width,
- height));
+ height),
+ false);
}
}
@@ -1516,7 +1523,8 @@ public class VideoMediaDeviceSession
fireVideoEvent(
VideoEvent.VIDEO_ADDED,
visualComponent,
- VideoEvent.REMOTE);
+ VideoEvent.REMOTE,
+ false);
}
}
}
@@ -1531,7 +1539,8 @@ public class VideoMediaDeviceSession
fireVideoEvent(
VideoEvent.VIDEO_REMOVED,
visualComponent,
- VideoEvent.REMOTE);
+ VideoEvent.REMOTE,
+ false);
}
}
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf b/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
index b849ffc..61abd92 100644
--- a/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
+++ b/src/net/java/sip/communicator/impl/neomedia/neomedia.manifest.mf
@@ -10,10 +10,11 @@ Import-Package: org.bouncycastle.crypto,
org.bouncycastle.crypto.macs,
org.bouncycastle.crypto.params,
org.bouncycastle.crypto.prng,
+ org.ice4j.socket,
org.json,
org.osgi.framework,
+ org.w3c.dom,
org.xml.sax,
- org.ice4j.socket,
javax.imageio,
javax.sound.sampled,
javax.swing,
@@ -21,6 +22,7 @@ Import-Package: org.bouncycastle.crypto,
javax.swing.event,
javax.swing.table,
javax.swing.text,
+ javax.xml.parsers,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.fileaccess,
net.java.sip.communicator.service.gui,
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopSharingServerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopSharingServerSipImpl.java
index c677757..a95fabd 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopSharingServerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopSharingServerSipImpl.java
@@ -474,9 +474,7 @@ public class OperationSetDesktopSharingServerSipImpl
byte[] rawContent)
{
if(requestEvent.getDialog() != callPeer.getDialog())
- {
return;
- }
if (rawContent != null)
{
@@ -514,19 +512,14 @@ public class OperationSetDesktopSharingServerSipImpl
List<ComponentEvent> events = null;
Point p = getOrigin();
- events = DesktopSharingProtocolSipImpl.parse(root, size,
- p);
+ events = DesktopSharingProtocolSipImpl.parse(root, size, p);
for(ComponentEvent evt : events)
{
if(evt instanceof MouseEvent)
- {
processMouseEvent((MouseEvent)evt);
- }
else if(evt instanceof KeyEvent)
- {
processKeyboardEvent((KeyEvent)evt);
- }
}
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopStreamingSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopStreamingSipImpl.java
index 8947bac..e8e1d84 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopStreamingSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDesktopStreamingSipImpl.java
@@ -83,10 +83,12 @@ public class OperationSetDesktopStreamingSipImpl
Address toAddress = parentProvider.parseAddressString(uri);
CallSipImpl call = basicTelephony.createOutgoingCall();
+
call.setVideoDevice(mediaDevice);
call.setLocalVideoAllowed(true, getMediaUseCase());
call.invite(toAddress, null);
origin = getOriginForMediaDevice(mediaDevice);
+
return call;
}
@@ -119,6 +121,7 @@ public class OperationSetDesktopStreamingSipImpl
}
CallSipImpl call = basicTelephony.createOutgoingCall();
+
call.setLocalVideoAllowed(true, getMediaUseCase());
call.setVideoDevice(mediaDevice);
call.invite(toAddress, null);
@@ -146,9 +149,9 @@ public class OperationSetDesktopStreamingSipImpl
public Call createVideoCall(String uri)
throws OperationFailedException, ParseException
{
- Call call = super.createVideoCall(uri);
- MediaDevice device = ((CallSipImpl)call).getDefaultDevice(
- MediaType.VIDEO);
+ CallSipImpl call = (CallSipImpl) super.createVideoCall(uri);
+ MediaDevice device = call.getDefaultDevice(MediaType.VIDEO);
+
size = (((VideoMediaFormat)device.getFormat()).getSize());
origin = getOriginForMediaDevice(device);
return call;
@@ -170,9 +173,9 @@ public class OperationSetDesktopStreamingSipImpl
@Override
public Call createVideoCall(Contact callee) throws OperationFailedException
{
- Call call = super.createVideoCall(callee);
- MediaDevice device = ((CallSipImpl)call).getDefaultDevice(
- MediaType.VIDEO);
+ CallSipImpl call = (CallSipImpl) super.createVideoCall(callee);
+ MediaDevice device = call.getDefaultDevice(MediaType.VIDEO);
+
size = (((VideoMediaFormat)device.getFormat()).getSize());
origin = getOriginForMediaDevice(device);
return call;
@@ -188,21 +191,24 @@ public class OperationSetDesktopStreamingSipImpl
* @param allowed <tt>true</tt> if local video transmission is allowed and
* <tt>false</tt> otherwise.
*
- * @throws OperationFailedException if video initialization fails.
+ * @throws OperationFailedException if video initialization fails.
*/
@Override
public void setLocalVideoAllowed(Call call, boolean allowed)
throws OperationFailedException
{
- ((CallSipImpl)call).setLocalVideoAllowed(allowed, MediaUseCase.DESKTOP);
- ((CallSipImpl)call).setVideoDevice(null);
- MediaDevice device = ((CallSipImpl)call).getDefaultDevice(
- MediaType.VIDEO);
- size = (((VideoMediaFormat)device.getFormat()).getSize());
+ CallSipImpl callImpl = (CallSipImpl) call;
+
+ callImpl.setLocalVideoAllowed(allowed, MediaUseCase.DESKTOP);
+ callImpl.setVideoDevice(null);
+
+ MediaDevice device = callImpl.getDefaultDevice(MediaType.VIDEO);
+
+ size = ((VideoMediaFormat)device.getFormat()).getSize();
origin = getOriginForMediaDevice(device);
/* reinvite all peers */
- ((CallSipImpl)call).reInvite();
+ callImpl.reInvite();
}
/**
@@ -267,13 +273,10 @@ public class OperationSetDesktopStreamingSipImpl
CallSipImpl callImpl = (CallSipImpl)call;
MediaDevice device = callImpl.getDefaultDevice(MediaType.VIDEO);
- if(device != null)
- {
- MediaService mediaService = SipActivator.getMediaService();
- return mediaService.isPartialStreaming(device);
- }
-
- return false;
+ return
+ (device == null)
+ ? false
+ : SipActivator.getMediaService().isPartialStreaming(device);
}
/**
@@ -325,8 +328,8 @@ public class OperationSetDesktopStreamingSipImpl
*/
protected static Point getOriginForMediaDevice(MediaDevice device)
{
- MediaService mediaService = SipActivator.getMediaService();
-
- return mediaService.getOriginForDesktopStreamingDevice(device);
+ return
+ SipActivator.getMediaService().getOriginForDesktopStreamingDevice(
+ device);
}
}
diff --git a/src/net/java/sip/communicator/service/neomedia/event/VideoNotifierSupport.java b/src/net/java/sip/communicator/service/neomedia/event/VideoNotifierSupport.java
index 4dffb14..70be427 100644
--- a/src/net/java/sip/communicator/service/neomedia/event/VideoNotifierSupport.java
+++ b/src/net/java/sip/communicator/service/neomedia/event/VideoNotifierSupport.java
@@ -6,18 +6,27 @@
*/
package net.java.sip.communicator.service.neomedia.event;
-import java.awt.Component;
+import java.awt.*;
import java.util.*;
+import java.util.List; // disambiguation
/**
* Represents a mechanism to easily add to a specific <tt>Object</tt> by means
* of composition support for firing <tt>VideoEvent</tt>s to
* <tt>VideoListener</tt>s.
*
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
*/
public class VideoNotifierSupport
{
+ private static final long THREAD_TIMEOUT = 5000;
+
+ /**
+ * The list of <tt>VideoEvent</tt>s which are to be delivered to the
+ * {@link #listeners} registered with this instance when
+ * {@link #synchronous} is equal to <tt>false</tt>.
+ */
+ private final List<VideoEvent> events;
/**
* The list of <tt>VideoListener</tt>s interested in changes in the
@@ -33,6 +42,18 @@ public class VideoNotifierSupport
private final Object source;
/**
+ * The indicator which determines whether this instance delivers the
+ * <tt>VideoEvent</tt>s to the {@link #listeners} synchronously.
+ */
+ private final boolean synchronous;
+
+ /**
+ * The <tt>Thread</tt> in which {@link #events} are delivered to the
+ * {@link #listeners} when {@link #synchronous} is equal to <tt>false</tt>.
+ */
+ private Thread thread;
+
+ /**
* Initializes a new <tt>VideoNotifierSupport</tt> instance which is to
* facilitate the management of <tt>VideoListener</tt>s and firing
* <tt>VideoEvent</tt>s to them for a specific <tt>Object</tt>.
@@ -42,7 +63,25 @@ public class VideoNotifierSupport
*/
public VideoNotifierSupport(Object source)
{
+ this(source, true);
+ }
+
+ /**
+ * Initializes a new <tt>VideoNotifierSupport</tt> instance which is to
+ * facilitate the management of <tt>VideoListener</tt>s and firing
+ * <tt>VideoEvent</tt>s to them for a specific <tt>Object</tt>.
+ *
+ * @param source the <tt>Object</tt> which is to be reported as the source
+ * of the <tt>VideoEvent</tt>s fired by the new instance
+ * @param synchronous <tt>true</tt> if the new instance is to deliver the
+ * <tt>VideoEvent</tt>s synchronously; otherwise, <tt>false</tt>
+ */
+ public VideoNotifierSupport(Object source, boolean synchronous)
+ {
this.source = source;
+ this.synchronous = synchronous;
+
+ events = this.synchronous ? null : new LinkedList<VideoEvent>();
}
/**
@@ -71,6 +110,32 @@ public class VideoNotifierSupport
}
}
+ protected void doFireVideoEvent(VideoEvent event)
+ {
+ VideoListener[] listeners;
+
+ synchronized (this.listeners)
+ {
+ listeners
+ = this.listeners.toArray(
+ new VideoListener[this.listeners.size()]);
+ }
+
+ for (VideoListener listener : listeners)
+ switch (event.getType())
+ {
+ case VideoEvent.VIDEO_ADDED:
+ listener.videoAdded(event);
+ break;
+ case VideoEvent.VIDEO_REMOVED:
+ listener.videoRemoved(event);
+ break;
+ default:
+ listener.videoUpdate(event);
+ break;
+ }
+ }
+
/**
* Notifies the <tt>VideoListener</tt>s registered with this
* <tt>VideoMediaStream</tt> about a specific type of change in the
@@ -83,6 +148,9 @@ public class VideoNotifierSupport
* @param origin {@link VideoEvent#LOCAL} if the origin of the video is
* local (e.g. it is being locally captured); {@link VideoEvent#REMOTE} if
* the origin of the video is remote (e.g. a remote peer is streaming it)
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
* @return <tt>true</tt> if this event and, more specifically, the visual
* <tt>Component</tt> it describes have been consumed and should be
* considered owned, referenced (which is important because
@@ -90,44 +158,14 @@ public class VideoNotifierSupport
* otherwise, <tt>false</tt>
*/
public boolean fireVideoEvent(
- int type,
- Component visualComponent,
- int origin)
+ int type, Component visualComponent, int origin,
+ boolean wait)
{
- VideoListener[] listeners;
-
- synchronized (this.listeners)
- {
- listeners
- = this.listeners
- .toArray(new VideoListener[this.listeners.size()]);
- }
-
- boolean consumed;
-
- if (listeners.length > 0)
- {
- VideoEvent event
- = new VideoEvent(source, type, visualComponent, origin);
-
- for (VideoListener listener : listeners)
- switch (type)
- {
- case VideoEvent.VIDEO_ADDED:
- listener.videoAdded(event);
- break;
- case VideoEvent.VIDEO_REMOVED:
- listener.videoRemoved(event);
- break;
- default:
- throw new IllegalArgumentException("type");
- }
+ VideoEvent event
+ = new VideoEvent(source, type, visualComponent, origin);
- consumed = event.isConsumed();
- }
- else
- consumed = false;
- return consumed;
+ fireVideoEvent(event, wait);
+ return event.isConsumed();
}
/**
@@ -136,31 +174,45 @@ public class VideoNotifierSupport
*
* @param event the <tt>VideoEvent</tt> to be fired to the
* <tt>VideoListener</tt>s registered with this instance
+ * @param wait <tt>true</tt> if the call is to wait till the specified
+ * <tt>VideoEvent</tt> has been delivered to the <tt>VideoListener</tt>s;
+ * otherwise, <tt>false</tt>
*/
- public void fireVideoEvent(VideoEvent event)
+ public void fireVideoEvent(VideoEvent event, boolean wait)
{
- VideoListener[] listeners;
-
- synchronized (this.listeners)
+ if (synchronous)
+ doFireVideoEvent(event);
+ else
{
- listeners
- = this.listeners
- .toArray(new VideoListener[this.listeners.size()]);
- }
-
- for (VideoListener listener : listeners)
- switch (event.getType())
+ synchronized (events)
{
- case VideoEvent.VIDEO_ADDED:
- listener.videoAdded(event);
- break;
- case VideoEvent.VIDEO_REMOVED:
- listener.videoRemoved(event);
- break;
- default:
- listener.videoUpdate(event);
- break;
+ events.add(event);
+
+ if (thread == null)
+ startThread();
+ else
+ events.notify();
+
+ if (wait)
+ {
+ boolean interrupted = false;
+
+ while (events.contains(event) && (thread != null))
+ {
+ try
+ {
+ events.wait();
+ }
+ catch (InterruptedException ie)
+ {
+ interrupted = true;
+ }
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
}
+ }
}
/**
@@ -179,4 +231,97 @@ public class VideoNotifierSupport
listeners.remove(listener);
}
}
+
+ private void runInThread()
+ {
+ while (true)
+ {
+ VideoEvent event = null;
+
+ synchronized (events)
+ {
+ long emptyTime = -1;
+ boolean interrupted = false;
+
+ while (events.isEmpty())
+ {
+ if (emptyTime == -1)
+ emptyTime = System.currentTimeMillis();
+ else
+ {
+ long newEmptyTime = System.currentTimeMillis();
+
+ if ((newEmptyTime - emptyTime) >= THREAD_TIMEOUT)
+ {
+ events.notify();
+ return;
+ }
+ }
+
+ try
+ {
+ events.wait(THREAD_TIMEOUT);
+ }
+ catch (InterruptedException ie)
+ {
+ interrupted = true;
+ }
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
+
+ event = events.remove(0);
+ }
+
+ if (event != null)
+ {
+ try
+ {
+ doFireVideoEvent(event);
+ }
+ catch (Throwable t)
+ {
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ }
+
+ synchronized (events)
+ {
+ events.notify();
+ }
+ }
+ }
+ }
+
+ private void startThread()
+ {
+ thread
+ = new Thread("VideoNotifierSupportThread")
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ runInThread();
+ }
+ finally
+ {
+ synchronized (events)
+ {
+ if (Thread.currentThread().equals(thread))
+ {
+ thread = null;
+ if (events.isEmpty())
+ events.notify();
+ else
+ startThread();
+ }
+ }
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java
index e71e0b6..efcf238 100644
--- a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java
+++ b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallPeer.java
@@ -375,12 +375,14 @@ public abstract class MediaAwareCallPeer
public void setLocalVideoAllowed(boolean allowed)
throws OperationFailedException
{
- if(getMediaHandler().isLocalVideoTransmissionEnabled() == allowed)
- return;
+ CallPeerMediaHandler<?> mediaHandler = getMediaHandler();
- // Modify the local media setup to reflect the requested setting for
- // the streaming of the local video.
- getMediaHandler().setLocalVideoTransmissionEnabled(allowed);
+ if(mediaHandler.isLocalVideoTransmissionEnabled() != allowed)
+ {
+ // Modify the local media setup to reflect the requested setting for
+ // the streaming of the local video.
+ mediaHandler.setLocalVideoTransmissionEnabled(allowed);
+ }
}
/**
@@ -509,14 +511,16 @@ public abstract class MediaAwareCallPeer
// of CallPeerMediaHandler) we won't set and fire the current state
// to Disconnected. Before closing the mediaHandler is setting the state
// in order to deliver states as quick as possible.
- synchronized(getMediaHandler())
+ CallPeerMediaHandler<?> mediaHandler = getMediaHandler();
+
+ synchronized(mediaHandler)
{
super.setState(newState, reason, reasonCode);
if (CallPeerState.DISCONNECTED.equals(newState)
|| CallPeerState.FAILED.equals(newState))
{
- getMediaHandler().close();
+ mediaHandler.close();
}
}
}
@@ -788,8 +792,10 @@ public abstract class MediaAwareCallPeer
// us audio for at least two separate participants. We therefore
// need to remove the stream level listeners and switch to CSRC
// level listening
- getMediaHandler().setStreamAudioLevelListener(null);
- getMediaHandler().setCsrcAudioLevelListener(this);
+ CallPeerMediaHandler<?> mediaHandler = getMediaHandler();
+
+ mediaHandler.setStreamAudioLevelListener(null);
+ mediaHandler.setCsrcAudioLevelListener(this);
}
}
@@ -811,8 +817,10 @@ public abstract class MediaAwareCallPeer
// since there's only us and her in the call. Lets stop being a CSRC
// listener and move back to listening the audio level of the
// stream itself.
- getMediaHandler().setStreamAudioLevelListener(this);
- getMediaHandler().setCsrcAudioLevelListener(null);
+ CallPeerMediaHandler<?> mediaHandler = getMediaHandler();
+
+ mediaHandler.setStreamAudioLevelListener(this);
+ mediaHandler.setCsrcAudioLevelListener(null);
}
}