Skip to content

Commit c2cc531

Browse files
committed
Move Opus native loads and usages behind interfaces
1 parent 239abca commit c2cc531

File tree

10 files changed

+340
-94
lines changed

10 files changed

+340
-94
lines changed

src/main/java/net/dv8tion/jda/api/audio/AudioNatives.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package net.dv8tion.jda.api.audio;
1818

19-
import club.minnced.opus.util.OpusLibrary;
19+
import net.dv8tion.jda.internal.audio.OpusCodecFactoryProvider;
2020
import net.dv8tion.jda.internal.utils.JDALogger;
2121
import org.slf4j.Logger;
2222

@@ -72,9 +72,7 @@ public static synchronized boolean ensureOpus()
7272
initialized = true;
7373
try
7474
{
75-
if (OpusLibrary.isInitialized())
76-
return audioSupported = true;
77-
audioSupported = OpusLibrary.loadFromJar();
75+
audioSupported = OpusCodecFactoryProvider.getInstance().initialize();
7876
}
7977
catch (Throwable e)
8078
{

src/main/java/net/dv8tion/jda/api/audio/OpusPacket.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package net.dv8tion.jda.api.audio;
1818

1919
import net.dv8tion.jda.internal.audio.AudioPacket;
20-
import net.dv8tion.jda.internal.audio.Decoder;
20+
import net.dv8tion.jda.internal.audio.OpusDecoder;
2121

2222
import javax.annotation.Nonnull;
2323
import javax.annotation.Nullable;
@@ -45,13 +45,13 @@ public final class OpusPacket implements Comparable<OpusPacket>
4545

4646
private final long userId;
4747
private final byte[] opusAudio;
48-
private final Decoder decoder;
48+
private final OpusDecoder decoder;
4949
private final AudioPacket rawPacket;
5050

5151
private short[] decoded;
5252
private boolean triedDecode;
5353

54-
public OpusPacket(@Nonnull AudioPacket packet, long userId, @Nullable Decoder decoder)
54+
public OpusPacket(@Nonnull AudioPacket packet, long userId, @Nullable OpusDecoder decoder)
5555
{
5656
this.rawPacket = packet;
5757
this.userId = userId;
@@ -156,7 +156,7 @@ public synchronized short[] decode()
156156
if (!decoder.isInOrder(getSequence()))
157157
throw new IllegalStateException("Packet is not in order");
158158
triedDecode = true;
159-
return decoded = decoder.decodeFromOpus(rawPacket); // null if failed to decode
159+
return decoded = decoder.decode(rawPacket); // null if failed to decode
160160
}
161161

162162
/**

src/main/java/net/dv8tion/jda/internal/audio/AudioConnection.java

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package net.dv8tion.jda.internal.audio;
1818

1919
import com.neovisionaries.ws.client.WebSocket;
20-
import com.sun.jna.ptr.PointerByReference;
2120
import gnu.trove.map.TIntLongMap;
2221
import gnu.trove.map.TIntObjectMap;
2322
import gnu.trove.map.hash.TIntLongHashMap;
@@ -37,14 +36,11 @@
3736
import net.dv8tion.jda.internal.managers.AudioManagerImpl;
3837
import net.dv8tion.jda.internal.utils.JDALogger;
3938
import org.slf4j.Logger;
40-
import tomp2p.opuswrapper.Opus;
4139

4240
import javax.annotation.Nonnull;
4341
import java.net.*;
4442
import java.nio.Buffer;
4543
import java.nio.ByteBuffer;
46-
import java.nio.IntBuffer;
47-
import java.nio.ShortBuffer;
4844
import java.util.*;
4945
import java.util.concurrent.ConcurrentLinkedQueue;
5046
import java.util.concurrent.Executors;
@@ -65,8 +61,9 @@ public class AudioConnection
6561

6662
protected volatile DatagramSocket udpSocket;
6763

64+
private final OpusCodecFactory codecFactory = OpusCodecFactoryProvider.getInstance();
6865
private final TIntLongMap ssrcMap = new TIntLongHashMap();
69-
private final TIntObjectMap<Decoder> opusDecoders = new TIntObjectHashMap<>();
66+
private final TIntObjectMap<OpusDecoder> opusDecoders = new TIntObjectHashMap<>();
7067
private final HashMap<User, Queue<AudioData>> combinedQueue = new HashMap<>();
7168
private final String threadIdentifier;
7269
private final AudioWebSocket webSocket;
@@ -76,7 +73,7 @@ public class AudioConnection
7673
protected final Condition readyCondvar = readyLock.newCondition();
7774

7875
private AudioChannel channel;
79-
private PointerByReference opusEncoder;
76+
private OpusEncoder opusEncoder;
8077
private ScheduledExecutorService combinedAudioExecutor;
8178
private IAudioSendSystem sendSystem;
8279
private Thread receiveThread;
@@ -188,11 +185,11 @@ public synchronized void shutdown()
188185
}
189186
if (opusEncoder != null)
190187
{
191-
Opus.INSTANCE.opus_encoder_destroy(opusEncoder);
188+
opusEncoder.close();
192189
opusEncoder = null;
193190
}
194191

195-
opusDecoders.valueCollection().forEach(Decoder::close);
192+
opusDecoders.valueCollection().forEach(OpusDecoder::close);
196193
opusDecoders.clear();
197194

198195
MiscUtil.locked(readyLock, readyCondvar::signalAll);
@@ -266,7 +263,7 @@ protected void removeUserSSRC(long userId)
266263
});
267264
if (!modified)
268265
return;
269-
final Decoder decoder = opusDecoders.remove(ssrcRef.get());
266+
final OpusDecoder decoder = opusDecoders.remove(ssrcRef.get());
270267
if (decoder != null) // cleanup decoder
271268
decoder.close();
272269
}
@@ -290,7 +287,7 @@ protected void updateUserSSRC(int ssrc, long userId)
290287

291288
//Only create a decoder if we are actively handling received audio.
292289
if (receiveThread != null && AudioNatives.ensureOpus())
293-
opusDecoders.put(ssrc, new Decoder(ssrc));
290+
opusDecoders.put(ssrc, codecFactory.createDecoder(ssrc));
294291
}
295292
}
296293

@@ -313,7 +310,7 @@ else if (sendHandler == null && sendSystem != null)
313310

314311
if (opusEncoder != null)
315312
{
316-
Opus.INSTANCE.opus_encoder_destroy(opusEncoder);
313+
opusEncoder.close();
317314
opusEncoder = null;
318315
}
319316
}
@@ -336,7 +333,7 @@ else if (receiveHandler == null && receiveThread != null)
336333
combinedAudioExecutor = null;
337334
}
338335

339-
opusDecoders.valueCollection().forEach(Decoder::close);
336+
opusDecoders.valueCollection().forEach(OpusDecoder::close);
340337
opusDecoders.clear();
341338
}
342339
else if (receiveHandler != null && !receiveHandler.canReceiveCombined() && combinedAudioExecutor != null)
@@ -379,7 +376,7 @@ private synchronized void setupReceiveThread()
379376

380377
int ssrc = decryptedPacket.getSSRC();
381378
final long userId = ssrcMap.get(ssrc);
382-
Decoder decoder = opusDecoders.get(ssrc);
379+
OpusDecoder decoder = opusDecoders.get(ssrc);
383380
if (userId == ssrcMap.getNoEntryValue())
384381
{
385382
ByteBuffer audio = decryptedPacket.getEncodedAudio();
@@ -395,7 +392,7 @@ private synchronized void setupReceiveThread()
395392
{
396393
if (AudioNatives.ensureOpus())
397394
{
398-
opusDecoders.put(ssrc, decoder = new Decoder(ssrc));
395+
opusDecoders.put(ssrc, decoder = codecFactory.createDecoder(ssrc));
399396
}
400397
else if (!receiveHandler.canReceiveEncoded())
401398
{
@@ -565,33 +562,6 @@ else if (sample < Short.MIN_VALUE)
565562
}
566563
}
567564

568-
private ByteBuffer encodeToOpus(ByteBuffer rawAudio)
569-
{
570-
ShortBuffer nonEncodedBuffer = ShortBuffer.allocate(rawAudio.remaining() / 2);
571-
ByteBuffer encoded = ByteBuffer.allocate(4096);
572-
for (int i = rawAudio.position(); i < rawAudio.limit(); i += 2)
573-
{
574-
int firstByte = (0x000000FF & rawAudio.get(i)); //Promotes to int and handles the fact that it was unsigned.
575-
int secondByte = (0x000000FF & rawAudio.get(i + 1));
576-
577-
//Combines the 2 bytes into a short. Opus deals with unsigned shorts, not bytes.
578-
short toShort = (short) ((firstByte << 8) | secondByte);
579-
580-
nonEncodedBuffer.put(toShort);
581-
}
582-
((Buffer) nonEncodedBuffer).flip();
583-
584-
int result = Opus.INSTANCE.opus_encode(opusEncoder, nonEncodedBuffer, OpusPacket.OPUS_FRAME_SIZE, encoded, encoded.capacity());
585-
if (result <= 0)
586-
{
587-
LOG.error("Received error code from opus_encode(...): {}", result);
588-
return null;
589-
}
590-
591-
((Buffer) encoded).position(0).limit(result);
592-
return encoded;
593-
}
594-
595565
private void setSpeaking(int raw)
596566
{
597567
DataObject obj = DataObject.empty()
@@ -706,15 +676,13 @@ private ByteBuffer encodeAudio(ByteBuffer rawAudio)
706676
printedError = true;
707677
return null;
708678
}
709-
IntBuffer error = IntBuffer.allocate(1);
710-
opusEncoder = Opus.INSTANCE.opus_encoder_create(OpusPacket.OPUS_SAMPLE_RATE, OpusPacket.OPUS_CHANNEL_COUNT, Opus.OPUS_APPLICATION_AUDIO, error);
711-
if (error.get() != Opus.OPUS_OK && opusEncoder == null)
679+
opusEncoder = codecFactory.createEncoder();
680+
if (opusEncoder == null)
712681
{
713-
LOG.error("Received error status from opus_encoder_create(...): {}", error.get());
714682
return null;
715683
}
716684
}
717-
return encodeToOpus(rawAudio);
685+
return opusEncoder.encode(rawAudio);
718686
}
719687

720688
private DatagramPacket getDatagramPacket(ByteBuffer b)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.dv8tion.jda.internal.audio;
18+
19+
import javax.annotation.Nonnull;
20+
import javax.annotation.Nullable;
21+
22+
public interface OpusCodecFactory
23+
{
24+
boolean initialize() throws Exception;
25+
26+
@Nonnull
27+
OpusDecoder createDecoder(int ssrc);
28+
29+
@Nullable
30+
OpusEncoder createEncoder();
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.dv8tion.jda.internal.audio;
18+
19+
import javax.annotation.Nonnull;
20+
21+
public class OpusCodecFactoryProvider
22+
{
23+
private static OpusCodecFactory codecFactory;
24+
25+
@Nonnull
26+
public static synchronized OpusCodecFactory getInstance()
27+
{
28+
if (codecFactory == null)
29+
codecFactory = new OpusJnaCodecFactory();
30+
31+
return codecFactory;
32+
}
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.dv8tion.jda.internal.audio;
18+
19+
import javax.annotation.Nullable;
20+
21+
public interface OpusDecoder
22+
{
23+
boolean isInOrder(char newSeq);
24+
25+
short[] decode(@Nullable AudioPacket decryptedPacket);
26+
27+
void close();
28+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.dv8tion.jda.internal.audio;
18+
19+
import javax.annotation.Nonnull;
20+
import javax.annotation.Nullable;
21+
import java.nio.ByteBuffer;
22+
23+
public interface OpusEncoder
24+
{
25+
@Nullable
26+
ByteBuffer encode(@Nonnull ByteBuffer rawAudio);
27+
28+
void close();
29+
}

0 commit comments

Comments
 (0)