diff --git a/lib/native/windows-64/jnwincoreaudio.dll b/lib/native/windows-64/jnwincoreaudio.dll index 2b0bac5c104f9894577c899445f278dbbcbcd7ce..6ded173cda25bc7c162b9ed4e9a55f7719c94cd0 100644 Binary files a/lib/native/windows-64/jnwincoreaudio.dll and b/lib/native/windows-64/jnwincoreaudio.dll differ diff --git a/lib/native/windows/jnwincoreaudio.dll b/lib/native/windows/jnwincoreaudio.dll index 9f1768b7f65952c06ff79882bce8525e5083cea3..cbc7a20c6ee184e2d022b518df7f39569e42ad82 100644 Binary files a/lib/native/windows/jnwincoreaudio.dll and b/lib/native/windows/jnwincoreaudio.dll differ diff --git a/src/native/windows/coreaudio/jni/org_jitsi_impl_neomedia_CoreAudioDevice.c b/src/native/windows/coreaudio/jni/org_jitsi_impl_neomedia_CoreAudioDevice.c index 2afc9305c4cd1c46752ca1afcb5edf5cba0f052d..68d3704ff626bd36bea4e5c2503efb22c1554e0f 100644 --- a/src/native/windows/coreaudio/jni/org_jitsi_impl_neomedia_CoreAudioDevice.c +++ b/src/native/windows/coreaudio/jni/org_jitsi_impl_neomedia_CoreAudioDevice.c @@ -49,6 +49,21 @@ Java_org_jitsi_impl_neomedia_CoreAudioDevice_getDeviceNameBytes return deviceNameBytes; } +JNIEXPORT jbyteArray JNICALL +Java_org_jitsi_impl_neomedia_CoreAudioDevice_getDeviceModelIdentifierBytes + (JNIEnv *env, jclass clazz, jstring deviceUID) +{ + const char * deviceUIDPtr = env->GetStringUTFChars(deviceUID, 0); + char * deviceModelIdentifier = getDeviceModelIdentifier(deviceUIDPtr); + jbyteArray deviceModelIdentifierBytes + = getStrBytes(env, deviceModelIdentifier); + // Free + free(deviceModelIdentifier); + env->ReleaseStringUTFChars(deviceUID, deviceUIDPtr); + + return deviceModelIdentifierBytes; +} + JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_CoreAudioDevice_setInputDeviceVolume (JNIEnv *env, jclass clazz, jstring deviceUID, jfloat volume) diff --git a/src/native/windows/coreaudio/lib/device.c b/src/native/windows/coreaudio/lib/device.c index 5895b46f93bfb9b1b4eda6413922db00bd31fb23..ebeb979f5ce5909da03af58ccf2052a26ad33ff3 100644 --- a/src/native/windows/coreaudio/lib/device.c +++ b/src/native/windows/coreaudio/lib/device.c @@ -16,6 +16,7 @@ #include <commctrl.h> // Must be defined after mmdeviceapi.h #include <endpointvolume.h> // Must be defined after mmdeviceapi.h + /** * Functions to list, access and modifies audio devices via coreaudio. * @@ -31,6 +32,16 @@ IAudioEndpointVolume * getEndpointVolume( void freeEndpointVolume( IAudioEndpointVolume * endpointVolume); +char* getDeviceDescription( + const char * deviceUID); + +char* getDeviceInterfaceName( + const char * deviceUID); + +char* getDeviceProperty( + const char * deviceUID, + PROPERTYKEY propertyKey); + int setDeviceVolume( const char * deviceUID, float volume); @@ -38,8 +49,15 @@ int setDeviceVolume( float getDeviceVolume( const char * deviceUID); +// Definitions find in "functiondiscoverykeys_devpkey.h" but not found by +// MINGW64 TDM-gcc compiler. +DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING +DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING + +DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32 + /** * Initializes the COM component. This function must be called first in order to * able each following function to work correctly. Once finished, the caller of @@ -224,7 +242,8 @@ void freeEndpointVolume( /** * Returns the device name for the given device. Or NULL, if not available. The - * returned string must be freed by the caller. + * returned string must be freed by the caller. The device name is composed of + * the device description and of the device interface name. * * @param device The device to get the name from. * @@ -234,10 +253,162 @@ void freeEndpointVolume( char* getDeviceName( const char * deviceUID) { - size_t deviceNameLength; - char * deviceName = NULL; - PROPVARIANT propertyDeviceName; - PropVariantInit(&propertyDeviceName); + return getDeviceProperty(deviceUID, PKEY_Device_FriendlyName); +} + +/** + * Returns the device model identifier for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. + * + * @param device The device to get the name from. + * + * @return The device model identifier for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. + */ +char* getDeviceModelIdentifier( + const char * deviceUID) +{ + int deviceModelIdentifierLength; + char * deviceModelIdentifier = NULL; + char * deviceDescription; + char * deviceInterface; + char * genericDeviceInterface; + + if((deviceDescription = getDeviceDescription(deviceUID)) == NULL) + { + fprintf(stderr, + "getDeviceModelIdentifier (coreaudio/device.c): \ + \n\tgetDeviceDescription\n"); + fflush(stderr); + return NULL; + } + if((deviceInterface = getDeviceInterfaceName(deviceUID)) == NULL) + { + fprintf(stderr, + "getDeviceModelIdentifier (coreaudio/device.c): \ + \n\tgetDeviceInterfaceName\n"); + fflush(stderr); + return NULL; + } + + // A USB device (without a serial ID) puts into a USB port will add the + // port number (if greater than 1) with the following prefix: "X- " + // (with X the port number). + genericDeviceInterface = deviceInterface; + // First skip the number at the beginning of the prefix. + while(genericDeviceInterface[0] != '\0' + && genericDeviceInterface[0] >= '0' + && genericDeviceInterface[0] <= '9') + { + ++genericDeviceInterface; + } + // Then skips the "-". + if(genericDeviceInterface[0] != '\0' + && genericDeviceInterface[0] == '-') + { + ++genericDeviceInterface; + } + // Finally skips the " ". + if(genericDeviceInterface[0] != '\0' + && genericDeviceInterface[0] == ' ') + { + ++genericDeviceInterface; + } + // If we have reached the end of the string, then the string does not + // contain the prefix. + if(genericDeviceInterface[0] == '\0') + { + genericDeviceInterface = deviceInterface; + } + + // Finally, concatenate the device description and its generic device + // interface. + deviceModelIdentifierLength + = strlen(deviceDescription) + 2 + strlen(genericDeviceInterface) + 2; + if((deviceModelIdentifier + = (char*) malloc(deviceModelIdentifierLength * sizeof(char))) + == NULL) + { + fprintf(stderr, + "getDeviceModelIdentifier (coreaudio/device.c): \ + \n\tmalloc\n"); + fflush(stderr); + return NULL; + } + if(snprintf( + deviceModelIdentifier, + deviceModelIdentifierLength, + "%s (%s)", + deviceDescription, + genericDeviceInterface) != (deviceModelIdentifierLength - 1)) + { + free(deviceModelIdentifier); + fprintf(stderr, + "getDeviceModelIdentifier (coreaudio/device.c): \ + \n\tsnprintf\n"); + fflush(stderr); + return NULL; + } + + // Frees memory. + free(deviceDescription); + free(deviceInterface); + + return deviceModelIdentifier; +} + +/** + * Returns the device description for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. The device + * description is a generic name such as "microphone", "speaker", etc. + * + * @param device The device to get the name from. + * + * @return The device description for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. + */ +char* getDeviceDescription( + const char * deviceUID) +{ + return getDeviceProperty(deviceUID, PKEY_Device_DeviceDesc); +} + +/** + * Returns the device interface name for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. The device + * interface name describes the way the device is connected, such as "USB audio + * adapter". + * + * @param device The device to get the name from. + * + * @return The device interface name for the given device. Or NULL, if not + * available. The returned string must be freed by the caller. + */ +char* getDeviceInterfaceName( + const char * deviceUID) +{ + return getDeviceProperty(deviceUID, PKEY_DeviceInterface_FriendlyName); +} + +/** + * Returns the device property for the given device. Or NULL, if not available. + * The returned string must be freed by the caller. + * + * @param device The device to get the name from. + * @param propertyKey The requested property (i.e. PKEY_Device_FriendlyName for + * the device name). + * + * @return The device property for the given device. Or NULL, if not available. + * The returned string must be freed by the caller. + */ +char* getDeviceProperty( + const char * deviceUID, + PROPERTYKEY propertyKey) +{ + size_t devicePropertyLength; + char * deviceProperty = NULL; + PROPVARIANT propertyDevice; + PropVariantInit(&propertyDevice); IPropertyStore * properties = NULL; // Gets the audio device. @@ -245,7 +416,7 @@ char* getDeviceName( if(device == NULL) { fprintf(stderr, - "getDeviceName (coreaudio/device.c): \ + "getDeviceProperty (coreaudio/device.c): \ \n\tgetDevice\n"); fflush(stderr); return NULL; @@ -255,35 +426,39 @@ char* getDeviceName( if(device->OpenPropertyStore(STGM_READ, &properties) != S_OK) { fprintf(stderr, - "getDeviceName (coreaudio/device.c): \ + "getDeviceProperty (coreaudio/device.c): \ \n\tIMMDevice.OpenPropertyStore\n"); fflush(stderr); return NULL; } - if(properties->GetValue(PKEY_Device_FriendlyName, &propertyDeviceName) + if(properties->GetValue(propertyKey, &propertyDevice) != S_OK) { fprintf(stderr, - "getDeviceName (coreaudio/device.c): \ + "getDeviceProperty (coreaudio/device.c): \ \n\tIPropertyStore.GetValue\n"); fflush(stderr); return NULL; } - deviceNameLength = wcslen(propertyDeviceName.pwszVal); - if((deviceName = (char *) malloc((deviceNameLength + 1) * sizeof(char))) + devicePropertyLength = wcslen(propertyDevice.pwszVal); + if((deviceProperty + = (char *) malloc((devicePropertyLength + 1) * sizeof(char))) == NULL) { fprintf(stderr, - "getDeviceName (coreaudio/device.c): \ + "getDeviceProperty (coreaudio/device.c): \ \n\tmalloc\n"); fflush(stderr); return NULL; } - if(wcstombs(deviceName, propertyDeviceName.pwszVal, deviceNameLength + 1) - != deviceNameLength) + if(wcstombs( + deviceProperty, + propertyDevice.pwszVal, + devicePropertyLength + 1) + != devicePropertyLength) { fprintf(stderr, - "getDeviceName (coreaudio/device.c): \ + "getDeviceProperty (coreaudio/device.c): \ \n\twcstombs\n"); fflush(stderr); return NULL; @@ -291,9 +466,9 @@ char* getDeviceName( // Frees. freeDevice(device); - PropVariantClear(&propertyDeviceName); + PropVariantClear(&propertyDevice); - return deviceName; + return deviceProperty; } /** diff --git a/src/native/windows/coreaudio/lib/device.h b/src/native/windows/coreaudio/lib/device.h index abc05f2eaa17e97304d094af81a41cab9c689787..0fc0417fd471e89f72aa2cd4cbf1335ce1fc8d19 100644 --- a/src/native/windows/coreaudio/lib/device.h +++ b/src/native/windows/coreaudio/lib/device.h @@ -28,6 +28,9 @@ void freeDevice( char* getDeviceName( const char * deviceUID); +char* getDeviceModelIdentifier( + const char * deviceUID); + int setInputDeviceVolume( const char * deviceUID, float volume); diff --git a/src/org/jitsi/impl/neomedia/device/Devices.java b/src/org/jitsi/impl/neomedia/device/Devices.java index 5bad919ced9c63afbc39ac9fbec6714e83c79556..c7e9ca320b8922bebc0e1d85f602a65eb5ee0213 100644 --- a/src/org/jitsi/impl/neomedia/device/Devices.java +++ b/src/org/jitsi/impl/neomedia/device/Devices.java @@ -73,7 +73,7 @@ public ExtendedCaptureDeviceInfo getDevice( ExtendedCaptureDeviceInfo activeDevice = activeDevices.get(i); if(!devicePreferences.contains( - activeDevice.getModelIdentifier())) + activeDevice.getIdentifier())) { // Adds the device in the preference list (to the end of the // list, but the save device will push it to the top of @@ -98,7 +98,7 @@ public ExtendedCaptureDeviceInfo getDevice( // If we have found the "preferred" device among active // device. if(devicePreference.equals( - activeDevice.getModelIdentifier())) + activeDevice.getIdentifier())) { return activeDevice; } @@ -210,7 +210,7 @@ private void saveDevice( String selectedDeviceIdentifier = (device == null) ? NoneAudioSystem.LOCATOR_PROTOCOL - : device.getModelIdentifier(); + : device.getIdentifier(); // Sorts the user preferences to put the selected device on top. addToDevicePreferences( @@ -306,7 +306,7 @@ private void addToDevicePreferences( for(ExtendedCaptureDeviceInfo activeDevice : activeDevices) { if(devicePreference.equals( - activeDevice.getModelIdentifier()) + activeDevice.getIdentifier()) || devicePreference.equals( NoneAudioSystem.LOCATOR_PROTOCOL)) { @@ -337,7 +337,7 @@ private void renameOldFashionedIdentifier( for(ExtendedCaptureDeviceInfo activeDevice : activeDevices) { String name = activeDevice.getName(); - String id = activeDevice.getModelIdentifier(); + String id = activeDevice.getIdentifier(); // We can only switch to the new fashioned notation, only if the OS // API gives us a unique identifier (different from the device diff --git a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java index 43bb6a921d1c971735744b4a8f91ca0570bf8fc7..104bf1b118df3e0274eb6eabf6f37a0f1b584882 100644 --- a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java +++ b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java @@ -264,6 +264,7 @@ protected void doInitialize() = new LinkedList<ExtendedCaptureDeviceInfo>(); final boolean loggerIsDebugEnabled = logger.isDebugEnabled(); + CoreAudioDevice.initDevices(); for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) { long deviceInfo = Pa.GetDeviceInfo(deviceIndex); @@ -397,6 +398,7 @@ else if (maxOutputChannels > 0) } } } + CoreAudioDevice.freeDevices(); /* * Make sure that devices which support both capture and playback are