-
Vincent Lucas authored
Corrects the property name org.jitsi.impl.neomadia.device.disableUsbDeviceAutoSelection to org.jitsi.impl.neomedia.device.disableUsbDeviceAutoSelection.
Vincent Lucas authoredCorrects the property name org.jitsi.impl.neomadia.device.disableUsbDeviceAutoSelection to org.jitsi.impl.neomedia.device.disableUsbDeviceAutoSelection.
Devices.java 15.33 KiB
/*
* 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 org.jitsi.service.configuration.*;
import org.jitsi.service.libjitsi.*;
/**
* Manages the list of active (currently plugged-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 name of the <tt>ConfigurationService</tt> <tt>boolean</tt> property
* which indicates whether the automatic selection of USB devices must be
* disabled. The default value is <tt>false</tt>.
*/
private static final String PROP_DISABLE_USB_DEVICE_AUTO_SELECTION
= "org.jitsi.impl.neomedia.device.disableUsbDeviceAutoSelection";
/**
* The audio system managing this device list.
*/
private final AudioSystem audioSystem;
/**
* The selected active device.
*/
private ExtendedCaptureDeviceInfo device = null;
/**
* The list of device ID/names saved by the configuration service and
* previously saved given user preference order.
*/
private final List<String> devicePreferences = new ArrayList<String>();
/**
* Initializes the device list management.
*
* @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.
* @param activeDevices The list of the active devices.
*
* @return The selected active device.
*/
public ExtendedCaptureDeviceInfo getDevice(
String locator,
List<ExtendedCaptureDeviceInfo> activeDevices)
{
if (activeDevices != null)
{
String property = getPropDevice();
loadDevicePreferences(locator, property);
renameOldFashionedIdentifier(activeDevices);
// 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 (only for USB devices since the user has
// deliberately plugged in the device).
for(int i = activeDevices.size() - 1; i >= 0; i--)
{
ExtendedCaptureDeviceInfo activeDevice = activeDevices.get(i);
if(!devicePreferences.contains(
activeDevice.getModelIdentifier()))
{
// By default, select automatically the USB devices.
boolean isSelected
= activeDevice.isSameTransportType("USB");
ConfigurationService cfg
= LibJitsi.getConfigurationService();
// Desactivate the USB device automatic selection if the
// property is set to true.
if(cfg != null
&& cfg.getBoolean(
PROP_DISABLE_USB_DEVICE_AUTO_SELECTION,
false))
{
isSelected = false;
}
// 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).
saveDevice(
locator,
property,
activeDevice,
activeDevices,
isSelected);
}
}
// Search if an active device match one of the previously configured
// in the preferences.
synchronized(devicePreferences)
{
for(String devicePreference : devicePreferences)
{
for(ExtendedCaptureDeviceInfo activeDevice : activeDevices)
{
// If we have found the "preferred" device among active
// device.
if(devicePreference.equals(
activeDevice.getModelIdentifier()))
{
return activeDevice;
}
// If the "none" device is the "preferred" device among
// "active" device.
else if(devicePreference.equals(
NoneAudioSystem.LOCATOR_PROTOCOL))
{
return null;
}
}
}
}
}
// Else if nothing was found, then returns null.
return null;
}
/**
* Returns the list of the active devices.
*
* @return The list of the active devices.
*/
public abstract List<ExtendedCaptureDeviceInfo> getDevices();
/**
* 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 deviceIdentifiersString = cfg.getString(new_property);
synchronized(devicePreferences)
{
if (deviceIdentifiersString != null)
{
devicePreferences.clear();
// We must parse the string in order to load the device
// list.
String[] deviceIdentifiers = deviceIdentifiersString
.substring(2, deviceIdentifiersString.length() - 2)
.split("\", \"");
for(int i = 0; i < deviceIdentifiers.length; ++i)
{
devicePreferences.add(deviceIdentifiers[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;
deviceIdentifiersString = cfg.getString(old_property);
if (deviceIdentifiersString != null
&& !NoneAudioSystem.LOCATOR_PROTOCOL
.equalsIgnoreCase(deviceIdentifiersString))
{
devicePreferences.clear();
devicePreferences.add(deviceIdentifiersString);
}
}
}
}
}
/**
* 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 selectedDevice The device selected by the user.
* @param activeDevices The list of the active devices.
* @param isSelected True if the device is the selected one.
*/
private void saveDevice(
String locator,
String property,
ExtendedCaptureDeviceInfo device,
List<ExtendedCaptureDeviceInfo> activeDevices,
boolean isSelected)
{
String selectedDeviceIdentifier
= (device == null)
? NoneAudioSystem.LOCATOR_PROTOCOL
: device.getModelIdentifier();
// Sorts the user preferences to put the selected device on top.
addToDevicePreferences(
locator,
activeDevices,
selectedDeviceIdentifier,
isSelected);
// Saves the user preferences.
writeDevicePreferences(locator, property);
}
/**
* 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.
* @param activeDevices The list of the active devices.
*/
public void setDevice(
String locator,
ExtendedCaptureDeviceInfo device,
boolean save,
List<ExtendedCaptureDeviceInfo> activeDevices)
{
// Checks if there is a change.
if ((device == null) || !device.equals(this.device))
{
ExtendedCaptureDeviceInfo oldValue = this.device;
// Saves the new selected device in top of the user preferences.
if (save)
{
saveDevice(
locator,
getPropDevice(),
device,
activeDevices,
true);
}
this.device = device;
audioSystem.propertyChange(getPropDevice(), oldValue, this.device);
}
}
/**
* Sets the list of the active devices.
*
* @param activeDevices The list of the active devices.
*/
public abstract void setActiveDevices(
List<ExtendedCaptureDeviceInfo> activeDevices);
/**
* Returns the property of the capture devices.
*
* @return The property of the capture devices.
*/
protected abstract String getPropDevice();
/**
* Adds a new device in the preferences (at the first active position if the
* isSelected argument is true).
*
* @param locator The string representation of the locator.
* @param activeDevices The list of the active devices.
* @param newsDeviceIdentifier The identifier of the device to add int first
* active position of the preferences.
* @param isSelected True if the device is the selected one.
*/
private void addToDevicePreferences(
String locator,
List<ExtendedCaptureDeviceInfo> activeDevices,
String newDeviceIdentifier,
boolean isSelected)
{
synchronized(devicePreferences)
{
devicePreferences.remove(newDeviceIdentifier);
if(isSelected)
{
// Search for the first active device.
for(int i = 0, devicePreferenceCount = devicePreferences.size();
i < devicePreferenceCount;
i++)
{
String devicePreference = devicePreferences.get(i);
// Check if devicePreference is an active device.
for(ExtendedCaptureDeviceInfo activeDevice : activeDevices)
{
if(devicePreference.equals(
activeDevice.getModelIdentifier())
|| devicePreference.equals(
NoneAudioSystem.LOCATOR_PROTOCOL))
{
// The first active device is found.
devicePreferences.add(i, newDeviceIdentifier);
// The device is added, stop the loops and quit.
return;
}
}
}
}
// If there is no active device or the device is not selected, then
// set the new device to the end of the device preference list.
devicePreferences.add(newDeviceIdentifier);
}
}
/**
* Renames the old fashioned identifier (name only), into new fashioned one
* (UID, or name + transport type).
*
* @param activeDevices The list of the active devices.
*/
private void renameOldFashionedIdentifier(
List<ExtendedCaptureDeviceInfo> activeDevices)
{
// Renames the old fashioned device identifier for all active devices.
for(ExtendedCaptureDeviceInfo activeDevice : activeDevices)
{
String name = activeDevice.getName();
String id = activeDevice.getModelIdentifier();
// We can only switch to the new fashioned notation, only if the OS
// API gives us a unique identifier (different from the device
// name).
if(!name.equals(id))
{
synchronized(devicePreferences)
{
do
{
int nameIndex = devicePreferences.indexOf(name);
// If there is one old fashioned identifier.
if(nameIndex == -1)
break;
else
{
int idIndex = devicePreferences.indexOf(id);
// If the corresponding new fashioned identifier
// does not exist, then renames the old one into
// the new one.
if(idIndex == -1)
devicePreferences.set(nameIndex, id);
else // Remove the duplicate.
devicePreferences.remove(nameIndex);
}
}
while(true);
}
}
}
}
/**
* Saves the device preferences and write it to the configuration file.
*
* @param locator The string representation of the locator.
* @param property the name of the <tt>ConfigurationService</tt> property
*/
private void writeDevicePreferences(String locator, String property)
{
ConfigurationService cfg = LibJitsi.getConfigurationService();
if (cfg != null)
{
property
= DeviceConfiguration.PROP_AUDIO_SYSTEM
+ "." + locator
+ "." + property
+ "_list";
StringBuilder value = new StringBuilder("[\"");
synchronized(devicePreferences)
{
int devicePreferenceCount = devicePreferences.size();
if(devicePreferenceCount != 0)
{
value.append(devicePreferences.get(0));
for(int i = 1; i < devicePreferenceCount; i++)
value.append("\", \"").append(devicePreferences.get(i));
}
}
value.append("\"]");
cfg.setProperty(property, value.toString());
}
}
}