diff --git a/src/org/jitsi/impl/neomedia/device/AudioSystem.java b/src/org/jitsi/impl/neomedia/device/AudioSystem.java index a7d937a196e662df7c899a7102ba13bd36e883ae..b60e21d233c2a49f0adf7187118fc8642e58d20c 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/AudioSystem.java @@ -26,12 +26,6 @@ public abstract class AudioSystem public static final int FEATURE_NOTIFY_AND_PLAYBACK_DEVICES = 8; - private static final int FLAG_CAPTURE_DEVICE_IS_NULL = 1; - - private static final int FLAG_NOTIFY_DEVICE_IS_NULL = 2; - - private static final int FLAG_PLAYBACK_DEVICE_IS_NULL = 4; - public static final String LOCATOR_PROTOCOL_AUDIORECORD = "audiorecord"; public static final String LOCATOR_PROTOCOL_JAVASOUND = "javasound"; @@ -42,12 +36,6 @@ public abstract class AudioSystem public static final String LOCATOR_PROTOCOL_PULSEAUDIO = "pulseaudio"; - public static final String PROP_CAPTURE_DEVICE = "captureDevice"; - - public static final String PROP_NOTIFY_DEVICE = "notifyDevice"; - - public static final String PROP_PLAYBACK_DEVICE = "playbackDevice"; - public static AudioSystem getAudioSystem(String locatorProtocol) { AudioSystem[] audioSystems = getAudioSystems(); @@ -89,15 +77,25 @@ public static AudioSystem[] getAudioSystems() : audioSystems.toArray(new AudioSystem[audioSystems.size()]); } - private CaptureDeviceInfo captureDevice; - - private int flags; + /** + * The index of the capture devices. + */ + public static final int CAPTURE_INDEX = 0; - private CaptureDeviceInfo notifyDevice; + /** + * The index of the notify devices. + */ + public static final int NOTIFY_INDEX = 1; - private CaptureDeviceInfo playbackDevice; + /** + * The index of the playback devices. + */ + public static final int PLAYBACK_INDEX = 2; - private List<CaptureDeviceInfo> playbackDevices; + /** + * The list of the devices: capture, notify or playback. + */ + private Devices[] devices; protected AudioSystem(String locatorProtocol) throws Exception @@ -111,188 +109,86 @@ protected AudioSystem(String locatorProtocol, int features) super(MediaType.AUDIO, locatorProtocol, features); } - public CaptureDeviceInfo getCaptureDevice() + /** + * Gets the list of a kind of devices: cpature, notify or playback. + * + * @param index The index of the specific devices: cpature, notify or + * playback. + * + * @return The list of a kind of devices: cpature, notify or playback. + */ + public List<CaptureDeviceInfo> getDevices(int index) { - List<CaptureDeviceInfo> captureDevices = null; - - if (this.captureDevice != null) - { - if (captureDevices == null) - captureDevices = getCaptureDevices(); - if ((captureDevices == null) - || !captureDevices.contains(this.captureDevice)) - setCaptureDevice(null, false); - } - - CaptureDeviceInfo captureDevice = this.captureDevice; - - if ((captureDevice == null) - && ((flags & FLAG_CAPTURE_DEVICE_IS_NULL) == 0)) - { - if (captureDevices == null) - captureDevices = getCaptureDevices(); - if ((captureDevices != null) && (captureDevices.size() > 0)) - { - captureDevice = loadDevice(PROP_CAPTURE_DEVICE, captureDevices); - if (captureDevice == null) - captureDevice = captureDevices.get(0); - } - } - return captureDevice; + return this.devices[index].getDevices(getLocatorProtocol()); } - public List<CaptureDeviceInfo> getCaptureDevices() - { - MediaServiceImpl mediaServiceImpl - = NeomediaServiceUtils.getMediaServiceImpl(); - DeviceConfiguration deviceConfiguration - = (mediaServiceImpl == null) - ? null - : mediaServiceImpl.getDeviceConfiguration(); - List<CaptureDeviceInfo> deviceList; - - if (deviceConfiguration == null) - { - /* - * XXX The initialization of MediaServiceImpl is very complex so it - * is wise to not reference it at the early stage of its - * initialization. The same goes for DeviceConfiguration. If for - * some reason one of the two is not available at this time, just - * fall back go something that makes sense. - */ - @SuppressWarnings("unchecked") - Vector<CaptureDeviceInfo> audioCaptureDeviceInfos - = CaptureDeviceManager.getDeviceList( - new AudioFormat(AudioFormat.LINEAR, -1, 16, -1)); - - deviceList = audioCaptureDeviceInfos; - } - else - { - deviceList = deviceConfiguration.getAvailableAudioCaptureDevices(); - } - - return - filterDeviceListByLocatorProtocol(deviceList, getLocatorProtocol()); - } - - public CaptureDeviceInfo getNotifyDevice() + /** + * Gets the selected device for a specific kind: cpature, notify or + * playback. + * + * @param index The index of the specific devices: cpature, notify or + * playback. + * + * @return The selected device for a specific kind: cpature, notify or + * playback. + */ + public CaptureDeviceInfo getDevice(int index) { - List<CaptureDeviceInfo> notifyDevices = null; - - if (this.notifyDevice != null) - { - if (notifyDevices == null) - notifyDevices = getNotifyDevices(); - if ((notifyDevices == null) - || !notifyDevices.contains(this.notifyDevice)) - setNotifyDevice(null, false); - } - - CaptureDeviceInfo notifyDevice = this.notifyDevice; - - if ((notifyDevice == null) - && ((flags & FLAG_NOTIFY_DEVICE_IS_NULL) == 0)) - { - if (notifyDevices == null) - notifyDevices = getNotifyDevices(); - if ((notifyDevices != null) && (notifyDevices.size() > 0)) - { - notifyDevice = loadDevice(PROP_NOTIFY_DEVICE, notifyDevices); - if (notifyDevice == null) - notifyDevice = notifyDevices.get(0); - } - } - return notifyDevice; + return this.devices[index].getDevice(getLocatorProtocol()); } - public List<CaptureDeviceInfo> getNotifyDevices() + /** + * Sets the list of a kind of devices: cpature, notify or playback. + * + * @param activeCaptureDevices The list of a kind of devices: cpature, + * notify or playback. + */ + protected void setCaptureDevices( + List<CaptureDeviceInfo> activeCaptureDevices) { - return getPlaybackDevices(); + this.devices[CAPTURE_INDEX].setActiveDevices(activeCaptureDevices); } - public CaptureDeviceInfo getPlaybackDevice() + /** + * Selects the active device. + * + * @param index The index corresponding to a specific device kind: + * capture/notify/playback. + * @param device The selected active device. + * @param save Flag set to true in order to save this choice in the + * configuration. False otherwise. + */ + public void setDevice(int index, CaptureDeviceInfo device, boolean save) { - List<CaptureDeviceInfo> playbackDevices = null; - - if (this.playbackDevice != null) - { - if (playbackDevices == null) - playbackDevices = getPlaybackDevices(); - if ((playbackDevices == null) - || !playbackDevices.contains(this.playbackDevice)) - setPlaybackDevice(null, false); - } - - CaptureDeviceInfo playbackDevice = this.playbackDevice; - - if ((playbackDevice == null) - && ((flags & FLAG_PLAYBACK_DEVICE_IS_NULL) == 0)) - { - if (playbackDevices == null) - playbackDevices = getPlaybackDevices(); - if ((playbackDevices != null) && (playbackDevices.size() > 0)) - { - playbackDevice - = loadDevice(PROP_PLAYBACK_DEVICE, playbackDevices); - if (playbackDevice == null) - playbackDevice = playbackDevices.get(0); - } - } - return playbackDevice; + this.devices[index].setDevice(getLocatorProtocol(), device, save); } - public List<CaptureDeviceInfo> getPlaybackDevices() + /** + * Sets the list of the active devices. + * + * @param activePlaybackDevices The list of the active devices. + */ + protected void setPlaybackDevices( + List<CaptureDeviceInfo> activePlaybackDevices) { - List<CaptureDeviceInfo> playbackDevices = this.playbackDevices; - - return - (playbackDevices == null) - ? null - : new ArrayList<CaptureDeviceInfo>(playbackDevices); + this.devices[PLAYBACK_INDEX].setActiveDevices(activePlaybackDevices); + // The active notify device list is a copy of the playback one. + this.devices[NOTIFY_INDEX].setActiveDevices(activePlaybackDevices); } /** - * Loads the user's preference with respect to a <tt>CaptureDeviceInfo</tt> - * among a specific list of <tt>CaptureDeviceInfo</tt>s from the - * <tt>ConfigurationService</tt>. - * - * @param property the name of the <tt>ConfigurationService</tt> property - * which specifies the user's preference with respect to a - * <tt>CaptureDeviceInfo</tt> among the specified list of - * <tt>CaptureDeviceInfo</tt>s - * @param devices the list of <tt>CaptureDeviceInfo</tt>s which are valid - * selections for the user's preference - * @return a <tt>CaptureDeviceInfo</tt> among the specified <tt>devices</tt> - * which represents the user's preference stored in the - * <tt>ConfigurationService</tt> + * Pre-initializes this audio system before setting the different devices. */ - private CaptureDeviceInfo loadDevice( - String property, - List<CaptureDeviceInfo> devices) + protected void preInitialize() { - ConfigurationService cfg = LibJitsi.getConfigurationService(); - - if (cfg != null) + super.preInitialize(); + if(this.devices == null) { - property - = DeviceConfiguration.PROP_AUDIO_SYSTEM - + "." - + getLocatorProtocol() - + "." - + property; - - String name = cfg.getString(property); - - if ((name != null) - && !NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase(name)) - { - for (CaptureDeviceInfo device : devices) - if (name.equals(device.getName())) - return device; - } + this.devices = new Devices[3]; + this.devices[0] = new CaptureDevices(this); + this.devices[1] = new NotifyDevices(this); + this.devices[2] = new PlaybackDevices(this); } - return null; } @Override @@ -306,24 +202,7 @@ protected void postInitialize() { try { - if (captureDevice != null) - { - List<CaptureDeviceInfo> captureDevices - = getCaptureDevices(); - - if ((captureDevices == null) - || !captureDevices.contains(captureDevice)) - setCaptureDevice(null, false); - } - else - { - /* - * If captureDevice is null, it means that a device is to be - * used as the default. The default in question may have - * changed. - */ - setCaptureDevice(null, false); - } + this.postInitializeSpecificDevices(CAPTURE_INDEX); } finally { @@ -331,46 +210,11 @@ protected void postInitialize() { try { - if (notifyDevice != null) - { - List<CaptureDeviceInfo> notifyDevices - = getNotifyDevices(); - - if ((notifyDevices == null) - || !notifyDevices.contains(notifyDevice)) - setNotifyDevice(null, false); - } - else - { - /* - * If notifyDevice is null, it means that a device - * is to be used as the default. The default in - * question may have changed. - */ - setNotifyDevice(null, false); - } + this.postInitializeSpecificDevices(NOTIFY_INDEX); } finally { - if (playbackDevice != null) - { - List<CaptureDeviceInfo> playbackDevices - = getPlaybackDevices(); - - if ((playbackDevices == null) - || !playbackDevices.contains( - playbackDevice)) - setPlaybackDevice(null, false); - } - else - { - /* - * If playbackDevice is null, it means that a device - * is to be used as the default. The default in - * question may have changed. - */ - setPlaybackDevice(null, false); - } + this.postInitializeSpecificDevices(PLAYBACK_INDEX); } } } @@ -378,157 +222,65 @@ protected void postInitialize() } /** - * Saves the user's preference with respect to a specific - * <tt>CaptureDeviceInfo</tt> in the <tt>ConfigurationService</tt>. + * Sets the device lists after the different audio systems (portaudio, + * pulseaudio, etc) have finished to detects the evices. * - * @param property the name of the <tt>ConfigurationService</tt> property - * into which the user's preference with respect to the specified - * <tt>CaptureDeviceInfo</tt> is to be saved - * @param device the <tt>CaptureDeviceInfo</tt> which is the user's - * preference - * @param isNull <tt>true</tt> if the user's preference with respect to the - * specified <tt>device</tt> is <tt>null</tt>; otherwise, <tt>false</tt> + * @param index The index corresponding to a specific device kind: + * capture/notify/playback. */ - private void saveDevice( - String property, - CaptureDeviceInfo device, - boolean isNull) - { - ConfigurationService cfg = LibJitsi.getConfigurationService(); - - if (cfg != null) - { - property - = DeviceConfiguration.PROP_AUDIO_SYSTEM - + "." - + getLocatorProtocol() - + "." - + property; - if (device == null) - { - if (isNull) - cfg.setProperty(property, NoneAudioSystem.LOCATOR_PROTOCOL); - else - cfg.removeProperty(property); - } - else - cfg.setProperty(property, device.getName()); - } - } - - public void setCaptureDevice(CaptureDeviceInfo captureDevice, boolean save) + protected void postInitializeSpecificDevices(int index) { - if ((this.captureDevice != captureDevice) || (captureDevice == null)) + // If there is a selected device, checks if it is part of the current + // active devices. + if (this.devices[index].getDevice(getLocatorProtocol()) != null) { - CaptureDeviceInfo oldValue = this.captureDevice; - - this.captureDevice = captureDevice; + List<CaptureDeviceInfo> devices = this.devices[index].getDevices( + getLocatorProtocol()); - if (save) + if ((devices == null) + || !devices.contains(this.devices[index].getDevice( + getLocatorProtocol()))) { - boolean isNull = (this.captureDevice == null); - - if (isNull) - flags |= FLAG_CAPTURE_DEVICE_IS_NULL; - else - flags &= ~FLAG_CAPTURE_DEVICE_IS_NULL; - - saveDevice(PROP_CAPTURE_DEVICE, this.captureDevice, isNull); + // The selected device is not part of the active devices, then + // set it to null (but not saved). + this.devices[index].setDevice( + getLocatorProtocol(), + null, + false); } - - CaptureDeviceInfo newValue = getCaptureDevice(); - - if (oldValue != newValue) - firePropertyChange(PROP_CAPTURE_DEVICE, oldValue, newValue); } - } - - protected void setCaptureDevices(List<CaptureDeviceInfo> captureDevices) - { - if (captureDevices != null) - { - boolean commit = false; - - for (CaptureDeviceInfo captureDevice : captureDevices) - { - CaptureDeviceManager.addDevice(captureDevice); - commit = true; - } - if (commit && !MediaServiceImpl.isJmfRegistryDisableLoad()) - { - try - { - CaptureDeviceManager.commit(); - } - catch (IOException ioe) - { - // Whatever. - } - } - } - } - - public void setNotifyDevice(CaptureDeviceInfo notifyDevice, boolean save) - { - if ((this.notifyDevice != notifyDevice) || (notifyDevice == null)) - { - CaptureDeviceInfo oldValue = this.notifyDevice; - - this.notifyDevice = notifyDevice; - - if (save) - { - boolean isNull = (this.notifyDevice == null); - - if (isNull) - flags |= FLAG_NOTIFY_DEVICE_IS_NULL; - else - flags &= ~FLAG_NOTIFY_DEVICE_IS_NULL; - - saveDevice(PROP_NOTIFY_DEVICE, this.notifyDevice, isNull); - } - - CaptureDeviceInfo newValue = getNotifyDevice(); - - if (oldValue != newValue) - firePropertyChange(PROP_NOTIFY_DEVICE, oldValue, newValue); - } - } - - public void setPlaybackDevice( - CaptureDeviceInfo playbackDevice, - boolean save) - { - if ((this.playbackDevice != playbackDevice) || (playbackDevice == null)) + else { - CaptureDeviceInfo oldValue = this.playbackDevice; - - this.playbackDevice = playbackDevice; - - if (save) - { - boolean isNull = (this.playbackDevice == null); - - if (isNull) - flags |= FLAG_PLAYBACK_DEVICE_IS_NULL; - else - flags &= ~FLAG_PLAYBACK_DEVICE_IS_NULL; - - saveDevice(PROP_PLAYBACK_DEVICE, this.playbackDevice, isNull); - } - - CaptureDeviceInfo newValue = getPlaybackDevice(); - - if (oldValue != newValue) - firePropertyChange(PROP_PLAYBACK_DEVICE, oldValue, newValue); + /* + * If the device is null, it means that a device is to be + * used as the default. The default in question may have + * changed. + */ + this.devices[index].setDevice(getLocatorProtocol(), null, false); } } - protected void setPlaybackDevices(List<CaptureDeviceInfo> playbackDevices) + /** + * Fires a new <tt>PropertyChangeEvent</tt> to the + * <tt>PropertyChangeListener</tt>s registered with this + * <tt>PropertyChangeNotifier</tt> in order to notify about a change in the + * value of a specific property which had its old value modified to a + * specific new value. <tt>PropertyChangeNotifier</tt> does not check + * whether the specified <tt>oldValue</tt> and <tt>newValue</tt> are indeed + * different. + * + * @param property the name of the property of this + * <tt>PropertyChangeNotifier</tt> which had its value changed + * @param oldValue the value of the property with the specified name before + * the change + * @param newValue the value of the property with the specified name after + * the change + */ + public void propertyChange( + String property, + Object oldValue, + Object newValue) { - this.playbackDevices - = (playbackDevices == null) - ? null - : new ArrayList<CaptureDeviceInfo>(playbackDevices); + firePropertyChange(property, oldValue, newValue); } } diff --git a/src/org/jitsi/impl/neomedia/device/CaptureDevices.java b/src/org/jitsi/impl/neomedia/device/CaptureDevices.java new file mode 100644 index 0000000000000000000000000000000000000000..05dee0e657720655793690b1bbc8836997316eee --- /dev/null +++ b/src/org/jitsi/impl/neomedia/device/CaptureDevices.java @@ -0,0 +1,138 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jitsi.impl.neomedia.device; + +import java.io.*; +import java.util.*; + +import javax.media.*; +import javax.media.format.*; + +import org.jitsi.impl.neomedia.*; + +/** + * Manages the list of active (currently pluged-in) capture devices and manages + * user preferences between all known devices (previously and actually + * plugged-in). + * + * @author Vincent Lucas + */ +public class CaptureDevices + extends Devices +{ + /** + * The flag nuber if the capture device is null. + */ + protected static final int FLAG_DEVICE_IS_NULL = 1; + + /** + * The property of the capture devices. + */ + public static final String PROP_DEVICE = "captureDevice"; + + /** + * Initializes the capture device list managment. + * + * @param audioSystem The audio system managing this capture device list. + */ + public CaptureDevices(AudioSystem audioSystem) + { + super(audioSystem); + } + + /** + * Returns the list of the active devices. + * + * @param locator The string representation of the locator. + * + * @return The list of the active devices. + */ + public List<CaptureDeviceInfo> getDevices(String locator) + { + MediaServiceImpl mediaServiceImpl + = NeomediaServiceUtils.getMediaServiceImpl(); + DeviceConfiguration deviceConfiguration = (mediaServiceImpl == null) + ? null + : mediaServiceImpl.getDeviceConfiguration(); + List<CaptureDeviceInfo> deviceList; + + if (deviceConfiguration == null) + { + /* + * XXX The initialization of MediaServiceImpl is very complex so it + * is wise to not reference it at the early stage of its + * initialization. The same goes for DeviceConfiguration. If for + * some reason one of the two is not available at this time, just + * fall back go something that makes sense. + */ + @SuppressWarnings("unchecked") + Vector<CaptureDeviceInfo> audioCaptureDeviceInfos + = CaptureDeviceManager.getDeviceList( + new AudioFormat(AudioFormat.LINEAR, -1, 16, -1)); + + deviceList = audioCaptureDeviceInfos; + } + else + { + deviceList = deviceConfiguration.getAvailableAudioCaptureDevices(); + } + + return DeviceSystem.filterDeviceListByLocatorProtocol( + deviceList, + locator); + } + + /** + * Sets the list of the active devices. + * + * @param activeDevices The list of the active devices. + */ + public void setActiveDevices(List<CaptureDeviceInfo> activeDevices) + { + if(activeDevices != null) + { + boolean commit = false; + + for (CaptureDeviceInfo activeDevice : activeDevices) + { + CaptureDeviceManager.addDevice(activeDevice); + commit = true; + } + if (commit && !MediaServiceImpl.isJmfRegistryDisableLoad()) + { + try + { + CaptureDeviceManager.commit(); + } + catch (IOException ioe) + { + // Whatever. + } + } + } + } + + /** + * Returns the flag nuber if the capture device is null. + * + * @return The flag nuber if the capture device is null. + */ + protected int getFlagDeviceIsNull() + { + return FLAG_DEVICE_IS_NULL; + } + + /** + * Returns the property of the capture devices. + * + * @return The property of the capture devices. + */ + protected String getPropDevice() + { + return PROP_DEVICE; + } +} diff --git a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java index 8c025e56e4506e13ccfc645ada82dd9181724d78..1c8ba4d31a1850eaf5b105dc54addc8205dfae32 100644 --- a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java +++ b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java @@ -43,21 +43,21 @@ public class DeviceConfiguration * the device used by <tt>DeviceConfiguration</tt> for audio capture. */ public static final String AUDIO_CAPTURE_DEVICE - = AudioSystem.PROP_CAPTURE_DEVICE; + = CaptureDevices.PROP_DEVICE; /** * The name of the <tt>DeviceConfiguration</tt> property which represents * the device used by <tt>DeviceConfiguration</tt> for audio notify. */ public static final String AUDIO_NOTIFY_DEVICE - = AudioSystem.PROP_NOTIFY_DEVICE; + = NotifyDevices.PROP_DEVICE; /** * The name of the <tt>DeviceConfiguration</tt> property which represents * the device used by <tt>DeviceConfiguration</tt> for audio playback. */ public static final String AUDIO_PLAYBACK_DEVICE - = AudioSystem.PROP_PLAYBACK_DEVICE; + = PlaybackDevices.PROP_DEVICE; /** * The list of class names of custom <tt>Renderer</tt> implementations to be @@ -399,7 +399,9 @@ public CaptureDeviceInfo getAudioCaptureDevice() { AudioSystem audioSystem = getAudioSystem(); - return (audioSystem == null) ? null : audioSystem.getCaptureDevice(); + return (audioSystem == null) + ? null + : audioSystem.getDevice(AudioSystem.CAPTURE_INDEX); } /** @@ -444,7 +446,7 @@ public AudioSystem[] getAvailableAudioSystems() audioSystem.getLocatorProtocol())) { List<CaptureDeviceInfo> captureDevices - = audioSystem.getCaptureDevices(); + = audioSystem.getDevices(AudioSystem.CAPTURE_INDEX); if ((captureDevices == null) || (captureDevices.size() <= 0)) @@ -458,13 +460,15 @@ public AudioSystem[] getAvailableAudioSystems() else { List<CaptureDeviceInfo> notifyDevices - = audioSystem.getNotifyDevices(); + = audioSystem.getDevices( + AudioSystem.NOTIFY_INDEX); if ((notifyDevices == null) || (notifyDevices.size() <= 0)) { List<CaptureDeviceInfo> playbackDevices - = audioSystem.getPlaybackDevices(); + = audioSystem.getDevices( + AudioSystem.PLAYBACK_INDEX); if ((playbackDevices == null) || (playbackDevices.size() <= 0)) @@ -651,7 +655,9 @@ public CaptureDeviceInfo getAudioNotifyDevice() { AudioSystem audioSystem = getAudioSystem(); - return (audioSystem == null) ? null : audioSystem.getNotifyDevice(); + return (audioSystem == null) + ? null + : audioSystem.getDevice(AudioSystem.NOTIFY_INDEX); } /** @@ -989,9 +995,9 @@ public void propertyChange(PropertyChangeEvent event) { String propertyName = event.getPropertyName(); - if (AudioSystem.PROP_CAPTURE_DEVICE.equals(propertyName) - || AudioSystem.PROP_NOTIFY_DEVICE.equals(propertyName) - || AudioSystem.PROP_PLAYBACK_DEVICE.equals(propertyName)) + if (AUDIO_CAPTURE_DEVICE.equals(propertyName) + || AUDIO_NOTIFY_DEVICE.equals(propertyName) + || AUDIO_PLAYBACK_DEVICE.equals(propertyName)) { firePropertyChange( propertyName, diff --git a/src/org/jitsi/impl/neomedia/device/Devices.java b/src/org/jitsi/impl/neomedia/device/Devices.java new file mode 100644 index 0000000000000000000000000000000000000000..bc34943b2f092a924220ee84c8cd0979d27a791c --- /dev/null +++ b/src/org/jitsi/impl/neomedia/device/Devices.java @@ -0,0 +1,371 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jitsi.impl.neomedia.device; + +import java.util.*; + +import javax.media.*; + +import org.jitsi.service.configuration.*; +import org.jitsi.service.libjitsi.*; + +/** + * Manages the list of active (currently pluged-in) capture/notify/playback + * devices and manages user preferences between all known devices (previously + * and actually plugged-in). + * + * @author Vincent Lucas + */ +public abstract class Devices +{ + /** + * The selected active device. + */ + protected CaptureDeviceInfo device = null; + + /** + * The list of device names saved by the congifuration service and + * previously saved given user preference order. + */ + protected List<String> devicePreferences = new ArrayList<String>(); + + /** + * The flags that can save if the FLAG_DEVICE_IS_NULL state is set. + */ + private int flags; + + /** + * The audio system managing this device list. + */ + private AudioSystem audioSystem; + + /** + * Initializes the device list managment. + * + * @param audioSystem The audio system managing this device list. + */ + public Devices(AudioSystem audioSystem) + { + this.audioSystem = audioSystem; + } + + /** + * Gets the selected active device. + * + * @param locator The string representation of the locator. + * + * @return The selected active device. + */ + public CaptureDeviceInfo getDevice(String locator) + { + List<CaptureDeviceInfo> devices = getDevices(locator); + + // Reinit the selected device if this one is no more in the active list. + if (this.device != null) + { + if ((devices == null) || !devices.contains(this.device)) + { + setDevice(locator, null, false); + } + } + + CaptureDeviceInfo device = this.device; + + // If the device is null and the device is not desactivated, then try to + // find the user preferred one between the active devices. + if ((device == null) && ((flags & getFlagDeviceIsNull()) == 0)) + { + if ((devices != null) && (devices.size() > 0)) + { + device = loadDevice(locator, getPropDevice(), devices); + if (device == null) + device = devices.get(0); + } + } + return device; + } + + /** + * Returns the list of the active devices. + * + * @param locator The string representation of the locator. + * + * @return The list of the active devices. + */ + public abstract List<CaptureDeviceInfo> getDevices(String locator); + + /** + * Loads the user's preference with respect to a <tt>CaptureDeviceInfo</tt> + * among a specific list of <tt>CaptureDeviceInfo</tt>s from the + * <tt>ConfigurationService</tt>. + * + * @param locator The string representation of the locator. + * @param property the name of the <tt>ConfigurationService</tt> property + * which specifies the user's preference with respect to a + * <tt>CaptureDeviceInfo</tt> among the specified list of + * <tt>CaptureDeviceInfo</tt>s + * @param devices the list of <tt>CaptureDeviceInfo</tt>s which are valid + * selections for the user's preference + * @return a <tt>CaptureDeviceInfo</tt> among the specified <tt>devices</tt> + * which represents the user's preference stored in the + * <tt>ConfigurationService</tt> + */ + private CaptureDeviceInfo loadDevice( + String locator, + String property, + List<CaptureDeviceInfo> devices) + { + loadDevicePreferences(locator, property); + + // Search if an active device is a new one (is not stored in the + // preferences yet). If true, then active this device and set it as + // default device. + for(CaptureDeviceInfo device : devices) + { + if(!devicePreferences.contains(device.getName())) + { + // Adds the device in the preference list (to the end of the + // list, but the save device will push it to the top of active + // devices). + devicePreferences.add(device.getName()); + this.saveDevice(locator, property, device, false); + } + } + // Search if an active device match one of the previsouly configured in + // the preferences. + for(int i = 0; i < devicePreferences.size(); ++i) + { + for(CaptureDeviceInfo device : devices) + if (devicePreferences.get(i).equals(device.getName())) + return device; + } + + // If no active devices matches a configured one, then gets the first + // active device available. + if(devices.size() > 0) + { + return devices.get(0); + } + + // Else if nothing was found, then returns null. + return null; + } + + /** + * Loads device name ordered with user's preference from the + * <tt>ConfigurationService</tt>. + * + * @param locator The string representation of the locator. + * @param property the name of the <tt>ConfigurationService</tt> property + * which specifies the user's preference. + */ + private void loadDevicePreferences(String locator, String property) + { + ConfigurationService cfg = LibJitsi.getConfigurationService(); + + if (cfg != null) + { + String new_property + = DeviceConfiguration.PROP_AUDIO_SYSTEM + + "." + + locator + + "." + + property + + "_list"; + + String deviceNamesString = cfg.getString(new_property); + + if (deviceNamesString != null + && !NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase( + deviceNamesString)) + { + devicePreferences.clear(); + // We must parce the string in order to load the device list. + String[] deviceNames = deviceNamesString + .substring(2, deviceNamesString.length() - 2) + .split("\", \""); + for(int i = 0; i < deviceNames.length; ++i) + { + devicePreferences.add(deviceNames[i]); + } + } + // Else, use the old property to load the last preferred device. + // This whole "else" block may be removed in the future. + else + { + String old_property + = DeviceConfiguration.PROP_AUDIO_SYSTEM + + "." + + locator + + "." + + property; + + deviceNamesString = cfg.getString(old_property); + + if (deviceNamesString != null + && !NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase( + deviceNamesString)) + { + devicePreferences.clear(); + devicePreferences.add(deviceNamesString); + } + } + } + } + + /** + * Saves the new selected device in top of the user preferences. + * + * @param locator The string representation of the locator. + * @param property the name of the <tt>ConfigurationService</tt> property + * into which the user's preference with respect to the specified + * <tt>CaptureDeviceInfo</tt> is to be saved + * @param device the <tt>CaptureDeviceInfo</tt> selected by the user. + * @param isNull <tt>true</tt> if the user's preference with respect to the + * specified <tt>device</tt> is <tt>null</tt>; otherwise, <tt>false</tt> + */ + private void saveDevice( + String locator, + String property, + CaptureDeviceInfo device, + boolean isNull) + { + ConfigurationService cfg = LibJitsi.getConfigurationService(); + + if (cfg != null) + { + property + = DeviceConfiguration.PROP_AUDIO_SYSTEM + + "." + locator + + "." + property + + "_list"; + if(device == null) + { + if(isNull) + { + cfg.setProperty(property, NoneAudioSystem.LOCATOR_PROTOCOL); + } + else + { + cfg.removeProperty(property); + } + } + else + { + // Sorts the user preferences to put the selected device on top. + ArrayList resultList + = new ArrayList<String>(devicePreferences.size() + 1); + List<CaptureDeviceInfo> devices = getDevices(locator); + boolean firstActiveFound = false; + for(int i = 0; i < devicePreferences.size(); ++i) + { + // Checks if this element is an active device. + for(int j = 0; !firstActiveFound && j < devices.size(); ++j) + { + if(devicePreferences.get(i).equals( + devices.get(j).getName())) + { + // The first active device is found, then place the + // selected device at the previous place. + resultList.add(device.getName()); + firstActiveFound = true; + } + } + + // Checks that we do not add dupplicate of the selected + // device> + if(!devicePreferences.get(i).equals(device.getName())) + { + resultList.add(devicePreferences.get(i)); + } + } + // Updates the preferences list with the ew one computed. + devicePreferences = resultList; + + // Saves the user preferences. + StringBuffer value = new StringBuffer("[\""); + if(devicePreferences.size() > 0) + { + value.append(devicePreferences.get(0)); + for(int i = 1; i < devicePreferences.size(); ++i) + { + value.append("\", \"" + devicePreferences.get(i)); + } + } + value.append("\"]"); + cfg.setProperty(property, value.toString()); + } + } + } + + /** + * Selects the active device. + * + * @param locator The string representation of the locator. + * @param device The selected active device. + * @param save Flag set to true in order to save this choice in the + * configuration. False otherwise. + */ + public void setDevice( + String locator, + CaptureDeviceInfo device, + boolean save) + { + // Checks if there is a change. + if ((this.device != device) || (device == null)) + { + CaptureDeviceInfo oldValue = this.device; + this.device = device; + + // Saves the new selected device in top of the user preferences. + if (save) + { + boolean isNull = (this.device == null); + + if (isNull) + flags |= getFlagDeviceIsNull(); + else + flags &= ~getFlagDeviceIsNull(); + + saveDevice(locator, getPropDevice(), this.device, isNull); + } + + CaptureDeviceInfo newValue = getDevice(locator); + + if (oldValue != newValue) + { + if(this.audioSystem != null) + { + this.audioSystem + .propertyChange(getPropDevice(), oldValue, newValue); + } + } + } + } + + /** + * Sets the list of the active devices. + * + * @param activeDevices The list of the active devices. + */ + public abstract void setActiveDevices( + List<CaptureDeviceInfo> activeDevices); + + /** + * Returns the flag nuber if the capture device is null. + * + * @return The flag nuber if the capture device is null. + */ + protected abstract int getFlagDeviceIsNull(); + + /** + * Returns the property of the capture devices. + * + * @return The property of the capture devices. + */ + protected abstract String getPropDevice(); +} diff --git a/src/org/jitsi/impl/neomedia/device/NotifyDevices.java b/src/org/jitsi/impl/neomedia/device/NotifyDevices.java new file mode 100644 index 0000000000000000000000000000000000000000..ff76b22acc25ef5c704b25f567de056ad56c1347 --- /dev/null +++ b/src/org/jitsi/impl/neomedia/device/NotifyDevices.java @@ -0,0 +1,62 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jitsi.impl.neomedia.device; + +import java.util.*; + +import javax.media.*; + +/** + * Manages the list of active (currently pluged-in) notify devices and manages + * user preferences between all known devices (previously and actually + * plugged-in). + * + * @author Vincent Lucas + */ +public class NotifyDevices + extends PlaybackDevices +{ + /** + * The flag nuber if the notify device is null. + */ + protected static final int FLAG_DEVICE_IS_NULL = 2; + + /** + * The property of the notify devices. + */ + public static final String PROP_DEVICE = "notifyDevice"; + + /** + * Initializes the notify device list managment. + * + * @param audioSystem The audio system managing this notify device list. + */ + public NotifyDevices(AudioSystem audioSystem) + { + super(audioSystem); + } + + /** + * Returns the flag nuber if the capture device is null. + * + * @return The flag nuber if the capture device is null. + */ + protected int getFlagDeviceIsNull() + { + return FLAG_DEVICE_IS_NULL; + } + + /** + * Returns the property of the capture devices. + * + * @return The property of the capture devices. + */ + protected String getPropDevice() + { + return PROP_DEVICE; + } +} diff --git a/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java b/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java new file mode 100644 index 0000000000000000000000000000000000000000..c2ba74231c934b636f628c48d2de43a2bc4abb83 --- /dev/null +++ b/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java @@ -0,0 +1,96 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package org.jitsi.impl.neomedia.device; + +import java.util.*; + +import javax.media.*; + +/** + * Manages the list of active (currently pluged-in) playback devices and manages + * user preferences between all known devices (previously and actually + * plugged-in). + * + * @author Vincent Lucas + */ +public class PlaybackDevices + extends Devices +{ + /** + * The flag nuber if the playback device is null. + */ + protected static final int FLAG_DEVICE_IS_NULL = 4; + + /** + * The property of the playback devices. + */ + public static final String PROP_DEVICE = "playbackDevice"; + + /** + * The list of active (actually plugged-in) playback devices. + */ + private List<CaptureDeviceInfo> activePlaybackDevices = null; + + /** + * Initializes the playback device list managment. + * + * @param audioSystem The audio system managing this playback device list. + */ + public PlaybackDevices(AudioSystem audioSystem) + { + super(audioSystem); + } + + /** + * Returns the list of the active devices. + * + * @param locator The string representation of the locator. + * + * @return The list of the active devices. + */ + public List<CaptureDeviceInfo> getDevices(String locator) + { + List<CaptureDeviceInfo> activePlaybackDevices + = this.activePlaybackDevices; + + return (activePlaybackDevices == null) + ? null + : new ArrayList<CaptureDeviceInfo>(activePlaybackDevices); + } + + /** + * Sets the list of the active devices. + * + * @param activeDevices The list of the active devices. + */ + public void setActiveDevices(List<CaptureDeviceInfo> activeDevices) + { + this.activePlaybackDevices = (activeDevices == null) + ? null + : new ArrayList<CaptureDeviceInfo>(activeDevices); + } + + /** + * Returns the flag nuber if the capture device is null. + * + * @return The flag nuber if the capture device is null. + */ + protected int getFlagDeviceIsNull() + { + return FLAG_DEVICE_IS_NULL; + } + + /** + * Returns the property of the capture devices. + * + * @return The property of the capture devices. + */ + protected String getPropDevice() + { + return PROP_DEVICE; + } +} diff --git a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java index 6a78d3625930e7741c37a6a33eed9f6243d8a8b6..09b8c170282510eff7a205facb740b04cd3028b3 100644 --- a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java @@ -69,7 +69,8 @@ public Renderer createRenderer(boolean playback) locator = null; else { - CaptureDeviceInfo notifyDevice = getNotifyDevice(); + CaptureDeviceInfo notifyDevice + = getDevice(AudioSystem.NOTIFY_INDEX); if (notifyDevice == null) return null; diff --git a/src/org/jitsi/impl/neomedia/device/PulseAudioSystem.java b/src/org/jitsi/impl/neomedia/device/PulseAudioSystem.java index aacdbc7a46d78494d7553d6857e3539aad2730aa..3c76ee51f067e0bd7c6250fa48296bf7fdee6f92 100644 --- a/src/org/jitsi/impl/neomedia/device/PulseAudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/PulseAudioSystem.java @@ -170,7 +170,8 @@ public Renderer createRenderer(boolean playback) locator = null; else { - CaptureDeviceInfo notifyDevice = getNotifyDevice(); + CaptureDeviceInfo notifyDevice + = getDevice(AudioSystem.NOTIFY_INDEX); if (notifyDevice == null) return null; 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 f37ba16eeafdecbaf24f9bf6576046f64dcbce45..0b24896cec01df8c77b9a9bfce8391c42261d2ee 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 @@ -78,7 +78,7 @@ public MediaLocator getLocator() if ((locator == null) && (audioSystem != null)) { CaptureDeviceInfo playbackDevice - = audioSystem.getPlaybackDevice(); + = audioSystem.getDevice(AudioSystem.PLAYBACK_INDEX); if (playbackDevice != null) locator = playbackDevice.getLocator(); @@ -121,7 +121,7 @@ protected void playbackDevicePropertyChange(PropertyChangeEvent event) private void propertyChange(PropertyChangeEvent event) { - if (AudioSystem.PROP_PLAYBACK_DEVICE.equals(event.getPropertyName())) + if (PlaybackDevices.PROP_DEVICE.equals(event.getPropertyName())) playbackDevicePropertyChange(event); }