diff --git a/lib/native/linux-64/libjnpulseaudio.so b/lib/native/linux-64/libjnpulseaudio.so index a31e9846b..1440a46ad 100755 Binary files a/lib/native/linux-64/libjnpulseaudio.so and b/lib/native/linux-64/libjnpulseaudio.so differ diff --git a/lib/native/linux/libjnpulseaudio.so b/lib/native/linux/libjnpulseaudio.so new file mode 100755 index 000000000..83a2f40d2 Binary files /dev/null and b/lib/native/linux/libjnpulseaudio.so differ diff --git a/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.c b/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.c index c0bcef23f..186210187 100644 --- a/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.c +++ b/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.c @@ -4,13 +4,21 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ + +#define _GNU_SOURCE + #include "net_java_sip_communicator_impl_neomedia_pulseaudio_PA.h" +#include #include #include +typedef pa_operation * (*pa_context_set_source_output_volume_t)(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + static void PulseAudio_contextStateCallback(pa_context *c, void *userdata); +#if (PA_MAJOR >= 1) static jlongArray PulseAudio_getFormatInfos(JNIEnv *env, jclass clazz, jsize length, pa_format_info **formats); +#endif /* #if (PA_MAJOR >= 1) */ static void PulseAudio_infoCallback(pa_context *c, jlong i, int eol, void *userdata, jmethodID methodID); static void PulseAudio_sinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata); static void PulseAudio_sourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata); @@ -18,6 +26,7 @@ static void PulseAudio_stateCallback(void *userdata); static void PulseAudio_streamRequestCallback(pa_stream *s, size_t nbytes, void *userdata); static void PulseAudio_streamStateCallback(pa_stream *s, void *userdata); +static pa_context_set_source_output_volume_t PulseAudio_contextSetSourceOutputVolume = NULL; static jclass PulseAudio_runnableClass = NULL; static jmethodID PulseAudio_runnableMethodID = 0; static jclass PulseAudio_sinkInfoCbClass = NULL; @@ -177,14 +186,21 @@ JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_context_1set_1source_1output_1volume (JNIEnv *env, jclass clazz, jlong c, jint idx, jlong volume, jobject cb) { - return - (intptr_t) - pa_context_set_source_output_volume( + pa_operation *o; + + if (PulseAudio_contextSetSourceOutputVolume) + { + o + = PulseAudio_contextSetSourceOutputVolume( (pa_context *) (intptr_t) c, (uint32_t) idx, (const pa_cvolume *) (intptr_t) volume, NULL, NULL); + } + else + o = NULL; + return (intptr_t) o; } JNIEXPORT void JNICALL @@ -236,6 +252,7 @@ Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_cvolume_1set (pa_volume_t) v); } +#if (PA_MAJOR >= 1) JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_format_1info_1get_1encoding (JNIEnv *env, jclass clazz, jlong f) @@ -279,6 +296,16 @@ Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_format_1info_1get_1pr } return ret; } +#endif /* #if (PA_MAJOR >= 1) */ + +JNIEXPORT jstring JNICALL +Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_get_1library_1version + (JNIEnv *env, jclass clazz) +{ + const char *chars = pa_get_library_version(); + + return chars ? (*env)->NewStringUTF(env, chars) : NULL; +} JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_operation_1get_1state @@ -371,11 +398,12 @@ JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1description (JNIEnv *env, jclass clazz, jlong i) { - const char *description = ((pa_sink_info *) (intptr_t) i)->description; + const char *chars = ((pa_sink_info *) (intptr_t) i)->description; - return description ? (*env)->NewStringUTF(env, description) : NULL; + return chars ? (*env)->NewStringUTF(env, chars) : NULL; } +#if (PA_MAJOR >= 1) JNIEXPORT jlongArray JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1formats (JNIEnv *env, jclass clazz, jlong i) @@ -387,6 +415,7 @@ Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1form env, clazz, sinkInfo->n_formats, sinkInfo->formats); } +#endif /* #if (PA_MAJOR >= 1) */ JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1index @@ -406,20 +435,18 @@ JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1monitor_1source_1name (JNIEnv *env, jclass clazz, jlong i) { - const char *monitorSourceName - = ((pa_sink_info *) (intptr_t) i)->monitor_source_name; + const char *chars = ((pa_sink_info *) (intptr_t) i)->monitor_source_name; - return - monitorSourceName ? (*env)->NewStringUTF(env, monitorSourceName) : NULL; + return chars ? (*env)->NewStringUTF(env, chars) : NULL; } JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_sink_1info_1get_1name (JNIEnv *env, jclass clazz, jlong i) { - const char *name = ((pa_sink_info *) (intptr_t) i)->name; + const char *chars = ((pa_sink_info *) (intptr_t) i)->name; - return name ? (*env)->NewStringUTF(env, name) : NULL; + return chars ? (*env)->NewStringUTF(env, chars) : NULL; } JNIEXPORT jint JNICALL @@ -447,11 +474,12 @@ JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_source_1info_1get_1description (JNIEnv *env, jclass clazz, jlong i) { - const char *description = ((pa_source_info *) (intptr_t) i)->description; + const char *chars = ((pa_source_info *) (intptr_t) i)->description; - return description ? (*env)->NewStringUTF(env, description) : NULL; + return chars ? (*env)->NewStringUTF(env, chars) : NULL; } +#if (PA_MAJOR >= 1) JNIEXPORT jlongArray JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_source_1info_1get_1formats (JNIEnv *env, jclass clazz, jlong i) @@ -463,6 +491,7 @@ Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_source_1info_1get_1fo env, clazz, sourceInfo->n_formats, sourceInfo->formats); } +#endif /* #if (PA_MAJOR >= 1) */ JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_source_1info_1get_1index @@ -482,9 +511,9 @@ JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_source_1info_1get_1name (JNIEnv *env, jclass clazz, jlong i) { - const char *name = ((pa_source_info *) (intptr_t) i)->name; + const char *chars = ((pa_source_info *) (intptr_t) i)->name; - return name ? (*env)->NewStringUTF(env, name) : NULL; + return chars ? (*env)->NewStringUTF(env, chars) : NULL; } JNIEXPORT jint JNICALL @@ -607,9 +636,9 @@ Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_stream_1new_1with_1pr = pa_stream_new_with_proplist( (pa_context *) (intptr_t) c, nameChars, - (const pa_sample_spec *) ss, - (const pa_channel_map *) map, - (pa_proplist *) p); + (const pa_sample_spec *) (intptr_t) ss, + (const pa_channel_map *) (intptr_t) map, + (pa_proplist *) (intptr_t) p); (*env)->ReleaseStringUTFChars(env, name, nameChars); } return (intptr_t) stream; @@ -914,7 +943,14 @@ JNI_OnLoad(JavaVM *vm, void *reserved) } } } - return PulseAudio_streamRequestCbMethodID ? version : JNI_ERR; + if (PulseAudio_streamRequestCbMethodID) + { + PulseAudio_contextSetSourceOutputVolume + = dlsym(RTLD_DEFAULT, "pa_context_set_source_output_volume"); + } + else + version = JNI_ERR; + return version; } JNIEXPORT void JNICALL @@ -962,6 +998,7 @@ PulseAudio_contextStateCallback(pa_context *c, void *userdata) PulseAudio_stateCallback(userdata); } +#if (PA_MAJOR >= 1) static jlongArray PulseAudio_getFormatInfos (JNIEnv *env, jclass clazz, jsize length, pa_format_info **formats) @@ -981,6 +1018,7 @@ PulseAudio_getFormatInfos } return ret; } +#endif /* #if (PA_MAJOR >= 1) */ static void PulseAudio_infoCallback diff --git a/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.h b/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.h index a0c0a7cf8..8624de6b0 100644 --- a/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.h +++ b/src/native/linux/pulseaudio/net_java_sip_communicator_impl_neomedia_pulseaudio_PA.h @@ -151,6 +151,14 @@ JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_ JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_format_1info_1get_1prop_1int (JNIEnv *, jclass, jlong, jstring); +/* + * Class: net_java_sip_communicator_impl_neomedia_pulseaudio_PA + * Method: get_library_version + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_neomedia_pulseaudio_PA_get_1library_1version + (JNIEnv *, jclass); + /* * Class: net_java_sip_communicator_impl_neomedia_pulseaudio_PA * Method: operation_get_state diff --git a/src/net/java/sip/communicator/impl/neomedia/device/PulseAudioSystem.java b/src/net/java/sip/communicator/impl/neomedia/device/PulseAudioSystem.java index 347330282..2234572a1 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/PulseAudioSystem.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/PulseAudioSystem.java @@ -367,7 +367,8 @@ public void callback(long c, long i, int eol) new CaptureDeviceInfo( NULL_DEV_CAPTURE_DEVICE_INFO_NAME, new MediaLocator(LOCATOR_PROTOCOL + ":"), - captureDeviceFormats.toArray(new Format[captureDeviceFormats.size()]))); + captureDeviceFormats.toArray( + new Format[captureDeviceFormats.size()]))); } if (!playbackDevices.isEmpty()) { @@ -492,94 +493,51 @@ private void sourceInfoListCallback( if (sampleSpecFormat != PA.SAMPLE_S16LE) return; - long[] formats = PA.source_info_get_formats(sourceInfo); - - if ((formats != null) && (formats.length > 0)) + int channels = PA.source_info_get_sample_spec_channels(sourceInfo); + int rate = PA.source_info_get_sample_spec_rate(sourceInfo); + List sourceInfoFormatList = new LinkedList(); + + if ((MediaUtils.MAX_AUDIO_CHANNELS != Format.NOT_SPECIFIED) + && (MediaUtils.MAX_AUDIO_CHANNELS < channels)) + channels = MediaUtils.MAX_AUDIO_CHANNELS; + if ((MediaUtils.MAX_AUDIO_SAMPLE_RATE != Format.NOT_SPECIFIED) + && (MediaUtils.MAX_AUDIO_SAMPLE_RATE < rate)) + rate = (int) MediaUtils.MAX_AUDIO_SAMPLE_RATE; + + AudioFormat audioFormat + = new AudioFormat( + AudioFormat.LINEAR, + rate, + 16, + channels, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED /* frameSizeInBits */, + Format.NOT_SPECIFIED /* frameRate */, + Format.byteArray); + + if (!sourceInfoFormatList.contains(audioFormat)) { - int sampleSpecChannels - = PA.source_info_get_sample_spec_channels(sourceInfo); - int sampleSpecRate - = PA.source_info_get_sample_spec_rate(sourceInfo); - List sourceInfoFormatList = new LinkedList(); - - for (long format : formats) - { - int encoding = PA.format_info_get_encoding(format); - - if ((encoding != PA.ENCODING_ANY) - && (encoding != PA.ENCODING_PCM)) - continue; - - int channels - = PA.format_info_get_prop_int( - format, - PA.PROP_FORMAT_CHANNELS); - - if (channels <= 0) - { - channels = sampleSpecChannels; - if (channels <= 0) - continue; - } - - int rate - = PA.format_info_get_prop_int( - format, - PA.PROP_FORMAT_RATE); - - if (rate <= 0) - { - rate = sampleSpecRate; - if (rate <= 0) - continue; - } - - if ((MediaUtils.MAX_AUDIO_CHANNELS != Format.NOT_SPECIFIED) - && (MediaUtils.MAX_AUDIO_CHANNELS < channels)) - channels = MediaUtils.MAX_AUDIO_CHANNELS; - if ((MediaUtils.MAX_AUDIO_SAMPLE_RATE != Format.NOT_SPECIFIED) - && (MediaUtils.MAX_AUDIO_SAMPLE_RATE < rate)) - rate = (int) MediaUtils.MAX_AUDIO_SAMPLE_RATE; - - AudioFormat audioFormat - = new AudioFormat( - AudioFormat.LINEAR, - rate, - 16, - channels, - AudioFormat.LITTLE_ENDIAN, - AudioFormat.SIGNED, - Format.NOT_SPECIFIED /* frameSizeInBits */, - Format.NOT_SPECIFIED /* frameRate */, - Format.byteArray); - - if (!sourceInfoFormatList.contains(audioFormat)) - { - sourceInfoFormatList.add(audioFormat); - if (!formatList.contains(audioFormat)) - formatList.add(audioFormat); - } - } + sourceInfoFormatList.add(audioFormat); + if (!formatList.contains(audioFormat)) + formatList.add(audioFormat); + } + if (!formatList.isEmpty()) + { + String description = PA.source_info_get_description(sourceInfo); + String name = PA.source_info_get_name(sourceInfo); - if (!formatList.isEmpty()) - { - String description = PA.source_info_get_description(sourceInfo); - String name = PA.source_info_get_name(sourceInfo); - - if (description == null) - description = name; - deviceList.add( - new CaptureDeviceInfo( - description, - new MediaLocator( - LOCATOR_PROTOCOL - + ":" - + name), - sourceInfoFormatList.toArray( - new Format[ - sourceInfoFormatList - .size()]))); - } + if (description == null) + description = name; + deviceList.add( + new CaptureDeviceInfo( + description, + new MediaLocator( + LOCATOR_PROTOCOL + + ":" + + name), + sourceInfoFormatList.toArray( + new Format[sourceInfoFormatList.size()]))); } } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/pulseaudio/DataSource.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/pulseaudio/DataSource.java index 88a94f922..209dd1ca5 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/pulseaudio/DataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/pulseaudio/DataSource.java @@ -7,6 +7,7 @@ package net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.pulseaudio; import java.io.*; +import java.util.*; import javax.media.*; import javax.media.control.*; @@ -33,7 +34,40 @@ public class DataSource private static final int FRAGSIZE_IN_TENS_OF_MILLIS = 2; - private static final boolean SOFTWARE_GAIN = false; + private static final boolean SOFTWARE_GAIN; + + static { + boolean softwareGain = true; + + try + { + String libraryVersion = PA.get_library_version(); + + if (libraryVersion != null) + { + StringTokenizer st = new StringTokenizer(libraryVersion, "."); + int major = Integer.parseInt(st.nextToken()); + int minor = Integer.parseInt(st.nextToken()); + + if ((major >= 1) && (minor >= 0)) + { + softwareGain = false; + if (logger.isDebugEnabled()) + { + logger.debug( + "Will control the volume" + + " through the native PulseAudio API."); + } + } + } + } + catch (Throwable t) + { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + } + SOFTWARE_GAIN = softwareGain; + } private class PulseAudioStream extends AbstractPullBufferStream diff --git a/src/net/java/sip/communicator/impl/neomedia/pulseaudio/PA.java b/src/net/java/sip/communicator/impl/neomedia/pulseaudio/PA.java index 971ae8c98..9f221c252 100644 --- a/src/net/java/sip/communicator/impl/neomedia/pulseaudio/PA.java +++ b/src/net/java/sip/communicator/impl/neomedia/pulseaudio/PA.java @@ -158,6 +158,8 @@ public static native long context_set_source_output_volume( public static native int format_info_get_prop_int(long f, String key); + public static native String get_library_version(); + public static native int operation_get_state(long o); public static native void operation_unref(long o);