diff --git a/src/org/jitsi/impl/neomedia/control/AbstractControls.java b/src/org/jitsi/impl/neomedia/control/AbstractControls.java index 87e03abd989d138c50ee1df7eea75c49c0280fda..e25d2daa082e2c3835e9e20ac24ce39a37bed505 100644 --- a/src/org/jitsi/impl/neomedia/control/AbstractControls.java +++ b/src/org/jitsi/impl/neomedia/control/AbstractControls.java @@ -15,7 +15,7 @@ * implementers by requiring them to only implement * {@link Controls#getControls()}. * - * @author Lubomir Marinov + * @author Lyubomir Marinov */ public abstract class AbstractControls implements Controls @@ -73,16 +73,111 @@ public static Object getControl(Controls controlsImpl, String controlType) catch (ClassNotFoundException cnfe) { controlClass = null; - logger - .warn( + logger.warn( "Failed to find control class " + controlType, cnfe); } if (controlClass != null) + { for (Object control : controls) + { if (controlClass.isInstance(control)) return control; + } + } } return null; } + + /** + * Returns an instance of a specific <tt>Class</tt> which is either a + * control of a specific <tt>Controls</tt> implementation or the + * <tt>Controls</tt> implementation itself if it is an instance of the + * specified <tt>Class</tt>. The method is similar to + * {@link #getControl(Controls, String)} in querying the specified + * <tt>Controls</tt> implementation about a control of the specified + * <tt>Class</tt> but is different in looking at the type hierarchy of the + * <tt>Controls</tt> implementation for the specified <tt>Class</tt>. + * + * @param controlsImpl the <tt>Controls</tt> implementation to query + * @param controlType the runtime type of the instance to be returned + * @return an instance of the specified <tt>controlType</tt> if such an + * instance can be found among the controls of the specified + * <tt>controlsImpl</tt> or <tt>controlsImpl</tt> is an instance of the + * specified <tt>controlType</tt>; otherwise, <tt>null</tt> + */ + @SuppressWarnings("unchecked") + public static <T> T queryInterface( + Controls controlsImpl, + Class<T> controlType) + { + T control; + + if (controlsImpl == null) + { + control = null; + } + else + { + control = (T) controlsImpl.getControl(controlType.getName()); + if ((control == null) && controlType.isInstance(controlsImpl)) + control = (T) controlsImpl; + } + return control; + } + + /** + * Returns an instance of a specific <tt>Class</tt> which is either a + * control of a specific <tt>Controls</tt> implementation or the + * <tt>Controls</tt> implementation itself if it is an instance of the + * specified <tt>Class</tt>. The method is similar to + * {@link #getControl(Controls, String)} in querying the specified + * <tt>Controls</tt> implementation about a control of the specified + * <tt>Class</tt> but is different in looking at the type hierarchy of the + * <tt>Controls</tt> implementation for the specified <tt>Class</tt>. + * + * @param controlsImpl the <tt>Controls</tt> implementation to query + * @param controlType the runtime type of the instance to be returned + * @return an instance of the specified <tt>controlType</tt> if such an + * instance can be found among the controls of the specified + * <tt>controlsImpl</tt> or <tt>controlsImpl</tt> is an instance of the + * specified <tt>controlType</tt>; otherwise, <tt>null</tt> + */ + public static Object queryInterface( + Controls controlsImpl, + String controlType) + { + Object control; + + if (controlsImpl == null) + { + control = null; + } + else + { + control = controlsImpl.getControl(controlType); + if (control == null) + { + Class<?> controlClass; + + try + { + controlClass = Class.forName(controlType); + } + catch (ClassNotFoundException cnfe) + { + controlClass = null; + logger.warn( + "Failed to find control class " + controlType, + cnfe); + } + if ((controlClass != null) + && controlClass.isInstance(controlsImpl)) + { + control = controlsImpl; + } + } + } + return control; + } } diff --git a/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java b/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java index d24f1f9b9ca7e8612c2ae5d0ff17d33a3c9a0b09..a9a4a7944898842c01f1fef0e292700aa5c4a78b 100644 --- a/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java +++ b/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java @@ -18,6 +18,7 @@ import javax.media.rtp.*; import org.jitsi.impl.neomedia.*; +import org.jitsi.impl.neomedia.control.*; import org.jitsi.impl.neomedia.format.*; import org.jitsi.impl.neomedia.protocol.*; import org.jitsi.service.neomedia.*; @@ -395,24 +396,36 @@ protected DataSource createCaptureDevice() { DataSource captureDevice = getDevice().createOutputDataSource(); - if (!(captureDevice instanceof MuteDataSource)) + if (captureDevice != null) { - // Try to enable muting. - if (captureDevice instanceof PushBufferDataSource) - { - captureDevice - = new RewritablePushBufferDataSource( - (PushBufferDataSource) captureDevice); - } - else if (captureDevice instanceof PullBufferDataSource) + MuteDataSource muteDataSource + = AbstractControls.queryInterface( + captureDevice, + MuteDataSource.class); + + if (muteDataSource == null) { - captureDevice - = new RewritablePullBufferDataSource( - (PullBufferDataSource) captureDevice); + // Try to enable muting. + if (captureDevice instanceof PushBufferDataSource) + { + captureDevice + = new RewritablePushBufferDataSource( + (PushBufferDataSource) captureDevice); + } + else if (captureDevice instanceof PullBufferDataSource) + { + captureDevice + = new RewritablePullBufferDataSource( + (PullBufferDataSource) captureDevice); + } + muteDataSource + = AbstractControls.queryInterface( + captureDevice, + MuteDataSource.class); } + if (muteDataSource != null) + muteDataSource.setMute(mute); } - if (captureDevice instanceof MuteDataSource) - ((MuteDataSource) captureDevice).setMute(mute); return captureDevice; } @@ -1179,9 +1192,13 @@ public boolean isMute() if (captureDevice == null) return mute; - if (captureDevice instanceof MuteDataSource) - return ((MuteDataSource) captureDevice).isMute(); - return false; + + MuteDataSource muteDataSource + = AbstractControls.queryInterface( + captureDevice, + MuteDataSource.class); + + return (muteDataSource == null) ? false : muteDataSource.isMute(); } /** @@ -1796,10 +1813,13 @@ public void setMute(boolean mute) { this.mute = mute; - DataSource captureDevice = this.captureDevice; + MuteDataSource muteDataSource + = AbstractControls.queryInterface( + captureDevice, + MuteDataSource.class); - if (captureDevice instanceof MuteDataSource) - ((MuteDataSource) captureDevice).setMute(this.mute); + if (muteDataSource != null) + muteDataSource.setMute(this.mute); } } @@ -1810,10 +1830,13 @@ public void setMute(boolean mute) */ public void addDTMF(DTMFInbandTone tone) { - DataSource captureDevice = this.captureDevice; + InbandDTMFDataSource inbandDTMFDataSource + = AbstractControls.queryInterface( + captureDevice, + InbandDTMFDataSource.class); - if (captureDevice instanceof InbandDTMFDataSource) - ((InbandDTMFDataSource) captureDevice).addDTMF(tone); + if (inbandDTMFDataSource != null) + inbandDTMFDataSource.addDTMF(tone); } /** diff --git a/src/org/jitsi/impl/neomedia/protocol/RewritablePullBufferDataSource.java b/src/org/jitsi/impl/neomedia/protocol/RewritablePullBufferDataSource.java index af5dd0b678d9c91011e44e212f9b7ee8487301e0..563dbab1e7df31d3325505084c535c47367018aa 100644 --- a/src/org/jitsi/impl/neomedia/protocol/RewritablePullBufferDataSource.java +++ b/src/org/jitsi/impl/neomedia/protocol/RewritablePullBufferDataSource.java @@ -12,6 +12,7 @@ import javax.media.*; import javax.media.protocol.*; +import org.jitsi.impl.neomedia.control.*; import org.jitsi.service.neomedia.*; /** @@ -24,7 +25,7 @@ * </p> * * @author Damian Minkov - * @author Lubomir Marinov + * @author Lyubomir Marinov */ public class RewritablePullBufferDataSource extends PullBufferDataSourceDelegate<PullBufferDataSource> @@ -39,7 +40,8 @@ public class RewritablePullBufferDataSource /** * The tones to send via inband DTMF, if not empty. */ - private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>(); + private final LinkedList<DTMFInbandTone> tones + = new LinkedList<DTMFInbandTone>(); /** * Initializes a new <tt>RewritablePullBufferDataSource</tt> instance which @@ -106,6 +108,24 @@ public PullBufferDataSource getWrappedDataSource() return dataSource; } + /** + * {@inheritDoc} + * + * Overrides the super implementation to include the type hierarchy of the + * very wrapped <tt>dataSource</tt> instance into the search for the + * specified <tt>controlType</tt>. + */ + @Override + public Object getControl(String controlType) + { + /* + * The super implements a delegate so we can be sure that it delegates + * the invocation of Controls#getControl(String) to the wrapped + * dataSource. + */ + return AbstractControls.queryInterface(dataSource, controlType); + } + /** * Implements {@link PullBufferDataSource#getStreams()}. Wraps the streams * of the wrapped <tt>PullBufferDataSource</tt> into diff --git a/src/org/jitsi/impl/neomedia/protocol/RewritablePushBufferDataSource.java b/src/org/jitsi/impl/neomedia/protocol/RewritablePushBufferDataSource.java index e718f23f0d212777164311fc39e1d7ff44421a52..66ee434fb68e243c53d86a3df511005d8c2613aa 100644 --- a/src/org/jitsi/impl/neomedia/protocol/RewritablePushBufferDataSource.java +++ b/src/org/jitsi/impl/neomedia/protocol/RewritablePushBufferDataSource.java @@ -15,10 +15,8 @@ import javax.media.format.*; import javax.media.protocol.*; +import org.jitsi.impl.neomedia.control.*; import org.jitsi.service.neomedia.*; -// disambiguation. -// disambiguation. -// disambiguation. /** * Implements a <tt>PushBufferDataSource</tt> wrapper which provides mute @@ -45,7 +43,8 @@ public class RewritablePushBufferDataSource /** * The tones to send via inband DTMF, if not empty. */ - private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>(); + private final LinkedList<DTMFInbandTone> tones + = new LinkedList<DTMFInbandTone>(); /** * Initializes a new <tt>RewritablePushBufferDataSource</tt> instance which @@ -59,6 +58,24 @@ public RewritablePushBufferDataSource(PushBufferDataSource dataSource) super(dataSource); } + /** + * {@inheritDoc} + * + * Overrides the super implementation to include the type hierarchy of the + * very wrapped <tt>dataSource</tt> instance into the search for the + * specified <tt>controlType</tt>. + */ + @Override + public Object getControl(String controlType) + { + /* + * The super implements a delegate so we can be sure that it delegates + * the invocation of Controls#getControl(String) to the wrapped + * dataSource. + */ + return AbstractControls.queryInterface(dataSource, controlType); + } + /** * Implements {@link PushBufferDataSource#getStreams()}. Wraps the streams * of the wrapped <tt>PushBufferDataSource</tt> into