diff --git a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java index 4169195e8dc..5273a53ecae 100644 --- a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java +++ b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java @@ -277,30 +277,30 @@ public class AudioManager { checkAndPlayClip(getManager().playerWon); } + private static boolean audioGroupEnabled(AudioGroup audioGroup) { + switch (audioGroup) { + case GameSounds: + return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_GAME_ON, "true")); + case DraftSounds: + return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_DRAFT_ON, "true")); + case SkipSounds: + return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_SKIP_BUTTONS_ON, "true")); + case OtherSounds: + return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_OTHER_ON, "true")); + } + return false; + } + private static void checkAndPlayClip(MageClip mageClip) { try { - if (mageClip != null) { - boolean playSound = false; - switch (mageClip.getAudioGroup()) { - case GameSounds: - playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_GAME_ON, "true").equals("true"); - break; - case DraftSounds: - playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_DRAFT_ON, "true").equals("true"); - break; - case SkipSounds: - playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_SKIP_BUTTONS_ON, "true").equals("true"); - break; - case OtherSounds: - playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_OTHER_ON, "true").equals("true"); - } - - if (playSound) { - audioManager.play(mageClip); - } + if (mageClip == null || mageClip.getBuffer() == null) { + return; + } + if (audioGroupEnabled(mageClip.getAudioGroup())) { + audioManager.play(mageClip); } } catch (Exception e) { - Logger.getLogger(AudioManager.class).fatal("Error while playing sound clip.", e); + log.warn("Error while playing sound clip.", e); } } diff --git a/Mage.Client/src/main/java/mage/client/util/audio/LinePool.java b/Mage.Client/src/main/java/mage/client/util/audio/LinePool.java index 8145f756bbf..f12a6d791eb 100644 --- a/Mage.Client/src/main/java/mage/client/util/audio/LinePool.java +++ b/Mage.Client/src/main/java/mage/client/util/audio/LinePool.java @@ -1,7 +1,9 @@ package mage.client.util.audio; +import java.util.ArrayDeque; import java.util.HashSet; import java.util.LinkedList; +import java.util.Queue; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -9,9 +11,7 @@ import java.util.TimerTask; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineEvent.Type; -import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; import javax.sound.sampled.SourceDataLine; @@ -25,11 +25,11 @@ public class LinePool { private final Logger log = LoggerFactory.getLogger(getClass()); private static final int LINE_CLEANUP_INTERVAL = 30000; - AudioFormat format; - Set freeLines = new HashSet<>(); - Set activeLines = new HashSet<>(); - Set busyLines = new HashSet<>(); - LinkedList queue = new LinkedList<>(); + + private final Queue freeLines = new ArrayDeque<>(); + private final Queue activeLines = new ArrayDeque<>(); + private final Set busyLines = new HashSet<>(); + private final LinkedList queue = new LinkedList<>(); /* * Initially all the lines are in the freeLines pool. When a sound plays, one line is being selected randomly from @@ -47,7 +47,6 @@ public class LinePool { } public LinePool(AudioFormat audioFormat, int size, int alwaysActive) { - format = audioFormat; this.alwaysActive = alwaysActive; mixer = AudioSystem.getMixer(null); DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat); @@ -56,11 +55,10 @@ public class LinePool { SourceDataLine line = (SourceDataLine) mixer.getLine(lineInfo); freeLines.add(line); } catch (LineUnavailableException e) { - e.printStackTrace(); + log.warn("Failed to get line from mixer", e); } } new Timer("Line cleanup", true).scheduleAtFixedRate(new TimerTask() { - @Override public void run() { synchronized (LinePool.this) { @@ -75,74 +73,75 @@ public class LinePool { }, LINE_CLEANUP_INTERVAL, LINE_CLEANUP_INTERVAL); } + private synchronized SourceDataLine borrowLine() { + SourceDataLine line = activeLines.poll(); + if (line == null) { + line = freeLines.poll(); + } + if (line != null) { + busyLines.add(line); + } + return line; + } + + private synchronized void returnLine(SourceDataLine line) { + busyLines.remove(line); + if (activeLines.size() < alwaysActive) { + activeLines.add(line); + } else { + freeLines.add(line); + } + } + public void playSound(final MageClip mageClip) { final SourceDataLine line; synchronized (LinePool.this) { log.debug("Playing {}", mageClip.getFilename()); logLineStats(); - if (activeLines.size() > 0) { - line = activeLines.iterator().next(); - } else if (freeLines.size() > 0) { - line = freeLines.iterator().next(); - } else { + line = borrowLine(); + if (line == null) { // no lines available, queue sound to play it when a line is available queue.add(mageClip); log.debug("Sound {} queued.", mageClip.getFilename()); return; } - freeLines.remove(line); - activeLines.remove(line); - busyLines.add(line); logLineStats(); } - ThreadUtils.threadPool.submit(new Runnable() { - - @Override - public void run() { - synchronized (LinePool.this) { - try { - if (!line.isOpen()) { - line.open(); - line.addLineListener(new LineListener() { - - @Override - public void update(LineEvent event) { - log.debug("Event: {}", event); - if (event.getType() != Type.STOP) { - return; - } - synchronized (LinePool.this) { - log.debug("Before stop on line {}", line); - logLineStats(); - busyLines.remove(line); - if (activeLines.size() < LinePool.this.alwaysActive) { - activeLines.add(line); - } else { - freeLines.add(line); - } - log.debug("After stop on line {}", line); - logLineStats(); - if (queue.size() > 0) { - MageClip queuedSound = queue.poll(); - log.debug("Playing queued sound {}", queuedSound); - playSound(queuedSound); - } - } + ThreadUtils.threadPool.submit(() -> { + synchronized (LinePool.this) { + try { + if (!line.isOpen()) { + line.open(); + line.addLineListener(event -> { + log.debug("Event: {}", event); + if (event.getType() != Type.STOP) { + return; + } + synchronized (LinePool.this) { + log.debug("Before stop on line {}", line); + logLineStats(); + returnLine(line); + log.debug("After stop on line {}", line); + logLineStats(); + MageClip queuedSound = queue.poll(); + if (queuedSound != null) { + log.debug("Playing queued sound {}", queuedSound); + playSound(queuedSound); } - }); - } - line.start(); - } catch (LineUnavailableException e) { - e.printStackTrace(); + } + }); } + line.start(); + } catch (LineUnavailableException e) { + log.warn("Failed to open line", e); } - byte[] buffer = mageClip.getBuffer(); - log.debug("Before write to line {}", line); - line.write(buffer, 0, buffer.length); - line.drain(); - line.stop(); - log.debug("Line completed: {}", line); } + byte[] buffer = mageClip.getBuffer(); + log.debug("Before write to line {}", line); + line.write(buffer, 0, buffer.length); + line.drain(); + line.stop(); + log.debug("Line completed: {}", line); }); }