Skip to content

Commit

Permalink
it works and its threaded!
Browse files Browse the repository at this point in the history
  • Loading branch information
ImUrX committed Sep 15, 2021
1 parent 3d0db98 commit 8d9530e
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 36 deletions.
65 changes: 38 additions & 27 deletions src/main/java/io/github/imurx/audioswitcher/AudioSwitcher.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,70 @@
package io.github.imurx.audioswitcher;

import io.github.imurx.audioswitcher.events.SoundSystemCallback;
import io.github.imurx.audioswitcher.mixin.SoundEngineAccessor;
import io.github.imurx.audioswitcher.mixin.SoundManagerAccessor;
import io.github.imurx.audioswitcher.mixin.SoundSystemAccessor;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.SoundEngine;
import net.minecraft.client.sound.SoundSystem;
import org.lwjgl.openal.*;

import java.nio.LongBuffer;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class AudioSwitcher implements ClientModInitializer {
private Timer timer;
private int tickCounter = -1;
static private Thread thread;
static public List<String> devices;
static public String defaultDevice = "";
static public String currentDevice = "";
static public AudioSwitcher switcher;
static public String preferredDevice = "";
static public boolean useDefault = true;

@Override
public void onInitializeClient() {
updateDevices();
switcher = this; //not good
}
ClientTickEvents.END_CLIENT_TICK.register((client) -> {
if(tickCounter < 0 || ++tickCounter < 40) return;
SoundEngine engine = ((SoundSystemAccessor) ((SoundManagerAccessor) client.getSoundManager()).getSoundSystem()).getSoundEngine();
SoundEngineAccessor accessor = (SoundEngineAccessor) engine;
int connect = ALC11.alcGetInteger(accessor.getDevicePointer(), EXTDisconnect.ALC_CONNECTED);
updateDevices();

public void onInitialized() {
timer = new Timer("AudioSwitcherChecker");
timer.scheduleAtFixedRate(new DisconnectCheckTask(), 0, 2000);
}
if(thread != null) {
try {
thread.join();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
thread = null;
return;
}

public void onStopSystem() {
if(timer != null) timer.cancel();
if(connect == ALC11.ALC_FALSE) {
thread = new Thread(() -> restartSoundSystem(defaultDevice));
} else if(!currentDevice.equals(preferredDevice) && devices.contains(preferredDevice)) {
thread = new Thread(() -> restartSoundSystem(preferredDevice));
} else {
return;
}

thread.setName("AudioSwitcher");
thread.start();
});
SoundSystemCallback.STARTED_SYSTEM.register((_x) -> tickCounter = 0);
SoundSystemCallback.STOPPING_SYSTEM.register((_x) -> tickCounter = -1);
}

static public void updateDevices() {
devices = ALUtil.getStringList(0, ALC11.ALC_ALL_DEVICES_SPECIFIER);
defaultDevice = ALC11.alcGetString(0, ALC11.ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
}

static public class DisconnectCheckTask extends TimerTask {
@Override
public void run() {
SoundSystem soundSystem = ((SoundManagerAccessor) MinecraftClient.getInstance().getSoundManager()).getSoundSystem();
SoundEngine engine = ((SoundSystemAccessor) soundSystem).getSoundEngine();
SoundEngineAccessor accessor = (SoundEngineAccessor) engine;
int connect = ALC11.alcGetInteger(accessor.getDevicePointer(), EXTDisconnect.ALC_CONNECTED);
if(connect == ALC11.ALC_FALSE) {
updateDevices();
currentDevice = defaultDevice;
soundSystem.reloadSounds();
}
}
static public void restartSoundSystem(String device) {
SoundSystem soundSystem = ((SoundManagerAccessor) MinecraftClient.getInstance().getSoundManager()).getSoundSystem();
soundSystem.stop();
currentDevice = device;
((SoundSystemAccessor) soundSystem).callStart();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.imurx.audioswitcher.events;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.sound.SoundSystem;

public interface SoundSystemCallback {

Event<SoundSystemCallback> STARTED_SYSTEM = EventFactory.createArrayBacked(SoundSystemCallback.class,
(listeners) -> (soundSystem) -> {
for(SoundSystemCallback listener : listeners) {
listener.onStateChange(soundSystem);
}
});

Event<SoundSystemCallback> STOPPING_SYSTEM = EventFactory.createArrayBacked(SoundSystemCallback.class,
(listeners) -> (soundSystem) -> {
for(SoundSystemCallback listener : listeners) {
listener.onStateChange(soundSystem);
}
});

void onStateChange(SoundSystem soundSystem);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
import net.minecraft.client.sound.SoundSystem;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;


@Mixin(SoundOptionsScreen.class)
public class SoundOptionsScreenMixin extends GameOptionsScreen {
int selectedIndex = 0;
@Unique
public int selectedIndex = 0;

public SoundOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text title) {
super(parent, gameOptions, title);
}
Expand All @@ -38,10 +41,15 @@ private Element addSubtitleWidget(SoundOptionsScreen soundOptionsScreen, Element
throw new IllegalStateException("The subtitle button isn't a ClickableWidget!");
}
AudioSwitcher.updateDevices();
if(!AudioSwitcher.useDefault) {
selectedIndex = AudioSwitcher.devices.indexOf(AudioSwitcher.currentDevice) + 1;
} else {
selectedIndex = 0;
}
subtitleWidget.x = this.width / 2 + 5;
subtitleWidget.y -= 24;
this.addDrawableChild(subtitleWidget);
String option = AudioSwitcher.useDefault ? "Device: Default" : "Device: " + AudioSwitcher.currentDevice.replaceAll("OpenAL Soft on ", "");
String option = AudioSwitcher.useDefault ? "Device: System Default" : "Device: " + AudioSwitcher.currentDevice.replaceAll("OpenAL Soft on ", "");
ButtonWidget sourcesWidget = new RightClickableWidget(subtitleWidget.x - 160, subtitleWidget.y + 24, subtitleWidget.getWidth() * 2 + 10, subtitleWidget.getHeight(), Text.of(option), (button) -> {
if(++selectedIndex > AudioSwitcher.devices.size()) {
selectedIndex = 0;
Expand All @@ -57,18 +65,20 @@ private Element addSubtitleWidget(SoundOptionsScreen soundOptionsScreen, Element
return widget;
}

@Unique
private void updateDevice(ClickableWidget button) {
SoundSystem soundSystem = ((SoundManagerAccessor) MinecraftClient.getInstance().getSoundManager()).getSoundSystem();
if(selectedIndex == 0) {
AudioSwitcher.useDefault = true;
button.setMessage(Text.of("Device: Default"));
button.setMessage(Text.of("Device: System Default"));
soundSystem.reloadSounds();
return;
} else if(AudioSwitcher.useDefault) {
AudioSwitcher.useDefault = false;
}
AudioSwitcher.currentDevice = AudioSwitcher.devices.get(selectedIndex - 1);
AudioSwitcher.preferredDevice = AudioSwitcher.currentDevice;
button.setMessage(Text.of("Device: " + AudioSwitcher.currentDevice.replaceAll("OpenAL Soft on ", "")));
soundSystem.reloadSounds();
AudioSwitcher.restartSoundSystem(AudioSwitcher.currentDevice);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import net.minecraft.client.sound.SoundSystem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;

@Mixin(SoundSystem.class)
public interface SoundSystemAccessor {
@Accessor
SoundEngine getSoundEngine();
@Invoker
void callStart();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.github.imurx.audioswitcher.mixin;

import io.github.imurx.audioswitcher.AudioSwitcher;
import io.github.imurx.audioswitcher.events.SoundSystemCallback;
import net.minecraft.client.sound.SoundSystem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -13,15 +13,15 @@ public class SoundSystemMixin {
method = "start",
at = @At("TAIL")
)
void onStarted(CallbackInfo ci) {
AudioSwitcher.switcher.onInitialized();
private void onStarted(CallbackInfo ci) {
SoundSystemCallback.STARTED_SYSTEM.invoker().onStateChange((SoundSystem) (Object) this);
}

@Inject(
method = "stop()V",
at = @At("HEAD")
)
void onStopped(CallbackInfo ci) {
AudioSwitcher.switcher.onStopSystem();
private void onStopped(CallbackInfo ci) {
SoundSystemCallback.STOPPING_SYSTEM.invoker().onStateChange((SoundSystem) (Object) this);
}
}

0 comments on commit 8d9530e

Please sign in to comment.