mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-28 13:16:41 +00:00
Merge pull request #4228 from awiouy/92-lsgl
librespot: gapless playback
This commit is contained in:
commit
8bc985b782
@ -1,3 +1,7 @@
|
|||||||
|
121
|
||||||
|
- Update to 66f8a98 (2020-02-26)
|
||||||
|
- Gapless playback
|
||||||
|
|
||||||
120
|
120
|
||||||
- Update to 0.1.1
|
- Update to 0.1.1
|
||||||
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||||
|
|
||||||
PKG_NAME="librespot"
|
PKG_NAME="librespot"
|
||||||
PKG_VERSION="0.1.1"
|
PKG_VERSION="66f8a98ad2f5bf35be4daecd788dad6f0d87fb7c"
|
||||||
PKG_SHA256="b4b5a3ebdb81784be8059615db7665a6dd736a9df94462acfb7b748e77c4e4c7"
|
PKG_SHA256="b027c983341aa53d940412d5624cfe91392958ea9836ba597289680a4430b253"
|
||||||
PKG_REV="120"
|
PKG_VERSION_DATE="2020-02-26"
|
||||||
|
PKG_REV="121"
|
||||||
PKG_ARCH="any"
|
PKG_ARCH="any"
|
||||||
PKG_LICENSE="MIT"
|
PKG_LICENSE="MIT"
|
||||||
PKG_SITE="https://github.com/librespot-org/librespot/"
|
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_DEPENDS_TARGET="toolchain alsa-lib libvorbis pulseaudio rust"
|
||||||
PKG_SECTION="service"
|
PKG_SECTION="service"
|
||||||
PKG_SHORTDESC="Librespot: play Spotify through Kodi using a Spotify app as a remote"
|
PKG_SHORTDESC="Librespot: play Spotify through Kodi using a Spotify app as a remote"
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
commit 6a9b509f4f85427f6392c08fc642afb9fc7bb8f2
|
commit 0623a601115f5c62d2b30645a85d9496546d5cba
|
||||||
Author: awiouy <awiouy@gmail.com>
|
Author: awiouy <awiouy@gmail.com>
|
||||||
Date: Tue Dec 3 23:21:35 2019 +0100
|
Date: Tue Dec 3 23:21:35 2019 +0100
|
||||||
|
|
||||||
Notify Kodi
|
Notify Kodi
|
||||||
|
|
||||||
diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs
|
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
|
--- a/core/src/spotify_id.rs
|
||||||
+++ b/core/src/spotify_id.rs
|
+++ b/core/src/spotify_id.rs
|
||||||
@@ -8,6 +8,12 @@ pub enum SpotifyAudioType {
|
@@ -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
|
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
|
--- a/playback/src/player.rs
|
||||||
+++ b/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;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
@ -53,97 +53,44 @@ index a54a577..4e006ab 100644
|
|||||||
+use std::fs::OpenOptions;
|
+use std::fs::OpenOptions;
|
||||||
+use std::io::{Read, Result, Seek, SeekFrom, Write};
|
+use std::io::{Read, Result, Seek, SeekFrom, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError};
|
|
||||||
use std::thread;
|
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) {
|
+ fn notify_kodi(&mut self, event: String) {
|
||||||
+ // println!("fifo = {} {}", id, track_id.to_base62());
|
+ // println!("Librespot fifo = {}", event);
|
||||||
+ if self.config.notify_kodi {
|
+ let mut file = OpenOptions::new().write(true).open("/tmp/librespot").unwrap();
|
||||||
+ let mut file = OpenOptions::new().write(true).open("/tmp/librespot").unwrap();
|
+ writeln!(&mut file, "{}", event).unwrap();
|
||||||
+ writeln!(&mut file, "{}\n{} {}", id, track_id.audio_type.to_string(), track_id.to_base62()).unwrap();
|
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
fn handle_command(&mut self, cmd: PlayerCommand) {
|
fn send_event(&mut self, event: PlayerEvent) {
|
||||||
debug!("command={:?}", cmd);
|
let mut index = 0;
|
||||||
match cmd {
|
while index < self.event_senders.len() {
|
||||||
@@ -451,11 +460,17 @@ impl PlayerInternal {
|
@@ -1425,6 +1432,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");
|
|
||||||
}
|
}
|
||||||
@@ -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();
|
fn load_track(
|
||||||
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");
|
|
||||||
diff --git a/src/main.rs b/src/main.rs
|
diff --git a/src/main.rs b/src/main.rs
|
||||||
index e3718fb..a480480 100644
|
index 70a2dff..3e63308 100644
|
||||||
--- a/src/main.rs
|
--- a/src/main.rs
|
||||||
+++ b/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 (dB) applied by volume normalisation",
|
||||||
"PREGAIN",
|
"PREGAIN",
|
||||||
)
|
)
|
||||||
@ -155,7 +102,7 @@ index e3718fb..a480480 100644
|
|||||||
.optflag(
|
.optflag(
|
||||||
"",
|
"",
|
||||||
"linear-volume",
|
"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 session_config = {
|
||||||
let device_id = device_id(&name);
|
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")
|
.opt_str("normalisation-pregain")
|
||||||
.map(|pregain| pregain.parse::<f32>().expect("Invalid pregain float value"))
|
.map(|pregain| pregain.parse::<f32>().expect("Invalid pregain float value"))
|
||||||
.unwrap_or(PlayerConfig::default().normalisation_pregain),
|
.unwrap_or(PlayerConfig::default().normalisation_pregain),
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
commit 0f3141a0874566ce867139aeadbefdb076706baf
|
commit 88ba7c3ad879e784ce55714c2c834911b2573ce1
|
||||||
Author: awiouy <awiouy@gmail.com>
|
Author: awiouy <awiouy@gmail.com>
|
||||||
Date: Tue Dec 3 23:22:55 2019 +0100
|
Date: Tue Dec 3 23:22:55 2019 +0100
|
||||||
|
|
||||||
Use own pulseaudio sink
|
Use own pulseaudio sink
|
||||||
|
|
||||||
diff --git a/playback/src/audio_backend/pulseaudio.rs b/playback/src/audio_backend/pulseaudio.rs
|
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
|
--- a/playback/src/audio_backend/pulseaudio.rs
|
||||||
+++ b/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 {
|
impl Sink for PulseAudioSink {
|
||||||
fn start(&mut self) -> io::Result<()> {
|
fn start(&mut self) -> io::Result<()> {
|
||||||
@ -16,7 +16,7 @@ index 88f6280..702be66 100644
|
|||||||
if self.s == null_mut() {
|
if self.s == null_mut() {
|
||||||
self.s = call_pulseaudio(
|
self.s = call_pulseaudio(
|
||||||
|err| unsafe {
|
|err| unsafe {
|
||||||
@@ -83,7 +84,7 @@ impl Sink for PulseAudioSink {
|
@@ -87,7 +88,7 @@ impl Sink for PulseAudioSink {
|
||||||
null(), // Use the default server.
|
null(), // Use the default server.
|
||||||
self.name.as_ptr(), // Our application's name.
|
self.name.as_ptr(), // Our application's name.
|
||||||
PA_STREAM_PLAYBACK,
|
PA_STREAM_PLAYBACK,
|
||||||
|
@ -49,6 +49,7 @@ class Player(threading.Thread, xbmc.Player):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
log('player started')
|
log('player started')
|
||||||
super(Player, self).__init__()
|
super(Player, self).__init__()
|
||||||
|
self.aborted = False
|
||||||
self.isLibrespotStarted = True
|
self.isLibrespotStarted = True
|
||||||
self.listitem = xbmcgui.ListItem()
|
self.listitem = xbmcgui.ListItem()
|
||||||
self.listitem.addStreamInfo('audio', {'codec': STREAM_CODEC})
|
self.listitem.addStreamInfo('audio', {'codec': STREAM_CODEC})
|
||||||
@ -63,6 +64,7 @@ class Player(threading.Thread, xbmc.Player):
|
|||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
log('aborting player')
|
log('aborting player')
|
||||||
|
self.aborted = True
|
||||||
with open(FIFO, 'w') as fifo:
|
with open(FIFO, 'w') as fifo:
|
||||||
fifo.close()
|
fifo.close()
|
||||||
self.join()
|
self.join()
|
||||||
@ -96,8 +98,7 @@ class Player(threading.Thread, xbmc.Player):
|
|||||||
log('pausing librespot playback')
|
log('pausing librespot playback')
|
||||||
self.pause()
|
self.pause()
|
||||||
|
|
||||||
def playLibrespot(self, spotify_id):
|
def playLibrespot(self, type, id):
|
||||||
type, id = spotify_id.split()
|
|
||||||
info = self.spotify.getInfo(type, id)
|
info = self.spotify.getInfo(type, id)
|
||||||
self.listitem.setArt(info.getArt())
|
self.listitem.setArt(info.getArt())
|
||||||
self.listitem.setInfo('music', info.getInfo())
|
self.listitem.setInfo('music', info.getInfo())
|
||||||
@ -115,19 +116,20 @@ class Player(threading.Thread, xbmc.Player):
|
|||||||
os.unlink(FIFO)
|
os.unlink(FIFO)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
os.mkfifo(FIFO)
|
while not self.aborted:
|
||||||
while (os.path.exists(FIFO) and
|
if not os.path.exists(FIFO):
|
||||||
stat.S_ISFIFO(os.stat(FIFO).st_mode)):
|
os.mkfifo(FIFO)
|
||||||
with open(FIFO, 'r') as fifo:
|
with open(FIFO, 'r') as fifo:
|
||||||
command = fifo.read().splitlines()
|
command = fifo.readline()
|
||||||
log('control pipe {}'.format(str(command)))
|
log('control pipe {}'.format(command))
|
||||||
if len(command) == 0:
|
if command == '':
|
||||||
break
|
continue
|
||||||
elif command[0] in ['3', '5', '6']:
|
command = command.split()
|
||||||
|
if command[0] in ['Paused']:
|
||||||
self.pauseLibrespot()
|
self.pauseLibrespot()
|
||||||
elif command[0] in ['1', '2', '4']:
|
elif command[0] in ['Playing']:
|
||||||
self.playLibrespot(command[1])
|
self.playLibrespot(command[1], command[2])
|
||||||
elif command[0] in ['7']:
|
elif command[0] in ['Stopped']:
|
||||||
self.stopLibrespot()
|
self.stopLibrespot()
|
||||||
try:
|
try:
|
||||||
os.unlink(FIFO)
|
os.unlink(FIFO)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user