From 886ef425e637b8907a0f440b8acc72affa9d789f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Oct 2015 15:25:16 -0700 Subject: [PATCH] Finish 5.1 surround sound support --- .../nvstream/StreamConfiguration.java | 26 +++++++++++--- .../nvstream/av/audio/AudioDepacketizer.java | 10 ++---- .../nvstream/av/audio/AudioStream.java | 36 ++++++++++++++----- .../nvstream/av/audio/OpusDecoder.java | 2 +- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/StreamConfiguration.java b/moonlight-common/src/com/limelight/nvstream/StreamConfiguration.java index 1f5ca10c..7403f10c 100644 --- a/moonlight-common/src/com/limelight/nvstream/StreamConfiguration.java +++ b/moonlight-common/src/com/limelight/nvstream/StreamConfiguration.java @@ -5,6 +5,15 @@ import com.limelight.nvstream.http.NvApp; public class StreamConfiguration { public static final int INVALID_APP_ID = 0; + public static final int AUDIO_CONFIGURATION_STEREO = 1; + public static final int AUDIO_CONFIGURATION_5_1 = 2; + + private static final int CHANNEL_COUNT_STEREO = 2; + private static final int CHANNEL_COUNT_5_1 = 6; + + private static final int CHANNEL_MASK_STEREO = 0x3; + private static final int CHANNEL_MASK_5_1 = 0xFC; + private NvApp app; private int width, height; private int refreshRate; @@ -66,9 +75,16 @@ public class StreamConfiguration { return this; } - public StreamConfiguration.Builder setAudioParameters(int audioChannelMask, int audioChannelCount) { - config.audioChannelCount = audioChannelCount; - config.audioChannelMask = audioChannelMask; + public StreamConfiguration.Builder setAudioConfiguration(int audioConfig) { + if (audioConfig == AUDIO_CONFIGURATION_STEREO) { + config.audioChannelCount = CHANNEL_COUNT_STEREO; + config.audioChannelMask = CHANNEL_MASK_STEREO; + } + else if (audioConfig == AUDIO_CONFIGURATION_5_1) { + config.audioChannelCount = CHANNEL_COUNT_5_1; + config.audioChannelMask = CHANNEL_MASK_5_1; + } + return this; } @@ -87,8 +103,8 @@ public class StreamConfiguration { this.maxPacketSize = 1024; this.sops = true; this.enableAdaptiveResolution = false; - this.audioChannelCount = 2; - this.audioChannelMask = 0x3; + this.audioChannelCount = CHANNEL_COUNT_STEREO; + this.audioChannelMask = CHANNEL_MASK_STEREO; } public int getWidth() { diff --git a/moonlight-common/src/com/limelight/nvstream/av/audio/AudioDepacketizer.java b/moonlight-common/src/com/limelight/nvstream/av/audio/AudioDepacketizer.java index e608076b..7f418db2 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/audio/AudioDepacketizer.java +++ b/moonlight-common/src/com/limelight/nvstream/av/audio/AudioDepacketizer.java @@ -11,9 +11,7 @@ public class AudioDepacketizer { private static final int DU_LIMIT = 30; private AbstractPopulatedBufferList decodedUnits; - - private final int channelCount; - + // Direct submit state private AudioRenderer directSubmitRenderer; private byte[] directSubmitData; @@ -24,10 +22,9 @@ public class AudioDepacketizer { // Sequencing state private short lastSequenceNumber; - public AudioDepacketizer(AudioRenderer directSubmitRenderer, final int channelCount, final int bufferSizeShorts) + public AudioDepacketizer(AudioRenderer directSubmitRenderer, final int bufferSizeShorts) { this.directSubmitRenderer = directSubmitRenderer; - this.channelCount = channelCount; if (directSubmitRenderer != null) { this.directSubmitData = new byte[bufferSizeShorts*2]; } @@ -68,9 +65,6 @@ public class AudioDepacketizer { } if (decodeLen > 0) { - // Return value of decode is frames (shorts) decoded per channel - decodeLen *= 2*channelCount; - if (directSubmitRenderer != null) { directSubmitRenderer.playDecodedAudio(directSubmitData, 0, decodeLen); } diff --git a/moonlight-common/src/com/limelight/nvstream/av/audio/AudioStream.java b/moonlight-common/src/com/limelight/nvstream/av/audio/AudioStream.java index 1b738106..5afd34b9 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/audio/AudioStream.java +++ b/moonlight-common/src/com/limelight/nvstream/av/audio/AudioStream.java @@ -19,7 +19,7 @@ public class AudioStream { 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; + private static final int MAX_PACKET_SIZE = 250; private DatagramSocket rtp; @@ -93,14 +93,36 @@ public class AudioStream { rtp.setReceiveBufferSize(RTP_RECV_BUFFER); } + private static final int[] STREAMS_2 = new int[] {1, 1}; + private static final int[] STREAMS_5_1 = new int[] {4, 2}; + + private static final byte[] MAPPING_2 = new byte[] {0, 1}; + private static final byte[] MAPPING_5_1 = new byte[] {0, 4, 1, 5, 2, 3}; + private boolean setupAudio() { int err; - err = OpusDecoder.init(SAMPLE_RATE, context.streamConfig.getAudioChannelCount(), - 1, 1, new byte[]{0, 1, 2, 3, 4, 5, 6}); + int channels = context.streamConfig.getAudioChannelCount(); + byte[] mapping; + int[] streams; + + if (channels == 2) { + mapping = MAPPING_2; + streams = STREAMS_2; + } + else if (channels == 6) { + mapping = MAPPING_5_1; + streams = STREAMS_5_1; + } + else { + throw new IllegalStateException("Unsupported surround configuration"); + } + + err = OpusDecoder.init(SAMPLE_RATE, SHORTS_PER_CHANNEL, channels, + streams[0], streams[1], mapping); if (err != 0) { - throw new IllegalStateException("Opus decoder failed to initialize"); + throw new IllegalStateException("Opus decoder failed to initialize: "+err); } if (!streamListener.streamInitialized(context.streamConfig.getAudioChannelCount(), @@ -111,12 +133,10 @@ public class AudioStream { } if ((streamListener.getCapabilities() & AudioRenderer.CAPABILITY_DIRECT_SUBMIT) != 0) { - depacketizer = new AudioDepacketizer(streamListener, context.streamConfig.getAudioChannelCount(), - context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL); + depacketizer = new AudioDepacketizer(streamListener, context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL); } else { - depacketizer = new AudioDepacketizer(null, context.streamConfig.getAudioChannelCount(), - context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL); + depacketizer = new AudioDepacketizer(null, context.streamConfig.getAudioChannelCount()*SHORTS_PER_CHANNEL); } return true; diff --git a/moonlight-common/src/com/limelight/nvstream/av/audio/OpusDecoder.java b/moonlight-common/src/com/limelight/nvstream/av/audio/OpusDecoder.java index 37212be3..9180c4c1 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/audio/OpusDecoder.java +++ b/moonlight-common/src/com/limelight/nvstream/av/audio/OpusDecoder.java @@ -5,7 +5,7 @@ public class OpusDecoder { System.loadLibrary("nv_opus_dec"); } - public static native int init(int sampleRate, int channelCount, int streams, int coupledStreams, byte[] mapping); + public static native int init(int sampleRate, int samplesPerChannel, int channelCount, int streams, int coupledStreams, byte[] mapping); public static native void destroy(); public static native int decode(byte[] indata, int inoff, int inlen, byte[] outpcmdata); }