Skip to content

Commit 28a256e

Browse files
committed
Starting radio implementation
1 parent 147b1f0 commit 28a256e

5 files changed

Lines changed: 377 additions & 104 deletions

File tree

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

Lines changed: 100 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
import xyz.gianlu.librespot.common.Utils;
66
import xyz.gianlu.librespot.common.proto.Spirc;
77
import xyz.gianlu.librespot.core.Session;
8+
import xyz.gianlu.librespot.mercury.model.TrackId;
89
import xyz.gianlu.librespot.spirc.FrameListener;
910
import xyz.gianlu.librespot.spirc.SpotifyIrc;
1011

1112
import java.io.IOException;
12-
import java.util.*;
1313

1414
/**
1515
* @author Gianlu
@@ -18,18 +18,18 @@ public class Player implements FrameListener, TrackHandler.Listener {
1818
private static final Logger LOGGER = Logger.getLogger(Player.class);
1919
private final Session session;
2020
private final SpotifyIrc spirc;
21-
private final Spirc.State.Builder state;
21+
private final StateWrapper state;
2222
private final PlayerConfiguration conf;
2323
private final CacheManager cacheManager;
24+
private TracksProvider tracksProvider;
2425
private TrackHandler trackHandler;
2526
private TrackHandler preloadTrackHandler;
26-
private long shuffleSeed = 0;
2727

2828
public Player(@NotNull PlayerConfiguration conf, @NotNull CacheManager.CacheConfiguration cacheConfiguration, @NotNull Session session) {
2929
this.conf = conf;
3030
this.session = session;
3131
this.spirc = session.spirc();
32-
this.state = initState();
32+
this.state = new StateWrapper(initState());
3333

3434
try {
3535
this.cacheManager = new CacheManager(cacheConfiguration);
@@ -40,16 +40,6 @@ public Player(@NotNull PlayerConfiguration conf, @NotNull CacheManager.CacheConf
4040
spirc.addListener(this);
4141
}
4242

43-
private static int[] getShuffleExchanges(int size, long seed) {
44-
int[] exchanges = new int[size - 1];
45-
Random rand = new Random(seed);
46-
for (int i = size - 1; i > 0; i--) {
47-
int n = rand.nextInt(i + 1);
48-
exchanges[size - 1 - i] = n;
49-
}
50-
return exchanges;
51-
}
52-
5343
public void playPause() {
5444
handlePlayPause();
5545
}
@@ -137,8 +127,8 @@ public void frame(@NotNull Spirc.Frame frame) {
137127
}
138128

139129
private void handlePlayPause() {
140-
if (state.getStatus() == Spirc.PlayStatus.kPlayStatusPlay) handlePause();
141-
else if (state.getStatus() == Spirc.PlayStatus.kPlayStatusPause) handlePlay();
130+
if (state.isStatus(Spirc.PlayStatus.kPlayStatusPlay)) handlePause();
131+
else if (state.isStatus(Spirc.PlayStatus.kPlayStatusPause)) handlePlay();
142132
}
143133

144134
private void handleSetVolume(int volume) {
@@ -169,58 +159,34 @@ private void handleVolumeUp() {
169159
}
170160

171161
private void stateUpdated() {
172-
spirc.deviceStateUpdated(state);
162+
spirc.deviceStateUpdated(state.state);
173163
}
174164

175165
private int getPosition() {
176166
int diff = (int) (System.currentTimeMillis() - state.getPositionMeasuredAt());
177167
return state.getPositionMs() + diff;
178168
}
179169

180-
private void shuffleTracks() {
181-
shuffleSeed = session.random().nextLong();
182-
183-
List<Spirc.TrackRef> tracks = new ArrayList<>(state.getTrackList());
184-
if (state.getPlayingTrackIndex() != 0) {
185-
Collections.swap(tracks, 0, state.getPlayingTrackIndex());
186-
state.setPlayingTrackIndex(0);
187-
}
188-
189-
int size = tracks.size() - 1;
190-
int[] exchanges = getShuffleExchanges(size, shuffleSeed);
191-
for (int i = size - 1; i > 1; i--) {
192-
int n = exchanges[size - 1 - i];
193-
Collections.swap(tracks, i, n + 1);
194-
}
195-
196-
state.clearTrack();
197-
state.addAllTrack(tracks);
198-
}
199-
200-
private void unshuffleTracks() {
201-
List<Spirc.TrackRef> tracks = new ArrayList<>(state.getTrackList());
202-
if (state.getPlayingTrackIndex() != 0) {
203-
Collections.swap(tracks, 0, state.getPlayingTrackIndex());
204-
state.setPlayingTrackIndex(0);
205-
}
206-
207-
int size = tracks.size() - 1;
208-
int[] exchanges = getShuffleExchanges(size, shuffleSeed);
209-
for (int i = 2; i < size; i++) {
210-
int n = exchanges[size - i - 1];
211-
Collections.swap(tracks, i, n + 1);
212-
}
213-
214-
state.clearTrack();
215-
state.addAllTrack(tracks);
216-
}
217-
218170
private void handleShuffle() {
219171
if (state.getShuffle()) shuffleTracks();
220172
else unshuffleTracks();
221173
stateUpdated();
222174
}
223175

176+
private void shuffleTracks() {
177+
if (tracksProvider instanceof PlaylistProvider)
178+
((PlaylistProvider) tracksProvider).shuffleTracks(session.random());
179+
else
180+
LOGGER.warn("Cannot shuffle TracksProvider: " + tracksProvider);
181+
}
182+
183+
private void unshuffleTracks() {
184+
if (tracksProvider instanceof PlaylistProvider)
185+
((PlaylistProvider) tracksProvider).unshuffleTracks();
186+
else
187+
LOGGER.warn("Cannot unshuffle TracksProvider: " + tracksProvider);
188+
}
189+
224190
private void handleSeek(int pos) {
225191
state.setPositionMs(pos);
226192
state.setPositionMeasuredAt(System.currentTimeMillis());
@@ -229,10 +195,12 @@ private void handleSeek(int pos) {
229195
}
230196

231197
private void updatedTracks(@NotNull Spirc.Frame frame) {
232-
state.setPlayingTrackIndex(frame.getState().getPlayingTrackIndex());
233-
state.clearTrack();
234-
state.addAllTrack(frame.getState().getTrackList());
235-
state.setContextUri(frame.getState().getContextUri());
198+
state.update(frame);
199+
String context = frame.getState().getContextUri();
200+
201+
if (context.startsWith("spotify:station:")) tracksProvider = new StationProvider(session, state.state, frame);
202+
else tracksProvider = new PlaylistProvider(state.state, frame);
203+
236204
state.setRepeat(frame.getState().getRepeat());
237205
state.setShuffle(frame.getState().getShuffle());
238206
if (state.getShuffle()) shuffleTracks();
@@ -272,7 +240,7 @@ public void endOfTrack(@NotNull TrackHandler handler) {
272240
@Override
273241
public void preloadNextTrack(@NotNull TrackHandler handler) {
274242
if (handler == trackHandler) {
275-
Spirc.TrackRef next = state.getTrack(getQueuedTrack(false));
243+
TrackId next = tracksProvider.getTrackAt(tracksProvider.getNextTrackIndex(false));
276244

277245
preloadTrackHandler = new TrackHandler(session, cacheManager, conf, this);
278246
preloadTrackHandler.sendLoad(next, false, 0);
@@ -304,14 +272,14 @@ private void handleLoad(@NotNull Spirc.Frame frame) {
304272
private void loadTrack(boolean play) {
305273
if (trackHandler != null) trackHandler.close();
306274

307-
Spirc.TrackRef ref = state.getTrack(state.getPlayingTrackIndex());
308-
if (preloadTrackHandler != null && preloadTrackHandler.isTrack(ref)) {
275+
TrackId id = tracksProvider.getCurrentTrack();
276+
if (preloadTrackHandler != null && preloadTrackHandler.isTrack(id)) {
309277
trackHandler = preloadTrackHandler;
310278
preloadTrackHandler = null;
311279
trackHandler.sendSeek(state.getPositionMs());
312280
} else {
313281
trackHandler = new TrackHandler(session, cacheManager, conf, this);
314-
trackHandler.sendLoad(ref, play, state.getPositionMs());
282+
trackHandler.sendLoad(id, play, state.getPositionMs());
315283
state.setStatus(Spirc.PlayStatus.kPlayStatusLoading);
316284
}
317285

@@ -326,7 +294,7 @@ private void loadTrack(boolean play) {
326294
}
327295

328296
private void handlePlay() {
329-
if (state.getStatus() == Spirc.PlayStatus.kPlayStatusPause) {
297+
if (state.isStatus(Spirc.PlayStatus.kPlayStatusPause)) {
330298
if (trackHandler != null) trackHandler.sendPlay();
331299
state.setStatus(Spirc.PlayStatus.kPlayStatusPlay);
332300
state.setPositionMeasuredAt(System.currentTimeMillis());
@@ -335,7 +303,7 @@ private void handlePlay() {
335303
}
336304

337305
private void handlePause() {
338-
if (state.getStatus() == Spirc.PlayStatus.kPlayStatusPlay) {
306+
if (state.isStatus(Spirc.PlayStatus.kPlayStatusPlay)) {
339307
if (trackHandler != null) trackHandler.sendPause();
340308
state.setStatus(Spirc.PlayStatus.kPlayStatusPause);
341309

@@ -349,7 +317,7 @@ private void handlePause() {
349317
}
350318

351319
private void handleNext() {
352-
int newTrack = getQueuedTrack(true);
320+
int newTrack = tracksProvider.getNextTrackIndex(true);
353321
boolean play = true;
354322
if (newTrack >= state.getTrackCount()) {
355323
newTrack = 0;
@@ -365,26 +333,7 @@ private void handleNext() {
365333

366334
private void handlePrev() {
367335
if (getPosition() < 3000) {
368-
List<Spirc.TrackRef> queueTracks = new ArrayList<>();
369-
Iterator<Spirc.TrackRef> iter = state.getTrackList().iterator();
370-
while (iter.hasNext()) {
371-
Spirc.TrackRef track = iter.next();
372-
if (track.getQueued()) {
373-
queueTracks.add(track);
374-
iter.remove();
375-
}
376-
}
377-
378-
int current = state.getPlayingTrackIndex();
379-
int newIndex;
380-
if (current > 0) newIndex = current - 1;
381-
else if (state.getRepeat()) newIndex = state.getTrackCount() - 1;
382-
else newIndex = 0;
383-
384-
for (int i = 0; i < queueTracks.size(); i++)
385-
state.getTrackList().add(newIndex + 1 + i, queueTracks.get(i));
386-
387-
state.setPlayingTrackIndex(newIndex);
336+
state.setPlayingTrackIndex(tracksProvider.getPrevTrackIndex(true));
388337
state.setPositionMs(0);
389338
state.setPositionMeasuredAt(System.currentTimeMillis());
390339

@@ -397,16 +346,6 @@ private void handlePrev() {
397346
}
398347
}
399348

400-
private int getQueuedTrack(boolean consume) {
401-
int current = state.getPlayingTrackIndex();
402-
if (state.getTrack(current).getQueued()) {
403-
if (consume) state.removeTrack(current);
404-
return current;
405-
}
406-
407-
return current + 1;
408-
}
409-
410349
public interface PlayerConfiguration {
411350
@NotNull
412351
StreamFeeder.AudioQuality preferredQuality();
@@ -415,4 +354,69 @@ public interface PlayerConfiguration {
415354

416355
float normalisationPregain();
417356
}
357+
358+
private class StateWrapper {
359+
private final Spirc.State.Builder state;
360+
361+
StateWrapper(@NotNull Spirc.State.Builder state) {
362+
this.state = state;
363+
}
364+
365+
@NotNull
366+
Spirc.PlayStatus getStatus() {
367+
return state.getStatus();
368+
}
369+
370+
void setStatus(@NotNull Spirc.PlayStatus status) {
371+
state.setStatus(status);
372+
}
373+
374+
boolean isStatus(@NotNull Spirc.PlayStatus status) {
375+
return status == getStatus();
376+
}
377+
378+
boolean getShuffle() {
379+
return state.getShuffle();
380+
}
381+
382+
void setShuffle(boolean shuffle) {
383+
state.setShuffle(shuffle && (tracksProvider == null || tracksProvider.canShuffle()));
384+
}
385+
386+
void update(@NotNull Spirc.Frame frame) {
387+
state.setContextUri(frame.getState().getContextUri());
388+
}
389+
390+
long getPositionMeasuredAt() {
391+
return state.getPositionMeasuredAt();
392+
}
393+
394+
void setPositionMeasuredAt(long ms) {
395+
state.setPositionMeasuredAt(ms);
396+
}
397+
398+
int getPositionMs() {
399+
return state.getPositionMs();
400+
}
401+
402+
void setPositionMs(int pos) {
403+
state.setPositionMs(pos);
404+
}
405+
406+
boolean getRepeat() {
407+
return state.getRepeat();
408+
}
409+
410+
void setRepeat(boolean repeat) {
411+
state.setRepeat(repeat && (tracksProvider == null || tracksProvider.canRepeat()));
412+
}
413+
414+
void setPlayingTrackIndex(int i) {
415+
state.setPlayingTrackIndex(i);
416+
}
417+
418+
int getTrackCount() {
419+
return state.getTrackCount();
420+
}
421+
}
418422
}

0 commit comments

Comments
 (0)