diff --git a/src/main/java/de/extio/game_engine/audio/AudioController.java b/src/main/java/de/extio/game_engine/audio/AudioController.java index a558dab..54789ad 100644 --- a/src/main/java/de/extio/game_engine/audio/AudioController.java +++ b/src/main/java/de/extio/game_engine/audio/AudioController.java @@ -11,7 +11,7 @@ public final class AudioController implements AudioControl { private final StorageService storageService; - private AudioOptions audioOptions; + private final AudioOptions audioOptions; // Passed as reference to strategies private AudioStrategy audioStrategy; @@ -31,12 +31,12 @@ public final class AudioController implements AudioControl { public AudioController(final StaticResourceService resourceService, final StorageService storageService) { this.storageService = storageService; - storageService.loadByPath(AudioOptions.class, List.of("audio"), "audioOptions").ifPresentOrElse( + this.audioOptions = new AudioOptions(); + storageService.loadByPath(AudioOptions.class, List.of("gameEngine"), "audioOptions").ifPresentOrElse( loadedOptions -> { - this.audioOptions = loadedOptions; + this.audioOptions.apply(loadedOptions); }, () -> { - this.audioOptions = new AudioOptions(); this.storeAudioOptions(); }); @@ -63,7 +63,7 @@ public final class AudioController implements AudioControl { } private void storeAudioOptions() { - this.storageService.store(List.of("audio"), "audioOptions", this.audioOptions); + this.storageService.store(List.of("gameEngine"), "audioOptions", this.audioOptions); } public void run() { @@ -91,11 +91,11 @@ public final class AudioController implements AudioControl { .start(this.audioLoader); if (this.audioOptions.getSfxOptions().isSoftwareMixing()) { - this.audioStrategy = new AudioStrategySoftwareMixing(this.audioOptions, this.audioLoader); + this.audioStrategy = new AudioStrategySoftwareMixing(this, this.audioOptions, this.audioLoader); this.useSoftwareMixing = true; } else { - this.audioStrategy = new AudioStrategyJavaMixer(this.audioOptions, this.audioLoader); + this.audioStrategy = new AudioStrategyJavaMixer(this, this.audioOptions, this.audioLoader); this.useSoftwareMixing = false; } diff --git a/src/main/java/de/extio/game_engine/audio/AudioPlayerMultiStream.java b/src/main/java/de/extio/game_engine/audio/AudioPlayerMultiStream.java index 8954c75..963b097 100644 --- a/src/main/java/de/extio/game_engine/audio/AudioPlayerMultiStream.java +++ b/src/main/java/de/extio/game_engine/audio/AudioPlayerMultiStream.java @@ -26,6 +26,8 @@ final class AudioPlayerMultiStream implements AudioPlayer { private static final int MUSIC_FADING_MS = 1000; private final BlockingQueue queue = new LinkedBlockingQueue<>(20); + + private final AudioControl audioControl; private volatile AudioData musicQueue; @@ -51,7 +53,8 @@ final class AudioPlayerMultiStream implements AudioPlayer { private long notStartedAudioCnt; - public AudioPlayerMultiStream() { + public AudioPlayerMultiStream(AudioControl audioControl) { + this.audioControl = audioControl; } @Override @@ -288,6 +291,10 @@ final class AudioPlayerMultiStream implements AudioPlayer { if (++this.notStartedAudioCnt > 5) { this.notStartedAudioCnt = 0; + var options =this.audioControl.getAudioOptions(); + options.getSfxOptions().enable = false; + options.getMusicOptions().enable = false; + this.audioControl.applyAudioOptions(options); this.exit = true; LOGGER.error("Too many audio playback errors, shutting down audio player."); } diff --git a/src/main/java/de/extio/game_engine/audio/AudioPlayerSingleStream.java b/src/main/java/de/extio/game_engine/audio/AudioPlayerSingleStream.java index 09265d4..c8c8d37 100644 --- a/src/main/java/de/extio/game_engine/audio/AudioPlayerSingleStream.java +++ b/src/main/java/de/extio/game_engine/audio/AudioPlayerSingleStream.java @@ -24,6 +24,8 @@ final class AudioPlayerSingleStream implements AudioPlayer { private final BlockingQueue queue = new LinkedBlockingQueue<>(5); + private final AudioControl audioControl; + private volatile boolean stopAudio; private volatile boolean playing; @@ -40,7 +42,8 @@ final class AudioPlayerSingleStream implements AudioPlayer { private int notStartedAudioCnt; - public AudioPlayerSingleStream() { + public AudioPlayerSingleStream(AudioControl audioControl) { + this.audioControl = audioControl; } @Override @@ -124,6 +127,10 @@ final class AudioPlayerSingleStream implements AudioPlayer { if (++this.notStartedAudioCnt > 5) { this.notStartedAudioCnt = 0; + var options =this.audioControl.getAudioOptions(); + options.getSfxOptions().enable = false; + options.getMusicOptions().enable = false; + this.audioControl.applyAudioOptions(options); this.exit = true; LOGGER.error("Too many audio playback errors, shutting down audio player."); } diff --git a/src/main/java/de/extio/game_engine/audio/AudioStrategyJavaMixer.java b/src/main/java/de/extio/game_engine/audio/AudioStrategyJavaMixer.java index c0b0430..0f5eae9 100644 --- a/src/main/java/de/extio/game_engine/audio/AudioStrategyJavaMixer.java +++ b/src/main/java/de/extio/game_engine/audio/AudioStrategyJavaMixer.java @@ -25,7 +25,9 @@ final class AudioStrategyJavaMixer implements AudioStrategy { private final static int MUSIC_INITIAL_DELAY_MS = 1000; - private final AudioOptions clientEngineData; + private final AudioControl audioControl; + + private final AudioOptions audioOptions; private final AudioLoader audioLoader; @@ -33,7 +35,7 @@ final class AudioStrategyJavaMixer implements AudioStrategy { private final List sfxAudioPlayers = new ArrayList<>(SFX_PLAYERS); - private final Set sfxQueue = new LinkedHashSet<>(); + private final Set sfxQueue = Collections.synchronizedSet(new LinkedHashSet<>()); private final List sfxPlayersBySize = new ArrayList<>(SFX_PLAYERS); @@ -47,15 +49,16 @@ final class AudioStrategyJavaMixer implements AudioStrategy { private long musicFirstQueued; - public AudioStrategyJavaMixer(final AudioOptions clientEngineData, final AudioLoader audioLoader) { - this.clientEngineData = clientEngineData; + public AudioStrategyJavaMixer(final AudioControl audioControl, final AudioOptions audioOptions, final AudioLoader audioLoader) { + this.audioControl = audioControl; + this.audioOptions = audioOptions; this.audioLoader = audioLoader; } @Override public void start() { { - final var musicAudioPlayer = new AudioPlayerSingleStream(); + final var musicAudioPlayer = new AudioPlayerSingleStream(this.audioControl); final var musicThread = Thread.ofPlatform() .name("Audio Music") .daemon(true) @@ -65,7 +68,7 @@ final class AudioStrategyJavaMixer implements AudioStrategy { } for (int i = 0; i < SFX_PLAYERS; i++) { - final AudioPlayer audioPlayer = new AudioPlayerSingleStream(); + final AudioPlayer audioPlayer = new AudioPlayerSingleStream(this.audioControl); final var audioThread = Thread.ofPlatform() .name("Audio SFX " + i) .daemon(true) @@ -91,7 +94,7 @@ final class AudioStrategyJavaMixer implements AudioStrategy { public void run() { // Music - if (!this.clientEngineData.getMusicOptions().isEnable()) { + if (!this.audioOptions.getMusicOptions().isEnable()) { if (this.musicAudioPlayer.audioPlayer().isPlaying()) { this.musicAudioPlayer.audioPlayer().stopAudio(); } @@ -113,7 +116,7 @@ final class AudioStrategyJavaMixer implements AudioStrategy { } if (this.musicAudioPlayer.audioPlayer().isPlaying() || !this.musicPlayQueue.isEmpty()) { - this.musicAudioPlayer.audioPlayer().updateAudioOptions(this.clientEngineData.getMusicOptions()); + this.musicAudioPlayer.audioPlayer().updateAudioOptions(this.audioOptions.getMusicOptions()); } if (!this.musicAudioPlayer.audioPlayer().isPlaying() && @@ -127,32 +130,34 @@ final class AudioStrategyJavaMixer implements AudioStrategy { // SFX - if (!this.sfxQueue.isEmpty()) { - for (int i = 0; i < SFX_PLAYERS; i++) { - this.sfxAudioPlayers.get(i).audioPlayer().updateAudioOptions(this.clientEngineData.getSfxOptions()); - this.sfxPlayersBySize.get(i).queueSize = this.sfxPlayersBySize.get(i).audioPlayer.getQueue().size(); - } - Collections.sort(this.sfxPlayersBySize); - - while (!this.sfxQueue.isEmpty()) { - int i = 0; - final Iterator it = this.sfxQueue.iterator(); - do { - this.sfxPlayersBySize.get(i).queueSize++; - - final AudioPlayer player = this.sfxPlayersBySize.get(i).audioPlayer; - final StaticResource nextFile = it.next(); - it.remove(); - - this.audioLoader.getQueue().offer(new AudioLoaderRequest(nextFile, true, stream -> player.getQueue().offer(new AudioData(nextFile.resourceName(), stream)))); - } while (it.hasNext() && ++i < this.sfxPlayersBySize.size() && this.sfxPlayersBySize.get(i - 1).queueSize > this.sfxPlayersBySize.get(i).queueSize); + synchronized (this.sfxQueue) { + if (!this.sfxQueue.isEmpty()) { + for (int i = 0; i < SFX_PLAYERS; i++) { + this.sfxAudioPlayers.get(i).audioPlayer().updateAudioOptions(this.audioOptions.getSfxOptions()); + this.sfxPlayersBySize.get(i).queueSize = this.sfxPlayersBySize.get(i).audioPlayer.getQueue().size(); + } + Collections.sort(this.sfxPlayersBySize); + + while (!this.sfxQueue.isEmpty()) { + int i = 0; + final Iterator it = this.sfxQueue.iterator(); + do { + this.sfxPlayersBySize.get(i).queueSize++; + + final AudioPlayer player = this.sfxPlayersBySize.get(i).audioPlayer; + final StaticResource nextFile = it.next(); + it.remove(); + + this.audioLoader.getQueue().offer(new AudioLoaderRequest(nextFile, true, stream -> player.getQueue().offer(new AudioData(nextFile.resourceName(), stream)))); + } while (it.hasNext() && ++i < this.sfxPlayersBySize.size() && this.sfxPlayersBySize.get(i - 1).queueSize > this.sfxPlayersBySize.get(i).queueSize); + } } } } @Override public void queueSfx(final Collection audioFile) { - if (!this.clientEngineData.getSfxOptions().isEnable()) { + if (!this.audioOptions.getSfxOptions().isEnable()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Not queued audio file (audio disabled): " + audioFile); } diff --git a/src/main/java/de/extio/game_engine/audio/AudioStrategySoftwareMixing.java b/src/main/java/de/extio/game_engine/audio/AudioStrategySoftwareMixing.java index 76fdc1f..095ebb9 100644 --- a/src/main/java/de/extio/game_engine/audio/AudioStrategySoftwareMixing.java +++ b/src/main/java/de/extio/game_engine/audio/AudioStrategySoftwareMixing.java @@ -24,7 +24,9 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { private final static int MUSIC_INITIAL_DELAY_MS = 1000; - private final AudioOptions clientEngineData; + private final AudioControl audioControl; + + private final AudioOptions audioOptions; private final AudioLoader audioLoader; @@ -32,7 +34,7 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { private AudioThread audioPlayer; - private final Set sfxQueue = new LinkedHashSet<>(); + private final Set sfxQueue = Collections.synchronizedSet(new LinkedHashSet<>()); private final List musicFiles = new ArrayList<>(); @@ -40,14 +42,15 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { private long musicFirstQueued; - public AudioStrategySoftwareMixing(final AudioOptions clientEngineData, final AudioLoader audioLoader) { - this.clientEngineData = clientEngineData; + public AudioStrategySoftwareMixing(final AudioControl audioControl, final AudioOptions audioOptions, final AudioLoader audioLoader) { + this.audioControl = audioControl; + this.audioOptions = audioOptions; this.audioLoader = audioLoader; } @Override public void start() { - final var multiStreamPlayer = new AudioPlayerMultiStream(); + final var multiStreamPlayer = new AudioPlayerMultiStream(this.audioControl); final var multiStreamThread = Thread.ofPlatform() .name("Audio MultiStream") .daemon(true) @@ -64,13 +67,13 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { @Override public void run() { if (this.audioPlayer.audioPlayer().isPlaying() || !this.sfxQueue.isEmpty() || !this.musicPlayQueue.isEmpty() || !this.musicFiles.isEmpty()) { - this.audioPlayer.audioPlayer().updateAudioOptions(this.clientEngineData.getSfxOptions()); - this.audioPlayer.audioPlayer().updateMusicAudioOptions(this.clientEngineData.getMusicOptions()); + this.audioPlayer.audioPlayer().updateAudioOptions(this.audioOptions.getSfxOptions()); + this.audioPlayer.audioPlayer().updateMusicAudioOptions(this.audioOptions.getMusicOptions()); } // Music - if (!this.clientEngineData.getMusicOptions().isEnable()) { + if (!this.audioOptions.getMusicOptions().isEnable()) { if (this.audioPlayer.audioPlayer().isMusicPlaying()) { this.audioPlayer.audioPlayer().setStopMusic(true); } @@ -94,13 +97,15 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { // Sfx - if (!this.sfxQueue.isEmpty()) { - final Iterator it = this.sfxQueue.iterator(); - while (it.hasNext()) { - final StaticResource nextFile = it.next(); - this.audioLoader.getQueue().offer(new AudioLoaderRequest(nextFile, true, stream -> this.audioPlayer.audioPlayer().getQueue().offer(new AudioData(nextFile.resourceName(), stream)))); + synchronized (this.sfxQueue) { + if (!this.sfxQueue.isEmpty()) { + final Iterator it = this.sfxQueue.iterator(); + while (it.hasNext()) { + final StaticResource nextFile = it.next(); + this.audioLoader.getQueue().offer(new AudioLoaderRequest(nextFile, true, stream -> this.audioPlayer.audioPlayer().getQueue().offer(new AudioData(nextFile.resourceName(), stream)))); + it.remove(); + } } - this.sfxQueue.clear(); } } @@ -111,7 +116,7 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { @Override public void queueSfx(final Collection audioFiles) { - if (!this.clientEngineData.getSfxOptions().isEnable()) { + if (!this.audioOptions.getSfxOptions().isEnable()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Not queued audio file (audio disabled): " + audioFiles); } @@ -141,7 +146,7 @@ final class AudioStrategySoftwareMixing implements AudioStrategy { } } - if (musicAudioFiles.equals(this.musicFiles)) { + if (musicAudioFiles.equals(this.musicFiles)) { this.musicFirstQueued = System.currentTimeMillis(); }