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);