diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml
index 01390f56a..da5d2689e 100644
--- a/bootstrap/pom.xml
+++ b/bootstrap/pom.xml
@@ -89,6 +89,11 @@
ilbc${project.parent.version}
+
+ org.restcomm.media.codecs.opus
+ opus-java
+ ${project.version}
+
diff --git a/bootstrap/src/main/assembly/descriptor.xml b/bootstrap/src/main/assembly/descriptor.xml
index ae6668de6..e55039607 100644
--- a/bootstrap/src/main/assembly/descriptor.xml
+++ b/bootstrap/src/main/assembly/descriptor.xml
@@ -19,6 +19,22 @@
/libfalseruntime
+
+ *:so
+ *:dylib
+
+
+
+ lib/native
+ ${artifact.artifactId}.${artifact.extension}
+ false
+ runtime
+ false
+ false
+
+ *:so
+ *:dylib
+
diff --git a/bootstrap/src/main/config/autoconfig/mediaserver.conf b/bootstrap/src/main/config/autoconfig/mediaserver.conf
index b598be78c..3f9f0c660 100644
--- a/bootstrap/src/main/config/autoconfig/mediaserver.conf
+++ b/bootstrap/src/main/config/autoconfig/mediaserver.conf
@@ -15,7 +15,7 @@ MEDIA_MAX_DURATION=14440
MEDIA_LOW_PORT=64534
MEDIA_HIGH_PORT=65534
MEDIA_JITTER_SIZE=50
-MEDIA_CODECS=pcmu,pcma,telephone-event
+MEDIA_CODECS=opus,pcmu,pcma,telephone-event
# Resources
AUDIO_CACHE_SIZE=100
@@ -42,4 +42,4 @@ DTLS_ALGORITHM=ecdsa
#ASR_DRIVER_SOMEPROVIDER_PROPERTY_PARAMETER2_VALUE=parameter2_value
# Java
-MS_OPTS="-Xms3400m -Xmx3400m -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1RSetUpdatingPauseTimePercent=10 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=4m -XX:G1HeapWastePercent=5 -XX:InitiatingHeapOccupancyPercent=85 -XX:+UnlockExperimentalVMOptions -XX:G1MixedGCLiveThresholdPercent=85 -XX:+AlwaysPreTouch -XX:+UseCompressedOops -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dhttp.keepAlive=false"
\ No newline at end of file
+MS_OPTS="-Xms3400m -Xmx3400m -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1RSetUpdatingPauseTimePercent=10 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=4m -XX:G1HeapWastePercent=5 -XX:InitiatingHeapOccupancyPercent=85 -XX:+UnlockExperimentalVMOptions -XX:G1MixedGCLiveThresholdPercent=85 -XX:+AlwaysPreTouch -XX:+UseCompressedOops -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dhttp.keepAlive=false"
diff --git a/bootstrap/src/main/config/mediaserver.xml b/bootstrap/src/main/config/mediaserver.xml
index 9829c908a..c1d700b40 100644
--- a/bootstrap/src/main/config/mediaserver.xml
+++ b/bootstrap/src/main/config/mediaserver.xml
@@ -39,6 +39,7 @@
+
-
\ No newline at end of file
+
diff --git a/bootstrap/src/main/config/run.sh b/bootstrap/src/main/config/run.sh
index fa948d815..6e1b6a47b 100755
--- a/bootstrap/src/main/config/run.sh
+++ b/bootstrap/src/main/config/run.sh
@@ -50,9 +50,14 @@ esac
# Force IPv4 on Linux systems since IPv6 doesn't work correctly with jdk5 and lower
if [ "$linux" = "true" ]; then
- JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
+ JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true -Djava.library.path=/usr/lib/x86_64-linux-gnu:../lib/native -Drestcomm.opus.library=opus_jni_linux"
fi
+if [ "$darwin" = "true" ]; then
+ JAVA_OPTS="$JAVA_OPTS -Djava.library.path=../lib/native -Drestcomm.opus.library=opus_jni_macos"
+fi
+
+
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$MMS_HOME" ] &&
diff --git a/bootstrap/src/test/resources/mediaserver.xml b/bootstrap/src/test/resources/mediaserver.xml
index 91ff74b28..f3a080646 100644
--- a/bootstrap/src/test/resources/mediaserver.xml
+++ b/bootstrap/src/test/resources/mediaserver.xml
@@ -38,6 +38,7 @@
+
@@ -73,4 +74,4 @@
-
\ No newline at end of file
+
diff --git a/codecs/opus/opus-java/pom.xml b/codecs/opus/opus-java/pom.xml
new file mode 100644
index 000000000..09e4b077e
--- /dev/null
+++ b/codecs/opus/opus-java/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+ jar
+
+
+ org.restcomm.media.codecs
+ opus
+ 7.0.0-SNAPSHOT
+
+
+ org.restcomm.media.codecs.opus
+ opus-java
+ Opus Java
+
+
+
+ linux-profile
+
+
+ Linux
+ unix
+
+
+
+ libopus_jni_linux
+ so
+ linux
+ opus_jni_linux
+
+
+
+
+ macosx-profile
+
+
+ mac
+
+
+
+ libopus_jni_macos
+ dylib
+ macosx
+ opus_jni_macos
+
+
+
+
+
+
+ org.restcomm.media
+ spi
+ ${project.version}
+
+
+ org.restcomm.media.codecs.opus
+ ${libopus.artifactId}
+ ${project.version}
+ ${libopus.packaging}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ -Djava.library.path=../opus-native/${libopus.distro}/target -Drestcomm.opus.library=${libopus.libName}
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.7
+
+
+
+ restcomm-mediaserver-codecs-opus-${project.version}
+
+
+
diff --git a/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Decoder.java b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Decoder.java
new file mode 100644
index 000000000..2e8fcfb31
--- /dev/null
+++ b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Decoder.java
@@ -0,0 +1,91 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2017, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.restcomm.media.codec.opus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.log4j.Logger;
+import org.restcomm.media.spi.dsp.Codec;
+import org.restcomm.media.spi.format.Format;
+import org.restcomm.media.spi.format.FormatFactory;
+import org.restcomm.media.spi.memory.Frame;
+import org.restcomm.media.spi.memory.Memory;
+
+/**
+ * Implements Opus decoder.
+ *
+ * @author Vladimir Morosev (vladimir.morosev@telestax.com)
+ *
+ */
+public class Decoder implements Codec {
+
+ private final static Logger log = Logger.getLogger(Encoder.class);
+
+ private final static Format opus = FormatFactory.createAudioFormat("opus", 48000, 8, 2);
+ private final static Format linear = FormatFactory.createAudioFormat("linear", 8000, 16, 1);
+
+ private long decoderAddress;
+
+ private final int OPUS_SAMPLE_RATE = 8000;
+
+ public Decoder() {
+ decoderAddress = OpusJni.createDecoderNative(OPUS_SAMPLE_RATE, 1);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (decoderAddress != 0) OpusJni.releaseDecoderNative(decoderAddress);
+ super.finalize();
+ }
+
+ @Override
+ public Format getSupportedInputFormat() {
+ return opus;
+ }
+
+ @Override
+ public Format getSupportedOutputFormat() {
+ return linear;
+ }
+
+ @Override
+ public Frame process(Frame frame) {
+
+ short[] decodedData = OpusJni.decodeNative(decoderAddress, frame.getData());
+ byte[] output = new byte[2 * decodedData.length];
+ ByteBuffer.wrap(output).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(decodedData);
+
+ Frame res = Memory.allocate(output.length);
+ System.arraycopy(output, 0, res.getData(), 0, output.length);
+
+ res.setOffset(0);
+ res.setLength(output.length);
+ res.setTimestamp(frame.getTimestamp());
+ res.setDuration(frame.getDuration());
+ res.setSequenceNumber(frame.getSequenceNumber());
+ res.setEOM(frame.isEOM());
+ res.setFormat(linear);
+ res.setHeader(frame.getHeader());
+ return res;
+ }
+}
diff --git a/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Encoder.java b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Encoder.java
new file mode 100644
index 000000000..9f26488b9
--- /dev/null
+++ b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/Encoder.java
@@ -0,0 +1,93 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2017, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.restcomm.media.codec.opus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.log4j.Logger;
+import org.restcomm.media.spi.dsp.Codec;
+import org.restcomm.media.spi.format.Format;
+import org.restcomm.media.spi.format.FormatFactory;
+import org.restcomm.media.spi.memory.Frame;
+import org.restcomm.media.spi.memory.Memory;
+
+/**
+ * Implements Opus encoder.
+ *
+ * @author Vladimir Morosev (vladimir.morosev@telestax.com)
+ *
+ */
+public class Encoder implements Codec {
+
+ private final static Logger log = Logger.getLogger(Encoder.class);
+
+ private final static Format opus = FormatFactory.createAudioFormat("opus", 48000, 8, 2);
+ private final static Format linear = FormatFactory.createAudioFormat("linear", 8000, 16, 1);
+
+ private long encoderAddress;
+
+ private final int OPUS_SAMPLE_RATE = 8000;
+ private final int OPUS_BITRATE = 20000;
+
+ public Encoder() {
+ encoderAddress = OpusJni.createEncoderNative(OPUS_SAMPLE_RATE, 1, OpusJni.OPUS_APPLICATION_VOIP, OPUS_BITRATE);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ OpusJni.releaseEncoderNative(encoderAddress);
+ super.finalize();
+ }
+
+ @Override
+ public Format getSupportedInputFormat() {
+ return linear;
+ }
+
+ @Override
+ public Format getSupportedOutputFormat() {
+ return opus;
+ }
+
+ @Override
+ public Frame process(Frame frame) {
+
+ byte[] input = frame.getData();
+ short[] inputData = new short[frame.getLength() / 2];
+ ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(inputData);
+ byte[] encodedData = OpusJni.encodeNative(encoderAddress, inputData);
+
+ Frame res = Memory.allocate(encodedData.length);
+ System.arraycopy(encodedData, 0, res.getData(), 0, encodedData.length);
+
+ res.setOffset(0);
+ res.setLength(encodedData.length);
+ res.setFormat(opus);
+ res.setTimestamp(frame.getTimestamp());
+ res.setDuration(frame.getDuration());
+ res.setEOM(frame.isEOM());
+ res.setSequenceNumber(frame.getSequenceNumber());
+
+ return res;
+ }
+}
diff --git a/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/OpusJni.java b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/OpusJni.java
new file mode 100644
index 000000000..424a3a0f6
--- /dev/null
+++ b/codecs/opus/opus-java/src/main/java/org/restcomm/media/codec/opus/OpusJni.java
@@ -0,0 +1,68 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2017, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.restcomm.media.codec.opus;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Implements access to JNI layer for native Opus library.
+ *
+ * @author Vladimir Morosev (vladimir.morosev@telestax.com)
+ *
+ */
+public class OpusJni {
+
+ private static final Logger log = Logger.getLogger(OpusJni.class);
+
+ public final static int OPUS_APPLICATION_VOIP = 2048;
+ public final static int OPUS_APPLICATION_AUDIO = 2049;
+ public final static int OPUS_APPLICATION_RESTRICTED_LOWDELAY = 2051;
+
+ public static interface Observer {
+ public void onHello();
+ }
+
+ static {
+ String libraryName = System.getProperty("restcomm.opus.library");
+ if (libraryName != null) {
+ try {
+ System.loadLibrary(libraryName);
+ } catch (UnsatisfiedLinkError e) {
+ log.error("Failed to load native Opus library. " + e.getMessage());
+ throw e;
+ }
+ } else {
+ log.error("Native Opus library parameter has not been defined (restcomm.opus.library).");
+ }
+ }
+
+ public static native long createEncoderNative(int sampleRate, int channels, int application, int bitRate);
+ public static native long createDecoderNative(int sampleRate, int channels);
+ public static native void releaseEncoderNative(long encoderAddress);
+ public static native void releaseDecoderNative(long decoderAddress);
+ public static native byte[] encodeNative(long encoderAddress, short[] pcmData);
+ public static native short[] decodeNative(long decoderAddress, byte[] opusData);
+
+ public native void sayHelloNative();
+ public native void setOpusObserverNative(Observer observer);
+ public native void unsetOpusObserverNative();
+}
diff --git a/codecs/opus/opus-java/src/test/java/org/restcomm/media/codec/opus/OpusCodecTest.java b/codecs/opus/opus-java/src/test/java/org/restcomm/media/codec/opus/OpusCodecTest.java
new file mode 100644
index 000000000..fe6a0eadf
--- /dev/null
+++ b/codecs/opus/opus-java/src/test/java/org/restcomm/media/codec/opus/OpusCodecTest.java
@@ -0,0 +1,146 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2017, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.restcomm.media.codec.opus;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.restcomm.media.codec.opus.Decoder;
+import org.restcomm.media.codec.opus.Encoder;
+import org.restcomm.media.codec.opus.OpusJni;
+import org.restcomm.media.spi.memory.Frame;
+import org.restcomm.media.spi.memory.Memory;
+
+
+/**
+ * Opus codec test class
+ *
+ * @author Vladimir Morosev (vladimir.morosev@telestax.com)
+ *
+ */
+public class OpusCodecTest {
+
+ private static final Logger log = Logger.getLogger(OpusCodecTest.class);
+
+ private Frame buffer = Memory.allocate(512);
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ public OpusCodecTest() {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ buffer.setLength(512);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test of process method, for Encoder and Decoder.
+ */
+ @Test
+ public void testCodec() throws Exception {
+
+ boolean testPassed = false;
+
+ try {
+ final int packetSize = 480;
+ File outputFile = File.createTempFile("opustest", ".tmp");
+ URL inputFileUrl = this.getClass().getResource("/test_sound_mono_48.pcm");
+ Encoder encoder = new Encoder();
+ Decoder decoder = new Decoder();
+ try (FileInputStream inputStream = new FileInputStream(inputFileUrl.getFile());
+ FileOutputStream outputStream = new FileOutputStream(outputFile, false)) {
+ byte[] input = new byte[2 * packetSize];
+ short[] inputData = new short[packetSize];
+ while (inputStream.read(input) == 2 * packetSize) {
+ Frame inputFrame = Memory.allocate(2 * packetSize);
+ inputFrame.setOffset(0);
+ inputFrame.setLength(2 * packetSize);
+ inputFrame.setFormat(encoder.getSupportedInputFormat());
+ inputFrame.setTimestamp(System.currentTimeMillis());
+ inputFrame.setDuration(10);
+ System.arraycopy(input, 0, inputFrame.getData(), 0, 2 * packetSize);
+ Frame encodedFrame = encoder.process(inputFrame);
+ Frame decodedFrame = decoder.process(encodedFrame);
+ outputStream.write(decodedFrame.getData());
+ }
+ testPassed = true;
+ } finally {
+ outputFile.delete();
+ }
+
+ outputFile.delete();
+ } catch (IOException exc) {
+ log.error("IOException: " + exc.getMessage());
+ fail("Opus test file access error");
+ }
+
+ assertTrue(testPassed);
+ }
+
+ /**
+ * Test for observer.
+ */
+ @Test
+ public void testObserver() throws Exception {
+
+ // given
+ final OpusJni.Observer observer = mock(OpusJni.Observer.class);
+
+ // when
+ OpusJni opus = new OpusJni();
+ opus.setOpusObserverNative(observer);
+ opus.sayHelloNative();
+ opus.unsetOpusObserverNative();
+
+ // then
+ verify(observer, times(1)).onHello();
+ }
+}
diff --git a/codecs/opus/opus-java/src/test/resources/test_sound_mono_48.pcm b/codecs/opus/opus-java/src/test/resources/test_sound_mono_48.pcm
new file mode 100644
index 000000000..7619a5019
Binary files /dev/null and b/codecs/opus/opus-java/src/test/resources/test_sound_mono_48.pcm differ
diff --git a/codecs/opus/opus-native/README.md b/codecs/opus/opus-native/README.md
new file mode 100644
index 000000000..c09063eda
--- /dev/null
+++ b/codecs/opus/opus-native/README.md
@@ -0,0 +1 @@
+c++ opus_jni.cpp -std=c++11 -I/usr/lib/jvm/jdk1.7.0_80/include -I/usr/lib/jvm/jdk1.7.0_80/include/linux -I/usr/include/opus -lopus -Wall -fPIC -shared -o libopus_jni.so
diff --git a/codecs/opus/opus-native/linux/pom.xml b/codecs/opus/opus-native/linux/pom.xml
new file mode 100644
index 000000000..788e88e89
--- /dev/null
+++ b/codecs/opus/opus-native/linux/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+ so
+
+
+ org.restcomm.media.codecs.opus
+ opus-native
+ 7.0.0-SNAPSHOT
+
+
+ org.restcomm.media.codecs.opus
+ libopus_jni_linux
+ Opus Native Linux
+
+
+
+
+ org.codehaus.mojo
+ native-maven-plugin
+ true
+
+
+ generic
+
+ -std=c++11 -I${java.home}/../include -I${java.home}/../include/linux -I/usr/include/opus -Wall -fPIC
+
+
+
+ -shared
+
+
+ -lopus
+
+ ${artifactId}
+
+
+
+
+
+
+
+
+
+
diff --git a/codecs/opus/opus-native/macosx/pom.xml b/codecs/opus/opus-native/macosx/pom.xml
new file mode 100644
index 000000000..ae06fe84a
--- /dev/null
+++ b/codecs/opus/opus-native/macosx/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+ dylib
+
+
+ org.restcomm.media.codecs.opus
+ opus-native
+ 7.0.0-SNAPSHOT
+
+
+ org.restcomm.media.codecs.opus
+ libopus_jni_macos
+ Opus Native Mac OSX
+
+
+
+
+ org.codehaus.mojo
+ native-maven-plugin
+ true
+
+
+ generic
+
+ -std=c++11 -I${java.home}/../include -I${java.home}/../include/darwin -I/usr/local/include/opus -Wall -fPIC
+
+
+
+ -shared -lopus
+
+ ${artifactId}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codecs/opus/opus-native/pom.xml b/codecs/opus/opus-native/pom.xml
new file mode 100644
index 000000000..40b190763
--- /dev/null
+++ b/codecs/opus/opus-native/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+ pom
+
+
+ org.restcomm.media.codecs
+ opus
+ 7.0.0-SNAPSHOT
+
+
+ org.restcomm.media.codecs.opus
+ opus-native
+ Opus Native
+
+
+
+
+ linux-profile
+
+
+ Linux
+ unix
+
+
+
+ linux
+
+
+
+
+ macosx-profile
+
+
+ mac
+
+
+
+ macosx
+
+
+
+
+
+
diff --git a/codecs/opus/opus-native/src/opus_jni.cpp b/codecs/opus/opus-native/src/opus_jni.cpp
new file mode 100644
index 000000000..8199fb684
--- /dev/null
+++ b/codecs/opus/opus-native/src/opus_jni.cpp
@@ -0,0 +1,212 @@
+/*
+* TeleStax, Open Source Cloud Communications
+* Copyright 2011-2017, Telestax Inc and individual contributors
+* by the @authors tag.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*
+* @author morosev
+*
+*/
+
+#if defined(_WIN32)
+#define OPUS_EXPORT __declspec(dllimport)
+#endif
+#include "opus.h"
+
+#include "jni.h"
+
+#include
+#include
+#include
+#include
+
+ org.restcomm.media.codecs.opus
+ opus-java
+ ${project.version}
+ org.restcomm.mediartp
diff --git a/core/src/main/java/org/restcomm/media/core/configuration/CodecType.java b/core/src/main/java/org/restcomm/media/core/configuration/CodecType.java
index 5a4634ad7..c3ec13bcb 100644
--- a/core/src/main/java/org/restcomm/media/core/configuration/CodecType.java
+++ b/core/src/main/java/org/restcomm/media/core/configuration/CodecType.java
@@ -35,6 +35,7 @@ public enum CodecType {
L16(97, "l16", org.restcomm.media.codec.l16.Encoder.class.getName(), org.restcomm.media.codec.l16.Decoder.class.getName()),
G729(18, "g729", org.restcomm.media.codec.g729.Encoder.class.getName(), org.restcomm.media.codec.g729.Decoder.class.getName()),
ILBC(102, "ilbc", org.restcomm.media.codec.ilbc.Encoder.class.getName(), org.restcomm.media.codec.ilbc.Decoder.class.getName()),
+ OPUS(111, "opus", org.restcomm.media.codec.opus.Encoder.class.getName(), org.restcomm.media.codec.opus.Decoder.class.getName()),
DTMF(101, "telephone-event", "", "");
private final int payloadType;
diff --git a/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Configuring_the_Media_Server.adoc b/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Configuring_the_Media_Server.adoc
index 8b04acd3d..d168d178b 100644
--- a/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Configuring_the_Media_Server.adoc
+++ b/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Configuring_the_Media_Server.adoc
@@ -174,6 +174,7 @@ The media configuration contains definitions that have an impact on the media ch
+
@@ -224,7 +225,7 @@ In case of 180 or 183 without SDP response , intermediate MDCX is not required.
==== Codecs
-Currently media server supports five codecs : G711 A/U, Linear PCM Raw, GSM, ILBC and G.729.
+Currently media server supports six codecs : G711 A/U, Linear PCM Raw, GSM, ILBC, Opus and G.729.
.G.729 usage
WARNING: Please note that a valid license is required to use G.729 , therefore you should purchase a license prior to enabling this codec.
@@ -236,6 +237,30 @@ This is useful only in case of a one way activity.
NOTE: L16 codec is useful only in server to server communication where you have enough network bandwidth.
It is not recommended to allow L16 codec for UA – server connections, this can lead to degradation of the signal quality due to increased jitter and packet loss.
+.Opus usage
+NOTE: Opus codec processes data internally at 8kHz as mono signal. This sample rate and number of channels are limiting factors for sound quality when this codec is used. Bitrate is around 20 kbps. Payload type is fixed to value 111. It won't work with clients with other payload type values assigned to Opus codec.
+
+==== Opus Codec Configuration
+
+http://opus-codec.org/[Opus Codec] is open, royalty-free, highly versatile audio codec.
+
+Prerequisite library for Opus codec is `libopus` (or `libopus-dev` if the project is compiled from sources).
+
+[source,shell]
+----
+# CentOS/RHEL
+yum install libopus
+
+# Ubuntu/Debian
+apt-get install libopus
+
+# macOS
+brew install opus
+----
+
+The location of libopus library and name of compiled JNI library used by media server are specified by command line parameters. The values of the parameters are defined in file `bin/run.sh`.
+
+
=== Resources Configuration
In the current Media Server release, a global pool of resources is used to decrease garbage collection and allow for faster resource allocation.
diff --git a/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Introduction_to_the_Media_Server.adoc b/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Introduction_to_the_Media_Server.adoc
index 399915129..ee499f6b4 100644
--- a/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Introduction_to_the_Media_Server.adoc
+++ b/docs/sources-asciidoc/src/main/asciidoc/concept-chapter-Introduction_to_the_Media_Server.adoc
@@ -54,6 +54,7 @@ The Restcomm Media Server is capable of
** GSM
** Linear PCM(L16)
** G729
+** Opus
** DTMF(RFC 2833, INBAND)
* Media Files :
diff --git a/sdp/src/main/java/org/restcomm/media/sdp/format/AVProfile.java b/sdp/src/main/java/org/restcomm/media/sdp/format/AVProfile.java
index e264d6051..d85b2a89c 100644
--- a/sdp/src/main/java/org/restcomm/media/sdp/format/AVProfile.java
+++ b/sdp/src/main/java/org/restcomm/media/sdp/format/AVProfile.java
@@ -52,6 +52,7 @@ public class AVProfile {
private final static RTPFormat dtmf = new RTPFormat(telephoneEventsID, telephoneEvent, 8000);
private final static RTPFormat dtmf126 = new RTPFormat(telephoneEvent126, telephoneEvent, 8000);
private final static RTPFormat ilbc = new RTPFormat(102, FormatFactory.createAudioFormat("ilbc", 8000, 16, 1), 8000);
+ private final static RTPFormat opus = new RTPFormat(111, FormatFactory.createAudioFormat("opus", 48000, 16, 2), 48000);
private final static RTPFormat linear = new RTPFormat(150, FormatFactory.createAudioFormat("linear", 8000, 16, 1), 8000);
private final static RTPFormat H261 = new RTPFormat(45, FormatFactory.createVideoFormat("h261"));
@@ -65,6 +66,7 @@ public class AVProfile {
audio.add(g729);
audio.add(l16);
audio.add(ilbc);
+ audio.add(opus);
audio.add(dtmf);
audio.add(dtmf126);
}