Skip to content

Commit

Permalink
Crude implementation of a new cache data storage protocol (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
devgianlu committed Nov 13, 2018
1 parent 92d8a27 commit 7fd41af
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 76 deletions.
2 changes: 1 addition & 1 deletion mdnsjava
10 changes: 7 additions & 3 deletions src/main/java/org/librespot/spotify/player/AudioFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
* @author Gianlu
*/
public interface AudioFile {
void writeChunk(byte[] chunk, int chunkIndex) throws IOException;
void writeChunk(byte[] chunk, int chunkIndex, boolean cached) throws IOException;

void header(byte id, byte[] bytes);
void cacheFailedChunk(int index, @NotNull AudioFile file);

void cacheFailed(int index, @NotNull AudioFile file);
void writeHeader(byte id, byte[] bytes, boolean cached);

void cacheFailedHeader(@NotNull AudioFile file);

void headerEnd(boolean cached);
}
43 changes: 38 additions & 5 deletions src/main/java/org/librespot/spotify/player/AudioFileFetch.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,63 @@
package org.librespot.spotify.player;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import static org.librespot.spotify.player.ChannelManager.CHUNK_SIZE;

/**
* @author Gianlu
*/
class AudioFileFetch implements AudioFile {
private final CacheManager.Handler cache;
private final ByteArrayOutputStream headersId = new ByteArrayOutputStream();
private final List<byte[]> headersData = new ArrayList<>();
private int size = -1;
private int chunks = -1;

AudioFileFetch() {
AudioFileFetch(@Nullable CacheManager.Handler cache) {
this.cache = cache;
}

@Override
public void writeChunk(byte[] chunk, int chunkIndex) {
public void writeChunk(byte[] chunk, int chunkIndex, boolean cached) {
if (chunkIndex != 0)
throw new IllegalStateException("chunkIndex not zero: " + chunkIndex);
}

@Override
public synchronized void header(byte id, byte[] bytes) {
public synchronized void writeHeader(byte id, byte[] bytes, boolean cached) {
if (!cached && cache != null) {
headersId.write(id);
headersData.add(bytes);
}

if (id == 0x3) {
size = ByteBuffer.wrap(bytes).getInt();
size *= 4;
chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
notifyAll();
}
}

@Override
public void cacheFailed(int index, @NotNull AudioFile file) {
public void cacheFailedHeader(@NotNull AudioFile file) {
throw new RuntimeException("That could be a problem!"); // FIXME
}

@Override
public synchronized void headerEnd(boolean cached) {
if (!cached && cache != null)
cache.writeHeaders(headersId.toByteArray(), headersData.toArray(new byte[0][]), (short) chunks);
}

@Override
public synchronized void cacheFailedChunk(int index, @NotNull AudioFile file) {
// Never called
}

Expand All @@ -44,7 +72,12 @@ synchronized void waitChunk() {
}

public int getSize() {
if (size == -1) throw new IllegalStateException("Check not received yet!");
if (size == -1) throw new IllegalStateException("Headers not received yet!");
return size;
}

public int getChunks() {
if (chunks == -1) throw new IllegalStateException("Headers not received yet!");
return chunks;
}
}
49 changes: 24 additions & 25 deletions src/main/java/org/librespot/spotify/player/AudioFileStreaming.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,21 @@ private void requestChunk(@NotNull ByteString fileId, int index, @NotNull AudioF
else session.channel().requestChunk(fileId, index, file);
}

private int requestSize() throws IOException {
if (cacheHandler != null && cacheHandler.has(0)) {
try {
return cacheHandler.requestSize();
} catch (IOException ex) {
LOGGER.warn("Failed loading track size from cache.", ex);
cacheHandler.remove();
}
}

AudioFileFetch fetch = new AudioFileFetch();
requestChunk(fileId, 0, fetch);
@NotNull
private AudioFileFetch requestHeaders() throws IOException {
AudioFileFetch fetch = new AudioFileFetch(cacheHandler);
if (cacheHandler != null && cacheHandler.hasHeaders()) cacheHandler.requestHeaders(fetch);
else requestChunk(fileId, 0, fetch);
fetch.waitChunk();
int size = fetch.getSize();
if (cacheHandler != null) cacheHandler.writeSize(size);
return size;
return fetch;
}

public void open() throws IOException {
int size = requestSize();
AudioFileFetch fetch = requestHeaders();

int size = fetch.getSize();
LOGGER.trace("Track size: " + size);
chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
chunks = fetch.getChunks();
LOGGER.trace(String.format("Track has %d chunks.", chunks));

chunksBuffer = new ChunksBuffer(size, chunks);
Expand All @@ -96,30 +89,36 @@ private void requestChunkFromStream(int index) {
}

@Override
public void writeChunk(byte[] buffer, int chunkIndex) throws IOException {
boolean cached = false;
if (cacheHandler != null) {
cached = cacheHandler.has(chunkIndex);
if (!cached) cacheHandler.write(buffer, chunkIndex);
}
public void writeChunk(byte[] buffer, int chunkIndex, boolean cached) throws IOException {
if (!cached && cacheHandler != null)
cacheHandler.write(buffer, chunkIndex);

chunksBuffer.writeChunk(buffer, chunkIndex);
LOGGER.trace(String.format("Chunk %d/%d completed, cached: %b", chunkIndex, chunks, cached));
}

@Override
public void header(byte id, byte[] bytes) {
public void writeHeader(byte id, byte[] bytes, boolean cached) {
}

@Override
public void cacheFailedHeader(@NotNull AudioFile file) {
}

@Override
public void cacheFailed(int index, @NotNull AudioFile file) {
public void cacheFailedChunk(int index, @NotNull AudioFile file) {
try {
session.channel().requestChunk(fileId, index, file);
} catch (IOException ex) {
LOGGER.fatal(String.format("Failed requesting chunk, index: %d", index), ex);
}
}

@Override
public void headerEnd(boolean cached) {
// Never called
}

private class ChunksBuffer {
private final int size;
private final byte[][] buffer;
Expand Down
Loading

0 comments on commit 7fd41af

Please sign in to comment.