diff options
Diffstat (limited to 'src/net/java')
35 files changed, 1411 insertions, 589 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java index c9d9244..9c90765 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java @@ -1222,6 +1222,116 @@ public class CallManager } /** + * Determines whether two specific addresses refer to one and the same + * peer/resource/contact. + * <p> + * <b>Warning</b>: Use the functionality sparingly because it assumes that + * an unspecified service is equal to any service. + * </p> + * + * @param a one of the addresses to be compared + * @param b the other address to be compared to <tt>a</tt> + * @return <tt>true</tt> if <tt>a</tt> and <tt>b</tt> name one and the same + * peer/resource/contact; <tt>false</tt>, otherwise + */ + public static boolean addressesAreEqual(String a, String b) + { + if (a.equals(b)) + return true; + + int aProtocolIndex = a.indexOf(':'); + if(aProtocolIndex > -1) + a = a.substring(aProtocolIndex + 1); + + int bProtocolIndex = b.indexOf(':'); + if(bProtocolIndex > -1) + b = b.substring(bProtocolIndex + 1); + + if (a.equals(b)) + return true; + + int aServiceBegin = a.indexOf('@'); + String aUserID; + String aService; + + if (aServiceBegin > -1) + { + aUserID = a.substring(0, aServiceBegin); + + int slashIndex = a.indexOf("/"); + if (slashIndex > 0) + aService = a.substring(aServiceBegin + 1, slashIndex); + else + aService = a.substring(aServiceBegin + 1); + } + else + { + aUserID = a; + aService = null; + } + + int bServiceBegin = b.indexOf('@'); + String bUserID; + String bService; + + if (bServiceBegin > -1) + { + bUserID = b.substring(0, bServiceBegin); + int slashIndex = b.indexOf("/"); + + if (slashIndex > 0) + bService = b.substring(bServiceBegin + 1, slashIndex); + else + bService = b.substring(bServiceBegin + 1); + } + else + { + bUserID = b; + bService = null; + } + + boolean userIDsAreEqual; + + if ((aUserID == null) || (aUserID.length() < 1)) + userIDsAreEqual = ((bUserID == null) || (bUserID.length() < 1)); + else + userIDsAreEqual = aUserID.equals(bUserID); + if (!userIDsAreEqual) + return false; + + boolean servicesAreEqual; + + /* + * It's probably a veeery long shot but it's assumed here that an + * unspecified service is equal to any service. Such a case is, for + * example, RegistrarLess SIP. + */ + if (((aService == null) || (aService.length() < 1)) + || ((bService == null) || (bService.length() < 1))) + servicesAreEqual = true; + else + servicesAreEqual = aService.equals(bService); + + return servicesAreEqual; + } + + /** + * Indicates if the given <tt>ConferenceMember</tt> corresponds to the local + * user. + * + * @param conferenceMember the conference member to check + */ + public static boolean isLocalUser(ConferenceMember conferenceMember) + { + String localUserAddress + = conferenceMember.getConferenceFocusCallPeer() + .getProtocolProvider().getAccountID().getAccountAddress(); + + return CallManager.addressesAreEqual( + conferenceMember.getAddress(), localUserAddress); + } + + /** * Adds a missed call notification. * * @param peerName the name of the peer diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java index ed0c8e4..84ed128 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java @@ -270,11 +270,6 @@ public class CallPanel = new Vector<CallTitleListener>(); /** - * Indicates if the video interface is enabled. - */ - private boolean isVideoInterfaceEnabled = false; - - /** * Creates an empty constructor allowing to extend this panel. */ public CallPanel() {} @@ -292,6 +287,24 @@ public class CallPanel this.call = call; this.callWindow = callWindow; + holdButton = new HoldButton(call); + recordButton = new RecordButton(call); + videoButton = new LocalVideoButton(call); + showHideVideoButton = new ShowHideVideoButton(call); + desktopSharingButton = new DesktopSharingButton(call); + transferCallButton = new TransferCallButton(call); + fullScreenButton = new FullScreenButton(this); + chatButton = new SIPCommButton( + ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), + ImageLoader.getImage(ImageLoader.CHAT_BUTTON_SMALL_WHITE)); + localLevel = new InputVolumeControlButton( + call, + ImageLoader.MICROPHONE, + ImageLoader.MUTE_BUTTON, + false, true, false); + remoteLevel = new OutputVolumeControlButton( + ImageLoader.VOLUME_CONTROL_BUTTON, false, true); + this.callDurationTimer = new Timer(1000, new CallTimerListener()); this.callDurationTimer.setRepeats(true); @@ -304,12 +317,7 @@ public class CallPanel if (isLastConference) { - if (CallManager.isVideoStreaming(call)) - callPanel = new VideoConferenceCallPanel( - CallPanel.this, call); - else - callPanel = new ConferenceCallPanel( - CallPanel.this, call); + enableConferenceInterface(CallManager.isVideoStreaming(call)); } else { @@ -347,10 +355,6 @@ public class CallPanel hangupButton = new SIPCommButton( ImageLoader.getImage(ImageLoader.HANGUP_BUTTON_BG)); - holdButton = new HoldButton(call); - recordButton = new RecordButton(call); - videoButton = new LocalVideoButton(call); - showHideVideoButton = new ShowHideVideoButton(call); holdButton.setIndex(2); recordButton.setIndex(3); videoButton.setIndex(11); @@ -381,29 +385,16 @@ public class CallPanel } }); - desktopSharingButton = new DesktopSharingButton(call); - transferCallButton = new TransferCallButton(call); - fullScreenButton = new FullScreenButton(this); desktopSharingButton.setIndex(8); transferCallButton.setIndex(5); fullScreenButton.setIndex(10); - chatButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.CHAT_BUTTON_SMALL_WHITE)); chatButton.setName(CHAT_BUTTON); chatButton.setToolTipText( GuiActivator.getResources().getI18NString("service.gui.CHAT")); chatButton.addActionListener(this); chatButton.setIndex(19); - localLevel = new InputVolumeControlButton( - call, - ImageLoader.MICROPHONE, - ImageLoader.MUTE_BUTTON, - false, true, false); - remoteLevel = new OutputVolumeControlButton( - ImageLoader.VOLUME_CONTROL_BUTTON, false, true); localLevel.setIndex(6); remoteLevel.setIndex(7); @@ -819,13 +810,15 @@ public class CallPanel = call.getProtocolProvider(); if (protocolProvider.getOperationSet( - OperationSetTelephonyConferencing.class) != null) + OperationSetTelephonyConferencing.class) != null + && conferenceButton != null) { conferenceButton.setEnabled(enable); } if (protocolProvider.getOperationSet(OperationSetVideoTelephony.class) - != null) + != null + && videoButton != null) { videoButton.setEnabled(enable); } @@ -843,13 +836,17 @@ public class CallPanel if (protocolProvider.getOperationSet( OperationSetAdvancedTelephony.class) - != null) + != null + && transferCallButton != null) { transferCallButton.setEnabled(enable); } if (protocolProvider.getOperationSet( - OperationSetVideoTelephony.class) != null) + OperationSetVideoTelephony.class) != null + && fullScreenButton != null + && videoButton != null + && desktopSharingButton != null) { fullScreenButton.setEnabled(enable); videoButton.setEnabled(enable); @@ -878,8 +875,26 @@ public class CallPanel { if (isLastConference) { - ((ConferenceCallPanel) callPanel) - .addCallPeerPanel(callPeer); + if (CallManager.isVideoStreaming(call)) + { + if (!(callPanel instanceof VideoConferenceCallPanel)) + { + enableConferenceInterface(true); + } + else + ((VideoConferenceCallPanel) callPanel) + .addCallPeerPanel(callPeer); + } + else + { + if(callPanel instanceof VideoConferenceCallPanel) + { + enableConferenceInterface(false); + } + else + ((ConferenceCallPanel) callPanel) + .addCallPeerPanel(callPeer); + } } else { @@ -889,18 +904,8 @@ public class CallPanel // conference. if (isLastConference) { - remove(callPanel); - - ConferenceCallPanel callPanel; - if (CallManager.isVideoStreaming(call)) - callPanel = new VideoConferenceCallPanel( - CallPanel.this, call); - else - callPanel = new ConferenceCallPanel( - CallPanel.this, call); - - updateCurrentCallPanel(callPanel); - add(callPanel, BorderLayout.CENTER); + enableConferenceInterface( + CallManager.isVideoStreaming(call)); } // We're still in one-to-one call and we receive the // remote peer. @@ -958,29 +963,19 @@ public class CallPanel { public void run() { - if (!isLastConference) - { - isLastConference = isConference(); - - // We've been in one-to-one call and we're now in a - // conference. - if (isLastConference) - { - removeOneToOneSpecificComponents(); - remove(callPanel); - - ConferenceCallPanel callPanel; - if (CallManager.isVideoStreaming(call)) - callPanel = new VideoConferenceCallPanel( - CallPanel.this, call); - else - callPanel = new ConferenceCallPanel( - CallPanel.this, call); - - updateCurrentCallPanel(callPanel); - add(callPanel, BorderLayout.CENTER); - } - } +// if (!isLastConference) +// { +// isLastConference = isConference(); +// +// // We've been in one-to-one call and we're now in a +// // conference. +// if (isLastConference) +// { +// removeOneToOneSpecificComponents(); +// enableConferenceInterface( +// CallManager.isVideoStreaming(call)); +// } +// } refreshContainer(); } @@ -1161,12 +1156,8 @@ public class CallPanel CallRenderer callRenderer = (CallRenderer) callPanel; - CallPeerRenderer currentPeerRenderer - = callRenderer - .getCallPeerRenderer(singlePeer); - UIVideoHandler videoHandler - = currentPeerRenderer.getVideoHandler(); + = callRenderer.getVideoHandler(); // If we have already a video handler, try to // initiate the new UI with the current video @@ -1326,10 +1317,6 @@ public class CallPanel if (callPanel instanceof OneToOneCallPanel) { - // If we have been in a video conference interface - if (isVideoInterfaceEnabled) - isVideoInterfaceEnabled = false; - removeConferenceSpecificComponents(); addOneToOneSpecificComponents(); } @@ -1343,48 +1330,46 @@ public class CallPanel /** * Enables or disables the video conference interface. * - * @param enable <tt>true</tt> to enable conference interface, + * @param isVideo <tt>true</tt> to enable conference interface, * <tt>false</tt> to disable it */ - public void enableVideoConferenceInterface(final boolean enable) + public void enableConferenceInterface(final boolean isVideo) { - isVideoInterfaceEnabled = enable; - - SwingUtilities.invokeLater(new Runnable() + if (!SwingUtilities.isEventDispatchThread()) { - public void run() + SwingUtilities.invokeLater(new Runnable() { - // We've been in one-to-one call and we're now in a - // conference. - if (enable) - { - remove(callPanel); - updateCurrentCallPanel(new VideoConferenceCallPanel( - CallPanel.this, call)); - add(callPanel, BorderLayout.CENTER); - } - else + public void run() { - remove(callPanel); - updateCurrentCallPanel(new ConferenceCallPanel( - CallPanel.this, call)); - add(callPanel, BorderLayout.CENTER); + enableConferenceInterface(isVideo); } + }); + return; + } - refreshContainer(); - } - }); - } + UIVideoHandler videoHandler = null; + if (callPanel != null) + videoHandler = ((CallRenderer) callPanel).getVideoHandler(); - /** - * Indicates if the conference interface is enabled. - * - * @return <tt>true</tt> if the conference interface is enabled, otherwise - * returns <tt>false</tt> - */ - public boolean isVideoConferenceInterfaceEnabled() - { - return isVideoInterfaceEnabled; + if (callPanel != null) + remove(callPanel); + + // We've been in one-to-one call and we're now in a + // conference. + if (isVideo) + { + updateCurrentCallPanel(new VideoConferenceCallPanel( + CallPanel.this, call, videoHandler)); + } + else + { + updateCurrentCallPanel(new ConferenceCallPanel( + CallPanel.this, call, videoHandler, false)); + } + + add(callPanel, BorderLayout.CENTER); + + refreshContainer(); } /** @@ -1393,22 +1378,28 @@ public class CallPanel private void removeOneToOneSpecificComponents() { // Disable desktop sharing. - if (desktopSharingButton.isSelected()) + if (desktopSharingButton != null && desktopSharingButton.isSelected()) desktopSharingButton.doClick(); // Disable full screen. - if (fullScreenButton.isSelected()) + if (fullScreenButton != null && fullScreenButton.isSelected()) fullScreenButton.doClick(); - settingsPanel.remove(videoButton); - settingsPanel.remove(showHideVideoButton); + if (videoButton != null) + settingsPanel.remove(videoButton); + + if (showHideVideoButton != null) + settingsPanel.remove(showHideVideoButton); if(resizeVideoButton != null) settingsPanel.remove(resizeVideoButton); - settingsPanel.remove(desktopSharingButton); - settingsPanel.remove(transferCallButton); - settingsPanel.remove(fullScreenButton); + if (desktopSharingButton != null) + { + settingsPanel.remove(desktopSharingButton); + settingsPanel.remove(transferCallButton); + settingsPanel.remove(fullScreenButton); + } } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java index 14188b3..044d49c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java @@ -163,13 +163,6 @@ public interface CallPeerRenderer public boolean isLocalVideoVisible(); /** - * Returns the video handler associated with this call peer renderer. - * - * @return the video handler associated with this call peer renderer - */ - public UIVideoHandler getVideoHandler(); - - /** * Shows/hides the security panel. * * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallRenderer.java b/src/net/java/sip/communicator/impl/gui/main/call/CallRenderer.java index 55dd0f5..133efe3 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallRenderer.java @@ -81,4 +81,11 @@ public interface CallRenderer */ public void conferenceMemberRemoved(CallPeer callPeer, ConferenceMember conferenceMember); + + /** + * Returns the video handler associated with this call peer renderer. + * + * @return the video handler associated with this call peer renderer + */ + public UIVideoHandler getVideoHandler(); } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java index 60d0bf5..8a4796b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java @@ -93,6 +93,8 @@ public class OneToOneCallPanel */ private JPanel southPanel; + private final UIVideoHandler videoHandler; + /** * Creates a call panel for the corresponding call, by specifying the * call type (incoming or outgoing) and the parent dialog. @@ -127,9 +129,18 @@ public class OneToOneCallPanel this.call = call; this.callPeer = callPeer; + if (videoHandler == null) + this.videoHandler = new UIVideoHandler(this, videoContainers); + else + { + this.videoHandler = videoHandler; + videoHandler.setVideoContainersList(videoContainers); + videoHandler.setCallRenderer(this); + } + this.setTransferHandler(new CallTransferHandler(call)); - this.addCallPeerPanel(callPeer, videoHandler); + this.addCallPeerPanel(callPeer); this.setPreferredSize(new Dimension(400, 400)); } @@ -139,15 +150,14 @@ public class OneToOneCallPanel * * @param peer the call peer */ - public void addCallPeerPanel(CallPeer peer, UIVideoHandler videoHandler) + public void addCallPeerPanel(CallPeer peer) { if (peerPanel == null) { - if (videoHandler != null) - peerPanel = new OneToOneCallPeerPanel( - this, peer, videoContainers, videoHandler); - else - peerPanel = new OneToOneCallPeerPanel( + videoHandler.addVideoListener(callPeer); + videoHandler.addRemoteControlListener(callPeer); + + peerPanel = new OneToOneCallPeerPanel( this, peer, videoContainers); /* Create the main Components of the UI. */ @@ -180,16 +190,6 @@ public class OneToOneCallPanel } /** - * Creates and adds a panel for a call peer. - * - * @param peer the call peer - */ - public void addCallPeerPanel(CallPeer peer) - { - addCallPeerPanel(peer, null); - } - - /** * Enters full screen mode. Initializes all components for the full screen * user interface. */ @@ -630,7 +630,21 @@ public class OneToOneCallPanel * @param conferenceMember the member that was added */ public void conferenceMemberAdded(CallPeer callPeer, - ConferenceMember conferenceMember) {} + ConferenceMember conferenceMember) + { + // We don't want to add the local member to the list of members. + if (CallManager.isLocalUser(conferenceMember)) + return; + + if (CallManager.addressesAreEqual( + conferenceMember.getAddress(), callPeer.getAddress())) + { + return; + } + + getCallContainer().enableConferenceInterface( + CallManager.isVideoStreaming(call)); + } /** * Indicates that the given conference member has been removed from the @@ -641,4 +655,14 @@ public class OneToOneCallPanel */ public void conferenceMemberRemoved(CallPeer callPeer, ConferenceMember conferenceMember) {} + + /** + * Returns the video handler associated with this call peer renderer. + * + * @return the video handler associated with this call peer renderer + */ + public UIVideoHandler getVideoHandler() + { + return videoHandler; + } } 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 2501f0d..a1bfc7c 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 @@ -163,20 +163,16 @@ public class OneToOneCallPeerPanel */ private final JLabel photoLabel; - private final UIVideoHandler videoHandler; - /** * Creates a <tt>CallPeerPanel</tt> for the given call peer. * * @param callRenderer the renderer of the call * @param callPeer the <tt>CallPeer</tt> represented in this panel * @param videoContainers the video <tt>Container</tt> list - * @param vHandler the <tt>UIVideoHandler</tt> */ public OneToOneCallPeerPanel( CallRenderer callRenderer, CallPeer callPeer, - List<Container> videoContainers, - UIVideoHandler vHandler) + List<Container> videoContainers) { this.callRenderer = callRenderer; this.callPeer = callPeer; @@ -184,18 +180,6 @@ public class OneToOneCallPeerPanel this.videoContainers = videoContainers; this.securityPanel = SecurityPanel.create(this, callPeer, null); - if (vHandler == null) - videoHandler - = new UIVideoHandler(callRenderer, videoContainers); - else - { - videoHandler = vHandler; - videoHandler.setVideoContainersList(videoContainers); - } - - videoHandler.addVideoListener(callPeer); - videoHandler.addRemoteControlListener(callPeer); - photoLabel = new JLabel(getPhotoLabelIcon()); center = createCenter(videoContainers); statusBar = createStatusBar(); @@ -242,20 +226,6 @@ public class OneToOneCallPeerPanel } /** - * Creates a <tt>CallPeerPanel</tt> for the given call peer. - * - * @param callRenderer the renderer of the call - * @param callPeer the <tt>CallPeer</tt> represented in this panel - * @param videoContainers the video <tt>Container</tt> list - */ - public OneToOneCallPeerPanel( CallRenderer callRenderer, - CallPeer callPeer, - List<Container> videoContainers) - { - this(callRenderer, callPeer, videoContainers, null); - } - - /** * Creates the <code>Component</code> hierarchy of the central area of this * <code>CallPeerPanel</code> which displays the photo of the * <code>CallPeer</code> or the video if any. @@ -295,7 +265,8 @@ public class OneToOneCallPeerPanel photoLabels.remove(photoLabel); } if (changed) - videoHandler.handleVideoEvent(callPeer, null); + callRenderer.getVideoHandler() + .handleVideoEvent(callPeer.getCall(), null); } } } @@ -327,7 +298,7 @@ public class OneToOneCallPeerPanel if (oldParent != null) oldParent.remove(noVideoComponent); - return new VideoContainer(noVideoComponent); + return new VideoContainer(noVideoComponent, false); } /** @@ -898,7 +869,7 @@ public class OneToOneCallPeerPanel */ public void setLocalVideoVisible(boolean isVisible) { - videoHandler.setLocalVideoVisible(isVisible); + callRenderer.getVideoHandler().setLocalVideoVisible(isVisible); } /** @@ -909,7 +880,7 @@ public class OneToOneCallPeerPanel */ public boolean isLocalVideoVisible() { - return videoHandler.isLocalVideoVisible(); + return callRenderer.getVideoHandler().isLocalVideoVisible(); } /** @@ -933,16 +904,6 @@ public class OneToOneCallPeerPanel } /** - * Returns the video handler associated with this call peer renderer. - * - * @return the video handler associated with this call peer renderer - */ - public UIVideoHandler getVideoHandler() - { - return videoHandler; - } - - /** * Initializes the security status label, shown in the call status bar. */ private void initSecurityStatusLabel() diff --git a/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java index ad657c2..961fdd3 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java @@ -278,7 +278,7 @@ public class SelectScreenDialog */ private static JComponent createVideoContainer(Component noVideoComponent) { - return new VideoContainer(noVideoComponent); + return new VideoContainer(noVideoComponent, false); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/call/UIVideoHandler.java b/src/net/java/sip/communicator/impl/gui/main/call/UIVideoHandler.java index 71c38b4..3bd9caa 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/UIVideoHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/UIVideoHandler.java @@ -14,6 +14,7 @@ import java.util.List; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.call.conference.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; @@ -58,6 +59,9 @@ public class UIVideoHandler private final LocalVideoMouseListener localVideoListener = new LocalVideoMouseListener(); + /** + * Indicates if the local video is visible. + */ private boolean localVideoVisible = true; /** @@ -69,7 +73,7 @@ public class UIVideoHandler /** * The renderer of the call. */ - private final CallRenderer callRenderer; + private CallRenderer callRenderer; /** * The close local video button. @@ -82,19 +86,24 @@ public class UIVideoHandler private List<Container> videoContainers; /** - * The video telephony listener. + * The operation set through which we do all video operations. */ - private VideoTelephonyListener videoTelephonyListener; + private OperationSetVideoTelephony videoTelephony; /** - * The operation set through which we do all video operations. + * A map of peer, video toolbar pair. */ - private OperationSetVideoTelephony videoTelephony; + private final Map<CallPeer, Component> peerToolbars; /** - * A list of peer, video tool bar pair. + * A map of conference member, video toolbar component. */ - private final Map<CallPeer, Component> videoToolbars; + private final Map<ConferenceMember, Component> memberToolbars; + + /** + * A map of conference member, visual component. + */ + private final Map<ConferenceMember, Component> memberVisualComponents; /** * The local video tool bar. @@ -117,7 +126,10 @@ public class UIVideoHandler { this.callRenderer = callRenderer; this.videoContainers = videoContainers; - this.videoToolbars = new Hashtable<CallPeer, Component>(); + this.peerToolbars = new Hashtable<CallPeer, Component>(); + this.memberToolbars = new Hashtable<ConferenceMember, Component>(); + this.memberVisualComponents + = new Hashtable<ConferenceMember, Component>(); } /** @@ -144,11 +156,46 @@ public class UIVideoHandler public void setVideoContainersList(List<Container> videoContainers) { this.videoContainers = videoContainers; + + localVideoToolbar = null; + peerToolbars.clear(); + memberToolbars.clear(); + } + + public void setCallRenderer(CallRenderer callRenderer) + { + this.callRenderer = callRenderer; } public void addVideoToolbar(CallPeer callPeer, Component videoToolbar) { - videoToolbars.put(callPeer, videoToolbar); + Component peerToolbar = peerToolbars.get(callPeer); + + if (peerToolbar == null) + { + peerToolbars.put(callPeer, videoToolbar); + } + } + + public void addVideoToolbar(ConferenceMember conferenceMember, + Component videoToolbar) + { + Component peerToolbar = memberToolbars.get(conferenceMember); + + if (peerToolbar == null) + { + memberToolbars.put(conferenceMember, videoToolbar); + } + } + + public void removeVideoToolbar(CallPeer callPeer) + { + peerToolbars.remove(callPeer); + } + + public void removeVideoToolbar(ConferenceMember conferenceMember) + { + memberToolbars.remove(conferenceMember); } public void setLocalVideoToolbar(Component videoToolbar) @@ -178,7 +225,8 @@ public class UIVideoHandler if (telephony == null) return null; - videoTelephonyListener = new VideoTelephonyListener(callPeer); + final VideoTelephonyListener videoTelephonyListener + = new VideoTelephonyListener(callPeer); /** * The video is only available while the #callPeer is in a Call @@ -192,6 +240,9 @@ public class UIVideoHandler telephony.addVideoListener( callPeer, videoTelephonyListener); + telephony.addVisualComponentResolveListener( + callPeer, videoTelephonyListener); + if (!isLocalVideoListenerAdded) { telephony.addPropertyChangeListener( @@ -204,7 +255,7 @@ public class UIVideoHandler { videoTelephony = telephony; - handleVideoEvent(callPeer, null); + handleVideoEvent(call, null); handleLocalVideoStreamingChange( callPeer, videoTelephonyListener); @@ -245,7 +296,8 @@ public class UIVideoHandler if (callPeer.equals(event.getSourceCallPeer())) { if (callPeer.getCall() != null) - removeVideoListener(event.getSourceCallPeer()); + removeVideoListener(event.getSourceCallPeer(), + videoTelephonyListener); } } @@ -269,7 +321,7 @@ public class UIVideoHandler if (CallState.CALL_ENDED.equals(newCallState)) { - removeVideoListener(callPeer); + removeVideoListener(callPeer, videoTelephonyListener); call.removeCallChangeListener(this); if(allowRemoteControl) @@ -294,7 +346,9 @@ public class UIVideoHandler /** * Removes the video listener */ - public void removeVideoListener(CallPeer callPeer) + public void removeVideoListener( + CallPeer callPeer, + VideoTelephonyListener videoTelephonyListener) { final Call call = callPeer.getCall(); if (call == null) @@ -312,6 +366,9 @@ public class UIVideoHandler telephony.removeVideoListener( callPeer, videoTelephonyListener); + telephony.removeVisualComponentResolveListener( + callPeer, videoTelephonyListener); + if (!CallManager.isVideoStreaming(call) && isLocalVideoListenerAdded) { telephony.removePropertyChangeListener( @@ -340,11 +397,19 @@ public class UIVideoHandler Container videoContainer = videoContainers.get(videoContainerCount - 1); - handleVideoEvent(callPeer, null, videoContainer); + handleVideoEvent(callPeer.getCall(), null, videoContainer); } } - videoToolbars.remove(callPeer); + peerToolbars.remove(callPeer); + + if (memberToolbars != null) + { + for (ConferenceMember member : callPeer.getConferenceMembers()) + { + memberToolbars.remove(member); + } + } callRenderer.exitFullScreen(); } @@ -356,7 +421,8 @@ public class UIVideoHandler */ private class VideoTelephonyListener implements PropertyChangeListener, - VideoListener + VideoListener, + VisualComponentResolveListener { private final CallPeer callPeer; @@ -440,12 +506,12 @@ public class UIVideoHandler CallPanel callContainer = callRenderer.getCallContainer(); if (callContainer.isConference() - && !callContainer.isVideoConferenceInterfaceEnabled()) + && !(callRenderer instanceof VideoConferenceCallPanel)) { - callContainer.enableVideoConferenceInterface(true); + callContainer.enableConferenceInterface(true); } - handleVideoEvent(callPeer, event); + handleVideoEvent(callPeer.getCall(), event); } /** @@ -457,12 +523,12 @@ public class UIVideoHandler if (callContainer.isConference() && callPeer.getCall() != null && !CallManager.isVideoStreaming(callPeer.getCall()) - && callContainer.isVideoConferenceInterfaceEnabled()) + && (callRenderer instanceof VideoConferenceCallPanel)) { - callContainer.enableVideoConferenceInterface(false); + callContainer.enableConferenceInterface(false); } - handleVideoEvent(callPeer, event); + handleVideoEvent(callPeer.getCall(), event); } /** @@ -470,7 +536,31 @@ public class UIVideoHandler */ public void videoUpdate(VideoEvent event) { - handleVideoEvent(callPeer, event); + handleVideoEvent(callPeer.getCall(), event); + } + + /** + * Notifies that a visual <tt>Component</tt> representing video has been + * resolved to be corresponding to a given <tt>ConferenceMember</tt>. + * + * @param event a <tt>VisualComponentResolveEvent</tt> describing the + * resolved component and the corresponding <tt>ConferenceMember</tt> + */ + public void visualComponentResolved(VisualComponentResolveEvent event) + { + ConferenceMember confMember = event.getConferenceMember(); + CallPeer focusCallPeer = confMember.getConferenceFocusCallPeer(); + + // If the member is already added in the call we refresh the + // the video container, otherwise it will be refreshed when added. + if ((CallManager.addressesAreEqual( confMember.getAddress(), + focusCallPeer.getAddress()) + && peerToolbars.containsKey(focusCallPeer)) + || memberToolbars.containsKey(event.getConferenceMember())) + { + handleVideoEvent( + confMember.getConferenceFocusCallPeer().getCall(), null); + } } } @@ -482,7 +572,7 @@ public class UIVideoHandler * <tt>Component</tt> representing video and the provider it was added into * or <tt>null</tt> if such information is not available */ - public void handleVideoEvent( final CallPeer callPeer, + public void handleVideoEvent( final Call call, final VideoEvent event) { if (event != null && logger.isTraceEnabled()) @@ -545,7 +635,7 @@ public class UIVideoHandler { public void run() { - handleVideoEvent(callPeer, event); + handleVideoEvent(call, event); } }); return; @@ -561,7 +651,7 @@ public class UIVideoHandler Container videoContainer = videoContainers.get(videoContainerCount - 1); - handleVideoEvent(callPeer, event, videoContainer); + handleVideoEvent(call, event, videoContainer); } } } @@ -571,6 +661,7 @@ public class UIVideoHandler * <tt>Component</tt> depicting video knowing that it is to be displayed or * is already displayed in a specific <tt>Container</tt>. * + * @param call the call, for which the video event is handled * @param videoEvent the <tt>VideoEvent</tt> describing the visual * <tt>Component</tt> which was added, removed or updated * @param videoContainer the <tt>Container</tt> which is to contain or @@ -578,9 +669,9 @@ public class UIVideoHandler * <tt>videoEvent</tt> */ private void handleVideoEvent( - CallPeer callPeer, - VideoEvent videoEvent, - Container videoContainer) + final Call call, + final VideoEvent videoEvent, + final Container videoContainer) { if (videoEvent != null) { @@ -638,6 +729,9 @@ public class UIVideoHandler videoContainer.removeAll(); + // Remove all previously added member visual components. + memberVisualComponents.clear(); + // REMOTE /* * UIVideoHandlers share a single VideoContainer in a Call i.e. there is @@ -645,7 +739,6 @@ public class UIVideoHandler * the videos of a single CallPeer, each UIVideoHandler adds all videos * of a Call. */ - Call call = callPeer.getCall(); Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); List<Component> remoteVideos = new LinkedList<Component>(); @@ -656,79 +749,135 @@ public class UIVideoHandler List<Component> visualComponents = videoTelephony.getVisualComponents(peer); - Component videoToolbar = videoToolbars.get(peer); - - if (videoToolbar != null) - { - Container toolbarParent = videoToolbar.getParent(); - - if (toolbarParent != null) - toolbarParent.remove(videoToolbar); - } - + boolean peerVisualComponentAdded = false; if (visualComponents != null && visualComponents.size() > 0) { + callRenderer.getCallContainer() + .addRemoteVideoSpecificComponents(peer); + for (int i = 0; i < visualComponents.size(); i++) { Component visualComponent = visualComponents.get(i); - - if (videoToolbar != null - && callRenderer.getCallContainer() - .isVideoConferenceInterfaceEnabled()) + + // Remove visual component parent if it exists. + Container remoteVideoParent + = visualComponent.getParent(); + + if (remoteVideoParent != null) + remoteVideoParent.remove(visualComponent); + + // Get conference member toolbar if the visual component + // does not correspond to the peer. + ConferenceMember conferenceMember = videoTelephony + .getConferenceMember(peer, visualComponent); + + Component peerToolbar = null; + + if (callRenderer instanceof VideoConferenceCallPanel) + { + if (call.isConferenceFocus() + || (conferenceMember == null + && peer.isConferenceFocus()) + || (conferenceMember != null + && CallManager.addressesAreEqual( + conferenceMember.getAddress(), + peer.getAddress()))) + { + peerToolbar = peerToolbars.get(peer); + peerVisualComponentAdded = true; + } + else if (conferenceMember != null) + { + peerToolbar = memberToolbars.get(conferenceMember); + memberVisualComponents.put( + conferenceMember, visualComponent); + } + else + { + peerToolbar = createDefaultVideoToolbar(peer); + } + } + + // Add the corresponding components to the remote videos. + if (peerToolbar != null) { - Container remoteVideoParent - = visualComponent.getParent(); + Container toolbarParent = peerToolbar.getParent(); - if (remoteVideoParent != null) - remoteVideoParent.remove(visualComponent); + if (toolbarParent != null) + toolbarParent.remove(peerToolbar); JPanel remoteVideoPanel = new TransparentPanel(new BorderLayout()); remoteVideoPanel.add(visualComponent); - remoteVideoPanel.add(videoToolbar, BorderLayout.SOUTH); + remoteVideoPanel + .add(peerToolbar, BorderLayout.SOUTH); remoteVideos.add(remoteVideoPanel); } else remoteVideos.add(visualComponent); } + + if (callRenderer instanceof VideoConferenceCallPanel) + { + if (!peerVisualComponentAdded) + { + remoteVideos.add(createDefaultPhotoPanel( + peer, + peerToolbars.get(peer))); + } + + for (ConferenceMember member : peer.getConferenceMembers()) + { + if (memberVisualComponents.get(member) == null) + { + Component defaultPhotoPanel = null; + if (!CallManager.isLocalUser(member) + && !CallManager.addressesAreEqual( + member.getAddress(), peer.getAddress()) + && memberToolbars.get(member) != null) + { + defaultPhotoPanel = createDefaultPhotoPanel( + member, + memberToolbars.get(member)); + } + + if (defaultPhotoPanel != null) + remoteVideos.add(defaultPhotoPanel); + } + } + } } - else if (videoToolbar != null && callRenderer.getCallContainer() - .isVideoConferenceInterfaceEnabled()) + else if (callRenderer instanceof VideoConferenceCallPanel) { - Component defaultPhotoPanel - = createDefaultPhotoPanel(callPeer, videoToolbar); + remoteVideos.add( + createDefaultPhotoPanel(peer, peerToolbars.get(peer))); - remoteVideos.add(defaultPhotoPanel); + for (ConferenceMember member : peer.getConferenceMembers()) + { + if (!CallManager.isLocalUser(member) + && !CallManager.addressesAreEqual( + member.getAddress(), peer.getAddress())) + { + remoteVideos.add(createDefaultPhotoPanel( + member, + memberToolbars.get(member))); + } + } } } if (remoteVideos.isEmpty()) { - callRenderer - .getCallContainer() - .removeRemoteVideoSpecificComponents(); + callRenderer.getCallContainer() + .removeRemoteVideoSpecificComponents(); } else { for (Component remoteVideo : remoteVideos) { - Container remoteVideoParent = remoteVideo.getParent(); - - if (remoteVideoParent != null) - { - remoteVideoParent.remove(remoteVideo); - Container parent = remoteVideoParent.getParent(); - - if (parent != null) - parent.remove(remoteVideoParent); - } - videoContainer.add( remoteVideo, VideoLayout.CENTER_REMOTE, 0); } - - callRenderer.getCallContainer().addRemoteVideoSpecificComponents( - callPeer); } // LOCAL @@ -753,13 +902,13 @@ public class UIVideoHandler if (localVideoVisible) { - if (localVideoToolbar != null && callRenderer.getCallContainer() - .isVideoConferenceInterfaceEnabled()) + if (localVideoToolbar != null + && (callRenderer instanceof VideoConferenceCallPanel)) { JPanel localVideoPanel = new TransparentPanel(new BorderLayout()); - localVideoPanel.add(localVideo); + localVideoPanel.add(localVideo, BorderLayout.CENTER); localVideoPanel.add(localVideoToolbar, BorderLayout.SOUTH); videoContainer.add(localVideoPanel, VideoLayout.LOCAL, 0); @@ -776,6 +925,13 @@ public class UIVideoHandler } } } + else if ((callRenderer instanceof VideoConferenceCallPanel) + && localVideoToolbar != null) + { + videoContainer.add(createDefaultPhotoPanel( + call.getProtocolProvider(), localVideoToolbar), + VideoLayout.LOCAL, 0); + } videoContainer.validate(); @@ -1486,4 +1642,142 @@ public class UIVideoHandler return defaultPanel; } + + /** + * Creates the default photo panel. + * + * @param callPeer the corresponding call peer + * @param videoToolbar the corresponding video tool bar + * @return + */ + private Component createDefaultPhotoPanel( + ConferenceMember conferenceMember, + Component videoToolbar) + { + JPanel defaultPanel = new TransparentPanel(new BorderLayout()); + + JPanel photoPanel = new TransparentPanel(new BorderLayout()) + { + /** + * @{inheritDoc} + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + g = g.create(); + + try + { + AntialiasingManager.activateAntialiasing(g); + + g.setColor(Color.GRAY); + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), 6, 6); + } + finally + { + g.dispose(); + } + } + }; + + JLabel photoLabel = new JLabel(new ImageIcon( + ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))); + photoPanel.add(photoLabel); + photoPanel.setPreferredSize(new Dimension(320, 240)); + + defaultPanel.add(photoPanel, BorderLayout.CENTER); + defaultPanel.add(videoToolbar, BorderLayout.SOUTH); + + return defaultPanel; + } + + /** + * Creates the default photo panel. + * + * @param callPeer the corresponding call peer + * @param videoToolbar the corresponding video tool bar + * @return + */ + private Component createDefaultPhotoPanel( ProtocolProviderService pps, + Component videoToolbar) + { + JPanel defaultPanel = new TransparentPanel(new BorderLayout()); + + JPanel photoPanel + = new TransparentPanel(new FlowLayout(FlowLayout.CENTER)) + { + /** + * @{inheritDoc} + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + g = g.create(); + + try + { + AntialiasingManager.activateAntialiasing(g); + + g.setColor(Color.GRAY); + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), 6, 6); + } + finally + { + g.dispose(); + } + } + }; + + JLabel photoLabel = new JLabel(); + + final OperationSetServerStoredAccountInfo accountInfoOpSet + = pps.getOperationSet( + OperationSetServerStoredAccountInfo.class); + + if (accountInfoOpSet != null) + { + byte[] accountImage + = AccountInfoUtils.getImage(accountInfoOpSet); + + // do not set empty images + if ((accountImage != null) + && (accountImage.length > 0)) + { + photoLabel.setIcon(new ImageIcon(accountImage)); + } + } + + if (photoLabel.getIcon() == null) + { + photoLabel.setIcon(new ImageIcon( + ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))); + } + + photoPanel.add(photoLabel); + photoLabel.setPreferredSize(new Dimension(320, 240)); + + defaultPanel.add(photoPanel, BorderLayout.CENTER); + defaultPanel.add(localVideoToolbar, BorderLayout.SOUTH); + + return defaultPanel; + } + + private Component createDefaultVideoToolbar(CallPeer callPeer) + { + ConferencePeerPanel peerPanel + = new ConferencePeerPanel( (ConferenceCallPanel)callRenderer, + callRenderer.getCallContainer(), + callPeer, + true); + + peerPanel.setPeerName(peerPanel.getParticipantName() + " unresolved"); + + return peerPanel; + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java index c4ce446..2f0f3d2 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java @@ -291,6 +291,15 @@ public abstract class BasicConferenceParticipantPanel } /** + * Sets the name of the participant. + * @param participantName the name of the participant + */ + public String getParticipantName() + { + return nameLabel.getText(); + } + + /** * Sets the state of the participant. * @param participantState the state of the participant */ diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceCallPanel.java index afa4123..9d6d042 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceCallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceCallPanel.java @@ -7,7 +7,6 @@ package net.java.sip.communicator.impl.gui.main.call.conference; import java.awt.*; -import java.awt.event.*; import java.util.*; import java.util.List; @@ -56,6 +55,11 @@ public class ConferenceCallPanel private JScrollPane scrollPane; /** + * Video handler for the conference call. + */ + private UIVideoHandler videoHandler; + + /** * The panel which contains ConferencePeerPanels. */ private final TransparentPanel mainPanel; @@ -119,7 +123,25 @@ public class ConferenceCallPanel * @param callPanel the call panel which contains this panel * @param c the conference call object */ - public ConferenceCallPanel(CallPanel callPanel, Call c, boolean isVideo) + public ConferenceCallPanel( CallPanel callPanel, + Call c, + boolean isVideo) + { + this(callPanel, c, null, isVideo); + } + + /** + * Creates an instance of <tt>ConferenceCallPanel</tt>. + * + * @param callPanel the call panel which contains this panel + * @param c the conference call object + * @param videoHandler the UI video handler + * @param isVideo indicates if this is used as a video conference renderer + */ + public ConferenceCallPanel( CallPanel callPanel, + Call c, + UIVideoHandler videoHandler, + boolean isVideo) { super(new GridBagLayout()); @@ -128,6 +150,15 @@ public class ConferenceCallPanel mainPanel = new TransparentPanel(); + if (videoHandler == null) + this.videoHandler = new UIVideoHandler(this, videoContainers); + else + { + this.videoHandler = videoHandler; + videoHandler.setVideoContainersList(videoContainers); + videoHandler.setCallRenderer(this); + } + // If we're in a video view we have nothing more to do here. if (isVideo) return; @@ -155,8 +186,6 @@ public class ConferenceCallPanel mainPanel.setTransferHandler(new CallTransferHandler(call)); - addVideoContainer(); - /* * XXX Call addCallPeerPanel(CallPeer) after calling addVideoContainer() * because the video may already be flowing between the CallPeers. @@ -185,113 +214,6 @@ public class ConferenceCallPanel } /** - * Initializes a new <tt>VideoContainer</tt> instance which is to contain - * the visual/video <tt>Component</tt>s of {@link #call}. - */ - protected void addVideoContainer() - { - final VideoContainer videoContainer = new VideoContainer(null); - - videoContainer.setPreferredSize(new Dimension(0, 0)); - - GridBagConstraints videoContainerGridBagConstraints - = new GridBagConstraints(); - - videoContainerGridBagConstraints.fill = GridBagConstraints.BOTH; - videoContainerGridBagConstraints.gridx = 0; - videoContainerGridBagConstraints.gridy = 0; - videoContainerGridBagConstraints.weightx = 0; - videoContainerGridBagConstraints.weighty = 1; - add(videoContainer, videoContainerGridBagConstraints); - /* - * When the videoContainer is empty i.e. it has nothing to show, don't - * show it. - */ - videoContainer.addContainerListener( - new ContainerListener() - { - public void componentAdded(ContainerEvent e) - { - GridBagLayout layout = (GridBagLayout) getLayout(); - boolean videoContainerIsVisible - = (videoContainer.getComponentCount() > 0); - - for (Component component : getComponents()) - { - GridBagConstraints constraints - = layout.getConstraints(component); - - if (videoContainerIsVisible) - { - constraints.weightx - = (component == videoContainer) ? 1 : 0; - scrollPane.setPreferredSize( - SCROLL_PANE_PREFERRED_SIZE_IF_VIDEO); - } - else - { - constraints.weightx - = (component == videoContainer) ? 0 : 1; - - if (SCROLL_PANE_PREFERRED_SIZE_IF_VIDEO.equals( - scrollPane.getPreferredSize())) - scrollPane.setPreferredSize(null); - } - layout.setConstraints(component, constraints); - } - - /* - * When the first visual/video Component gets added, this - * videoContainer is still not accommodated by the frame - * size because it has just become visible. So try to resize - * the frame to accommodate this videoContainer. - */ - if (e.getID() == ContainerEvent.COMPONENT_ADDED) - { - Component component = e.getComponent(); - Dimension preferredSize = component.getPreferredSize(); - - if ((preferredSize != null) - && (preferredSize.width > 0) - && (preferredSize.height > 0)) - { - ensureSize( - component, - preferredSize.width, preferredSize.height); - } - else - { - /* - * XXX The method ensureSize is supposed to know - * that it should not apply the specified size to - * the videoContainer. - */ - int s - = Math.max( - SCROLL_PANE_PREFERRED_SIZE_IF_VIDEO - .width, - SCROLL_PANE_PREFERRED_SIZE_IF_VIDEO - .height); - - ensureSize(videoContainer, s, s); - } - } - } - - public void componentRemoved(ContainerEvent e) - { - /* - * It's all the same with respect to the purpose of this - * ContainerListener. - */ - componentAdded(e); - } - }); - - videoContainers.add(videoContainer); - } - - /** * Returns the vertical <tt>JScrollBar</tt>. * * @return the vertical <tt>JScrollBar</tt> @@ -348,16 +270,13 @@ public class ConferenceCallPanel ConferenceCallPeerRenderer confPeerRenderer; - UIVideoHandler videoHandler - = new UIVideoHandler(this, videoContainers); - videoHandler.addVideoListener(peer); videoHandler.addRemoteControlListener(peer); if (peer.getConferenceMemberCount() > 0) { confPeerRenderer = new ConferenceFocusPanel( - this, callPanel, peer, videoHandler); + this, callPanel, peer); peer.addConferenceMembersSoundLevelListener(confPeerRenderer. getConferenceMembersSoundLevelListener()); peer.addStreamSoundLevelListener(confPeerRenderer. @@ -367,7 +286,7 @@ public class ConferenceCallPanel { confPeerRenderer = new ConferencePeerPanel( - this, callPanel, peer, videoHandler, false); + this, callPanel, peer, false); //peer.addConferenceMembersSoundLevelListener( // confPeerRenderer.getConferenceMembersSoundLevelListener()); @@ -414,7 +333,7 @@ public class ConferenceCallPanel if (confPeerRenderer == null) return; - confPeerRenderer.getVideoHandler().removeRemoteControlListener(peer); + getVideoHandler().removeRemoteControlListener(peer); // first remove the listeners as after removing the panel // we may still receive sound level indicators and there are @@ -837,4 +756,14 @@ public class ConferenceCallPanel addCallPeerPanel(callPeer); } } + + /** + * Returns the video handler associated with this call peer renderer. + * + * @return the video handler associated with this call peer renderer + */ + public UIVideoHandler getVideoHandler() + { + return videoHandler; + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java index 4d69092..c50b83c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java @@ -67,11 +67,6 @@ public class ConferenceFocusPanel private ConferencePeerPanel focusPeerPanel; /** - * The video handler for this peer. - */ - private UIVideoHandler videoHandler; - - /** * Creates an instance of <tt>ConferenceFocusPanel</tt> by specifying the * parent call renderer, the call panel and the peer represented by this * conference focus panel. @@ -83,13 +78,11 @@ public class ConferenceFocusPanel */ public ConferenceFocusPanel(ConferenceCallPanel callRenderer, CallPanel callPanel, - CallPeer callPeer, - UIVideoHandler videoHandler) + CallPeer callPeer) { this.focusPeer = callPeer; this.callRenderer = callRenderer; this.callPanel = callPanel; - this.videoHandler = videoHandler; this.setLayout(new GridBagLayout()); @@ -109,7 +102,7 @@ public class ConferenceFocusPanel { focusPeerPanel = new ConferencePeerPanel( - callRenderer, callPanel, focusPeer, videoHandler, false); + callRenderer, callPanel, focusPeer, false); GridBagConstraints constraints = new GridBagConstraints(); @@ -133,18 +126,12 @@ public class ConferenceFocusPanel */ public void addConferenceMemberPanel(ConferenceMember member) { - String localUserAddress - = focusPeer.getProtocolProvider().getAccountID(). - getAccountAddress(); - - boolean isLocalMember - = addressesAreEqual(member.getAddress(), localUserAddress); - // We don't want to add the local member to the list of members. - if (isLocalMember) + if (CallManager.isLocalUser(member)) return; - if (addressesAreEqual(member.getAddress(), focusPeer.getAddress())) + if (CallManager.addressesAreEqual( + member.getAddress(), focusPeer.getAddress())) return; // It's already there. @@ -152,7 +139,7 @@ public class ConferenceFocusPanel return; ConferenceMemberPanel memberPanel - = new ConferenceMemberPanel(callRenderer, member); + = new ConferenceMemberPanel(callRenderer, member, false); member.addPropertyChangeListener(memberPanel); @@ -190,7 +177,8 @@ public class ConferenceFocusPanel this.remove(memberPanel); conferenceMembersPanels.remove(member); - if (!addressesAreEqual(member.getAddress(), focusPeer.getAddress())) + if (!CallManager.addressesAreEqual( + member.getAddress(), focusPeer.getAddress())) member.removePropertyChangeListener( (ConferenceMemberPanel) memberPanel); @@ -488,100 +476,6 @@ public class ConferenceFocusPanel } /** - * Determines whether two specific addresses refer to one and the same - * peer/resource/contact. - * <p> - * <b>Warning</b>: Use the functionality sparingly because it assumes that - * an unspecified service is equal to any service. - * </p> - * - * @param a one of the addresses to be compared - * @param b the other address to be compared to <tt>a</tt> - * @return <tt>true</tt> if <tt>a</tt> and <tt>b</tt> name one and the same - * peer/resource/contact; <tt>false</tt>, otherwise - */ - private static boolean addressesAreEqual(String a, String b) - { - if (a.equals(b)) - return true; - - int aProtocolIndex = a.indexOf(':'); - if(aProtocolIndex > -1) - a = a.substring(aProtocolIndex + 1); - - int bProtocolIndex = b.indexOf(':'); - if(bProtocolIndex > -1) - b = b.substring(bProtocolIndex + 1); - - if (a.equals(b)) - return true; - - int aServiceBegin = a.indexOf('@'); - String aUserID; - String aService; - - if (aServiceBegin > -1) - { - aUserID = a.substring(0, aServiceBegin); - - int slashIndex = a.indexOf("/"); - if (slashIndex > 0) - aService = a.substring(aServiceBegin + 1, slashIndex); - else - aService = a.substring(aServiceBegin + 1); - } - else - { - aUserID = a; - aService = null; - } - - int bServiceBegin = b.indexOf('@'); - String bUserID; - String bService; - - if (bServiceBegin > -1) - { - bUserID = b.substring(0, bServiceBegin); - int slashIndex = b.indexOf("/"); - - if (slashIndex > 0) - bService = b.substring(bServiceBegin + 1, slashIndex); - else - bService = b.substring(bServiceBegin + 1); - } - else - { - bUserID = b; - bService = null; - } - - boolean userIDsAreEqual; - - if ((aUserID == null) || (aUserID.length() < 1)) - userIDsAreEqual = ((bUserID == null) || (bUserID.length() < 1)); - else - userIDsAreEqual = aUserID.equals(bUserID); - if (!userIDsAreEqual) - return false; - - boolean servicesAreEqual; - - /* - * It's probably a veeery long shot but it's assumed here that an - * unspecified service is equal to any service. Such a case is, for - * example, RegistrarLess SIP. - */ - if (((aService == null) || (aService.length() < 1)) - || ((bService == null) || (bService.length() < 1))) - servicesAreEqual = true; - else - servicesAreEqual = aService.equals(bService); - - return servicesAreEqual; - } - - /** * Returns the listener instance and created if needed. * @return the conferenceMembersSoundLevelListener */ @@ -619,16 +513,6 @@ public class ConferenceFocusPanel } /** - * Returns the video handler associated with this call peer renderer. - * - * @return the video handler associated with this call peer renderer - */ - public UIVideoHandler getVideoHandler() - { - return videoHandler; - } - - /** * Updates according sound level indicators to reflect the new member sound * level. */ diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceMemberPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceMemberPanel.java index 5eaa02b..3522bfa 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceMemberPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceMemberPanel.java @@ -41,11 +41,13 @@ public class ConferenceMemberPanel * * @param callRenderer the parent call renderer * @param member the <tt>ConferenceMember</tt> shown in this panel + * @param isVideo indicates if the video conference interface is enabled. */ public ConferenceMemberPanel( CallRenderer callRenderer, - ConferenceMember member) + ConferenceMember member, + boolean isVideo) { - super(callRenderer, false); + super(callRenderer, false, isVideo); this.member = member; diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java index 018571b..c091ac0 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java @@ -93,30 +93,25 @@ public class ConferencePeerPanel private StreamSoundLevelListener streamSoundLevelListener = null; /** - * The video handler associated with this peer. - */ - private UIVideoHandler videoHandler; - - /** * Creates a <tt>ConferencePeerPanel</tt> by specifying the parent * <tt>callDialog</tt>, containing it and the corresponding * <tt>protocolProvider</tt>. * * @param callRenderer the renderer of the corresponding call - * @param callPanel the call panel containing this peer panel + * @param callContainer the call panel containing this peer panel * @param protocolProvider the <tt>ProtocolProviderService</tt> for the * call * @param isVideo indicates if the video interface is enabled */ public ConferencePeerPanel( ConferenceCallPanel callRenderer, - CallPanel callPanel, + CallPanel callContainer, ProtocolProviderService protocolProvider, boolean isVideo) { super(callRenderer, true, isVideo); this.callRenderer = callRenderer; - this.callPanel = callPanel; + this.callPanel = callContainer; this.callPeer = null; // Try to set the same image as the one in the main window. This way @@ -153,7 +148,6 @@ public class ConferencePeerPanel public ConferencePeerPanel( ConferenceCallPanel callRenderer, CallPanel callContainer, CallPeer callPeer, - UIVideoHandler videoHandler, boolean isVideo) { super(callRenderer, false, isVideo); @@ -161,7 +155,6 @@ public class ConferencePeerPanel this.callRenderer = callRenderer; this.callPanel = callContainer; this.callPeer = callPeer; - this.videoHandler = videoHandler; this.securityPanel = SecurityPanel.create(this, callPeer, null); @@ -581,16 +574,6 @@ public class ConferencePeerPanel } /** - * Returns the video handler associated with this call peer renderer. - * - * @return the video handler associated with this call peer renderer - */ - public UIVideoHandler getVideoHandler() - { - return videoHandler; - } - - /** * Returns <tt>CallPeer</tt> contact address. * * @return <tt>CallPeer</tt> contact address diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java index 08b00db..f44bc8b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java @@ -22,11 +22,6 @@ public class VideoConferenceCallPanel extends ConferenceCallPanel { /** - * Handles video events and components. - */ - private final UIVideoHandler videoHandler; - - /** * The contained call. */ private final Call call; @@ -38,22 +33,35 @@ public class VideoConferenceCallPanel callPeerPanels = new Hashtable<CallPeer, ConferenceCallPeerRenderer>(); /** + * A mapping of a member and its renderer. + */ + private final Map<ConferenceMember, ConferenceMemberPanel> + conferenceMembersPanels + = new Hashtable<ConferenceMember, ConferenceMemberPanel>(); + + public VideoConferenceCallPanel(CallPanel callPanel, + Call call) + { + this(callPanel, call, null); + } + + /** * Creates an instance of <tt>VideoConferenceCallPanel</tt>. * * @param callPanel the call panel which contains this panel * @param call the conference call object */ - public VideoConferenceCallPanel(CallPanel callPanel, Call call) + public VideoConferenceCallPanel(CallPanel callPanel, + Call call, + UIVideoHandler videoHandler) { - super(callPanel, call, true); + super(callPanel, call, videoHandler, true); this.call = call; addVideoContainer(); - videoHandler = new UIVideoHandler(this, videoContainers); - - videoHandler.setLocalVideoToolbar(createLocalVideoToolBar()); + getVideoHandler().setLocalVideoToolbar(createLocalVideoToolBar()); Iterator<? extends CallPeer> iterator; @@ -64,7 +72,12 @@ public class VideoConferenceCallPanel ConferenceCallPeerRenderer peerRenderer = createVideoToolBar(peer); - videoHandler.addVideoToolbar(peer, peerRenderer.getComponent()); + getVideoHandler().addVideoToolbar(peer, peerRenderer.getComponent()); + + for (ConferenceMember member : peer.getConferenceMembers()) + { + conferenceMemberAdded(peer, member, true); + } // Map the call peer to its renderer. callPeerPanels.put(peer, peerRenderer); @@ -77,7 +90,12 @@ public class VideoConferenceCallPanel ConferenceCallPeerRenderer peerRenderer = createVideoToolBar(peer); - videoHandler.addVideoToolbar(peer, peerRenderer.getComponent()); + getVideoHandler().addVideoToolbar(peer, peerRenderer.getComponent()); + + for (ConferenceMember member : peer.getConferenceMembers()) + { + conferenceMemberAdded(peer, member, true); + } // Map the call peer to its renderer. callPeerPanels.put(peer, peerRenderer); @@ -118,17 +136,73 @@ public class VideoConferenceCallPanel return callPeerPanels.get(callPeer); } + public void conferenceMemberAdded( CallPeer callPeer, + ConferenceMember member) + { + // It's already there. + if (conferenceMembersPanels.containsKey(member)) + return; + + conferenceMemberAdded(callPeer, member, false); + + getVideoHandler().handleVideoEvent(call, null); + } + /** * */ - public void conferenceMemberAdded(CallPeer callPeer, - ConferenceMember conferenceMember) {} + public void conferenceMemberAdded( CallPeer callPeer, + ConferenceMember member, + boolean isInitialAdd) + { + // We don't want to add the local member to the list of members. + if (CallManager.isLocalUser(member)) + return; + + if (CallManager.addressesAreEqual( + member.getAddress(), callPeer.getAddress())) + { + return; + } + + // It's already there. + if (conferenceMembersPanels.containsKey(member)) + return; + + ConferenceMemberPanel memberVideoToolbar = createVideoToolBar(member); + + member.addPropertyChangeListener(memberVideoToolbar); + + getVideoHandler().addVideoToolbar(member, memberVideoToolbar); + conferenceMembersPanels.put(member, memberVideoToolbar); + } /** * */ public void conferenceMemberRemoved(CallPeer callPeer, - ConferenceMember conferenceMember) {} + ConferenceMember member) + { + // We don't want to add the local member to the list of members. + if (CallManager.isLocalUser(member)) + return; + + if (CallManager.addressesAreEqual( + member.getAddress(), callPeer.getAddress())) + { + return; + } + + getVideoHandler().removeVideoToolbar(member); + + ConferenceMemberPanel memberPanel = conferenceMembersPanels.get(member); + + if (memberPanel != null) + { + member.removePropertyChangeListener(memberPanel); + conferenceMembersPanels.remove(member); + } + } /** * Creates and adds a <tt>CallPeerRenderer</tt> for the given <tt>peer</tt>. @@ -139,12 +213,14 @@ public class VideoConferenceCallPanel { ConferenceCallPeerRenderer peerRenderer = createVideoToolBar(peer); - videoHandler.addVideoToolbar(peer, peerRenderer.getComponent()); + getVideoHandler().addVideoToolbar(peer, peerRenderer.getComponent()); // Map the call peer to its renderer. callPeerPanels.put(peer, peerRenderer); addCallPeerPanel(peer, peerRenderer); + + getVideoHandler().handleVideoEvent(call, null); } /** @@ -153,11 +229,11 @@ public class VideoConferenceCallPanel * @param peer the added peer * @param peer the peer for which to create a renderer */ - private void addCallPeerPanel( CallPeer peer, + private void addCallPeerPanel( CallPeer peer, ConferenceCallPeerRenderer peerRenderer) { - videoHandler.addVideoListener(peer); - videoHandler.addRemoteControlListener(peer); + getVideoHandler().addVideoListener(peer); + getVideoHandler().addRemoteControlListener(peer); if (peer.getConferenceMemberCount() > 0) { @@ -199,7 +275,13 @@ public class VideoConferenceCallPanel if (confPeerRenderer == null) return; - confPeerRenderer.getVideoHandler().removeRemoteControlListener(peer); + getVideoHandler().removeRemoteControlListener(peer); + getVideoHandler().removeVideoToolbar(peer); + + for (ConferenceMember member : peer.getConferenceMembers()) + { + getVideoHandler().removeVideoToolbar(member); + } // first remove the listeners as after removing the panel // we may still receive sound level indicators and there are @@ -247,7 +329,20 @@ public class VideoConferenceCallPanel private ConferenceCallPeerRenderer createVideoToolBar(CallPeer callPeer) { return new ConferencePeerPanel( - this, getCallContainer(), callPeer, videoHandler, true); + this, getCallContainer(), callPeer, true); + } + + /** + * Initializes the video tool bar. + * + * @param callPeer the <tt>CallPeer</tt> for which we create a video toolbar + * @return the created component + */ + private ConferenceMemberPanel createVideoToolBar( + ConferenceMember conferenceMember) + { + return new ConferenceMemberPanel( + this, conferenceMember, true); } /** @@ -268,7 +363,8 @@ public class VideoConferenceCallPanel return; } - final VideoContainer videoContainer = new VideoContainer(null); + final VideoContainer videoContainer + = new VideoContainer(new JLabel(), true); videoContainer.setPreferredSize(new Dimension(0, 0)); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index fe33ba7..d38df5e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -9,7 +9,6 @@ package net.java.sip.communicator.impl.gui.main.contactlist; import java.awt.*; import java.awt.event.*; -import java.awt.image.*; import java.util.*; import java.util.List; @@ -572,7 +571,7 @@ public class ContactListTreeCellRenderer if (contact instanceof ShowMoreContact) preferredSize.height = 18; else if (isSelected) - preferredSize.height = 55; + preferredSize.height = 70; else preferredSize.height = 30; } diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java b/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java index 23fb8ef..f8bae04 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java @@ -839,7 +839,7 @@ public class MediaConfiguration */
private static JComponent createVideoContainer(Component noVideoComponent)
{
- return new VideoContainer(noVideoComponent);
+ return new VideoContainer(noVideoComponent, false);
}
/**
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java index 655dea5..a701474 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java @@ -930,7 +930,7 @@ public class MediaServiceImpl noPreview.setHorizontalAlignment(SwingConstants.CENTER); noPreview.setVerticalAlignment(SwingConstants.CENTER); - final JComponent videoContainer = new VideoContainer(noPreview); + final JComponent videoContainer = new VideoContainer(noPreview, false); if ((preferredWidth > 0) && (preferredHeight > 0)) videoContainer.setPreferredSize( diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java index de3bbf5..e48941c 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaStreamImpl.java @@ -783,6 +783,7 @@ public class MediaStreamImpl } csrcArray[csrcArray.length - 1] = getLocalSourceID(); + this.localContributingSourceIDList = csrcArray; } @@ -1117,6 +1118,17 @@ public class MediaStreamImpl } /** + * Gets the synchronization source (SSRC) identifiers of the remote peers. + * + * @return the synchronization source (SSRC) identifiers of the remote peers + * @see MediaStream#getRemoteSourceIDs() + */ + public List<Long> getRemoteSourceIDs() + { + return Collections.unmodifiableList(remoteSourceIDs); + } + + /** * Gets the <tt>RTPConnector</tt> through which this instance sends and * receives RTP and RTCP traffic. * @@ -2097,7 +2109,7 @@ public class MediaStreamImpl + receiveStreamSSRC); } - setRemoteSourceID(receiveStreamSSRC); + addRemoteSourceID(receiveStreamSSRC); synchronized (receiveStreams) { @@ -2279,7 +2291,7 @@ public class MediaStreamImpl * @param remoteSourceID the SSRC identifier that this stream will be using * in outgoing RTP packets from now on. */ - protected void setRemoteSourceID(long remoteSourceID) + protected void addRemoteSourceID(long remoteSourceID) { Long oldValue = getRemoteSourceID(); diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java index 5c1077f..ad582fc 100644 --- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java @@ -640,6 +640,28 @@ public class VideoMediaStreamImpl } /** + * Gets the visual <tt>Component</tt>s rendering the <tt>ReceiveStream</tt> + * corresponding to the given ssrc. + * + * @param ssrc the src-id of the receive stream, which visual + * <tt>Component</tt> we're looking for + * @return the visual <tt>Component</tt> rendering the + * <tt>ReceiveStream</tt> corresponding to the given ssrc + */ + public Component getVisualComponent(long ssrc) + { + MediaDeviceSession deviceSession = getDeviceSession(); + + if (deviceSession instanceof VideoMediaDeviceSession) + { + return ((VideoMediaDeviceSession) deviceSession) + .getVisualComponent(ssrc); + } + + return null; + } + + /** * Removes a specific <tt>VideoListener</tt> from this * <tt>VideoMediaStream</tt> in order to have to no longer receive * notifications when visual/video <tt>Component</tt>s are being added and @@ -968,9 +990,9 @@ public class VideoMediaStreamImpl * @param ssrc remote SSRC */ @Override - protected void setRemoteSourceID(long ssrc) + protected void addRemoteSourceID(long ssrc) { - super.setRemoteSourceID(ssrc); + super.addRemoteSourceID(ssrc); ((VideoMediaDeviceSession) getDeviceSession()).setRemoteSSRC(ssrc); } 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 8922067..64841be 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java @@ -1013,6 +1013,26 @@ public class MediaDeviceSession } /** + * Gets the <tt>Player</tt>s rendering the <tt>ReceiveStream</tt> + * corresponding to the given ssrc. + * + * @param ssrc the src-id of the receive stream, which player we're + * looking for + * @return the <tt>Player</tt>s rendering the <tt>ReceiveStream</tt> + * corresponding to the given ssrc + */ + protected Player getPlayer(long ssrc) + { + synchronized (playbacks) + { + for (Playback playback : playbacks) + if (playback.receiveStream.getSSRC() == ssrc) + return playback.player; + } + return null; + } + + /** * Gets the JMF <tt>Processor</tt> which transcodes the <tt>MediaDevice</tt> * of this instance into the format of this instance. * 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 a8a9ae2..74368f2 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java @@ -856,6 +856,25 @@ public class VideoMediaDeviceSession } /** + * Gets the visual <tt>Component</tt>s rendering the <tt>ReceiveStream</tt> + * corresponding to the given ssrc. + * + * @param ssrc the src-id of the receive stream, which visual + * <tt>Component</tt> we're looking for + * @return the visual <tt>Component</tt> rendering the + * <tt>ReceiveStream</tt> corresponding to the given ssrc + */ + public Component getVisualComponent(long ssrc) + { + Player player = getPlayer(ssrc); + + if (player != null) + return player.getVisualComponent(); + + return null; + } + + /** * Gets the visual <tt>Component</tt> of a specific <tt>Player</tt> if it * has one and ignores the failure to access it if the specified * <tt>Player</tt> is unrealized. diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java index 2283345..6c12388 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java @@ -672,7 +672,8 @@ public class OperationSetTelephonyConferencingJabberImpl List<EndpointPacketExtension> endpoints = u.getChildExtensionsOfType(EndpointPacketExtension.class); String endpointStatus = null; - String ssrc = null; + String audioSsrc = null; + String videoSsrc = null; if(endpoints.size() > 0) { @@ -694,7 +695,13 @@ public class OperationSetTelephonyConferencingJabberImpl if(media.getType().equalsIgnoreCase( MediaType.AUDIO.toString())) { - ssrc = media.getSrcID(); + audioSsrc = media.getSrcID(); + } + + if(media.getType().equalsIgnoreCase( + MediaType.VIDEO.toString())) + { + videoSsrc = media.getSrcID(); } } } @@ -702,13 +709,22 @@ public class OperationSetTelephonyConferencingJabberImpl existingConferenceMember.setDisplayName(displayName); existingConferenceMember.setEndpointStatus(endpointStatus); - if (ssrc != null) + if (audioSsrc != null) + { + long newSsrc = Long.parseLong(audioSsrc); + if(existingConferenceMember.getAudioSsrc() != newSsrc) + changed = true; + + existingConferenceMember.setAudioSsrc(newSsrc); + } + + if (videoSsrc != null) { - long newSsrc = Long.parseLong(ssrc); - if(existingConferenceMember.getSSRC() != newSsrc) + long newSsrc = Long.parseLong(videoSsrc); + if(existingConferenceMember.getVideoSsrc() != newSsrc) changed = true; - existingConferenceMember.setSSRC(newSsrc); + existingConferenceMember.setVideoSsrc(newSsrc); } if (addConferenceMember) diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java index 41cedc1..7575135 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyConferencingSipImpl.java @@ -6,11 +6,14 @@ */ package net.java.sip.communicator.impl.protocol.sip; +import java.awt.*; import java.io.*; import java.text.*; import java.util.*; +import java.util.List; import javax.sip.*; +import javax.sip.Dialog; import javax.sip.address.*; import javax.sip.header.*; import javax.sip.message.*; @@ -1046,7 +1049,8 @@ public class OperationSetTelephonyConferencingSipImpl int userChildCount = userChildList.getLength(); String displayName = null; String endpointStatus = null; - String ssrc = null; + String audioSsrc = null; + String videoSsrc = null; for (int userChildIndex = 0; userChildIndex < userChildCount; @@ -1060,20 +1064,50 @@ public class OperationSetTelephonyConferencingSipImpl else if (ELEMENT_ENDPOINT.equals(userChildName)) { endpointStatus = getEndpointStatus(userChild); - ssrc = getEndpointMediaSrcId( - userChild, - MediaType.AUDIO); + audioSsrc = getEndpointMediaSrcId( + userChild, + MediaType.AUDIO); + videoSsrc = getEndpointMediaSrcId( + userChild, + MediaType.VIDEO); } } existingConferenceMember.setDisplayName(displayName); existingConferenceMember.setEndpointStatus(endpointStatus); - if (ssrc != null) + if (audioSsrc != null) { - long newSsrc = Long.parseLong(ssrc); - if(existingConferenceMember.getSSRC() != newSsrc) + long newSsrc = Long.parseLong(audioSsrc); + if(existingConferenceMember.getAudioSsrc() != newSsrc) changed = true; - existingConferenceMember.setSSRC(newSsrc); + existingConferenceMember.setAudioSsrc(newSsrc); + } + + if (videoSsrc != null) + { + long newSsrc = Long.parseLong(videoSsrc); + long currentSsrc + = existingConferenceMember.getVideoSsrc(); + + if (currentSsrc != -1 && currentSsrc == newSsrc) + continue; + + if(existingConferenceMember.getVideoSsrc() != newSsrc) + changed = true; + + existingConferenceMember.setVideoSsrc(newSsrc); + + VideoMediaStream peerVideoStream + = (VideoMediaStream) callPeer.getMediaHandler() + .getStream(MediaType.VIDEO); + + Component visualComponent + = peerVideoStream.getVisualComponent(newSsrc); + + if (visualComponent != null) + callPeer.getMediaHandler() + .fireVisualComponentResolveEvent( + visualComponent, existingConferenceMember); } if (addConferenceMember) diff --git a/src/net/java/sip/communicator/service/neomedia/MediaStream.java b/src/net/java/sip/communicator/service/neomedia/MediaStream.java index bd42432..00dcc76 100644 --- a/src/net/java/sip/communicator/service/neomedia/MediaStream.java +++ b/src/net/java/sip/communicator/service/neomedia/MediaStream.java @@ -116,6 +116,14 @@ public interface MediaStream public long getRemoteSourceID(); /** + * Gets the synchronization source (SSRC) identifiers of the remote peers. + * + * @return the synchronization source (SSRC) identifiers of the remote peers + * @see MediaStream#getRemoteSourceIDs() + */ + public List<Long> getRemoteSourceIDs(); + + /** * Returns the synchronization source (SSRC) identifier of the local * participant or <tt>-1</tt> if that identifier is not yet known at this * point. diff --git a/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java b/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java index 524da5b..851ac94 100644 --- a/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java +++ b/src/net/java/sip/communicator/service/neomedia/VideoMediaStream.java @@ -62,6 +62,17 @@ public interface VideoMediaStream public List<Component> getVisualComponents(); /** + * Gets the visual <tt>Component</tt>s rendering the <tt>ReceiveStream</tt> + * corresponding to the given ssrc. + * + * @param ssrc the src-id of the receive stream, which visual + * <tt>Component</tt> we're looking for + * @return the visual <tt>Component</tt> rendering the + * <tt>ReceiveStream</tt> corresponding to the given ssrc + */ + public Component getVisualComponent(long ssrc); + + /** * Adds a specific <tt>VideoListener</tt> to this <tt>VideoMediaStream</tt> * in order to receive notifications when visual/video <tt>Component</tt>s * are being added and removed. diff --git a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java index 745bb91..7eb43a8 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractCallPeer.java @@ -829,7 +829,7 @@ public abstract class AbstractCallPeer<T extends Call, { ConferenceMember mmbr = conferenceMembers.get(i); - if (mmbr.getSSRC() == ssrc) + if (mmbr.getAudioSsrc() == ssrc) return mmbr; } return null; diff --git a/src/net/java/sip/communicator/service/protocol/AbstractConferenceMember.java b/src/net/java/sip/communicator/service/protocol/AbstractConferenceMember.java index a3a2bc6..739a03a 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractConferenceMember.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractConferenceMember.java @@ -44,9 +44,14 @@ public class AbstractConferenceMember private ConferenceMemberState state = ConferenceMemberState.UNKNOWN; /** - * The SSRC value if transmitted by the focus of the conference. + * The audio SSRC value if transmitted by the focus of the conference. */ - private long ssrc = -1; + private long audioSsrc = -1; + + /** + * The video SSRC value if transmitted by the focus of the conference. + */ + private long videoSsrc = -1; /** * Creates an instance of <tt>AbstractConferenceMember</tt> by specifying @@ -157,20 +162,40 @@ public class AbstractConferenceMember /** * Returns the SSRC value associated with this participant; * - * @return the ssrc + * @return the audio ssrc id + */ + public long getAudioSsrc() + { + return audioSsrc; + } + + /** + * Sets the audio SSRC identifier of this member. + * + * @param ssrc the audio SSRC ID to set for this member. + */ + public void setAudioSsrc(long ssrc) + { + this.audioSsrc = ssrc; + } + + /** + * Returns the SSRC value associated with this participant; + * + * @return the video ssrc id */ - public long getSSRC() + public long getVideoSsrc() { - return ssrc; + return videoSsrc; } /** - * Sets the SSRC identifier of this member. + * Sets the video SSRC identifier of this member. * - * @param ssrc the SSRC ID to set for this member. + * @param ssrc the video SSRC ID to set for this member. */ - public void setSSRC(long ssrc) + public void setVideoSsrc(long ssrc) { - this.ssrc = ssrc; + this.videoSsrc = ssrc; } } diff --git a/src/net/java/sip/communicator/service/protocol/ConferenceMember.java b/src/net/java/sip/communicator/service/protocol/ConferenceMember.java index 1550df3..1afe8f2 100644 --- a/src/net/java/sip/communicator/service/protocol/ConferenceMember.java +++ b/src/net/java/sip/communicator/service/protocol/ConferenceMember.java @@ -108,5 +108,14 @@ public interface ConferenceMember * @return the ssrc associated with the RTP stream that this participant * is transmitting or <tt>null</tt> if this value is not currently known. */ - public long getSSRC(); + public long getAudioSsrc(); + + /** + * Returns the SSRC value associated with this participant or <tt>null</tt> + * if the value is not currently known.; + * + * @return the ssrc associated with the RTP stream that this participant + * is transmitting or <tt>null</tt> if this value is not currently known. + */ + public long getVideoSsrc(); } diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetVideoTelephony.java b/src/net/java/sip/communicator/service/protocol/OperationSetVideoTelephony.java index 6870764..a6119bd 100644 --- a/src/net/java/sip/communicator/service/protocol/OperationSetVideoTelephony.java +++ b/src/net/java/sip/communicator/service/protocol/OperationSetVideoTelephony.java @@ -12,6 +12,7 @@ import java.text.*; import java.util.List; import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.event.*; /** @@ -287,4 +288,48 @@ public interface OperationSetVideoTelephony * @return the implemented quality control. */ public QualityControl getQualityControl(CallPeer peer); + + /** + * Adds a specific <tt>VisualComponentResolveListener</tt> to this telephony + * in order to receive notifications when visual/video <tt>Component</tt>s + * are being resolved to correspond to a particular + * <tt>ConferenceMember</tt>. + * + * @param callPeer the <tt>CallPeer</tt>, which visual components we're + * listening to + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * notified when visual/video <tt>Component</tt>s are being resolved to + * correspond to a particular <tt>ConferenceMember</tt>. + */ + public void addVisualComponentResolveListener( + CallPeer callPeer, + VisualComponentResolveListener listener); + + /** + * Removes a <tt>VisualComponentResolveListener</tt> from this video + * telephony operation set, which was previously added in order to receive + * notifications when visual/video <tt>Component</tt>s are being resolved to + * be corresponding to a particular <tt>ConferenceMember</tt>. + * + * @param callPeer the <tt>CallPeer</tt>, which visual components we're + * listening to + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * removed + */ + public void removeVisualComponentResolveListener( + CallPeer callPeer, + VisualComponentResolveListener listener); + + /** + * Returns the <tt>ConferenceMember</tt> corresponding to the given + * <tt>visualComponent</tt>. + * + * @param peer the parent <tt>CallPeer</tt> + * @param visualComponent the visual <tt>Component</tt>, which corresponding + * <tt>ConferenceMember</tt> we're looking for + * @return the <tt>ConferenceMember</tt> corresponding to the given + * <tt>visualComponent</tt>. + */ + public ConferenceMember getConferenceMember(CallPeer peer, + Component visualComponent); } diff --git a/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveEvent.java b/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveEvent.java new file mode 100644 index 0000000..d9479fc --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveEvent.java @@ -0,0 +1,79 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol.event; + +import java.awt.*; +import java.util.*; + +import net.java.sip.communicator.service.protocol.*; + +/** + * In a conference call notifies that a visual <tt>Component</tt> representing + * video has been resolved to be corresponding to a given + * <tt>ConferenceMember</tt>. The event contains information about the concerned + * visual component and it's corresponding member. + * + * @author Yana Stamcheva + */ +public class VisualComponentResolveEvent + extends EventObject +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The visual component that has been resolved. + */ + private final ConferenceMember conferenceMember; + + /** + * The visual <tt>Component</tt> depicting video which had its availability + * changed and which this <tt>VideoEvent</tt> notifies about. + */ + private final Component visualComponent; + + /** + * + * @param source the source of the new <tt>VideoEvent</tt> and the provider + * of the visual <tt>Component</tt> depicting video + */ + public VisualComponentResolveEvent( Object source, + Component visualComponent, + ConferenceMember resolvedMember) + { + super(source); + + this.visualComponent = visualComponent; + this.conferenceMember = resolvedMember; + } + + /** + * Gets the visual <tt>Component</tt> depicting video which had its + * availability changed and which this <tt>VideoEvent</tt> notifies about. + * + * @return the visual <tt>Component</tt> depicting video which had its + * availability changed and which this <tt>VideoEvent</tt> notifies about + */ + public Component getVisualComponent() + { + return visualComponent; + } + + /** + * Gets the <tt>ConferenceMember</tt> that was resolved to be corresponding + * to the source visual component. + * + * @return the <tt>ConferenceMember</tt> that was resolved to be + * corresponding to the source visual component + */ + public ConferenceMember getConferenceMember() + { + return conferenceMember; + } +} diff --git a/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveListener.java b/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveListener.java new file mode 100644 index 0000000..c475b07 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/VisualComponentResolveListener.java @@ -0,0 +1,29 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol.event; + +import java.util.*; + +/** + * In a conference call notifies that a visual <tt>Component</tt> representing + * video has been resolved to be corresponding to a given + * <tt>ConferenceMember</tt>. + * + * @author Yana Stamcheva + */ +public interface VisualComponentResolveListener + extends EventListener +{ + /** + * Notifies that a visual <tt>Component</tt> representing video has been + * resolved to be corresponding to a given <tt>ConferenceMember</tt>. + * + * @param event a <tt>VisualComponentResolveEvent</tt> describing the + * resolved component and the corresponding <tt>ConferenceMember</tt> + */ + public void visualComponentResolved(VisualComponentResolveEvent event); +} diff --git a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetVideoTelephony.java b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetVideoTelephony.java index 43da709..9e9074e 100644 --- a/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetVideoTelephony.java +++ b/src/net/java/sip/communicator/service/protocol/media/AbstractOperationSetVideoTelephony.java @@ -13,6 +13,7 @@ import java.util.List; import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.event.*; /** @@ -155,6 +156,41 @@ public abstract class AbstractOperationSetVideoTelephony< } /** + * Returns the <tt>ConferenceMember</tt> corresponding to the given + * <tt>visualComponent</tt>. + * + * @param peer the parent <tt>CallPeer</tt> + * @param visualComponent the visual <tt>Component</tt>, which corresponding + * <tt>ConferenceMember</tt> we're looking for + * @return the <tt>ConferenceMember</tt> corresponding to the given + * <tt>visualComponent</tt>. + */ + @SuppressWarnings("unchecked") // work with MediaAware* in media package + public ConferenceMember getConferenceMember(CallPeer peer, + Component visualComponent) + { + VideoMediaStream peerVideoStream + = (VideoMediaStream) ((W)peer).getMediaHandler() + .getStream(MediaType.VIDEO); + + if (peerVideoStream == null) + return null; + + for (ConferenceMember member : peer.getConferenceMembers()) + { + Component memberComponent = peerVideoStream + .getVisualComponent(member.getVideoSsrc()); + + if (memberComponent != null + && memberComponent.equals(visualComponent)) + { + return member; + } + } + return null; + } + + /** * Delegates to the <tt>CallPeerMediaHandler</tt> of the specified * <tt>CallPeer</tt> because the video is provided by it. * @@ -503,4 +539,48 @@ public abstract class AbstractOperationSetVideoTelephony< delegate.videoUpdate(event); } } + + /** + * Adds a specific <tt>VisualComponentResolveListener</tt> to this telephony + * in order to receive notifications when visual/video <tt>Component</tt>s + * are being resolved to correspond to a particular + * <tt>ConferenceMember</tt>. + * + * @param callPeer the <tt>CallPeer</tt>, which visual components we're + * listening to + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * notified when visual/video <tt>Component</tt>s are being resolved to + * correspond to a particular <tt>ConferenceMember</tt>. + */ + @SuppressWarnings("unchecked") // work with MediaAware* in media package + public void addVisualComponentResolveListener( + CallPeer callPeer, + VisualComponentResolveListener listener) + { + if (listener == null) + throw new NullPointerException("listener"); + + ((W)callPeer).getMediaHandler().addVisualComponentResolveListener( + listener); + } + + /** + * Removes a <tt>VisualComponentResolveListener</tt> from this video + * telephony operation set, which was previously added in order to receive + * notifications when visual/video <tt>Component</tt>s are being resolved to + * be corresponding to a particular <tt>ConferenceMember</tt>. + * + * @param callPeer the <tt>CallPeer</tt>, which visual components we're + * listening to + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * removed + */ + @SuppressWarnings("unchecked") // work with MediaAware* in media package + public void removeVisualComponentResolveListener( + CallPeer callPeer, + VisualComponentResolveListener listener) + { + ((W)callPeer).getMediaHandler().removeVisualComponentResolveListener( + listener); + } } diff --git a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java index a38b332..3affd16 100644 --- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java +++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java @@ -17,6 +17,7 @@ import net.java.sip.communicator.service.neomedia.device.*; import net.java.sip.communicator.service.neomedia.event.*; import net.java.sip.communicator.service.neomedia.format.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.event.*; /** @@ -184,6 +185,18 @@ public abstract class CallPeerMediaHandler }; /** + * The <tt>Object</tt> to synchronize the access to + * {@link #localUserAudioLevelListeners}. + */ + private final Object visualComponentResolveSyncRoot = new Object(); + + /** + * The list of <tt>VisualComponentResolveListener</tt>s interested in + * visual component resolve events. + */ + private List<VisualComponentResolveListener> visualComponentResolveListeners; + + /** * The state of this instance which may be shared with multiple other * <tt>CallPeerMediaHandler</tt>s. */ @@ -1474,4 +1487,100 @@ public abstract class CallPeerMediaHandler } } } + + /** + * Adds a specific <tt>VisualComponentResolveListener</tt> to this telephony + * in order to receive notifications when visual/video <tt>Component</tt>s + * are being resolved to correspond to a particular + * <tt>ConferenceMember</tt>. + * + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * notified when visual/video <tt>Component</tt>s are being resolved to + * correspond to a particular <tt>ConferenceMember</tt>. + */ + public void addVisualComponentResolveListener( + VisualComponentResolveListener listener) + { + if (listener == null) + throw new NullPointerException("listener"); + + synchronized (visualComponentResolveSyncRoot) + { + if ((visualComponentResolveListeners == null) + || visualComponentResolveListeners.isEmpty()) + { + visualComponentResolveListeners + = new ArrayList<VisualComponentResolveListener>(); + } + + visualComponentResolveListeners.add(listener); + } + } + + /** + * Removes a <tt>VisualComponentResolveListener</tt> from this video + * telephony operation set, which was previously added in order to receive + * notifications when visual/video <tt>Component</tt>s are being resolved to + * be corresponding to a particular <tt>ConferenceMember</tt>. + * + * @param listener the <tt>VisualComponentResolveListener</tt> to be + * removed + */ + public void removeVisualComponentResolveListener( + VisualComponentResolveListener listener) + { + synchronized (visualComponentResolveSyncRoot) + { + if ((visualComponentResolveListeners != null) + && !visualComponentResolveListeners.isEmpty()) + { + visualComponentResolveListeners.remove(listener); + } + } + } + + /** + * Notifies all registered <tt>VisualComponentResolveListener</tt> that a + * visual <tt>Component</tt> has been resolved. + * + * @param visualComponent the visual <tt>Component</tt> that has been + * resolved + * @param conferenceMember the resolved <tt>ConferenceMember</tt> + */ + public void fireVisualComponentResolveEvent( + Component visualComponent, + ConferenceMember conferenceMember) + { + List<VisualComponentResolveListener> visualComponentResolveListeners; + + synchronized (visualComponentResolveSyncRoot) + { + /* + * Since the localUserAudioLevelListeners field of this + * MediaAwareCall is implemented as a copy-on-write storage, just + * get a reference to it and it should be safe to iterate over it + * without ConcurrentModificationExceptions. + */ + visualComponentResolveListeners + = this.visualComponentResolveListeners; + } + + if (visualComponentResolveListeners != null) + { + /* + * Iterate over localUserAudioLevelListeners using an index rather + * than an Iterator in order to try to reduce the number of + * allocations (as the number of audio level changes is expected to + * be very large). + */ + int visualComponentResolveListenerCount + = visualComponentResolveListeners.size(); + + for(int i = 0; i < visualComponentResolveListenerCount; i++) + visualComponentResolveListeners.get(i).visualComponentResolved( + new VisualComponentResolveEvent(this, + visualComponent, + conferenceMember)); + } + } } diff --git a/src/net/java/sip/communicator/util/swing/VideoContainer.java b/src/net/java/sip/communicator/util/swing/VideoContainer.java index 164cc3d..aed90a1 100644 --- a/src/net/java/sip/communicator/util/swing/VideoContainer.java +++ b/src/net/java/sip/communicator/util/swing/VideoContainer.java @@ -72,10 +72,12 @@ public class VideoContainer *
* @param noVideoComponent the component to be displayed when no remote
* video is available
+ * @param isConference indicates if this <tt>VideoLayout</tt> is dedicated
+ * to a conference interface.
*/
- public VideoContainer(Component noVideoComponent)
+ public VideoContainer(Component noVideoComponent, boolean isConference)
{
- setLayout(new VideoLayout());
+ setLayout(new VideoLayout(isConference));
this.noVideoComponent = noVideoComponent;
@@ -162,7 +164,9 @@ public class VideoContainer {
if (VideoLayout.CENTER_REMOTE.equals(constraints)
&& (noVideoComponent != null)
- && !noVideoComponent.equals(comp))
+ && !noVideoComponent.equals(comp)
+ || (comp.equals(noVideoComponent)
+ && noVideoComponent.getParent() != null))
{
remove(noVideoComponent);
validate();
diff --git a/src/net/java/sip/communicator/util/swing/VideoLayout.java b/src/net/java/sip/communicator/util/swing/VideoLayout.java index 714d0f9..fb7ba7c 100644 --- a/src/net/java/sip/communicator/util/swing/VideoLayout.java +++ b/src/net/java/sip/communicator/util/swing/VideoLayout.java @@ -83,6 +83,26 @@ public class VideoLayout extends FitLayout private float remoteAlignmentX = Component.CENTER_ALIGNMENT;
/**
+ * Indicates if this <tt>VideoLayout</tt> is dedicated to a conference
+ * interface.
+ */
+ private final boolean isConference;
+
+ /**
+ * Creates an instance of <tt>VideoLayout</tt> by also indicating if this
+ * video layout is dedicated to a conference interface.
+ *
+ * @param isConference indicates if this <tt>VideoLayout</tt> is dedicated
+ * to a conference interface.
+ */
+ public VideoLayout(boolean isConference)
+ {
+ super();
+
+ this.isConference = isConference;
+ }
+
+ /**
* Adds the given component in this layout on the specified by name
* position.
*
@@ -216,7 +236,7 @@ public class VideoLayout extends FitLayout Dimension parentSize = parent.getSize();
parentSize.width -= remoteCount*10;
- if (remoteCount == 1)
+ if (remoteCount == 1 && !isConference)
{
super.layoutContainer(parent,
(local == null)
@@ -266,7 +286,7 @@ public class VideoLayout extends FitLayout * If the local visual/video Component is not displayed as if it is
* a remote one, it will be placed on top of a remote one.
*/
- if (!remotes.contains(local))
+ if (!remotes.contains(local) && !isConference)
{
Component remote0 = remotes.isEmpty() ? null : remotes.get(0);
int localX;
@@ -421,8 +441,6 @@ public class VideoLayout extends FitLayout int columns = calculateColumnCount(remotes);
int rows = (remoteCount + columns - 1) / columns;
-System.out.println("EHIIIIII WIDTH=========" + maxWidth * columns
- + "EHIIIIIIIII HEIGHT========" + maxHeight * rows);
return new Dimension(maxWidth * columns, maxHeight * rows);
}
}
|