Refactor audio configuration in preparation for 7.1 surround sound

This commit is contained in:
Cameron Gutman 2020-04-03 17:47:57 -07:00
parent c957b8b06b
commit 49a1524f4f
9 changed files with 90 additions and 53 deletions

View File

@ -454,9 +454,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
.setEnableHdr(willStreamHdr) .setEnableHdr(willStreamHdr)
.setAttachedGamepadMask(gamepadMask) .setAttachedGamepadMask(gamepadMask)
.setClientRefreshRateX100((int)(displayRefreshRate * 100)) .setClientRefreshRateX100((int)(displayRefreshRate * 100))
.setAudioConfiguration(prefConfig.enable51Surround ? .setAudioConfiguration(prefConfig.audioConfiguration)
MoonBridge.AUDIO_CONFIGURATION_51_SURROUND :
MoonBridge.AUDIO_CONFIGURATION_STEREO)
.build(); .build();
// Initialize the connection // Initialize the connection

View File

@ -64,25 +64,36 @@ public class AndroidAudioRenderer implements AudioRenderer {
} }
@Override @Override
public int setup(int audioConfiguration, int sampleRate, int samplesPerFrame) { public int setup(MoonBridge.AudioConfiguration audioConfiguration, int sampleRate, int samplesPerFrame) {
int channelConfig; int channelConfig;
int bytesPerFrame; int bytesPerFrame;
switch (audioConfiguration) switch (audioConfiguration.channelCount)
{ {
case MoonBridge.AUDIO_CONFIGURATION_STEREO: case 2:
channelConfig = AudioFormat.CHANNEL_OUT_STEREO; channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
bytesPerFrame = 2 * samplesPerFrame * 2;
break; break;
case MoonBridge.AUDIO_CONFIGURATION_51_SURROUND: case 4:
channelConfig = AudioFormat.CHANNEL_OUT_QUAD;
break;
case 6:
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1; channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
bytesPerFrame = 6 * samplesPerFrame * 2; break;
case 8:
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
// in 5.0, so just hardcode the constant so we can work on Lollipop.
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
break; break;
default: default:
LimeLog.severe("Decoder returned unhandled channel count"); LimeLog.severe("Decoder returned unhandled channel count");
return -1; return -1;
} }
LimeLog.info("Audio channel config: "+String.format("0x%X", channelConfig));
bytesPerFrame = audioConfiguration.channelCount * samplesPerFrame * 2;
// We're not supposed to request less than the minimum // We're not supposed to request less than the minimum
// buffer size for our buffer, but it appears that we can // buffer size for our buffer, but it appears that we can
// do this on many devices and it lowers audio latency. // do this on many devices and it lowers audio latency.

View File

@ -263,7 +263,7 @@ public class NvConnection {
context.negotiatedWidth, context.negotiatedHeight, context.negotiatedWidth, context.negotiatedHeight,
context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(), context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(),
context.streamConfig.getMaxPacketSize(), context.streamConfig.getMaxPacketSize(),
context.streamConfig.getRemote(), context.streamConfig.getAudioConfiguration(), context.streamConfig.getRemote(), context.streamConfig.getAudioConfiguration().toInt(),
context.streamConfig.getHevcSupported(), context.streamConfig.getHevcSupported(),
context.negotiatedHdr, context.negotiatedHdr,
context.streamConfig.getHevcBitratePercentageMultiplier(), context.streamConfig.getHevcBitratePercentageMultiplier(),

View File

@ -9,12 +9,6 @@ public class StreamConfiguration {
public static final int STREAM_CFG_LOCAL = 0; public static final int STREAM_CFG_LOCAL = 0;
public static final int STREAM_CFG_REMOTE = 1; public static final int STREAM_CFG_REMOTE = 1;
public static final int STREAM_CFG_AUTO = 2; public static final int STREAM_CFG_AUTO = 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 NvApp app;
private int width, height; private int width, height;
@ -27,9 +21,7 @@ public class StreamConfiguration {
private boolean playLocalAudio; private boolean playLocalAudio;
private int maxPacketSize; private int maxPacketSize;
private int remote; private int remote;
private int audioChannelMask; private MoonBridge.AudioConfiguration audioConfiguration;
private int audioChannelCount;
private int audioConfiguration;
private boolean supportsHevc; private boolean supportsHevc;
private int hevcBitratePercentageMultiplier; private int hevcBitratePercentageMultiplier;
private boolean enableHdr; private boolean enableHdr;
@ -119,21 +111,8 @@ public class StreamConfiguration {
return this; return this;
} }
public StreamConfiguration.Builder setAudioConfiguration(int audioConfig) { public StreamConfiguration.Builder setAudioConfiguration(MoonBridge.AudioConfiguration audioConfig) {
if (audioConfig == MoonBridge.AUDIO_CONFIGURATION_STEREO) {
config.audioChannelCount = CHANNEL_COUNT_STEREO;
config.audioChannelMask = CHANNEL_MASK_STEREO;
}
else if (audioConfig == MoonBridge.AUDIO_CONFIGURATION_51_SURROUND) {
config.audioChannelCount = CHANNEL_COUNT_5_1;
config.audioChannelMask = CHANNEL_MASK_5_1;
}
else {
throw new IllegalArgumentException("Invalid audio configuration");
}
config.audioConfiguration = audioConfig; config.audioConfiguration = audioConfig;
return this; return this;
} }
@ -159,8 +138,7 @@ public class StreamConfiguration {
this.remote = STREAM_CFG_AUTO; this.remote = STREAM_CFG_AUTO;
this.sops = true; this.sops = true;
this.enableAdaptiveResolution = false; this.enableAdaptiveResolution = false;
this.audioChannelCount = CHANNEL_COUNT_STEREO; this.audioConfiguration = MoonBridge.AUDIO_CONFIGURATION_STEREO;
this.audioChannelMask = CHANNEL_MASK_STEREO;
this.supportsHevc = false; this.supportsHevc = false;
this.enableHdr = false; this.enableHdr = false;
this.attachedGamepadMask = 0; this.attachedGamepadMask = 0;
@ -209,16 +187,8 @@ public class StreamConfiguration {
public int getRemote() { public int getRemote() {
return remote; return remote;
} }
public int getAudioChannelCount() {
return audioChannelCount;
}
public int getAudioChannelMask() {
return audioChannelMask;
}
public int getAudioConfiguration() { public MoonBridge.AudioConfiguration getAudioConfiguration() {
return audioConfiguration; return audioConfiguration;
} }

View File

@ -1,7 +1,9 @@
package com.limelight.nvstream.av.audio; package com.limelight.nvstream.av.audio;
import com.limelight.nvstream.jni.MoonBridge;
public interface AudioRenderer { public interface AudioRenderer {
int setup(int audioConfiguration, int sampleRate, int samplesPerFrame); int setup(MoonBridge.AudioConfiguration audioConfiguration, int sampleRate, int samplesPerFrame);
void start(); void start();

View File

@ -648,7 +648,7 @@ public class NvHTTP {
"&rikeyid="+context.riKeyId + "&rikeyid="+context.riKeyId +
(!enableHdr ? "" : "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0") + (!enableHdr ? "" : "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0") +
"&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) + "&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) +
"&surroundAudioInfo=" + ((context.streamConfig.getAudioChannelMask() << 16) + context.streamConfig.getAudioChannelCount()) + "&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") + (context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""), (context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""),
false); false);
@ -660,7 +660,7 @@ public class NvHTTP {
String xmlStr = openHttpConnectionToString(baseUrlHttps + "/resume?" + buildUniqueIdUuidString() + String xmlStr = openHttpConnectionToString(baseUrlHttps + "/resume?" + buildUniqueIdUuidString() +
"&rikey="+bytesToHex(context.riKey.getEncoded()) + "&rikey="+bytesToHex(context.riKey.getEncoded()) +
"&rikeyid="+context.riKeyId + "&rikeyid="+context.riKeyId +
"&surroundAudioInfo=" + ((context.streamConfig.getAudioChannelMask() << 16) + context.streamConfig.getAudioChannelCount()), "&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo(),
false); false);
String resume = getXmlString(xmlStr, "resume"); String resume = getXmlString(xmlStr, "resume");
return Integer.parseInt(resume) != 0; return Integer.parseInt(resume) != 0;

View File

@ -7,8 +7,9 @@ import com.limelight.nvstream.av.video.VideoDecoderRenderer;
public class MoonBridge { public class MoonBridge {
/* See documentation in Limelight.h for information about these functions and constants */ /* See documentation in Limelight.h for information about these functions and constants */
public static final int AUDIO_CONFIGURATION_STEREO = 0; public static final AudioConfiguration AUDIO_CONFIGURATION_STEREO = new AudioConfiguration(2, 0x3);
public static final int AUDIO_CONFIGURATION_51_SURROUND = 1; public static final AudioConfiguration AUDIO_CONFIGURATION_51_SURROUND = new AudioConfiguration(6, 0x3F);
public static final AudioConfiguration AUDIO_CONFIGURATION_71_SURROUND = new AudioConfiguration(8, 0x63F);
public static final int VIDEO_FORMAT_H264 = 0x0001; public static final int VIDEO_FORMAT_H264 = 0x0001;
public static final int VIDEO_FORMAT_H265 = 0x0100; public static final int VIDEO_FORMAT_H265 = 0x0100;
@ -45,6 +46,57 @@ public class MoonBridge {
return slices << 24; return slices << 24;
} }
public static class AudioConfiguration {
public final int channelCount;
public final int channelMask;
public AudioConfiguration(int channelCount, int channelMask) {
this.channelCount = channelCount;
this.channelMask = channelMask;
}
// Creates an AudioConfiguration from the integer value returned by moonlight-common-c
// See CHANNEL_COUNT_FROM_AUDIO_CONFIGURATION() and CHANNEL_MASK_FROM_AUDIO_CONFIGURATION()
// in Limelight.h
private AudioConfiguration(int audioConfiguration) {
// Check the magic byte before decoding to make sure we got something that's actually
// a MAKE_AUDIO_CONFIGURATION()-based value and not something else like an older version
// hardcoded AUDIO_CONFIGURATION value from an earlier version of moonlight-common-c.
if ((audioConfiguration & 0xFF) != 0xCA) {
throw new IllegalArgumentException("Audio configuration has invalid magic byte!");
}
this.channelCount = (audioConfiguration >> 8) & 0xFF;
this.channelMask = (audioConfiguration >> 16) & 0xFFFF;
}
// See SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION() in Limelight.h
public int getSurroundAudioInfo() {
return channelMask << 16 | channelCount;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof AudioConfiguration) {
AudioConfiguration that = (AudioConfiguration)obj;
return this.toInt() == that.toInt();
}
return false;
}
@Override
public int hashCode() {
return toInt();
}
// Returns the integer value expected by moonlight-common-c
// See MAKE_AUDIO_CONFIGURATION() in Limelight.h
public int toInt() {
return ((channelMask) << 16) | (channelCount << 8) | 0xCA;
}
}
public static int bridgeDrSetup(int videoFormat, int width, int height, int redrawRate) { public static int bridgeDrSetup(int videoFormat, int width, int height, int redrawRate) {
if (videoRenderer != null) { if (videoRenderer != null) {
return videoRenderer.setup(videoFormat, width, height, redrawRate); return videoRenderer.setup(videoFormat, width, height, redrawRate);
@ -86,7 +138,7 @@ public class MoonBridge {
public static int bridgeArInit(int audioConfiguration, int sampleRate, int samplesPerFrame) { public static int bridgeArInit(int audioConfiguration, int sampleRate, int samplesPerFrame) {
if (audioRenderer != null) { if (audioRenderer != null) {
return audioRenderer.setup(audioConfiguration, sampleRate, samplesPerFrame); return audioRenderer.setup(new AudioConfiguration(audioConfiguration), sampleRate, samplesPerFrame);
} }
else { else {
return -1; return -1;

View File

@ -6,6 +6,8 @@ import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import com.limelight.nvstream.jni.MoonBridge;
public class PreferenceConfiguration { public class PreferenceConfiguration {
private static final String LEGACY_RES_FPS_PREF_STRING = "list_resolution_fps"; private static final String LEGACY_RES_FPS_PREF_STRING = "list_resolution_fps";
@ -78,7 +80,7 @@ public class PreferenceConfiguration {
public int oscOpacity; public int oscOpacity;
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings; public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
public String language; public String language;
public boolean listMode, smallIconMode, multiController, enable51Surround, usbDriver; public boolean listMode, smallIconMode, multiController, usbDriver;
public boolean onscreenController; public boolean onscreenController;
public boolean onlyL3R3; public boolean onlyL3R3;
public boolean disableFrameDrop; public boolean disableFrameDrop;
@ -91,6 +93,7 @@ public class PreferenceConfiguration {
public boolean unlockFps; public boolean unlockFps;
public boolean vibrateOsc; public boolean vibrateOsc;
public boolean vibrateFallbackToDevice; public boolean vibrateFallbackToDevice;
public MoonBridge.AudioConfiguration audioConfiguration;
private static int getHeightFromResolutionString(String resString) { private static int getHeightFromResolutionString(String resString) {
if (resString.equalsIgnoreCase("360p")) { if (resString.equalsIgnoreCase("360p")) {
@ -332,7 +335,8 @@ public class PreferenceConfiguration {
config.listMode = prefs.getBoolean(LIST_MODE_PREF_STRING, DEFAULT_LIST_MODE); config.listMode = prefs.getBoolean(LIST_MODE_PREF_STRING, DEFAULT_LIST_MODE);
config.smallIconMode = prefs.getBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context)); config.smallIconMode = prefs.getBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context));
config.multiController = prefs.getBoolean(MULTI_CONTROLLER_PREF_STRING, DEFAULT_MULTI_CONTROLLER); config.multiController = prefs.getBoolean(MULTI_CONTROLLER_PREF_STRING, DEFAULT_MULTI_CONTROLLER);
config.enable51Surround = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND); config.audioConfiguration = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND) ?
MoonBridge.AUDIO_CONFIGURATION_51_SURROUND : MoonBridge.AUDIO_CONFIGURATION_STEREO;
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER); config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT); config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT); config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);

@ -1 +1 @@
Subproject commit f489c9d725d22517d3b3a017f6bbb0a22ed43707 Subproject commit 85de16b41bca7ece0a6e0c69acdb76a5da0e79e0