diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java
index baf0bc20..f8b05642 100644
--- a/app/src/main/java/com/limelight/Game.java
+++ b/app/src/main/java/com/limelight/Game.java
@@ -2,6 +2,7 @@ package com.limelight;
import com.limelight.binding.PlatformBinding;
+import com.limelight.binding.audio.AndroidAudioRenderer;
import com.limelight.binding.input.ControllerHandler;
import com.limelight.binding.input.KeyboardTranslator;
import com.limelight.binding.input.capture.InputCaptureManager;
@@ -1920,7 +1921,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
UiHelper.notifyStreamConnecting(Game.this);
decoderRenderer.setRenderTarget(holder);
- conn.start(PlatformBinding.getAudioRenderer(), decoderRenderer, Game.this);
+ conn.start(new AndroidAudioRenderer(Game.this, prefConfig.enableAudioFx),
+ decoderRenderer, Game.this);
}
}
diff --git a/app/src/main/java/com/limelight/binding/PlatformBinding.java b/app/src/main/java/com/limelight/binding/PlatformBinding.java
index b37c7645..73bb2a30 100644
--- a/app/src/main/java/com/limelight/binding/PlatformBinding.java
+++ b/app/src/main/java/com/limelight/binding/PlatformBinding.java
@@ -8,16 +8,6 @@ import com.limelight.nvstream.av.audio.AudioRenderer;
import com.limelight.nvstream.http.LimelightCryptoProvider;
public class PlatformBinding {
- public static String getDeviceName() {
- String deviceName = android.os.Build.MODEL;
- deviceName = deviceName.replace(" ", "");
- return deviceName;
- }
-
- public static AudioRenderer getAudioRenderer() {
- return new AndroidAudioRenderer();
- }
-
public static LimelightCryptoProvider getCryptoProvider(Context c) {
return new AndroidCryptoProvider(c);
}
diff --git a/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java b/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java
index bbecec63..7c7776bc 100644
--- a/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java
+++ b/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java
@@ -1,9 +1,12 @@
package com.limelight.binding.audio;
+import android.content.Context;
+import android.content.Intent;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.media.audiofx.AudioEffect;
import android.os.Build;
import com.limelight.LimeLog;
@@ -12,8 +15,16 @@ import com.limelight.nvstream.jni.MoonBridge;
public class AndroidAudioRenderer implements AudioRenderer {
+ private final Context context;
+ private final boolean enableAudioFx;
+
private AudioTrack track;
+ public AndroidAudioRenderer(Context context, boolean enableAudioFx) {
+ this.context = context;
+ this.enableAudioFx = enableAudioFx;
+ }
+
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return new AudioTrack(AudioManager.STREAM_MUSIC,
@@ -161,6 +172,12 @@ public class AndroidAudioRenderer implements AudioRenderer {
continue;
}
+ // Skip low latency options when using audio effects, since low latency mode
+ // precludes the use of the audio effect pipeline (as of Android 13).
+ if (enableAudioFx && lowLatency) {
+ continue;
+ }
+
try {
track = createAudioTrack(channelConfig, sampleRate, bufferSize, lowLatency);
track.play();
@@ -203,10 +220,27 @@ public class AndroidAudioRenderer implements AudioRenderer {
}
@Override
- public void start() {}
+ public void start() {
+ if (enableAudioFx) {
+ // Open an audio effect control session to allow equalizers to apply audio effects
+ Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
+ i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, track.getAudioSessionId());
+ i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
+ i.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_GAME);
+ context.sendBroadcast(i);
+ }
+ }
@Override
- public void stop() {}
+ public void stop() {
+ if (enableAudioFx) {
+ // Close our audio effect control session when we're stopping
+ Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+ i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, track.getAudioSessionId());
+ i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
+ context.sendBroadcast(i);
+ }
+ }
@Override
public void cleanup() {
diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
index 8720ec00..f19592e0 100644
--- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
+++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
@@ -45,6 +45,7 @@ public class PreferenceConfiguration {
private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast";
private static final String FRAME_PACING_PREF_STRING = "frame_pacing";
private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode";
+ private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx";
static final String DEFAULT_RESOLUTION = "1280x720";
static final String DEFAULT_FPS = "60";
@@ -75,6 +76,7 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_LATENCY_TOAST = false;
private static final String DEFAULT_FRAME_PACING = "latency";
private static final boolean DEFAULT_ABSOLUTE_MOUSE_MODE = false;
+ private static final boolean DEFAULT_ENABLE_AUDIO_FX = false;
public static final int FORCE_H265_ON = -1;
public static final int AUTOSELECT_H265 = 0;
@@ -117,6 +119,7 @@ public class PreferenceConfiguration {
public MoonBridge.AudioConfiguration audioConfiguration;
public int framePacing;
public boolean absoluteMouseMode;
+ public boolean enableAudioFx;
public static boolean isNativeResolution(int width, int height) {
// It's not a native resolution if it matches an existing resolution option
@@ -471,6 +474,7 @@ public class PreferenceConfiguration {
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
+ config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
return config;
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4b672c16..1fb47e5b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -156,6 +156,8 @@
Audio Settings
Surround sound configuration
Enable 5.1 or 7.1 surround sound for home-theater systems
+ Enable system equalizer support
+ Allows audio effects to function while streaming, but may increase audio latency
Input Settings
Use the touchscreen as a trackpad
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 9a3627c2..1add66f0 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -49,6 +49,11 @@
android:entries="@array/audio_config_names"
android:entryValues="@array/audio_config_values"
android:defaultValue="2" />
+