Skip to content

Commit 6112130

Browse files
authored
Merge pull request #2 from librespot-org/dev
merge current dev
2 parents d3ef1b4 + 9156a7f commit 6112130

31 files changed

Lines changed: 545 additions & 228 deletions

.github/dependabot.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: maven
4+
directory: "/"
5+
schedule:
6+
interval: daily
7+
open-pull-requests-limit: 10
8+
ignore:
9+
- dependency-name: com.google.protobuf:protobuf-java
10+
versions:
11+
- 3.15.0
12+
- 3.15.1
13+
- 3.15.2
14+
- 3.15.4
15+
- 3.15.5
16+
- package-ecosystem: maven
17+
directory: "/lib"
18+
schedule:
19+
interval: daily
20+
open-pull-requests-limit: 10
21+
- package-ecosystem: maven
22+
directory: "/player"
23+
schedule:
24+
interval: daily
25+
open-pull-requests-limit: 10
26+
- package-ecosystem: maven
27+
directory: "/api"
28+
schedule:
29+
interval: daily
30+
open-pull-requests-limit: 10
31+
- package-ecosystem: maven
32+
directory: "/dacp"
33+
schedule:
34+
interval: daily
35+
open-pull-requests-limit: 10
36+
- package-ecosystem: maven
37+
directory: "/sink"
38+
schedule:
39+
interval: daily
40+
open-pull-requests-limit: 10
41+
- package-ecosystem: maven
42+
directory: "/sink-api"
43+
schedule:
44+
interval: daily
45+
open-pull-requests-limit: 10

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ Its main features are:
1818
- Zeroconf (Spotify Connect)
1919
- Gapless playback
2020
- Mixed playlists (cuepoints and transitions)
21+
- DACP metadata pipe
22+
- Execute commands for various events
23+
- Android compatible (see [librespot-android](https://github.com/devgianlu/librespot-android))
24+
- Optional HTTP API (see [librespot-api](api))
25+
- Supports custom sinks and decoders
26+
- Actively developed and up-to-date with the latest internal API
2127

2228
## The library
2329
The `lib` module provides all the necessary components and tools to interact with Spotify. More [here](lib).
@@ -39,6 +45,7 @@ Snapshots for all variants are available [here](https://oss.sonatype.org/content
3945
- [librespot](https://github.com/librespot-org/librespot)
4046
- [ansible-role-librespot](https://github.com/xMordax/ansible-role-librespot/tree/master) - Ansible role that will build, install and configure librespot-java.
4147
- [spocon](https://github.com/spocon/spocon) - Install librespot-java from APT
48+
- [librespot-android](https://github.com/devgianlu/librespot-android) - Run librespot-java on your Android device
4249

4350
# Special thanks
4451
- All the developers of [librespot](https://github.com/librespot-org/librespot) which started this project in Rust

api/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
<dependency>
100100
<groupId>io.undertow</groupId>
101101
<artifactId>undertow-core</artifactId>
102-
<version>2.2.3.Final</version>
102+
<version>2.2.7.Final</version>
103103
</dependency>
104104
</dependencies>
105105
</project>

decoder-api/pom.xml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!--
2+
~ Copyright 2021 devgianlu
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
17+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
18+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
21+
<parent>
22+
<groupId>xyz.gianlu.librespot</groupId>
23+
<artifactId>librespot-java</artifactId>
24+
<version>1.5.6-SNAPSHOT</version>
25+
<relativePath>../pom.xml</relativePath>
26+
</parent>
27+
28+
<artifactId>librespot-decoder-api</artifactId>
29+
<packaging>jar</packaging>
30+
31+
<name>librespot-java decoder API</name>
32+
33+
<dependencies>
34+
<dependency>
35+
<groupId>xyz.gianlu.librespot</groupId>
36+
<artifactId>librespot-sink-api</artifactId>
37+
<version>${project.version}</version>
38+
</dependency>
39+
40+
<!-- Logging -->
41+
<dependency>
42+
<groupId>org.slf4j</groupId>
43+
<artifactId>slf4j-api</artifactId>
44+
<version>${slf4j-api.version}</version>
45+
</dependency>
46+
</dependencies>
47+
</project>

player/src/main/java/xyz/gianlu/librespot/player/codecs/Codec.java renamed to decoder-api/src/main/java/xyz/gianlu/librespot/player/decoders/Decoder.java

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,34 @@
1414
* limitations under the License.
1515
*/
1616

17-
package xyz.gianlu.librespot.player.codecs;
17+
package xyz.gianlu.librespot.player.decoders;
1818

1919
import org.jetbrains.annotations.NotNull;
20-
import org.jetbrains.annotations.Nullable;
2120
import org.slf4j.Logger;
2221
import org.slf4j.LoggerFactory;
23-
import xyz.gianlu.librespot.audio.AbsChunkedInputStream;
24-
import xyz.gianlu.librespot.audio.GeneralAudioStream;
25-
import xyz.gianlu.librespot.audio.NormalizationData;
26-
import xyz.gianlu.librespot.player.PlayerConfiguration;
2722
import xyz.gianlu.librespot.player.mixing.output.OutputAudioFormat;
2823

2924
import java.io.Closeable;
3025
import java.io.IOException;
3126
import java.io.OutputStream;
3227

3328
/**
34-
* @author Gianlu
29+
* @author devgianlu
3530
*/
36-
public abstract class Codec implements Closeable {
31+
public abstract class Decoder implements Closeable {
3732
public static final int BUFFER_SIZE = 2048;
38-
private static final Logger LOGGER = LoggerFactory.getLogger(Codec.class);
39-
protected final AbsChunkedInputStream audioIn;
33+
private static final Logger LOGGER = LoggerFactory.getLogger(Decoder.class);
34+
protected final SeekableInputStream audioIn;
4035
protected final float normalizationFactor;
4136
protected final int duration;
42-
private final GeneralAudioStream audioFile;
4337
protected volatile boolean closed = false;
4438
protected int seekZero = 0;
4539
private OutputAudioFormat format;
4640

47-
public Codec(@NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, @NotNull PlayerConfiguration conf, int duration) {
48-
this.audioIn = audioFile.stream();
49-
this.audioFile = audioFile;
41+
public Decoder(@NotNull SeekableInputStream audioIn, float normalizationFactor, int duration) {
42+
this.audioIn = audioIn;
5043
this.duration = duration;
51-
if (conf.enableNormalisation)
52-
this.normalizationFactor = normalizationData != null ? normalizationData.getFactor(conf.normalisationPregain) : 1;
53-
else
54-
this.normalizationFactor = 1;
44+
this.normalizationFactor = normalizationFactor;
5545
}
5646

5747
public final int writeSomeTo(@NotNull OutputStream out) throws IOException, CodecException {
@@ -108,25 +98,27 @@ public final int duration() {
10898
return duration;
10999
}
110100

111-
public int size() {
101+
public final int size() {
112102
return audioIn.size();
113103
}
114104

115-
public int decodedLength() {
116-
return audioIn.decodedLength();
117-
}
118-
119-
public int decryptTimeMs() {
120-
return audioFile.decryptTimeMs();
121-
}
122-
123105
public static class CannotGetTimeException extends Exception {
124-
CannotGetTimeException() {
106+
public CannotGetTimeException(String message) {
107+
super(message);
108+
}
109+
110+
public CannotGetTimeException(String message, Throwable cause) {
111+
super(message, cause);
125112
}
126113
}
127114

128115
public static class CodecException extends Exception {
129-
CodecException() {
116+
public CodecException(String message) {
117+
super(message);
118+
}
119+
120+
public CodecException(String message, Throwable cause) {
121+
super(message, cause);
130122
}
131123
}
132124
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2021 devgianlu
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package xyz.gianlu.librespot.player.decoders;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
22+
/**
23+
* @author devgianlu
24+
*/
25+
public abstract class SeekableInputStream extends InputStream {
26+
public abstract int size();
27+
28+
public abstract int position();
29+
30+
public abstract void seek(int seekZero) throws IOException;
31+
32+
public abstract long skip(long skip) throws IOException;
33+
34+
public abstract int read(byte[] buffer, int index, int length) throws IOException;
35+
36+
public abstract void close();
37+
38+
public abstract int decodedLength();
39+
}

lib/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@
8282
</build>
8383

8484
<dependencies>
85+
<dependency>
86+
<groupId>xyz.gianlu.librespot</groupId>
87+
<artifactId>librespot-decoder-api</artifactId>
88+
<version>${project.version}</version>
89+
</dependency>
90+
91+
<!-- Audio -->
92+
<dependency>
93+
<groupId>org.jcraft</groupId>
94+
<artifactId>jorbis</artifactId>
95+
<version>0.0.17</version>
96+
</dependency>
97+
<dependency>
98+
<groupId>com.badlogicgames.jlayer</groupId>
99+
<artifactId>jlayer</artifactId>
100+
<version>1.0.2-gdx</version>
101+
</dependency>
102+
85103
<!-- Data -->
86104
<dependency>
87105
<groupId>com.google.protobuf</groupId>

lib/src/main/java/xyz/gianlu/librespot/audio/AbsChunkedInputStream.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
package xyz.gianlu.librespot.audio;
1818

1919
import org.jetbrains.annotations.NotNull;
20+
import xyz.gianlu.librespot.player.decoders.SeekableInputStream;
2021

2122
import java.io.IOException;
22-
import java.io.InputStream;
2323

2424
import static xyz.gianlu.librespot.audio.storage.ChannelManager.CHUNK_SIZE;
2525

2626
/**
27-
* @author Gianlu
27+
* @author devgianlu
2828
*/
29-
public abstract class AbsChunkedInputStream extends InputStream implements HaltListener {
29+
public abstract class AbsChunkedInputStream extends SeekableInputStream implements HaltListener {
3030
private static final int PRELOAD_AHEAD = 3;
3131
private static final int PRELOAD_CHUNK_RETRIES = 2;
3232
private static final int MAX_CHUNK_TRIES = 128;
@@ -82,10 +82,12 @@ public final synchronized void reset() {
8282
pos = mark;
8383
}
8484

85-
public final synchronized int pos() {
85+
@Override
86+
public final synchronized int position() {
8687
return pos;
8788
}
8889

90+
@Override
8991
public final synchronized void seek(int where) throws IOException {
9092
if (where < 0) throw new IllegalArgumentException();
9193
if (closed) throw new IOException("Stream is closed!");
@@ -260,6 +262,7 @@ public final void notifyChunkError(int index, @NotNull ChunkException ex) {
260262
}
261263
}
262264

265+
@Override
263266
public int decodedLength() {
264267
return decodedLength;
265268
}

lib/src/main/java/xyz/gianlu/librespot/audio/GeneralAudioStream.java renamed to lib/src/main/java/xyz/gianlu/librespot/audio/DecodedAudioStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222

2323
/**
24-
* @author Gianlu
24+
* @author devgianlu
2525
*/
26-
public interface GeneralAudioStream {
26+
public interface DecodedAudioStream {
2727
@NotNull
2828
AbsChunkedInputStream stream();
2929

lib/src/main/java/xyz/gianlu/librespot/audio/PlayableContentFeeder.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private LoadedStream loadEpisode(@NotNull EpisodeId id, @NotNull AudioQualityPic
183183
}
184184
}
185185

186-
private static class FileAudioStream implements GeneralAudioStream {
186+
private static class FileAudioStream implements DecodedAudioStream {
187187
private static final Logger LOGGER = LoggerFactory.getLogger(FileAudioStream.class);
188188
private final File file;
189189
private final RandomAccessFile raf;
@@ -276,25 +276,25 @@ public int decryptTimeMs() {
276276

277277
public static class LoadedStream {
278278
public final MetadataWrapper metadata;
279-
public final GeneralAudioStream in;
279+
public final DecodedAudioStream in;
280280
public final NormalizationData normalizationData;
281281
public final Metrics metrics;
282282

283-
public LoadedStream(@NotNull Metadata.Track track, @NotNull GeneralAudioStream in, @Nullable NormalizationData normalizationData, @NotNull Metrics metrics) {
283+
public LoadedStream(@NotNull Metadata.Track track, @NotNull DecodedAudioStream in, @Nullable NormalizationData normalizationData, @NotNull Metrics metrics) {
284284
this.metadata = new MetadataWrapper(track, null, null);
285285
this.in = in;
286286
this.normalizationData = normalizationData;
287287
this.metrics = metrics;
288288
}
289289

290-
public LoadedStream(@NotNull Metadata.Episode episode, @NotNull GeneralAudioStream in, @Nullable NormalizationData normalizationData, @NotNull Metrics metrics) {
290+
public LoadedStream(@NotNull Metadata.Episode episode, @NotNull DecodedAudioStream in, @Nullable NormalizationData normalizationData, @NotNull Metrics metrics) {
291291
this.metadata = new MetadataWrapper(null, episode, null);
292292
this.in = in;
293293
this.normalizationData = normalizationData;
294294
this.metrics = metrics;
295295
}
296296

297-
private LoadedStream(@NotNull LocalId id, @NotNull GeneralAudioStream in) {
297+
private LoadedStream(@NotNull LocalId id, @NotNull DecodedAudioStream in) {
298298
this.metadata = new MetadataWrapper(null, null, id);
299299
this.in = in;
300300
this.normalizationData = null;

0 commit comments

Comments
 (0)