Skip to content

Commit 7e2a77c

Browse files
committed
Fixed #240
1 parent 5a97a60 commit 7e2a77c

9 files changed

Lines changed: 116 additions & 86 deletions

File tree

core/src/main/java/xyz/gianlu/librespot/player/Player.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,8 @@ private void sendProgress() {
990990
TrackOrEpisode metadata = currentMetadata();
991991
if (metadata == null) return;
992992

993-
String data = String.format("1/%.0f/%.0f", state.getPosition() * AudioSink.OUTPUT_FORMAT.getSampleRate() / 1000 + 1,
994-
metadata.duration() * AudioSink.OUTPUT_FORMAT.getSampleRate() / 1000 + 1);
993+
String data = String.format("1/%.0f/%.0f", state.getPosition() * AudioSink.DEFAULT_FORMAT.getSampleRate() / 1000 + 1,
994+
metadata.duration() * AudioSink.DEFAULT_FORMAT.getSampleRate() / 1000 + 1);
995995
metadataPipe.safeSend(MetadataPipe.TYPE_SSNC, MetadataPipe.CODE_PRGR, data);
996996
}
997997

core/src/main/java/xyz/gianlu/librespot/player/codecs/Codec.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import xyz.gianlu.librespot.player.Player;
88
import xyz.gianlu.librespot.player.feeders.AbsChunkedInputStream;
99
import xyz.gianlu.librespot.player.feeders.GeneralAudioStream;
10+
import xyz.gianlu.librespot.player.mixing.AudioSink;
1011

