diff --git a/lib/native/linux-64/libjnopus.so b/lib/native/linux-64/libjnopus.so new file mode 100755 index 0000000000000000000000000000000000000000..9d0952dc571f87a56c172521fa4e46a1a4778381 Binary files /dev/null and b/lib/native/linux-64/libjnopus.so differ diff --git a/lib/native/linux/libjnopus.so b/lib/native/linux/libjnopus.so new file mode 100755 index 0000000000000000000000000000000000000000..b5450721bc4fe97b7f3dcd1bae16e2bba195e836 Binary files /dev/null and b/lib/native/linux/libjnopus.so differ diff --git a/lib/native/mac/libjnopus.jnilib b/lib/native/mac/libjnopus.jnilib new file mode 100755 index 0000000000000000000000000000000000000000..7b58804f5b41e2c9dfb88a3ce0fa9d1be6a6ab7c Binary files /dev/null and b/lib/native/mac/libjnopus.jnilib differ diff --git a/lib/native/windows-64/jnopus.dll b/lib/native/windows-64/jnopus.dll new file mode 100755 index 0000000000000000000000000000000000000000..02ddb34c378d3712b74771d49786b056e48e8bc5 Binary files /dev/null and b/lib/native/windows-64/jnopus.dll differ diff --git a/lib/native/windows/jnopus.dll b/lib/native/windows/jnopus.dll new file mode 100755 index 0000000000000000000000000000000000000000..961fb5be44ddfe082a3dd9b8558ce7c69c2f8864 Binary files /dev/null and b/lib/native/windows/jnopus.dll differ diff --git a/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.c b/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.c new file mode 100644 index 0000000000000000000000000000000000000000..55058e782d74c31806bf0f2ca957fc155af6037b --- /dev/null +++ b/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.c @@ -0,0 +1,225 @@ +#include "org_jitsi_impl_neomedia_codec_audio_opus_Opus.h" +#include <stdint.h> +#include <opus.h> + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1size + (JNIEnv *enc, jclass clazz, jint channels) +{ + return opus_encoder_get_size(channels); +} + +JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1create + (JNIEnv *env, jclass clazz, jint Fs, jint channels) +{ + int e; + OpusEncoder *enc = opus_encoder_create(Fs, channels, OPUS_APPLICATION_VOIP, &e); + + if(e != OPUS_OK) + { + return (jlong) 0; + } + + return (jlong) (intptr_t) enc; +} + +JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1destroy + (JNIEnv *env, jclass clazz, jlong encoder) +{ + opus_encoder_destroy((OpusEncoder *)(intptr_t) encoder); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1bitrate + (JNIEnv *env, jclass clazz, jlong encoder, jint bitrate) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_BITRATE(bitrate)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1bitrate + (JNIEnv *env, jclass clazz, jlong encoder) +{ + int x, ret; + ret = opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_GET_BITRATE(&x)); + if(ret < 0) + return ret; + return x; +} + + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1bandwidth + (JNIEnv *env, jclass clazz, jlong encoder, jint bandwidth) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_BANDWIDTH(bandwidth)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1bandwidth + (JNIEnv *env, jclass clazz, jlong encoder) +{ + int x, ret; + ret = opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_GET_BANDWIDTH(&x)); + if(ret<0) return ret; + return x; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1vbr + (JNIEnv *env, jclass clazz, jlong encoder, jint use_vbr) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_VBR(use_vbr)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1vbr_1constraint + (JNIEnv *env, jclass clazz, jlong encoder, jint use_cvbr) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_VBR_CONSTRAINT(use_cvbr)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1complexity + (JNIEnv *env, jclass clazz, jlong encoder, jint complexity) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_COMPLEXITY(complexity)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1inband_1fec + (JNIEnv *env, jclass clazz, jlong encoder, jint use_inband_fec) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_INBAND_FEC(use_inband_fec)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1force_1channels + (JNIEnv *env, jclass clazz, jlong encoder, jint forcechannels) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_FORCE_CHANNELS(forcechannels)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1dtx + (JNIEnv *env, jclass clazz, jlong encoder, jint use_dtx) +{ + return (jint) opus_encoder_ctl((OpusEncoder *)(intptr_t)encoder, OPUS_SET_DTX(use_dtx)); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encode + (JNIEnv *env, jclass clazz, jlong encoder, jbyteArray input, jint inputOffset, jint frameSize, jbyteArray output, jint outputSize) +{ + jbyte *inputPtr = (*env)->GetByteArrayElements(env, input, NULL); + jbyte *outputPtr = (*env)->GetByteArrayElements(env, output, NULL); + jint ret; + + if (inputPtr && outputPtr) + { + ret = opus_encode((OpusEncoder *)(intptr_t)encoder, + (opus_int16 *) (inputPtr + inputOffset), + (int) frameSize, + (unsigned char *)outputPtr, + (int) outputSize); + } + else + ret = 0; + + if(inputPtr) + (*env)->ReleaseByteArrayElements(env, input, inputPtr, JNI_ABORT); + if(outputPtr) + (*env)->ReleaseByteArrayElements(env, output, outputPtr, 0); + + return ret; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1get_1size + (JNIEnv *env, jclass clazz, jint channels) +{ + return opus_decoder_get_size(channels); +} + +JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1create + (JNIEnv *env, jclass clazz, jint Fs, jint channels) +{ + int e; + OpusDecoder *decoder = opus_decoder_create(Fs, channels, &e); + + if(e != OPUS_OK) + { + return (jlong) 0; + } + return (jlong)(intptr_t) decoder; +} + +JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1destroy + (JNIEnv *env, jclass clazz, jlong decoder) +{ + opus_decoder_destroy((OpusDecoder *)(intptr_t)decoder); +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decode + (JNIEnv *env, jclass clazz, jlong decoder, jbyteArray input, jint inputOffset, jint inputSize, jbyteArray output, jint outputSize) +{ + jbyte *inputPtr = (*env)->GetByteArrayElements(env, input, NULL); + jbyte *outputPtr = (*env)->GetByteArrayElements(env, output, NULL); + jint ret; + + if (inputPtr && outputPtr) + { + ret = opus_decode((OpusDecoder *)(intptr_t)decoder, + (unsigned char *) ((char *)inputPtr + inputOffset), + (int) inputSize, + (opus_int16 *)outputPtr, + (int) outputSize, + 0); + } + else + ret = 0; + + if(inputPtr) + (*env)->ReleaseByteArrayElements(env, input, inputPtr, JNI_ABORT); + if(outputPtr) + (*env)->ReleaseByteArrayElements(env, output, outputPtr, 0); + + return ret; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1bandwidth + (JNIEnv *env, jclass clazz, jbyteArray packet, jint offset) +{ + jbyte *packetPtr = (*env)->GetByteArrayElements(env, packet, NULL); + jint bandwidth = 0; + if(packetPtr){ + bandwidth = (jint) opus_packet_get_bandwidth((unsigned char *)packetPtr+offset); + (*env)->ReleaseByteArrayElements(env, packet, packetPtr, JNI_ABORT); + } + return bandwidth; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1nb_1channels + (JNIEnv *env, jclass clazz, jbyteArray packet, jint offset) +{ + jbyte *packetPtr = (*env)->GetByteArrayElements(env, packet, NULL); + jint channels = 0; + if(packetPtr){ + channels = (jint) opus_packet_get_nb_channels((unsigned char *)packetPtr+offset); + (*env)->ReleaseByteArrayElements(env, packet, packetPtr, JNI_ABORT); + } + return channels; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1nb_1frames + (JNIEnv *env, jclass clazz, jbyteArray packet, jint offset, jint len) +{ + jbyte *packetPtr = (*env)->GetByteArrayElements(env, packet, NULL); + jint frames = 0; + if(packetPtr){ + frames = (jint) opus_packet_get_nb_frames((unsigned char *)packetPtr+offset, len); + (*env)->ReleaseByteArrayElements(env, packet, packetPtr, JNI_ABORT); + } + return frames; +} + +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1get_1nb_1samples + (JNIEnv *env, jclass clazz, jlong decoder, jbyteArray packet, jint offset, jint len) +{ + int samples= 0; + jbyte *packetPtr = (*env)->GetByteArrayElements(env, packet, NULL); + if(decoder && packetPtr) + { + samples = opus_decoder_get_nb_samples((OpusDecoder*)(intptr_t)decoder, (unsigned char *)packetPtr+offset, len); + } + if(packetPtr) + (*env)->ReleaseByteArrayElements(env, packet, packetPtr, JNI_ABORT); + return samples; +} diff --git a/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.h b/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.h new file mode 100644 index 0000000000000000000000000000000000000000..57f053967070e5e897a74d5d86111cfa5725b592 --- /dev/null +++ b/src/native/opus/org_jitsi_impl_neomedia_codec_audio_opus_Opus.h @@ -0,0 +1,205 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_jitsi_impl_neomedia_codec_audio_opus_Opus */ + +#ifndef _Included_org_jitsi_impl_neomedia_codec_audio_opus_Opus +#define _Included_org_jitsi_impl_neomedia_codec_audio_opus_Opus +#ifdef __cplusplus +extern "C" { +#endif +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_NARROWBAND +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_NARROWBAND 1101L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_MEDIUMBAND +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_MEDIUMBAND 1102L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_WIDEBAND +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_WIDEBAND 1103L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_SUPERWIDEBAND +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_SUPERWIDEBAND 1104L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_FULLBAND +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_BANDWIDTH_FULLBAND 1105L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_OPUS_OK +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_OPUS_OK 0L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_INVALID_PACKET +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_INVALID_PACKET -4L +#undef org_jitsi_impl_neomedia_codec_audio_opus_Opus_MAX_PACKET +#define org_jitsi_impl_neomedia_codec_audio_opus_Opus_MAX_PACKET 1276L +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_get_size + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1size + (JNIEnv *, jclass, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_create + * Signature: (II)J + */ +JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1create + (JNIEnv *, jclass, jint, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_destroy + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1destroy + (JNIEnv *, jclass, jlong); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_bitrate + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1bitrate + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_get_bitrate + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1bitrate + (JNIEnv *, jclass, jlong); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_bandwidth + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1bandwidth + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_get_bandwidth + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1get_1bandwidth + (JNIEnv *, jclass, jlong); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_vbr + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1vbr + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_vbr_constraint + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1vbr_1constraint + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_complexity + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1complexity + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_inband_fec + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1inband_1fec + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_force_channels + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1force_1channels + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encoder_set_dtx + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1dtx + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: encode + * Signature: (J[BII[BI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encode + (JNIEnv *, jclass, jlong, jbyteArray, jint, jint, jbyteArray, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: decoder_get_size + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1get_1size + (JNIEnv *, jclass, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: decoder_create + * Signature: (II)J + */ +JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1create + (JNIEnv *, jclass, jint, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: decoder_destroy + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1destroy + (JNIEnv *, jclass, jlong); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: decode + * Signature: (J[BII[BI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decode + (JNIEnv *, jclass, jlong, jbyteArray, jint, jint, jbyteArray, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: packet_get_bandwidth + * Signature: ([BI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1bandwidth + (JNIEnv *, jclass, jbyteArray, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: packet_get_nb_channels + * Signature: ([BI)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1nb_1channels + (JNIEnv *, jclass, jbyteArray, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: packet_get_nb_frames + * Signature: ([BII)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1nb_1frames + (JNIEnv *, jclass, jbyteArray, jint, jint); + +/* + * Class: org_jitsi_impl_neomedia_codec_audio_opus_Opus + * Method: decoder_get_nb_samples + * Signature: (J[BII)I + */ +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_decoder_1get_1nb_1samples + (JNIEnv *, jclass, jlong, jbyteArray, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java index 73acc614d36e54f6ba1423925ea4e509777b2739..c692b2ae8d2b5171955211cf4a8ed54e1d73d988 100644 --- a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java +++ b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java @@ -1509,7 +1509,10 @@ private static void setupFMJ() } /** - * Returns a new <tt>EncodingConfiguration</tt> instance. + * Returns a new {@link EncodingConfiguration} instance that can be + * used by other bundles. + * + * @return a new {@link EncodingConfiguration} instance. */ public EncodingConfiguration getNewEncodingConfiguration() { diff --git a/src/org/jitsi/impl/neomedia/MediaUtils.java b/src/org/jitsi/impl/neomedia/MediaUtils.java index d79ced779ebf269f7dfd4ab2f30a01fcf2873429..f56d34dc5a14ac61bd2f9748cc3d9682316f4602 100644 --- a/src/org/jitsi/impl/neomedia/MediaUtils.java +++ b/src/org/jitsi/impl/neomedia/MediaUtils.java @@ -169,6 +169,12 @@ public class MediaUtils MediaType.AUDIO, Constants.TELEPHONE_EVENT, 8000); + addMediaFormats( + MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN, + "opus", + MediaType.AUDIO, + Constants.OPUS_RTP, + 48000); /* * We don't really support these. diff --git a/src/org/jitsi/impl/neomedia/codec/Constants.java b/src/org/jitsi/impl/neomedia/codec/Constants.java index 43decdc6f84f247efd6ef2e60e58d311ba76f3ad..fb9529394b6255554d5a300b0ee7bfb8d4b61ea5 100644 --- a/src/org/jitsi/impl/neomedia/codec/Constants.java +++ b/src/org/jitsi/impl/neomedia/codec/Constants.java @@ -63,6 +63,11 @@ public class Constants */ public static final String SPEEX_RTP = "speex/rtp"; + /** + * The OPUS/RTP constant. + */ + public static final String OPUS_RTP = "opus/rtp"; + /** * The H264 constant. */ diff --git a/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java b/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java index 59035585075d8ab1021912330e35c09199ef34f2..358875d4ac266da419cb6acbeb9b7a854ede1f8c 100644 --- a/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java +++ b/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java @@ -55,6 +55,8 @@ public class EncodingConfigurationImpl extends EncodingConfiguration "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaDecoder", "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaEncoder", "org.jitsi.impl.neomedia.codec.audio.ulaw.Packetizer", + "org.jitsi.impl.neomedia.codec.audio.opus.JNIDecoder", + "org.jitsi.impl.neomedia.codec.audio.opus.JNIEncoder", "org.jitsi.impl.neomedia.codec.audio.speex.JNIDecoder", "org.jitsi.impl.neomedia.codec.audio.speex.JNIEncoder", "org.jitsi.impl.neomedia.codec.audio.speex.SpeexResampler", @@ -171,6 +173,7 @@ private void initializeFormatPreferences() setEncodingPreference("SILK", 12000, 0); setEncodingPreference("SILK", 8000, 0); setEncodingPreference("G729", 8000, 0 /* proprietary */); + setEncodingPreference("opus", 48000, 2); // enables by default telephone event(DTMF rfc4733), with lowest // priority as it is not needed to order it with audio codecs diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java new file mode 100644 index 0000000000000000000000000000000000000000..82f82c441221b2b47d4434f13d1e0d56ecd0b04b --- /dev/null +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java @@ -0,0 +1,247 @@ +/* + * 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.codec.audio.opus; + +import javax.media.*; +import javax.media.format.*; + +import net.sf.fmj.media.*; +import org.jitsi.impl.neomedia.codec.*; + +/** + * Implements an Opus decoder + * + * @author Boris Grozec + */ +public class JNIDecoder + extends AbstractCodecExt +{ + /** + * The list of <tt>Format</tt>s of audio data supported as input by + * <tt>JNIDecoder</tt> instances. + */ + private static final Format[] SUPPORTED_INPUT_FORMATS; + + /** + * The list of <tt>Format</tt>s of audio data supported as output by + * <tt>JNIDecoder</tt> instances. + */ + private static final Format[] SUPPORTED_OUTPUT_FORMATS + = new Format[] + { + new AudioFormat( + AudioFormat.LINEAR, + 48000, + 16, + 1, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray) + }; + + static + { + SUPPORTED_INPUT_FORMATS + = new Format[] {new AudioFormat(Constants.OPUS_RTP)}; + } + + /** + * Pointer to the native OpusDecoder structure + */ + private long decoder = 0; + + /** + * Number of channels + */ + private int channels = 1; + + /** + * Output sampling rate + */ + private int outputSamplingRate = 48000; + + /** + * Initializes a new <tt>JNIDecoder</tt> instance. + */ + public JNIDecoder() + { + super( + "Opus JNI Decoder", + AudioFormat.class, + SUPPORTED_OUTPUT_FORMATS); + + inputFormats = SUPPORTED_INPUT_FORMATS; + } + + /** + * @see AbstractCodecExt#doClose() + */ + protected void doClose() + { + if (decoder != 0) + { + Opus.decoder_destroy(decoder); + } + } + + /** + * Opens this <tt>Codec</tt> and acquires the resources that it needs to + * operate. A call to {@link PlugIn#open()} on this instance will result in + * a call to <tt>doOpen</tt> only if {@link AbstractCodec#opened} is + * <tt>false</tt>. All required input and/or output formats are assumed to + * have been set on this <tt>Codec</tt> before <tt>doOpen</tt> is called. + * + * @throws ResourceUnavailableException if any of the resources that this + * <tt>Codec</tt> needs to operate cannot be acquired + * @see AbstractCodecExt#doOpen() + */ + protected void doOpen() + throws ResourceUnavailableException + { + decoder = Opus.decoder_create(outputSamplingRate, channels); + if (decoder == 0) + throw new ResourceUnavailableException("opus_decoder_create"); + } + + /** + * Decodes an Opus packet + * + * @param inputBuffer input <tt>Buffer</tt> + * @param outputBuffer output <tt>Buffer</tt> + * @return <tt>BUFFER_PROCESSED_OK</tt> if <tt>inBuffer</tt> has been + * successfully processed + * @see AbstractCodecExt#doProcess(Buffer, Buffer) + */ + protected int doProcess(Buffer inputBuffer, Buffer outputBuffer) + { + Format inputFormat = inputBuffer.getFormat(); + + if ((inputFormat != null) + && (inputFormat != this.inputFormat) + && !inputFormat.equals(this.inputFormat)) + { + if (null == setInputFormat(inputFormat)) + return BUFFER_PROCESSED_FAILED; + } + inputFormat = this.inputFormat; + + byte[] input = (byte[]) inputBuffer.getData(); + int inputOffset = inputBuffer.getOffset(); + int inputLength = inputBuffer.getLength(); + + int outputLength = Opus.decoder_get_nb_samples(decoder, + input, inputOffset, inputLength) * 2 /* sizeof(short) */; + byte[] output = validateByteArraySize(outputBuffer, outputLength); + + int samplesCount = Opus.decode(decoder, input, inputOffset, inputLength, + output, outputLength); + + if (samplesCount > 0) + { + outputBuffer.setDuration( + (samplesCount*1000*1000)/outputSamplingRate); + outputBuffer.setFormat(getOutputFormat()); + outputBuffer.setLength(2*samplesCount); //16bit pcm + outputBuffer.setOffset(0); + } + else + { + outputBuffer.setLength(0); + discardOutputBuffer(outputBuffer); + } + + return BUFFER_PROCESSED_OK; + } + + /** + * Get all supported output <tt>Format</tt>s. + * + * @param inputFormat input <tt>Format</tt> to determine corresponding output + * <tt>Format/tt>s + * @return array of supported <tt>Format</tt> + * @see AbstractCodecExt#getMatchingOutputFormats(Format) + */ + @Override + protected Format[] getMatchingOutputFormats(Format inputFormat) + { + AudioFormat inputAudioFormat = (AudioFormat) inputFormat; + + return + new Format[] + { + new AudioFormat( + AudioFormat.LINEAR, + inputAudioFormat.getSampleRate(), + 16, + 1, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray) + }; + } + + /** + * Sets the <tt>Format</tt> of the media data to be input for processing in + * this <tt>Codec</tt>. + * + * @param format the <tt>Format</tt> of the media data to be input for + * processing in this <tt>Codec</tt> + * @return the <tt>Format</tt> of the media data to be input for processing + * in this <tt>Codec</tt> if <tt>format</tt> is compatible with this + * <tt>Codec</tt>; otherwise, <tt>null</tt> + * @see AbstractCodecExt#setInputFormat(Format) + */ + @Override + public Format setInputFormat(Format format) + { + Format inputFormat = super.setInputFormat(format); + + if (inputFormat != null) + { + double outputSampleRate; + int outputChannels; + + if (outputFormat == null) + { + outputSampleRate = Format.NOT_SPECIFIED; + outputChannels = Format.NOT_SPECIFIED; + } + else + { + AudioFormat outputAudioFormat = (AudioFormat) outputFormat; + + outputSampleRate = outputAudioFormat.getSampleRate(); + outputChannels = outputAudioFormat.getChannels(); + } + + AudioFormat inputAudioFormat = (AudioFormat) inputFormat; + double inputSampleRate = inputAudioFormat.getSampleRate(); + int inputChannels = inputAudioFormat.getChannels(); + + if ((outputSampleRate != inputSampleRate) + || (outputChannels != inputChannels)) + { + setOutputFormat( + new AudioFormat( + AudioFormat.LINEAR, + inputSampleRate, + 16, + inputChannels, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray)); + } + } + return inputFormat; + } +} diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java new file mode 100644 index 0000000000000000000000000000000000000000..34a06814f90c7e5dbf431ff143ab71f8eced4afe --- /dev/null +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java @@ -0,0 +1,414 @@ +/* + * 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.codec.audio.opus; + +import javax.media.*; +import javax.media.format.*; +import net.sf.fmj.media.*; +import org.jitsi.impl.neomedia.codec.*; + +/** + * Implements an opus encoder + * + * @author Boris Grozev + */ +public class JNIEncoder + extends AbstractCodecExt +{ + /** + * The list of <tt>Format</tt>s of audio data supported as input by + * <tt>JNIEncoder</tt> instances. + */ + private static final Format[] SUPPORTED_INPUT_FORMATS; + + /** + * The list of sample rates of audio data supported as input by + * <tt>JNIEncoder</tt> instances. + * This codec does support 8, 12, 16, 24 and 48kHz input. Just enable them + * here if needed. The reason lower rates are disabled is that enabling for + * example 8kHz causes FMJ to always use it. + */ + static final double[] SUPPORTED_INPUT_SAMPLE_RATES + = new double[] { 48000 }; + //= new double[] { 8000, 12000, 16000, 24000, 48000 }; + + /** + * The list of <tt>Format</tt>s of audio data supported as output by + * <tt>JNIEncoder</tt> instances. + */ + private static final Format[] SUPPORTED_OUTPUT_FORMATS + = new Format[] { new AudioFormat(Constants.OPUS_RTP) }; + + /** + * Set the supported input formats. + */ + static + { + int supportedInputCount = SUPPORTED_INPUT_SAMPLE_RATES.length; + + SUPPORTED_INPUT_FORMATS = new Format[supportedInputCount*2]; + for (int i = 0; i < supportedInputCount; i++) + { + SUPPORTED_INPUT_FORMATS[i] + = new AudioFormat( + AudioFormat.LINEAR, + SUPPORTED_INPUT_SAMPLE_RATES[i], + 16, + 1, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray); + } + for (int i = 0; i < supportedInputCount; i++) + { + SUPPORTED_INPUT_FORMATS[i+supportedInputCount] + = new AudioFormat( + AudioFormat.LINEAR, + SUPPORTED_INPUT_SAMPLE_RATES[i], + 16, + 2, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray); + } + } + + /** + * The bytes from an input <tt>Buffer</tt> from a previous call to + * {@link #process(Buffer, Buffer)} that this <tt>Codec</tt> didn't process + * because the total number of bytes was less than {@link #inputFrameSize()} + * need to be prepended to a subsequent input <tt>Buffer</tt> in order to + * process a total of {@link #inputFrameSize()} bytes. + */ + private byte[] previousInput = null; + + /** + * The length of the audio data in {@link #previousInput}. + */ + private int previousInputLength = 0; + + /** + * The pointer to the native OpusEncoder structure + */ + private long encoder = 0; + + /** + * Number of channels to use, default to 1. + */ + private int channels = 1; + + /** + * Frame size in ms (2.5, 5, 10, 20, 40 or 60). Default to 20 + */ + private double frameSize = 20; + + /** + * Returns the number of bytes that we need to read from the input buffer + * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input + * sample frequency, the number of channels and <tt>frameSize</tt> + * + * @return the number of bytes that we need to read from the input buffer + * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input + * sample frequency, the number of channels and <tt>frameSize</tt> + */ + private int inputFrameSize() + { + int fs = + (int) ( + 2 /* sizeof(short) */ + * channels + * ((AudioFormat)getInputFormat()).getSampleRate() /* samples in 1s */ + * frameSize /* milliseconds */ + ) / 1000; + + return fs; + } + + /** + * Initializes a new <tt>JNIEncoder</tt> instance. + */ + public JNIEncoder() + { + super("Opus JNI Encoder", + AudioFormat.class, + SUPPORTED_OUTPUT_FORMATS); + + inputFormats = SUPPORTED_INPUT_FORMATS; + } + + /** + * @see AbstractCodecExt#doClose() + */ + protected void doClose() + { + if (encoder != 0) + { + Opus.encoder_destroy(encoder); + } + } + + /** + * Opens this <tt>Codec</tt> and acquires the resources that it needs to + * operate. A call to {@link PlugIn#open()} on this instance will result in + * a call to <tt>doOpen</tt> only if {@link AbstractCodec#opened} is + * <tt>false</tt>. All required input and/or output formats are assumed to + * have been set on this <tt>Codec</tt> before <tt>doOpen</tt> is called. + * + * @throws ResourceUnavailableException if any of the resources that this + * <tt>Codec</tt> needs to operate cannot be acquired + * @see AbstractCodecExt#doOpen() + */ + protected void doOpen() + throws ResourceUnavailableException + { + + //TODO: make a ParametrizedAudioFormat (or something) class, and use it here + //to set the encoder parameters + AudioFormat inputFormat = (AudioFormat) getInputFormat(); + int sampleRate = (int)inputFormat.getSampleRate(); + channels = inputFormat.getChannels(); + + encoder = Opus.encoder_create(sampleRate, channels); + if (encoder == 0) + throw new ResourceUnavailableException("opus_encoder_create()"); + + //set default encoder settings + Opus.encoder_set_bitrate(encoder, 60000); + Opus.encoder_set_bandwidth(encoder, Opus.BANDWIDTH_FULLBAND); + Opus.encoder_set_vbr(encoder, 1); + Opus.encoder_set_complexity(encoder, 10); + Opus.encoder_set_inband_fec(encoder, 0); + Opus.encoder_set_dtx(encoder, 1); + Opus.encoder_set_force_channels(encoder, 1); + } + + /** + * Processes (encode) a specific input <tt>Buffer</tt>. + * + * @param inputBuffer input buffer + * @param outputBuffer output buffer + * @return <tt>BUFFER_PROCESSED_OK</tt> if buffer has been successfully + * processed + * @see AbstractCodecExt#doProcess(Buffer, Buffer) + */ + protected int doProcess(Buffer inputBuffer, Buffer outputBuffer) + { + Format inputFormat = inputBuffer.getFormat(); + + if ((inputFormat != null) + && (inputFormat != this.inputFormat) + && !inputFormat.equals(this.inputFormat)) + { + if (null == setInputFormat(inputFormat)) + return BUFFER_PROCESSED_FAILED; + } + inputFormat = this.inputFormat; + + byte[] input = (byte[]) inputBuffer.getData(); + int inputLength = inputBuffer.getLength(); + int inputOffset = inputBuffer.getOffset(); + + + int inputBytesNeeded = inputFrameSize(); + + if ((previousInput != null) && (previousInputLength > 0)) + { + if (previousInputLength < inputBytesNeeded) + { + if (previousInput.length < inputBytesNeeded) + { + byte[] newPreviousInput = new byte[inputBytesNeeded]; + + System.arraycopy( + previousInput, 0, + newPreviousInput, 0, + previousInput.length); + previousInput = newPreviousInput; + } + + int bytesToCopyFromInputToPreviousInput + = Math.min( + inputBytesNeeded - previousInputLength, + inputLength); + + if (bytesToCopyFromInputToPreviousInput > 0) + { + System.arraycopy( + input, inputOffset, + previousInput, previousInputLength, + bytesToCopyFromInputToPreviousInput); + previousInputLength += bytesToCopyFromInputToPreviousInput; + inputLength -= bytesToCopyFromInputToPreviousInput; + inputBuffer.setLength(inputLength); + inputBuffer.setOffset( + inputOffset + bytesToCopyFromInputToPreviousInput); + } + } + + if (previousInputLength == inputBytesNeeded) + { + input = previousInput; + inputOffset = 0; + previousInputLength = 0; + } + else + { + outputBuffer.setLength(0); + discardOutputBuffer(outputBuffer); + if (inputLength < 1) + return BUFFER_PROCESSED_OK; + else + return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED; + } + } + else if (inputLength < 1) + { + outputBuffer.setLength(0); + discardOutputBuffer(outputBuffer); + return BUFFER_PROCESSED_OK; + } + else if (inputLength < inputBytesNeeded) + { + if ((previousInput == null) || (previousInput.length < inputLength)) + previousInput = new byte[inputBytesNeeded]; + System.arraycopy(input, inputOffset, previousInput, 0, inputLength); + previousInputLength = inputLength; + outputBuffer.setLength(0); + discardOutputBuffer(outputBuffer); + return BUFFER_PROCESSED_OK; + } + else + { + inputLength -= inputBytesNeeded; + inputBuffer.setLength(inputLength); + inputBuffer.setOffset(inputOffset + inputBytesNeeded); + } + + + + /* At long last, do the actual encoding. */ + + byte[] output = validateByteArraySize(outputBuffer, Opus.MAX_PACKET); + + int outputLength = Opus.encode(encoder, input, inputOffset, + inputBytesNeeded / 2, output, Opus.MAX_PACKET); + + + if (outputLength < 0) //error from opus_encode + return BUFFER_PROCESSED_FAILED; + + if (outputLength > 0) + { + outputBuffer.setDuration((long) this.frameSize * 1000 * 1000); + outputBuffer.setFormat(getOutputFormat()); + outputBuffer.setLength(outputLength); + outputBuffer.setOffset(0); + } + + if (inputLength < 1) + return BUFFER_PROCESSED_OK; + else + return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED; + } + + /** + * Get the output format. + * + * @return output format + * @see net.sf.fmj.media.AbstractCodec#getOutputFormat() + */ + @Override + public Format getOutputFormat() + { + Format outputFormat = super.getOutputFormat(); + + if ((outputFormat != null) + && (outputFormat.getClass() == AudioFormat.class)) + { + AudioFormat outputAudioFormat = (AudioFormat) outputFormat; + + outputFormat = setOutputFormat( + new AudioFormat( + outputAudioFormat.getEncoding(), + outputAudioFormat.getSampleRate(), + outputAudioFormat.getSampleSizeInBits(), + outputAudioFormat.getChannels(), + outputAudioFormat.getEndian(), + outputAudioFormat.getSigned(), + outputAudioFormat.getFrameSizeInBits(), + outputAudioFormat.getFrameRate(), + outputAudioFormat.getDataType()) + { + private static final long serialVersionUID = 0L; + + @Override + public long computeDuration(long length) + { + return ((long) JNIEncoder.this.frameSize)*1000*1000; + } + }); + } + return outputFormat; + } + + /** + * Sets the input format. + * + * @param format format to set + * @return format + * @see AbstractCodecExt#setInputFormat(Format) + */ + @Override + public Format setInputFormat(Format format) + { + Format inputFormat = super.setInputFormat(format); + + if (inputFormat != null) + { + double outputSampleRate; + int outputChannels; + + if (outputFormat == null) + { + outputSampleRate = Format.NOT_SPECIFIED; + outputChannels = Format.NOT_SPECIFIED; + } + else + { + AudioFormat outputAudioFormat = (AudioFormat) outputFormat; + + outputSampleRate = outputAudioFormat.getSampleRate(); + outputChannels = outputAudioFormat.getChannels(); + } + + AudioFormat inputAudioFormat = (AudioFormat) inputFormat; + double inputSampleRate = inputAudioFormat.getSampleRate(); + int inputChannels = inputAudioFormat.getChannels(); + + if ((outputSampleRate != inputSampleRate) + || (outputChannels != inputChannels)) + { + setOutputFormat( + new AudioFormat( + Constants.SPEEX_RTP, + inputSampleRate, + Format.NOT_SPECIFIED, + inputChannels, + AudioFormat.LITTLE_ENDIAN, + AudioFormat.SIGNED, + Format.NOT_SPECIFIED, + Format.NOT_SPECIFIED, + Format.byteArray)); + } + } + return inputFormat; + } +} diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java new file mode 100644 index 0000000000000000000000000000000000000000..bf27ddaed3bf10ae4d3cdccdd39c52a02b2999ef --- /dev/null +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java @@ -0,0 +1,322 @@ +/* + * 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.codec.audio.opus; + +/** + * Implements an interface to the native opus library + */ +public class Opus +{ + /** + * Opus narrowband constant + */ + public static final int BANDWIDTH_NARROWBAND = 1101; + + /** + * Opus mediumband constant + */ + public static final int BANDWIDTH_MEDIUMBAND = 1102; + + /** + * Opus wideband constant + */ + public static final int BANDWIDTH_WIDEBAND = 1103; + + /** + * Opus superwideband constant + */ + public static final int BANDWIDTH_SUPERWIDEBAND = 1104; + + /** + * Opus fullband constant + */ + public static final int BANDWIDTH_FULLBAND = 1105; + + /** + * Constant usually indicating that no error occurred + */ + public static final int OPUS_OK = 0; + + /** + * Opus constant for an invalid packet + */ + public static final int INVALID_PACKET = -4; + + /** + * The maximum size of a packet we can create. Since we're only creating + * packets with a single frame, that's a 1 byte TOC + the maximum frame size. + * See http://tools.ietf.org/html/rfc6716#section-3.2 + */ + public static final int MAX_PACKET = 1+1275; + + + + /** + * Returns the size in bytes required for an OpusEncoder structure. + * + * @param channels number of channels (1/2) + * + * @return the size in bytes required for an OpusEncoder structure. + */ + public static native int encoder_get_size(int channels); + + /** + * Creates an OpusEncoder structure, returns a pointer to it casted to long. + * The native function's <tt>application</tt> parameter is always set to + * OPUS_APPLICATION_VOIP. + * + * @param Fs Sample rate of the input PCM + * @param channels number of channels in the input (1/2) + * + * @return A pointer to the OpusEncoder structure created, 0 on error + */ + public static native long encoder_create(int Fs, int channels); + + /** + * Destroys an OpusEncoder, freeing it's resources. + * + * @param encoder Address of the structure (as returned from encoder_create) + */ + public static native void encoder_destroy(long encoder); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder bitrate + * + * @param encoder The encoder to use + * @param bitrate The bitrate to set + * + * @return OPUS_OK on success + */ + public static native int encoder_set_bitrate(long encoder, int bitrate); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the + * current encoder bitrate. + * + * @param encoder The encoder to use + * + * @return The current encoder bitrate. + */ + public static native int encoder_get_bitrate(long encoder); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder audio bandwidth. + * + * @param encoder The encoder to use + * @param bandwidth The bandwidth to set, should be one of + * <tt>BANDWIDTH_FULLBAND</tt>, <tt>BANDWIDTH_MEDIUMBAND</tt>, + * <tt>BANDWIDTH_NARROWBAND</tt>, <tt>BANDWIDTH_SUPERWIDEBAND</tt> or + * <tt>BANDWIDTH_WIDEBAND</tt>. + * + * @return OPUS_OK on success + */ + public static native int encoder_set_bandwidth(long encoder, int bandwidth); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the + * current encoder audio bandwidth + * . + * @param encoder The encoder to use + * + * @return the current encoder audio bandwidth + */ + public static native int encoder_get_bandwidth(long encoder); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder VBR setting + * + * @param encoder The encoder to use + * @param use_vbr 0 to turn VBR off, non-zero to turn it on. + * + * @return OPUS_OK on success + */ + public static native int encoder_set_vbr(long encoder, int use_vbr); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder VBR constraint setting + * + * @param encoder The encoder to use + * @param use_cvbr 0 to turn VBR constraint off, non-zero to turn it on. + * + * @return OPUS_OK on success + */ + public static native int encoder_set_vbr_constraint(long encoder, + int use_cvbr); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder complexity setting. + * + * @param encoder The encoder to use + * @param complexity The complexity level, from 1 to 10 + * + * @return OPUS_OK on success + */ + public static native int encoder_set_complexity(long encoder, + int complexity); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder FEC setting. + * @param encoder The encoder to use + * @param use_inband_fec 0 to turn FEC off, non-zero to turn it on. + * + * @return OPUS_OK on success + */ + public static native int encoder_set_inband_fec(long encoder, + int use_inband_fec); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * force channels setting of the encoder. + * + * @param encoder The encoder to use + * @param forcechannels Number of channels + * + * @return OPUS_OK on success + */ + public static native int encoder_set_force_channels(long encoder, + int forcechannels); + + /** + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * DTX setting of the encoder. + * + * @param encoder The encoder to use + * @param use_dtx 0 to turn DTX off, non-zero to turn it on + * + * @return OPUS_OK on success + */ + public static native int encoder_set_dtx(long encoder, int use_dtx); + + /** + * Encodes the input from <tt>input</tt> into an opus packet in + * <tt>output</tt>. + * + * @param encoder The encoder to use. + * @param input Array containing PCM encoded input. + * @param offset Offset to use into the <tt>input</tt> array + * @param frameSize The number of samples per channel in <tt>input</tt>. + * @param output Array where the encoded packet will be stored. + * @param outputSize The number of available bytes in <tt>output</tt>. + * + * @return The number of bytes written in <tt>output</tt>, or a negative + * on error. + */ + public static native int encode(long encoder, byte[] input, int offset, + int frameSize, byte[] output, + int outputSize); + + + + + /** + * Returns the size in bytes required for an OpusDecoder structure. + * + * @param channels number of channels (1/2) + * + * @return the size in bytes required for an OpusDecoder structure. + */ + public static native int decoder_get_size(int channels); + + /** + * Creates an OpusDecoder structure, returns a pointer to it or 0 on error. + * + * @param Fs Sample rate to decode to + * @param channels number of channels to decode to(1/2) + * + * @return A pointer to the OpusDecoder structure created, 0 on error. + */ + public static native long decoder_create(int Fs, int channels); + + /** + * Destroys an OpusDecoder, freeing it's resources. + * + * @param decoder Address of the structure (as returned from decoder_create) + */ + public static native void decoder_destroy(long decoder); + + /** + * Decodes an opus packet from <tt>input</tt> into <tt>output</tt>. + * + * @param decoder The decoder to use + * @param input An array containing the opus packet. + * @param inputOffset The offset into <tt>input</tt> where the packets + * begins. + * @param inputSize Size of the packet in bytes. + * @param output Output buffer where the output will be stored. + * @param outputSize Size in bytes of the output buffer. + * + * @return Number of samples decoded + */ + public static native int decode(long decoder, byte[] input, int inputOffset, + int inputSize, byte[] output, + int outputSize); + + /** + * Returns the audio bandwidth of an opus packet, one of + * <tt>BANDWIDTH_FULLBAND</tt>, <tt>BANDWIDTH_MEDIUMBAND</tt>, + * <tt>BANDWIDTH_NARROWBAND</tt>, <tt>BANDWIDTH_SUPERWIDEBAND</tt> or + * <tt>BANDWIDTH_WIDEBAND</tt>, or <tt>INVALID_PACKET</tt> on error. + * + * @param packet Array holding the packet. + * @param offset Offset into packet where the actual packet begins. + * + * @return one of <tt>BANDWIDTH_FULLBAND</tt>, + * <tt>BANDWIDTH_MEDIUMBAND</tt>, <tt>BANDWIDTH_NARROWBAND</tt>, + * <tt>BANDWIDTH_SUPERWIDEBAND</tt>, <tt>BANDWIDTH_WIDEBAND</tt>, + * or <tt>INVALID_PACKET</tt> on error. + */ + public static native int packet_get_bandwidth(byte[] packet, int offset); + + /** + * Returns the number of channels encoded in an opus packet. + * + * @param packet Array holding the packet. + * @param offset Offset into packet where the actual packet begins. + * + * @return the number of channels encoded in <tt>packet</tt>. + */ + public static native int packet_get_nb_channels(byte[] packet, int offset); + + /** + * Returns the number of frames in an opus packet. + * + * @param packet Array holding the packet. + * @param offset Offset into packet where the actual packet begins. + * @param len Length of the packet. + * + * @return the number of frames in <tt>packet</tt>. + */ + public static native int packet_get_nb_frames(byte[] packet, int offset, + int len); + + /** + * Returns the number of samples in an opus packet + + * @param decoder The decoder to use. + * @param packet Array holding the packet. + * @param offset Offset into packet where the actual packet begins. + * @param len Length of the packet. + * + * @return the number of samples in <tt>packet</tt> . + */ + public static native int decoder_get_nb_samples(long decoder, byte[] packet, int offset, int len); + + /** + * Load the native library. + */ + static + { + System.loadLibrary("jnopus"); + } + +} diff --git a/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java b/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java index 8056231974fc709d9ec65db7fff00d301f84cf5d..4923402ea294bc85bc8c1ce2e5a8fd8c8e98139b 100644 --- a/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java +++ b/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java @@ -472,7 +472,7 @@ private List<MediaFormat> getSupportedMediaFormats( .getEncodingConfiguration(); List<MediaFormat> supportedMediaFormats = getMatchingMediaFormats( - encodingConfiguration.getSupportedEncodings( + encodingConfiguration.getAvailableEncodings( MediaType.AUDIO), encoding, clockRate); @@ -480,7 +480,7 @@ private List<MediaFormat> getSupportedMediaFormats( if (supportedMediaFormats.isEmpty()) supportedMediaFormats = getMatchingMediaFormats( - encodingConfiguration.getSupportedEncodings( + encodingConfiguration.getAvailableEncodings( MediaType.VIDEO), encoding, clockRate);