diff --git a/packages/addons/service/librespot/changelog.txt b/packages/addons/service/librespot/changelog.txt index cf0f35e799..c700ceeac6 100644 --- a/packages/addons/service/librespot/changelog.txt +++ b/packages/addons/service/librespot/changelog.txt @@ -1,3 +1,7 @@ +121 +- Update to 66f8a98 (2020-02-26) +- Gapless playback + 120 - Update to 0.1.1 diff --git a/packages/addons/service/librespot/package.mk b/packages/addons/service/librespot/package.mk index 30bcef742c..a236cfc85d 100644 --- a/packages/addons/service/librespot/package.mk +++ b/packages/addons/service/librespot/package.mk @@ -3,13 +3,14 @@ # Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) PKG_NAME="librespot" -PKG_VERSION="0.1.1" -PKG_SHA256="b4b5a3ebdb81784be8059615db7665a6dd736a9df94462acfb7b748e77c4e4c7" -PKG_REV="120" +PKG_VERSION="66f8a98ad2f5bf35be4daecd788dad6f0d87fb7c" +PKG_SHA256="b027c983341aa53d940412d5624cfe91392958ea9836ba597289680a4430b253" +PKG_VERSION_DATE="2020-02-26" +PKG_REV="121" PKG_ARCH="any" PKG_LICENSE="MIT" PKG_SITE="https://github.com/librespot-org/librespot/" -PKG_URL="https://github.com/librespot-org/librespot/archive/v$PKG_VERSION.tar.gz" +PKG_URL="https://github.com/librespot-org/librespot/archive/$PKG_VERSION.tar.gz" PKG_DEPENDS_TARGET="toolchain alsa-lib libvorbis pulseaudio rust" PKG_SECTION="service" PKG_SHORTDESC="Librespot: play Spotify through Kodi using a Spotify app as a remote" diff --git a/packages/addons/service/librespot/patches/librespot-01_notify_kodi.patch b/packages/addons/service/librespot/patches/librespot-01_notify_kodi.patch index 0afb08bf2e..c310c058db 100644 --- a/packages/addons/service/librespot/patches/librespot-01_notify_kodi.patch +++ b/packages/addons/service/librespot/patches/librespot-01_notify_kodi.patch @@ -1,11 +1,11 @@ -commit 6a9b509f4f85427f6392c08fc642afb9fc7bb8f2 +commit 0623a601115f5c62d2b30645a85d9496546d5cba Author: awiouy Date: Tue Dec 3 23:21:35 2019 +0100 Notify Kodi diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs -index e6f0cdd..03f8912 100644 +index 1a5fcd2..c670977 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -8,6 +8,12 @@ pub enum SpotifyAudioType { @@ -42,10 +42,10 @@ index 0f71110..931167d 100644 } } diff --git a/playback/src/player.rs b/playback/src/player.rs -index a54a577..4e006ab 100644 +index ef7484c..5b56782 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs -@@ -5,7 +5,8 @@ use futures::{future, Future}; +@@ -4,7 +4,8 @@ use futures::{future, Async, Future, Poll, Stream}; use std; use std::borrow::Cow; use std::cmp::max; @@ -53,97 +53,44 @@ index a54a577..4e006ab 100644 +use std::fs::OpenOptions; +use std::io::{Read, Result, Seek, SeekFrom, Write}; use std::mem; - use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; use std::thread; -@@ -427,6 +428,14 @@ impl PlayerInternal { + use std::time::{Duration, Instant}; +@@ -1415,6 +1416,12 @@ impl PlayerInternal { } } -+ fn notify_kodi(&mut self, id: &str, track_id: &SpotifyId) { -+ // println!("fifo = {} {}", id, track_id.to_base62()); -+ if self.config.notify_kodi { -+ let mut file = OpenOptions::new().write(true).open("/tmp/librespot").unwrap(); -+ writeln!(&mut file, "{}\n{} {}", id, track_id.audio_type.to_string(), track_id.to_base62()).unwrap(); -+ } ++ fn notify_kodi(&mut self, event: String) { ++ // println!("Librespot fifo = {}", event); ++ let mut file = OpenOptions::new().write(true).open("/tmp/librespot").unwrap(); ++ writeln!(&mut file, "{}", event).unwrap(); + } + - fn handle_command(&mut self, cmd: PlayerCommand) { - debug!("command={:?}", cmd); - match cmd { -@@ -451,11 +460,17 @@ impl PlayerInternal { - | PlayerState::EndOfTrack { - track_id: old_track_id, - .. -- } => self.send_event(PlayerEvent::Changed { -- old_track_id: old_track_id, -- new_track_id: track_id, -- }), -- _ => self.send_event(PlayerEvent::Started { track_id }), -+ } => { -+ self.send_event(PlayerEvent::Changed { -+ old_track_id: old_track_id, -+ new_track_id: track_id, -+ }); -+ self.notify_kodi("1", &track_id) -+ } -+ _ => { -+ self.send_event(PlayerEvent::Started { track_id }); -+ self.notify_kodi("2", &track_id) -+ } - } - - self.start_sink(); -@@ -485,13 +500,17 @@ impl PlayerInternal { - | PlayerState::EndOfTrack { - track_id: old_track_id, - .. -- } => self.send_event(PlayerEvent::Changed { -- old_track_id: old_track_id, -- new_track_id: track_id, -- }), -+ } => { -+ self.send_event(PlayerEvent::Changed { -+ old_track_id: old_track_id, -+ new_track_id: track_id, -+ }); -+ self.notify_kodi("3", &track_id) -+ } - _ => (), - } - self.send_event(PlayerEvent::Stopped { track_id }); -+ self.notify_kodi("4", &track_id) - } - } - -@@ -547,6 +566,7 @@ impl PlayerInternal { - - self.send_event(PlayerEvent::Started { track_id }); - self.start_sink(); -+ self.notify_kodi("5", &track_id) - } else { - warn!("Player::play called from invalid state"); + fn send_event(&mut self, event: PlayerEvent) { + let mut index = 0; + while index < self.event_senders.len() { +@@ -1425,6 +1432,17 @@ impl PlayerInternal { } -@@ -558,6 +578,7 @@ impl PlayerInternal { + } + } ++ if self.config.notify_kodi { ++ use PlayerEvent::*; ++ match event { ++ Paused { .. } => self.notify_kodi("Paused".to_string()), ++ Playing {track_id, .. } => self.notify_kodi(["Playing", ++ &track_id.audio_type.to_string(), ++ &track_id.to_base62()].join(" ")), ++ Stopped { .. } => self.notify_kodi("Stopped".to_string()), ++ _ => () ++ } ++ } + } - self.stop_sink_if_running(); - self.send_event(PlayerEvent::Stopped { track_id }); -+ self.notify_kodi("6", &track_id) - } else { - warn!("Player::pause called from invalid state"); - } -@@ -570,6 +591,7 @@ impl PlayerInternal { - self.stop_sink_if_running(); - self.send_event(PlayerEvent::Stopped { track_id }); - self.state = PlayerState::Stopped; -+ self.notify_kodi("7", &track_id) - } - PlayerState::Stopped => { - warn!("Player::stop called from invalid state"); + fn load_track( diff --git a/src/main.rs b/src/main.rs -index e3718fb..a480480 100644 +index 70a2dff..3e63308 100644 --- a/src/main.rs +++ b/src/main.rs -@@ -184,6 +184,11 @@ fn setup(args: &[String]) -> Setup { +@@ -171,6 +171,11 @@ fn setup(args: &[String]) -> Setup { "Pregain (dB) applied by volume normalisation", "PREGAIN", ) @@ -155,7 +102,7 @@ index e3718fb..a480480 100644 .optflag( "", "linear-volume", -@@ -276,6 +281,8 @@ fn setup(args: &[String]) -> Setup { +@@ -277,6 +282,8 @@ fn setup(args: &[String]) -> Setup { ) }; @@ -164,7 +111,7 @@ index e3718fb..a480480 100644 let session_config = { let device_id = device_id(&name); -@@ -319,6 +326,7 @@ fn setup(args: &[String]) -> Setup { +@@ -320,6 +327,7 @@ fn setup(args: &[String]) -> Setup { .opt_str("normalisation-pregain") .map(|pregain| pregain.parse::().expect("Invalid pregain float value")) .unwrap_or(PlayerConfig::default().normalisation_pregain), diff --git a/packages/addons/service/librespot/patches/librespot-02_use_own_pulseaudio_sink.patch b/packages/addons/service/librespot/patches/librespot-02_use_own_pulseaudio_sink.patch index 5f8f899455..5614ef7c69 100644 --- a/packages/addons/service/librespot/patches/librespot-02_use_own_pulseaudio_sink.patch +++ b/packages/addons/service/librespot/patches/librespot-02_use_own_pulseaudio_sink.patch @@ -1,14 +1,14 @@ -commit 0f3141a0874566ce867139aeadbefdb076706baf +commit 88ba7c3ad879e784ce55714c2c834911b2573ce1 Author: awiouy Date: Tue Dec 3 23:22:55 2019 +0100 Use own pulseaudio sink diff --git a/playback/src/audio_backend/pulseaudio.rs b/playback/src/audio_backend/pulseaudio.rs -index 88f6280..702be66 100644 +index e844b0d..0320f65 100644 --- a/playback/src/audio_backend/pulseaudio.rs +++ b/playback/src/audio_backend/pulseaudio.rs -@@ -76,6 +76,7 @@ impl Open for PulseAudioSink { +@@ -80,6 +80,7 @@ impl Open for PulseAudioSink { impl Sink for PulseAudioSink { fn start(&mut self) -> io::Result<()> { @@ -16,7 +16,7 @@ index 88f6280..702be66 100644 if self.s == null_mut() { self.s = call_pulseaudio( |err| unsafe { -@@ -83,7 +84,7 @@ impl Sink for PulseAudioSink { +@@ -87,7 +88,7 @@ impl Sink for PulseAudioSink { null(), // Use the default server. self.name.as_ptr(), // Our application's name. PA_STREAM_PLAYBACK, diff --git a/packages/addons/service/librespot/source/default.py b/packages/addons/service/librespot/source/default.py index d984f53c80..dfc9e3615d 100644 --- a/packages/addons/service/librespot/source/default.py +++ b/packages/addons/service/librespot/source/default.py @@ -49,6 +49,7 @@ class Player(threading.Thread, xbmc.Player): def __init__(self): log('player started') super(Player, self).__init__() + self.aborted = False self.isLibrespotStarted = True self.listitem = xbmcgui.ListItem() self.listitem.addStreamInfo('audio', {'codec': STREAM_CODEC}) @@ -63,6 +64,7 @@ class Player(threading.Thread, xbmc.Player): def abort(self): log('aborting player') + self.aborted = True with open(FIFO, 'w') as fifo: fifo.close() self.join() @@ -96,8 +98,7 @@ class Player(threading.Thread, xbmc.Player): log('pausing librespot playback') self.pause() - def playLibrespot(self, spotify_id): - type, id = spotify_id.split() + def playLibrespot(self, type, id): info = self.spotify.getInfo(type, id) self.listitem.setArt(info.getArt()) self.listitem.setInfo('music', info.getInfo()) @@ -115,19 +116,20 @@ class Player(threading.Thread, xbmc.Player): os.unlink(FIFO) except OSError: pass - os.mkfifo(FIFO) - while (os.path.exists(FIFO) and - stat.S_ISFIFO(os.stat(FIFO).st_mode)): + while not self.aborted: + if not os.path.exists(FIFO): + os.mkfifo(FIFO) with open(FIFO, 'r') as fifo: - command = fifo.read().splitlines() - log('control pipe {}'.format(str(command))) - if len(command) == 0: - break - elif command[0] in ['3', '5', '6']: + command = fifo.readline() + log('control pipe {}'.format(command)) + if command == '': + continue + command = command.split() + if command[0] in ['Paused']: self.pauseLibrespot() - elif command[0] in ['1', '2', '4']: - self.playLibrespot(command[1]) - elif command[0] in ['7']: + elif command[0] in ['Playing']: + self.playLibrespot(command[1], command[2]) + elif command[0] in ['Stopped']: self.stopLibrespot() try: os.unlink(FIFO)