Transition to the Opus Multistream Decoder API

This commit is contained in:
Cameron Gutman 2015-10-17 17:15:22 -07:00
parent 469dcab5c7
commit fbd61d2a21
6 changed files with 50 additions and 13 deletions

View File

@ -14,6 +14,8 @@ public class StreamConfiguration {
private boolean playLocalAudio;
private int maxPacketSize;
private boolean remote;
private int audioChannelMask;
private int audioChannelCount;
public static class Builder {
private StreamConfiguration config = new StreamConfiguration();
@ -64,6 +66,12 @@ public class StreamConfiguration {
return this;
}
public StreamConfiguration.Builder setAudioParameters(int audioChannelMask, int audioChannelCount) {
config.audioChannelCount = audioChannelCount;
config.audioChannelMask = audioChannelMask;
return this;
}
public StreamConfiguration build() {
return config;
}
@ -79,6 +87,8 @@ public class StreamConfiguration {
this.maxPacketSize = 1024;
this.sops = true;
this.enableAdaptiveResolution = false;
this.audioChannelCount = 2;
this.audioChannelMask = 0x3;
}
public int getWidth() {
@ -120,4 +130,12 @@ public class StreamConfiguration {
public boolean getRemote() {
return remote;
}
public int getAudioChannelCount() {
return audioChannelCount;
}
public int getAudioChannelMask() {
return audioChannelMask;
}
}

View File

@ -12,6 +12,8 @@ public class AudioDepacketizer {
private static final int DU_LIMIT = 30;
private AbstractPopulatedBufferList<ByteBufferDescriptor> decodedUnits;
private final int channelCount;
// Direct submit state
private AudioRenderer directSubmitRenderer;
private byte[] directSubmitData;
@ -22,16 +24,17 @@ public class AudioDepacketizer {
// Sequencing state
private short lastSequenceNumber;
public AudioDepacketizer(AudioRenderer directSubmitRenderer)
public AudioDepacketizer(AudioRenderer directSubmitRenderer, final int channelCount, final int bufferSizeShorts)
{
this.directSubmitRenderer = directSubmitRenderer;
this.channelCount = channelCount;
if (directSubmitRenderer != null) {
this.directSubmitData = new byte[OpusDecoder.getMaxOutputShorts()*2];
this.directSubmitData = new byte[bufferSizeShorts*2];
}
else {
decodedUnits = new AtomicPopulatedBufferList<ByteBufferDescriptor>(DU_LIMIT, new AbstractPopulatedBufferList.BufferFactory() {
public Object createFreeBuffer() {
return new ByteBufferDescriptor(new byte[OpusDecoder.getMaxOutputShorts()*2], 0, OpusDecoder.getMaxOutputShorts()*2);
return new ByteBufferDescriptor(new byte[bufferSizeShorts*2], 0, bufferSizeShorts*2);
}
public void cleanupObject(Object o) {
@ -66,7 +69,7 @@ public class AudioDepacketizer {
if (decodeLen > 0) {
// Return value of decode is frames (shorts) decoded per channel
decodeLen *= 2*OpusDecoder.getChannelCount();
decodeLen *= 2*channelCount;
if (directSubmitRenderer != null) {
directSubmitRenderer.playDecodedAudio(directSubmitData, 0, decodeLen);

View File

@ -6,7 +6,7 @@ public interface AudioRenderer {
public int getCapabilities();
public boolean streamInitialized(int channelCount, int sampleRate);
public boolean streamInitialized(int channelCount, int channelMask, int samplesPerFrame, int sampleRate);
public void playDecodedAudio(byte[] audioData, int offset, int length);

View File

@ -15,6 +15,9 @@ import com.limelight.nvstream.av.RtpReorderQueue;
public class AudioStream {
private static final int RTP_PORT = 48000;
private static final int SAMPLE_RATE = 48000;
private static final int SHORTS_PER_CHANNEL = 240;
private static final int RTP_RECV_BUFFER = 64 * 1024;
private static final int MAX_PACKET_SIZE = 100;
@ -94,20 +97,26 @@ public class AudioStream {
{
int err;
err = OpusDecoder.init();
err = OpusDecoder.init(SAMPLE_RATE, context.streamConfig.getAudioChannelCount(),
1, 1, new byte[]{0, 1, 2, 3, 4, 5, 6});
if (err != 0) {
throw new IllegalStateException("Opus decoder failed to initialize");
}
if (!streamListener.streamInitialized(OpusDecoder.getChannelCount(), OpusDecoder.getSampleRate())) {
if (!streamListener.streamInitialized(context.streamConfig.getAudioChannelCount(),
context.streamConfig.getAudioChannelMask(),
context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL,
SAMPLE_RATE)) {
return false;
}
if ((streamListener.getCapabilities() & AudioRenderer.CAPABILITY_DIRECT_SUBMIT) != 0) {
depacketizer = new AudioDepacketizer(streamListener);
depacketizer = new AudioDepacketizer(streamListener, context.streamConfig.getAudioChannelCount(),
context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL);
}
else {
depacketizer = new AudioDepacketizer(null);
depacketizer = new AudioDepacketizer(null, context.streamConfig.getAudioChannelCount(),
context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL);
}
return true;

View File

@ -5,10 +5,7 @@ public class OpusDecoder {
System.loadLibrary("nv_opus_dec");
}
public static native int init();
public static native int init(int sampleRate, int channelCount, int streams, int coupledStreams, byte[] mapping);
public static native void destroy();
public static native int getChannelCount();
public static native int getMaxOutputShorts();
public static native int getSampleRate();
public static native int decode(byte[] indata, int inoff, int inlen, byte[] outpcmdata);
}

View File

@ -57,6 +57,16 @@ public class SdpGenerator {
// Use slicing for increased performance on some decoders
addSessionAttribute(config, "x-nv-video[0].videoEncoderSlicesPerFrame", "4");
// Enable surround sound if configured for it
addSessionAttribute(config, "x-nv-audio.surround.numChannels", ""+context.streamConfig.getAudioChannelCount());
addSessionAttribute(config, "x-nv-audio.surround.channelMask", ""+context.streamConfig.getAudioChannelMask());
if (context.streamConfig.getAudioChannelCount() > 2) {
addSessionAttribute(config, "x-nv-audio.surround.enable", "1");
}
else {
addSessionAttribute(config, "x-nv-audio.surround.enable", "0");
}
}
public static String generateSdpFromContext(ConnectionContext context) {