From 924f49327513cad83a7e05e1ce32d0b2d0659bf4 Mon Sep 17 00:00:00 2001
From: Vincent Lucas <chenzo@jitsi.org>
Date: Thu, 6 Dec 2012 15:07:05 +0000
Subject: [PATCH] Corrects UnsatisfiedLinkError when trying to load nonexistent
 Windows or MacOSX CoreAudio library. Initializes microphone volume based on
 system value for MacOSX and Windows Vista/7/8.

---
 .../AbstractHardwareVolumeControl.java        | 49 ++++++++++++++---
 .../impl/neomedia/AbstractVolumeControl.java  | 54 +++++++++++--------
 .../jitsi/impl/neomedia/MediaServiceImpl.java | 43 +++++++++------
 .../maccoreaudio/CoreAudioVolumeControl.java  | 22 ++++++++
 .../wincoreaudio/CoreAudioVolumeControl.java  | 35 +++++++++++-
 5 files changed, 157 insertions(+), 46 deletions(-)

diff --git a/src/org/jitsi/impl/neomedia/AbstractHardwareVolumeControl.java b/src/org/jitsi/impl/neomedia/AbstractHardwareVolumeControl.java
index 8e3216bd..c1e5d1c0 100644
--- a/src/org/jitsi/impl/neomedia/AbstractHardwareVolumeControl.java
+++ b/src/org/jitsi/impl/neomedia/AbstractHardwareVolumeControl.java
@@ -51,7 +51,15 @@ public AbstractHardwareVolumeControl(
     {
         super(volumeLevelConfigurationPropertyName);
         this.mediaServiceImpl = mediaServiceImpl;
-        updateHardwareVolume();
+
+        // Gets the device volume (an error use the default volume).
+        this.volumeLevel = getDefaultVolumeLevel();
+        String deviceUID = getCaptureDeviceUID();
+        float volume = this.getInputDeviceVolume(deviceUID);
+        if(volume != -1)
+        {
+            this.volumeLevel = volume;
+        }
     }
 
     /**
@@ -85,12 +93,7 @@ protected static float getGainReferenceLevel()
     protected void updateHardwareVolume()
     {
         // Gets the selected input dvice UID.
-        AudioSystem audioSystem
-            = mediaServiceImpl.getDeviceConfiguration().getAudioSystem();
-        ExtendedCaptureDeviceInfo captureDevice = (audioSystem == null)
-            ? null
-            : audioSystem.getDevice(AudioSystem.CAPTURE_INDEX);
-        String deviceUID = captureDevice.getUID();
+        String deviceUID = getCaptureDeviceUID();
 
         // Computes the hardware volume.
         float jitsiHarwareVolumeFactor = MAX_VOLUME_LEVEL / MAX_HARDWARE_POWER;
@@ -109,6 +112,28 @@ protected void updateHardwareVolume()
         }
     }
 
+    /**
+     * Returns the selected input device UID.
+     *
+     * @return The selected input device UID. Or null if not found.
+     */
+    protected String getCaptureDeviceUID()
+    {
+        String deviceUID = null;
+
+        AudioSystem audioSystem
+            = mediaServiceImpl.getDeviceConfiguration().getAudioSystem();
+        ExtendedCaptureDeviceInfo captureDevice = (audioSystem == null)
+            ? null
+            : audioSystem.getDevice(AudioSystem.CAPTURE_INDEX);
+        if(captureDevice != null)
+        {
+            deviceUID = captureDevice.getUID();
+        }
+
+        return deviceUID;
+    }
+
     /**
      * Changes the device volume via the system API.
      *
@@ -118,4 +143,14 @@ protected void updateHardwareVolume()
      * @return 0 if everything works fine.
      */
     protected abstract int setInputDeviceVolume(String deviceUID, float volume);
+
+    /**
+     * Returns the device volume via the system API.
+     *
+     * @param deviceUID The device ID.
+     *
+     * @Return A scalar value between 0 and 1 if everything works fine. -1 if an
+     * error occured.
+     */
+    protected abstract float getInputDeviceVolume(String deviceUID);
 }
