diff options
author | Yana Stamcheva <yana@jitsi.org> | 2012-06-25 12:54:06 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2012-06-25 12:54:06 +0000 |
commit | 51d7bf04f69968bafb4e29d376875e8d300427b4 (patch) | |
tree | 11b795b8c5b21f1eeaa073395bde1254e2bc08d2 /src/net/java/sip/communicator/service | |
parent | d1835c8e95e65b48d0f61b97690b4a2a3cc48344 (diff) | |
download | jitsi-51d7bf04f69968bafb4e29d376875e8d300427b4.zip jitsi-51d7bf04f69968bafb4e29d376875e8d300427b4.tar.gz jitsi-51d7bf04f69968bafb4e29d376875e8d300427b4.tar.bz2 |
Adds video conference interface enhancements.
Diffstat (limited to 'src/net/java/sip/communicator/service')
10 files changed, 406 insertions, 11 deletions
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)); + } + } } |