From 795e31aa626e257bcfeb0443ba0afa2ac3919f6a Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Sun, 19 Jun 2022 00:00:15 +0100 Subject: [PATCH] Fix playback issues caused by new track player. Submitted ByteBuffer needed to be rewound, and provide method should return true until there are zero bytes left in the buffer. --- .../moe/nekojimi/chords/MusicHandler.java | 59 +++++++++++++------ .../java/moe/nekojimi/chords/TrackPlayer.java | 41 ++++++++----- 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/src/main/java/moe/nekojimi/chords/MusicHandler.java b/src/main/java/moe/nekojimi/chords/MusicHandler.java index 9931c6b..6f84a50 100644 --- a/src/main/java/moe/nekojimi/chords/MusicHandler.java +++ b/src/main/java/moe/nekojimi/chords/MusicHandler.java @@ -5,15 +5,15 @@ */ package moe.nekojimi.chords; -import java.io.Closeable; -import java.io.IOException; +import java.io.*; +import moe.nekojimi.chords.Util; import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.Queue; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; -import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.*; import net.dv8tion.jda.api.audio.AudioSendHandler; import org.apache.commons.io.input.buffer.CircularByteBuffer; @@ -27,7 +27,7 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer private final LinkedList songQueue = new LinkedList<>(); // private final Queue queue = new ConcurrentLinkedQueue<>(); private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024); - private boolean playing = true; + private boolean playing = true; private int byteCount; private boolean arrayErr = false; @@ -35,8 +35,22 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer private Song currentSong; private TrackPlayer player; + private File debugOutFile; + private BufferedOutputStream debugOut; + public MusicHandler() { + try + { + debugOutFile = new File("debug.wav"); + if (debugOutFile.exists()) + debugOutFile.delete(); + debugOutFile.createNewFile(); + debugOut = new BufferedOutputStream(new FileOutputStream(debugOutFile)); + } catch (IOException ex) + { + Logger.getLogger(MusicHandler.class.getName()).log(Level.SEVERE, null, ex); + } } public void addSong(Song song) @@ -94,7 +108,11 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer } currentSong = songQueue.poll(); if (currentSong == null) + { + System.out.println("End of queue."); + debugOut.flush(); return false; + } System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath()); arrayErr = false; byteCount = 3840; @@ -125,7 +143,7 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer @Override public boolean canProvide() { - return player != null && player.has(byteCount); + return player != null && player.has(1); // If we have something in our buffer we can provide it to the send system // return audioBuffer.getCurrentNumberOfBytes() > byteCount && playing; } @@ -136,25 +154,32 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer ByteBuffer ret = ByteBuffer.allocate(byteCount); while (ret.position() < byteCount && player != null) { - System.out.println("Position: " + ret.position() + " Remaining: " + ret.remaining()); - ByteBuffer read = player.read(ret.remaining()); - - if (read != null) +// System.out.println("Position: " + ret.position() + " Remaining: " + ret.remaining()); + try { + ByteBuffer read = player.read(ret.remaining()); + // System.out.println("SAMPLES from player: " + Util.printSamples(read)); + System.out.println("Read: " + read.remaining()); ret.put(read); - } else if (!nextSong()) + } catch (TrackPlayer.OutOfInputException | IOException ex) { - System.out.println("Out of songs!"); - break; + System.out.println("Track ended, starting next."); + boolean foundNext = nextSong(); + + if (!foundNext) + { + System.out.println("Out of tracks!"); + break; + } } + } + System.out.println("Buffer filled, submitting."); + ret.rewind(); // required apparently, if returned buf has pos > 0 you get silence + assert ret.hasArray(); // output MUST be array backed return ret; -// fillBuffer(true); -// byte[] data = new byte[byteCount]; -// audioBuffer.read(data, 0, data.length); -//// byte[] data = queue.poll(); -// return ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer + } // private void fillBuffer(boolean canSkip) diff --git a/src/main/java/moe/nekojimi/chords/TrackPlayer.java b/src/main/java/moe/nekojimi/chords/TrackPlayer.java index 340efab..a1aa680 100644 --- a/src/main/java/moe/nekojimi/chords/TrackPlayer.java +++ b/src/main/java/moe/nekojimi/chords/TrackPlayer.java @@ -25,7 +25,7 @@ public class TrackPlayer implements Closeable { private static final int DESIRED_BUFFER_SIZE = 3840 * 500; - private static final int MAX_READ_FAILS = 100; + private static final int MAX_READ_FAILS = 3; private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024); @@ -41,7 +41,7 @@ public class TrackPlayer implements Closeable fillBuffer(false); } - public TrackPlayer(AudioInputStream input) + public TrackPlayer(AudioInputStream input) throws IOException { this.input = input; fillBuffer(false); @@ -49,22 +49,33 @@ public class TrackPlayer implements Closeable boolean has(int byteCount) { - return audioBuffer.getCurrentNumberOfBytes() > byteCount; +// return true; + return audioBuffer.getCurrentNumberOfBytes() >= byteCount; } - public ByteBuffer read(int length) + public ByteBuffer read(int length) throws IOException { boolean filled = fillBuffer(true); - if (!filled) +// if (!filled) +// throw new OutOfInputException(); + + int toRead = Math.min(length, audioBuffer.getCurrentNumberOfBytes()); + System.out.println("To read: " + toRead + " from " + audioBuffer.getCurrentNumberOfBytes()); + if (toRead <= 0) throw new OutOfInputException(); - byte[] data = new byte[length]; + byte[] data = new byte[toRead]; audioBuffer.read(data, 0, data.length); // byte[] data = queue.poll(); return ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer } - private boolean fillBuffer(boolean canSkip) + /** + * + * @param canSkip + * @return true if the buffer is not empty; false otherwise + */ + private boolean fillBuffer(boolean canSkip) throws IOException { int fails = 0; // use what we have in our buffer to send audio as PCM @@ -81,7 +92,11 @@ public class TrackPlayer implements Closeable return true; } - private boolean readData() + /** + * + * @return true if any data was read; false otherwise + */ + private boolean readData() throws IOException { if (input == null) return false; @@ -106,19 +121,13 @@ public class TrackPlayer implements Closeable // queue.add(bytes); audioBuffer.add(bytes, 0, read); - } catch (IOException ex) - { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - return false; +// System.out.println("SAMPLES player buff: " + Util.printSamples(audioBuffer)); } catch (ArrayIndexOutOfBoundsException ex) { if (!arrayErr) arrayErr = true; else - { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - return false; - } + throw ex; } return true; }