Skip to content

Commit 1365787

Browse files
committed
Stop playback when #74 happens
1 parent 2ca4226 commit 1365787

6 files changed

Lines changed: 74 additions & 14 deletions

File tree

core/src/main/java/xyz/gianlu/librespot/cdn/CdnManager.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,8 @@ private void requestChunk(int index, boolean retried) {
224224
writeChunk(resp.buffer, index, false);
225225
} catch (IOException ex) {
226226
LOGGER.fatal(String.format("Failed requesting chunk from network, index: %d, retried: %b", index, retried), ex);
227-
if (retried) {
228-
// TODO: Fatal
229-
} else {
230-
requestChunk(index, true);
231-
}
227+
if (retried) internalStream.notifyChunkError(index, new AbsChunckedInputStream.ChunkException(ex));
228+
else requestChunk(index, true);
232229
}
233230
}
234231

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
public abstract class AbsChunckedInputStream extends InputStream {
1515
private static final int PRELOAD_AHEAD = 3;
1616
private final AtomicInteger waitForChunk = new AtomicInteger(-1);
17+
private ChunkException chunkException = null;
1718
private int pos = 0;
1819
private int mark = 0;
1920
private volatile boolean closed = false;
@@ -75,8 +76,13 @@ public void waitFor(int chunkIndex) throws IOException {
7576

7677
synchronized (waitForChunk) {
7778
try {
79+
chunkException = null;
80+
7881
waitForChunk.set(chunkIndex);
7982
waitForChunk.wait();
83+
84+
if (chunkException != null)
85+
throw chunkException;
8086
} catch (InterruptedException ex) {
8187
throw new IOException(ex);
8288
}
@@ -163,4 +169,32 @@ public final void notifyChunkAvailable(int index) {
163169
}
164170
}
165171
}
172+
173+
public final void notifyChunkError(int index, @NotNull ChunkException ex) {
174+
availableChunks()[index] = false;
175+
requestedChunks()[index] = false;
176+
177+
if (index == waitForChunk.get()) {
178+
synchronized (waitForChunk) {
179+
chunkException = ex;
180+
waitForChunk.set(-1);
181+
waitForChunk.notifyAll();
182+
}
183+
}
184+
}
185+
186+
public static class ChunkException extends IOException {
187+
public ChunkException(@NotNull Throwable cause) {
188+
super(cause);
189+
}
190+
191+
private ChunkException(@NotNull String message) {
192+
super(message);
193+
}
194+
195+
@NotNull
196+
public static ChunkException from(short streamError) {
197+
return new ChunkException("Failed due to stream error, code: " + streamError);
198+
}
199+
}
166200
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,22 @@ public void preloadNextTrack(@NotNull TrackHandler handler) {
373373
}
374374
}
375375

376+
@Override
377+
public void playbackError(@NotNull TrackHandler handler, @NotNull Exception ex) {
378+
if (handler == trackHandler) {
379+
if (ex instanceof AbsChunckedInputStream.ChunkException)
380+
LOGGER.fatal("Failed retrieving chunk, playback failed!", ex);
381+
else
382+
LOGGER.fatal("Playback error!", ex);
383+
384+
state.setStatus(Spirc.PlayStatus.kPlayStatusStop);
385+
stateUpdated();
386+
} else if (handler == preloadTrackHandler) {
387+
LOGGER.warn("Preloaded track loading failed!", ex);
388+
preloadTrackHandler = null;
389+
}
390+
}
391+
376392
private void handleLoad(@NotNull Remote3Frame frame) {
377393
if (!spirc.deviceState().getIsActive()) {
378394
spirc.deviceState()

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public void endOfTrack() {
135135

136136
@Override
137137
public void playbackError(@NotNull Exception ex) {
138-
LOGGER.fatal("Playback failed!", ex);
138+
listener.playbackError(this, ex);
139139
}
140140

141141
@Override
@@ -190,6 +190,8 @@ public interface Listener {
190190
void endOfTrack(@NotNull TrackHandler handler);
191191

192192
void preloadNextTrack(@NotNull TrackHandler handler);
193+
194+
void playbackError(@NotNull TrackHandler handler, @NotNull Exception ex);
193195
}
194196

195197
private class Looper implements Runnable {

core/src/main/java/xyz/gianlu/librespot/player/feeders/storage/AudioFileFetch.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.jetbrains.annotations.Nullable;
55
import xyz.gianlu.librespot.cache.CacheManager;
66
import xyz.gianlu.librespot.common.Utils;
7+
import xyz.gianlu.librespot.player.AbsChunckedInputStream;
78

89
import java.io.IOException;
910
import java.nio.ByteBuffer;
@@ -21,6 +22,7 @@ public class AudioFileFetch implements AudioFile {
2122
private int size = -1;
2223
private int chunks = -1;
2324
private volatile boolean closed = false;
25+
private Short streamError = null;
2426

2527
AudioFileFetch(@Nullable CacheManager.Handler cache) {
2628
this.cache = cache;
@@ -49,20 +51,29 @@ public synchronized void writeHeader(byte id, byte[] bytes, boolean cached) thro
4951
size = ByteBuffer.wrap(bytes).getInt();
5052
size *= 4;
5153
chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
54+
55+
streamError = null;
5256
notifyAll();
5357
}
5458
}
5559

5660
@Override
57-
public void streamError(int chunkIndex, short code) {
58-
LOGGER.fatal(String.format("Stream error, index: %d, code: %d", chunkIndex, code)); // TODO: Fatal
61+
public synchronized void streamError(int chunkIndex, short code) {
62+
LOGGER.fatal(String.format("Stream error, index: %d, code: %d", chunkIndex, code));
63+
64+
streamError = code;
65+
notifyAll();
5966
}
6067

61-
synchronized void waitChunk() {
68+
synchronized void waitChunk() throws AbsChunckedInputStream.ChunkException {
6269
if (size != -1) return;
6370

6471
try {
72+
streamError = null;
6573
wait();
74+
75+
if (streamError != null)
76+
throw AbsChunckedInputStream.ChunkException.from(streamError);
6677
} catch (InterruptedException ex) {
6778
throw new RuntimeException(ex);
6879
}

core/src/main/java/xyz/gianlu/librespot/player/feeders/storage/AudioFileStreaming.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,10 @@ private void requestChunk(@NotNull ByteString fileId, int index, @NotNull AudioF
6666
session.channel().requestChunk(fileId, index, file);
6767
} catch (IOException ex) {
6868
LOGGER.fatal(String.format("Failed requesting chunk from network, index: %d, retried: %b", index, retried), ex);
69-
if (retried) {
70-
// TODO: Fatal
71-
} else {
69+
if (retried)
70+
chunksBuffer.internalStream.notifyChunkError(index, new AbsChunckedInputStream.ChunkException(ex));
71+
else
7272
requestChunk(fileId, index, file, true);
73-
}
7473
}
7574
}
7675
}
@@ -150,7 +149,8 @@ public void writeHeader(byte id, byte[] bytes, boolean cached) {
150149

151150
@Override
152151
public void streamError(int chunkIndex, short code) {
153-
LOGGER.fatal(String.format("Stream error, index: %d, code: %d", chunkIndex, code)); // TODO: Fatal
152+
LOGGER.fatal(String.format("Stream error, index: %d, code: %d", chunkIndex, code));
153+
chunksBuffer.internalStream.notifyChunkError(chunkIndex, AbsChunckedInputStream.ChunkException.from(code));
154154
}
155155

156156
@Override

0 commit comments

Comments
 (0)