diff --git a/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java b/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
index bc1ff397..1fe139bd 100644
--- a/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
+++ b/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
@@ -127,29 +127,7 @@ public AbstractVolumeControl(
             = volumeLevelConfigurationPropertyName;
 
         // Read the initial volume level from the ConfigurationService.
-        try
-        {
-            ConfigurationService cfg = LibJitsi.getConfigurationService();
-
-            if (cfg != null)
-            {
-                String volumeLevelString
-                    = cfg.getString(this.volumeLevelConfigurationPropertyName);
-
-                if (volumeLevelString != null)
-                {
-                    this.volumeLevel = Float.parseFloat(volumeLevelString);
-                    if(logger.isDebugEnabled())
-                    {
-                        logger.debug("Restored volume: " + volumeLevelString);
-                    }
-                }
-            }
-        }
-        catch (Throwable t)
-        {
-            logger.warn("Error restoring volume", t);
-        }
+        this.loadVolume();
     }
 
     /**
@@ -589,4 +567,34 @@ protected void updateHardwareVolume()
     {
         // Nothing to do. This AbstractVolumeControl only modifies the gain.
     }
+
+    /**
+     * Reads the initial volume level from the system.
+     */
+    protected void loadVolume()
+    {
+        try
+        {
+            ConfigurationService cfg = LibJitsi.getConfigurationService();
+
+            if (cfg != null)
+            {
+                String volumeLevelString
+                    = cfg.getString(this.volumeLevelConfigurationPropertyName);
+
+                if (volumeLevelString != null)
+                {
+                    this.volumeLevel = Float.parseFloat(volumeLevelString);
+                    if(logger.isDebugEnabled())
+                    {
+                        logger.debug("Restored volume: " + volumeLevelString);
+                    }
+                }
+            }
+        }
+        catch (Throwable t)
+        {
+            logger.warn("Error restoring volume", t);
+        }
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
index d84bfd21..641ab4f4 100644
--- a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
+++ b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
@@ -748,25 +748,38 @@ public VolumeControl getInputVolumeControl()
     {
         if (inputVolumeControl == null)
         {
-            if(OSUtils.IS_MAC)
-            {
-                inputVolumeControl
-                    = new
+            boolean initialized = false;
+            try{
+                if(OSUtils.IS_MAC)
+                {
+                    inputVolumeControl = new
                     org.jitsi.impl.neomedia.maccoreaudio.CoreAudioVolumeControl(
-                            this,
-                            VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME);
+                                this,
+                                VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME
+                                );
+                    initialized = true;
+                }
+                else if(OSUtils.IS_WINDOWS_VISTA
+                        || OSUtils.IS_WINDOWS_7
+                        || OSUtils.IS_WINDOWS_8)
+                {
+                    inputVolumeControl = new
+                    org.jitsi.impl.neomedia.wincoreaudio.CoreAudioVolumeControl(
+                                this,
+                                VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME
+                                );
+                    initialized = true;
+                }
             }
-            else if(OSUtils.IS_WINDOWS_VISTA
-                    || OSUtils.IS_WINDOWS_7
-                    || OSUtils.IS_WINDOWS_8)
+            catch(UnsatisfiedLinkError ule)
             {
-                inputVolumeControl
-                    = new
-                    org.jitsi.impl.neomedia.wincoreaudio.CoreAudioVolumeControl(
-                            this,
-                            VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME);
+                //initialized = false;
+                logger.info("Can not load system volume control: "
+                        + ule.getMessage()
+                        + ". Loading default software volume control.");
             }
-            else
+
+            if(!initialized)
             {
                 inputVolumeControl
                     = new AbstractVolumeControl(
diff --git a/src/org/jitsi/impl/neomedia/maccoreaudio/CoreAudioVolumeControl.java b/src/org/jitsi/impl/neomedia/maccoreaudio/CoreAudioVolumeControl.java
index 2df72ad7..217906ba 100644
--- a/src/org/jitsi/impl/neomedia/maccoreaudio/CoreAudioVolumeControl.java
+++ b/src/org/jitsi/impl/neomedia/maccoreaudio/CoreAudioVolumeControl.java
@@ -61,4 +61,26 @@ protected int setInputDeviceVolume(String deviceUID, float volume)
         }
         return 0;
     }
+
+    /**
+     * Returns the device volume via the system API.
+     *
+     * @param deviceUID The device ID.
+     *
+     * @Return A scalar value between 0 and 1 if everything works fine. -1 if an
+     * error occured.
+     */
+    protected float getInputDeviceVolume(String deviceUID)
+    {
+        float volume;
+
+        if((volume = CoreAudioDevice.getInputDeviceVolume(deviceUID))
+                != 0)
+        {
+            logger.debug(
+                    "Could not get MacOsX CoreAudio input device level");
+        }
+
+        return volume;
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/wincoreaudio/CoreAudioVolumeControl.java b/src/org/jitsi/impl/neomedia/wincoreaudio/CoreAudioVolumeControl.java
index a14c77f4..188540b4 100644
--- a/src/org/jitsi/impl/neomedia/wincoreaudio/CoreAudioVolumeControl.java
+++ b/src/org/jitsi/impl/neomedia/wincoreaudio/CoreAudioVolumeControl.java
@@ -59,7 +59,7 @@ protected int setInputDeviceVolume(String deviceUID, float volume)
                     "Could not initialize Windows CoreAudio input devices");
             return -1;
         }
-        // Changes the input volume of the capture device.
+        // Change the input volume of the capture device.
         if(CoreAudioDevice.setInputDeviceVolume(deviceUID, volume) != 0)
         {
             CoreAudioDevice.freeDevices();
@@ -71,4 +71,37 @@ protected int setInputDeviceVolume(String deviceUID, float volume)
 
         return 0;
     }
+
+    /**
+     * Returns the device volume via the system API.
+     *
+     * @param deviceUID The device ID.
+     *
+     * @Return A scalar value between 0 and 1 if everything works fine. -1 if an
+     * error occured.
+     */
+    protected float getInputDeviceVolume(String deviceUID)
+    {
+        float volume;
+
+        if(CoreAudioDevice.initDevices() == -1)
+        {
+            CoreAudioDevice.freeDevices();
+            logger.debug(
+                    "Could not initialize Windows CoreAudio input devices");
+            return -1;
+        }
+        // Get the input volume of the capture device.
+        if((volume = CoreAudioDevice.getInputDeviceVolume(deviceUID))
+                == -1)
+        {
+            CoreAudioDevice.freeDevices();
+            logger.debug(
+                    "Could not get Windows CoreAudio input device level");
+            return -1;
+        }
+        CoreAudioDevice.freeDevices();
+
+        return volume;
+    }
 }
-- 
GitLab