diff --git a/lib/native/mac/libjncoreaudio.jnilib b/lib/native/mac/libjncoreaudio.jnilib
new file mode 100755
index 0000000000000000000000000000000000000000..07697e3d57ede90963f041cf48ffebe2fb7e4ff0
Binary files /dev/null and b/lib/native/mac/libjncoreaudio.jnilib differ
diff --git a/src/native/build.xml b/src/native/build.xml
index 5071e585a5fcdd516f8b071ffa1cabda813424f0..b257e950c5386fce0496efa18eb719aceced74f8 100644
--- a/src/native/build.xml
+++ b/src/native/build.xml
@@ -668,6 +668,38 @@
     </cc>
   </target>
 
+  <!-- compile jncoreaudio library for Mac OS X (32-bit/64-bit) -->
+  <target name="coreaudio" description="Build jncoreaudio shared library for Mac OS X" if="is.running.macos"
+    depends="init-native">
+    <cc outtype="shared" name="gcc" outfile="${native_install_dir}/jncoreaudio" objdir="${obj}">
+      <compilerarg value="-Wall" />
+      <compilerarg value="-O2" />
+      <compilerarg value="-arch" />
+      <compilerarg value="x86_64" />
+      <compilerarg value="-arch" />
+      <compilerarg value="i386" />
+      <compilerarg value="-I/System/Library/Frameworks/JavaVM.framework/Headers"
+      />
+
+      <linkerarg value="-o" location="end" />
+      <linkerarg value="libjncoreaudio.jnilib" location="end" />
+      <linkerarg value="-arch" />
+      <linkerarg value="x86_64" />
+      <linkerarg value="-arch" />
+      <linkerarg value="i386" />
+      <linkerarg value="-framework" />
+      <linkerarg value="Foundation" />
+      <linkerarg value="-framework" />
+      <linkerarg value="Coreaudio" />
+
+      <fileset dir="${src}/native/macosx/coreaudio/lib" includes="*.c"/>
+      <fileset dir="${src}/native/macosx/coreaudio/jni" includes="*.c"/>
+    </cc>
+
+    <delete dir="${obj}" failonerror="false" />
+    <delete file="${native_install_dir}/history.xml" failonerror="false" />
+  </target>
+
   <!-- compile jnquicktime library for Mac OS X (32-bit/64-bit/ppc) -->
   <target name="quicktime" description="Build jnquicktime shared library for Mac OS X" if="is.running.macos"
     depends="init-native">
@@ -767,6 +799,7 @@
     <echo message="'ant directshow (Windows only)' to compile jdirectshow shared library" />
     <echo message="'ant aegeturleventhandler (Mac OS X only)' to compile AEGetURLEventHandler shared library" />
     <echo message="'ant sparkle (Mac OS X only)' to compile sparkle shared library" />
+    <echo message="'ant coreaudio (Mac OS X only)' to compile jcoreaudio shared library" />
     <echo message="'ant quicktime (Mac OS X only)' to compile jquicktime shared library" />
     <echo message="" />
     <echo message="Options:" />
