From 31da6d8c62cef07925fee28f0a2e65118e9d47e3 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov <lyubomir.marinov@jitsi.org> Date: Wed, 19 Dec 2012 00:23:37 +0000 Subject: [PATCH] Commits the C source code of a refining of the automatic audio device selection to pick up devices from the same hardware. --- src/native/build.xml | 1 + .../portaudio/AudioQualityImprovement.h | 6 +- src/native/portaudio/ConditionVariable.h | 7 +- src/native/portaudio/Mutex.h | 7 +- src/native/portaudio/WMME_DSound.c | 297 ++++++++++++++++++ src/native/portaudio/WMME_DSound.h | 47 +++ .../org_jitsi_impl_neomedia_portaudio_Pa.c | 36 ++- .../impl/neomedia/device/AudioSystem.java | 17 +- .../impl/neomedia/device/CaptureDevices.java | 19 +- .../neomedia/device/DeviceConfiguration.java | 14 +- .../jitsi/impl/neomedia/device/Devices.java | 88 +++--- .../impl/neomedia/device/PlaybackDevices.java | 19 +- .../impl/neomedia/device/PortAudioSystem.java | 40 ++- 13 files changed, 510 insertions(+), 88 deletions(-) create mode 100644 src/native/portaudio/WMME_DSound.c create mode 100644 src/native/portaudio/WMME_DSound.h diff --git a/src/native/build.xml b/src/native/build.xml index d753fa7f..0530b117 100644 --- a/src/native/build.xml +++ b/src/native/build.xml @@ -437,6 +437,7 @@ <linkerarg value="-lspeexdsp" location="end" if="is.running.windows" /> <linkerarg value="-lwinmm" location="end" if="is.running.windows" /> <linkerarg value="-lsetupapi" location="end" if="is.running.windows" /> + <linkerarg value="-ldsound" location="end" if="is.running.windows" /> <linkerarg value="-lm" location="end" if="is.running.windows" /> <linkerarg value="-lstdc++" location="end" if="is.running.windows" /> <linkerarg value="-lole32" location="end" if="is.running.windows" /> diff --git a/src/native/portaudio/AudioQualityImprovement.h b/src/native/portaudio/AudioQualityImprovement.h index 6aa2f83b..45255d31 100644 --- a/src/native/portaudio/AudioQualityImprovement.h +++ b/src/native/portaudio/AudioQualityImprovement.h @@ -5,8 +5,8 @@ * See terms of license at gnu.org. */ -#ifndef _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ -#define _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ +#ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ +#define _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ #include <jni.h> @@ -162,4 +162,4 @@ void AudioQualityImprovement_setSampleRate /** Unloads the <tt>AudioQualityImprovement</tt> class. */ void AudioQualityImprovement_unload(); -#endif /* #ifndef _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ */ +#endif /* #ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_AUDIOQUALITYIMPROVEMENT_H_ */ diff --git a/src/native/portaudio/ConditionVariable.h b/src/native/portaudio/ConditionVariable.h index 30a65502..de04b6db 100644 --- a/src/native/portaudio/ConditionVariable.h +++ b/src/native/portaudio/ConditionVariable.h @@ -5,13 +5,12 @@ * See terms of license at gnu.org. */ -#ifndef _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_CONDITIONVARIABLE_H_ -#define _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_CONDITIONVARIABLE_H_ +#ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_CONDITIONVARIABLE_H_ +#define _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_CONDITIONVARIABLE_H_ #include "Mutex.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN #include <windows.h> typedef HANDLE ConditionVariable; @@ -92,4 +91,4 @@ static inline int ConditionVariable_wait } #endif /* #ifdef _WIN32 */ -#endif /* _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_CONDITIONVARIABLE_H_ */ +#endif /* _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_CONDITIONVARIABLE_H_ */ diff --git a/src/native/portaudio/Mutex.h b/src/native/portaudio/Mutex.h index 93ab3ec7..96b33edc 100644 --- a/src/native/portaudio/Mutex.h +++ b/src/native/portaudio/Mutex.h @@ -5,13 +5,12 @@ * See terms of license at gnu.org. */ -#ifndef _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ -#define _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ +#ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ +#define _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ #include <stdlib.h> #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN #include <windows.h> typedef CRITICAL_SECTION Mutex; @@ -79,4 +78,4 @@ static inline int Mutex_unlock(Mutex* mutex) } #endif /* #ifdef _WIN32 */ -#endif /* #ifndef _NET_JAVA_SIP_COMMUNICATOR_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ */ +#endif /* #ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_MUTEX_H_ */ diff --git a/src/native/portaudio/WMME_DSound.c b/src/native/portaudio/WMME_DSound.c new file mode 100644 index 00000000..02967798 --- /dev/null +++ b/src/native/portaudio/WMME_DSound.c @@ -0,0 +1,297 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +#ifdef _WIN32 + +#include "WMME_DSound.h" + +#include <dsound.h> +#include <objbase.h> +#include <stdlib.h> +#include <string.h> + +/** + * The length in characters including the C string terminating NULL character of + * a GUID represented as a C string of printable characters including enclosing + * braces. + */ +#define GUID_LENGTH 39 + +/** + * Represents the information related to a DirectSound device reported by + * either the <tt>DirectSoundCaptureEnumerate</tt> function or the + * <tt>DirectSoundEnumerate</tt> function. + */ +typedef struct _WMMEDSoundDeviceInfo +{ + /** + * The textual description of the DirectSound device that this instance + * provides information about. Represents the name of the device which is + * to be displayed to the user. + */ + char *description; + /** + * The GUID which (uniquely) identifies the DirectSound device that this + * instance provides information about. + */ + char guid[GUID_LENGTH]; + /** + * The name of the module of the DirectSound driver corresponding to the + * device this instance provides information about. + */ + char *module; + + /** + * The next <tt>WMMEDSoundDeviceInfo</tt> in the linked list of + * <tt>WMMEDSoundDeviceInfo</tt>s that this instance is an element of. + */ + struct _WMMEDSoundDeviceInfo *next; +} +WMMEDSoundDeviceInfo; + +static BOOL CALLBACK WMME_DSound_dsEnumCallback( + LPGUID guid, LPCSTR description, LPCSTR module, + LPVOID context); +static WMMEDSoundDeviceInfo *WMME_DSound_findDeviceInfoByDeviceUID( + WMMEDSoundDeviceInfo *deviceInfos, + const char *deviceUID); +/** + * Frees (the memory allocated to) a specific linked list of + * <tt>WMMEDSoundDeviceInfo</tt>s. + * + * @param deviceInfos the linked list of <tt>WMMEDSoundDeviceInfo</tt>s to be + * freed + */ +static void WMME_DSound_freeDeviceInfos(WMMEDSoundDeviceInfo **deviceInfos); + +/** + * The linked list of DirectSound capture devices enumerated till now and cached + * so that it may be searched through for the purposes of, for example, + * retrieving the non-truncated name of a <tt>PaDeviceInfo</tt> detected by + * PortAudio's WMME backend. + */ +static WMMEDSoundDeviceInfo *WMME_DSound_captureDeviceInfos = NULL; +/** + * The linked list of DirectSound playback devices enumerated till now and + * cached so that it may be searched through for the purposes of, for example, + * retrieving the non-truncated name of a <tt>PaDeviceInfo</tt> detected by + * PortAudio's WMME backend. + */ +static WMMEDSoundDeviceInfo *WMME_DSound_playbackDeviceInfos = NULL; + +/** + * Retrieve a human-readable name for a specific <tt>PaDeviceInfo</tt> by + * utilizing information from DirectSound. The implementation is provided in an + * attempt to overcome a limitation of the legacy API employed by PortAudio's + * WMME backend which limits the names of the devices to 32 characters. + * + * @param deviceInfo the <tt>PaDeviceInfo</tt> to retrieve a human-readable name + * for by utilizing information from DirectSound + * @return a human-readable name of the specified <tt>deviceInfo</tt> retrieved + * by utilizing information from DirectSound or <tt>NULL</tt> if no such + * information is available for the specified <tt>deviceInfo</tt> + */ +const char * +WMME_DSound_DeviceInfo_getName(PaDeviceInfo *deviceInfo) +{ + const char *deviceUID = deviceInfo->deviceUID; + const char *name = NULL; + + if (deviceUID) + { + if (deviceInfo->maxInputChannels) + { + if (!WMME_DSound_captureDeviceInfos) + { + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if ((S_OK == hr) || (S_FALSE == hr)) + { + DirectSoundCaptureEnumerateA( + WMME_DSound_dsEnumCallback, + (LPVOID) &WMME_DSound_captureDeviceInfos); + CoUninitialize(); + } + } + if (WMME_DSound_captureDeviceInfos) + { + WMMEDSoundDeviceInfo *match + = WMME_DSound_findDeviceInfoByDeviceUID( + WMME_DSound_captureDeviceInfos, + deviceUID); + + if (match) + name = match->description; + } + } + if (!name && deviceInfo->maxOutputChannels) + { + if (!WMME_DSound_playbackDeviceInfos) + { + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if ((S_OK == hr) || (S_FALSE == hr)) + { + DirectSoundEnumerateA( + WMME_DSound_dsEnumCallback, + (LPVOID) &WMME_DSound_playbackDeviceInfos); + CoUninitialize(); + } + } + if (WMME_DSound_playbackDeviceInfos) + { + WMMEDSoundDeviceInfo *match + = WMME_DSound_findDeviceInfoByDeviceUID( + WMME_DSound_playbackDeviceInfos, + deviceUID); + + if (match) + name = match->description; + } + } + } + return name; +} + +/** + * Notifies the <tt>WMME_DSound</tt> module that PortAudio's + * <tt>PaUpdateAvailableDeviceList()<tt> function has been invoked. + * Frees/destroys the caches of the capture and playback DirectSound devices so + * that they may be rebuilt and, consequently, up-to-date upon next use. + */ +void +WMME_DSound_didUpdateAvailableDeviceList() +{ + WMME_DSound_freeDeviceInfos(&WMME_DSound_captureDeviceInfos); + WMME_DSound_freeDeviceInfos(&WMME_DSound_playbackDeviceInfos); +} + +static BOOL CALLBACK +WMME_DSound_dsEnumCallback( + LPGUID guid, LPCSTR description, LPCSTR module, + LPVOID context) +{ + if (guid && description) + { + OLECHAR olestrGUID[GUID_LENGTH]; + + if (StringFromGUID2(guid, olestrGUID, GUID_LENGTH)) + { + WMMEDSoundDeviceInfo *deviceInfo + = malloc(sizeof(WMMEDSoundDeviceInfo)); + + if (deviceInfo) + { + if (WideCharToMultiByte( + CP_ACP, + 0, + olestrGUID, -1, + deviceInfo->guid, GUID_LENGTH, + NULL, + NULL) + == GUID_LENGTH) + { + deviceInfo->description = strdup(description); + if (deviceInfo->description) + { + WMMEDSoundDeviceInfo **deviceInfos + = (WMMEDSoundDeviceInfo **) context; + + deviceInfo->module = strdup(module); + + deviceInfo->next = *deviceInfos; + *deviceInfos = deviceInfo; + } + else + free(deviceInfo); + } + else + free(deviceInfo); + } + } + } + + return TRUE; +} + +static WMMEDSoundDeviceInfo * +WMME_DSound_findDeviceInfoByDeviceUID( + WMMEDSoundDeviceInfo *deviceInfos, + const char *deviceUID) +{ + while (deviceInfos) + { + if (strstr(deviceUID, deviceInfos->guid)) + return deviceInfos; + else + { + const char *module = deviceInfos->module; + + if (module && strlen(module) && strstr(deviceUID, module)) + return deviceInfos; + } + + deviceInfos = deviceInfos->next; + } + + return NULL; +} + +/** + * Frees (the memory allocated to) a specific linked list of + * <tt>WMMEDSoundDeviceInfo</tt>s. + * + * @param deviceInfos the linked list of <tt>WMMEDSoundDeviceInfo</tt>s to be + * freed + */ +static void +WMME_DSound_freeDeviceInfos(WMMEDSoundDeviceInfo **deviceInfos) +{ + WMMEDSoundDeviceInfo *deviceInfo = *deviceInfos; + + while (deviceInfo) + { + char *description = deviceInfo->description; + char *module = deviceInfo->module; + WMMEDSoundDeviceInfo *next = deviceInfo->next; + + if (description) + free(description); + if (module) + free(module); + free(deviceInfo); + deviceInfo = next; + } + *deviceInfos = NULL; +} + +/** + * Notifies the <tt>WMME_DSound</tt> module that the JNI library it is a part of + * is loading. + */ +void +WMME_DSound_load() +{ + /* TODO Auto-generated method stub */ +} + +/** + * Notifies the <tt>WMME_DSound</tt> module that the JNI library it is a part of + * is unloading. + */ +void +WMME_DSound_unload() +{ + /* + * WMME_DSound frees/destroys the cached DirectSound device information when + * PortAudio is told to update its list of available devices. The very same + * cleanup has to be performed when the JNI library is unloading. + */ + WMME_DSound_didUpdateAvailableDeviceList(); +} + +#endif /* #ifdef _WIN32 */ diff --git a/src/native/portaudio/WMME_DSound.h b/src/native/portaudio/WMME_DSound.h new file mode 100644 index 00000000..f8f75df8 --- /dev/null +++ b/src/native/portaudio/WMME_DSound.h @@ -0,0 +1,47 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +#ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_WMME_DSOUND_H_ +#define _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_WMME_DSOUND_H_ + +#include <portaudio.h> + +/** + * Retrieve a human-readable name for a specific <tt>PaDeviceInfo</tt> by + * utilizing information from DirectSound. The implementation is provided in an + * attempt to overcome a limitation of the legacy API employed by PortAudio's + * WMME backend which limits the names of the devices to 32 characters. + * + * @param deviceInfo the <tt>PaDeviceInfo</tt> to retrieve a human-readable name + * for by utilizing information from DirectSound + * @return a human-readable name of the specified <tt>deviceInfo</tt> retrieved + * by utilizing information from DirectSound or <tt>NULL</tt> if no such + * information is available for the specified <tt>deviceInfo</tt> + */ +const char *WMME_DSound_DeviceInfo_getName(PaDeviceInfo *deviceInfo); + +/** + * Notifies the <tt>WMME_DSound</tt> module that PortAudio's + * <tt>PaUpdateAvailableDeviceList()<tt> function has been invoked. + * Frees/destroys the caches of the capture and playback DirectSound devices so + * that they may be rebuilt and, consequently, up-to-date upon next use. + */ +void WMME_DSound_didUpdateAvailableDeviceList(); + +/** + * Notifies the <tt>WMME_DSound</tt> module that the JNI library it is a part of + * is loading. + */ +void WMME_DSound_load(); + +/** + * Notifies the <tt>WMME_DSound</tt> module that the JNI library it is a part of + * is unloading. + */ +void WMME_DSound_unload(); + +#endif /* #ifndef _ORG_JITSI_IMPL_NEOMEDIA_PORTAUDIO_WMME_DSOUND_H_ */ diff --git a/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c b/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c index c2b22f54..0be49486 100644 --- a/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c +++ b/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c @@ -10,6 +10,7 @@ #include "AudioQualityImprovement.h" #include "ConditionVariable.h" #include "Mutex.h" + #include <portaudio.h> #include <stdint.h> #include <stdio.h> @@ -17,6 +18,10 @@ #include <string.h> #include <sys/time.h> +#ifdef _WIN32 + #include "WMME_DSound.h" +#endif /* #ifdef _WIN32 */ + typedef struct { AudioQualityImprovement *audioQualityImprovement; @@ -250,10 +255,24 @@ JNIEXPORT jbyteArray JNICALL Java_org_jitsi_impl_neomedia_portaudio_Pa_DeviceInfo_1getNameBytes (JNIEnv *env, jclass clazz, jlong deviceInfo) { - return - PortAudio_getStrBytes( - env, - ((PaDeviceInfo *) (intptr_t) deviceInfo)->name); + PaDeviceInfo *di = (PaDeviceInfo *) (intptr_t) deviceInfo; + const char *name; + +#ifdef _WIN32 + const PaHostApiInfo *hai = Pa_GetHostApiInfo(di->hostApi); + + if (hai && (paMME == hai->type)) + { + name = WMME_DSound_DeviceInfo_getName(di); + if (!name) + name = di->name; + } + else + name = di->name; +#else /* #ifdef _WIN32 */ + name = di->name; +#endif /* #ifdef _WIN32 */ + return PortAudio_getStrBytes(env, name); } JNIEXPORT jbyteArray JNICALL @@ -876,6 +895,9 @@ Java_org_jitsi_impl_neomedia_portaudio_Pa_UpdateAvailableDeviceList (JNIEnv *env, jclass clazz) { Pa_UpdateAvailableDeviceList(); +#ifdef _WIN32 + WMME_DSound_didUpdateAvailableDeviceList(); +#endif /* #ifdef _WIN32 */ } JNIEXPORT void JNICALL @@ -1005,6 +1027,9 @@ JNI_OnLoad(JavaVM *vm, void *reserved) { PortAudio_vm = vm; AudioQualityImprovement_load(); +#ifdef _WIN32 + WMME_DSound_load(); +#endif /* #ifdef _WIN32 */ return JNI_VERSION_1_4; } @@ -1013,6 +1038,9 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { AudioQualityImprovement_unload(); +#ifdef _WIN32 + WMME_DSound_unload(); +#endif /* #ifdef _WIN32 */ PortAudio_vm = NULL; } diff --git a/src/org/jitsi/impl/neomedia/device/AudioSystem.java b/src/org/jitsi/impl/neomedia/device/AudioSystem.java index 8a1ac516..6cb47b70 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/AudioSystem.java @@ -24,6 +24,7 @@ * integrate the native PortAudio, PulseAudio libraries. * * @author Lyubomir Marinov + * @author Vincent Lucas */ public abstract class AudioSystem extends DeviceSystem @@ -293,15 +294,17 @@ protected void postInitializeSpecificDevices(int index) List<ExtendedCaptureDeviceInfo> activeDevices = getDevices(index); // Gets the default device. Devices devices = this.devices[index]; + String locatorProtocol = getLocatorProtocol(); ExtendedCaptureDeviceInfo selectedActiveDevice - = devices.getDevice(getLocatorProtocol(), activeDevices); - // Sets the default device as selected (this function will only fire a - // property change if the device has changed from previous - // configuration). - // This "set" part is important because only the fire property event - // provides a way to get hot plugged devices working during a call. + = devices.getDevice(locatorProtocol, activeDevices); + + // Sets the default device as selected. The function will fire a + // property change only if the device has changed from a previous + // configuration. The "set" part is important because only the fired + // property event provides a way to get the hotplugged devices working + // during a call. devices.setDevice( - getLocatorProtocol(), + locatorProtocol, selectedActiveDevice, false, activeDevices); diff --git a/src/org/jitsi/impl/neomedia/device/CaptureDevices.java b/src/org/jitsi/impl/neomedia/device/CaptureDevices.java index 6e58099e..9a296ea9 100644 --- a/src/org/jitsi/impl/neomedia/device/CaptureDevices.java +++ b/src/org/jitsi/impl/neomedia/device/CaptureDevices.java @@ -32,7 +32,7 @@ public class CaptureDevices /** * The list of active (actually plugged-in) capture devices. */ - private List<ExtendedCaptureDeviceInfo> activeCaptureDevices = null; + private List<ExtendedCaptureDeviceInfo> activeCaptureDevices; /** * Initializes the capture device list management. @@ -51,9 +51,11 @@ public CaptureDevices(AudioSystem audioSystem) */ public List<ExtendedCaptureDeviceInfo> getDevices() { - List<ExtendedCaptureDeviceInfo> devices = null; + List<ExtendedCaptureDeviceInfo> devices; - if(activeCaptureDevices != null) + if(activeCaptureDevices == null) + devices = Collections.emptyList(); + else { devices = new ArrayList<ExtendedCaptureDeviceInfo>( @@ -94,7 +96,9 @@ protected String getPropDevice() */ public void setActiveDevices(List<ExtendedCaptureDeviceInfo> activeDevices) { - if(activeDevices != null) + if(activeDevices == null) + activeCaptureDevices = null; + else { boolean commit = false; @@ -114,10 +118,9 @@ public void setActiveDevices(List<ExtendedCaptureDeviceInfo> activeDevices) // Whatever. } } - } - activeCaptureDevices = (activeDevices == null) - ? null - : new ArrayList<ExtendedCaptureDeviceInfo>(activeDevices); + activeCaptureDevices + = new ArrayList<ExtendedCaptureDeviceInfo>(activeDevices); + } } } diff --git a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java index 9fc8bd83..90b34921 100644 --- a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java +++ b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java @@ -405,9 +405,10 @@ public ExtendedCaptureDeviceInfo getAudioCaptureDevice() { AudioSystem audioSystem = getAudioSystem(); - return (audioSystem == null) - ? null - : audioSystem.getDevice(AudioSystem.CAPTURE_INDEX); + return + (audioSystem == null) + ? null + : audioSystem.getDevice(AudioSystem.CAPTURE_INDEX); } /** @@ -668,9 +669,10 @@ public CaptureDeviceInfo getAudioNotifyDevice() { AudioSystem audioSystem = getAudioSystem(); - return (audioSystem == null) - ? null - : audioSystem.getDevice(AudioSystem.NOTIFY_INDEX); + return + (audioSystem == null) + ? null + : audioSystem.getDevice(AudioSystem.NOTIFY_INDEX); } /** diff --git a/src/org/jitsi/impl/neomedia/device/Devices.java b/src/org/jitsi/impl/neomedia/device/Devices.java index 56ab17b8..a8f32f83 100644 --- a/src/org/jitsi/impl/neomedia/device/Devices.java +++ b/src/org/jitsi/impl/neomedia/device/Devices.java @@ -67,9 +67,11 @@ public ExtendedCaptureDeviceInfo getDevice( // 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(ExtendedCaptureDeviceInfo activeDevice : activeDevices) + // deliberately plugged in the device). + for(int i = activeDevices.size() - 1; i >= 0; i--) { + ExtendedCaptureDeviceInfo activeDevice = activeDevices.get(i); + if(!devicePreferences.contains(activeDevice.getIdentifier())) { // Adds the device in the preference list (to the end of the @@ -204,11 +206,10 @@ private void saveDevice( List<ExtendedCaptureDeviceInfo> activeDevices, boolean isSelected) { - String selectedDeviceIdentifier = NoneAudioSystem.LOCATOR_PROTOCOL; - if(device != null) - { - selectedDeviceIdentifier = device.getIdentifier(); - } + String selectedDeviceIdentifier + = (device == null) + ? NoneAudioSystem.LOCATOR_PROTOCOL + : device.getIdentifier(); // Sorts the user preferences to put the selected device on top. addToDevicePreferences( @@ -288,24 +289,25 @@ private void addToDevicePreferences( String newDeviceIdentifier, boolean isSelected) { - int i; - int j; - synchronized(devicePreferences) { devicePreferences.remove(newDeviceIdentifier); if(isSelected) { - // Searches for the first active device. - for(i = 0; i < devicePreferences.size(); ++i) + // Search for the first active device. + for(int i = 0, devicePreferenceCount = devicePreferences.size(); + i < devicePreferenceCount; + i++) { - // Checks if this element is an active device. - for(j = 0; j < activeDevices.size(); ++j) + String devicePreference = devicePreferences.get(i); + + // Check if devicePreference is an active device. + for(ExtendedCaptureDeviceInfo activeDevice : activeDevices) { - if(devicePreferences.get(i).equals( - activeDevices.get(j).getIdentifier()) - || devicePreferences.get(i).equals( - NoneAudioSystem.LOCATOR_PROTOCOL)) + if(devicePreference.equals( + activeDevice.getIdentifier()) + || devicePreference.equals( + NoneAudioSystem.LOCATOR_PROTOCOL)) { // The first active device is found. devicePreferences.add(i, newDeviceIdentifier); @@ -315,7 +317,7 @@ private void addToDevicePreferences( } } } - // If there is no active devices or the device is not selected, then + // 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); } @@ -330,46 +332,40 @@ private void addToDevicePreferences( private void renameOldFashionedIdentifier( List<ExtendedCaptureDeviceInfo> activeDevices) { - String name; - String id; - int nameIndex; - int idIndex; // Renames the old fashioned device identifier for all active devices. - for(int i = 0; i < activeDevices.size(); ++i) + for(ExtendedCaptureDeviceInfo activeDevice : activeDevices) { - name = activeDevices.get(i).getName(); - id = activeDevices.get(i).getIdentifier(); + String name = activeDevice.getName(); + String id = activeDevice.getIdentifier(); + // We can only switch to the new fashioned notation, only if the OS - // api give us a unique identifier (different from the device name). + // API gives us a unique identifier (different from the device + // name). if(!name.equals(id)) { synchronized(devicePreferences) { do { - nameIndex = devicePreferences.indexOf( - activeDevices.get(i).getName()); - idIndex = devicePreferences.indexOf( - activeDevices.get(i).getIdentifier()); + int nameIndex = devicePreferences.indexOf(name); + // If there is one old fashioned identifier. - if(nameIndex != -1) + if(nameIndex == -1) + break; + else { + int idIndex = devicePreferences.indexOf(id); + // If the corresponding new fashioned identifier - // does not exists, then renames the old one into + // does not exist, then renames the old one into // the new one. if(idIndex == -1) - { - devicePreferences.set(nameIndex, - activeDevices.get(i).getIdentifier()); - } - // Else removes the duplicate. - else - { + devicePreferences.set(nameIndex, id); + else // Remove the duplicate. devicePreferences.remove(nameIndex); - } } } - while(nameIndex != -1); + while(true); } } } @@ -397,13 +393,13 @@ private void writeDevicePreferences(String locator, String property) synchronized(devicePreferences) { - if(devicePreferences.size() > 0) + int devicePreferenceCount = devicePreferences.size(); + + if(devicePreferenceCount != 0) { value.append(devicePreferences.get(0)); - for(int i = 1; i < devicePreferences.size(); ++i) - { + for(int i = 1; i < devicePreferenceCount; i++) value.append("\", \"").append(devicePreferences.get(i)); - } } } value.append("\"]"); diff --git a/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java b/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java index e7b64895..43d63b0c 100644 --- a/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java +++ b/src/org/jitsi/impl/neomedia/device/PlaybackDevices.java @@ -26,7 +26,7 @@ public class PlaybackDevices /** * The list of active (actually plugged-in) playback devices. */ - private List<ExtendedCaptureDeviceInfo> activePlaybackDevices = null; + private List<ExtendedCaptureDeviceInfo> activePlaybackDevices; /** * Initializes the playback device list management. @@ -45,10 +45,18 @@ public PlaybackDevices(AudioSystem audioSystem) */ public List<ExtendedCaptureDeviceInfo> getDevices() { - return (activePlaybackDevices == null) - ? null - : new ArrayList<ExtendedCaptureDeviceInfo>( + List<ExtendedCaptureDeviceInfo> devices; + + if (activePlaybackDevices == null) + devices = Collections.emptyList(); + else + { + devices + = new ArrayList<ExtendedCaptureDeviceInfo>( activePlaybackDevices); + } + + return devices; } /** @@ -68,7 +76,8 @@ protected String getPropDevice() */ public void setActiveDevices(List<ExtendedCaptureDeviceInfo> activeDevices) { - activePlaybackDevices = (activeDevices == null) + activePlaybackDevices + = (activeDevices == null) ? null : new ArrayList<ExtendedCaptureDeviceInfo>(activeDevices); } diff --git a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java index 2af313dd..c46f6164 100644 --- a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java @@ -147,6 +147,41 @@ else if (l.equals(listener)) } } + /** + * Sorts a specific list of <tt>ExtendedCaptureDeviceInfo</tt>s so that the + * ones representing USB devices appear at the beginning/top of the + * specified list. + * + * @param devices the list of <tt>ExtendedCaptureDeviceInfo</tt>s to be + * sorted so that the ones representing USB devices appear at the + * beginning/top of the list + */ + private void bubbleUpUsbDevices(List<ExtendedCaptureDeviceInfo> devices) + { + if (!devices.isEmpty()) + { + List<ExtendedCaptureDeviceInfo> nonUsbDevices + = new ArrayList<ExtendedCaptureDeviceInfo>(devices.size()); + + for (Iterator<ExtendedCaptureDeviceInfo> i = devices.iterator(); + i.hasNext();) + { + ExtendedCaptureDeviceInfo d = i.next(); + + if (!d.isSameTransportType("USB")) + { + nonUsbDevices.add(d); + i.remove(); + } + } + if (!nonUsbDevices.isEmpty()) + { + for (ExtendedCaptureDeviceInfo d : nonUsbDevices) + devices.add(d); + } + } + } + @Override public Renderer createRenderer(boolean playback) { @@ -366,6 +401,8 @@ else if (maxOutputChannels > 0) * capture or playback (in order to achieve our goal to have automatic * selection pick up devices from one and the same hardware). */ + bubbleUpUsbDevices(captureDevices); + bubbleUpUsbDevices(playbackDevices); if (!captureDevices.isEmpty() && !playbackDevices.isEmpty()) { /* @@ -382,6 +419,7 @@ else if (maxOutputChannels > 0) */ if (!captureAndPlaybackDevices.isEmpty()) { + bubbleUpUsbDevices(captureAndPlaybackDevices); for (int i = captureAndPlaybackDevices.size() - 1; i >= 0; i--) { ExtendedCaptureDeviceInfo cdi @@ -581,7 +619,7 @@ private void matchDevicesByName( = captureDevices.iterator(); Pattern pattern = Pattern.compile( - "microphone|speakers|\\p{Space}|\\(|\\)", + "array|headphones|microphone|speakers|\\p{Space}|\\(|\\)", Pattern.CASE_INSENSITIVE); LinkedList<ExtendedCaptureDeviceInfo> captureDevicesWithPlayback = new LinkedList<ExtendedCaptureDeviceInfo>(); -- GitLab