Skip to content

Commit 76dc378

Browse files
authored
Merge pull request #674 from RestComm/github-107
Support for OPUS Codec. Close #107
2 parents 2bb15ec + 9dcbace commit 76dc378

File tree

25 files changed

+930
-9
lines changed

25 files changed

+930
-9
lines changed

bootstrap/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@
8989
<artifactId>ilbc</artifactId>
9090
<version>${project.parent.version}</version>
9191
</dependency>
92+
<dependency>
93+
<groupId>org.restcomm.media.codecs.opus</groupId>
94+
<artifactId>opus-java</artifactId>
95+
<version>${project.version}</version>
96+
</dependency>
9297

9398
<!-- External Dependencies -->
9499
<dependency>

bootstrap/src/main/assembly/descriptor.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@
1919
<outputDirectory>/lib</outputDirectory>
2020
<unpack>false</unpack>
2121
<scope>runtime</scope>
22+
<excludes>
23+
<exclude>*:so</exclude>
24+
<exclude>*:dylib</exclude>
25+
</excludes>
26+
</dependencySet>
27+
<dependencySet>
28+
<outputDirectory>lib/native</outputDirectory>
29+
<outputFileNameMapping>${artifact.artifactId}.${artifact.extension}</outputFileNameMapping>
30+
<unpack>false</unpack>
31+
<scope>runtime</scope>
32+
<useProjectArtifact>false</useProjectArtifact>
33+
<useStrictFiltering>false</useStrictFiltering>
34+
<includes>
35+
<include>*:so</include>
36+
<include>*:dylib</include>
37+
</includes>
2238
</dependencySet>
2339
</dependencySets>
2440
<componentDescriptors>

bootstrap/src/main/config/autoconfig/mediaserver.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ MEDIA_MAX_DURATION=14440
1515
MEDIA_LOW_PORT=64534
1616
MEDIA_HIGH_PORT=65534
1717
MEDIA_JITTER_SIZE=50
18-
MEDIA_CODECS=pcmu,pcma,telephone-event
18+
MEDIA_CODECS=opus,pcmu,pcma,telephone-event
1919

2020
# Resources
2121
AUDIO_CACHE_SIZE=100
@@ -42,4 +42,4 @@ DTLS_ALGORITHM=ecdsa
4242
#ASR_DRIVER_SOMEPROVIDER_PROPERTY_PARAMETER2_VALUE=parameter2_value
4343

4444
# Java
45-
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"
45+
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"

bootstrap/src/main/config/mediaserver.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<codec name="pcmu" />
4040
<codec name="pcma" />
4141
<codec name="gsm" />
42+
<codec name="opus" />
4243
<!-- RestComm Media Server ships with G.729 codec. G.729 includes patents
4344
from several companies and is licensed by Sipro Lab Telecom. Sipro Lab Telecom
4445
is the authorized Intellectual Property Licensing Administrator for G.729
@@ -80,4 +81,4 @@
8081
-->
8182
</subsystem>
8283
</subsystems>
83-
</mediaserver>
84+
</mediaserver>

bootstrap/src/main/config/run.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,14 @@ esac
5050

5151
# Force IPv4 on Linux systems since IPv6 doesn't work correctly with jdk5 and lower
5252
if [ "$linux" = "true" ]; then
53-
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
53+
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"
5454
fi
5555

56+
if [ "$darwin" = "true" ]; then
57+
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=../lib/native -Drestcomm.opus.library=opus_jni_macos"
58+
fi
59+
60+
5661
# For Cygwin, ensure paths are in UNIX format before anything is touched
5762
if $cygwin ; then
5863
[ -n "$MMS_HOME" ] &&

bootstrap/src/test/resources/mediaserver.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<codec name="pcmu" />
3939
<codec name="pcma" />
4040
<codec name="gsm" />
41+
<codec name="opus" />
4142
<codec name="g729" />
4243
<codec name="telephone-event" />
4344
</codecs>
@@ -73,4 +74,4 @@
7374
</driver>
7475
</subsystem>
7576
</subsystems>
76-
</mediaserver>
77+
</mediaserver>

