From 1e258ced342d04ec7d64ab5bd0b8a25c19c58866 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Wed, 21 Nov 2012 16:13:12 +0000 Subject: [PATCH] - Fixes the Eclipse .classpath of libjitsi which was broken because of the change of the JSON implementation library. - Fixes a call-related memory leak. --- .../media/MediaAwareCallConference.java | 258 +++++++++++++++++- 1 file changed, 244 insertions(+), 14 deletions(-) diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallConference.java b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallConference.java index 673ed83b0..f439dd5cf 100644 --- a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallConference.java +++ b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCallConference.java @@ -7,11 +7,13 @@ package net.java.sip.communicator.service.protocol.media; import java.beans.*; +import java.lang.ref.*; import java.util.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.device.*; import org.jitsi.util.*; +import org.jitsi.util.event.*; import net.java.sip.communicator.service.protocol.*; @@ -25,6 +27,13 @@ public class MediaAwareCallConference extends CallConference { + /** + * The PropertyChangeListener which will listen to the + * MediaService about PropertyChangeEvents. + */ + private static WeakPropertyChangeListener + mediaServicePropertyChangeListener; + /** * The MediaDevices indexed by MediaType ordinal which are * to be used by this telephony conference for media capture and/or @@ -47,12 +56,12 @@ public class MediaAwareCallConference */ private final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() - { - public void propertyChange(PropertyChangeEvent event) - { - MediaAwareCallConference.this.propertyChange(event); - } - }; + { + public void propertyChange(PropertyChangeEvent ev) + { + MediaAwareCallConference.this.propertyChange(ev); + } + }; /** * The RTPTranslator which forwards video RTP and RTCP traffic @@ -92,8 +101,49 @@ public MediaAwareCallConference(boolean jitsiVideoBridge) * Listen to the MediaService in order to reflect changes in the user's * selection with respect to the default media device. */ - ProtocolMediaActivator.getMediaService().addPropertyChangeListener( - propertyChangeListener); + addMediaServicePropertyChangeListener(propertyChangeListener); + } + + /** + * Adds a specific PropertyChangeListener to be notified about + * PropertyChangeEvents fired by the current MediaService + * implementation. The implementation adds a WeakReference to the + * specified listener because MediaAwareCallConference + * is unable to determine when the PropertyChangeListener is to be + * removed. + * + * @param listener the PropertyChangeListener to add + */ + private static synchronized void addMediaServicePropertyChangeListener( + PropertyChangeListener listener) + { + if (mediaServicePropertyChangeListener == null) + { + final MediaService mediaService + = ProtocolMediaActivator.getMediaService(); + + if (mediaService != null) + { + mediaServicePropertyChangeListener + = new WeakPropertyChangeListener() + { + protected void addThisToNotifier() + { + mediaService.addPropertyChangeListener(this); + } + + protected void removeThisFromNotifier() + { + mediaService.removePropertyChangeListener(this); + } + }; + } + } + if (mediaServicePropertyChangeListener != null) + { + mediaServicePropertyChangeListener.addPropertyChangeListener( + listener); + } } /** @@ -103,6 +153,7 @@ public MediaAwareCallConference(boolean jitsiVideoBridge) * not being such, disposes of the mixers used by this instance when it was * a conference focus */ + @Override protected void conferenceFocusChanged(boolean oldValue, boolean newValue) { /* @@ -243,17 +294,17 @@ public RTPTranslator getRTPTranslator(MediaType mediaType) * {@link MediaService#DEFAULT_DEVICE} which represents the user's choice * with respect to the default audio device. * - * @param event a PropertyChangeEvent which specifies the name of - * the property which had its value changed and the old and new values of - * that property + * @param ev a PropertyChangeEvent which specifies the name of the + * property which had its value changed and the old and new values of that + * property */ - private void propertyChange(PropertyChangeEvent event) + private void propertyChange(PropertyChangeEvent ev) { - String propertyName = event.getPropertyName(); + String propertyName = ev.getPropertyName(); if (MediaService.DEFAULT_DEVICE.equals(propertyName)) { - Object source = event.getSource(); + Object source = ev.getSource(); if (source instanceof MediaService) { @@ -332,4 +383,183 @@ void setDevice(MediaType mediaType, MediaDevice device) oldValue, newValue); } } + + /** + * Implements a PropertyChangeListener which weakly references and + * delegates to specific PropertyChangeListeners and automatically + * adds itself to and removes itself from a specific + * PropertyChangeNotifier depending on whether there are + * PropertyChangeListeners to delegate to. Thus enables listening + * to a PropertyChangeNotifier by invoking + * {@link PropertyChangeNotifier#addPropertyChangeListener( + * PropertyChangeListener)} without + * {@link PropertyChangeNotifier#removePropertyChangeListener( + * PropertyChangeListener)}. + */ + private static class WeakPropertyChangeListener + implements PropertyChangeListener + { + /** + * The indicator which determines whether this + * PropertyChangeListener has been added to {@link #notifier}. + */ + private boolean added = false; + + /** + * The list of PropertyChangeListeners which are to be notified + * about PropertyChangeEvents fired by {@link #notifier}. + */ + private final List> listeners + = new LinkedList>(); + + /** + * The PropertyChangeNotifier this instance is to listen to + * about PropertyChangeEvents which are to be forwarded to + * {@link #listeners}. + */ + private final PropertyChangeNotifier notifier; + + /** + * Initializes a new WeakPropertyChangeListener instance. + */ + protected WeakPropertyChangeListener() + { + this(null); + } + + /** + * Initializes a new WeakPropertyChangeListener instance which + * is to listen to a specific PropertyChangeNotifier. + * + * @param notifier the PropertyChangeNotifier the new instance + * is to listen to + */ + public WeakPropertyChangeListener(PropertyChangeNotifier notifier) + { + this.notifier = notifier; + } + + /** + * Adds a specific PropertyChangeListener to the list of + * PropertyChangeListeners to be notified about + * PropertyChangeEvents fired by the + * PropertyChangeNotifier associated with this instance. + * + * @param listener the PropertyChangeListener to add + */ + public synchronized void addPropertyChangeListener( + PropertyChangeListener listener) + { + Iterator> i + = listeners.iterator(); + boolean add = true; + + while (i.hasNext()) + { + PropertyChangeListener l = i.next().get(); + + if (l == null) + i.remove(); + else if (l.equals(listener)) + add = false; + } + if (add + && listeners.add( + new WeakReference(listener)) + && !this.added) + { + addThisToNotifier(); + this.added = true; + } + } + + /** + * Adds this as a PropertyChangeListener to {@link #notifier}. + */ + protected void addThisToNotifier() + { + if (notifier != null) + notifier.addPropertyChangeListener(this); + } + + /** + * {@inheritDoc} + * + * Notifies this instance about a PropertyChangeEvent fired by + * {@link #notifier}. + */ + public void propertyChange(PropertyChangeEvent ev) + { + PropertyChangeListener[] ls; + int n; + + synchronized (this) + { + Iterator> i + = listeners.iterator(); + + ls = new PropertyChangeListener[listeners.size()]; + n = 0; + while (i.hasNext()) + { + PropertyChangeListener l = i.next().get(); + + if (l == null) + i.remove(); + else + ls[n++] = l; + } + if ((n == 0) && this.added) + { + removeThisFromNotifier(); + this.added = false; + } + } + + if (n != 0) + { + for (PropertyChangeListener l : ls) + l.propertyChange(ev); + } + } + + /** + * Removes a specific PropertyChangeListener from the list of + * PropertyChangeListeners to be notified about + * PropertyChangeEvents fired by the + * PropertyChangeNotifier associated with this instance. + * + * @param listener the PropertyChangeListener to remove + */ + @SuppressWarnings("unused") + public synchronized void removePropertyChangeListener( + PropertyChangeListener listener) + { + Iterator> i + = listeners.iterator(); + + while (i.hasNext()) + { + PropertyChangeListener l = i.next().get(); + + if ((l == null) || l.equals(listener)) + i.remove(); + } + if (this.added && (listeners.size() == 0)) + { + removeThisFromNotifier(); + this.added = false; + } + } + + /** + * Removes this as a PropertyChangeListener from + * {@link #notifier}. + */ + protected void removeThisFromNotifier() + { + if (notifier != null) + notifier.removePropertyChangeListener(this); + } + } }