1112
import javax.sound.sampled.AudioFormat;
1213
import java.io.Closeable;
@@ -22,15 +23,14 @@ public abstract class Codec implements Closeable {
2223
protected final AbsChunkedInputStream audioIn;
2324
protected final float normalizationFactor;
2425
protected final int duration;
26+
private final AudioSink sink;
2527
private final GeneralAudioStream audioFile;
26-
private final AudioFormat dstFormat;
2728
protected volatile boolean closed = false;
2829
protected int seekZero = 0;
2930
private AudioFormat format;
30-
private StreamConverter converter = null;
3131

32-
Codec(@NotNull AudioFormat dstFormat, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, @NotNull Player.Configuration conf, int duration) {
33-
this.dstFormat = dstFormat;
32+
Codec(@NotNull AudioSink sink, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, @NotNull Player.Configuration conf, int duration) {
33+
this.sink = sink;
3434
this.audioIn = audioFile.stream();
3535
this.audioFile = audioFile;
3636
this.duration = duration;
@@ -41,13 +41,7 @@ public abstract class Codec implements Closeable {
4141
}
4242

4343
public final int writeSomeTo(@NotNull OutputStream out) throws IOException, CodecException {
44-
if (converter == null) return readInternal(out);
45-
46-
int written = readInternal(converter);
47-
if (written == -1) return -1;
48-
49-
converter.checkWritten(written);
50-
return converter.convertInto(out);
44+
return readInternal(out);
5145
}
5246

5347
protected abstract int readInternal(@NotNull OutputStream out) throws IOException, CodecException;
@@ -90,9 +84,6 @@ public final AudioFormat getAudioFormat() {
9084

9185
protected final void setAudioFormat(@NotNull AudioFormat format) {
9286
this.format = format;
93-
94-
if (format.matches(dstFormat)) converter = null;
95-
else converter = StreamConverter.converter(format, dstFormat);
9687
}
9788

9889
protected final int sampleSizeBytes() {

core/src/main/java/xyz/gianlu/librespot/player/codecs/Mp3Codec.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jetbrains.annotations.Nullable;
66
import xyz.gianlu.librespot.player.Player;
77
import xyz.gianlu.librespot.player.feeders.GeneralAudioStream;
8+
import xyz.gianlu.librespot.player.mixing.AudioSink;
89

910
import javax.sound.sampled.AudioFormat;
1011
import java.io.IOException;
@@ -20,8 +21,8 @@ public class Mp3Codec extends Codec {
2021
private final byte[] buffer = new byte[2 * BUFFER_SIZE];
2122
private final Mp3InputStream in;
2223

23-
public Mp3Codec(@NotNull AudioFormat dstFormat, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, Player.@NotNull Configuration conf, int duration) throws IOException, BitstreamException {
24-
super(dstFormat, audioFile, normalizationData, conf, duration);
24+
public Mp3Codec(@NotNull AudioSink sink, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, Player.@NotNull Configuration conf, int duration) throws IOException, BitstreamException {
25+
super(sink, audioFile, normalizationData, conf, duration);
2526

2627
skipMp3Tags(audioIn);
2728
this.in = new Mp3InputStream(audioIn, normalizationFactor);

core/src/main/java/xyz/gianlu/librespot/player/codecs/StreamConverter.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package xyz.gianlu.librespot.player.codecs;
22

3-
import org.apache.logging.log4j.LogManager;
4-
import org.apache.logging.log4j.Logger;
53
import org.jetbrains.annotations.Contract;
64
import org.jetbrains.annotations.NotNull;
75

86
import javax.sound.sampled.AudioFormat;
9-
import java.io.IOException;
107
import java.io.OutputStream;
118

129
public final class StreamConverter extends OutputStream {
13-
private static final Logger LOGGER = LogManager.getLogger(StreamConverter.class);
1410
private final boolean monoToStereo;
1511
private final int sampleSizeFrom;
1612
private final int sampleSizeTo;
@@ -20,8 +16,6 @@ private StreamConverter(@NotNull AudioFormat from, @NotNull AudioFormat to) {
2016
monoToStereo = from.getChannels() == 1 && to.getChannels() == 2;
2117
sampleSizeFrom = from.getSampleSizeInBits();
2218
sampleSizeTo = to.getSampleSizeInBits();
23-
24-
LOGGER.debug("Converting '{}' to '{}'", from, to);
2519
}
2620

2721
public static boolean canConvert(@NotNull AudioFormat from, @NotNull AudioFormat to) {
@@ -95,12 +89,10 @@ private static byte[] sampleSizeConversion(byte[] src, int fromSampleSize, int t
9589
}
9690
}
9791

98-
public int convertInto(@NotNull OutputStream out) throws IOException {
92+
public byte[] convert() {
9993
byte[] result = sampleSizeConversion(buffer, sampleSizeFrom, sampleSizeTo);
10094
if (monoToStereo) result = monoToStereo(result, sampleSizeTo);
101-
102-
out.write(result);
103-
return result.length;
95+
return result;
10496
}
10597

10698
@Override
@@ -114,9 +106,4 @@ public void write(@NotNull byte[] b, int off, int len) {
114106
public void write(int i) {
115107
throw new UnsupportedOperationException();
116108
}
117-
118-
public void checkWritten(int written) {
119-
if (buffer.length != written)
120-
throw new IllegalStateException(String.format("Buffer is %d bytes long, %d should have been written!", buffer.length, written));
121-
}
122109
}

core/src/main/java/xyz/gianlu/librespot/player/codecs/VorbisCodec.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.jetbrains.annotations.Nullable;
1313
import xyz.gianlu.librespot.player.Player;
1414
import xyz.gianlu.librespot.player.feeders.GeneralAudioStream;
15+
import xyz.gianlu.librespot.player.mixing.AudioSink;
1516
import xyz.gianlu.librespot.player.mixing.LineHelper;
1617

1718
import javax.sound.sampled.AudioFormat;
@@ -32,16 +33,16 @@ public class VorbisCodec extends Codec {
3233
private final Page joggPage = new Page();
3334
private final SyncState joggSyncState = new SyncState();
3435
private final Object readLock = new Object();
35-
private byte[] buffer;
36-
private int count;
37-
private int index;
3836
private final byte[] convertedBuffer;
3937
private final float[][][] pcmInfo;
4038
private final int[] pcmIndex;
39+
private byte[] buffer;
40+
private int count;
41+
private int index;
4142
private long pcm_offset;
4243

43-
public VorbisCodec(@NotNull AudioFormat dstFormat, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, Player.@NotNull Configuration conf, int duration) throws IOException, CodecException, LineHelper.MixerException {
44-
super(dstFormat, audioFile, normalizationData, conf, duration);
44+
public VorbisCodec(@NotNull AudioSink sink, @NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, Player.@NotNull Configuration conf, int duration) throws IOException, CodecException, LineHelper.MixerException {
45+
super(sink, audioFile, normalizationData, conf, duration);
4546

4647
this.joggSyncState.init();
4748
this.joggSyncState.buffer(BUFFER_SIZE);

core/src/main/java/xyz/gianlu/librespot/player/mixing/AudioSink.java

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@
1717
* @author devgianlu
1818
*/
1919
public final class AudioSink implements Runnable, Closeable {
20-
public static final AudioFormat OUTPUT_FORMAT = new AudioFormat(44100, 16, 2, true, false);
20+
public static final AudioFormat DEFAULT_FORMAT = new AudioFormat(44100, 16, 2, true, false);
2121
private static final Logger LOGGER = LogManager.getLogger(AudioSink.class);
2222
private final Object pauseLock = new Object();
2323
private final Output output;
24-
private final MixingLine mixing = new MixingLine(OUTPUT_FORMAT);
24+
private final MixingLine mixing = new MixingLine();
2525
private final Thread thread;
2626
private final Listener listener;
2727
private volatile boolean closed = false;
2828
private volatile boolean paused = true;
2929

3030
/**
31-
* Creates a new sink from the current {@param conf} with the standard {@link AudioSink#OUTPUT_FORMAT} format. Also sets the initial volume.
31+
* Creates a new sink from the current {@param conf}. Also sets the initial volume.
3232
*/
3333
public AudioSink(@NotNull Player.Configuration conf, @NotNull Listener listener) {
3434
this.listener = listener;
@@ -56,14 +56,6 @@ public AudioSink(@NotNull Player.Configuration conf, @NotNull Listener listener)
5656
thread.start();
5757
}
5858

59-
/**
60-
* @return The {@link AudioFormat} that this sink accepts
61-
*/
62-
@NotNull
63-
public AudioFormat getFormat() {
64-
return output.getFormat();
65-
}
66-
6759
public void clearOutputs() {
6860
mixing.firstOut().clear();
6961
mixing.secondOut().clear();
@@ -145,8 +137,11 @@ public void run() {
145137
}
146138
} else {
147139
try {
148-
if (!started)
149-
started = output.start();
140+
if (!started || mixing.switchFormat) {
141+
AudioFormat format = mixing.getFormat();
142+
if (format != null) started = output.start(format);
143+
mixing.switchFormat = false;
144+
}
150145

151146
int count = mixing.read(buffer);
152147
output.write(buffer, count);
@@ -197,11 +192,22 @@ private static float calcLogarithmic(int val) {
197192
return (float) (Math.log10((double) val / Player.VOLUME_MAX) * 20f);
198193
}
199194

200-
private void acquireLine() throws LineUnavailableException, LineHelper.MixerException {
201-
if (line != null) return;
195+
private void acquireLine(@NotNull AudioFormat format) throws LineUnavailableException, LineHelper.MixerException {
196+
if (type != Type.MIXER)
197+
return;
202198

203-
line = LineHelper.getLineFor(conf, OUTPUT_FORMAT);
204-
line.open(OUTPUT_FORMAT);
199+
if (line == null || !line.getFormat().matches(format)) {
200+
if (line != null) line.close();
201+
202+
try {
203+
line = LineHelper.getLineFor(conf, format);
204+
line.open(format);
205+
} catch (LineUnavailableException | LineHelper.MixerException ex) {
206+
LOGGER.warn("Failed opening like for custom format '{}'. Opening default.", format);
207+
line = LineHelper.getLineFor(conf, DEFAULT_FORMAT);
208+
line.open(DEFAULT_FORMAT);
209+
}
210+
}
205211

206212
if (lastVolume != -1) setVolume(lastVolume);
207213
}
@@ -214,9 +220,9 @@ void stop() {
214220
if (line != null) line.stop();
215221
}
216222

217-
boolean start() throws LineUnavailableException {
223+
boolean start(@NotNull AudioFormat format) throws LineUnavailableException {
218224
if (type == Type.MIXER) {
219-
acquireLine();
225+
acquireLine(format);
220226
line.start();
221227
return true;
222228
}
@@ -271,12 +277,6 @@ public void close() throws IOException {
271277
if (out != null && out != System.out) out.close();
272278
}
273279

274-
@NotNull
275-
public AudioFormat getFormat() {
276-
if (line != null) return line.getFormat();
277-
else return OUTPUT_FORMAT;
278-
}
279-
280280
void setVolume(int volume) {
281281
lastVolume = volume;
282282

0 commit comments

Comments
 (0)