From 9c1721ba14f431f1d4af64307087097528cc36b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 22:17:42 +0200 Subject: [PATCH 01/32] Target class, field in target class --- .../goxr3plus/streamplayer/stream/Outlet.java | 16 +++ .../streamplayer/stream/StreamPlayer.java | 37 ++++--- .../stream/SourceDataLineTest.java | 98 +++++++++++++++++++ 3 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java create mode 100644 src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java new file mode 100644 index 0000000..250c873 --- /dev/null +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -0,0 +1,16 @@ +package com.goxr3plus.streamplayer.stream; + +import javax.sound.sampled.FloatControl; + +public class Outlet { + + public FloatControl getGainControl() { + return gainControl; + } + + public void setGainControl(FloatControl gainControl) { + this.gainControl = gainControl; + } + + private FloatControl gainControl; +} diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 126adde..717cce8 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -159,7 +159,10 @@ public class StreamPlayer implements Callable { // Properties when the File/URL/InputStream is opened. Map audioProperties; - // -------------------BEGIN OF CONSTRUCTOR--------------------- + /** + * Responsible for the output SourceDataLine and the controls that depend on it. + */ + private Outlet outlet; /** * Default parameter less Constructor. A default logger will be used. @@ -190,6 +193,7 @@ public StreamPlayer(Logger logger, ExecutorService streamPlayerExecutorService, this.streamPlayerExecutorService = streamPlayerExecutorService; this.eventsExecutorService = eventsExecutorService; listeners = new ArrayList<>(); + outlet = new Outlet(); reset(); } @@ -217,7 +221,7 @@ public void reset() { encodedAudioLength = -1; // Controls - gainControl = null; + setGainControl(null); panControl = null; balanceControl = null; // sampleRateControl = null @@ -534,8 +538,8 @@ private void openLine() throws LineUnavailableException { // Master_Gain Control? if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) - gainControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN); - else gainControl = null; + setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); + else setGainControl(null); // PanControl? if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) @@ -1095,8 +1099,8 @@ private boolean hasControl(final Type control, final Control component) { */ public float getGainValue() { - if (hasControl(FloatControl.Type.MASTER_GAIN, gainControl)) { - return gainControl.getValue(); + if (hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { + return getGainControl().getValue(); } else { return 0.0F; } @@ -1108,7 +1112,7 @@ public float getGainValue() { * @return The Maximum Gain Value */ public float getMaximumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, gainControl) ? 0.0F : gainControl.getMaximum(); + return !hasControl(FloatControl.Type.MASTER_GAIN, getGainControl()) ? 0.0F : getGainControl().getMaximum(); } @@ -1119,7 +1123,7 @@ public float getMaximumGain() { */ public float getMinimumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, gainControl) ? 0.0F : gainControl.getMinimum(); + return !hasControl(FloatControl.Type.MASTER_GAIN, getGainControl()) ? 0.0F : getGainControl().getMinimum(); } @@ -1259,15 +1263,15 @@ public void setPan(final double fPan) { * @param fGain The new gain value */ public void setGain(final double fGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, gainControl)) { + if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { final double logScaleGain = 20 * Math.log10(fGain); - gainControl.setValue((float) logScaleGain); + getGainControl().setValue((float) logScaleGain); } } public void setLogScaleGain(final double logScaleGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, gainControl)) { - gainControl.setValue((float) logScaleGain); + if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { + getGainControl().setValue((float) logScaleGain); } } @@ -1402,4 +1406,13 @@ public boolean isSeeking() { Logger getLogger() { return logger; } + + /** The gain control. */ + public FloatControl getGainControl() { + return gainControl; + } + + public void setGainControl(FloatControl gainControl) { + this.gainControl = gainControl; + } } diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java new file mode 100644 index 0000000..fde23e7 --- /dev/null +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -0,0 +1,98 @@ +package com.goxr3plus.streamplayer.stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.logging.Logger; + +import static java.lang.Math.log10; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +public class SourceDataLineTest { + + StreamPlayer player; + private File audioFile; + + @BeforeEach + void setup() { + final Logger logger = mock(Logger.class); + player = new StreamPlayer(logger); + audioFile = new File("Logic - Ballin [Bass Boosted].mp3"); + } + + @Test + void gain() throws StreamPlayerException, InterruptedException { + // Setup + final double gain1 = 0.83; + final double gain2 = 0.2; + final double delta = 0.05; + final boolean listen = false; + + // Exercise + final float initialGain = player.getGainValue(); + player.open(audioFile); + player.seekTo(30); + player.play(); + player.setGain(gain1); + final float actualGain1First = player.getGainValue(); + if (listen) Thread.sleep(2000); + final float actualGain1 = player.getGainValue(); + + player.setGain(gain2); + if (listen) Thread.sleep(2000); + final float actualGain2 = player.getGainValue(); + + player.setGain(gain1); + if (listen) Thread.sleep(2000); + + player.stop(); + + // Verify + assertEquals(0, initialGain); + assertEquals(actualGain1First, actualGain1); + assertEquals(20*log10(gain1), actualGain1, delta); // TODO: Investigate probable bug. + // fail("Test not done"); + } + + /** + * Plays music if "listen" is true. + * Varies the gain, and checks that it can be read back. + * If listen is true, it plays for 2 seconds per gain level. + * + * @throws StreamPlayerException + * @throws InterruptedException + */ + @Test + void logScaleGain() throws StreamPlayerException, InterruptedException { + // Setup + final boolean listen = false; + + // Exercise + + player.open(audioFile); + player.seekTo(30); + player.play(); + + assertGainCanBeSetTo(-10, listen); + assertGainCanBeSetTo(-75, listen); + assertGainCanBeSetTo(0, listen); + assertGainCanBeSetTo(6, listen); + + player.stop(); + } + + private void assertGainCanBeSetTo(double gain, boolean listen) throws InterruptedException { + final float atGain = playAtGain(listen, gain); + assertEquals(gain, atGain, 0.01); + } + + private float playAtGain(boolean listen, double gain) throws InterruptedException { + player.setLogScaleGain(gain); + if (listen) { + Thread.sleep(2000); + } + return player.getGainValue(); + } +} From 2c087f567a8ae3d62ab723079c763750fdee542c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 22:24:24 +0200 Subject: [PATCH 02/32] gainControl moved to outet --- .../streamplayer/stream/StreamPlayer.java | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 717cce8..dd14166 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -89,7 +89,7 @@ public class StreamPlayer implements Callable { // -------------------CONTROLS--------------------- /** The gain control. */ - private FloatControl gainControl; + //private FloatControl gainControl; /** The pan control. */ private FloatControl panControl; @@ -221,7 +221,7 @@ public void reset() { encodedAudioLength = -1; // Controls - setGainControl(null); + outlet.setGainControl(null); panControl = null; balanceControl = null; // sampleRateControl = null @@ -538,8 +538,8 @@ private void openLine() throws LineUnavailableException { // Master_Gain Control? if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) - setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); - else setGainControl(null); + outlet.setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); + else outlet.setGainControl(null); // PanControl? if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) @@ -1099,8 +1099,8 @@ private boolean hasControl(final Type control, final Control component) { */ public float getGainValue() { - if (hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { - return getGainControl().getValue(); + if (hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { + return outlet.getGainControl().getValue(); } else { return 0.0F; } @@ -1112,7 +1112,7 @@ public float getGainValue() { * @return The Maximum Gain Value */ public float getMaximumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, getGainControl()) ? 0.0F : getGainControl().getMaximum(); + return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMaximum(); } @@ -1123,7 +1123,7 @@ public float getMaximumGain() { */ public float getMinimumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, getGainControl()) ? 0.0F : getGainControl().getMinimum(); + return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMinimum(); } @@ -1263,15 +1263,15 @@ public void setPan(final double fPan) { * @param fGain The new gain value */ public void setGain(final double fGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { + if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { final double logScaleGain = 20 * Math.log10(fGain); - getGainControl().setValue((float) logScaleGain); + outlet.getGainControl().setValue((float) logScaleGain); } } public void setLogScaleGain(final double logScaleGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { - getGainControl().setValue((float) logScaleGain); + if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { + outlet.getGainControl().setValue((float) logScaleGain); } } @@ -1407,12 +1407,4 @@ Logger getLogger() { return logger; } - /** The gain control. */ - public FloatControl getGainControl() { - return gainControl; - } - - public void setGainControl(FloatControl gainControl) { - this.gainControl = gainControl; - } } From 4f1a7898d5575f83652d985bf3d03394ea05d1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 22:57:00 +0200 Subject: [PATCH 03/32] balancecontrol moved to Outlet --- .../goxr3plus/streamplayer/stream/Outlet.java | 13 +++++++++++-- .../streamplayer/stream/StreamPlayer.java | 13 +++++++------ .../stream/SourceDataLineTest.java | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 250c873..a803c79 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -4,6 +4,17 @@ public class Outlet { + private FloatControl balanceControl; + private FloatControl gainControl; + + public FloatControl getBalanceControl() { + return balanceControl; + } + + public void setBalanceControl(FloatControl balanceControl) { + this.balanceControl = balanceControl; + } + public FloatControl getGainControl() { return gainControl; } @@ -11,6 +22,4 @@ public FloatControl getGainControl() { public void setGainControl(FloatControl gainControl) { this.gainControl = gainControl; } - - private FloatControl gainControl; } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index dd14166..99e2127 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -95,7 +95,7 @@ public class StreamPlayer implements Callable { private FloatControl panControl; /** The balance control. */ - private FloatControl balanceControl; +// private FloatControl balanceControl; /** The sample rate control. */ // private FloatControl sampleRateControl @@ -223,7 +223,7 @@ public void reset() { // Controls outlet.setGainControl(null); panControl = null; - balanceControl = null; + outlet.setBalanceControl(null); // sampleRateControl = null // Notify the Status @@ -559,9 +559,10 @@ private void openLine() throws LineUnavailableException { : null; // Speakers Balance? - balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) + FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) ? (FloatControl) sourceDataLine.getControl(FloatControl.Type.BALANCE) : null; + outlet.setBalanceControl(balanceControl); } } @@ -1162,7 +1163,7 @@ public boolean getMute() { * @return The Balance Value */ public float getBalance() { - return !hasControl(FloatControl.Type.BALANCE, balanceControl) ? 0f : balanceControl.getValue(); + return !hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) ? 0f : outlet.getBalanceControl().getValue(); } /**** @@ -1293,8 +1294,8 @@ public void setMute(final boolean mute) { * @param fBalance the new balance */ public void setBalance(final float fBalance) { - if (hasControl(FloatControl.Type.BALANCE, balanceControl) && fBalance >= -1.0 && fBalance <= 1.0) - balanceControl.setValue(fBalance); + if (hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) && fBalance >= -1.0 && fBalance <= 1.0) + outlet.getBalanceControl().setValue(fBalance); else try { throw new StreamPlayerException(PlayerException.BALANCE_CONTROL_NOT_SUPPORTED); diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index fde23e7..45edde3 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -95,4 +95,23 @@ private float playAtGain(boolean listen, double gain) throws InterruptedExceptio } return player.getGainValue(); } + + @Test + void balance() throws StreamPlayerException { + // Setup + final float wantedBalance = 0.5f; + + //Exercise + player.open(audioFile); + player.play(); // Necessary to be able to set the balance + + final float initialBalance = player.getBalance(); + player.setBalance(wantedBalance); + player.stop(); // Probably not needed, but cleanup is good. + final float actualBalance = player.getBalance(); // Can be made before or after stop() + + // Verify + assertEquals(0, initialBalance); + assertEquals(wantedBalance, actualBalance); + } } From 32dca21aa0f64a7b46c5019344ea93cbbc5c7fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:01:33 +0200 Subject: [PATCH 04/32] Minor cleanup --- .../com/goxr3plus/streamplayer/stream/StreamPlayer.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 99e2127..223a1e7 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -88,18 +88,9 @@ public class StreamPlayer implements Callable { // -------------------CONTROLS--------------------- - /** The gain control. */ - //private FloatControl gainControl; - /** The pan control. */ private FloatControl panControl; - /** The balance control. */ -// private FloatControl balanceControl; - - /** The sample rate control. */ - // private FloatControl sampleRateControl - /** The mute control. */ private BooleanControl muteControl; From f54066d21b861cd66b494e2df5ccd09079dbc207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:10:48 +0200 Subject: [PATCH 05/32] Test for pan --- .../stream/SourceDataLineTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index 45edde3..51aa45b 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -8,6 +8,7 @@ import static java.lang.Math.log10; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; public class SourceDataLineTest { @@ -114,4 +115,24 @@ void balance() throws StreamPlayerException { assertEquals(0, initialBalance); assertEquals(wantedBalance, actualBalance); } + + @Test + void pan() throws StreamPlayerException { + double delta = 1e-6; + final float initialPan = player.getPan(); + assertEquals(0, initialPan); + + player.open(audioFile); + player.play(); + + double pan = -0.9; + player.setPan(pan); + assertEquals(pan, player.getPan(), delta); + + double outsideRange = 1.1; + player.setPan(outsideRange); + assertEquals(pan, player.getPan(), delta); + +// fail("Test not done"); + } } From 57b28e2d4ca63509b4c16c77df5da4ad4fde1f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:12:42 +0200 Subject: [PATCH 06/32] pan control moved --- .../goxr3plus/streamplayer/stream/Outlet.java | 10 ++++++++++ .../streamplayer/stream/StreamPlayer.java | 17 +++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index a803c79..933a3d2 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -6,6 +6,16 @@ public class Outlet { private FloatControl balanceControl; private FloatControl gainControl; + private FloatControl panControl; + + + public FloatControl getPanControl() { + return panControl; + } + + public void setPanControl(FloatControl panControl) { + this.panControl = panControl; + } public FloatControl getBalanceControl() { return balanceControl; diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 223a1e7..e15db88 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -88,9 +88,6 @@ public class StreamPlayer implements Callable { // -------------------CONTROLS--------------------- - /** The pan control. */ - private FloatControl panControl; - /** The mute control. */ private BooleanControl muteControl; @@ -213,7 +210,7 @@ public void reset() { // Controls outlet.setGainControl(null); - panControl = null; + outlet.setPanControl(null); outlet.setBalanceControl(null); // sampleRateControl = null @@ -534,8 +531,8 @@ private void openLine() throws LineUnavailableException { // PanControl? if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) - panControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN); - else panControl = null; + outlet.setPanControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN)); + else outlet.setPanControl(null); // SampleRate? // if (sourceDataLine.isControlSupported(FloatControl.Type.SAMPLE_RATE)) @@ -1125,7 +1122,7 @@ public float getMinimumGain() { * @return The Precision Value */ public float getPrecision() { - return !hasControl(FloatControl.Type.PAN, panControl) ? 0.0F : panControl.getPrecision(); + return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getPrecision(); } @@ -1135,7 +1132,7 @@ public float getPrecision() { * @return The Pan Value */ public float getPan() { - return !hasControl(FloatControl.Type.PAN, panControl) ? 0.0F : panControl.getValue(); + return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getValue(); } @@ -1240,10 +1237,10 @@ public void setLineBufferSize(final int size) { */ public void setPan(final double fPan) { - if (!hasControl(FloatControl.Type.PAN, panControl) || fPan < -1.0 || fPan > 1.0) + if (!hasControl(FloatControl.Type.PAN, outlet.getPanControl()) || fPan < -1.0 || fPan > 1.0) return; logger.info(() -> "Pan : " + fPan); - panControl.setValue((float) fPan); + outlet.getPanControl().setValue((float) fPan); generateEvent(Status.PAN, getEncodedStreamPosition(), null); } From 3847ec6eea701936868d98131662d7f58b581879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:14:22 +0200 Subject: [PATCH 07/32] Update StreamPlayerMethodsTest.java --- .../stream/StreamPlayerMethodsTest.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index 755896d..fbe2405 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -295,11 +295,21 @@ void stop() { } @Test - void pan() { - player.getPan(); - player.setPan(1000); + void pan() throws StreamPlayerException { + double delta = 1e-6; + final float initialPan = player.getPan(); + assertEquals(0, initialPan); - fail("Test not done"); + player.open(audioFile); + player.play(); + + double pan = -0.9; + player.setPan(pan); + assertEquals(pan, player.getPan(), delta); + + double outsideRange = 1.1; + player.setPan(outsideRange); + assertEquals(pan, player.getPan(), delta); } @Test From 18e55fd514f21d292cf2b87428bc2e94386dbd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:21:23 +0200 Subject: [PATCH 08/32] Test for mute --- .../goxr3plus/streamplayer/stream/Outlet.java | 11 ++++++++ .../stream/SourceDataLineTest.java | 27 ++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 933a3d2..f6258c6 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -1,14 +1,25 @@ package com.goxr3plus.streamplayer.stream; +import javax.sound.sampled.BooleanControl; import javax.sound.sampled.FloatControl; public class Outlet { private FloatControl balanceControl; private FloatControl gainControl; + private BooleanControl muteControl; private FloatControl panControl; + public BooleanControl getMuteControl() { + return muteControl; + } + + public void setMuteControl(BooleanControl muteControl) { + this.muteControl = muteControl; + } + + public FloatControl getPanControl() { return panControl; } diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index 51aa45b..ee4cdc3 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -1,5 +1,6 @@ package com.goxr3plus.streamplayer.stream; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -7,8 +8,7 @@ import java.util.logging.Logger; import static java.lang.Math.log10; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; public class SourceDataLineTest { @@ -23,6 +23,11 @@ void setup() { audioFile = new File("Logic - Ballin [Bass Boosted].mp3"); } + @AfterEach + void tearDown() { + player.stop(); + } + @Test void gain() throws StreamPlayerException, InterruptedException { // Setup @@ -132,7 +137,23 @@ void pan() throws StreamPlayerException { double outsideRange = 1.1; player.setPan(outsideRange); assertEquals(pan, player.getPan(), delta); + } + + @Test + void mute() throws StreamPlayerException { + assertFalse(player.getMute()); + player.setMute(true); + assertFalse(player.getMute()); + player.open(audioFile); + player.setMute(true); + assertFalse(player.getMute()); + + player.play(); + player.setMute(true); + assertTrue(player.getMute()); // setMute works only after play() has been called. + -// fail("Test not done"); + player.setMute(false); + assertFalse(player.getMute()); } } From 2452944e03faa21499ecc1bdd489cb80badd75f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:24:30 +0200 Subject: [PATCH 09/32] Mute moved; last control. --- .../streamplayer/stream/StreamPlayer.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index e15db88..05ab636 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -85,12 +85,7 @@ public class StreamPlayer implements Callable { /** The source data line. */ private SourceDataLine sourceDataLine; - - // -------------------CONTROLS--------------------- - - /** The mute control. */ - private BooleanControl muteControl; - + // -------------------LOCKS--------------------- /** @@ -542,9 +537,10 @@ private void openLine() throws LineUnavailableException { // sampleRateControl = null // Mute? - muteControl = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) + BooleanControl muteControl1 = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) ? (BooleanControl) sourceDataLine.getControl(BooleanControl.Type.MUTE) : null; + outlet.setMuteControl(muteControl1); // Speakers Balance? FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) @@ -1142,7 +1138,7 @@ public float getPan() { * @return True if muted , False if not */ public boolean getMute() { - return hasControl(BooleanControl.Type.MUTE, muteControl) && muteControl.getValue(); + return hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue(); } /** @@ -1270,8 +1266,8 @@ public void setLogScaleGain(final double logScaleGain) { * @param mute True to mute the audio of False to unmute it */ public void setMute(final boolean mute) { - if (hasControl(BooleanControl.Type.MUTE, muteControl) && muteControl.getValue() != mute) - muteControl.setValue(mute); + if (hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue() != mute) + outlet.getMuteControl().setValue(mute); } /** From bc1cc50a22963d2cf41a244cd044dbd5f02b933b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:39:01 +0200 Subject: [PATCH 10/32] SourceDataLine moved --- .../goxr3plus/streamplayer/stream/Outlet.java | 12 ++ .../streamplayer/stream/StreamPlayer.java | 111 ++++++++---------- .../stream/StreamPlayerMethodsTest.java | 3 +- 3 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index f6258c6..93b0b7f 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -2,6 +2,7 @@ import javax.sound.sampled.BooleanControl; import javax.sound.sampled.FloatControl; +import javax.sound.sampled.SourceDataLine; public class Outlet { @@ -10,6 +11,17 @@ public class Outlet { private BooleanControl muteControl; private FloatControl panControl; + /** The source data line. */ + private SourceDataLine sourceDataLine; + + public SourceDataLine getSourceDataLine() { + return sourceDataLine; + } + + public void setSourceDataLine(SourceDataLine sourceDataLine) { + this.sourceDataLine = sourceDataLine; + } + public BooleanControl getMuteControl() { return muteControl; diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 05ab636..29afbdd 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -82,9 +82,6 @@ public class StreamPlayer implements Callable { /** The audio file format. */ private AudioFileFormat audioFileFormat; - - /** The source data line. */ - private SourceDataLine sourceDataLine; // -------------------LOCKS--------------------- @@ -191,10 +188,10 @@ public void reset() { } // Source Data Line - if (sourceDataLine != null) { - sourceDataLine.flush(); - sourceDataLine.close(); - sourceDataLine = null; + if (outlet.getSourceDataLine() != null) { + outlet.getSourceDataLine().flush(); + outlet.getSourceDataLine().close(); + outlet.setSourceDataLine(null); } // AudioFile @@ -368,7 +365,7 @@ private void determineProperties() { audioProperties.putAll(audioFormat.properties()); // Add SourceDataLine - audioProperties.put("basicplayer.sourcedataline", sourceDataLine); + audioProperties.put("basicplayer.sourcedataline", outlet.getSourceDataLine()); // Keep this final reference for the lambda expression final Map audioPropertiesCopy = audioProperties; @@ -390,12 +387,12 @@ private void initLine() throws LineUnavailableException, StreamPlayerException { logger.info("Initiating the line..."); - if (sourceDataLine == null) + if (outlet.getSourceDataLine() == null) createLine(); - if (!sourceDataLine.isOpen()) + if (!outlet.getSourceDataLine().isOpen()) openLine(); - else if (!sourceDataLine.getFormat().equals(audioInputStream == null ? null : audioInputStream.getFormat())) { - sourceDataLine.close(); + else if (!outlet.getSourceDataLine().getFormat().equals(audioInputStream == null ? null : audioInputStream.getFormat())) { + outlet.getSourceDataLine().close(); openLine(); } } @@ -434,7 +431,7 @@ private void createLine() throws LineUnavailableException, StreamPlayerException logger.info("Entered CreateLine()!:\n"); - if (sourceDataLine != null) + if (outlet.getSourceDataLine() != null) logger.warning("Warning Source DataLine is not null!\n"); else { final AudioFormat sourceFormat = audioInputStream.getFormat(); @@ -481,19 +478,19 @@ private void createLine() throws LineUnavailableException, StreamPlayerException // Continue final Mixer mixer = getMixer(mixerName); if (mixer == null) { - sourceDataLine = (SourceDataLine) AudioSystem.getLine(lineInfo); + outlet.setSourceDataLine((SourceDataLine) AudioSystem.getLine(lineInfo)); mixerName = null; } else { logger.info("Mixer: " + mixer.getMixerInfo()); - sourceDataLine = (SourceDataLine) mixer.getLine(lineInfo); + outlet.setSourceDataLine((SourceDataLine) mixer.getLine(lineInfo)); } - sourceDataLine = (SourceDataLine) AudioSystem.getLine(lineInfo); + outlet.setSourceDataLine((SourceDataLine) AudioSystem.getLine(lineInfo)); // -------------------------------------------------------------------------------- - logger.info(() -> "Line : " + sourceDataLine); - logger.info(() -> "Line Info : " + sourceDataLine.getLineInfo()); - logger.info(() -> "Line AudioFormat: " + sourceDataLine.getFormat() + "\n"); + logger.info(() -> "Line : " + outlet.getSourceDataLine()); + logger.info(() -> "Line Info : " + outlet.getSourceDataLine().getLineInfo()); + logger.info(() -> "Line AudioFormat: " + outlet.getSourceDataLine().getFormat() + "\n"); logger.info("Exited CREATELINE()!:\n"); } } @@ -507,26 +504,26 @@ private void openLine() throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); - if (sourceDataLine != null) { + if (outlet.getSourceDataLine() != null) { final AudioFormat audioFormat = audioInputStream.getFormat(); - currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : sourceDataLine.getBufferSize(); - sourceDataLine.open(audioFormat, currentLineBufferSize); + currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); + outlet.getSourceDataLine().open(audioFormat, currentLineBufferSize); // opened? - if (sourceDataLine.isOpen()) { + if (outlet.getSourceDataLine().isOpen()) { // logger.info(() -> "Open Line Buffer Size=" + bufferSize + "\n"); /*-- Display supported controls --*/ // Control[] c = m_line.getControls() // Master_Gain Control? - if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) - outlet.setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); + if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) + outlet.setGainControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); else outlet.setGainControl(null); // PanControl? - if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) - outlet.setPanControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN)); + if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) + outlet.setPanControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.PAN)); else outlet.setPanControl(null); // SampleRate? @@ -537,14 +534,14 @@ private void openLine() throws LineUnavailableException { // sampleRateControl = null // Mute? - BooleanControl muteControl1 = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) - ? (BooleanControl) sourceDataLine.getControl(BooleanControl.Type.MUTE) + BooleanControl muteControl1 = outlet.getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) + ? (BooleanControl) outlet.getSourceDataLine().getControl(BooleanControl.Type.MUTE) : null; outlet.setMuteControl(muteControl1); // Speakers Balance? - FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) - ? (FloatControl) sourceDataLine.getControl(FloatControl.Type.BALANCE) + FloatControl balanceControl = outlet.getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) + ? (FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.BALANCE) : null; outlet.setBalanceControl(balanceControl); } @@ -576,8 +573,8 @@ public void play() throws StreamPlayerException { } // Open the sourceDataLine - if (sourceDataLine != null && !sourceDataLine.isRunning()) { - sourceDataLine.start(); + if (outlet.getSourceDataLine() != null && !outlet.getSourceDataLine().isRunning()) { + outlet.getSourceDataLine().start(); // Proceed only if we have not problems logger.info("Submitting new StreamPlayer Thread"); @@ -597,7 +594,7 @@ public void play() throws StreamPlayerException { * @return true, if successful */ public boolean pause() { - if (sourceDataLine == null || status != Status.PLAYING) + if (outlet.getSourceDataLine() == null || status != Status.PLAYING) return false; status = Status.PAUSED; logger.info("pausePlayback() completed"); @@ -629,9 +626,9 @@ public void stop() { * @return False if failed(so simple...) */ public boolean resume() { - if (sourceDataLine == null || status != Status.PAUSED) + if (outlet.getSourceDataLine() == null || status != Status.PAUSED) return false; - sourceDataLine.start(); + outlet.getSourceDataLine().start(); status = Status.PLAYING; generateEvent(Status.RESUMED, getEncodedStreamPosition(), null); logger.info("resumePlayback() completed"); @@ -877,9 +874,9 @@ public Void call() { toRead)) != -1; toRead -= nBytesRead, totalRead += nBytesRead) // Check for under run - if (sourceDataLine.available() >= sourceDataLine.getBufferSize()) - logger.info(() -> "Underrun> Available=" + sourceDataLine.available() - + " , SourceDataLineBuffer=" + sourceDataLine.getBufferSize()); + if (outlet.getSourceDataLine().available() >= outlet.getSourceDataLine().getBufferSize()) + logger.info(() -> "Underrun> Available=" + outlet.getSourceDataLine().available() + + " , SourceDataLineBuffer=" + outlet.getSourceDataLine().getBufferSize()); // Check if anything has been read if (totalRead > 0) { @@ -893,7 +890,7 @@ public Void call() { } // Writes audio data to the mixer via this source data line - sourceDataLine.write(trimBuffer, 0, totalRead); + outlet.getSourceDataLine().write(trimBuffer, 0, totalRead); // Compute position in bytes in encoded stream. final int nEncodedBytes = getEncodedStreamPosition(); @@ -905,11 +902,11 @@ public Void call() { if (audioInputStream instanceof PropertiesContainer) { // Pass audio parameters such as instant // bit rate, ... - listener.progress(nEncodedBytes, sourceDataLine.getMicrosecondPosition(), + listener.progress(nEncodedBytes, outlet.getSourceDataLine().getMicrosecondPosition(), trimBuffer, ((PropertiesContainer) audioInputStream).properties()); } else // Pass audio parameters - listener.progress(nEncodedBytes, sourceDataLine.getMicrosecondPosition(), + listener.progress(nEncodedBytes, outlet.getSourceDataLine().getMicrosecondPosition(), trimBuffer, emptyMap); }); @@ -918,9 +915,9 @@ public Void call() { } else if (status == Status.PAUSED) { // Flush and stop the source data line - if (sourceDataLine != null && sourceDataLine.isRunning()) { - sourceDataLine.flush(); - sourceDataLine.stop(); + if (outlet.getSourceDataLine() != null && outlet.getSourceDataLine().isRunning()) { + outlet.getSourceDataLine().flush(); + outlet.getSourceDataLine().stop(); } try { while (status == Status.PAUSED) { @@ -939,11 +936,11 @@ public Void call() { } // Free audio resources. - if (sourceDataLine != null) { - sourceDataLine.drain(); - sourceDataLine.stop(); - sourceDataLine.close(); - sourceDataLine = null; + if (outlet.getSourceDataLine() != null) { + outlet.getSourceDataLine().drain(); + outlet.getSourceDataLine().stop(); + outlet.getSourceDataLine().close(); + outlet.setSourceDataLine(null); } // Close stream. @@ -1073,8 +1070,8 @@ private Mixer getMixer(final String name) { * * @return true, if successful */ - private boolean hasControl(final Type control, final Control component) { - return component != null && (sourceDataLine != null) && (sourceDataLine.isControlSupported(control)); + public boolean hasControl(final Type control, final Control component) { + return component != null && (outlet.getSourceDataLine() != null) && (outlet.getSourceDataLine().isControlSupported(control)); } /** @@ -1183,13 +1180,9 @@ public int getPositionByte() { return positionByte; } - /** - * Gets the source data line. - * - * @return The SourceDataLine - */ - public SourceDataLine getSourceDataLine() { - return sourceDataLine; + /** The source data line. */ + public Outlet getOutlet() { + return outlet; } /** diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index fbe2405..8adabdd 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -198,7 +198,8 @@ void stopped() { @Test void sourceDataLine() { - final SourceDataLine sourceDataLine = player.getSourceDataLine(); + final SourceDataLine sourceDataLine = player.getOutlet().getSourceDataLine(); + assertNotNull(sourceDataLine); From f89aa044caf5f0a45512e8d7c6dbd4b53d7c8405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Mon, 9 Sep 2019 23:43:42 +0200 Subject: [PATCH 11/32] SourceDataLine tested, getter restored in StreamPlayer --- .../goxr3plus/streamplayer/stream/StreamPlayer.java | 5 ++++- .../streamplayer/stream/SourceDataLineTest.java | 13 +++++++++++++ .../stream/StreamPlayerMethodsTest.java | 10 ++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 29afbdd..ab0026d 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -82,7 +82,7 @@ public class StreamPlayer implements Callable { /** The audio file format. */ private AudioFileFormat audioFileFormat; - + // -------------------LOCKS--------------------- /** @@ -1385,4 +1385,7 @@ Logger getLogger() { return logger; } + public SourceDataLine getSourceDataLine() { + return outlet.getSourceDataLine(); + } } diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index ee4cdc3..a1b3658 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import javax.sound.sampled.SourceDataLine; import java.io.File; import java.util.logging.Logger; @@ -156,4 +157,16 @@ void mute() throws StreamPlayerException { player.setMute(false); assertFalse(player.getMute()); } + + @Test + void sourceDataLine() throws StreamPlayerException { + assertNull(player.getSourceDataLine()); + + player.open(audioFile); + assertNotNull(player.getSourceDataLine()); + + player.play(); + + assertNotNull(player.getSourceDataLine()); + } } diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index 8adabdd..c75163a 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -197,13 +197,15 @@ void stopped() { } @Test - void sourceDataLine() { - final SourceDataLine sourceDataLine = player.getOutlet().getSourceDataLine(); + void sourceDataLine() throws StreamPlayerException { + assertNull(player.getSourceDataLine()); + player.open(audioFile); + assertNotNull(player.getSourceDataLine()); - assertNotNull(sourceDataLine); + player.play(); - fail("Test not done"); + assertNotNull(player.getSourceDataLine()); } @Test From 6eef3196be136e0eb28fed415fb52cdd13fd6781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:11:29 +0200 Subject: [PATCH 12/32] StreamPlayerInterface implemented, so that I can maintain compatibility. --- .../application/AnotherDemoApplication.java | 5 +- .../streamplayer/application/AnotherMain.java | 3 +- .../AnotherStreamPlayerListener.java | 5 +- .../streamplayer/stream/StreamPlayer.java | 49 ++- .../stream/StreamPlayerInterface.java | 338 ++++++++++++++++++ 5 files changed, 393 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java diff --git a/src/main/java/com/goxr3plus/streamplayer/application/AnotherDemoApplication.java b/src/main/java/com/goxr3plus/streamplayer/application/AnotherDemoApplication.java index 5bd49e8..c47c260 100644 --- a/src/main/java/com/goxr3plus/streamplayer/application/AnotherDemoApplication.java +++ b/src/main/java/com/goxr3plus/streamplayer/application/AnotherDemoApplication.java @@ -3,6 +3,7 @@ import com.goxr3plus.streamplayer.enums.Status; import com.goxr3plus.streamplayer.stream.StreamPlayer; import com.goxr3plus.streamplayer.stream.StreamPlayerEvent; +import com.goxr3plus.streamplayer.stream.StreamPlayerInterface; import com.goxr3plus.streamplayer.stream.StreamPlayerListener; import java.io.File; @@ -16,10 +17,10 @@ public class AnotherDemoApplication { private final String audioFileName = "Logic - Ballin [Bass Boosted].mp3"; - private StreamPlayer streamPlayer; + private StreamPlayerInterface streamPlayer; private StreamPlayerListener listener; - public AnotherDemoApplication(StreamPlayer streamPlayer) { + public AnotherDemoApplication(StreamPlayerInterface streamPlayer) { this.streamPlayer = streamPlayer; this.listener = new AnotherStreamPlayerListener(audioFileName, streamPlayer); diff --git a/src/main/java/com/goxr3plus/streamplayer/application/AnotherMain.java b/src/main/java/com/goxr3plus/streamplayer/application/AnotherMain.java index d8bfdb0..66ede42 100644 --- a/src/main/java/com/goxr3plus/streamplayer/application/AnotherMain.java +++ b/src/main/java/com/goxr3plus/streamplayer/application/AnotherMain.java @@ -1,12 +1,13 @@ package com.goxr3plus.streamplayer.application; import com.goxr3plus.streamplayer.stream.StreamPlayer; +import com.goxr3plus.streamplayer.stream.StreamPlayerInterface; import com.goxr3plus.streamplayer.stream.StreamPlayerListener; public class AnotherMain { public static void main(String[] args) { - final StreamPlayer streamPlayer = new StreamPlayer(); + final StreamPlayerInterface streamPlayer = new StreamPlayer(); final AnotherDemoApplication application = new AnotherDemoApplication(streamPlayer); application.start(); diff --git a/src/main/java/com/goxr3plus/streamplayer/application/AnotherStreamPlayerListener.java b/src/main/java/com/goxr3plus/streamplayer/application/AnotherStreamPlayerListener.java index 2b27805..0cae44c 100644 --- a/src/main/java/com/goxr3plus/streamplayer/application/AnotherStreamPlayerListener.java +++ b/src/main/java/com/goxr3plus/streamplayer/application/AnotherStreamPlayerListener.java @@ -3,6 +3,7 @@ import com.goxr3plus.streamplayer.enums.Status; import com.goxr3plus.streamplayer.stream.StreamPlayer; import com.goxr3plus.streamplayer.stream.StreamPlayerEvent; +import com.goxr3plus.streamplayer.stream.StreamPlayerInterface; import com.goxr3plus.streamplayer.stream.StreamPlayerListener; import java.util.Map; @@ -10,10 +11,10 @@ class AnotherStreamPlayerListener implements StreamPlayerListener { private final String audioFileName; - private StreamPlayer streamPlayer; + private StreamPlayerInterface streamPlayer; - public AnotherStreamPlayerListener(String audioFileName, StreamPlayer streamPlayer) { + public AnotherStreamPlayerListener(String audioFileName, StreamPlayerInterface streamPlayer) { this.audioFileName = audioFileName; this.streamPlayer = streamPlayer; } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index ab0026d..c755366 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -60,14 +60,14 @@ * @author GOXR3PLUS (www.goxr3plus.co.nf) * @author JavaZOOM (www.javazoom.net) */ -public class StreamPlayer implements Callable { +public class StreamPlayer implements StreamPlayerInterface, Callable { /** * Class logger */ private Logger logger; - // -------------------AUDIO--------------------- + // -------------------AUDIO----------------,----- private volatile Status status = Status.NOT_SPECIFIED; @@ -180,6 +180,7 @@ public StreamPlayer(Logger logger, ExecutorService streamPlayerExecutorService, /** * Freeing the resources. */ + @Override public void reset() { // Close the stream @@ -237,6 +238,7 @@ private String generateEvent(final Status status, final int encodedStreamPositio * * @param streamPlayerListener the listener */ + @Override public void addStreamPlayerListener(final StreamPlayerListener streamPlayerListener) { listeners.add(streamPlayerListener); } @@ -246,6 +248,7 @@ public void addStreamPlayerListener(final StreamPlayerListener streamPlayerListe * * @param streamPlayerListener the listener */ + @Override public void removeStreamPlayerListener(final StreamPlayerListener streamPlayerListener) { if (listeners != null) listeners.remove(streamPlayerListener); @@ -259,6 +262,7 @@ public void removeStreamPlayerListener(final StreamPlayerListener streamPlayerLi * * @throws StreamPlayerException the stream player exception */ + @Override public void open(final Object object) throws StreamPlayerException { logger.info(() -> "open(" + object + ")\n"); @@ -407,6 +411,7 @@ else if (!outlet.getSourceDataLine().getFormat().equals(audioInputStream == null * * @param speedFactor speedFactor */ + @Override public void setSpeedFactor(final double speedFactor) { this.speedFactor = speedFactor; @@ -556,6 +561,7 @@ private void openLine() throws LineUnavailableException { * * @throws StreamPlayerException the stream player exception */ + @Override public void play() throws StreamPlayerException { if (status == Status.STOPPED) initAudioInputStream(); @@ -593,6 +599,7 @@ public void play() throws StreamPlayerException { * * @return true, if successful */ + @Override public boolean pause() { if (outlet.getSourceDataLine() == null || status != Status.PLAYING) return false; @@ -608,6 +615,7 @@ public boolean pause() { * Player Status = STOPPED.
* Thread should free Audio resources. */ + @Override public void stop() { if (status == Status.STOPPED) return; @@ -625,6 +633,7 @@ public void stop() { * * @return False if failed(so simple...) */ + @Override public boolean resume() { if (outlet.getSourceDataLine() == null || status != Status.PAUSED) return false; @@ -686,6 +695,7 @@ private void awaitTermination() { * * @throws StreamPlayerException the stream player exception */ + @Override public long seekBytes(final long bytes) throws StreamPlayerException { long totalSkipped = 0; @@ -748,6 +758,7 @@ else if (previousStatus == Status.PAUSED) { * * @param seconds Seconds to Skip */ + @Override //todo not finished needs more validations public long seekSeconds(int seconds) throws StreamPlayerException { int durationInSeconds = this.getDurationInSeconds(); @@ -781,6 +792,7 @@ public long seekSeconds(int seconds) throws StreamPlayerException { * * @param seconds Seconds to Skip */ + @Override public long seekTo(int seconds) throws StreamPlayerException { int durationInSeconds = this.getDurationInSeconds(); @@ -815,6 +827,8 @@ private void validateSeconds(int seconds, int durationInSeconds) { } } + + @Override public int getDurationInSeconds() { // Audio resources from file||URL||inputStream. @@ -968,6 +982,7 @@ public Void call() { * * @return The Position of the encoded stream in term of bytes */ + @Override public int getEncodedStreamPosition() { int position = -1; if (dataSource instanceof File && encodedAudioInputStream != null) @@ -999,6 +1014,7 @@ private void closeStream() { * * @return -1 maximum buffer size. */ + @Override public int getLineBufferSize() { return lineBufferSize; } @@ -1008,6 +1024,7 @@ public int getLineBufferSize() { * * @return The current line buffer size */ + @Override public int getLineCurrentBufferSize() { return currentLineBufferSize; } @@ -1017,6 +1034,7 @@ public int getLineCurrentBufferSize() { * * @return A List of available Mixers */ + @Override public List getMixers() { final List mixers = new ArrayList<>(); @@ -1079,6 +1097,7 @@ public boolean hasControl(final Type control, final Control component) { * * @return The Gain Value */ + @Override public float getGainValue() { if (hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { @@ -1093,6 +1112,7 @@ public float getGainValue() { * * @return The Maximum Gain Value */ + @Override public float getMaximumGain() { return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMaximum(); @@ -1103,6 +1123,7 @@ public float getMaximumGain() { * * @return The Minimum Gain Value */ + @Override public float getMinimumGain() { return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMinimum(); @@ -1114,6 +1135,7 @@ public float getMinimumGain() { * * @return The Precision Value */ + @Override public float getPrecision() { return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getPrecision(); @@ -1124,6 +1146,7 @@ public float getPrecision() { * * @return The Pan Value */ + @Override public float getPan() { return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getValue(); @@ -1134,6 +1157,7 @@ public float getPan() { * * @return True if muted , False if not */ + @Override public boolean getMute() { return hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue(); } @@ -1143,6 +1167,7 @@ public boolean getMute() { * * @return The Balance Value */ + @Override public float getBalance() { return !hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) ? 0f : outlet.getBalanceControl().getValue(); } @@ -1152,6 +1177,7 @@ public float getBalance() { * * @return encodedAudioLength */ + @Override public long getTotalBytes() { return encodedAudioLength; } @@ -1169,6 +1195,7 @@ public long getTotalBytes() { /** * @return BytePosition */ + @Override public int getPositionByte() { final int positionByte = AudioSystem.NOT_SPECIFIED; if (audioProperties != null) { @@ -1190,6 +1217,7 @@ public Outlet getOutlet() { * * @return The Player Status */ + @Override public Status getStatus() { return status; } @@ -1214,6 +1242,7 @@ private Map deepCopy(final Map map) { * * @param size -1 means maximum buffer size available. */ + @Override public void setLineBufferSize(final int size) { lineBufferSize = size; } @@ -1224,6 +1253,7 @@ public void setLineBufferSize(final int size) { * * @param fPan the new pan */ + @Override public void setPan(final double fPan) { if (!hasControl(FloatControl.Type.PAN, outlet.getPanControl()) || fPan < -1.0 || fPan > 1.0) @@ -1240,6 +1270,7 @@ public void setPan(final double fPan) { * * @param fGain The new gain value */ + @Override public void setGain(final double fGain) { if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { final double logScaleGain = 20 * Math.log10(fGain); @@ -1247,6 +1278,7 @@ public void setGain(final double fGain) { } } + @Override public void setLogScaleGain(final double logScaleGain) { if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { outlet.getGainControl().setValue((float) logScaleGain); @@ -1258,6 +1290,7 @@ public void setLogScaleGain(final double logScaleGain) { * * @param mute True to mute the audio of False to unmute it */ + @Override public void setMute(final boolean mute) { if (hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue() != mute) outlet.getMuteControl().setValue(mute); @@ -1270,6 +1303,7 @@ public void setMute(final boolean mute) { * * @param fBalance the new balance */ + @Override public void setBalance(final float fBalance) { if (hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) && fBalance >= -1.0 && fBalance <= 1.0) outlet.getBalanceControl().setValue(fBalance); @@ -1287,6 +1321,7 @@ public void setBalance(final float fBalance) { * @param array the array * @param stop the stop */ + @Override public void setEqualizer(final float[] array, final int stop) { if (!isPausedOrPlaying() || !(audioInputStream instanceof PropertiesContainer)) return; @@ -1302,6 +1337,7 @@ public void setEqualizer(final float[] array, final int stop) { * @param value the value * @param key the key */ + @Override public void setEqualizerKey(final float value, final int key) { if (!isPausedOrPlaying() || !(audioInputStream instanceof PropertiesContainer)) return; @@ -1314,6 +1350,7 @@ public void setEqualizerKey(final float value, final int key) { /** * @return The Speech Factor of the Audio */ + @Override public double getSpeedFactor() { return this.speedFactor; } @@ -1323,6 +1360,7 @@ public double getSpeedFactor() { * * @return If Status==STATUS.UNKNOWN. */ + @Override public boolean isUnknown() { return status == Status.NOT_SPECIFIED; } @@ -1332,6 +1370,7 @@ public boolean isUnknown() { * * @return true if player is playing ,false if not. */ + @Override public boolean isPlaying() { return status == Status.PLAYING; } @@ -1341,6 +1380,7 @@ public boolean isPlaying() { * * @return true if player is paused ,false if not. */ + @Override public boolean isPaused() { return status == Status.PAUSED; } @@ -1350,6 +1390,7 @@ public boolean isPaused() { * * @return true if player is paused/playing,false if not */ + @Override public boolean isPausedOrPlaying() { return isPlaying() || isPaused(); } @@ -1359,6 +1400,7 @@ public boolean isPausedOrPlaying() { * * @return true if player is stopped ,false if not */ + @Override public boolean isStopped() { return status == Status.STOPPED; } @@ -1368,6 +1410,7 @@ public boolean isStopped() { * * @return true if player is opened ,false if not */ + @Override public boolean isOpened() { return status == Status.OPENED; } @@ -1377,6 +1420,7 @@ public boolean isOpened() { * * @return true if player is seeking ,false if not */ + @Override public boolean isSeeking() { return status == Status.SEEKING; } @@ -1385,6 +1429,7 @@ Logger getLogger() { return logger; } + @Override public SourceDataLine getSourceDataLine() { return outlet.getSourceDataLine(); } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java new file mode 100644 index 0000000..47c79cf --- /dev/null +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java @@ -0,0 +1,338 @@ +package com.goxr3plus.streamplayer.stream; + +import com.goxr3plus.streamplayer.enums.Status; + +import javax.sound.sampled.SourceDataLine; +import java.util.List; +import java.util.concurrent.Callable; + +public interface StreamPlayerInterface { + /** + * Freeing the resources. + */ + void reset(); + + /** + * Add a listener to be notified. + * + * @param streamPlayerListener the listener + */ + void addStreamPlayerListener(StreamPlayerListener streamPlayerListener); + + /** + * Remove registered listener. + * + * @param streamPlayerListener the listener + */ + void removeStreamPlayerListener(StreamPlayerListener streamPlayerListener); + + /** + * Open the specific object which can be File,URL or InputStream. + * + * @param object the object [File or URL or InputStream ] + * + * @throws StreamPlayerException the stream player exception + */ + void open(Object object) throws StreamPlayerException; + + /** + * Change the Speed Rate of the Audio , this variable affects the Sample Rate , + * for example 1.0 is normal , 0.5 is half the speed and 2.0 is double the speed + * Note that you have to restart the audio for this to take effect + * + * @param speedFactor speedFactor + */ + void setSpeedFactor(double speedFactor); + + /** + * Starts the play back. + * + * @throws StreamPlayerException the stream player exception + */ + void play() throws StreamPlayerException; + + /** + * Pauses the play back.
+ *

+ * Player Status = PAUSED. * @return False if failed(so simple...) + * + * @return true, if successful + */ + boolean pause(); + + /** + * Stops the play back.
+ *

+ * Player Status = STOPPED.
+ * Thread should free Audio resources. + */ + void stop(); + + /** + * Resumes the play back.
+ *

+ * Player Status = PLAYING* + * + * @return False if failed(so simple...) + */ + boolean resume(); + + /** + * Skip bytes in the File input stream. It will skip N frames matching to bytes, + * so it will never skip given bytes len + * + * @param bytes the bytes + * + * @return value bigger than 0 for File and value = 0 for URL and InputStream + * + * @throws StreamPlayerException the stream player exception + */ + long seekBytes(long bytes) throws StreamPlayerException; + + /** + * Skip x seconds of audio + * See {@link #seekBytes(long)} + * + * @param seconds Seconds to Skip + */ + //todo not finished needs more validations + long seekSeconds(int seconds) throws StreamPlayerException; + + /** + * Go to X time of the Audio + * See {@link #seekBytes(long)} + * + * @param seconds Seconds to Skip + */ + long seekTo(int seconds) throws StreamPlayerException; + + int getDurationInSeconds(); + +// /** +// * Main loop. +// *

+// * Player Status == STOPPED || SEEKING = End of Thread + Freeing Audio +// * Resources.
+// * Player Status == PLAYING = Audio stream data sent to Audio line.
+// * Player Status == PAUSED = Waiting for another status. +// */ +// @Override +// Void call(); + + /** + * Calculates the current position of the encoded audio based on
+ * nEncodedBytes = encodedAudioLength - + * encodedAudioInputStream.available(); + * + * @return The Position of the encoded stream in term of bytes + */ + int getEncodedStreamPosition(); + + /** + * Return SourceDataLine buffer size. + * + * @return -1 maximum buffer size. + */ + int getLineBufferSize(); + + /** + * Return SourceDataLine current buffer size. + * + * @return The current line buffer size + */ + int getLineCurrentBufferSize(); + + /** + * Returns all available mixers. + * + * @return A List of available Mixers + */ + List getMixers(); + + /** + * Returns Gain value. + * + * @return The Gain Value + */ + float getGainValue(); + + /** + * Returns maximum Gain value. + * + * @return The Maximum Gain Value + */ + float getMaximumGain(); + + /** + * Returns minimum Gain value. + * + * @return The Minimum Gain Value + */ + float getMinimumGain(); + + /** + * Returns Pan precision. + * + * @return The Precision Value + */ + float getPrecision(); + + /** + * Returns Pan value. + * + * @return The Pan Value + */ + float getPan(); + + /** + * Return the mute Value(true || false). + * + * @return True if muted , False if not + */ + boolean getMute(); + + /** + * Return the balance Value. + * + * @return The Balance Value + */ + float getBalance(); + + /**** + * Return the total size of this file in bytes. + * + * @return encodedAudioLength + */ + long getTotalBytes(); + + /** + * @return BytePosition + */ + int getPositionByte(); + + /** + * Gets the source data line. + * + * @return The SourceDataLine + */ + SourceDataLine getSourceDataLine(); + + /** + * This method will return the status of the player + * + * @return The Player Status + */ + Status getStatus(); + + /** + * Set SourceDataLine buffer size. It affects audio latency. (the delay between + * line.write(data) and real sound). Minimum value should be over 10000 bytes. + * + * @param size -1 means maximum buffer size available. + */ + void setLineBufferSize(int size); + + /** + * Sets Pan value. Line should be opened before calling this method. Linear + * scale : -1.0 ... +1.0 + * + * @param fPan the new pan + */ + void setPan(double fPan); + + /** + * Sets Gain value. Line should be opened before calling this method. Linear + * scale 0.0 ... 1.0 Threshold Coef. : 1/2 to avoid saturation. + * + * @param fGain The new gain value + */ + void setGain(double fGain); + + void setLogScaleGain(double logScaleGain); + + /** + * Set the mute of the Line. Note that mute status does not affect gain. + * + * @param mute True to mute the audio of False to unmute it + */ + void setMute(boolean mute); + + /** + * Represents a control for the relative balance of a stereo signal between two + * stereo speakers. The valid range of values is -1.0 (left channel only) to 1.0 + * (right channel only). The default is 0.0 (centered). + * + * @param fBalance the new balance + */ + void setBalance(float fBalance); + + /** + * Changes specific values from equalizer. + * + * @param array the array + * @param stop the stop + */ + void setEqualizer(float[] array, int stop); + + /** + * Changes a value from equalizer. + * + * @param value the value + * @param key the key + */ + void setEqualizerKey(float value, int key); + + /** + * @return The Speech Factor of the Audio + */ + double getSpeedFactor(); + + /** + * Checks if is unknown. + * + * @return If Status==STATUS.UNKNOWN. + */ + boolean isUnknown(); + + /** + * Checks if is playing. + * + * @return true if player is playing ,false if not. + */ + boolean isPlaying(); + + /** + * Checks if is paused. + * + * @return true if player is paused ,false if not. + */ + boolean isPaused(); + + /** + * Checks if is paused or playing. + * + * @return true if player is paused/playing,false if not + */ + boolean isPausedOrPlaying(); + + /** + * Checks if is stopped. + * + * @return true if player is stopped ,false if not + */ + boolean isStopped(); + + /** + * Checks if is opened. + * + * @return true if player is opened ,false if not + */ + boolean isOpened(); + + /** + * Checks if is seeking. + * + * @return true if player is seeking ,false if not + */ + boolean isSeeking(); +} From 89114b96c6060f133fc541c6c7fc15adabbca71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:13:54 +0200 Subject: [PATCH 13/32] Update StreamPlayerInterface.java Minor comment fixes --- .../streamplayer/stream/StreamPlayerInterface.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java index 47c79cf..6fc309c 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayerInterface.java @@ -108,17 +108,6 @@ public interface StreamPlayerInterface { int getDurationInSeconds(); -// /** -// * Main loop. -// *

-// * Player Status == STOPPED || SEEKING = End of Thread + Freeing Audio -// * Resources.
-// * Player Status == PLAYING = Audio stream data sent to Audio line.
-// * Player Status == PAUSED = Waiting for another status. -// */ -// @Override -// Void call(); - /** * Calculates the current position of the encoded audio based on
* nEncodedBytes = encodedAudioLength - @@ -198,7 +187,7 @@ public interface StreamPlayerInterface { */ float getBalance(); - /**** + /** * Return the total size of this file in bytes. * * @return encodedAudioLength From db4c7135c8fb8b2a23d92347f2f714e7245fce71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:19:26 +0200 Subject: [PATCH 14/32] Update Outlet.java Alphabetically sorted methods --- .../goxr3plus/streamplayer/stream/Outlet.java | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 93b0b7f..65b88f4 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -10,49 +10,46 @@ public class Outlet { private FloatControl gainControl; private BooleanControl muteControl; private FloatControl panControl; - - /** The source data line. */ private SourceDataLine sourceDataLine; - public SourceDataLine getSourceDataLine() { - return sourceDataLine; - } - public void setSourceDataLine(SourceDataLine sourceDataLine) { - this.sourceDataLine = sourceDataLine; + public FloatControl getBalanceControl() { + return balanceControl; } + public FloatControl getGainControl() { + return gainControl; + } public BooleanControl getMuteControl() { return muteControl; } - public void setMuteControl(BooleanControl muteControl) { - this.muteControl = muteControl; - } - - public FloatControl getPanControl() { return panControl; } - public void setPanControl(FloatControl panControl) { - this.panControl = panControl; - } - - public FloatControl getBalanceControl() { - return balanceControl; + public SourceDataLine getSourceDataLine() { + return sourceDataLine; } public void setBalanceControl(FloatControl balanceControl) { this.balanceControl = balanceControl; } - public FloatControl getGainControl() { - return gainControl; - } - public void setGainControl(FloatControl gainControl) { this.gainControl = gainControl; } + + public void setMuteControl(BooleanControl muteControl) { + this.muteControl = muteControl; + } + + public void setPanControl(FloatControl panControl) { + this.panControl = panControl; + } + + public void setSourceDataLine(SourceDataLine sourceDataLine) { + this.sourceDataLine = sourceDataLine; + } } From fdb191d924b7da61635f60e1419e7f3b01509b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:28:34 +0200 Subject: [PATCH 15/32] hasControl moved to Outlet --- .../goxr3plus/streamplayer/stream/Outlet.java | 15 ++++++++ .../streamplayer/stream/StreamPlayer.java | 38 ++++++------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 65b88f4..6004599 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -1,6 +1,7 @@ package com.goxr3plus.streamplayer.stream; import javax.sound.sampled.BooleanControl; +import javax.sound.sampled.Control; import javax.sound.sampled.FloatControl; import javax.sound.sampled.SourceDataLine; @@ -52,4 +53,18 @@ public void setPanControl(FloatControl panControl) { public void setSourceDataLine(SourceDataLine sourceDataLine) { this.sourceDataLine = sourceDataLine; } + + + /** + * Check if the Control is Supported by m_line. + * + * @param control the control + * @param component the component + * + * @param streamPlayer + * @return true, if successful + */ + public boolean hasControl(final Control.Type control, final Control component, StreamPlayer streamPlayer) { + return component != null && (getSourceDataLine() != null) && (getSourceDataLine().isControlSupported(control)); + } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index c755366..bc80f97 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -34,8 +34,6 @@ import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.BooleanControl; -import javax.sound.sampled.Control; -import javax.sound.sampled.Control.Type; import javax.sound.sampled.DataLine; import javax.sound.sampled.FloatControl; import javax.sound.sampled.Line; @@ -1080,18 +1078,6 @@ private Mixer getMixer(final String name) { return mixer; } - /** - * Check if the Control is Supported by m_line. - * - * @param control the control - * @param component the component - * - * @return true, if successful - */ - public boolean hasControl(final Type control, final Control component) { - return component != null && (outlet.getSourceDataLine() != null) && (outlet.getSourceDataLine().isControlSupported(control)); - } - /** * Returns Gain value. * @@ -1100,7 +1086,7 @@ public boolean hasControl(final Type control, final Control component) { @Override public float getGainValue() { - if (hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { + if (outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { return outlet.getGainControl().getValue(); } else { return 0.0F; @@ -1114,7 +1100,7 @@ public float getGainValue() { */ @Override public float getMaximumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMaximum(); + return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this) ? 0.0F : outlet.getGainControl().getMaximum(); } @@ -1126,7 +1112,7 @@ public float getMaximumGain() { @Override public float getMinimumGain() { - return !hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMinimum(); + return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this) ? 0.0F : outlet.getGainControl().getMinimum(); } @@ -1137,7 +1123,7 @@ public float getMinimumGain() { */ @Override public float getPrecision() { - return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getPrecision(); + return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) ? 0.0F : outlet.getPanControl().getPrecision(); } @@ -1148,7 +1134,7 @@ public float getPrecision() { */ @Override public float getPan() { - return !hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getValue(); + return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) ? 0.0F : outlet.getPanControl().getValue(); } @@ -1159,7 +1145,7 @@ public float getPan() { */ @Override public boolean getMute() { - return hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue(); + return outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl(), this) && outlet.getMuteControl().getValue(); } /** @@ -1169,7 +1155,7 @@ public boolean getMute() { */ @Override public float getBalance() { - return !hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) ? 0f : outlet.getBalanceControl().getValue(); + return !outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl(), this) ? 0f : outlet.getBalanceControl().getValue(); } /**** @@ -1256,7 +1242,7 @@ public void setLineBufferSize(final int size) { @Override public void setPan(final double fPan) { - if (!hasControl(FloatControl.Type.PAN, outlet.getPanControl()) || fPan < -1.0 || fPan > 1.0) + if (!outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) || fPan < -1.0 || fPan > 1.0) return; logger.info(() -> "Pan : " + fPan); outlet.getPanControl().setValue((float) fPan); @@ -1272,7 +1258,7 @@ public void setPan(final double fPan) { */ @Override public void setGain(final double fGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { + if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { final double logScaleGain = 20 * Math.log10(fGain); outlet.getGainControl().setValue((float) logScaleGain); } @@ -1280,7 +1266,7 @@ public void setGain(final double fGain) { @Override public void setLogScaleGain(final double logScaleGain) { - if (isPlaying() || isPaused() && hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { + if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { outlet.getGainControl().setValue((float) logScaleGain); } } @@ -1292,7 +1278,7 @@ public void setLogScaleGain(final double logScaleGain) { */ @Override public void setMute(final boolean mute) { - if (hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue() != mute) + if (outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl(), this) && outlet.getMuteControl().getValue() != mute) outlet.getMuteControl().setValue(mute); } @@ -1305,7 +1291,7 @@ public void setMute(final boolean mute) { */ @Override public void setBalance(final float fBalance) { - if (hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) && fBalance >= -1.0 && fBalance <= 1.0) + if (outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl(), this) && fBalance >= -1.0 && fBalance <= 1.0) outlet.getBalanceControl().setValue(fBalance); else try { From 2da2d78b762352a7457328be5e561e7fa129fa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:32:11 +0200 Subject: [PATCH 16/32] hasControl signature simplified --- .../goxr3plus/streamplayer/stream/Outlet.java | 3 +-- .../streamplayer/stream/StreamPlayer.java | 24 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 6004599..5328270 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -61,10 +61,9 @@ public void setSourceDataLine(SourceDataLine sourceDataLine) { * @param control the control * @param component the component * - * @param streamPlayer * @return true, if successful */ - public boolean hasControl(final Control.Type control, final Control component, StreamPlayer streamPlayer) { + public boolean hasControl(final Control.Type control, final Control component) { return component != null && (getSourceDataLine() != null) && (getSourceDataLine().isControlSupported(control)); } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index bc80f97..2c8bb5c 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -1086,7 +1086,7 @@ private Mixer getMixer(final String name) { @Override public float getGainValue() { - if (outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { + if (outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { return outlet.getGainControl().getValue(); } else { return 0.0F; @@ -1100,7 +1100,7 @@ public float getGainValue() { */ @Override public float getMaximumGain() { - return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this) ? 0.0F : outlet.getGainControl().getMaximum(); + return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMaximum(); } @@ -1112,7 +1112,7 @@ public float getMaximumGain() { @Override public float getMinimumGain() { - return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this) ? 0.0F : outlet.getGainControl().getMinimum(); + return !outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl()) ? 0.0F : outlet.getGainControl().getMinimum(); } @@ -1123,7 +1123,7 @@ public float getMinimumGain() { */ @Override public float getPrecision() { - return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) ? 0.0F : outlet.getPanControl().getPrecision(); + return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getPrecision(); } @@ -1134,7 +1134,7 @@ public float getPrecision() { */ @Override public float getPan() { - return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) ? 0.0F : outlet.getPanControl().getValue(); + return !outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl()) ? 0.0F : outlet.getPanControl().getValue(); } @@ -1145,7 +1145,7 @@ public float getPan() { */ @Override public boolean getMute() { - return outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl(), this) && outlet.getMuteControl().getValue(); + return outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue(); } /** @@ -1155,7 +1155,7 @@ public boolean getMute() { */ @Override public float getBalance() { - return !outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl(), this) ? 0f : outlet.getBalanceControl().getValue(); + return !outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) ? 0f : outlet.getBalanceControl().getValue(); } /**** @@ -1242,7 +1242,7 @@ public void setLineBufferSize(final int size) { @Override public void setPan(final double fPan) { - if (!outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl(), this) || fPan < -1.0 || fPan > 1.0) + if (!outlet.hasControl(FloatControl.Type.PAN, outlet.getPanControl()) || fPan < -1.0 || fPan > 1.0) return; logger.info(() -> "Pan : " + fPan); outlet.getPanControl().setValue((float) fPan); @@ -1258,7 +1258,7 @@ public void setPan(final double fPan) { */ @Override public void setGain(final double fGain) { - if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { + if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { final double logScaleGain = 20 * Math.log10(fGain); outlet.getGainControl().setValue((float) logScaleGain); } @@ -1266,7 +1266,7 @@ public void setGain(final double fGain) { @Override public void setLogScaleGain(final double logScaleGain) { - if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl(), this)) { + if (isPlaying() || isPaused() && outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { outlet.getGainControl().setValue((float) logScaleGain); } } @@ -1278,7 +1278,7 @@ public void setLogScaleGain(final double logScaleGain) { */ @Override public void setMute(final boolean mute) { - if (outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl(), this) && outlet.getMuteControl().getValue() != mute) + if (outlet.hasControl(BooleanControl.Type.MUTE, outlet.getMuteControl()) && outlet.getMuteControl().getValue() != mute) outlet.getMuteControl().setValue(mute); } @@ -1291,7 +1291,7 @@ public void setMute(final boolean mute) { */ @Override public void setBalance(final float fBalance) { - if (outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl(), this) && fBalance >= -1.0 && fBalance <= 1.0) + if (outlet.hasControl(FloatControl.Type.BALANCE, outlet.getBalanceControl()) && fBalance >= -1.0 && fBalance <= 1.0) outlet.getBalanceControl().setValue(fBalance); else try { From b21b6bbe6f5d198ad1f26ec5c30fa9a309de252b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 08:35:02 +0200 Subject: [PATCH 17/32] getGainValue moved, thin wrapper left in place. --- .../com/goxr3plus/streamplayer/stream/Outlet.java | 14 ++++++++++++++ .../streamplayer/stream/StreamPlayer.java | 7 +------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 5328270..7268640 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -66,4 +66,18 @@ public void setSourceDataLine(SourceDataLine sourceDataLine) { public boolean hasControl(final Control.Type control, final Control component) { return component != null && (getSourceDataLine() != null) && (getSourceDataLine().isControlSupported(control)); } + + /** + * Returns Gain value. + * + * @return The Gain Value + */ + public float getGainValue() { + + if (hasControl(FloatControl.Type.MASTER_GAIN, getGainControl())) { + return getGainControl().getValue(); + } else { + return 0.0F; + } + } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 2c8bb5c..1ba18ac 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -1085,12 +1085,7 @@ private Mixer getMixer(final String name) { */ @Override public float getGainValue() { - - if (outlet.hasControl(FloatControl.Type.MASTER_GAIN, outlet.getGainControl())) { - return outlet.getGainControl().getValue(); - } else { - return 0.0F; - } + return outlet.getGainValue(); } /** From 409bf9bf6f5362a027c0fac1bae29bb83de4b69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 22:14:09 +0200 Subject: [PATCH 18/32] Step towards testing reset() and moving a couple of methods --- .../streamplayer/stream/StreamPlayer.java | 28 +++++++++++-------- .../stream/SourceDataLineTest.java | 19 +++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 1ba18ac..634d0d3 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -185,13 +185,7 @@ public void reset() { synchronized (audioLock) { closeStream(); } - - // Source Data Line - if (outlet.getSourceDataLine() != null) { - outlet.getSourceDataLine().flush(); - outlet.getSourceDataLine().close(); - outlet.setSourceDataLine(null); - } + resetOutlet(); // AudioFile audioInputStream = null; @@ -200,10 +194,7 @@ public void reset() { encodedAudioLength = -1; // Controls - outlet.setGainControl(null); - outlet.setPanControl(null); - outlet.setBalanceControl(null); - // sampleRateControl = null + resetControls(); // Notify the Status status = Status.NOT_SPECIFIED; @@ -211,6 +202,21 @@ public void reset() { } + private void resetControls() { + outlet.setGainControl(null); + outlet.setPanControl(null); + outlet.setBalanceControl(null); + } + + private void resetOutlet() { + // Source Data Line + if (outlet.getSourceDataLine() != null) { + outlet.getSourceDataLine().flush(); + outlet.getSourceDataLine().close(); + outlet.setSourceDataLine(null); + } + } + /** * Notify listeners about a BasicPlayerEvent. * diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index a1b3658..4b9c746 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -169,4 +169,23 @@ void sourceDataLine() throws StreamPlayerException { assertNotNull(player.getSourceDataLine()); } + + @Test + // @Timeout(1) + void reset() throws StreamPlayerException { + + assertNull(player.getSourceDataLine()); + + player.open(audioFile); + assertNotNull(player.getSourceDataLine()); + +// player.play(); +// assertNotNull(player.getSourceDataLine()); + + player.reset(); + assertNull(player.getSourceDataLine()); + player.stop(); + + + } } From 266f97b4ea1703f451a1da146e1a5483a6d2a426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 22:50:01 +0200 Subject: [PATCH 19/32] Test with reset() behaves oddly reset() is a public method. If it's called when the player is playing, it seems to not return. I cannot really see what is executing when I run the test in the debugger. The test print "play()", and goes on to play the song. It never prints "reset()" Expected behavior: The player is stopped so quickly, that no music is heard. Maxium one frame of sound samples. The word "reset() should be printed after "play()". What can be learnt from this behavior? --- .../streamplayer/stream/StreamPlayerMethodsTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index 755896d..05e2a3b 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -403,5 +403,15 @@ void equalizerKey() { fail("Test not done"); } + @Test + void resetShouldStopPlayback() throws StreamPlayerException { + player.open((audioFile)); + player.play(); + System.out.println("play()"); + player.reset(); + System.out.println("reset()"); + player.stop(); + } + } From ea5528582a844761f62af58cfb041868847a5e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 22:53:17 +0200 Subject: [PATCH 20/32] Revert "Step towards testing reset() and moving a couple of methods" This reverts commit 409bf9bf6f5362a027c0fac1bae29bb83de4b69b. --- .../streamplayer/stream/StreamPlayer.java | 28 ++++++++----------- .../stream/SourceDataLineTest.java | 19 ------------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 634d0d3..1ba18ac 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -185,7 +185,13 @@ public void reset() { synchronized (audioLock) { closeStream(); } - resetOutlet(); + + // Source Data Line + if (outlet.getSourceDataLine() != null) { + outlet.getSourceDataLine().flush(); + outlet.getSourceDataLine().close(); + outlet.setSourceDataLine(null); + } // AudioFile audioInputStream = null; @@ -194,7 +200,10 @@ public void reset() { encodedAudioLength = -1; // Controls - resetControls(); + outlet.setGainControl(null); + outlet.setPanControl(null); + outlet.setBalanceControl(null); + // sampleRateControl = null // Notify the Status status = Status.NOT_SPECIFIED; @@ -202,21 +211,6 @@ public void reset() { } - private void resetControls() { - outlet.setGainControl(null); - outlet.setPanControl(null); - outlet.setBalanceControl(null); - } - - private void resetOutlet() { - // Source Data Line - if (outlet.getSourceDataLine() != null) { - outlet.getSourceDataLine().flush(); - outlet.getSourceDataLine().close(); - outlet.setSourceDataLine(null); - } - } - /** * Notify listeners about a BasicPlayerEvent. * diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index 4b9c746..a1b3658 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -169,23 +169,4 @@ void sourceDataLine() throws StreamPlayerException { assertNotNull(player.getSourceDataLine()); } - - @Test - // @Timeout(1) - void reset() throws StreamPlayerException { - - assertNull(player.getSourceDataLine()); - - player.open(audioFile); - assertNotNull(player.getSourceDataLine()); - -// player.play(); -// assertNotNull(player.getSourceDataLine()); - - player.reset(); - assertNull(player.getSourceDataLine()); - player.stop(); - - - } } From 8df75ce3e930c3fecf2fe1a84958bbce5c8e2018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 08:20:40 +0200 Subject: [PATCH 21/32] Extracted stopAndFreeDataLine from call(), moved it to Outlet Also extracted flushAndStopOutlet, but it's not tested yet, so it will be moved when it's tested. --- .../goxr3plus/streamplayer/stream/Outlet.java | 10 +++++ .../streamplayer/stream/StreamPlayer.java | 38 +++++++++---------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 7268640..d1944db 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -80,4 +80,14 @@ public float getGainValue() { return 0.0F; } } + + void stopAndFreeDataLine() { + // Free audio resources. + if (sourceDataLine != null) { + sourceDataLine.drain(); + sourceDataLine.stop(); + sourceDataLine.close(); + this.sourceDataLine = null; + } + } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 1ba18ac..aa53472 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -925,20 +925,8 @@ public Void call() { } } else if (status == Status.PAUSED) { + flushAndStopOutlet(); - // Flush and stop the source data line - if (outlet.getSourceDataLine() != null && outlet.getSourceDataLine().isRunning()) { - outlet.getSourceDataLine().flush(); - outlet.getSourceDataLine().stop(); - } - try { - while (status == Status.PAUSED) { - Thread.sleep(50); - } - } catch (final InterruptedException ex) { - Thread.currentThread().interrupt(); - logger.warning("Thread cannot sleep.\n" + ex); - } } } catch (final IOException ex) { logger.log(Level.WARNING, "\"Decoder Exception: \" ", ex); @@ -946,14 +934,8 @@ public Void call() { generateEvent(Status.STOPPED, getEncodedStreamPosition(), null); } } - // Free audio resources. - if (outlet.getSourceDataLine() != null) { - outlet.getSourceDataLine().drain(); - outlet.getSourceDataLine().stop(); - outlet.getSourceDataLine().close(); - outlet.setSourceDataLine(null); - } + outlet.stopAndFreeDataLine(); // Close stream. closeStream(); @@ -973,6 +955,22 @@ public Void call() { return null; } + private void flushAndStopOutlet() { + // Flush and stop the source data line + if (outlet.getSourceDataLine() != null && outlet.getSourceDataLine().isRunning()) { + outlet.getSourceDataLine().flush(); + outlet.getSourceDataLine().stop(); + } + try { + while (status == Status.PAUSED) { + Thread.sleep(50); + } + } catch (final InterruptedException ex) { + Thread.currentThread().interrupt(); + logger.warning("Thread cannot sleep.\n" + ex); + } + } + /** * Calculates the current position of the encoded audio based on
* nEncodedBytes = encodedAudioLength - From 7c411f88a2ac07350cbc1f106695b8f271cd0131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 08:35:51 +0200 Subject: [PATCH 22/32] Update SourceDataLineTest.java Test that paueses, to exercise flushAndStopOutlet() --- .../stream/SourceDataLineTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index a1b3658..73ea045 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; import javax.sound.sampled.SourceDataLine; import java.io.File; @@ -10,6 +11,7 @@ import static java.lang.Math.log10; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.booleanThat; import static org.mockito.Mockito.mock; public class SourceDataLineTest { @@ -169,4 +171,22 @@ void sourceDataLine() throws StreamPlayerException { assertNotNull(player.getSourceDataLine()); } + + @Test + void playAndPause() throws StreamPlayerException, InterruptedException { + boolean listen = true; + player.open(audioFile); + player.play(); + player.seekTo(30); + if (listen) Thread.sleep(2000); + + player.pause(); + if (listen) Thread.sleep(1000); + + player.resume(); // TODO: Examine what happens if play() is called instead. + if (listen) Thread.sleep(2000); + //player.stop(); + + // TODO: asserts and listen=false + } } From 2a7747fdd3c9c377c951e74bba1c16fd5fcea37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 18:43:28 +0200 Subject: [PATCH 23/32] flushAndStop extracted from SteamPlayer.call() into Outlet class --- .../com/goxr3plus/streamplayer/stream/Outlet.java | 11 +++++++++++ .../goxr3plus/streamplayer/stream/StreamPlayer.java | 11 ++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index d1944db..6e42461 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -1,5 +1,7 @@ package com.goxr3plus.streamplayer.stream; +import com.goxr3plus.streamplayer.enums.Status; + import javax.sound.sampled.BooleanControl; import javax.sound.sampled.Control; import javax.sound.sampled.FloatControl; @@ -90,4 +92,13 @@ void stopAndFreeDataLine() { this.sourceDataLine = null; } } + + void flushAndStop() { + // Flush and stop the source data line + if (getSourceDataLine() != null && getSourceDataLine().isRunning()) { + getSourceDataLine().flush(); + getSourceDataLine().stop(); + } + } + } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index aa53472..4ed0752 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -925,7 +925,9 @@ public Void call() { } } else if (status == Status.PAUSED) { - flushAndStopOutlet(); + // Flush and stop the source data line + outlet.flushAndStop(); + goOutOfPause(); } } catch (final IOException ex) { @@ -955,12 +957,7 @@ public Void call() { return null; } - private void flushAndStopOutlet() { - // Flush and stop the source data line - if (outlet.getSourceDataLine() != null && outlet.getSourceDataLine().isRunning()) { - outlet.getSourceDataLine().flush(); - outlet.getSourceDataLine().stop(); - } + private void goOutOfPause() { try { while (status == Status.PAUSED) { Thread.sleep(50); From 2e680459b532e03ce8ff78d9e0915e0abfd3e2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 18:55:55 +0200 Subject: [PATCH 24/32] stopAndFreeDataLine extracted from StreamPlayer.reset() --- .../com/goxr3plus/streamplayer/stream/Outlet.java | 14 ++++++++++---- .../streamplayer/stream/StreamPlayer.java | 9 ++------- .../streamplayer/stream/SourceDataLineTest.java | 6 +++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 6e42461..8e736e7 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -1,7 +1,5 @@ package com.goxr3plus.streamplayer.stream; -import com.goxr3plus.streamplayer.enums.Status; - import javax.sound.sampled.BooleanControl; import javax.sound.sampled.Control; import javax.sound.sampled.FloatControl; @@ -83,13 +81,21 @@ public float getGainValue() { } } - void stopAndFreeDataLine() { + void drainStopAndFreeDataLine() { // Free audio resources. if (sourceDataLine != null) { sourceDataLine.drain(); sourceDataLine.stop(); sourceDataLine.close(); - this.sourceDataLine = null; + this.sourceDataLine = null; // TODO: Is this necessary? Will it not be garbage collected? + } + } + + void stopAndFreeDataLine() { + if (getSourceDataLine() != null) { + getSourceDataLine().flush(); + getSourceDataLine().close(); + this.sourceDataLine = null; // TODO: Is this necessary? Will it not be garbage collected? } } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 4ed0752..b607ae3 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -186,12 +186,7 @@ public void reset() { closeStream(); } - // Source Data Line - if (outlet.getSourceDataLine() != null) { - outlet.getSourceDataLine().flush(); - outlet.getSourceDataLine().close(); - outlet.setSourceDataLine(null); - } + outlet.stopAndFreeDataLine(); // AudioFile audioInputStream = null; @@ -937,7 +932,7 @@ public Void call() { } } // Free audio resources. - outlet.stopAndFreeDataLine(); + outlet.drainStopAndFreeDataLine(); // Close stream. closeStream(); diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java index 73ea045..e7ec583 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/SourceDataLineTest.java @@ -178,13 +178,13 @@ void playAndPause() throws StreamPlayerException, InterruptedException { player.open(audioFile); player.play(); player.seekTo(30); - if (listen) Thread.sleep(2000); + if (listen) Thread.sleep(200); player.pause(); - if (listen) Thread.sleep(1000); + if (listen) Thread.sleep(100); player.resume(); // TODO: Examine what happens if play() is called instead. - if (listen) Thread.sleep(2000); + if (listen) Thread.sleep(200); //player.stop(); // TODO: asserts and listen=false From fec1005f071e24b982bcf6642de0aefab5bb01c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 20:23:44 +0200 Subject: [PATCH 25/32] Outlet.start(), used now in StreamPlayer.play() --- .../java/com/goxr3plus/streamplayer/stream/Outlet.java | 7 +++++++ .../com/goxr3plus/streamplayer/stream/StreamPlayer.java | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 8e736e7..2bdda5c 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -107,4 +107,11 @@ void flushAndStop() { } } + boolean isStartable() { + return getSourceDataLine() != null && !getSourceDataLine().isRunning(); + } + void start() { + getSourceDataLine().start(); + } + } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index b607ae3..0d92528 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -572,8 +572,8 @@ public void play() throws StreamPlayerException { } // Open the sourceDataLine - if (outlet.getSourceDataLine() != null && !outlet.getSourceDataLine().isRunning()) { - outlet.getSourceDataLine().start(); + if (outlet.isStartable()) { + outlet.start(); // Proceed only if we have not problems logger.info("Submitting new StreamPlayer Thread"); From 2fc083c0ca92c548603823879101ff982cd650fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 20:50:24 +0200 Subject: [PATCH 26/32] Removed some calls of outlet.getSourceDataLine() --- .../streamplayer/stream/StreamPlayer.java | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 0d92528..577c73f 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -502,26 +502,27 @@ private void openLine() throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); - if (outlet.getSourceDataLine() != null) { + final SourceDataLine sourceDataLine = outlet.getSourceDataLine(); + if (sourceDataLine != null) { final AudioFormat audioFormat = audioInputStream.getFormat(); - currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); - outlet.getSourceDataLine().open(audioFormat, currentLineBufferSize); + currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : sourceDataLine.getBufferSize(); + sourceDataLine.open(audioFormat, currentLineBufferSize); // opened? - if (outlet.getSourceDataLine().isOpen()) { + if (sourceDataLine.isOpen()) { // logger.info(() -> "Open Line Buffer Size=" + bufferSize + "\n"); /*-- Display supported controls --*/ // Control[] c = m_line.getControls() // Master_Gain Control? - if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) - outlet.setGainControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); + if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) + outlet.setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); else outlet.setGainControl(null); // PanControl? - if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) - outlet.setPanControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.PAN)); + if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) + outlet.setPanControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN)); else outlet.setPanControl(null); // SampleRate? @@ -532,14 +533,14 @@ private void openLine() throws LineUnavailableException { // sampleRateControl = null // Mute? - BooleanControl muteControl1 = outlet.getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) - ? (BooleanControl) outlet.getSourceDataLine().getControl(BooleanControl.Type.MUTE) + BooleanControl muteControl1 = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) + ? (BooleanControl) sourceDataLine.getControl(BooleanControl.Type.MUTE) : null; outlet.setMuteControl(muteControl1); // Speakers Balance? - FloatControl balanceControl = outlet.getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) - ? (FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.BALANCE) + FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) + ? (FloatControl) sourceDataLine.getControl(FloatControl.Type.BALANCE) : null; outlet.setBalanceControl(balanceControl); } @@ -630,7 +631,7 @@ public void stop() { public boolean resume() { if (outlet.getSourceDataLine() == null || status != Status.PAUSED) return false; - outlet.getSourceDataLine().start(); + outlet.start(); status = Status.PLAYING; generateEvent(Status.RESUMED, getEncodedStreamPosition(), null); logger.info("resumePlayback() completed"); @@ -857,15 +858,6 @@ public Void call() { // Main play/pause loop. while ((nBytesRead != -1) && status != Status.STOPPED && status != Status.NOT_SPECIFIED && status != Status.SEEKING) { - // if (status == Status.SEEKING) { - // try { - // System.out.println("Audio Seeking ..."); - // Thread.sleep(50); - // } catch (InterruptedException e) { - // e.printStackTrace(); - // } - // continue; - // } try { // Playing? From 460f7dbf215be4a610cbdc46911010e7dc66dc66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 20:59:02 +0200 Subject: [PATCH 27/32] Revert outlet.getSourceDataLine() --> sourceDataLine, more or less --- .../streamplayer/stream/StreamPlayer.java | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 577c73f..60c90ea 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -198,7 +198,6 @@ public void reset() { outlet.setGainControl(null); outlet.setPanControl(null); outlet.setBalanceControl(null); - // sampleRateControl = null // Notify the Status status = Status.NOT_SPECIFIED; @@ -365,7 +364,7 @@ private void determineProperties() { audioProperties.put("basicplayer.sourcedataline", outlet.getSourceDataLine()); // Keep this final reference for the lambda expression - final Map audioPropertiesCopy = audioProperties; + final Map audioPropertiesCopy = audioProperties; // TODO: Remove, it's meaningless. // Notify all registered StreamPlayerListeners listeners.forEach(listener -> listener.opened(dataSource, audioPropertiesCopy)); @@ -502,45 +501,33 @@ private void openLine() throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); - final SourceDataLine sourceDataLine = outlet.getSourceDataLine(); - if (sourceDataLine != null) { + if (outlet.getSourceDataLine() != null) { final AudioFormat audioFormat = audioInputStream.getFormat(); - currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : sourceDataLine.getBufferSize(); - sourceDataLine.open(audioFormat, currentLineBufferSize); + currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); + outlet.getSourceDataLine().open(audioFormat, currentLineBufferSize); // opened? - if (sourceDataLine.isOpen()) { - // logger.info(() -> "Open Line Buffer Size=" + bufferSize + "\n"); - - /*-- Display supported controls --*/ - // Control[] c = m_line.getControls() + if (outlet.getSourceDataLine().isOpen()) { // Master_Gain Control? - if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) - outlet.setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); + if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) + outlet.setGainControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); else outlet.setGainControl(null); // PanControl? - if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) - outlet.setPanControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN)); + if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) + outlet.setPanControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.PAN)); else outlet.setPanControl(null); - // SampleRate? - // if (sourceDataLine.isControlSupported(FloatControl.Type.SAMPLE_RATE)) - // sampleRateControl = (FloatControl) - // sourceDataLine.getControl(FloatControl.Type.SAMPLE_RATE); - // else - // sampleRateControl = null - // Mute? - BooleanControl muteControl1 = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) - ? (BooleanControl) sourceDataLine.getControl(BooleanControl.Type.MUTE) + BooleanControl muteControl1 = outlet.getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) + ? (BooleanControl) outlet.getSourceDataLine().getControl(BooleanControl.Type.MUTE) : null; outlet.setMuteControl(muteControl1); // Speakers Balance? - FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) - ? (FloatControl) sourceDataLine.getControl(FloatControl.Type.BALANCE) + FloatControl balanceControl = outlet.getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) + ? (FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.BALANCE) : null; outlet.setBalanceControl(balanceControl); } From ed25d8fd57ead2922dc26177634d8ee986c58f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 21:18:38 +0200 Subject: [PATCH 28/32] openLine() ready for move --- .../streamplayer/stream/StreamPlayer.java | 21 ++++++++++++------- .../stream/StreamPlayerMethodsTest.java | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 60c90ea..6b600a6 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -385,11 +385,16 @@ private void initLine() throws LineUnavailableException, StreamPlayerException { if (outlet.getSourceDataLine() == null) createLine(); - if (!outlet.getSourceDataLine().isOpen()) - openLine(); - else if (!outlet.getSourceDataLine().getFormat().equals(audioInputStream == null ? null : audioInputStream.getFormat())) { - outlet.getSourceDataLine().close(); - openLine(); + if (!outlet.getSourceDataLine().isOpen()) { + currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); + openLine(audioInputStream.getFormat(), currentLineBufferSize); + } else { + AudioFormat format = audioInputStream == null ? null : audioInputStream.getFormat(); + if (!outlet.getSourceDataLine().getFormat().equals(format)) { // TODO: Check if bug, does equals work as intended? + outlet.getSourceDataLine().close(); + currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); + openLine(audioInputStream.getFormat(), currentLineBufferSize); + } } } @@ -496,14 +501,14 @@ private void createLine() throws LineUnavailableException, StreamPlayerException * Open the line. * * @throws LineUnavailableException the line unavailable exception + * @param audioFormat + * @param currentLineBufferSize */ - private void openLine() throws LineUnavailableException { + private void openLine(AudioFormat audioFormat, int currentLineBufferSize) throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); if (outlet.getSourceDataLine() != null) { - final AudioFormat audioFormat = audioInputStream.getFormat(); - currentLineBufferSize = lineBufferSize >= 0 ? lineBufferSize : outlet.getSourceDataLine().getBufferSize(); outlet.getSourceDataLine().open(audioFormat, currentLineBufferSize); // opened? diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index c75163a..683e9a2 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -344,7 +344,7 @@ void seekBytes() throws StreamPlayerException { } - // The methods tested below aren't used otherwhere in this project, nor in XR3Player + // The methods tested below aren't used elsewhere in this project, nor in XR3Player @Test void lineBufferSize() { From e12f0b30a8adc3603de79c8058072dbdbc12de1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 21:26:18 +0200 Subject: [PATCH 29/32] openLine() moved to outlet:open() --- .../goxr3plus/streamplayer/stream/Outlet.java | 46 +++++++++++++++++-- .../streamplayer/stream/StreamPlayer.java | 38 +-------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 2bdda5c..042dff9 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -1,18 +1,21 @@ package com.goxr3plus.streamplayer.stream; -import javax.sound.sampled.BooleanControl; -import javax.sound.sampled.Control; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.*; +import java.util.logging.Logger; public class Outlet { + private final Logger logger; private FloatControl balanceControl; private FloatControl gainControl; private BooleanControl muteControl; private FloatControl panControl; private SourceDataLine sourceDataLine; + public Outlet(Logger logger) { + this.logger = logger; + } + public FloatControl getBalanceControl() { return balanceControl; @@ -114,4 +117,39 @@ void start() { getSourceDataLine().start(); } + void open(AudioFormat audioFormat, int currentLineBufferSize) throws LineUnavailableException { + logger.info("Entered OpenLine()!:\n"); + + if (getSourceDataLine() != null) { + getSourceDataLine().open(audioFormat, currentLineBufferSize); + + // opened? + if (getSourceDataLine().isOpen()) { + + // Master_Gain Control? + if (getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) + setGainControl((FloatControl) getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); + else setGainControl(null); + + // PanControl? + if (getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) + setPanControl((FloatControl) getSourceDataLine().getControl(FloatControl.Type.PAN)); + else setPanControl(null); + + // Mute? + BooleanControl muteControl1 = getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) + ? (BooleanControl) getSourceDataLine().getControl(BooleanControl.Type.MUTE) + : null; + setMuteControl(muteControl1); + + // Speakers Balance? + FloatControl balanceControl = getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) + ? (FloatControl) getSourceDataLine().getControl(FloatControl.Type.BALANCE) + : null; + setBalanceControl(balanceControl); + } + } + logger.info("Exited OpenLine()!:\n"); + } + } diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 6b600a6..41d0735 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -171,7 +171,7 @@ public StreamPlayer(Logger logger, ExecutorService streamPlayerExecutorService, this.streamPlayerExecutorService = streamPlayerExecutorService; this.eventsExecutorService = eventsExecutorService; listeners = new ArrayList<>(); - outlet = new Outlet(); + outlet = new Outlet(logger); reset(); } @@ -505,41 +505,7 @@ private void createLine() throws LineUnavailableException, StreamPlayerException * @param currentLineBufferSize */ private void openLine(AudioFormat audioFormat, int currentLineBufferSize) throws LineUnavailableException { - - logger.info("Entered OpenLine()!:\n"); - - if (outlet.getSourceDataLine() != null) { - outlet.getSourceDataLine().open(audioFormat, currentLineBufferSize); - - // opened? - if (outlet.getSourceDataLine().isOpen()) { - - // Master_Gain Control? - if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) - outlet.setGainControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); - else outlet.setGainControl(null); - - // PanControl? - if (outlet.getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) - outlet.setPanControl((FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.PAN)); - else outlet.setPanControl(null); - - // Mute? - BooleanControl muteControl1 = outlet.getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) - ? (BooleanControl) outlet.getSourceDataLine().getControl(BooleanControl.Type.MUTE) - : null; - outlet.setMuteControl(muteControl1); - - // Speakers Balance? - FloatControl balanceControl = outlet.getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) - ? (FloatControl) outlet.getSourceDataLine().getControl(FloatControl.Type.BALANCE) - : null; - outlet.setBalanceControl(balanceControl); - } - - } - - logger.info("Exited OpenLine()!:\n"); + outlet.open(audioFormat, currentLineBufferSize); } /** From c437025e151f13449e17d8393aeed2b464cf6bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 21:28:23 +0200 Subject: [PATCH 30/32] inline calls to getSourceDataLine() in Outlet --- .../goxr3plus/streamplayer/stream/Outlet.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 042dff9..7cf3908 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -67,7 +67,7 @@ public void setSourceDataLine(SourceDataLine sourceDataLine) { * @return true, if successful */ public boolean hasControl(final Control.Type control, final Control component) { - return component != null && (getSourceDataLine() != null) && (getSourceDataLine().isControlSupported(control)); + return component != null && (sourceDataLine != null) && (sourceDataLine.isControlSupported(control)); } /** @@ -95,56 +95,56 @@ void drainStopAndFreeDataLine() { } void stopAndFreeDataLine() { - if (getSourceDataLine() != null) { - getSourceDataLine().flush(); - getSourceDataLine().close(); + if (sourceDataLine != null) { + sourceDataLine.flush(); + sourceDataLine.close(); this.sourceDataLine = null; // TODO: Is this necessary? Will it not be garbage collected? } } void flushAndStop() { // Flush and stop the source data line - if (getSourceDataLine() != null && getSourceDataLine().isRunning()) { - getSourceDataLine().flush(); - getSourceDataLine().stop(); + if (sourceDataLine != null && sourceDataLine.isRunning()) { + sourceDataLine.flush(); + sourceDataLine.stop(); } } boolean isStartable() { - return getSourceDataLine() != null && !getSourceDataLine().isRunning(); + return sourceDataLine != null && !sourceDataLine.isRunning(); } void start() { - getSourceDataLine().start(); + sourceDataLine.start(); } void open(AudioFormat audioFormat, int currentLineBufferSize) throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); - if (getSourceDataLine() != null) { - getSourceDataLine().open(audioFormat, currentLineBufferSize); + if (sourceDataLine != null) { + sourceDataLine.open(audioFormat, currentLineBufferSize); // opened? - if (getSourceDataLine().isOpen()) { + if (sourceDataLine.isOpen()) { // Master_Gain Control? - if (getSourceDataLine().isControlSupported(FloatControl.Type.MASTER_GAIN)) - setGainControl((FloatControl) getSourceDataLine().getControl(FloatControl.Type.MASTER_GAIN)); + if (sourceDataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) + setGainControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN)); else setGainControl(null); // PanControl? - if (getSourceDataLine().isControlSupported(FloatControl.Type.PAN)) - setPanControl((FloatControl) getSourceDataLine().getControl(FloatControl.Type.PAN)); + if (sourceDataLine.isControlSupported(FloatControl.Type.PAN)) + setPanControl((FloatControl) sourceDataLine.getControl(FloatControl.Type.PAN)); else setPanControl(null); // Mute? - BooleanControl muteControl1 = getSourceDataLine().isControlSupported(BooleanControl.Type.MUTE) - ? (BooleanControl) getSourceDataLine().getControl(BooleanControl.Type.MUTE) + BooleanControl muteControl1 = sourceDataLine.isControlSupported(BooleanControl.Type.MUTE) + ? (BooleanControl) sourceDataLine.getControl(BooleanControl.Type.MUTE) : null; setMuteControl(muteControl1); // Speakers Balance? - FloatControl balanceControl = getSourceDataLine().isControlSupported(FloatControl.Type.BALANCE) - ? (FloatControl) getSourceDataLine().getControl(FloatControl.Type.BALANCE) + FloatControl balanceControl = sourceDataLine.isControlSupported(FloatControl.Type.BALANCE) + ? (FloatControl) sourceDataLine.getControl(FloatControl.Type.BALANCE) : null; setBalanceControl(balanceControl); } From 96a52e3af2f77d5efa9bbc6456c1a0124e4ef39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Wed, 11 Sep 2019 21:56:04 +0200 Subject: [PATCH 31/32] JavaDoc for Outlet methods --- .../goxr3plus/streamplayer/stream/Outlet.java | 77 ++++++++++++++++++- .../streamplayer/stream/StreamPlayer.java | 25 +----- 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java index 7cf3908..efe293e 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/Outlet.java @@ -3,6 +3,14 @@ import javax.sound.sampled.*; import java.util.logging.Logger; +/** + * Owner of the SourceDataLine which is the output line of the player. + * Also owns controls for the SourceDataLine. + * Future goal is to move all handling of the SourceDataLine to here, + * so that the StreamPlayer doesn't have to call {@link #getSourceDataLine()}. + * Another goal is to remove some of the setter and getter methods of this class, + * by moving all code that needs them to this class. + */ public class Outlet { private final Logger logger; @@ -12,47 +20,82 @@ public class Outlet { private FloatControl panControl; private SourceDataLine sourceDataLine; + /** + * @param logger used to log messages + */ public Outlet(Logger logger) { this.logger = logger; } + /** + * @return the balance control of the {@link #sourceDataLine} + */ public FloatControl getBalanceControl() { return balanceControl; } + /** + * @return the gain control of the {@link #sourceDataLine} + */ public FloatControl getGainControl() { return gainControl; } + /** + * @return the mute control of the {@link #sourceDataLine} + */ public BooleanControl getMuteControl() { return muteControl; } + /** + * @return the pan control of the {@link #sourceDataLine} + */ public FloatControl getPanControl() { return panControl; } + /** + * @return the {@link #sourceDataLine}, which is the output audio signal of the player + */ public SourceDataLine getSourceDataLine() { return sourceDataLine; } + + /** + * @param balanceControl to be set on the {@link #sourceDataLine} + */ public void setBalanceControl(FloatControl balanceControl) { this.balanceControl = balanceControl; } + /** + * @param gainControl to be set on the {@link #sourceDataLine} + */ public void setGainControl(FloatControl gainControl) { this.gainControl = gainControl; } + /** + * @param muteControl to be set on the {@link #sourceDataLine} + */ public void setMuteControl(BooleanControl muteControl) { this.muteControl = muteControl; } + /** + * @param panControl to be set on the {@link #sourceDataLine} + */ public void setPanControl(FloatControl panControl) { this.panControl = panControl; } + /** + * @param sourceDataLine representing the audio output of the player. + * Usually taken from {@link AudioSystem#getLine(Line.Info)}. + */ public void setSourceDataLine(SourceDataLine sourceDataLine) { this.sourceDataLine = sourceDataLine; } @@ -84,6 +127,10 @@ public float getGainValue() { } } + /** + * Stop the {@link #sourceDataLine} in a nice way. + * Also nullify it. (Is that necessary?) + */ void drainStopAndFreeDataLine() { // Free audio resources. if (sourceDataLine != null) { @@ -94,7 +141,11 @@ void drainStopAndFreeDataLine() { } } - void stopAndFreeDataLine() { + /** + * Flush and close the {@link #sourceDataLine} in a nice way. + * Also nullify it. (Is that necessary?) + */ + void flushAndFreeDataLine() { if (sourceDataLine != null) { sourceDataLine.flush(); sourceDataLine.close(); @@ -102,26 +153,44 @@ void stopAndFreeDataLine() { } } + /** + * Flush and stop the {@link #sourceDataLine}, if it's running. + */ void flushAndStop() { // Flush and stop the source data line - if (sourceDataLine != null && sourceDataLine.isRunning()) { + if (sourceDataLine != null && sourceDataLine.isRunning()) { // TODO: Risk for NullPointerException? sourceDataLine.flush(); sourceDataLine.stop(); } } + /** + * @return true if the {@link #sourceDataLine} is startable. + */ boolean isStartable() { return sourceDataLine != null && !sourceDataLine.isRunning(); } + + + /** + * Start the {@link #sourceDataLine} + */ void start() { sourceDataLine.start(); } - void open(AudioFormat audioFormat, int currentLineBufferSize) throws LineUnavailableException { + /** + * Open the {@link #sourceDataLine}. + * Also create controls for it. + * @param format The wanted audio format. + * @param bufferSize the desired buffer size for the {@link #sourceDataLine} + * @throws LineUnavailableException + */ + void open(AudioFormat format, int bufferSize) throws LineUnavailableException { logger.info("Entered OpenLine()!:\n"); if (sourceDataLine != null) { - sourceDataLine.open(audioFormat, currentLineBufferSize); + sourceDataLine.open(format, bufferSize); // opened? if (sourceDataLine.isOpen()) { diff --git a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java index 41d0735..76a0c82 100644 --- a/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java +++ b/src/main/java/com/goxr3plus/streamplayer/stream/StreamPlayer.java @@ -186,7 +186,7 @@ public void reset() { closeStream(); } - outlet.stopAndFreeDataLine(); + outlet.flushAndFreeDataLine(); // AudioFile audioInputStream = null; @@ -759,17 +759,6 @@ public long seekTo(int seconds) throws StreamPlayerException { return seekBytes(bytes); } -// /** -// * Go to X time of the Audio -// * See {@link #seek(long)} -// * -// * @param pattern A string in the format (HH:MM:SS) WHERE h = HOURS , M = minutes , S = seconds -// */ -// public void seekTo(String pattern) throws StreamPlayerException { -// long bytes = 0; -// -// seek(bytes); -// } private void validateSeconds(int seconds, int durationInSeconds) { if (seconds < 0) { @@ -852,8 +841,6 @@ public Void call() { // Compute position in bytes in encoded stream. final int nEncodedBytes = getEncodedStreamPosition(); - // System.err.println(trimBuffer[0] + " , Data Length :" + trimBuffer.length) - // Notify all registered Listeners listeners.forEach(listener -> { if (audioInputStream instanceof PropertiesContainer) { @@ -1103,16 +1090,6 @@ public long getTotalBytes() { return encodedAudioLength; } - /** - * @return - */ - // public int getByteLength() { - // return audioProperties == null || - // !audioProperties.containsKey("audio.length.bytes") ? - // AudioSystem.NOT_SPECIFIED - // : ((Integer) audioProperties.get("audio.length.bytes")).intValue(); - // } - /** * @return BytePosition */ From 90c3dc206bf67a18892932076c44e8c55dbc46a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20Stenstr=C3=B6m?= Date: Tue, 10 Sep 2019 22:50:01 +0200 Subject: [PATCH 32/32] Test with reset() behaves oddly reset() is a public method. If it's called when the player is playing, it seems to not return. I cannot really see what is executing when I run the test in the debugger. The test print "play()", and goes on to play the song. It never prints "reset()" Expected behavior: The player is stopped so quickly, that no music is heard. Maxium one frame of sound samples. The word "reset() should be printed after "play()". What can be learnt from this behavior? --- .../streamplayer/stream/StreamPlayerMethodsTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java index 683e9a2..8f88f38 100644 --- a/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java +++ b/src/test/java/com/goxr3plus/streamplayer/stream/StreamPlayerMethodsTest.java @@ -416,5 +416,15 @@ void equalizerKey() { fail("Test not done"); } + @Test + void resetShouldStopPlayback() throws StreamPlayerException { + player.open((audioFile)); + player.play(); + System.out.println("play()"); + player.reset(); + System.out.println("reset()"); + player.stop(); + } + }