diff --git a/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.c b/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.c
new file mode 100644
index 0000000000000000000000000000000000000000..d66c9aa4e2a39571d32c2dfaf358e691cb97c348
--- /dev/null
+++ b/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.c
@@ -0,0 +1,111 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+#include "org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.h"
+
+#include "../lib/device.h"
+
+/**
+ * JNI code for CoreAudioDevice.
+ *
+ * @author Vicnent Lucas
+ */
+
+// Private functions
+
+static jbyteArray getStrBytes(JNIEnv *env, const char *str);
+
+// Implementation
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getDeviceNameBytes
+  (JNIEnv *env, jclass clazz, jstring deviceUID)
+{
+    const char * deviceUIDPtr = (*env)->GetStringUTFChars(env, deviceUID, 0);
+    char * deviceName = getDeviceName(deviceUIDPtr);
+    jbyteArray deviceNameBytes = getStrBytes(env, deviceName);
+    // Free
+    free(deviceName);
+    (*env)->ReleaseStringUTFChars(env, deviceUID, deviceUIDPtr);
+
+    return deviceNameBytes;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_setInputDeviceVolume
+  (JNIEnv *env, jclass clazz, jstring deviceUID, jfloat volume)
+{
+    const char * deviceUIDPtr = (*env)->GetStringUTFChars(env, deviceUID, 0);
+    jint err = setInputDeviceVolume(deviceUIDPtr, volume);
+    // Free
+    (*env)->ReleaseStringUTFChars(env, deviceUID, deviceUIDPtr);
+
+    return err;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_setOutputDeviceVolume
+  (JNIEnv *env, jclass clazz, jstring deviceUID, jfloat volume)
+{
+    const char * deviceUIDPtr = (*env)->GetStringUTFChars(env, deviceUID, 0);
+    jint err = setOutputDeviceVolume(deviceUIDPtr, volume);
+    // Free
+    (*env)->ReleaseStringUTFChars(env, deviceUID, deviceUIDPtr);
+
+    return err;
+}
+
+JNIEXPORT jfloat JNICALL
+Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getInputDeviceVolume
+  (JNIEnv *env, jclass clazz, jstring deviceUID)
+{
+    const char * deviceUIDPtr = (*env)->GetStringUTFChars(env, deviceUID, 0);
+    jfloat volume = getInputDeviceVolume(deviceUIDPtr);
+    // Free
+    (*env)->ReleaseStringUTFChars(env, deviceUID, deviceUIDPtr);
+
+    return volume;
+}
+
+JNIEXPORT jfloat JNICALL
+Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getOutputDeviceVolume
+  (JNIEnv *env, jclass clazz, jstring deviceUID)
+{
+    const char * deviceUIDPtr = (*env)->GetStringUTFChars(env, deviceUID, 0);
+    jfloat volume = getOutputDeviceVolume(deviceUIDPtr);
+    // Free
+    (*env)->ReleaseStringUTFChars(env, deviceUID, deviceUIDPtr);
+
+    return volume;
+}
+
+/**
+ * Gets a new <tt>jbyteArray</tt> instance which is initialized with the bytes
+ * of a specific C string i.e. <tt>const char *</tt>.
+ *
+ * @param env
+ * @param str the bytes/C string to initialize the new <tt>jbyteArray</tt>
+ * instance with
+ * @return a new <tt>jbyteArray</tt> instance which is initialized with the
+ * bytes of the specified <tt>str</tt>
+ */
+static jbyteArray getStrBytes(JNIEnv *env, const char *str)
+{
+    jbyteArray bytes;
+
+    if (str)
+    {
+        size_t length = strlen(str);
+
+        bytes = (*env)->NewByteArray(env, length);
+        if (bytes && length)
+            (*env)->SetByteArrayRegion(env, bytes, 0, length, (jbyte *) str);
+    }
+    else
+        bytes = NULL;
+    return bytes;
+}
diff --git a/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.h b/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e7e83bba31f51f9a941537892dd996df578e701
--- /dev/null
+++ b/src/native/macosx/coreaudio/jni/org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice.h
@@ -0,0 +1,60 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice */
+
+#ifndef _Included_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+#define _Included_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+ * Method:    getDeviceNameBytes
+ * Signature: (Ljava/lang/String;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getDeviceNameBytes
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+ * Method:    setInputDeviceVolume
+ * Signature: (Ljava/lang/String;F)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_setInputDeviceVolume
+  (JNIEnv *, jclass, jstring, jfloat);
+
+/*
+ * Class:     org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+ * Method:    setOutputDeviceVolume
+ * Signature: (Ljava/lang/String;F)I
+ */
+JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_setOutputDeviceVolume
+  (JNIEnv *, jclass, jstring, jfloat);
+
+/*
+ * Class:     org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+ * Method:    getInputDeviceVolume
+ * Signature: (Ljava/lang/String;)F
+ */
+JNIEXPORT jfloat JNICALL Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getInputDeviceVolume
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice
+ * Method:    getOutputDeviceVolume
+ * Signature: (Ljava/lang/String;)F
+ */
+JNIEXPORT jfloat JNICALL Java_org_jitsi_impl_neomedia_coreaudio_CoreAudioDevice_getOutputDeviceVolume
+  (JNIEnv *, jclass, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/native/macosx/coreaudio/lib/device.c b/src/native/macosx/coreaudio/lib/device.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6bfe3482ca87c58be31ba00a26c95ec555f4cea
--- /dev/null
+++ b/src/native/macosx/coreaudio/lib/device.c
@@ -0,0 +1,459 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+#include "device.h"
+
+#include <CoreAudio/CoreAudio.h>
+#include <CoreFoundation/CFString.h>
+#include <stdio.h>
+/**
+ * Functions to list, access and modifies audio devices via coreaudio.
+ *
+ * @author Vincent Lucas
+ */
+
+/**
+ * Private definition of functions,
+ */
+OSStatus setDeviceVolume(
+        const char * deviceUID,
+        Float32 volume,
+        UInt32 inputOutputScope);
+
+Float32 getDeviceVolume(
+        const char * deviceUID,
+        UInt32 inputOutputScope);
+
+OSStatus getChannelsForStereo(
+        const char * deviceUID,
+        UInt32 * channels);
+
+/**
+ * Returns the audio device corresponding to the UID given in parameter. Or
+ * kAudioObjectUnknown if the device is nonexistant or if anything as failed.
+ *
+ * @pqrqm deviceUID The device UID.
+ *
+ * @return The audio device corresponding to the UID given in parameter. Or
+ * kAudioObjectUnknown if the device is nonexistant or if anything as failed.
+ */
+AudioDeviceID getDevice(
+        const char * deviceUID)
+{
+    OSStatus err = noErr;
+    AudioObjectPropertyAddress address;
+    AudioDeviceID device = kAudioObjectUnknown;
+    UInt32 size;
+
+    // Converts the device UID into a ref.
+    CFStringRef deviceUIDRef;
+    if((deviceUIDRef = CFStringCreateWithCString(
+            kCFAllocatorDefault,
+            deviceUID,
+            kCFStringEncodingASCII)) == NULL)
+    {
+        fprintf(stderr,
+                "getDevice (coreaudio/device.c): \
+                    \n\tCFStringCreateWithCString\n");
+        return kAudioObjectUnknown;
+    }
+
+    // Gets the device corresponding to the given UID.
+    AudioValueTranslation translation;
+    translation.mInputData = &deviceUIDRef;
+    translation.mInputDataSize = sizeof(deviceUIDRef);
+    translation.mOutputData = &device;
+    translation.mOutputDataSize = sizeof(device);
+    size = sizeof(translation);
+    address.mSelector = kAudioHardwarePropertyDeviceForUID;
+    address.mScope = kAudioObjectPropertyScopeGlobal;
+    address.mElement = kAudioObjectPropertyElementMaster;
+
+    if((err = AudioObjectGetPropertyData(
+            kAudioObjectSystemObject,
+            &address,
+            0,
+            NULL,
+            &size,
+            &translation)) != noErr)
+    {
+        fprintf(stderr,
+                "getDevice (coreaudio/device.c): \
+                    \n\tAudioObjectGetPropertyData, err: %d\n",
+                ((int) err));
+        return kAudioObjectUnknown;
+    }
+
+    // Frees the allocated device UID ref.
+    CFRelease(deviceUIDRef);
+
+    return device;
+}
+
+/**
+ * Returns the device name 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 name for the given device. Or NULL, if not available. The
+ * returned string must be freed by the caller.
+ */
+char* getDeviceName(
+        const char * deviceUID)
+{
+    AudioDeviceID device;
+    OSStatus err = noErr;
+    AudioObjectPropertyAddress address;
+    UInt32 size;
+
+    // Gets the correspoding device
+    if((device = getDevice(deviceUID)) == kAudioObjectUnknown)
+    {
+        fprintf(stderr,
+                "getDeviceName (coreaudio/device.c): \
+                    \n\tgetDevice\n");
+        return NULL;
+    }
+
+    // Gets the device name
+    CFStringRef deviceName;
+    size = sizeof(deviceName);
+    address.mSelector = kAudioObjectPropertyName;
+    address.mScope = kAudioObjectPropertyScopeGlobal;
+    address.mElement = kAudioObjectPropertyElementMaster;
+
+    if((err = AudioObjectGetPropertyData(
+            device,
+            &address,
+            0,
+            NULL,
+            &size,
+            &deviceName)) != noErr)
+    {
+        fprintf(stderr,
+                "getDeviceName (coreaudio/device.c): \
+                    \n\tAudioObjectGetPropertyData, err: %d\n",
+                ((int) err));
+        return NULL;
+    }
+
+    // Converts the device name to ASCII.
+    CFIndex deviceNameLength = CFStringGetLength(deviceName) + 1;
+    char * deviceASCIIName;
+    // The caller of this function must free the string.
+    if((deviceASCIIName = (char *) malloc(deviceNameLength * sizeof(char)))
+            == NULL)
+    {
+        perror("getDeviceName (coreaudio/device.c): \
+                    \n\tmalloc\n");
+        return NULL;
+    }
+    if(CFStringGetCString(
+                deviceName,
+                deviceASCIIName,
+                deviceNameLength,
+                kCFStringEncodingASCII))
+    {
+        return deviceASCIIName;
+    }
+    return NULL;
+}
+
+/**
+ * Sets the input volume for a given device.
+ *
+ * @param device The device which volume must be changed.
+ * @param volume The new volume of the device. This is a scalar value between
+ * 0.0 and 1.0
+ *
+ * @return noErr if everything works well. Another value if an error has
+ * occured.  
+ */
+OSStatus setInputDeviceVolume(
+        const char * deviceUID,
+        Float32 volume)
+{
+    return setDeviceVolume(
+            deviceUID,
+            volume,
+            kAudioDevicePropertyScopeInput);
+}
+
+/**
+ * Sets the output volume for a given device.
+ *
+ * @param device The device which volume must be changed.
+ * @param volume The new volume of the device. This is a scalar value between
+ * 0.0 and 1.0
+ *
+ * @return noErr if everything works well. Another value if an error has
+ * occured.  
+ */
+OSStatus setOutputDeviceVolume(
+        const char * deviceUID,
+        Float32 volume)
+{
+    return setDeviceVolume(
+            deviceUID,
+            volume,
+            kAudioDevicePropertyScopeOutput);
+}
+
+/**
+ * Sets the input or output volume for a given device. This is an internal
+ * (private) function and must only be called by setInputDeviceVolume or
+ * setOutputDeviceVolume.
+ *
+ * @param device The device which volume must be changed.
+ * @param volume The new volume of the device. This is a scalar value between
+ * 0.0 and 1.0
+ * @param inputOutputScope The scope to tell if this is an output or an input
+ * device.
+ *
+ * @return noErr if everything works well. Another value if an error has
+ * occured.  
+ */
+OSStatus setDeviceVolume(
+        const char * deviceUID,
+        Float32 volume,
+        UInt32 inputOutputScope)
+{
+    AudioDeviceID device;
+    OSStatus err = noErr;
+    AudioObjectPropertyAddress address;
+    UInt32 size;
+    UInt32 channels[2];
+
+    // Gets the correspoding device
+    if((device = getDevice(deviceUID)) == kAudioObjectUnknown)
+    {
+        fprintf(stderr,
+                "setDeviceVolume (coreaudio/device.c): \
+                    \n\tgetDevice (unknown device for UID: %s)\n", deviceUID);
+        return -1;
+    }
+
+    // get the input device stereo channels
+    if((getChannelsForStereo(deviceUID, channels)) != noErr)
+    {
+        fprintf(stderr,
+                "setDeviceVolume (coreaudio/device.c): \
+                    \n\tgetChannelsForStereo, err: %d\n",
+                ((int) err));
+        return err;
+    }
+
+    // Sets the volume
+    size = sizeof(volume);
+    address.mSelector = kAudioDevicePropertyVolumeScalar;
+    address.mScope = inputOutputScope;
+    int i;
+    int elementsLength = 3;
+    UInt32 elements[] =
+    {
+        // The global volume.
+        kAudioObjectPropertyElementMaster,
+        // The left channel.
+        channels[0],
+        // The right channel.
+        channels[1]
+    };
+
+    // Applies the volume to the different elements of the device.
+    for(i = 0; i < elementsLength; ++i)
+    {
+        address.mElement = elements[i];
+        // Checks if this device volume can be set. If yes, then do so.
+        if(AudioObjectHasProperty(device, &address))
+        {
+            if((err = AudioObjectSetPropertyData(
+                    device,
+                    &address,
+                    0,
+                    NULL,
+                    size,
+                    &volume)) != noErr)
+            {
+                fprintf(stderr,
+                        "setDeviceVolume (coreaudio/device.c): \
+                            \n\tAudioObjectSetPropertyData, err: %d\n",
+                        ((int) err));
+                return err;
+            }
+        }
+    }
+
+    return err;
+}
+
+/**
+ * Gets the input volume for a given device.
+ *
+ * @param device The device to get volume from.
+ *
+ * @return The device volume as a scalar value between 0.0 and 1.0. Returns -1.0
+ * if an error occurs.
+ */
+Float32 getInputDeviceVolume(
+        const char * deviceUID)
+{
+    return getDeviceVolume(
+            deviceUID,
+            kAudioDevicePropertyScopeInput);
+}
+
+/**
+ * Gets the output volume for a given device.
+ *
+ * @param device The device to get volume from.
+ *
+ * @return The device volume as a scalar value between 0.0 and 1.0. Returns -1.0
+ * if an error occurs.
+ */
+Float32 getOutputDeviceVolume(
+        const char * deviceUID)
+{
+    return getDeviceVolume(
+            deviceUID,
+            kAudioDevicePropertyScopeOutput);
+}
+
+/**
+ * Gets the input or output volume for a given device. This is an internal
+ * (private) function and must only be called by getInputDeviceVolume or
+ * getOutputDeviceVolume.
+ *
+ * @param device The device to get volume from.
+ * @param inputOutputScope The scope to tell if this is an output or an input
+ * device.
+ *
+ * @return The device volume as a scalar value between 0.0 and 1.0. Returns -1.0
+ * if an error occurs.
+ */
+Float32 getDeviceVolume(
+        const char * deviceUID,
+        UInt32 inputOutputScope)
+{
+    AudioDeviceID device;
+    Float32 volume = -1.0;
+    OSStatus err = noErr;
+    AudioObjectPropertyAddress address;
+    UInt32 size;
+    UInt32 channels[2];
+
+    // Gets the correspoding device
+    if((device = getDevice(deviceUID)) == kAudioObjectUnknown)
+    {
+        fprintf(stderr,
+                "getDeviceVolume (coreaudio/device.c): \
+                    \n\tgetDevice\n");
+        return -1.0;
+    }
+
+    // get the input device stereo channels
+    if((getChannelsForStereo(deviceUID, channels)) != noErr)
+    {
+        fprintf(stderr,
+                "getDeviceVolume (coreaudio/device.c): \
+                    \n\tgetChannelsForStereo, err: %d\n",
+                ((int) err));
+        return -1.0;
+    }
+
+    // Sets the volume
+    size = sizeof(volume);
+    address.mSelector = kAudioDevicePropertyVolumeScalar;
+    address.mScope = inputOutputScope;
+    int i;
+    int elementsLength = 3;
+    UInt32 elements[] =
+    {
+        // The global volume.
+        kAudioObjectPropertyElementMaster,
+        // The left channel.
+        channels[0],
+        // The right channel.
+        channels[1]
+    };
+
+    // Applies the volume to the different elements of the device.
+    for(i = 0; i < elementsLength; ++i)
+    {
+        address.mElement = elements[i];
+        // Checks if this device volume can be set. If yes, then do so.
+        if(AudioObjectHasProperty(device, &address))
+        {
+            if((err = AudioObjectGetPropertyData(
+                    device,
+                    &address,
+                    0,
+                    NULL,
+                    &size,
+                    &volume)) != noErr)
+            {
+                fprintf(stderr,
+                        "getDeviceVolume (coreaudio/device.c): \
+                            \n\tAudioObjectSetPropertyData, err: %d\n",
+                        ((int) err));
+                return -1.0;
+            }
+        }
+    }
+
+    return volume;
+}
+
+/**
+ * Sets the channels for stereo of a given device.
+ *
+ * @param device The device to get the channels from.
+ * @param channels The channels to be filled in with the correct values. This
+ * must be a 2 item length array.
+ *
+ * @return An OSStatus set to noErr if everything works well. Any other vlaue
+ * otherwise.
+ */
+OSStatus getChannelsForStereo(
+        const char * deviceUID,
+        UInt32 * channels)
+{
+    AudioDeviceID device;
+    OSStatus err = noErr;
+    AudioObjectPropertyAddress address;
+    UInt32 size;
+
+    // Gets the correspoding device
+    if((device = getDevice(deviceUID)) == kAudioObjectUnknown)
+    {
+        fprintf(stderr,
+                "getChannelsForStereo (coreaudio/device.c): \
+                    \n\tgetDevice\n");
+        return -1;
+    }
+
+    // get the input device stereo channels
+    address.mSelector = kAudioDevicePropertyPreferredChannelsForStereo;
+    address.mScope = kAudioDevicePropertyScopeInput;
+    address.mElement = kAudioObjectPropertyElementWildcard;
+    size = sizeof(channels);
+    if((err = AudioObjectGetPropertyData(
+            device,
+            &address,
+            0,
+            NULL,
+            &size,
+            channels)) != noErr)
+    {
+        fprintf(stderr,
+                "getChannelsForStereo (coreaudio/device.c): \
+                    \n\tAudioObjectGetPropertyData, err: %d\n",
+                ((int) err));
+        return err;
+    }
+
+    return err;
+}
diff --git a/src/native/macosx/coreaudio/lib/device.h b/src/native/macosx/coreaudio/lib/device.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed5b12cb85c5caad2c6ad0f3128f2a6c47a40510
--- /dev/null
+++ b/src/native/macosx/coreaudio/lib/device.h
@@ -0,0 +1,39 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+#ifndef device_h
+#define device_h
+
+#include <CoreAudio/CoreAudio.h>
+#include <CoreFoundation/CFString.h>
+#include <stdio.h>
+
+/**
+ * Functions to list, access and modifies audio devices via coreaudio.
+ * Look at correspondig ".c" file for documentation.
+ *
+ * @author Vincent Lucas
+ */
+AudioDeviceID getDevice(
+        const char * deviceUID);
+
+char* getDeviceName(
+        const char * deviceUID);
+
+OSStatus setInputDeviceVolume(
+        const char * deviceUID,
+        Float32 volume);
+
+OSStatus setOutputDeviceVolume(
+        const char * deviceUID,
+        Float32 volume);
+
+Float32 getInputDeviceVolume(
+        const char * deviceUID);
+
+Float32 getOutputDeviceVolume(
+        const char * deviceUID);
+#endif
diff --git a/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java b/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
index 2c8a5234c95ec94705a31c88ab60a93df80ed02e..bc1ff3976d4d156c15cb8f19308d3a77c179e152 100644
--- a/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
+++ b/src/org/jitsi/impl/neomedia/AbstractVolumeControl.java
@@ -43,7 +43,7 @@ public class AbstractVolumeControl
     /**
      * The minimum volume level accepted by <tt>AbstractVolumeControl</tt>.
      */
-    private static final float MIN_VOLUME_LEVEL = 0.0F;
+    protected static final float MIN_VOLUME_LEVEL = 0.0F;
 
     /**
      * The minimum volume level expressed in percent accepted by
@@ -54,7 +54,7 @@ public class AbstractVolumeControl
     /**
      * The maximum volume level accepted by <tt>AbstractVolumeControl</tt>.
      */
-    private static final float MAX_VOLUME_LEVEL = 1.0F;
+    protected static final float MAX_VOLUME_LEVEL = 1.0F;
 
     /**
      * The maximum volume level expressed in percent accepted by
@@ -62,14 +62,6 @@ public class AbstractVolumeControl
      */
     public static final int MAX_VOLUME_PERCENT = 200;
 
-    /**
-     * The default volume level.
-     */
-    private static final float DEFAULT_VOLUME_LEVEL
-        = MIN_VOLUME_LEVEL
-            + (MAX_VOLUME_LEVEL - MIN_VOLUME_LEVEL)
-                / ((MAX_VOLUME_PERCENT - MIN_VOLUME_PERCENT) / 100);
-
     /**
      * The <tt>VolumeChangeListener</tt>s interested in volume change events
      * through the <tt>VolumeControl</tt> interface.
@@ -92,7 +84,13 @@ public class AbstractVolumeControl
     /**
      * The current volume level.
      */
-    private float volumeLevel = DEFAULT_VOLUME_LEVEL;
+    protected float volumeLevel;
+
+    /**
+     * The power level reference used to compute equivelents between the volume
+     * power level and the gain in decibels.
+     */
+    private float gainReferenceLevel;
 
     /**
      * Current mute state, by default we start unmuted.
@@ -104,11 +102,6 @@ public class AbstractVolumeControl
      */
     private float db;
 
-    /**
-     * The initial volume level, when this instance was created.
-     */
-    private final float initialVolumeLevel;
-
     /**
      * The name of the configuration property which specifies the value of the
      * volume level of this <tt>AbstractVolumeControl</tt>.
@@ -126,29 +119,29 @@ public class AbstractVolumeControl
     public AbstractVolumeControl(
         String volumeLevelConfigurationPropertyName)
     {
+        // Initializes default values.
+        this.volumeLevel = getDefaultVolumeLevel();
+        this.gainReferenceLevel = getGainReferenceLevel();
+
         this.volumeLevelConfigurationPropertyName
             = volumeLevelConfigurationPropertyName;
 
         // Read the initial volume level from the ConfigurationService.
-        float initialVolumeLevel = DEFAULT_VOLUME_LEVEL;
-
         try
         {
             ConfigurationService cfg = LibJitsi.getConfigurationService();
 
             if (cfg != null)
             {
-                String initialVolumeLevelString
+                String volumeLevelString
                     = cfg.getString(this.volumeLevelConfigurationPropertyName);
 
-                if (initialVolumeLevelString != null)
+                if (volumeLevelString != null)
                 {
-                    initialVolumeLevel
-                        = Float.parseFloat(initialVolumeLevelString);
+                    this.volumeLevel = Float.parseFloat(volumeLevelString);
                     if(logger.isDebugEnabled())
                     {
-                        logger.debug(
-                                "Restored volume: " + initialVolumeLevelString);
+                        logger.debug("Restored volume: " + volumeLevelString);
                     }
                 }
             }
@@ -157,9 +150,6 @@ public AbstractVolumeControl(
         {
             logger.warn("Error restoring volume", t);
         }
-
-        this.initialVolumeLevel = initialVolumeLevel;
-        this.volumeLevel = this.initialVolumeLevel;
     }
 
     /**
@@ -310,6 +300,7 @@ else if (value > MAX_VOLUME_LEVEL)
             return value;
 
         volumeLevel = value;
+        updateHardwareVolume();
         fireVolumeChange();
 
         /*
@@ -325,13 +316,7 @@ else if (value > MAX_VOLUME_LEVEL)
                     String.valueOf(volumeLevel));
         }
 
-        float f1 = value / initialVolumeLevel;
-
-        db
-            = (float)
-                ((Math.log(((double)f1 != 0.0D) ? f1 : 0.0001D)
-                        / Math.log(10D))
-                    * 20D);
+        db = getDbFromPowerRatio(value, this.gainReferenceLevel);
         fireGainEvents();
 
         return volumeLevel;
@@ -380,9 +365,7 @@ public float setDB(float gain)
         if(this.db != gain)
         {
             this.db = gain;
-
-            float f1 = (float)Math.pow(10D, (double)this.db / 20D);
-            float volumeLevel = f1 * this.initialVolumeLevel;
+            float volumeLevel = getPowerRatioFromDb(gain, gainReferenceLevel);
 
             setVolumeLevel(volumeLevel);
         }
@@ -533,4 +516,77 @@ public Component getControlComponent()
     {
         return null;
     }
+
+    /**
+     * Returns the decibel value for a ratio between a power level required and
+     * the reference power level.
+     *
+     * @param powerLevelRequired The power level wished for the signal
+     * (corresponds to the mesured power level).
+     * @param referencePowerLevel The reference power level.
+     *
+     * @return The gain in Db.
+     */
+    private static float getDbFromPowerRatio(
+            float powerLevelRequired,
+            float referencePowerLevel)
+    {
+        float powerRatio = powerLevelRequired / referencePowerLevel;
+
+        // Limits the lowest power ratio to be 0.0001.
+        float minPowerRatio = 0.0001F;
+        float flooredPowerRatio = Math.max(powerRatio, minPowerRatio);
+
+        return (float) (20.0 * Math.log10(flooredPowerRatio));
+    }
+
+    /**
+     * Returns the mesured power level corresponding to a gain in decibel and
+     * compared to the reference power level.
+     *
+     * @param gainInDb The gain in Db.
+     * @param referencePowerLevel The reference power level.
+     *
+     * @return The power level the signal, which corresponds to the mesured
+     * power level.
+     */
+    private static float getPowerRatioFromDb(
+            float gainInDb,
+            float referencePowerLevel)
+    {
+        return (float) Math.pow(10, (gainInDb / 20)) * referencePowerLevel;
+    }
+
+    /**
+     * Returns the default volume level.
+     *
+     * @return The default volume level.
+     */
+    protected static float getDefaultVolumeLevel()
+    {
+        return MIN_VOLUME_LEVEL
+            + (MAX_VOLUME_LEVEL - MIN_VOLUME_LEVEL)
+                / ((MAX_VOLUME_PERCENT - MIN_VOLUME_PERCENT) / 100);
+    }
+
+    /**
+     * Returns the reference volume level for computing the gain.
+     *
+     * @return The reference volume level for computing the gain.
+     */
+    protected static float getGainReferenceLevel()
+    {
+        return getDefaultVolumeLevel();
+    }
+
+    /**
+     * Modifies the hardware microphone sensibility (hardaware amplification).
+     * This is a void function for AbstractVolumeControl sincei it does not have
+     * any connection to hardware volume. But, this function must be redefined
+     * by any extending class.
+     */
+    protected void updateHardwareVolume()
+    {
+        // Nothing to do. This AbstractVolumeControl only modifies the gain.
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
index 0a8592201967cb9628664ff7bfd976a088aa8222..2055b523419f75574c5cc70d6191f33f63a1f796 100644
--- a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
+++ b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
@@ -21,6 +21,7 @@
 
 import org.jitsi.impl.neomedia.codec.*;
 import org.jitsi.impl.neomedia.codec.video.*;
+import org.jitsi.impl.neomedia.coreaudio.*;
 import org.jitsi.impl.neomedia.device.*;
 import org.jitsi.impl.neomedia.format.*;
 import org.jitsi.impl.neomedia.transform.sdes.*;
@@ -748,9 +749,19 @@ public VolumeControl getInputVolumeControl()
     {
         if (inputVolumeControl == null)
         {
-            inputVolumeControl
-                = new AbstractVolumeControl(
-                        VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME);
+            if(OSUtils.IS_MAC)
+            {
+                inputVolumeControl
+                    = new CoreAudioVolumeControl(
+                            this,
+                            VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME);
+            }
+            else
+            {
+                inputVolumeControl
+                    = new AbstractVolumeControl(
+                            VolumeControl.CAPTURE_VOLUME_LEVEL_PROPERTY_NAME);
+            }
         }
         return inputVolumeControl;
     }
diff --git a/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioDevice.java b/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioDevice.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ed93340fe3c6c1d12b6deb6c98d57706683f759
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioDevice.java
@@ -0,0 +1,51 @@
+/*
+ * 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.coreaudio;
+
+import org.jitsi.util.*;
+
+/**
+ * JNI link to the CoreAudio library.
+ *
+ * @author Vincent Lucqs
+ */
+public class CoreAudioDevice
+{
+    static
+    {
+        System.loadLibrary("jncoreaudio");
+    }
+
+//    public static native AudioDeviceID getDevice(
+//            String deviceUID);
+
+    public static String getDeviceName(
+            String deviceUID)
+    {
+        byte[] deviceNameBytes = getDeviceNameBytes(deviceUID);
+        String deviceName = StringUtils.newString(deviceNameBytes);
+
+        return deviceName;
+    }
+
+    public static native byte[] getDeviceNameBytes(
+            String deviceUID);
+
+    public static native int setInputDeviceVolume(
+            String deviceUID,
+            float volume);
+
+    public static native int setOutputDeviceVolume(
+            String deviceUID,
+            float volume);
+
+    public static native float getInputDeviceVolume(
+            String deviceUID);
+
+    public static native float getOutputDeviceVolume(
+            String deviceUID);
+}
diff --git a/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioVolumeControl.java b/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioVolumeControl.java
new file mode 100644
index 0000000000000000000000000000000000000000..60eb5da67f720a258b5b836009d2134c19edfc33
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/coreaudio/CoreAudioVolumeControl.java
@@ -0,0 +1,113 @@
+/*
+ * 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.coreaudio;
+
+import org.jitsi.impl.neomedia.*;
+import org.jitsi.impl.neomedia.device.*;
+import org.jitsi.service.neomedia.*;
+import org.jitsi.util.*;
+
+/**
+ * Implementation of VolumeControl which uses MacOSX sound architecture
+ * CoreAudio to change input/output hardware volume.
+ *
+ * @author Vincent Lucas
+ */
+public class CoreAudioVolumeControl
+    extends AbstractVolumeControl
+{
+    /**
+     * The <tt>Logger</tt> used by the <tt>CoreAudioVolumeControl</tt> class and
+     * its instances for logging output.
+     */
+    private static final Logger logger
+        = Logger.getLogger(CoreAudioVolumeControl.class);
+
+    /**
+     * The media service implementation.
+     */
+    MediaServiceImpl mediaServiceImpl = null;
+
+    /**
+     * The maximal power level used for hardware amplification. Over this value
+     * software amplification is used.
+     */
+    private static final float MAX_HARDWARE_POWER = 1.0F;
+
+    /**
+     * Creates volume control instance and initializes initial level value
+     * if stored in the configuration service.
+     *
+     * @param mediaServiceImpl The media service implementation.
+     * @param volumeLevelConfigurationPropertyName the name of the configuration
+     * property which specifies the value of the volume level of the new
+     * instance
+     */
+    public CoreAudioVolumeControl(
+        MediaServiceImpl mediaServiceImpl,
+        String volumeLevelConfigurationPropertyName)
+    {
+        super(volumeLevelConfigurationPropertyName);
+        this.mediaServiceImpl = mediaServiceImpl;
+        updateHardwareVolume();
+    }
+
+    /**
+     * Returns the default volume level.
+     *
+     * @return The default volume level.
+     */
+    protected static float getDefaultVolumeLevel()
+    {
+        // By default set the microphone at the middle of its hardware
+        // sensibility range.
+        return MAX_HARDWARE_POWER / 2;
+    }
+
+    /**
+     * Returns the reference volume level for computing the gain.
+     *
+     * @return The reference volume level for computing the gain.
+     */
+    protected static float getGainReferenceLevel()
+    {
+        // Starts to activate the gain (software amplification), only once the
+        // microphone sensibility is sets to its maximum (hardware
+        // amplification).
+        return MAX_HARDWARE_POWER;
+    }
+
+    /**
+     * Modifies the hardware microphone sensibility (hardware amplification).
+     */
+    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();
+
+        // Computes the hardware volume.
+        float jitsiHarwareVolumeFactor = MAX_VOLUME_LEVEL / MAX_HARDWARE_POWER;
+        float hardwareVolumeLevel = this.volumeLevel * jitsiHarwareVolumeFactor;
+        if(hardwareVolumeLevel > 1.0F)
+        {
+            hardwareVolumeLevel = 1.0F;
+        }
+
+        // Changes the input volume of the capture device.
+        if(CoreAudioDevice.setInputDeviceVolume(
+                    deviceUID,
+                    hardwareVolumeLevel) != 0)
+        {
+            logger.debug("Could not change CoreAudio input device level");
+        }
+    }
+}
diff --git a/src/org/jitsi/impl/neomedia/portaudio/Pa.java b/src/org/jitsi/impl/neomedia/portaudio/Pa.java
index 703c89f3d1ac78d9d176d57c9fac4e00f6e9c19a..46223bd815e436d707284f85076c33aa7ff239d0 100644
--- a/src/org/jitsi/impl/neomedia/portaudio/Pa.java
+++ b/src/org/jitsi/impl/neomedia/portaudio/Pa.java
@@ -8,7 +8,6 @@
 
 import java.io.*;
 import java.lang.reflect.*;
-import java.nio.charset.*;
 
 import org.jitsi.service.configuration.*;
 import org.jitsi.service.libjitsi.*;
@@ -247,7 +246,7 @@ public static native double DeviceInfo_getDefaultSampleRate(
      */
     public static String DeviceInfo_getDeviceUID(long deviceInfo)
     {
-        return newString(DeviceInfo_getDeviceUIDBytes(deviceInfo));
+        return StringUtils.newString(DeviceInfo_getDeviceUIDBytes(deviceInfo));
     }
 
     /**
@@ -293,7 +292,7 @@ public static String DeviceInfo_getDeviceUID(long deviceInfo)
      */
     public static String DeviceInfo_getName(long deviceInfo)
     {
-        return newString(DeviceInfo_getNameBytes(deviceInfo));
+        return StringUtils.newString(DeviceInfo_getNameBytes(deviceInfo));
     }
 
     /**
@@ -316,7 +315,8 @@ public static String DeviceInfo_getName(long deviceInfo)
      */
     public static String DeviceInfo_getTransportType(long deviceInfo)
     {
-        return newString(DeviceInfo_getTransportTypeBytes(deviceInfo));
+        return StringUtils.newString(
+                DeviceInfo_getTransportTypeBytes(deviceInfo));
     }
 
     /**
@@ -565,36 +565,6 @@ public static native boolean IsFormatSupported(
         long outputParameters,
         double sampleRate);
 
-    /**
-     * Initializes a new <tt>String</tt> instance by decoding a specified array
-     * of bytes.
-     *
-     * @param bytes the bytes to be decoded into characters/a new
-     * <tt>String</tt> instance
-     * @return a new <tt>String</tt> instance whose characters were decoded from
-     * the specified <tt>bytes</tt>
-     */
-    private static String newString(byte[] bytes)
-    {
-        if ((bytes == null) || (bytes.length == 0))
-            return null;
-        else
-        {
-            Charset defaultCharset = Charset.defaultCharset();
-            String charsetName
-                = (defaultCharset == null) ? "UTF-8" : defaultCharset.name();
-
-            try
-            {
-                return new String(bytes, charsetName);
-            }
-            catch (UnsupportedEncodingException ueex)
-            {
-                return new String(bytes);
-            }
-        }
-    }
-
     /**
      * Opens a stream for either input, output or both.
      *
diff --git a/src/org/jitsi/util/StringUtils.java b/src/org/jitsi/util/StringUtils.java
index c5dd5a55e58f5a2a9479fce0c2a1a81c29463b14..e5e35898498ea40e261f908c777410e8c28122f4 100644
--- a/src/org/jitsi/util/StringUtils.java
+++ b/src/org/jitsi/util/StringUtils.java
@@ -7,6 +7,7 @@
 package org.jitsi.util;
 
 import java.io.*;
+import java.nio.charset.*;
 
 /**
  * Implements utility functions to facilitate work with <tt>String</tt>s.
@@ -233,4 +234,34 @@ public static String concatenateWords(String string)
         }
         return buff.toString();
     }
+
+    /**
+     * Initializes a new <tt>String</tt> instance by decoding a specified array
+     * of bytes (mostly used by JNI).
+     *
+     * @param bytes the bytes to be decoded into characters/a new
+     * <tt>String</tt> instance
+     * @return a new <tt>String</tt> instance whose characters were decoded from
+     * the specified <tt>bytes</tt>
+     */
+    public static String newString(byte[] bytes)
+    {
+        if ((bytes == null) || (bytes.length == 0))
+            return null;
+        else
+        {
+            Charset defaultCharset = Charset.defaultCharset();
+            String charsetName
+                = (defaultCharset == null) ? "UTF-8" : defaultCharset.name();
+
+            try
+            {
+                return new String(bytes, charsetName);
+            }
+            catch (UnsupportedEncodingException ueex)
+            {
+                return new String(bytes);
+            }
+        }
+    }
 }