From 8fee2866a69e969403c19b1f51083d1828ee81af Mon Sep 17 00:00:00 2001 From: Damian Minkov Date: Fri, 20 Nov 2009 10:27:34 +0000 Subject: [PATCH] Implements soundlevel indicator listeners, still to handle setting ssrc coming from focus and triggering sound level events from media for remote parties. --- .../impl/protocol/sip/CallPeerSipImpl.java | 218 ++++++++++++++++++ .../protocol/sip/ConferenceMemberSipImpl.java | 23 ++ 2 files changed, 241 insertions(+) diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java index 95d35c448..a2ef25d97 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java @@ -16,6 +16,9 @@ import javax.sip.message.*; import net.java.sip.communicator.impl.protocol.sip.sdp.*; +import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.neomedia.MediaType; +import net.java.sip.communicator.service.neomedia.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -117,6 +120,30 @@ public class CallPeerSipImpl private final List videoPropertyChangeListeners = new LinkedList(); + /** + * Holds the wrapped ConferenceMembersSoundLevelListeners + * and their wrappers. + */ + private Hashtable< + ConferenceMembersSoundLevelListener, + SoundLevelListenerWrapperForConferences> + confmembersSoundLevelListeners = + new Hashtable< + ConferenceMembersSoundLevelListener, + SoundLevelListenerWrapperForConferences>(); + + /** + * Holds the wrapped StreamSoundLevelListener + * and their wrappers. + */ + private Hashtable< + StreamSoundLevelListener, + SoundLevelListenerWrapperForStream> + streamSoundLevelListeners = + new Hashtable< + StreamSoundLevelListener, + SoundLevelListenerWrapperForStream>(); + /** * Creates a new call peer with address peerAddress. * @@ -1665,4 +1692,195 @@ public void setState(CallPeerState newState, String reason) || CallPeerState.FAILED.equals(newState)) getMediaHandler().close(); } + + /** + * Adds a specific ConferenceMembersSoundLevelListener to the list + * of listeners interested in and notified about changes in conference + * members sound level. + * + * @param listener the ConferenceMembersSoundLevelListener to add + */ + public void addConferenceMembersSoundLevelListener( + ConferenceMembersSoundLevelListener listener) + { + AudioMediaStream audioStream = + (AudioMediaStream)mediaHandler.getStream(MediaType.AUDIO); + + if(audioStream != null) + { + SoundLevelListenerWrapperForConferences sli = + new SoundLevelListenerWrapperForConferences(listener); + audioStream.addConferenceMemberSoundLevelListener(sli); + + confmembersSoundLevelListeners.put(listener, sli); + super.addConferenceMembersSoundLevelListener(listener); + } + } + + /** + * Removes a specific ConferenceMembersSoundLevelListener of the + * list of listeners interested in and notified about changes in conference + * members sound level. + * + * @param listener the ConferenceMembersSoundLevelListener to + * remove + */ + public void removeConferenceMembersSoundLevelListener( + ConferenceMembersSoundLevelListener listener) + { + super.removeConferenceMembersSoundLevelListener(listener); + + AudioMediaStream audioStream = + (AudioMediaStream)mediaHandler.getStream(MediaType.AUDIO); + + if(audioStream != null) + { + SoundLevelListenerWrapperForConferences sli = + confmembersSoundLevelListeners.get(listener); + if(sli != null) + audioStream.removeConferenceMemberSoundLevelListener(sli); + } + confmembersSoundLevelListeners.remove(listener); + } + + /** + * Adds a specific StreamSoundLevelListener to the list of + * listeners interested in and notified about changes in stream sound level + * related information. + * + * @param listener the StreamSoundLevelListener to add + */ + public void addStreamSoundLevelListener(StreamSoundLevelListener listener) + { + AudioMediaStream audioStream = + (AudioMediaStream)mediaHandler.getStream(MediaType.AUDIO); + + if(audioStream != null) + { + SoundLevelListenerWrapperForStream sli = + new SoundLevelListenerWrapperForStream(listener); + audioStream.addSoundLevelListener(sli); + + streamSoundLevelListeners.put(listener, sli); + super.addStreamSoundLevelListener(listener); + } + } + + /** + * Removes a specific StreamSoundLevelListener of the list of + * listeners interested in and notified about changes in stream sound level + * related information. + * + * @param listener the StreamSoundLevelListener to remove + */ + public void removeStreamSoundLevelListener( + StreamSoundLevelListener listener) + { + super.removeStreamSoundLevelListener(listener); + + AudioMediaStream audioStream = + (AudioMediaStream)mediaHandler.getStream(MediaType.AUDIO); + + if(audioStream != null) + { + SoundLevelListenerWrapperForStream sli = + streamSoundLevelListeners.get(listener); + if(sli != null) + audioStream.removeSoundLevelListener(sli); + } + streamSoundLevelListeners.remove(listener); + } + + /** + * Wraps SoundLevelListener and convert its event to + * ConferenceMembersSoundLevelEvent events to be delivered to + * ConferenceMembersSoundLevelListener. + */ + private class SoundLevelListenerWrapperForConferences + implements SoundLevelListener + { + private ConferenceMembersSoundLevelListener listener; + + public SoundLevelListenerWrapperForConferences( + ConferenceMembersSoundLevelListener listener) + { + this.listener = listener; + } + + /** + * + * @param evt the notification event containing the list of changes. + */ + public void soundLevelChanged(SoundLevelChangeEvent evt) + { + Map levels = evt.getLevels(); + + if(levels.size() == 0) + return; + + Map res = + new HashMap(); + + ConferenceMember[] cms = getConferenceMembers(); + for(int i = 0; i < cms.length; i++) + { + ConferenceMemberSipImpl cm = (ConferenceMemberSipImpl)cms[i]; + String ssrc = cm.getSSRC(); + if(ssrc != null) + { + Integer level = levels.get(ssrc); + if(level != null) + res.put(cm, level); + } + } + + if(res.size() > 0) + listener.membersSoundLevelChanged( + new ConferenceMembersSoundLevelEvent( + CallPeerSipImpl.this, res)); + } + } + + /** + * Wraps SoundLevelListener and convert its event to + * StreamSoundLevelEvent events to be delivered to + * StreamSoundLevelListener. + */ + private class SoundLevelListenerWrapperForStream + implements SoundLevelListener + { + private StreamSoundLevelListener listener; + + public SoundLevelListenerWrapperForStream( + StreamSoundLevelListener listener) + { + this.listener = listener; + } + + /** + * Receives SoundLevelChangeEvents and converts them to + * StreamSoundLevelEvent and fires them. + * + * @param evt the notification event containing the list of changes. + */ + public void soundLevelChanged(SoundLevelChangeEvent evt) + { + Map levels = evt.getLevels(); + + // as we listens for stream sound levels we must receive + // only one level at a time, or something is wrong + if(levels.size() == 1) + { + listener.streamSoundLevelChanged( + new StreamSoundLevelEvent( + CallPeerSipImpl.this, + levels.values().iterator().next() + )); + } + else + logger.warn("suspicious behavior of the SoundLevelListener " + + "for peer " + CallPeerSipImpl.this); + } + + } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ConferenceMemberSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ConferenceMemberSipImpl.java index 4c86c9fc9..66e15c046 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ConferenceMemberSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ConferenceMemberSipImpl.java @@ -62,6 +62,11 @@ public class ConferenceMemberSipImpl */ static final String PENDING = "pending"; + /** + * The SSRC value if transmitted by the focus of the conference. + */ + private String ssrc; + /** * Initializes a new ConferenceMemberSipImpl instance with a * specific SIP address as indicated by the conference-info XML received @@ -134,4 +139,22 @@ else if (PENDING.equalsIgnoreCase(endpointStatus)) setState(state); } + + /** + * Return the SSRC value; + * @return the ssrc + */ + public String getSSRC() + { + return ssrc; + } + + /** + * Changes SSRC value; + * @param ssrc the ssrc to set + */ + public void setSSRC(String ssrc) + { + this.ssrc = ssrc; + } }