This repository was archived by the owner on Sep 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Stream Encoding and Decoding #1
Copy link
Copy link
Open
Description
Hello!
I modified your example to keep running in a loop. I cleaned up the code and reduced the lag of the audio to less than half a second. But I get little breaks in the audio. I don't know if the issue is in the usage of the library, or somewhere in the code:
import com.sun.jna.ptr.PointerByReference;
import net.tomp2p.opuswrapper.Opus;
import javax.sound.sampled.*;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
public class Main {
private static final int SAMPLE_RATE = 48000;
private static final int FRAME_SIZE = 480;
public static void main(String[] args) throws LineUnavailableException {
AudioFormat format = new AudioFormat(SAMPLE_RATE, 16, 1, true, true);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException("not supported");
}
TargetDataLine microphone = AudioSystem.getTargetDataLine(format);
// Obtain and open the line.
microphone.open(format);
// Begin audio capture.
microphone.start();
SourceDataLine speaker = AudioSystem.getSourceDataLine(format);
speaker.open(format);
speaker.start();
IntBuffer error = IntBuffer.allocate(4);
PointerByReference opusDecoder = Opus.INSTANCE.opus_decoder_create(SAMPLE_RATE, 1, error);
PointerByReference opusEncoder = Opus.INSTANCE.opus_encoder_create(SAMPLE_RATE, 1, Opus.OPUS_APPLICATION_RESTRICTED_LOWDELAY, error);
while (true) {
ShortBuffer dataFromMic = recordFromMicrophone(microphone);
long start = System.nanoTime();
List<ByteBuffer> packets = encode(opusEncoder, dataFromMic);
// packets go over network
ShortBuffer decodedFromNetwork = decode(opusDecoder, packets);
long stop = System.nanoTime();
System.out.println((stop - start) / 1000000D + "ms");
playBack(speaker, decodedFromNetwork);
}
// Opus.INSTANCE.opus_decoder_destroy(opusDecoder);
// Opus.INSTANCE.opus_encoder_destroy(opusEncoder);
}
private static ShortBuffer decode(PointerByReference opusDecoder, List<ByteBuffer> packets) {
ShortBuffer shortBuffer = ShortBuffer.allocate(packets.size() * FRAME_SIZE);
for (ByteBuffer dataBuffer : packets) {
byte[] transferedBytes = new byte[dataBuffer.remaining()];
dataBuffer.get(transferedBytes);
int decoded = Opus.INSTANCE.opus_decode(opusDecoder, transferedBytes, transferedBytes.length, shortBuffer, FRAME_SIZE, 0);
shortBuffer.position(shortBuffer.position() + decoded);
}
shortBuffer.flip();
return shortBuffer;
}
private static List<ByteBuffer> encode(PointerByReference opusEncoder, ShortBuffer shortBuffer) {
int read = 0;
List<ByteBuffer> list = new ArrayList<>();
while (shortBuffer.hasRemaining()) {
ByteBuffer dataBuffer = ByteBuffer.allocate(8192);
int toRead = Math.min(shortBuffer.remaining(), dataBuffer.remaining());
read = Opus.INSTANCE.opus_encode(opusEncoder, shortBuffer, FRAME_SIZE, dataBuffer, toRead);
dataBuffer.position(dataBuffer.position() + read);
dataBuffer.flip();
list.add(dataBuffer);
shortBuffer.position(shortBuffer.position() + FRAME_SIZE);
}
// used for debugging
shortBuffer.flip();
return list;
}
private static void playBack(SourceDataLine speaker, ShortBuffer shortBuffer) throws LineUnavailableException {
short[] shortAudioBuffer = new short[shortBuffer.remaining()];
shortBuffer.get(shortAudioBuffer);
byte[] audio = ShortToByte_Twiddle_Method(shortAudioBuffer);
speaker.write(audio, 0, audio.length);
}
private static ShortBuffer recordFromMicrophone(TargetDataLine microphone) throws LineUnavailableException {
// Assume that the TargetDataLine, line, has already been obtained and
// opened.
byte[] data = new byte[microphone.getBufferSize() / 10];
// probably way too big
// Here, stopped is a global boolean set by another thread.
int numBytesRead;
numBytesRead = microphone.read(data, 0, data.length);
ShortBuffer shortBuffer = ShortBuffer.allocate(numBytesRead * 2);
shortBuffer.put(ByteBuffer.wrap(data).asShortBuffer());
shortBuffer.flip();
return shortBuffer;
}
private static byte[] ShortToByte_Twiddle_Method(final short[] input) {
final int len = input.length;
final byte[] buffer = new byte[len * 2];
for (int i = 0; i < len; i++) {
buffer[(i * 2) + 1] = (byte) (input[i]);
buffer[(i * 2)] = (byte) (input[i] >> 8);
}
return buffer;
}
}Metadata
Metadata
Assignees
Labels
No labels