mirror of
https://github.com/librespot-org/librespot.git
synced 2026-04-27 08:15:50 +03:00
[GH-ISSUE #21] Preload next track when approaching the end of current one & gapless playback support #12
Labels
No labels
A-Alsa
SpotifyAPI
Tokio 1.0
audio
bug
can't reproduce
compilation
dependencies
duplicate
enhancement
good first issue
help wanted
high priority
imported
imported
invalid
new api
pull-request
question
reverse engineering
wiki
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/librespot#12
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @sashahilton00 on GitHub (Jan 29, 2018).
Original GitHub issue: https://github.com/librespot-org/librespot/issues/21
Wednesday Dec 30, 2015 at 12:01 GMT
Originally opened as https://github.com/plietar/librespot/issues/18
Currently we don't start loading the next track until the current one has completed. This causes a short delay between tracks.
Instead the next track should start loading before that.
@sashahilton00 commented on GitHub (Jan 29, 2018):
Saturday Jan 02, 2016 at 10:11 GMT
Maybe with (optional) crossfading, if possible
@sashahilton00 commented on GitHub (Jan 29, 2018):
Friday Nov 11, 2016 at 19:00 GMT
Crossfading and gapless playback are two different things. In HW spotify connect gear, gapless is standard.
@sashahilton00 commented on GitHub (Jan 29, 2018):
Friday Jan 20, 2017 at 21:54 GMT
Gapless is really a must for me, since most of what I listen to is either live or classical music, where much of the 'transitions' are mid-sound (specially in Opera, for instance).
Any time frame on this new feature? Thanks for all the hard work, best regards,
Rafa.
@sashahilton00 commented on GitHub (Jan 29, 2018):
Friday Jan 20, 2017 at 22:14 GMT
Gapless isn't too hard, and I'm working on a refactor which will also enable that. I can't give it an ETA, but probably somewhere within the next month.
Cross-fade is a lot trickier, and I don't have any immediate plans for it
@sashahilton00 commented on GitHub (Jan 29, 2018):
Tuesday Feb 14, 2017 at 08:12 GMT
+1 for gapless for me.
(Just for the record, no pressure, keep up the good work.)
@sashahilton00 commented on GitHub (Jan 29, 2018):
Wednesday May 31, 2017 at 18:35 GMT
+1 – would be great if this was implemented.
@sashahilton00 commented on GitHub (Jan 29, 2018):
Tuesday Jun 27, 2017 at 17:00 GMT
Any news on this? I'm eagerly awaiting for this and 6 months ago you said it wasn't hard. Was it more difficult than expected or this is simply not a priority for others? For me its critical. Please? Thanks.
@sashahilton00 commented on GitHub (Jan 29, 2018):
Tuesday Jun 27, 2017 at 18:18 GMT
Paul mentioned he was busy until July, most things have been put on hold till then. I'm sure it will be added in due course. Cross fade is harder due to the need to mix audio streams
@sashahilton00 commented on GitHub (Jan 29, 2018):
Tuesday Jun 27, 2017 at 19:14 GMT
Yeah, I wasn't talking about crossfading, just gapless playback for concerts, and classical pieces that flow seamlessly into the next movement (most critical in Opera).
@sashahilton00 commented on GitHub (Jan 29, 2018):
Friday Nov 17, 2017 at 14:37 GMT
Any progress on gapless playback? I still hear breaks between the tracks.
@sashahilton00 commented on GitHub (Mar 14, 2018):
With regards to this, one thing I have noticed, is that the loading of tracks is synchronous, hence if one is listening to a playlist and skips a few songs, it loads each of the skipped tracks, leading to a few seconds of silence. Ideally, when firing load_track, we'd dump any existing track load requests.
@RafaPolit commented on GitHub (Apr 2, 2018):
Please give some love to this issue. Most other issues can be accomplished by other means or extra steps. This is the one that is un-accomplishable, no matter how you see it.
It's the only thing still keeping me with other approaches.
Best regards,
Rafa.
@herrernst commented on GitHub (Apr 9, 2018):
Would also love to see somebody working on gapless playback (I don't care about crossfading). This is the last issue that make playback imperfect :/
@st0nec0ld commented on GitHub (May 8, 2018):
Anything new? The gap between two songs is realy annoying.
@WhiteHatTux commented on GitHub (May 12, 2018):
I started looking into it. As the main delay for me is with the network, the first step I see is to implement a PlayerCommand:PreLoad which will just make sure, that the file is available, when it will be requested for real. This part I have actually implemented.
Something, that I have not yet figured out is, how the PreLoad Command could be triggered. Something like: "end of track is 15 seconds away. Start Preload now".
@WhiteHatTux commented on GitHub (May 12, 2018):
@st0nec0ld Do you get the delay between every song, or only between songs, that are not yet cached?
@berrywhite96 commented on GitHub (May 15, 2018):
@WhiteHatTux I think it make sense to trigger the loading of the next song on every new track. So if a new track starts, load the next track. Also the RAM on the pi is big enough, see raspberry pi 3 b+, to handle this easily.
I personally skip often through tracks. In detail: hear the song for 3 seconds and then skip. These 3 seconds are enough (in my network) to load a track, so in this scenario there wouldnt be a gap.
This gap is really annoying, loading tracks needs maybe 1-2 seconds (in my network with 320kbps), but my av receiver dont get a signal for a second and needs then some time to recognize the codec of the audio stream, so the gap is longer than the track needs to load.
@github-ronk commented on GitHub (Jun 20, 2018):
+1 for this...
Thanks :)
@giggywithit commented on GitHub (Jun 27, 2018):
Vorbis is designed from the ground up to be used for streaming no?
MPD can do gapless playback and apparently buffers.
I know that it is also possible to playback a vorbis file as it is being created (downloaded)
Forget hacks of how to anticipate what the user is going to do.
@kingosticks commented on GitHub (Jun 27, 2018):
I think it's safe to implement gapless the same way everyone else in the world does it. i.e. buffer the output slightly. If you skip through tracks you'll have a small gap but that's fine - gapless here makes no sense at all.
Issues with external audio devices caused by 'stopping' the audio output are a separate issue.
@giggywithit commented on GitHub (Jun 27, 2018):
If I use the 'play *' command in a directory filled with files from a live album, the files are played back gaplessly. If I use the 'play *' command with one file in the directory and add one after I have executed the command, it will stop playback after playing the initial file, not seeing the next. It would seem apparent that one could implement an addition to the 'play' command to optionally seek another file during playback and adding it to its process. 'play' also has the capacity to playback files over http etc.. If this were the case, 'play' could be used to simply play files that are being loaded into a cache directory.
play is an audio player as part of the SOX project
@giggywithit commented on GitHub (Jul 8, 2018):
Hello Nick Steel
It seems that you have been around these places for some time and would be the person to ask the question...
What I am looking for, since there are no reliable spotify players for the raspberry pi and seems that it will be quite some time until one that works effectively, is the best method to stream audio to the raspberry pi from another computer on the network. I have an ubuntu laptop that I connect directly to the raspberry pi via the cat5 wired interface and share the internet connection that I get on the laptop with it. I like the idea of streaming pcm audio rather than compressing it. I like using raspian lite headless.. Minimal but full effectiveness preferred.
Can you offer a better solution?
Absolutely appreciated
@kingosticks commented on GitHub (Jul 8, 2018):
I think you'd be better off asking your question on the official raspberry pi forums. Hijacking this issue here with your unrelated question isn't helpful. Please don't do that.
@RafaPolit commented on GitHub (Aug 15, 2018):
Another month gone by, is this going anywhere? Or are the people in need of gapless just doomed to look elsewhere?
@jebos commented on GitHub (Oct 21, 2018):
was there any work on this? any updates?
@awiouy commented on GitHub (Oct 21, 2018):
@jebos No
@CooperWhitlow commented on GitHub (Oct 30, 2018):
+1 would be super awesome for crossfade
@laurensnl commented on GitHub (Nov 4, 2018):
+1 for gapless playback. Would be great!
@sashahilton00 commented on GitHub (Nov 5, 2018):
no work on this issue yet. I think most maintainers are busy with work or studies atm. PR's always welcome, otherwise I suspect this will remain in progress for a while longer. also, please use reactions to indicate support. any more +1 comments will be deleted.
@jebos commented on GitHub (Nov 6, 2018):
Though, in theory - what needs to be done (for gapless)?
Any suggestion on how to do this? Keeping the sink open (at least for some time) seems achiveable, I'm not sure about the buffering part, though (without large changes, at least)
@ashthespy commented on GitHub (Nov 6, 2018):
FWIW: I managed to implement a proof of concept of the preloading - but didn't find time to implement a buffer yet from the sink side.
What it does it implement a new channel that communicates "almost end of track" to
spricwhich triggers the prefetching of the next track provided byhandle_nextfromspirc. I can clean it up and push it if someone is interested in it.Keeping the sink open as it is now will lead to underruns in
alsaas there is no data to be played - we would need to implement a small buffer insideplayerthat is responsible to feed the sink.@sashahilton00 commented on GitHub (Nov 8, 2018):
@ashthespy by all means push it to a branch. i was just getting started on working out how to signal from player back to spirc, so if you have a PoC, that would save me a headache :)
@ashthespy commented on GitHub (Nov 8, 2018):
Here you go https://github.com/librespot-org/librespot/compare/master...ashthespy:gapless
It's not an optimised implementation in anyway but should work with the
lewton, and prefetch a track when there are 2 seconds left in the current track.@jebos commented on GitHub (Nov 9, 2018):
Hi, I think there should be a check that the current track duration is longer than 2 seconds (paranoid me) and maybe the amount of time should depend on the selected quality (assuming that higher qualtiy results in slower prefetch time)
What do you think about doing a procentual amount like 5% of duration and bounding that on 0 seconds (min) and 5 seconds. (max)
@plietar commented on GitHub (Nov 9, 2018):
IMO the best thing to do is start loading the next track as soon as the current one is fully cached. This may be a little complicated to implement for now, so a 2 second window sounds fine.
@ashthespy commented on GitHub (Nov 9, 2018):
I had initially set it to trigger when there was 20% remaining, but then switched to a hard-coded 2 seconds to test - but it might be a good idea to make this bitrate/file size dependent.
That would need another channel with the fetcher right?
Also - any ideas about the buffer implementation? I I put something together, but now trying to implement tracking the playback state independent of the buffer - need to look into if there is some way to queue the Vorbis decoder?
@sashahilton00 commented on GitHub (Nov 9, 2018):
If we want to keep behaviour consistent with the Spotify clients, I believe that they have hardcoded 30 seconds before the end of the track as the preload trigger for all bitrates/files.
With regards to keeping to sink open, how about implementing a feature flag such as
--disable-sink-keepalive, and then by default keep the sync open between songs unless that flag was present? If we preload things 30 seconds before the end of the track à la Spotify, there shouldn't be any delay in filling the buffer (causing an underrun), or if there is it should be <1s, at which point do we care? If it is an issue, one could just disable it for the current behaviour.This sounds potentially tricky from a logistics point of view. Let's say I play track 1. Track 2 is cached after a few seconds, then what? Does it cache Track 3, then 4, etc. or does it wait until Track 2 starts, then start caching Track 3? In the former case, if Spotify loads a large playlist or album, the cache is going to fill up quickly, which would potentially have to be managed through some sort of cache expiry mechanism mentioned in a previous issue (will add issue number later if I can find it), and in the latter case, why bother with the extra complexity of another channel and a buffer to preload a track at the beginning of a song? We could do that with minor modifications to @ashthespy's branch. Also, as an afterthought, for those on limited data plans (e.g. mobile broadband), librespot could use up a lot of bandwidth pointlessly loading tracks that end up not being played in the former case.
Also @ashthespy could you create a PR so that we can move discussion of implementation details over to that, review, commit, etc. Thanks.
@kingosticks commented on GitHub (Nov 9, 2018):
No. That's a different strategy and it's unnecessary.
Signalling at x seconds before end of track to start fetching the next song is fine. x can be really small, you only need to fetch enough to start playing, you do not need the entire song.
@ashthespy commented on GitHub (Nov 11, 2018):
I don't know about that - I tried something along these lines already (an option to keep the sink open b/w songs at https://github.com/librespot-org/librespot/compare/master...ashthespy:greedysink) but on my fruity pi systems, the time taken to fetch the next song, decrypt, and decode the audio (even from cache) leads to noticeable under runs from alsa.
#263 Sure, I might be pressed for time the next few weeks - so it might be slow progress!
@loeffelpan commented on GitHub (Dec 30, 2018):
Any progress here?
Is there a branch who could be built by someone for debian? Just for testing.
@devgianlu commented on GitHub (Dec 30, 2018):
@ashthespy is working on it here in Rust. I've implemented it in librespot-java.
@loeffelpan commented on GitHub (Jan 6, 2019):
@ashthespy Is your gapless branch ready to use?
I would give it a try to use is in my raspotify installation.
@ashthespy commented on GitHub (Jan 8, 2019):
@loeffelpan No, haven't had much time off late, prefetch is implemented, gapless needs some restructuring of the player (unless I am missing something).
My tentative approach is to have two audio buffers - on for the currently playing track, and another buffer where a few packets of the next track are decoded and kept ready for playback. That way the current playback state can be tracked independent of the packet decoder. If anyone has suggestions for alternatives - do share!
@loeffelpan commented on GitHub (Jan 8, 2019):
I don't have any suggestions. Just want to be up to date.
Sounds good. Do you have any plan to finish that project?
No pressure, but i'm very exited to try the result with my audiobooks hearing gapless! <3
@nkappler commented on GitHub (Mar 5, 2019):
Hi, any news on this already?
Would love it as well :)
Let me know if you need help with this, I might have a look at it aswell...
@loeffelpan commented on GitHub (Mar 5, 2019):
I switched to librespot-java.
Works flawlessly now after some issues.
@Identity9165 commented on GitHub (May 7, 2019):
I spent an hour with maven and it's not compiling. binaries don't help either. :(
@devgianlu commented on GitHub (May 7, 2019):
@msc1 You need to install Java, then download a precompiled binary and run
java -jar ./librespot-core-jar-with-dependencies.jar. Check the read me, you can contact me on Gitter if you still have problems.@Identity9165 commented on GitHub (May 7, 2019):
yes I have them installed already, I couldn't found a solution for the following error:
env: DietPi v6.22.3 (Debian 9) RPi 3 Model B (armv7l)
building with maven fails around api client
any help would be appreciated, thanks.
@devgianlu commented on GitHub (May 7, 2019):
Check https://github.com/librespot-org/librespot-java/issues/86#issuecomment-489096807
@Identity9165 commented on GitHub (May 7, 2019):
@devgianlu thanks for the tip, installing
openjfxsolved the issue. any tips for crossfading?@devgianlu commented on GitHub (May 7, 2019):
Crossfade isn't implemented yet. Open an issue on
librespot-java, I'll start to think about the implementation when I have time.@AInteriorB commented on GitHub (Nov 13, 2019):
Anything new on this topic? I use raspotify. If I skip to the next song, everything is smooth. But if I'm listening till the end of a song I hear a "click" in the pause to the next one.
@bendarlog commented on GitHub (Dec 5, 2019):
Hello, Any news about gapless feature ? It would be really nice, as actually I hear clicks (Amplifier's DAC disconnect/reconnect) at the change of each tracks as the flow is cut and restarted.
I think it would be a great feature for this project.
Many thanks for all your great work,
@nkappler commented on GitHub (Dec 5, 2019):
the click can be prevented by leaving the audio device attached.
This guide might help
https://learn.adafruit.com/adafruit-i2s-stereo-decoder-uda1334a/raspberry-pi-usage
We've added an extra helper systemd script that will play quiet audio when the I2S peripheral isn't in use. This removes popping when playback starts or stops. It uses a tiny amount of CPU time (on a Pi Zero, 5%, on a Pi 2 or 3 its negligible). You don't need this on RetroPie because it never releases the I2S device, but it's great for Raspbian.@AInteriorB commented on GitHub (Dec 5, 2019):
Thanks for your hint, but this breaks raspotify on Rasbian. I have no more sound on hdmi. Or is this workarount for the headphone jack?
Update: If you're just interested in removing the clicking noise between songs, it is sufficient to play a silent audio in the background so that the sound receiver doesn't detach.
aplay -D default -t raw -r 44100 -c 2 -f S16_LE /dev/zero@bendarlog commented on GitHub (Dec 12, 2019):
Thanks for the help but unfortunately this doesn’t start if raspotify is playing
aplay: main:788: audio open error: Device or resource busy@AInteriorB commented on GitHub (Dec 12, 2019):
Start it as a service before you start playing your music:
https://github.com/dtcooper/raspotify/issues/231
@paolo1983 commented on GitHub (Feb 22, 2020):
Is there a news? I tried LMS + squezelite: with the plugin called "Spotty" there isn't the gap issue. But I read that "spotty" use librespot... So, can you get a look?
@kaymes commented on GitHub (Feb 27, 2020):
Gapless playback has just been merged into dev (PR #430).
I think this issue can be closed now.