codecs/opus/opus-java/pom.xml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<packaging>jar</packaging>
5+
6+
<parent>
7+
<groupId>org.restcomm.media.codecs</groupId>
8+
<artifactId>opus</artifactId>
9+
<version>7.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<groupId>org.restcomm.media.codecs.opus</groupId>
13+
<artifactId>opus-java</artifactId>
14+
<name>Opus Java</name>
15+
16+
<profiles>
17+
<profile>
18+
<id>linux-profile</id>
19+
<activation>
20+
<os>
21+
<name>Linux</name>
22+
<family>unix</family>
23+
</os>
24+
</activation>
25+
<properties>
26+
<libopus.artifactId>libopus_jni_linux</libopus.artifactId>
27+
<libopus.packaging>so</libopus.packaging>
28+
<libopus.distro>linux</libopus.distro>
29+
<libopus.libName>opus_jni_linux</libopus.libName>
30+
</properties>
31+
</profile>
32+
33+
<profile>
34+
<id>macosx-profile</id>
35+
<activation>
36+
<os>
37+
<family>mac</family>
38+
</os>
39+
</activation>
40+
<properties>
41+
<libopus.artifactId>libopus_jni_macos</libopus.artifactId>
42+
<libopus.packaging>dylib</libopus.packaging>
43+
<libopus.distro>macosx</libopus.distro>
44+
<libopus.libName>opus_jni_macos</libopus.libName>
45+
</properties>
46+
</profile>
47+
</profiles>
48+
49+
<dependencies>
50+
<dependency>
51+
<groupId>org.restcomm.media</groupId>
52+
<artifactId>spi</artifactId>
53+
<version>${project.version}</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.restcomm.media.codecs.opus</groupId>
57+
<artifactId>${libopus.artifactId}</artifactId>
58+
<version>${project.version}</version>
59+
<type>${libopus.packaging}</type>
60+
</dependency>
61+
</dependencies>
62+
63+
<build>
64+
<plugins>
65+
<plugin>
66+
<groupId>org.apache.maven.plugins</groupId>
67+
<artifactId>maven-surefire-plugin</artifactId>
68+
<configuration>
69+
<argLine>-Djava.library.path=../opus-native/${libopus.distro}/target -Drestcomm.opus.library=${libopus.libName}</argLine>
70+
</configuration>
71+
</plugin>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-compiler-plugin</artifactId>
75+
<configuration>
76+
<source>1.7</source>
77+
<target>1.7</target>
78+
</configuration>
79+
</plugin>
80+
</plugins>
81+
<finalName>restcomm-mediaserver-codecs-opus-${project.version}</finalName>
82+
</build>
83+
84+
</project>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* TeleStax, Open Source Cloud Communications
3+
* Copyright 2011-2017, Telestax Inc and individual contributors
4+
* by the @authors tag.
5+
*
6+
* This is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as
8+
* published by the Free Software Foundation; either version 2.1 of
9+
* the License, or (at your option) any later version.
10+
*
11+
* This software is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this software; if not, write to the Free
18+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
20+
*/
21+
22+
package org.restcomm.media.codec.opus;
23+
24+
import java.nio.ByteBuffer;
25+
import java.nio.ByteOrder;
26+
27+
import org.apache.log4j.Logger;
28+
import org.restcomm.media.spi.dsp.Codec;
29+
import org.restcomm.media.spi.format.Format;
30+
import org.restcomm.media.spi.format.FormatFactory;
31+
import org.restcomm.media.spi.memory.Frame;
32+
import org.restcomm.media.spi.memory.Memory;
33+
34+
/**
35+
* Implements Opus decoder.
36+
*
37+
* @author Vladimir Morosev (vladimir.morosev@telestax.com)
38+
*
39+
*/
40+
public class Decoder implements Codec {
41+
42+
private final static Logger log = Logger.getLogger(Encoder.class);
43+
44+
private final static Format opus = FormatFactory.createAudioFormat("opus", 48000, 8, 2);
45+
private final static Format linear = FormatFactory.createAudioFormat("linear", 8000, 16, 1);
46+
47+
private long decoderAddress;
48+
49+
private final int OPUS_SAMPLE_RATE = 8000;
50+
51+
public Decoder() {
52+
decoderAddress = OpusJni.createDecoderNative(OPUS_SAMPLE_RATE, 1);
53+
}
54+
55+
@Override
56+
protected void finalize() throws Throwable {
57+
if (decoderAddress != 0) OpusJni.releaseDecoderNative(decoderAddress);
58+
super.finalize();
59+
}
60+
61+
@Override
62+
public Format getSupportedInputFormat() {
63+
return opus;
64+
}
65+
66+
@Override
67+
public Format getSupportedOutputFormat() {
68+
return linear;
69+
}
70+
71+
@Override
72+
public Frame process(Frame frame) {
73+
74+
short[] decodedData = OpusJni.decodeNative(decoderAddress, frame.getData());
75+
byte[] output = new byte[2 * decodedData.length];
76+
ByteBuffer.wrap(output).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(decodedData);
77+
78+
Frame res = Memory.allocate(output.length);
79+
System.arraycopy(output, 0, res.getData(), 0, output.length);
80+
81+
res.setOffset(0);
82+
res.setLength(output.length);
83+
res.setTimestamp(frame.getTimestamp());
84+
res.setDuration(frame.getDuration());
85+
res.setSequenceNumber(frame.getSequenceNumber());
86+
res.setEOM(frame.isEOM());
87+
res.setFormat(linear);
88+
res.setHeader(frame.getHeader());
89+
return res;
90+
}
91+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* TeleStax, Open Source Cloud Communications
3+
* Copyright 2011-2017, Telestax Inc and individual contributors
4+
* by the @authors tag.
5+
*
6+
* This is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as
8+
* published by the Free Software Foundation; either version 2.1 of
9+
* the License, or (at your option) any later version.
10+
*
11+
* This software is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this software; if not, write to the Free
18+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
20+
*/
21+
22+
package org.restcomm.media.codec.opus;
23+
24+
import java.nio.ByteBuffer;
25+
import java.nio.ByteOrder;
26+
27+
import org.apache.log4j.Logger;
28+
import org.restcomm.media.spi.dsp.Codec;
29+
import org.restcomm.media.spi.format.Format;
30+
import org.restcomm.media.spi.format.FormatFactory;
31+
import org.restcomm.media.spi.memory.Frame;
32+
import org.restcomm.media.spi.memory.Memory;
33+
34+
/**
35+
* Implements Opus encoder.
36+
*
37+
* @author Vladimir Morosev (vladimir.morosev@telestax.com)
38+
*
39+
*/
40+
public class Encoder implements Codec {
41+
42+
private final static Logger log = Logger.getLogger(Encoder.class);
43+
44+
private final static Format opus = FormatFactory.createAudioFormat("opus", 48000, 8, 2);
45+
private final static Format linear = FormatFactory.createAudioFormat("linear", 8000, 16, 1);
46+
47+
private long encoderAddress;
48+
49+
private final int OPUS_SAMPLE_RATE = 8000;
50+
private final int OPUS_BITRATE = 20000;
51+
52+
public Encoder() {
53+
encoderAddress = OpusJni.createEncoderNative(OPUS_SAMPLE_RATE, 1, OpusJni.OPUS_APPLICATION_VOIP, OPUS_BITRATE);
54+
}
55+
56+
@Override
57+
protected void finalize() throws Throwable {
58+
OpusJni.releaseEncoderNative(encoderAddress);
59+
super.finalize();
60+
}
61+
62+
@Override
63+
public Format getSupportedInputFormat() {
64+
return linear;
65+
}
66+
67+
@Override
68+
public Format getSupportedOutputFormat() {
69+
return opus;
70+
}
71+
72+
@Override
73+
public Frame process(Frame frame) {
74+
75+
byte[] input = frame.getData();
76+
short[] inputData = new short[frame.getLength() / 2];
77+
ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(inputData);
78+
byte[] encodedData = OpusJni.encodeNative(encoderAddress, inputData);
79+
80+
Frame res = Memory.allocate(encodedData.length);
81+
System.arraycopy(encodedData, 0, res.getData(), 0, encodedData.length);
82+
83+
res.setOffset(0);
84+
res.setLength(encodedData.length);
85+
res.setFormat(opus);
86+
res.setTimestamp(frame.getTimestamp());
87+
res.setDuration(frame.getDuration());
88+
res.setEOM(frame.isEOM());
89+
res.setSequenceNumber(frame.getSequenceNumber());
90+
91+
return res;
92+
}
93+
}

0 commit comments

Comments
 (0)