package andesite.node.player; import andesite.node.util.ByteRingBuffer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import javax.annotation.Nonnull; import java.util.concurrent.TimeUnit; public class FrameLossTracker extends AudioEventAdapter implements FrameLossCounter { private static final long ACCEPTABLE_TRACK_SWITCH_TIME = TimeUnit.MILLISECONDS.toNanos(100); private static final long ONE_SECOND = TimeUnit.SECONDS.toNanos(1); private final ByteRingBuffer loss = new ByteRingBuffer(60); private final ByteRingBuffer success = new ByteRingBuffer(60); private long playingSince = Long.MAX_VALUE; private long trackStart; private long lastTrackEnd; private long lastUpdate; private byte currentLoss; private byte currentSuccess; public void onSuccess() { checkTime(); currentSuccess++; } public void onFail() { checkTime(); currentLoss++; } @Nonnull @Override public ByteRingBuffer lastMinuteLoss() { return loss; } @Nonnull @Override public ByteRingBuffer lastMinuteSuccess() { return success; } @Override public boolean isDataUsable() { if(trackStart - lastTrackEnd > ACCEPTABLE_TRACK_SWITCH_TIME && lastTrackEnd != 0) { return false; } return TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - playingSince) >= 60; } private void checkTime() { var now = System.nanoTime(); if(now - lastUpdate > ONE_SECOND) { lastUpdate = now; loss.put(currentLoss); success.put(currentSuccess); currentLoss = 0; currentSuccess = 0; } } private void start() { trackStart = System.nanoTime(); if(trackStart - playingSince > ACCEPTABLE_TRACK_SWITCH_TIME || playingSince == Long.MAX_VALUE) { playingSince = trackStart; loss.clear(); success.clear(); } } private void end() { lastTrackEnd = System.nanoTime(); } @Override public void onPlayerPause(AudioPlayer player) { end(); } @Override public void onPlayerResume(AudioPlayer player) { start(); } @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { start(); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { end(); } }