From 2f6e76ba45b0eb06e97fbb97f23d12fe2b05ab30 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov <lyubomir.marinov@jitsi.org> Date: Sat, 20 Jul 2013 15:35:00 +0300 Subject: [PATCH] Allows disabling the playback mid-stream when running Windows Audio Session API (WASAPI) without acoustic echo cancellation. --- .../impl/neomedia/device/AudioSystem.java | 5 +- .../renderer/audio/AbstractAudioRenderer.java | 12 ++-- .../media/renderer/audio/WASAPIRenderer.java | 66 +++++++++++++++++-- .../notify/AudioNotifierServiceImpl.java | 55 +++++++++++----- 4 files changed, 108 insertions(+), 30 deletions(-) diff --git a/src/org/jitsi/impl/neomedia/device/AudioSystem.java b/src/org/jitsi/impl/neomedia/device/AudioSystem.java index 320c6f70..5a8f3728 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/AudioSystem.java @@ -606,10 +606,7 @@ protected void preInitialize() * @param newValue the value of the property with the specified name after * the change */ - public void propertyChange( - String property, - Object oldValue, - Object newValue) + void propertyChange(String property, Object oldValue, Object newValue) { firePropertyChange(property, oldValue, newValue); } diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/AbstractAudioRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/AbstractAudioRenderer.java index 1048a60d..355b3e9c 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/AbstractAudioRenderer.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/AbstractAudioRenderer.java @@ -272,10 +272,14 @@ public void open() */ if ((this.locator == null) && (audioSystem != null)) { - MediaLocator locator = getLocator(); - - if (locator != null) - audioSystem.addPropertyChangeListener(propertyChangeListener); + /* + * We actually want to allow the user to switch the playback and/or + * notify device to none mid-stream in order to disable the + * playback. If an extender does not want to support that behavior, + * they will throw an exception and/or not call this implementation + * anyway. + */ + audioSystem.addPropertyChangeListener(propertyChangeListener); } } diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/WASAPIRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/WASAPIRenderer.java index 04c1967f..47c883d7 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/WASAPIRenderer.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/WASAPIRenderer.java @@ -123,6 +123,15 @@ public class WASAPIRenderer */ private long iAudioRenderClient; + /** + * The indicator which determines whether the value of the <tt>locator</tt> + * property of this instance was equal to null when this <tt>Renderer</tt> + * was opened. Indicates that this <tt>Renderer</tt> should successfully + * process media data without actually rendering to any render endpoint + * device. + */ + private boolean locatorIsNull; + /** * The maximum capacity in frames of the endpoint buffer. */ @@ -303,6 +312,7 @@ public synchronized void close() maybeCloseResampler(); dstFormat = null; + locatorIsNull = false; remainder = null; remainderLength = 0; srcFormat = null; @@ -567,8 +577,16 @@ public synchronized void open() try { locator = getLocator(); - if (locator == null) - throw new NullPointerException("No locator/MediaLocator set."); + if (locatorIsNull = (locator == null)) + { + /* + * We actually want to allow the user to switch the playback + * and/or notify device to none mid-stream in order to disable + * the playback. + */ + } + else + { /* * The method getFormatsToInitializeIAudioClient will assert that @@ -707,6 +725,8 @@ public synchronized void open() if (eventHandle != 0) CloseHandle(eventHandle); } + + } // The locator of this Renderer is not null. } catch (Throwable t) { @@ -750,7 +770,9 @@ protected synchronized void playbackDevicePropertyChange( waitWhileBusy(); - boolean open = ((iAudioClient != 0) && (iAudioRenderClient != 0)); + boolean open + = ((iAudioClient != 0) && (iAudioRenderClient != 0)) + || locatorIsNull; if (open) { @@ -817,7 +839,19 @@ public int process(Buffer buffer) synchronized (this) { - if ((iAudioClient == 0) || (iAudioRenderClient == 0) || !started) + if ((iAudioClient == 0) || (iAudioRenderClient == 0)) + { + /* + * We actually want to allow the user to switch the playback + * and/or notify device to none mid-stream in order to disable + * the playback. + */ + return + locatorIsNull + ? BUFFER_PROCESSED_OK + : BUFFER_PROCESSED_FAILED; + } + else if (!started) return BUFFER_PROCESSED_FAILED; else { @@ -1426,7 +1460,17 @@ private void setWriteIsMalfunctioning(boolean writeIsMalfunctioning) */ public synchronized void start() { - if (iAudioClient != 0) + if (iAudioClient == 0) + { + /* + * We actually want to allow the user to switch the playback and/or + * notify device to none mid-stream in order to disable the + * playback. + */ + if (locatorIsNull) + started = true; + } + else { waitWhileBusy(); waitWhileEventHandleCmd(); @@ -1519,7 +1563,17 @@ public void run() */ public synchronized void stop() { - if (iAudioClient != 0) + if (iAudioClient == 0) + { + /* + * We actually want to allow the user to switch the playback and/or + * notify device to none mid-stream in order to disable the + * playback. + */ + if (locatorIsNull) + started = false; + } + else { waitWhileBusy(); diff --git a/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java b/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java index b55e69b6..2587bdb2 100644 --- a/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java +++ b/src/org/jitsi/impl/neomedia/notify/AudioNotifierServiceImpl.java @@ -65,8 +65,9 @@ public AudioNotifierServiceImpl() } /** - * Checks whether the playback and notification configuration - * share the same device. + * Checks whether the playback and notification configuration share the same + * device. + * * @return are audio out and notifications using the same device. */ public boolean audioOutAndNotificationsShareSameDevice() @@ -77,10 +78,15 @@ public boolean audioOutAndNotificationsShareSameDevice() CaptureDeviceInfo playback = audioSystem.getSelectedDevice(AudioSystem.DataFlow.PLAYBACK); - return - (notify == null) - ? (playback == null) - : notify.getLocator().equals(playback.getLocator()); + if (notify == null) + return (playback == null); + else + { + if (playback == null) + return false; + else + return notify.getLocator().equals(playback.getLocator()); + } } /** @@ -212,6 +218,13 @@ private Boolean evaluateLoopCondition( : loopCondition.call(); } + /** + * {@inheritDoc} + * + * Returns the wrapped <tt>SCAudioClip</tt> into the + * cache from it has earlier been retrieved in order to + * allow its reuse. + */ @Override protected void finalize() throws Throwable @@ -307,8 +320,11 @@ public DeviceConfiguration getDeviceConfiguration() } /** - * Returns TRUE if the sound is currently disabled, FALSE otherwise. - * @return TRUE if the sound is currently disabled, FALSE otherwise + * Returns <tt>true</tt> if the sound is currently disabled; <tt>false</tt>, + * otherwise. + * + * @return <tt>true</tt> if the sound is currently disabled; <tt>false</tt>, + * otherwise */ public boolean isMute() { @@ -316,7 +332,8 @@ public boolean isMute() } /** - * Listens for changes in notify device + * Listens for changes in notify device. + * * @param ev the event that notify device has changed. */ public void propertyChange(PropertyChangeEvent ev) @@ -339,21 +356,21 @@ public void propertyChange(PropertyChangeEvent ev) } /** - * Enables or disables the sound in the application. If FALSE, we try to - * restore all looping sounds if any. + * Enables or disables the sound in the application. If <tt>false</tt>, we + * try to restore all looping sounds if any. * - * @param mute when TRUE disables the sound, otherwise enables the sound. + * @param mute when <tt>true</tt> disables the sound; otherwise, enables the + * sound. */ public void setMute(boolean mute) { - this.mute = mute; - // TODO Auto-generated method stub + this.mute = mute; } /** - * Implements the key of {@link AudioNotifierServiceImpl#audios}. Combines the - * <tt>uri</tt> of the <tt>SCAudioClip</tt> with the indicator which + * Implements the key of {@link AudioNotifierServiceImpl#audios}. Combines + * the <tt>uri</tt> of the <tt>SCAudioClip</tt> with the indicator which * determines whether the <tt>SCAudioClip</tt> in question uses the playback * or the notify audio device. */ @@ -381,6 +398,9 @@ private AudioKey(String uri, boolean playback) this.playback = playback; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object o) { @@ -398,6 +418,9 @@ public boolean equals(Object o) : uri.equals(that.uri)); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { -- GitLab