diff --git a/packages/addons/service/librespot/changelog.txt b/packages/addons/service/librespot/changelog.txt index ffbebe8438..70d297ec79 100644 --- a/packages/addons/service/librespot/changelog.txt +++ b/packages/addons/service/librespot/changelog.txt @@ -1,2 +1,5 @@ +101 +- Enable streaming to Kodi + 100 - Initial addon diff --git a/packages/addons/service/librespot/package.mk b/packages/addons/service/librespot/package.mk index d954fe6880..4912b3c891 100644 --- a/packages/addons/service/librespot/package.mk +++ b/packages/addons/service/librespot/package.mk @@ -18,20 +18,21 @@ ################################################################################ PKG_NAME="librespot" -PKG_VERSION="2259188" -PKG_REV="100" +PKG_VERSION="67deb07" +PKG_REV="101" PKG_ARCH="any" -PKG_LICENSE="prop." +PKG_LICENSE="MIT" PKG_SITE="https://github.com/plietar/$PKG_NAME/" PKG_URL="https://github.com/plietar/$PKG_NAME/archive/$PKG_VERSION.zip" -PKG_DEPENDS_TARGET="toolchain avahi libvorbis pyalsaaudio rust" +PKG_DEPENDS_TARGET="toolchain avahi ffmpegx libvorbis pyalsaaudio rust" PKG_SECTION="service" -PKG_LONGDESC="Librespot ($PKG_VERSION) plays Spotify through LibreELEC using the opensource librespot library using a Spotify app as a remote." +PKG_SHORTDESC="Librespot: play Spotify through LibreELEC using a Spotify app as a remote" +PKG_LONGDESC="Librespot ($PKG_VERSION) plays Spotify through LibreELEC using the open source librespot library using a Spotify app as a remote." PKG_AUTORECONF="no" PKG_IS_ADDON="yes" PKG_ADDON_NAME="Librespot" -PKG_ADDON_TYPE="xbmc.service" +PKG_ADDON_TYPE="xbmc.service.library" PKG_MAINTAINER="Anton Voyl (awiouy)" configure_target() { @@ -43,6 +44,8 @@ configure_target() { make_target() { cd src $CARGO_BUILD --no-default-features --features "alsa-backend with-avahi" + cd "$PKG_BUILD/.$TARGET_NAME"/*/release + $STRIP librespot } makeinstall_target() { @@ -50,15 +53,16 @@ makeinstall_target() { } addon() { + mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID" + cp "$(get_build_dir pyalsaaudio)/.install_pkg/usr/lib/python2.7/site-packages/alsaaudio.so" \ + "$ADDON_BUILD/$PKG_ADDON_ID" + mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/bin" cp "$PKG_BUILD/.$TARGET_NAME"/*/release/librespot \ + "$(get_build_dir ffmpegx)/.install_pkg/usr/local/bin/ffmpegx" \ "$ADDON_BUILD/$PKG_ADDON_ID/bin" mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/lib" cp "$(get_build_dir avahi)/avahi-compat-libdns_sd/.libs/libdns_sd.so.1" \ "$ADDON_BUILD/$PKG_ADDON_ID/lib" - - mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/wizard" - cp "$(get_build_dir pyalsaaudio)/.install_pkg/usr/lib/python2.7/site-packages/alsaaudio.so" \ - "$ADDON_BUILD/$PKG_ADDON_ID/wizard/" } diff --git a/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch b/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch deleted file mode 100644 index 42502b0df3..0000000000 --- a/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 031cc0a420db9d3ae8dd3543d07ff8503bdc508d Mon Sep 17 00:00:00 2001 -From: Michael Herger -Date: Tue, 20 Jun 2017 12:31:55 +0200 -Subject: [PATCH] Add --disable-audio-cache startup parameter - -Disable caching of downloaded audio files at runtime. Comes in handy when running librespot on a small device with SD card or other small storage. ---- - src/audio_file.rs | 24 +++++++++++++----------- - src/main.rs | 2 ++ - src/session.rs | 2 ++ - 3 files changed, 17 insertions(+), 11 deletions(-) - -diff --git a/src/audio_file.rs b/src/audio_file.rs -index 369d5ca..d014ba2 100644 ---- a/src/audio_file.rs -+++ b/src/audio_file.rs -@@ -151,17 +151,19 @@ impl AudioFileManager { - complete_tx: Some(complete_tx), - }; - -- let session = self.session(); -- self.session().spawn(move |_| { -- complete_rx.map(move |mut file| { -- if let Some(cache) = session.cache() { -- cache.save_file(file_id, &mut file); -- debug!("File {} complete, saving to cache", file_id); -- } else { -- debug!("File {} complete", file_id); -- } -- }).or_else(|oneshot::Canceled| Ok(())) -- }); -+ if self.session().config().use_audio_cache { -+ let session = self.session(); -+ self.session().spawn(move |_| { -+ complete_rx.map(move |mut file| { -+ if let Some(cache) = session.cache() { -+ cache.save_file(file_id, &mut file); -+ debug!("File {} complete, saving to cache", file_id); -+ } else { -+ debug!("File {} complete", file_id); -+ } -+ }).or_else(|oneshot::Canceled| Ok(())) -+ }); -+ } - - AudioFileOpen::Streaming(open) - } -diff --git a/src/main.rs b/src/main.rs -index 38c57fd..8a31a44 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -86,6 +86,7 @@ struct Setup { - fn setup(args: &[String]) -> Setup { - let mut opts = getopts::Options::new(); - opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE") -+ .optflag("", "disable-audio-cache", "Disable caching of the audio data.") - .reqopt("n", "name", "Device name", "NAME") - .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE") - .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM") -@@ -152,6 +153,7 @@ fn setup(args: &[String]) -> Setup { - bitrate: bitrate, - onstart: matches.opt_str("onstart"), - onstop: matches.opt_str("onstop"), -+ use_audio_cache: !matches.opt_present("disable-audio-cache"), - }; - - let device = matches.opt_str("device"); -diff --git a/src/session.rs b/src/session.rs -index 86162bd..a5d397e 100644 ---- a/src/session.rs -+++ b/src/session.rs -@@ -49,6 +49,7 @@ pub struct Config { - pub bitrate: Bitrate, - pub onstart: Option, - pub onstop: Option, -+ pub use_audio_cache: bool, - } - - impl Default for Config { -@@ -60,6 +61,7 @@ impl Default for Config { - bitrate: Bitrate::Bitrate160, - onstart: None, - onstop: None, -+ use_audio_cache: true, - } - } - } diff --git a/packages/addons/service/librespot/source/wizard/wizard.py b/packages/addons/service/librespot/source/addon.py similarity index 68% rename from packages/addons/service/librespot/source/wizard/wizard.py rename to packages/addons/service/librespot/source/addon.py index 585a4b92dc..86a51cca4e 100644 --- a/packages/addons/service/librespot/source/wizard/wizard.py +++ b/packages/addons/service/librespot/source/addon.py @@ -16,24 +16,8 @@ # along with LibreELEC. If not, see . ################################################################################ -import alsaaudio as alsa -import xbmcaddon -import xbmcgui +from default import addon as addon + if __name__ == '__main__': - - addon = xbmcaddon.Addon('service.librespot') - dialog = xbmcgui.Dialog() - strings = addon.getLocalizedString - - while True: - pcms = alsa.pcms()[1:] - if len(pcms) == 0: - dialog.ok(strings(30211), strings(30212)) - break - pcmx = dialog.select(strings(30113), pcms) - if pcmx == -1: - break - pcm = pcms[pcmx] - addon.setSetting('ls_o', pcm) - break + addon() diff --git a/packages/addons/service/librespot/source/bin/librespot.start b/packages/addons/service/librespot/source/bin/librespot.start index 0d5aaed6b4..aefaa45f47 100755 --- a/packages/addons/service/librespot/source/bin/librespot.start +++ b/packages/addons/service/librespot/source/bin/librespot.start @@ -17,10 +17,6 @@ # along with LibreELEC. If not, see . ################################################################################ -. /etc/os-release -. /etc/profile -oe_setup_addon service.librespot - activate_card() { if [ -e "/proc/asound/$1" ]; then return @@ -39,62 +35,83 @@ activate_card() { esac } -if [ ! "$(cat /proc/asound/pcm 2> /dev/null)" ]; then - case "$LIBREELEC_ARCH" in - RPi*.arm) - activate_card "ALSA" +init_alsa() { + . /etc/os-release + + if [ ! "$(cat /proc/asound/pcm 2> /dev/null)" ]; then + case "$LIBREELEC_ARCH" in + RPi*.arm) + activate_card "ALSA" + ;; + *) + echo "Unable to activate an audio interface on $LIBREELEC_ARCH" + exit + ;; + esac + fi + + case "$ls_o" in + *:CARD=*) + card="${ls_o##*:CARD=}" + card="${card%%,*}" + activate_card "$card" + index="$(readlink /proc/asound/$card)" + index="${index##*card}" ;; + hw:*,*) + echo "The hw:d,s specification is unreliable, use device:CARD=card instead" + index="${ls_o##hw:}" + index="${index%%,*}" + card="card$index" + activate_card "$card" + ;; *) - echo "Unable to activate an audio interface on $LIBREELEC_ARCH" - exit + if [ -n "$ls_o" ]; then + echo "Unknown playback device specification $ls_o" + fi ;; esac -fi -case "$ls_o" in - *:CARD=*) - card="${ls_o##*:CARD=}" - card="${card%%,*}" - activate_card "$card" - index="$(readlink /proc/asound/$card)" - index="${index##*card}" - ;; - hw:*,*) - echo "The hw:d,s specification is unreliable, use device:CARD=card instead" - index="${ls_o##hw:}" - index="${index%%,*}" - card="card$index" - activate_card "$card" - ;; - *) - if [ -n "$ls_o" ]; then - echo "Unknown playback device specification $ls_o" - fi - ;; -esac + case "$LIBREELEC_ARCH" in + RPi*.arm) + [ "$(readlink /proc/asound/ALSA)" == "card$index" ] && [ "$pcm_3" ] && + amixer -c "$index" cset name="PCM Playback Route" "$pcm_3" + ;; + esac +} + + +. /etc/profile +oe_setup_addon service.librespot + +LIBRESPOT="librespot --cache \"$ADDON_HOME/cache\" + --disable-audio-cache \ + --name \"Librespot@$HOSTNAME\"" if [ -n "$ls_b" -a "$ls_b" != "-" ]; then - bitrate="--bitrate $ls_b" -fi - -if [ -n "$ls_o" ]; then - device="--device $ls_o" + LIBRESPOT="$LIBRESPOT --bitrate $ls_b" fi if [ -n "$ls_p" -a -n "$ls_u" ]; then - discovery="--disable-discovery --password $ls_p --username $ls_u" + LIBRESPOT="$LIBRESPOT --disable-discovery \ + --password \"$ls_p\" \ + --username \"$ls_u\"" fi -case "$LIBREELEC_ARCH" in - RPi*.arm) - [ "$(readlink /proc/asound/ALSA)" == "card$index" ] && [ "$pcm_3" ] && - amixer -c "$index" cset name="PCM Playback Route" "$pcm_3" - ;; -esac +if [ "$ls_O" == "Kodi" ]; then + LIBRESPOT="$LIBRESPOT --backend pipe \ + --onstart=\"kodi-send \ + --action=RunAddon(service.librespot)\" \ + | ffmpegx -hide_banner -loglevel warning \ + -avioflags direct -fflags nobuffer \ + -re -ac 2 -ar 44100 -channel_layout stereo -f s16le -i pipe: \ + -sdp_file \"$ADDON_HOME/librespot.sdp\" \ + -f rtp rtp://127.0.0.1:5555" +else + init_alsa + if [ -n "$ls_o" ]; then + LIBRESPOT="$LIBRESPOT --device \"$ls_o\"" + fi +fi -librespot $bitrate \ - --cache "$ADDON_HOME/cache" \ - $device \ - --disable-audio-cache \ - $discovery \ - --name "Librespot@$HOSTNAME" +eval $LIBRESPOT diff --git a/packages/addons/service/librespot/source/default.py b/packages/addons/service/librespot/source/default.py index 1388ab8636..149b4a2169 100644 --- a/packages/addons/service/librespot/source/default.py +++ b/packages/addons/service/librespot/source/default.py @@ -16,20 +16,91 @@ # along with LibreELEC. If not, see . ################################################################################ +import alsaaudio as alsa +import os import subprocess +import sys import xbmc import xbmcaddon +import xbmcgui + + +ICON = xbmcaddon.Addon().getAddonInfo('icon') +ID = xbmcaddon.Addon().getAddonInfo('id') +NAME = xbmcaddon.Addon().getAddonInfo('name') +PROFILE = xbmcaddon.Addon().getAddonInfo('profile') +STRINGS = xbmcaddon.Addon().getLocalizedString + +ITEM = os.path.join(PROFILE, 'librespot.sdp') +LISTITEM = xbmcgui.ListItem(NAME) +LISTITEM.setArt({'thumb': ICON}) + + +def addon(): + if len(sys.argv) == 1: + Player().play() + elif sys.argv[1] == 'wizard': + dialog = xbmcgui.Dialog() + while True: + pcms = alsa.pcms()[1:] + if len(pcms) == 0: + dialog.ok(NAME, STRINGS(30210)) + break + pcmx = dialog.select(STRINGS(30112), pcms) + if pcmx == -1: + break + pcm = pcms[pcmx] + xbmcaddon.Addon().setSetting('ls_o', pcm) + break + + +def systemctl(command): + subprocess.call(['systemctl', command, ID]) class Monitor(xbmc.Monitor): def __init__(self, *args, **kwargs): - xbmc.Monitor.__init__(self) - self.id = xbmcaddon.Addon().getAddonInfo('id') + super(Monitor, self).__init__(self) + self.player = Player() def onSettingsChanged(self): - subprocess.call(['systemctl', 'restart', self.id]) + self.player.stop() +class Player(xbmc.Player): + + def __init__(self, *args, **kwargs): + super(Player, self).__init__(self) + if self.isPlaying(): + self.onPlayBackStarted() + + def onPlayBackEnded(self): + if not self.islibrespot: + xbmc.sleep(5000) + if not self.isPlaying(): + systemctl('start') + + def onPlayBackStarted(self): + if self.getPlayingFile() == ITEM: + self.islibrespot = True + else: + self.islibrespot = False + systemctl('stop') + + def onPlayBackStopped(self): + systemctl('restart') + + def play(self): + if not self.isPlaying(): + super(Player, self).play(ITEM, LISTITEM) + + def stop(self): + if self.isPlaying(): + if self.getPlayingFile() == ITEM: + super(Player, self).stop() + else: + systemctl('restart') + if __name__ == '__main__': Monitor().waitForAbort() diff --git a/packages/addons/service/librespot/source/resources/language/English/strings.po b/packages/addons/service/librespot/source/resources/language/English/strings.po index 02ec26527d..3b62e23c88 100644 --- a/packages/addons/service/librespot/source/resources/language/English/strings.po +++ b/packages/addons/service/librespot/source/resources/language/English/strings.po @@ -4,69 +4,73 @@ msgid "" msgstr "" msgctxt "#30100" -msgid "Configuration" +msgid "Librespot" msgstr "" msgctxt "#30101" -msgid "ALSA" -msgstr "" - -msgctxt "#30102" -msgid "Configuration wizard" -msgstr "" - -msgctxt "#30103" -msgid "Playback device" -msgstr "" - -msgctxt "#30104" -msgid "Playback route" -msgstr "" - -msgctxt "#30105" -msgid "auto detect" -msgstr "" - -msgctxt "#30106" -msgid "headphone jack" -msgstr "" - -msgctxt "#30107" -msgid "HDMI" -msgstr "" - -msgctxt "#30108" -msgid "Spotify" -msgstr "" - -msgctxt "#30109" -msgid "Username" -msgstr "" - -msgctxt "#30110" -msgid "Password" -msgstr "" - -msgctxt "#30111" -msgid "Discovery mode (set username and password to disable)" -msgstr "" - -msgctxt "#30112" msgid "Bit rate" msgstr "" -msgctxt "#30113" +msgctxt "#30102" msgid "-" msgstr "" -msgctxt "#30114" -msgid "90" +msgctxt "#30103" +msgid "96" msgstr "" -msgctxt "#30115" +msgctxt "#30104" msgid "160" msgstr "" -msgctxt "#30116" +msgctxt "#30105" msgid "320" msgstr "" + +msgctxt "#30106" +msgid "Output" +msgstr "" + +msgctxt "#30107" +msgid "Username" +msgstr "" + +msgctxt "#30108" +msgid "Password" +msgstr "" + +msgctxt "#30109" +msgid "Discovery mode (set username and password to disable)" +msgstr "" + +msgctxt "#30110" +msgid "ALSA" +msgstr "" + +msgctxt "#30111" +msgid "Configuration wizard" +msgstr "" + +msgctxt "#30112" +msgid "Playback device" +msgstr "" + +msgctxt "#30113" +msgid "Playback route" +msgstr "" + +msgctxt "#30114" +msgid "auto detect" +msgstr "" + +msgctxt "#30115" +msgid "headphone jack" +msgstr "" + +msgctxt "#30116" +msgid "HDMI" +msgstr "" + +msgctxt "#30210" +msgid "Could not find a playback device" +msgstr "" diff --git a/packages/addons/service/librespot/source/resources/settings.xml b/packages/addons/service/librespot/source/resources/settings.xml index 7292787476..bc502031c0 100644 --- a/packages/addons/service/librespot/source/resources/settings.xml +++ b/packages/addons/service/librespot/source/resources/settings.xml @@ -1,14 +1,17 @@ - - - - - - - - - + + + + + + + + + + + +