mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2024-11-23 00:09:52 +00:00
Merge branch 'libreelec-11.0' of github.com:LibreELEC/LibreELEC.tv into Lakka-v5.x
This commit is contained in:
commit
cff38254a6
@ -3,7 +3,7 @@
|
||||
|
||||
PKG_NAME="cli"
|
||||
PKG_VERSION="$(get_pkg_version moby)"
|
||||
PKG_SHA256="bef4fc68b9f81ab2ae8bb2605e16a0965a3c4a82f0c0cf9d9f5d2cee8e95415d"
|
||||
PKG_SHA256="b31eb0343e8bb587e921a7630baa659896602072a77ad97720e5f2a8e48005e9"
|
||||
PKG_LICENSE="ASL"
|
||||
PKG_SITE="https://github.com/docker/cli"
|
||||
PKG_URL="https://github.com/docker/cli/archive/v${PKG_VERSION}.tar.gz"
|
||||
@ -12,7 +12,7 @@ PKG_LONGDESC="The Docker CLI"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
# Git commit of the matching release https://github.com/docker/cli/releases
|
||||
export PKG_GIT_COMMIT="569dd73db13099a7c3104d73aa15117b359045bc"
|
||||
export PKG_GIT_COMMIT="ef23cbc4315ae76c744e02d687c09548ede461bd"
|
||||
|
||||
configure_target() {
|
||||
go_configure
|
||||
|
@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="containerd"
|
||||
PKG_VERSION="1.7.0"
|
||||
PKG_SHA256="c80b1c7f04057108059fdec9c936fc1ec0dccafa45c00a1d54f14dceb6500552"
|
||||
PKG_VERSION="1.7.1"
|
||||
PKG_SHA256="fd844af82afda7242d8eba5e0086c5a0d54ddc3041c1bbdd4d3c62bfee844e3a"
|
||||
PKG_LICENSE="APL"
|
||||
PKG_SITE="https://containerd.io"
|
||||
PKG_URL="https://github.com/containerd/containerd/archive/v${PKG_VERSION}.tar.gz"
|
||||
@ -19,9 +19,9 @@ pre_make_target() {
|
||||
|
||||
go_configure
|
||||
|
||||
export CONTAINERD_VERSION=${PKG_VERSION}
|
||||
export CONTAINERD_REVISION=${PKG_GIT_COMMIT}
|
||||
export CONTAINERD_PKG=github.com/containerd/containerd
|
||||
export CONTAINERD_VERSION="${PKG_VERSION}"
|
||||
export CONTAINERD_REVISION="${PKG_GIT_COMMIT}"
|
||||
export CONTAINERD_PKG="github.com/containerd/containerd"
|
||||
export LDFLAGS="-w -extldflags -static -X ${CONTAINERD_PKG}/version.Version=${CONTAINERD_VERSION} -X ${CONTAINERD_PKG}/version.Revision=${CONTAINERD_REVISION} -X ${CONTAINERD_PKG}/version.Package=${CONTAINERD_PKG} -extld ${CC}"
|
||||
export GO111MODULE=off
|
||||
|
||||
|
32
packages/addons/addon-depends/docker/ctop/package.mk
Normal file
32
packages/addons/addon-depends/docker/ctop/package.mk
Normal file
@ -0,0 +1,32 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (C) 2023-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="ctop"
|
||||
PKG_VERSION="0.7.7"
|
||||
PKG_SHA256="0db439f2030af73ad5345884b08a33a762c3b41b30604223dd0ebddde72d2741"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://ctop.sh"
|
||||
PKG_URL="https://github.com/bcicen/ctop/archive/v${PKG_VERSION}.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain go:host"
|
||||
PKG_LONGDESC="Top-like interface for container metrics"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
# Git commit of the matching release https://github.com/bcicen/ctop/releases
|
||||
PKG_GIT_COMMIT="11a1cb10f416b4ca5e36c22c1acc2d11dbb24fb4"
|
||||
|
||||
pre_make_target() {
|
||||
go_configure
|
||||
|
||||
export CTOP_VERSION="${PKG_VERSION}"
|
||||
export CTOP_REVISION="${PKG_GIT_COMMIT}"
|
||||
export CTOP_PKG="github.com/bcicen/ctop"
|
||||
export LDFLAGS="-w -extldflags -static -X main.version=${CTOP_VERSION} -X main.build=${CTOP_REVISION} -extld ${CC}"
|
||||
|
||||
mkdir -p ${GOPATH}/src/github.com/bcicen
|
||||
ln -fs ${PKG_BUILD} ${GOPATH}/src/${CTOP_PKG}
|
||||
}
|
||||
|
||||
make_target() {
|
||||
mkdir -p bin
|
||||
${GOLANG} build -v -o bin/ctop -a -tags "static_build release" -ldflags "${LDFLAGS}"
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2022-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="moby"
|
||||
PKG_VERSION="23.0.2"
|
||||
PKG_SHA256="4caca59c774445a5aad6114d89c97c88d9705f048704fecdd3f5712cb369dc39"
|
||||
PKG_VERSION="23.0.6"
|
||||
PKG_SHA256="3bbd32f401f652cc15084d3c09bd7acd381571802beac9333fd63d803dc66c3e"
|
||||
PKG_LICENSE="ASL"
|
||||
PKG_SITE="https://mobyproject.org/"
|
||||
PKG_URL="https://github.com/moby/moby/archive/v${PKG_VERSION}.tar.gz"
|
||||
@ -12,7 +12,7 @@ PKG_LONGDESC="Moby is an open-source project created by Docker to enable and acc
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
# Git commit of the matching release https://github.com/moby/moby
|
||||
export PKG_GIT_COMMIT="219f21bf07502b447095649b5a2764661737f164"
|
||||
export PKG_GIT_COMMIT="9dbdbd4b6d7681bd18c897a6ba0376073c2a72ff"
|
||||
|
||||
PKG_MOBY_BUILDTAGS="daemon \
|
||||
autogen \
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Copyright (C) 2022-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="aspnet6-runtime"
|
||||
PKG_VERSION="6.0.15"
|
||||
PKG_VERSION="6.0.18"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://dotnet.microsoft.com/"
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
@ -11,16 +11,16 @@ PKG_TOOLCHAIN="manual"
|
||||
|
||||
case "${ARCH}" in
|
||||
"aarch64")
|
||||
PKG_SHA256="b37cf63d5962b2f67288a78b6541151c458bc9e67baaf5d5852b2214e858070b"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/0d9619a1-af06-40c6-9816-46d08c9e42d6/744ecc09a1058822dc08ae17a3dc9c77/aspnetcore-runtime-6.0.15-linux-arm64.tar.gz"
|
||||
PKG_SHA256="cae83353c508eb7766be43f6cae4e500569f3bcf8a1139e4e762c5b9f7dabbf1"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/f60912b4-b50d-4d85-b3aa-3b69504a426b/190ebc4012cd4da240e4d5247b484b15/aspnetcore-runtime-6.0.18-linux-arm64.tar.gz"
|
||||
;;
|
||||
"arm")
|
||||
PKG_SHA256="70afd74a6a070f629fcf44571582eec026442c4530f69afc142b92667542932c"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/c7eade0f-81ff-4587-a58e-647702814ec4/1b8c56efc82990ee986d8dd52a9a09ab/aspnetcore-runtime-6.0.15-linux-arm.tar.gz"
|
||||
PKG_SHA256="45d22a5ef4eb687648fdd4bf918e25f2fc9a63a0f84fa68a45a88ee6d44f204d"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/7b10cc0d-3627-4d1b-8307-630c05fb30be/06e4498eeb854db5a723b46114377fce/aspnetcore-runtime-6.0.18-linux-arm.tar.gz"
|
||||
;;
|
||||
"x86_64")
|
||||
PKG_SHA256="930b6254500e53a4f0d87b5551840a3ac8882e93797cf1e23da40652085d44dd"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/4518a0d8-9a6b-4836-ada9-096afa24efd0/ad0d8ccefb6b6a36dc108417b74775cb/aspnetcore-runtime-6.0.15-linux-x64.tar.gz"
|
||||
PKG_SHA256="8b7a6c4fc46887d1281f18558e76e34b1656ca1f487c3c71f63d3453a1f5c63b"
|
||||
PKG_URL="https://download.visualstudio.microsoft.com/download/pr/503c4325-104f-41e0-8dc6-1a8b55e0651a/3dcd8a5d03d3a04bb4111296b12cd11d/aspnetcore-runtime-6.0.18-linux-x64.tar.gz"
|
||||
;;
|
||||
esac
|
||||
PKG_SOURCE_NAME="aspnetcore-runtime_${PKG_VERSION}_${ARCH}.tar.gz"
|
||||
|
@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="runc"
|
||||
PKG_VERSION="1.1.5"
|
||||
PKG_SHA256="76cbf30637cbb828794d72d32fb3fd6ff3139cd9743b8b44790fd110f43d96b2"
|
||||
PKG_VERSION="1.1.7"
|
||||
PKG_SHA256="f1885d6dfa188f8112328ac2355e5d67346174a2e2e795ec514a972bcbfcc2fa"
|
||||
PKG_LICENSE="APL"
|
||||
PKG_SITE="https://github.com/opencontainers/runc"
|
||||
PKG_URL="https://github.com/opencontainers/runc/archive/v${PKG_VERSION}.tar.gz"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="asio"
|
||||
PKG_VERSION="1.27.0"
|
||||
PKG_SHA256="9bee8e50236ce7752325efde38cae223cbc85759ed49509d9cbc5d55458332d9"
|
||||
PKG_VERSION="1.28.0"
|
||||
PKG_SHA256="5c2af07ef73b42a2d48e34c0ecbf41cd40dc823bc681bf5833c129384999c963"
|
||||
PKG_LICENSE="BSL"
|
||||
PKG_SITE="http://think-async.com/Asio"
|
||||
PKG_URL="https://github.com/chriskohlhoff/asio/archive/asio-${PKG_VERSION//./-}.zip"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2022-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="nqptp"
|
||||
PKG_VERSION="c71b49a3556ba8547ee28482cb31a97fe99298aa"
|
||||
PKG_SHA256="02ed710ed37269adbede06fcd4e12892cc0f9d14d5c68b7f45d67b8694bff1e4"
|
||||
PKG_VERSION="1.2.1"
|
||||
PKG_SHA256="fab700572961ca81addb405e8bd4bd57c47259f91e7e8e0f5f82240c38c63ce5"
|
||||
PKG_LICENSE="GPL-2.0"
|
||||
PKG_SITE="https://github.com/mikebrady/nqptp"
|
||||
PKG_URL="https://github.com/mikebrady/nqptp/archive/${PKG_VERSION}.tar.gz"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="shairport-sync"
|
||||
PKG_VERSION="4.1.1"
|
||||
PKG_SHA256="e55caad73dcd36341baf8947cf5e0923997370366d6caf3dd917b345089c4a20"
|
||||
PKG_VERSION="4.2"
|
||||
PKG_SHA256="649d95eede8b9284b2e8b9c97d18c1c64cffae0a6c75bc4f03e3ae494a3e25b6"
|
||||
PKG_LICENSE="OSS"
|
||||
PKG_SITE="https://github.com/mikebrady/shairport-sync"
|
||||
PKG_URL="https://github.com/mikebrady/shairport-sync/archive/${PKG_VERSION}.tar.gz"
|
||||
|
@ -1 +1,17 @@
|
||||
initial release
|
||||
1
|
||||
- not released for LE11
|
||||
|
||||
2
|
||||
- not released for LE11
|
||||
|
||||
3
|
||||
- fix ctop
|
||||
- update moby and cli to 23.0.4
|
||||
- containerd: update to 1.7.0
|
||||
- runc: build with seccomp
|
||||
- runc: update to 1.1.5
|
||||
|
||||
4
|
||||
- update moby and cli to 23.0.6
|
||||
- containerd: update to 1.7.1
|
||||
- runc: update to 1.1.7
|
||||
|
@ -3,11 +3,11 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="docker"
|
||||
PKG_REV="2"
|
||||
PKG_REV="4"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="ASL"
|
||||
PKG_SITE="http://www.docker.com/"
|
||||
PKG_DEPENDS_TARGET="cli containerd moby runc tini"
|
||||
PKG_DEPENDS_TARGET="cli containerd ctop moby runc tini"
|
||||
PKG_SECTION="service/system"
|
||||
PKG_SHORTDESC="Docker is an open-source engine that automates the deployment of any application as a lightweight, portable, self-sufficient container that will run virtually anywhere."
|
||||
PKG_LONGDESC="Docker containers can encapsulate any payload, and will run consistently on and between virtually any server. The same container that a developer builds and tests on a laptop will run at scale, in production*, on VMs, bare-metal servers, OpenStack clusters, public instances, or combinations of the above."
|
||||
@ -32,6 +32,9 @@ addon() {
|
||||
cp -P $(get_build_dir containerd)/bin/containerd-shim ${ADDON_BUILD}/${PKG_ADDON_ID}/bin/containerd-shim
|
||||
cp -P $(get_build_dir containerd)/bin/containerd-shim-runc-v2 ${ADDON_BUILD}/${PKG_ADDON_ID}/bin/containerd-shim-runc-v2
|
||||
|
||||
# ctop
|
||||
cp -P $(get_build_dir ctop)/bin/ctop ${ADDON_BUILD}/${PKG_ADDON_ID}/bin/ctop
|
||||
|
||||
# runc
|
||||
cp -P $(get_build_dir runc)/bin/runc ${ADDON_BUILD}/${PKG_ADDON_ID}/bin/runc
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- jellyfin: update to 10.8.10
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
PKG_NAME="jellyfin"
|
||||
PKG_VERSION="1.0"
|
||||
PKG_VERSION_NUMBER="10.8.9"
|
||||
PKG_REV="0"
|
||||
PKG_VERSION_NUMBER="10.8.10"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="https://jellyfin.org/"
|
||||
|
@ -1 +1,4 @@
|
||||
initial release
|
||||
1
|
||||
- update librespot to githash 03b547d (2023-04-16)
|
||||
2
|
||||
- update librespot to githash c964102 (2023-05-14)
|
||||
|
@ -3,13 +3,14 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="librespot"
|
||||
PKG_VERSION="0.3.1"
|
||||
PKG_SHA256="d360eaf61ad4216ee2c4a4d583d61c8ec7367b5efbe512011d049f73e4f24952"
|
||||
PKG_REV="0"
|
||||
PKG_VERSION="c964102a349589d644baef5f43a566d6d1e151f1"
|
||||
PKG_VERSION_DATE="2023-05-14"
|
||||
PKG_SHA256="3bc6782d8796253040d995043fba4e6f6c71ff902da110b50398071e082b1930"
|
||||
PKG_REV="2"
|
||||
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 avahi pulseaudio cargo:host"
|
||||
PKG_SECTION="service"
|
||||
PKG_SHORTDESC="Librespot: play Spotify through Kodi using a Spotify app as a remote"
|
||||
@ -19,10 +20,10 @@ PKG_TOOLCHAIN="manual"
|
||||
PKG_IS_ADDON="yes"
|
||||
PKG_ADDON_NAME="Librespot"
|
||||
PKG_ADDON_TYPE="xbmc.service"
|
||||
PKG_ADDON_REQUIRES="script.module.requests:0.0.0"
|
||||
PKG_MAINTAINER="Anton Voyl (awiouy)"
|
||||
|
||||
make_target() {
|
||||
export RUSTC_LINKER=${CC}
|
||||
cargo build \
|
||||
--target ${TARGET_NAME} \
|
||||
--release \
|
||||
|
@ -1,108 +0,0 @@
|
||||
commit 10489ef0b9de4241eb8e007596f3d62616120545
|
||||
Author: awiouy <awiouy@gmail.com>
|
||||
Date: Fri May 29 07:40:19 2020 +0200
|
||||
|
||||
Notify Kodi
|
||||
|
||||
diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs
|
||||
index 1a5fcd2..c670977 100644
|
||||
--- a/core/src/spotify_id.rs
|
||||
+++ b/core/src/spotify_id.rs
|
||||
@@ -9,6 +9,12 @@
|
||||
Podcast,
|
||||
NonPlayable,
|
||||
}
|
||||
+
|
||||
+impl fmt::Display for SpotifyAudioType {
|
||||
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
+ write!(f, "{:?}", self)
|
||||
+ }
|
||||
+}
|
||||
|
||||
impl From<&str> for SpotifyAudioType {
|
||||
fn from(v: &str) -> Self {
|
||||
diff --git a/playback/src/config.rs b/playback/src/config.rs
|
||||
index 9d65042..6d098db 100644
|
||||
--- a/playback/src/config.rs
|
||||
+++ b/playback/src/config.rs
|
||||
@@ -142,6 +142,7 @@
|
||||
// pass function pointers so they can be lazily instantiated *after* spawning a thread
|
||||
// (thereby circumventing Send bounds that they might not satisfy)
|
||||
pub ditherer: Option<DithererBuilder>,
|
||||
+ pub notify_kodi: bool,
|
||||
}
|
||||
|
||||
impl Default for PlayerConfig {
|
||||
@@ -159,6 +160,7 @@
|
||||
normalisation_knee: 1.0,
|
||||
passthrough: false,
|
||||
ditherer: Some(mk_ditherer::<TriangularDitherer>),
|
||||
+ notify_kodi: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/playback/src/player.rs b/playback/src/player.rs
|
||||
index 2dd8f3b..67b3b28 100644
|
||||
--- a/playback/src/player.rs
|
||||
+++ b/playback/src/player.rs
|
||||
@@ -1868,6 +1868,10 @@ impl PlayerInternal {
|
||||
}
|
||||
}
|
||||
|
||||
+ fn notify_kodi(&mut self, event: String) {
|
||||
+ eprintln!("@{}", event);
|
||||
+ }
|
||||
+
|
||||
fn send_event(&mut self, event: PlayerEvent) {
|
||||
let mut index = 0;
|
||||
while index < self.event_senders.len() {
|
||||
@@ -1878,6 +1882,16 @@ impl PlayerInternal {
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if self.config.notify_kodi {
|
||||
+ use PlayerEvent::*;
|
||||
+ match event {
|
||||
+ 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()),
|
||||
+ _ => ()
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
fn load_track(
|
||||
diff --git a/src/main.rs b/src/main.rs
|
||||
index 2efd62b..ecee2ff 100644
|
||||
--- a/src/main.rs
|
||||
+++ b/src/main.rs
|
||||
@@ -424,6 +424,11 @@
|
||||
"",
|
||||
PASSTHROUGH,
|
||||
"Pass a raw stream to the output. Only works with the pipe and subprocess backends.",
|
||||
+ )
|
||||
+ .optflag(
|
||||
+ "",
|
||||
+ "notify-kodi",
|
||||
+ "Notify Kodi",
|
||||
);
|
||||
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
@@ -644,6 +649,8 @@ fn setup(args: &[String]) -> Setup {
|
||||
)
|
||||
};
|
||||
|
||||
+ let notify_kodi = matches.opt_present("notify-kodi");
|
||||
+
|
||||
let session_config = {
|
||||
let device_id = device_id(&name);
|
||||
|
||||
@@ -763,6 +763,7 @@
|
||||
normalisation_release,
|
||||
normalisation_knee,
|
||||
ditherer,
|
||||
+ notify_kodi: notify_kodi,
|
||||
}
|
||||
};
|
||||
|
66
packages/addons/service/librespot/source/bin/onevent.py
Normal file
66
packages/addons/service/librespot/source/bin/onevent.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/python
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
|
||||
ADDRESS = ('127.0.0.1', 36963)
|
||||
BUFFER_SIZE = 1024
|
||||
|
||||
|
||||
def send_event(event):
|
||||
data = json.dumps(event).encode()
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.sendto(data, ADDRESS)
|
||||
|
||||
|
||||
def receive_event():
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.settimeout(None)
|
||||
sock.bind(ADDRESS)
|
||||
while True:
|
||||
data, addr = sock.recvfrom(BUFFER_SIZE)
|
||||
event = json.loads(data.decode())
|
||||
if not event:
|
||||
break
|
||||
yield event
|
||||
|
||||
|
||||
ARG_ALBUM = 'album'
|
||||
ARG_ARTIST = 'artist'
|
||||
ARG_ART = 'art'
|
||||
ARG_TITLE = 'title'
|
||||
|
||||
KEY_ALBUM = 'ALBUM'
|
||||
KEY_ARTISTS = 'ARTISTS'
|
||||
KEY_COVERS = 'COVERS'
|
||||
KEY_ITEM_TYPE = 'ITEM_TYPE'
|
||||
KEY_NAME = 'NAME'
|
||||
KEY_PLAYER_EVENT = 'PLAYER_EVENT'
|
||||
KEY_SHOW_NAME = 'SHOW_NAME'
|
||||
|
||||
PLAYER_EVENT_STOPPED = 'stopped'
|
||||
PLAYER_EVENT_TRACK_CHANGED = 'track_changed'
|
||||
|
||||
ITEM_TYPE_EPISODE = 'Episode'
|
||||
ITEM_TYPE_TRACK = 'Track'
|
||||
|
||||
|
||||
def get_env_value(key):
|
||||
return os.environ.get(key, '').partition('\n')[0]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
player_event = get_env_value(KEY_PLAYER_EVENT)
|
||||
event = {KEY_PLAYER_EVENT: player_event}
|
||||
if player_event == PLAYER_EVENT_STOPPED:
|
||||
send_event(event)
|
||||
elif player_event == PLAYER_EVENT_TRACK_CHANGED:
|
||||
event[ARG_ART] = get_env_value(KEY_COVERS)
|
||||
event[ARG_TITLE] = get_env_value(KEY_NAME)
|
||||
item_type = get_env_value(KEY_ITEM_TYPE)
|
||||
if item_type == ITEM_TYPE_EPISODE:
|
||||
event[ARG_ALBUM] = get_env_value(KEY_SHOW_NAME)
|
||||
elif item_type == ITEM_TYPE_TRACK:
|
||||
event[ARG_ALBUM] = get_env_value(KEY_ALBUM)
|
||||
event[ARG_ARTIST] = get_env_value(KEY_ARTISTS)
|
||||
send_event(event)
|
@ -1,8 +1,25 @@
|
||||
import os
|
||||
import sys
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'resources', 'lib'))
|
||||
|
||||
from ls_monitor import Monitor as Monitor
|
||||
def _set_home():
|
||||
home = xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
os.makedirs(home, exist_ok=True)
|
||||
os.chdir(home)
|
||||
|
||||
Monitor().run()
|
||||
|
||||
def _set_paths():
|
||||
path = xbmcaddon.Addon().getAddonInfo('path')
|
||||
os.environ['PATH'] += os.pathsep + os.path.join(path, 'bin')
|
||||
os.environ['LD_LIBRARY_PATH'] += os.pathsep + os.path.join(path, 'lib')
|
||||
sys.path.append(os.path.join(path, 'bin'))
|
||||
sys.path.append(os.path.join(path, 'resources', 'lib'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
_set_home()
|
||||
_set_paths()
|
||||
import service
|
||||
service.Monitor().run()
|
||||
|
@ -1,30 +0,0 @@
|
||||
# Librespot for ALSA
|
||||
# Copy this file to '/storage/.config/system.d/service.librespot-alsa.service' and adapt it to your needs
|
||||
# Enable the service with 'systemctl enable /storage/.config/system.d/service.librespot-alsa.service'
|
||||
# Start the service with 'systemctl start service.librespot-alsa.service'
|
||||
# If you update the file, reload units with 'systemctl daemon-reload' and restart the service
|
||||
|
||||
[Unit]
|
||||
Description=librespot alsa backend
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Environment=LD_LIBRARY_PATH=/storage/.kodi/addons/service.librespot/lib
|
||||
#Enable Raspberry Pi onboard audio
|
||||
#ExecStartPre=-dtparam audio=on
|
||||
#Set Raspberry Pi playback route
|
||||
#ExecStartPre=-amixer -c 0 cset name="PCM Playback Route" 1
|
||||
ExecStart=/storage/.kodi/addons/service.librespot/bin/librespot \
|
||||
--backend alsa \
|
||||
--bitrate 320 \
|
||||
--cache "/storage/.config/lsa_cache" \
|
||||
# Use 'aplay -L' to list available devices
|
||||
# --device "default:CARD=ALSA" \
|
||||
--device-type computer \
|
||||
--disable-audio-cache \
|
||||
--name "Librespot ALSA" \
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=network-online.target
|
@ -8,29 +8,21 @@ msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30101"
|
||||
msgid "Autoplay"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30102"
|
||||
msgid "Discovery"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30103"
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30104"
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30105"
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30106"
|
||||
msgid "RTP Port"
|
||||
msgctxt "#30102"
|
||||
msgid "Do not disturb Kodi"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30107"
|
||||
msgid "Connect Port"
|
||||
msgctxt "#30103"
|
||||
msgid "User options"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30104"
|
||||
msgid "Backend"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30105"
|
||||
msgid "ALSA device"
|
||||
msgstr ""
|
||||
|
@ -0,0 +1,8 @@
|
||||
import player
|
||||
import service
|
||||
|
||||
|
||||
class Player(player.Player):
|
||||
|
||||
def onLibrespotTrackChanged(self, art, artist, title, **kwargs):
|
||||
service.notification(heading=title, message=artist, icon=art)
|
@ -0,0 +1,34 @@
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
import player
|
||||
import service
|
||||
|
||||
|
||||
class Player(player.Player):
|
||||
|
||||
def __init__(self, codec='pcm_sb16be', max_fanarts='10', **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._max_fanarts = int(max_fanarts)
|
||||
self._list_item = xbmcgui.ListItem(path=self.librespot.file)
|
||||
self._list_item.getVideoInfoTag().addAudioStream(xbmc.AudioStreamDetail(2, codec))
|
||||
self._music_info_tag = self._list_item.getMusicInfoTag()
|
||||
|
||||
def onLibrespotTrackChanged(self, album='', art='', artist='', title=''):
|
||||
fanart = service.get_fanart(art, self._max_fanarts) if art else art
|
||||
self._list_item.setArt({'fanart': fanart, 'thumb': art})
|
||||
self._music_info_tag.setAlbum(album)
|
||||
self._music_info_tag.setArtist(artist)
|
||||
self._music_info_tag.setTitle(title)
|
||||
if self.isPlaying() and self.getPlayingFile() == self.librespot.file:
|
||||
self.updateInfoTag(self._list_item)
|
||||
else:
|
||||
self.stop() # fixes unepxected behaviour of Player.play()
|
||||
self.librespot.start_sink()
|
||||
self.play(self.librespot.file, listitem=self._list_item)
|
||||
|
||||
def onLibrespotStopped(self):
|
||||
self.librespot.stop_sink()
|
||||
if self.isPlaying() and self.getPlayingFile() == self.librespot.file:
|
||||
self.last_file = None
|
||||
self.stop()
|
@ -0,0 +1,93 @@
|
||||
import shlex
|
||||
import socket
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import external_player
|
||||
import internal_player
|
||||
import service
|
||||
|
||||
|
||||
class Librespot:
|
||||
|
||||
def __init__(self,
|
||||
bitrate='320',
|
||||
device_type='tv',
|
||||
max_retries='5',
|
||||
name='Librespot@{}',
|
||||
options='',
|
||||
**kwargs):
|
||||
name = name.format(socket.gethostname())
|
||||
self.command = [
|
||||
'librespot',
|
||||
'--bitrate', f'{bitrate}',
|
||||
'--device-type', f'{device_type}',
|
||||
'--disable-audio-cache',
|
||||
'--disable-credential-cache',
|
||||
'--name', f'{name}',
|
||||
'--onevent', 'onevent.py',
|
||||
'--quiet',
|
||||
] + shlex.split(options)
|
||||
service.log(self.command)
|
||||
self.file = ''
|
||||
self._is_started = threading.Event()
|
||||
self._is_stopped = threading.Event()
|
||||
self._librespot = None
|
||||
self._max_retries = int(max_retries)
|
||||
self._retries = 0
|
||||
self._thread = threading.Thread()
|
||||
|
||||
def get_player(self, **kwargs):
|
||||
return (internal_player if self.file else external_player).Player(**kwargs)
|
||||
|
||||
def restart(self):
|
||||
if self._thread.is_alive():
|
||||
self._librespot.terminate()
|
||||
else:
|
||||
self.start()
|
||||
|
||||
def start(self):
|
||||
if not self._thread.is_alive() and self._retries < self._max_retries:
|
||||
self._thread = threading.Thread(daemon=True, target=self._run)
|
||||
self._thread.start()
|
||||
self._is_started.wait(1)
|
||||
|
||||
def stop(self):
|
||||
if self._thread.is_alive():
|
||||
self._is_stopped.set()
|
||||
self._librespot.terminate()
|
||||
self._thread.join()
|
||||
|
||||
def start_sink(self):
|
||||
pass
|
||||
|
||||
def stop_sink(self):
|
||||
pass
|
||||
|
||||
def _run(self):
|
||||
service.log('librespot thread started')
|
||||
self._is_started.clear()
|
||||
self._is_stopped.clear()
|
||||
while not self._is_stopped.is_set():
|
||||
with subprocess.Popen(self.command, stderr=subprocess.PIPE, text=True) as self._librespot:
|
||||
self._is_started.set()
|
||||
for line in self._librespot.stderr:
|
||||
service.log(line.rstrip())
|
||||
self.stop_sink()
|
||||
if self._librespot.returncode <= 0:
|
||||
self._retries = 0
|
||||
else:
|
||||
self._retries += 1
|
||||
if self._retries < self._max_retries:
|
||||
service.notification(
|
||||
f'librespot failed {self._retries}/{self._max_retries}')
|
||||
else:
|
||||
service.notification('librespot failed too many times')
|
||||
break
|
||||
service.log('librespot thread stopped')
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.stop()
|
@ -0,0 +1,11 @@
|
||||
import librespot
|
||||
|
||||
|
||||
class Librespot(librespot.Librespot):
|
||||
|
||||
def __init__(self, alsa_device='hw:2,0', **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.command += [
|
||||
'--backend', 'alsa',
|
||||
'--device', f'{alsa_device}',
|
||||
]
|
@ -0,0 +1,73 @@
|
||||
import socket
|
||||
import subprocess
|
||||
|
||||
import librespot
|
||||
import service
|
||||
|
||||
|
||||
class Librespot(librespot.Librespot):
|
||||
|
||||
def __init__(self,
|
||||
codec='pcm_sb16be',
|
||||
pa_rtp_address='127.0.0.1',
|
||||
pa_rtp_device='librespot',
|
||||
pa_rtp_port='24642',
|
||||
**kwargs):
|
||||
service.log('pulseaudio backend started')
|
||||
sap_cmd = f'nc -l -u -s {pa_rtp_address} -p 9875'.split()
|
||||
self._sap_server = subprocess.Popen(sap_cmd,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.STDOUT)
|
||||
service.log(f'sap server started')
|
||||
if not pa_rtp_port:
|
||||
with socket.socket() as s:
|
||||
s.bind((pa_rtp_address, 0))
|
||||
pa_rtp_port = s.getsockname()[1]
|
||||
modules = [
|
||||
[
|
||||
f'module-null-sink',
|
||||
f'sink_name={pa_rtp_device}',
|
||||
],
|
||||
[
|
||||
f'module-rtp-send',
|
||||
f'destination_ip={pa_rtp_address}',
|
||||
f'inhibit_auto_suspend=always',
|
||||
f'port={pa_rtp_port}',
|
||||
f'source={pa_rtp_device}.monitor',
|
||||
],
|
||||
]
|
||||
self._modules = [self._pactl('load-module', *m) for m in modules]
|
||||
self._sink_name = f'{pa_rtp_device}'
|
||||
self.stop_sink()
|
||||
service.log(f'pulseaudio modules loaded: {self._modules}')
|
||||
super().__init__(**kwargs)
|
||||
self.command += [
|
||||
'--backend', 'pulseaudio',
|
||||
'--device', f'{pa_rtp_device}',
|
||||
]
|
||||
self.file = f'rtp://{pa_rtp_address}:{pa_rtp_port}'
|
||||
|
||||
def start_sink(self):
|
||||
self._pactl('suspend-sink', self._sink_name, '0')
|
||||
|
||||
def stop_sink(self):
|
||||
self._pactl('suspend-sink', self._sink_name, '1')
|
||||
|
||||
def _pactl(self, command, *args):
|
||||
out = subprocess.run(['pactl', command, *args],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True
|
||||
).stdout.rstrip()
|
||||
service.log(f'pactl {command} {args}: {out}')
|
||||
return out
|
||||
|
||||
def __exit__(self, *args):
|
||||
super().__exit__(*args)
|
||||
for module in reversed(self._modules):
|
||||
if module:
|
||||
self._pactl('unload-module', module)
|
||||
service.log('pulseaudio backend stopped')
|
||||
if self._sap_server.poll() is None:
|
||||
self._sap_server.terminate()
|
||||
self._sap_server.wait()
|
||||
service.log('sap server stopped')
|
@ -1,49 +0,0 @@
|
||||
import os
|
||||
import socket
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
|
||||
DEFAULTS = dict(
|
||||
autoplay='true',
|
||||
bitrate='320',
|
||||
device='librespot',
|
||||
discovery='true',
|
||||
name='Librespot@{}',
|
||||
password='',
|
||||
rtp_dest='127.0.0.1',
|
||||
rtp_port='24642',
|
||||
connect_port='0',
|
||||
username='',
|
||||
)
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
ADDON_HOME = xbmcvfs.translatePath(ADDON.getAddonInfo('profile'))
|
||||
ADDON_ICON = ADDON.getAddonInfo('icon')
|
||||
ADDON_NAME = ADDON.getAddonInfo('name')
|
||||
ADDON_PATH = ADDON.getAddonInfo('path')
|
||||
ADDON_ENVT = dict(
|
||||
LD_LIBRARY_PATH=os.path.join(ADDON_PATH, 'lib'),
|
||||
PATH=os.path.join(ADDON_PATH, 'bin'))
|
||||
DIALOG = xbmcgui.Dialog()
|
||||
|
||||
|
||||
def get_settings():
|
||||
if not os.path.exists(ADDON_HOME):
|
||||
os.makedirs(ADDON_HOME)
|
||||
settings = dict()
|
||||
for id in DEFAULTS.keys():
|
||||
value = ADDON.getSetting(id)
|
||||
settings[id] = DEFAULTS[id] if value == '' else value
|
||||
settings['name'] = settings['name'].format(socket.gethostname())
|
||||
return settings
|
||||
|
||||
|
||||
def log(message):
|
||||
xbmc.log('{}: {}'.format(ADDON_NAME, message), xbmc.LOGINFO)
|
||||
|
||||
|
||||
def notification(message):
|
||||
DIALOG.notification(ADDON_NAME, message, ADDON_ICON)
|
@ -1,164 +0,0 @@
|
||||
import shlex
|
||||
import subprocess
|
||||
import threading
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from ls_addon import ADDON_ENVT as ADDON_ENVT
|
||||
from ls_addon import ADDON_HOME as ADDON_HOME
|
||||
from ls_addon import get_settings as get_settings
|
||||
from ls_addon import log as log
|
||||
from ls_pulseaudio import Pulseaudio as Pulseaudio
|
||||
from ls_spotify import SPOTIFY as SPOTIFY
|
||||
|
||||
|
||||
LIBRESPOT = 'librespot' \
|
||||
' --backend pulseaudio' \
|
||||
' --bitrate {bitrate}' \
|
||||
' --cache cache' \
|
||||
' --device {device}' \
|
||||
' --device-type TV' \
|
||||
' --disable-audio-cache' \
|
||||
' --name {name}' \
|
||||
' --notify-kodi'
|
||||
LIBRESPOT_AUTOPLAY = ' --autoplay'
|
||||
LIBRESPOT_AUTHENTICATE = ' --disable-discovery' \
|
||||
' --password {password}' \
|
||||
' --username {username}'
|
||||
|
||||
CODEC = 'pcm_s16be'
|
||||
MAX_PANICS = 3
|
||||
|
||||
|
||||
class Librespot(xbmc.Player):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
settings = get_settings()
|
||||
quoted = {k: shlex.quote(v) for (k, v) in settings.items()}
|
||||
command = LIBRESPOT
|
||||
if settings['connect_port'] != "0":
|
||||
command += ' --zeroconf-port %s ' % settings['connect_port']
|
||||
if settings['autoplay'] == 'true':
|
||||
command += LIBRESPOT_AUTOPLAY
|
||||
if (settings['discovery'] == 'false' and
|
||||
settings['password'] != '' and
|
||||
settings['username'] != ''):
|
||||
command += LIBRESPOT_AUTHENTICATE
|
||||
self.command = shlex.split(command.format(**quoted))
|
||||
log(shlex.split(command.format(**dict(quoted, password='*obfuscated*'))))
|
||||
self.is_aborted = False
|
||||
self.is_dead = False
|
||||
self.pulseaudio = Pulseaudio(settings)
|
||||
self.listitem = xbmcgui.ListItem()
|
||||
self.listitem.addStreamInfo('audio', {'codec': CODEC})
|
||||
self.listitem.setPath(path=self.pulseaudio.url)
|
||||
|
||||
def __enter__(self):
|
||||
self.pulseaudio.load_modules()
|
||||
self.panics = 0
|
||||
self.librespot = None
|
||||
self.is_playing_librespot = False
|
||||
if not self.isPlaying():
|
||||
self.start_librespot()
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.stop_librespot()
|
||||
self.pulseaudio.unload_modules()
|
||||
|
||||
def on_event_panic(self):
|
||||
self.pulseaudio.suspend_sink(1)
|
||||
self.panics += 1
|
||||
log('event panic {}/{}'.format(self.panics, MAX_PANICS))
|
||||
self.is_dead = self.panics >= MAX_PANICS
|
||||
self.stop_librespot(True)
|
||||
|
||||
def on_event_playing(self, type, id):
|
||||
log('event playing')
|
||||
SPOTIFY.update_listitem(self.listitem, type, id, self.country)
|
||||
if not self.isPlaying():
|
||||
log('starting librespot playback')
|
||||
self.pulseaudio.suspend_sink(0)
|
||||
self.play(self.pulseaudio.url, self.listitem)
|
||||
elif self.is_playing_librespot:
|
||||
log('updating librespot playback')
|
||||
self.updateInfoTag(self.listitem)
|
||||
|
||||
def on_event_stopped(self):
|
||||
self.pulseaudio.suspend_sink(1)
|
||||
log('event stopped')
|
||||
self.panics = 0
|
||||
self.stop()
|
||||
|
||||
def onPlayBackEnded(self):
|
||||
self.onPlayBackStopped()
|
||||
|
||||
def onPlayBackError(self):
|
||||
self.onPlayBackStopped()
|
||||
|
||||
def onPlayBackStarted(self):
|
||||
log('Kodi playback started')
|
||||
self.is_playing_librespot = self.getPlayingFile() == self.pulseaudio.url
|
||||
if not self.is_playing_librespot:
|
||||
self.stop_librespot()
|
||||
|
||||
def onPlayBackStopped(self):
|
||||
if self.is_playing_librespot:
|
||||
log('librespot playback stopped')
|
||||
self.is_playing_librespot = False
|
||||
self.stop_librespot(True)
|
||||
else:
|
||||
log('Kodi playback stopped')
|
||||
self.start_librespot()
|
||||
|
||||
def run_librespot(self):
|
||||
log('librespot thread started')
|
||||
self.restart = True
|
||||
while self.restart and not self.is_dead:
|
||||
self.librespot = subprocess.Popen(
|
||||
self.command,
|
||||
cwd=ADDON_HOME,
|
||||
env=ADDON_ENVT,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
encoding='utf-8')
|
||||
log('librespot started')
|
||||
with self.librespot.stdout:
|
||||
for line in self.librespot.stdout:
|
||||
words = line.split()
|
||||
if words[0] == '@Playing':
|
||||
self.on_event_playing(words[1], words[2])
|
||||
elif words[0] == '@Stopped':
|
||||
self.on_event_stopped()
|
||||
elif words[0] == 'stack':
|
||||
self.on_event_panic()
|
||||
else:
|
||||
log(line.rstrip())
|
||||
if 'Country:' in line:
|
||||
self.country = words[-1].strip('"')
|
||||
log('country={}'.format(self.country))
|
||||
self.pulseaudio.suspend_sink(1)
|
||||
self.stop()
|
||||
self.librespot.wait()
|
||||
log('librespot stopped')
|
||||
self.librespot = None
|
||||
log('librespot thread stopped')
|
||||
|
||||
def start_librespot(self):
|
||||
if self.librespot is None:
|
||||
self.thread = threading.Thread(target=self.run_librespot)
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
if self.is_playing_librespot and not self.is_aborted:
|
||||
log('stopping librespot playback')
|
||||
self.is_playing_librespot = False
|
||||
super().stop()
|
||||
|
||||
def stop_librespot(self, restart=False):
|
||||
self.restart = restart
|
||||
if self.librespot is not None:
|
||||
self.librespot.terminate()
|
||||
if not restart:
|
||||
self.thread.join()
|
@ -1,35 +0,0 @@
|
||||
import xbmc
|
||||
|
||||
from ls_addon import log as log
|
||||
from ls_addon import notification as notification
|
||||
from ls_librespot import Librespot as Librespot
|
||||
|
||||
|
||||
class Monitor(xbmc.Monitor):
|
||||
|
||||
def onSettingsChanged(self):
|
||||
self.is_changed = True
|
||||
|
||||
def run(self):
|
||||
log('monitor started')
|
||||
is_aborted = False
|
||||
is_dead = False
|
||||
while not (is_aborted or is_dead):
|
||||
self.is_changed = False
|
||||
librespot = Librespot()
|
||||
with librespot:
|
||||
while True:
|
||||
is_aborted = self.waitForAbort(1)
|
||||
if is_aborted:
|
||||
log('monitor aborted')
|
||||
librespot.is_aborted = True
|
||||
break
|
||||
is_dead = librespot.is_dead
|
||||
if is_dead:
|
||||
log('librespot died')
|
||||
notification('Too many errors')
|
||||
break
|
||||
if self.is_changed:
|
||||
log('settings changed')
|
||||
break
|
||||
log('monitor stopped')
|
@ -1,46 +0,0 @@
|
||||
import subprocess
|
||||
|
||||
from ls_addon import log as log
|
||||
|
||||
|
||||
def run(command):
|
||||
return subprocess.check_output(command.split(), text=True)
|
||||
|
||||
|
||||
class Pulseaudio:
|
||||
|
||||
def __init__(self, settings):
|
||||
self.null_sink = dict(
|
||||
module='module-null-sink',
|
||||
args='sink_name={device}'.format(**settings)
|
||||
)
|
||||
self.rtp_send = dict(
|
||||
module='module-rtp-send',
|
||||
args='destination_ip={rtp_dest} port={rtp_port}'
|
||||
' source={device}.monitor'.format(**settings)
|
||||
)
|
||||
self.suspend = 'pactl suspend-sink {device} {{}}'.format(**settings)
|
||||
self.url = 'rtp://{rtp_dest}:{rtp_port}'.format(**settings)
|
||||
|
||||
def list_modules(self):
|
||||
return [module.split('\t')
|
||||
for module in run('pactl list modules short').splitlines()[::-1]]
|
||||
|
||||
def load_modules(self):
|
||||
args = [module[2] for module in self.list_modules()]
|
||||
for module in [self.null_sink, self.rtp_send]:
|
||||
if module['args'] not in args:
|
||||
run('pactl load-module {} {}'.format(
|
||||
module['module'], module['args']))
|
||||
log('loaded {} {}'.format(module['module'], module['args']))
|
||||
self.suspend_sink(1)
|
||||
|
||||
def suspend_sink(self, bit):
|
||||
run(self.suspend.format(bit))
|
||||
log('suspended sink {}'.format(bit))
|
||||
|
||||
def unload_modules(self):
|
||||
for module in self.list_modules():
|
||||
if module[2] in [self.null_sink['args'], self.rtp_send['args']]:
|
||||
run('pactl unload-module {}'.format(module[0]))
|
||||
log('unloaded {} {}'.format(module[1], module[2]))
|
@ -1,80 +0,0 @@
|
||||
import requests
|
||||
import time
|
||||
|
||||
|
||||
from ls_addon import ADDON_ICON as ADDON_ICON
|
||||
from ls_addon import log as log
|
||||
|
||||
|
||||
SPOTIFY_ENDPOINT_EPISODES = 'https://api.spotify.com/v1/episodes/'
|
||||
SPOTIFY_ENDPOINT_TRACKS = 'https://api.spotify.com/v1/tracks/'
|
||||
SPOTIFY_HEADERS = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
SPOTIFY_REQUEST_TOKEN = {
|
||||
'url': 'https://accounts.spotify.com/api/token',
|
||||
'data': {'grant_type': 'client_credentials'},
|
||||
'headers': {'Authorization': 'Basic MTY5ZGY1NTMyZGVlNDdhNTk5MTNmODUyOGU4M2FlNzE6MWYzZDhiNTA3YmJlNGY2OGJlYjNhNDQ3MmU4YWQ0MTE='}
|
||||
}
|
||||
|
||||
|
||||
def get(info, indices, default):
|
||||
try:
|
||||
for index in indices:
|
||||
info = info[index]
|
||||
return info.encode('utf-8')
|
||||
except LookupError:
|
||||
return default
|
||||
|
||||
|
||||
class Spotify:
|
||||
|
||||
def __init__(self):
|
||||
self.headers = SPOTIFY_HEADERS
|
||||
self.expiration = time.time()
|
||||
|
||||
def get_headers(self):
|
||||
if time.time() > self.expiration:
|
||||
log('token expired')
|
||||
token = requests.post(**SPOTIFY_REQUEST_TOKEN).json()
|
||||
log(token)
|
||||
self.expiration = time.time() + float(token['expires_in']) - 5
|
||||
self.headers['Authorization'] = 'Bearer {}'.format(
|
||||
token['access_token'])
|
||||
|
||||
def get_endpoint(self, endpoint, id, market):
|
||||
try:
|
||||
self.get_headers()
|
||||
return requests.get(url=endpoint + id,
|
||||
headers=self.headers,
|
||||
params=dict(market=market)).json()
|
||||
except Exception as e:
|
||||
log('failed to get {} from Spotify {}'.format(endpoint, e))
|
||||
return {}
|
||||
|
||||
def update_listitem(self, listitem, type, id, market='SE'):
|
||||
if type == 'Podcast':
|
||||
info = self.get_endpoint(SPOTIFY_ENDPOINT_EPISODES, id, market)
|
||||
album = get(info, ['show', 'name'], 'unknown show',)
|
||||
artist = get(info, ['show', 'publisher'], 'unknown publisher')
|
||||
thumb = get(info, ['images', 0, 'url'], ADDON_ICON)
|
||||
title = get(info, ['name'], 'unknown episode')
|
||||
elif type == 'Track':
|
||||
info = self.get_endpoint(SPOTIFY_ENDPOINT_TRACKS, id, market)
|
||||
album = get(info, ['album', 'name'], 'unknown album')
|
||||
artist = get(info, ['artists', 0, 'name'], 'unknown artist')
|
||||
thumb = get(info, ['album', 'images', 0, 'url'], ADDON_ICON)
|
||||
title = get(info, ['name'], 'unknown title')
|
||||
else:
|
||||
album = ''
|
||||
artist = 'Unknown Media Type'
|
||||
thumb = ADDON_ICON
|
||||
title = ''
|
||||
listitem.setArt(dict(fanart=thumb, thumb=thumb))
|
||||
listitem.setInfo('music', dict(
|
||||
album=album, artist=artist, title=title))
|
||||
log('{}#{}#{}#{}'.format(title, artist, album, thumb))
|
||||
|
||||
|
||||
SPOTIFY = Spotify()
|
@ -0,0 +1,71 @@
|
||||
import threading
|
||||
import xbmc
|
||||
|
||||
import onevent
|
||||
import service
|
||||
|
||||
|
||||
class Player(xbmc.Player):
|
||||
|
||||
def __init__(self, dnd_kodi='false', librespot=None, **kwargs):
|
||||
super().__init__()
|
||||
self._dnd_kodi = (dnd_kodi == 'true')
|
||||
self._thread = threading.Thread(daemon=True, target=self._run)
|
||||
self._thread.start()
|
||||
self.last_file = None
|
||||
self.librespot = librespot
|
||||
if not (self._dnd_kodi and self.isPlaying()):
|
||||
self.librespot.start()
|
||||
|
||||
def onAVStarted(self):
|
||||
file = self.getPlayingFile()
|
||||
if file != self.librespot.file:
|
||||
if self._dnd_kodi:
|
||||
self.librespot.stop()
|
||||
elif self.last_file == self.librespot.file:
|
||||
self.librespot.restart()
|
||||
self.last_file = file
|
||||
|
||||
def onLibrespotStopped(self):
|
||||
pass
|
||||
|
||||
def onLibrespotTrackChanged(self, album='', art='', artist='', title=''):
|
||||
pass
|
||||
|
||||
def onPlayBackEnded(self):
|
||||
if self.last_file == self.librespot.file:
|
||||
self.librespot.restart()
|
||||
else:
|
||||
self.librespot.start()
|
||||
self.last_file = None
|
||||
|
||||
def onPlayBackError(self):
|
||||
self.onPlayBackEnded()
|
||||
|
||||
def onPlayBackStopped(self):
|
||||
self.onPlayBackEnded()
|
||||
|
||||
# fixes unexpected behaviour of Player.stop()
|
||||
def stop(self):
|
||||
xbmc.executebuiltin('PlayerControl(Stop)')
|
||||
|
||||
def _run(self):
|
||||
service.log('onevent dispatcher started')
|
||||
for event in onevent.receive_event():
|
||||
try:
|
||||
player_event = event.pop(onevent.KEY_PLAYER_EVENT)
|
||||
if player_event == onevent.PLAYER_EVENT_STOPPED:
|
||||
self.onLibrespotStopped()
|
||||
elif player_event == onevent.PLAYER_EVENT_TRACK_CHANGED:
|
||||
self.onLibrespotTrackChanged(**event)
|
||||
except Exception as e:
|
||||
service.log(e, True)
|
||||
service.log('onevent dispatcher stopped')
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
onevent.send_event({})
|
||||
self._thread.join()
|
||||
self.onLibrespotStopped()
|
@ -0,0 +1,88 @@
|
||||
import PIL.Image
|
||||
import urllib.request
|
||||
import tempfile
|
||||
import os
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
_ADDON = xbmcaddon.Addon()
|
||||
_ICON = _ADDON.getAddonInfo('icon')
|
||||
_NAME = _ADDON.getAddonInfo('name')
|
||||
_DIALOG = xbmcgui.Dialog()
|
||||
|
||||
|
||||
def log(message, show=False):
|
||||
xbmc.log(f'{_NAME}: {message}', xbmc.LOGINFO if show else xbmc.LOGDEBUG)
|
||||
|
||||
|
||||
def notification(message='', sound=False, heading=_NAME, icon=_ICON, time=5000):
|
||||
_DIALOG.notification(heading, message, icon, time, sound)
|
||||
|
||||
|
||||
_FANART_DIR = os.path.join(tempfile.gettempdir(), 'librespot.fanart')
|
||||
|
||||
|
||||
def get_fanart(url, max_fanarts):
|
||||
name = os.path.basename(url)
|
||||
target = os.path.join(_FANART_DIR, f'{name}_16x9')
|
||||
if not os.path.exists(target):
|
||||
if not os.path.exists(_FANART_DIR):
|
||||
os.makedirs(_FANART_DIR)
|
||||
files = os.listdir(_FANART_DIR)
|
||||
files = [os.path.join(_FANART_DIR, file) for file in files if os.path.isfile(
|
||||
os.path.join(_FANART_DIR, file))]
|
||||
files.sort(key=os.path.getmtime)
|
||||
for file in files[:-max_fanarts]:
|
||||
os.remove(file)
|
||||
source = os.path.join(_FANART_DIR, f'{name}_9x9')
|
||||
urllib.request.urlretrieve(url, source)
|
||||
image = PIL.Image.open(source)
|
||||
width, height = image.size
|
||||
new_width = int(height * 16 / 9)
|
||||
delta_w = new_width - width
|
||||
new_image = PIL.Image.new('RGB', (new_width, height), (0, 0, 0))
|
||||
new_image.paste(image, (delta_w // 2, 0))
|
||||
new_image.save(target, 'JPEG', optimize=True)
|
||||
os.remove(source)
|
||||
return target
|
||||
|
||||
|
||||
_SETTINGS = {
|
||||
'alsa_device': 'hw:2,0',
|
||||
'backend': 'pulseaudio_rtp',
|
||||
'dnd_kodi': 'false',
|
||||
'name': f'{_NAME}@{{}}',
|
||||
'options': '',
|
||||
}
|
||||
|
||||
|
||||
def _get_setting(setting, default):
|
||||
value = _ADDON.getSetting(setting)
|
||||
return value if value else default
|
||||
|
||||
|
||||
def _get_librespot():
|
||||
while True:
|
||||
settings = {k: _get_setting(k, v) for k, v in _SETTINGS.items()}
|
||||
backend = settings.pop('backend')
|
||||
librespot_class = __import__(f'librespot_{backend}').Librespot
|
||||
with librespot_class(**settings) as librespot:
|
||||
with librespot.get_player(librespot=librespot, **settings) as player:
|
||||
yield
|
||||
|
||||
|
||||
class Monitor(xbmc.Monitor):
|
||||
|
||||
def __init__(self):
|
||||
self._get_librespot = _get_librespot()
|
||||
self.onSettingsChanged()
|
||||
|
||||
def onSettingsChanged(self):
|
||||
log('settings changed')
|
||||
next(self._get_librespot)
|
||||
|
||||
def run(self):
|
||||
self.waitForAbort()
|
||||
log('abort requested')
|
||||
self._get_librespot.close()
|
@ -1,12 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<settings>
|
||||
<category label="30100">
|
||||
<setting label="30101" id="autoplay" type="bool" default="true" />
|
||||
<setting label="30102" id="discovery" type="bool" default="true" />
|
||||
<setting label="30103" id="username" type="text" default="" subsetting="true" visible="eq(-1,false)" />
|
||||
<setting label="30104" id="password" type="text" default="" subsetting="true" visible="eq(-2,false)" option="hidden" />
|
||||
<setting label="30105" id="name" type="text" default="Librespot@{}" />
|
||||
<setting label="30106" id="rtp_port" type="number" default="24642" />
|
||||
<setting label="30107" id="connect_port" type="number" default="0" />
|
||||
<setting label="30101" id="name" type="text" default="Librespot@{}" />
|
||||
<setting label="30102" id="dnd_kodi" type="bool" default="false" />
|
||||
<setting label="30103" id="options" type="text" default="" />
|
||||
<setting label="30104" id="backend" type="select" values="pulseaudio_rtp|alsa" />
|
||||
<setting label="30105" id="alsa_device" type="text" default="hw:2,0" subsetting="true" visible="eq(-1,1)" />
|
||||
</category>
|
||||
</settings>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
PKG_NAME="minisatip"
|
||||
PKG_VERSION="1.2.84"
|
||||
PKG_SHA256="b8e58eae2e0502d940b59cf60bf73ffb6af1a4c7d4cd23ddd939f29cd4004d8c"
|
||||
PKG_SHA256="d5a06b0c371e1f5ccba6fcb3d76abf348e93e14ab4d7317bb701ae023c085e4b"
|
||||
PKG_REV="0"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
|
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- mpd: update to 0.23.12
|
||||
|
@ -1,3 +1,5 @@
|
||||
3
|
||||
Update to 6.1.3
|
||||
2
|
||||
Fix nextpvr-downloader script
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="nextpvr"
|
||||
PKG_VERSION="6.1.1~Nexus"
|
||||
PKG_ADDON_VERSION="6.1.1~2"
|
||||
PKG_VERSION="6.1.3~Nexus"
|
||||
PKG_ADDON_VERSION="6.1.3~3"
|
||||
PKG_REV="0"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="NextPVR"
|
||||
|
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- ccid: update to 1.5.2
|
||||
|
@ -1 +1,8 @@
|
||||
initial release
|
||||
2
|
||||
- asio: update to 1.28.0
|
||||
- nqptp: update to 1.2.1
|
||||
- shairport-sync: update to 4.2
|
||||
|
||||
1
|
||||
- asio: update to 1.27.0
|
||||
- snapcast: update to 0.27.0
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
PKG_NAME="snapclient"
|
||||
PKG_VERSION="0.27.0"
|
||||
PKG_REV="1"
|
||||
PKG_REV="2"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv3"
|
||||
PKG_DEPENDS_TARGET="toolchain alsa-plugins snapcast"
|
||||
|
@ -1 +1,8 @@
|
||||
initial release
|
||||
2
|
||||
- asio: update to 1.28.0
|
||||
- nqptp: update to 1.2.1
|
||||
- shairport-sync: update to 4.2
|
||||
|
||||
1
|
||||
- asio: update to 1.27.0
|
||||
- snapcast: update to 0.27.0
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
PKG_NAME="snapserver"
|
||||
PKG_VERSION="0.27.0"
|
||||
PKG_REV="1"
|
||||
PKG_REV="2"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv3"
|
||||
PKG_DEPENDS_TARGET="toolchain nqptp shairport-sync snapcast"
|
||||
|
@ -1 +1,5 @@
|
||||
initial release
|
||||
1
|
||||
- not released for LE11
|
||||
|
||||
2
|
||||
- syncthing: update to 1.23.4
|
||||
|
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- fix not working TigerVNC
|
||||
|
@ -4,7 +4,7 @@
|
||||
PKG_NAME="tigervnc"
|
||||
PKG_VERSION="1.10.1"
|
||||
PKG_SHA256="19fcc80d7d35dd58115262e53cac87d8903180261d94c2a6b0c19224f50b58c4"
|
||||
PKG_REV="0"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="x86_64"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="http://www.tigervnc.org"
|
||||
|
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- ttyd: update to 1.7.3
|
||||
|
@ -1 +1,2 @@
|
||||
initial release
|
||||
1
|
||||
- btrfs-progs: update to 6.2.2
|
||||
|
@ -1 +1,8 @@
|
||||
initial release
|
||||
3
|
||||
- aspnet6-runtime: update to 6.0.18
|
||||
|
||||
2
|
||||
- aspnet6-runtime: update to 6.0.16
|
||||
|
||||
1
|
||||
- aspnet6-runtime: update to 6.0.15
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="dotnet-runtime"
|
||||
PKG_REV="1"
|
||||
PKG_REV="3"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://dotnet.microsoft.com/"
|
||||
|
@ -1 +1,3 @@
|
||||
initial release
|
||||
1
|
||||
- mpg123: update to 1.31.3
|
||||
- mpv-drmprime: update to 0.35.1
|
||||
|
@ -1 +1,5 @@
|
||||
initial release
|
||||
1
|
||||
- iperf: update to 3.13
|
||||
- libpcap: update to 1.10.3
|
||||
- rar2fs: update to 1.29.6
|
||||
- tcpdump: update to 4.99.3
|
||||
|
@ -1 +1,9 @@
|
||||
initial release
|
||||
1
|
||||
- bottom: update to 0.8.0
|
||||
- diffutils: update to 3.9
|
||||
- htop: update to 3.2.2
|
||||
- lshw: fix lshw -version display
|
||||
- mc: update to 4.8.29
|
||||
- stress-ng: update to 0.15.06
|
||||
- unrar: update to 6.2.6
|
||||
- vim: update to 9.0.1417
|
||||
|
@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="bcm2835-driver"
|
||||
PKG_VERSION="c4122b8708d2d1e8a123e45b188d0bc2d0105bca"
|
||||
PKG_SHA256="b4c9701d6e5803a5e42cc55f117feee27f35549c5156d165fe120282f9b98544"
|
||||
PKG_VERSION="543692d23dff7075915bc9c7e34abb3fe28e1c46"
|
||||
PKG_SHA256="838aa79b842fc10030c6a8b8d7f8dc6b6b08ed7ac762a5488d3d64f1bc51a4ec"
|
||||
PKG_LICENSE="nonfree"
|
||||
PKG_SITE="http://www.broadcom.com"
|
||||
PKG_URL="${DISTRO_SRC}/${PKG_NAME}-${PKG_VERSION}.tar.xz"
|
||||
|
@ -15,14 +15,3 @@ PKG_TOOLCHAIN="manual"
|
||||
makeinstall_target() {
|
||||
DESTDIR=${INSTALL}/$(get_kernel_overlay_dir) ./install
|
||||
}
|
||||
|
||||
post_makeinstall_target() {
|
||||
# Install rpi btuart script to bring up Bluetooth
|
||||
mkdir -p ${INSTALL}/usr/bin
|
||||
cp -P ${PKG_DIR}/scripts/rpi-btuart ${INSTALL}/usr/bin
|
||||
cp -P ${PKG_DIR}/scripts/rpi-udev ${INSTALL}/usr/bin
|
||||
}
|
||||
|
||||
post_install() {
|
||||
enable_service brcmfmac_sdio-firmware.service
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
HCIATTACH=/usr/bin/hciattach
|
||||
if grep -q "Pi 4" /proc/device-tree/model; then
|
||||
BDADDR=
|
||||
else
|
||||
SERIAL=$(cat /proc/device-tree/serial-number | cut -c9-)
|
||||
B1=${SERIAL:2:2}
|
||||
B2=${SERIAL:4:2}
|
||||
B3=${SERIAL:6:2}
|
||||
BDADDR=$(printf b8:27:eb:%02x:%02x:%02x $((0x$B1 ^ 0xaa)) $((0x$B2 ^ 0xaa)) $((0x$B3 ^ 0xaa)))
|
||||
fi
|
||||
|
||||
uart0="$(cat /proc/device-tree/aliases/uart0)"
|
||||
serial1="$(cat /proc/device-tree/aliases/serial1)"
|
||||
|
||||
if [ "$uart0" = "$serial1" ] ; then
|
||||
uart0_pins="$(wc -c /proc/device-tree/soc/gpio@7e200000/uart0_pins/brcm\,pins | cut -f 1 -d ' ')"
|
||||
if [ "$uart0_pins" = "16" ] ; then
|
||||
$HCIATTACH /dev/serial1 bcm43xx 3000000 flow - $BDADDR
|
||||
else
|
||||
$HCIATTACH /dev/serial1 bcm43xx 921600 noflow - $BDADDR
|
||||
fi
|
||||
else
|
||||
$HCIATTACH /dev/serial1 bcm43xx 460800 noflow - $BDADDR
|
||||
fi
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
ALIASES="/proc/device-tree/aliases"
|
||||
UARTX="uart${1}"
|
||||
|
||||
if [ $(cat ${ALIASES}/${UARTX}) = $(cat ${ALIASES}/serial0) ]; then
|
||||
echo 0
|
||||
elif [ $(cat ${ALIASES}/${UARTX}) = $(cat ${ALIASES}/serial1) ]; then
|
||||
echo 1
|
||||
else
|
||||
exit 1
|
||||
fi
|
@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=Broadcom sdio firmware update for BCM43430A1
|
||||
ConditionFileNotEmpty=/proc/device-tree/soc/gpio@7e200000/bt_pins/brcm,pins
|
||||
Requires=dev-serial1.device
|
||||
After=dev-serial1.device network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/rpi-btuart
|
||||
|
||||
[Install]
|
||||
WantedBy=network.target
|
@ -1,2 +0,0 @@
|
||||
KERNEL=="ttyAMA[01]", PROGRAM="/usr/bin/rpi-udev 0", SYMLINK+="serial%c"
|
||||
KERNEL=="ttyS0", PROGRAM="/usr/bin/rpi-udev 1", SYMLINK+="serial%c"
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="intel-ucode"
|
||||
PKG_VERSION="20230214"
|
||||
PKG_SHA256="3a3cfe2c7642339af9f4c2ad69f5f367dfa4cd1f7f9fd4124dedefb7803591d4"
|
||||
PKG_VERSION="20230613"
|
||||
PKG_SHA256="894d822d2347222a2595d4fc47d358e01d35a54780123100c317dfc31b1b0cc9"
|
||||
PKG_ARCH="x86_64"
|
||||
[ "${DISTRO}" = "Lakka" ] && PKG_ARCH+=" i386" || true
|
||||
PKG_LICENSE="other"
|
||||
|
@ -16,15 +16,15 @@ PKG_PATCH_DIRS="${LINUX}"
|
||||
|
||||
case "${LINUX}" in
|
||||
amlogic)
|
||||
PKG_VERSION="7d54cb2c26dad1264ecca85992bfe8984df4b7b5" # 6.1.14
|
||||
PKG_SHA256="76f039741d61e06c740b846291e5017b97da7d3f91fb2f368230a161d46905a6"
|
||||
PKG_VERSION="6449a0ba6843fe70523eeb7855984054f36f6d24" # 6.1.19
|
||||
PKG_SHA256="6a46c7b91028157d56437736cc8601fa46485e6f52bd6983e92ff80f17aa3065"
|
||||
PKG_URL="https://github.com/torvalds/linux/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_SOURCE_NAME="linux-${LINUX}-${PKG_VERSION}.tar.gz"
|
||||
PKG_PATCH_DIRS="default"
|
||||
;;
|
||||
raspberrypi)
|
||||
PKG_VERSION="cb8d82ae0059dd19f0f24a3c1e1081c87d73b0ea" # 6.1.23
|
||||
PKG_SHA256="bb447497dddae03d6cf9235e8e8a9613a637c0143ea4ca6cb842d0f5c805c577"
|
||||
PKG_VERSION="a72a720bfd4d2093ce9e51239cd7067dd060ff81" # 6.1.34
|
||||
PKG_SHA256="3acaf74f06c04c5727e8d917251b40e5378303b9e2fc62eca81f362857c1db70"
|
||||
PKG_URL="https://github.com/raspberrypi/linux/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_SOURCE_NAME="linux-${LINUX}-${PKG_VERSION}.tar.gz"
|
||||
;;
|
||||
|
@ -0,0 +1,138 @@
|
||||
From 94d0a9815c99385e57a17fb20448e47a1f229bcf Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 3 Jun 2023 12:00:28 +0200
|
||||
Subject: [PATCH 1/2] ALSA: pcm: fix ELD constraints for (E)AC3, DTS(-HD) and
|
||||
MLP formats
|
||||
|
||||
The SADs of compressed formats contain the channel and sample rate
|
||||
info of the audio data inside the compressed stream, but when
|
||||
building constraints we must use the rates and channels used to
|
||||
transport the compressed streams.
|
||||
|
||||
eg 48kHz 6ch EAC3 needs to be transmitted as a 2ch 192kHz stream.
|
||||
|
||||
This patch fixes the constraints for the common AC3 and DTS formats,
|
||||
the constraints for the less common MPEG, DSD etc formats are copied
|
||||
directly from the info in the SADs as before as I don't have the specs
|
||||
and equipment to test those.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/core/pcm_drm_eld.c | 73 ++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 70 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
|
||||
index 4b5faae5d16e5..07075071972dd 100644
|
||||
--- a/sound/core/pcm_drm_eld.c
|
||||
+++ b/sound/core/pcm_drm_eld.c
|
||||
@@ -2,11 +2,25 @@
|
||||
/*
|
||||
* PCM DRM helpers
|
||||
*/
|
||||
+#include <linux/bitfield.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/hdmi.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
|
||||
+#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
|
||||
+#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
|
||||
+
|
||||
+#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
|
||||
+#define SAD1_RATE_32000_MASK BIT(0)
|
||||
+#define SAD1_RATE_44100_MASK BIT(1)
|
||||
+#define SAD1_RATE_48000_MASK BIT(2)
|
||||
+#define SAD1_RATE_88200_MASK BIT(3)
|
||||
+#define SAD1_RATE_96000_MASK BIT(4)
|
||||
+#define SAD1_RATE_176400_MASK BIT(5)
|
||||
+#define SAD1_RATE_192000_MASK BIT(6)
|
||||
+
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
44100,
|
||||
@@ -17,9 +31,62 @@ static const unsigned int eld_rates[] = {
|
||||
192000,
|
||||
};
|
||||
|
||||
+static unsigned int map_rate_families(const u8 *sad,
|
||||
+ unsigned int mask_32000,
|
||||
+ unsigned int mask_44100,
|
||||
+ unsigned int mask_48000)
|
||||
+{
|
||||
+ unsigned int rate_mask = 0;
|
||||
+
|
||||
+ if (sad[1] & SAD1_RATE_32000_MASK)
|
||||
+ rate_mask |= mask_32000;
|
||||
+ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
|
||||
+ rate_mask |= mask_44100;
|
||||
+ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
|
||||
+ rate_mask |= mask_48000;
|
||||
+ return rate_mask;
|
||||
+}
|
||||
+
|
||||
+static unsigned int sad_rate_mask(const u8 *sad)
|
||||
+{
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ return map_rate_families(sad,
|
||||
+ SAD1_RATE_32000_MASK,
|
||||
+ SAD1_RATE_44100_MASK,
|
||||
+ SAD1_RATE_48000_MASK);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return map_rate_families(sad,
|
||||
+ 0,
|
||||
+ SAD1_RATE_176400_MASK,
|
||||
+ SAD1_RATE_192000_MASK);
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
- return 1 + (sad[0] & 7);
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 2;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 8;
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
@@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
- rate_mask |= sad[1];
|
||||
+ rate_mask |= sad_rate_mask(sad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
- if (rate_mask & sad[1])
|
||||
+ if (rate_mask & sad_rate_mask(sad))
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
||||
--
|
||||
2.39.2
|
||||
|
@ -1,91 +0,0 @@
|
||||
From a2769637a9b98c6809d4d25a3a20447a3ff7b23a Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Fri, 19 Mar 2021 12:14:17 +0100
|
||||
Subject: [PATCH] ALSA: pcm: fix ELD constraints for some compressed audio
|
||||
formats
|
||||
|
||||
The SADs of compressed formats like AC3 and DTS contain the channel
|
||||
and sample rate info of the audio data inside the compressed stream,
|
||||
but when building constraints we must use the rates and formats used
|
||||
to pass through the stream. eg 2ch 48kHz for AC3.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/core/pcm_drm_eld.c | 38 +++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 35 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
|
||||
index 4b5faae5d16e5..e7ec7a8b9d420 100644
|
||||
--- a/sound/core/pcm_drm_eld.c
|
||||
+++ b/sound/core/pcm_drm_eld.c
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
+#include <linux/hdmi.h>
|
||||
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
@@ -17,9 +18,40 @@ static const unsigned int eld_rates[] = {
|
||||
192000,
|
||||
};
|
||||
|
||||
+static unsigned int sad_format(const u8 *sad)
|
||||
+{
|
||||
+ return (sad[0] & 0x78) >> 3;
|
||||
+}
|
||||
+
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
- return 1 + (sad[0] & 7);
|
||||
+ switch (sad_format(sad)) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 2;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 8;
|
||||
+ default:
|
||||
+ return 1 + (sad[0] & 7);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static unsigned int sad_rate_mask(const u8 *sad)
|
||||
+{
|
||||
+ switch (sad_format(sad)) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ return 0x07; // 32-48kHz
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 0x7f; // 32-192kHz
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 0x60; // 176.4, 192kHz
|
||||
+ default:
|
||||
+ return sad[1] & 0x7f;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
@@ -42,7 +74,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
- rate_mask |= sad[1];
|
||||
+ rate_mask |= sad_rate_mask(sad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +102,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
- if (rate_mask & sad[1])
|
||||
+ if (rate_mask & sad_rate_mask(sad))
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
||||
--
|
||||
2.20.1
|
||||
|
@ -0,0 +1,89 @@
|
||||
From 99586e3f502fcc4fdd21b621f3c87ae7a8f7c170 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 3 Jun 2023 12:12:28 +0200
|
||||
Subject: [PATCH 2/2] ASoC: hdmi-codec: don't set channel and speaker info for
|
||||
compressed formats
|
||||
|
||||
CTA 861 only mandates that the speaker allocation in the audio info frame
|
||||
is set for multichannel PCM formats. Likewise the number of channels in the
|
||||
audio infoframe is only relevant for PCM.
|
||||
|
||||
Some TVs won't decode compressed formats if the number of channels isn't
|
||||
set to 0 (refer to stream header) and the speaker allocation is set to the
|
||||
default 0 (FL and FR).
|
||||
|
||||
So fill in this info only for PCM audio and set it to 0 for compressed
|
||||
audio formats.
|
||||
|
||||
This also prevents hdmi_codec_prepare failing with an error when trying to
|
||||
play back DTS-HD or MLP (which is passed through as 8ch) if the sink only
|
||||
supports 2ch PCM and announces only FL/FR speaker support in the EDID.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/codecs/hdmi-codec.c | 36 +++++++++++++++++++++++------------
|
||||
1 file changed, 24 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
|
||||
index 0b1cdb2d60498..a192d985c5f18 100644
|
||||
--- a/sound/soc/codecs/hdmi-codec.c
|
||||
+++ b/sound/soc/codecs/hdmi-codec.c
|
||||
@@ -484,31 +484,43 @@ static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
|
||||
struct hdmi_codec_params *hp)
|
||||
{
|
||||
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
|
||||
- int idx;
|
||||
-
|
||||
- /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
- if (idx < 0) {
|
||||
- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
- idx);
|
||||
- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
- return idx;
|
||||
+ int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ u8 ca_id = 0;
|
||||
+ bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO);
|
||||
+
|
||||
+ if (pcm_audio) {
|
||||
+ /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
+
|
||||
+ if (idx < 0) {
|
||||
+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
+ idx);
|
||||
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ return idx;
|
||||
+ }
|
||||
+
|
||||
+ ca_id = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
}
|
||||
|
||||
memset(hp, 0, sizeof(*hp));
|
||||
|
||||
hdmi_audio_infoframe_init(&hp->cea);
|
||||
- hp->cea.channels = channels;
|
||||
+
|
||||
+ if (pcm_audio)
|
||||
+ hp->cea.channels = channels;
|
||||
+ else
|
||||
+ hp->cea.channels = 0;
|
||||
+
|
||||
hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
|
||||
hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
|
||||
hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
|
||||
- hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hp->cea.channel_allocation = ca_id;
|
||||
|
||||
hp->sample_width = sample_width;
|
||||
hp->sample_rate = sample_rate;
|
||||
hp->channels = channels;
|
||||
|
||||
- hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hcp->chmap_idx = idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.39.2
|
||||
|
@ -0,0 +1,138 @@
|
||||
From 94d0a9815c99385e57a17fb20448e47a1f229bcf Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 3 Jun 2023 12:00:28 +0200
|
||||
Subject: [PATCH 1/2] ALSA: pcm: fix ELD constraints for (E)AC3, DTS(-HD) and
|
||||
MLP formats
|
||||
|
||||
The SADs of compressed formats contain the channel and sample rate
|
||||
info of the audio data inside the compressed stream, but when
|
||||
building constraints we must use the rates and channels used to
|
||||
transport the compressed streams.
|
||||
|
||||
eg 48kHz 6ch EAC3 needs to be transmitted as a 2ch 192kHz stream.
|
||||
|
||||
This patch fixes the constraints for the common AC3 and DTS formats,
|
||||
the constraints for the less common MPEG, DSD etc formats are copied
|
||||
directly from the info in the SADs as before as I don't have the specs
|
||||
and equipment to test those.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/core/pcm_drm_eld.c | 73 ++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 70 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
|
||||
index 4b5faae5d16e5..07075071972dd 100644
|
||||
--- a/sound/core/pcm_drm_eld.c
|
||||
+++ b/sound/core/pcm_drm_eld.c
|
||||
@@ -2,11 +2,25 @@
|
||||
/*
|
||||
* PCM DRM helpers
|
||||
*/
|
||||
+#include <linux/bitfield.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/hdmi.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
|
||||
+#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
|
||||
+#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
|
||||
+
|
||||
+#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
|
||||
+#define SAD1_RATE_32000_MASK BIT(0)
|
||||
+#define SAD1_RATE_44100_MASK BIT(1)
|
||||
+#define SAD1_RATE_48000_MASK BIT(2)
|
||||
+#define SAD1_RATE_88200_MASK BIT(3)
|
||||
+#define SAD1_RATE_96000_MASK BIT(4)
|
||||
+#define SAD1_RATE_176400_MASK BIT(5)
|
||||
+#define SAD1_RATE_192000_MASK BIT(6)
|
||||
+
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
44100,
|
||||
@@ -17,9 +31,62 @@ static const unsigned int eld_rates[] = {
|
||||
192000,
|
||||
};
|
||||
|
||||
+static unsigned int map_rate_families(const u8 *sad,
|
||||
+ unsigned int mask_32000,
|
||||
+ unsigned int mask_44100,
|
||||
+ unsigned int mask_48000)
|
||||
+{
|
||||
+ unsigned int rate_mask = 0;
|
||||
+
|
||||
+ if (sad[1] & SAD1_RATE_32000_MASK)
|
||||
+ rate_mask |= mask_32000;
|
||||
+ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
|
||||
+ rate_mask |= mask_44100;
|
||||
+ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
|
||||
+ rate_mask |= mask_48000;
|
||||
+ return rate_mask;
|
||||
+}
|
||||
+
|
||||
+static unsigned int sad_rate_mask(const u8 *sad)
|
||||
+{
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ return map_rate_families(sad,
|
||||
+ SAD1_RATE_32000_MASK,
|
||||
+ SAD1_RATE_44100_MASK,
|
||||
+ SAD1_RATE_48000_MASK);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return map_rate_families(sad,
|
||||
+ 0,
|
||||
+ SAD1_RATE_176400_MASK,
|
||||
+ SAD1_RATE_192000_MASK);
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
- return 1 + (sad[0] & 7);
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 2;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 8;
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
@@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
- rate_mask |= sad[1];
|
||||
+ rate_mask |= sad_rate_mask(sad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
- if (rate_mask & sad[1])
|
||||
+ if (rate_mask & sad_rate_mask(sad))
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
||||
--
|
||||
2.39.2
|
||||
|
@ -1,91 +0,0 @@
|
||||
From a2769637a9b98c6809d4d25a3a20447a3ff7b23a Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Fri, 19 Mar 2021 12:14:17 +0100
|
||||
Subject: [PATCH] ALSA: pcm: fix ELD constraints for some compressed audio
|
||||
formats
|
||||
|
||||
The SADs of compressed formats like AC3 and DTS contain the channel
|
||||
and sample rate info of the audio data inside the compressed stream,
|
||||
but when building constraints we must use the rates and formats used
|
||||
to pass through the stream. eg 2ch 48kHz for AC3.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/core/pcm_drm_eld.c | 38 +++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 35 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
|
||||
index 4b5faae5d16e5..e7ec7a8b9d420 100644
|
||||
--- a/sound/core/pcm_drm_eld.c
|
||||
+++ b/sound/core/pcm_drm_eld.c
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
+#include <linux/hdmi.h>
|
||||
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
@@ -17,9 +18,40 @@ static const unsigned int eld_rates[] = {
|
||||
192000,
|
||||
};
|
||||
|
||||
+static unsigned int sad_format(const u8 *sad)
|
||||
+{
|
||||
+ return (sad[0] & 0x78) >> 3;
|
||||
+}
|
||||
+
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
- return 1 + (sad[0] & 7);
|
||||
+ switch (sad_format(sad)) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 2;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 8;
|
||||
+ default:
|
||||
+ return 1 + (sad[0] & 7);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static unsigned int sad_rate_mask(const u8 *sad)
|
||||
+{
|
||||
+ switch (sad_format(sad)) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ return 0x07; // 32-48kHz
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 0x7f; // 32-192kHz
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 0x60; // 176.4, 192kHz
|
||||
+ default:
|
||||
+ return sad[1] & 0x7f;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
@@ -42,7 +74,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
- rate_mask |= sad[1];
|
||||
+ rate_mask |= sad_rate_mask(sad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +102,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
- if (rate_mask & sad[1])
|
||||
+ if (rate_mask & sad_rate_mask(sad))
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
||||
--
|
||||
2.20.1
|
||||
|
@ -0,0 +1,89 @@
|
||||
From 99586e3f502fcc4fdd21b621f3c87ae7a8f7c170 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 3 Jun 2023 12:12:28 +0200
|
||||
Subject: [PATCH 2/2] ASoC: hdmi-codec: don't set channel and speaker info for
|
||||
compressed formats
|
||||
|
||||
CTA 861 only mandates that the speaker allocation in the audio info frame
|
||||
is set for multichannel PCM formats. Likewise the number of channels in the
|
||||
audio infoframe is only relevant for PCM.
|
||||
|
||||
Some TVs won't decode compressed formats if the number of channels isn't
|
||||
set to 0 (refer to stream header) and the speaker allocation is set to the
|
||||
default 0 (FL and FR).
|
||||
|
||||
So fill in this info only for PCM audio and set it to 0 for compressed
|
||||
audio formats.
|
||||
|
||||
This also prevents hdmi_codec_prepare failing with an error when trying to
|
||||
play back DTS-HD or MLP (which is passed through as 8ch) if the sink only
|
||||
supports 2ch PCM and announces only FL/FR speaker support in the EDID.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/codecs/hdmi-codec.c | 36 +++++++++++++++++++++++------------
|
||||
1 file changed, 24 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
|
||||
index 0b1cdb2d60498..a192d985c5f18 100644
|
||||
--- a/sound/soc/codecs/hdmi-codec.c
|
||||
+++ b/sound/soc/codecs/hdmi-codec.c
|
||||
@@ -484,31 +484,43 @@ static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
|
||||
struct hdmi_codec_params *hp)
|
||||
{
|
||||
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
|
||||
- int idx;
|
||||
-
|
||||
- /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
- if (idx < 0) {
|
||||
- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
- idx);
|
||||
- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
- return idx;
|
||||
+ int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ u8 ca_id = 0;
|
||||
+ bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO);
|
||||
+
|
||||
+ if (pcm_audio) {
|
||||
+ /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
+
|
||||
+ if (idx < 0) {
|
||||
+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
+ idx);
|
||||
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ return idx;
|
||||
+ }
|
||||
+
|
||||
+ ca_id = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
}
|
||||
|
||||
memset(hp, 0, sizeof(*hp));
|
||||
|
||||
hdmi_audio_infoframe_init(&hp->cea);
|
||||
- hp->cea.channels = channels;
|
||||
+
|
||||
+ if (pcm_audio)
|
||||
+ hp->cea.channels = channels;
|
||||
+ else
|
||||
+ hp->cea.channels = 0;
|
||||
+
|
||||
hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
|
||||
hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
|
||||
hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
|
||||
- hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hp->cea.channel_allocation = ca_id;
|
||||
|
||||
hp->sample_width = sample_width;
|
||||
hp->sample_rate = sample_rate;
|
||||
hp->channels = channels;
|
||||
|
||||
- hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hcp->chmap_idx = idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.39.2
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.2sf"
|
||||
PKG_VERSION="20.2.1-Nexus"
|
||||
PKG_SHA256="247ad2d9e1df00304882b40d80bc8fd70a4efd2bf2613163c24177d36649247c"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.2sf"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.asap"
|
||||
PKG_VERSION="20.3.0-Nexus"
|
||||
PKG_SHA256="9f54285866766b80d0d0c5210561678579d396591ab16cf70c83c4968bfbc8ba"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.asap"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.dumb"
|
||||
PKG_VERSION="20.2.1-Nexus"
|
||||
PKG_SHA256="d2ef04e80645f0bd1c9d31c9633d2a27d1757198fbcd2d43d00c84889e6ae585"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.dumb"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.fluidsynth"
|
||||
PKG_VERSION="20.2.1-Nexus"
|
||||
PKG_SHA256="dd8ca6386a3beed360c1d2f989cd81553baf81652007fdfd478a28b44b68db10"
|
||||
PKG_REV="7"
|
||||
PKG_REV="6"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.fluidsynth"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.gme"
|
||||
PKG_VERSION="20.2.1-Nexus"
|
||||
PKG_SHA256="5aaec959e92f4af2684aa0439576d7f576f28a0a43f50439a6f38d0738792bdc"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.gme"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.gsf"
|
||||
PKG_VERSION="20.2.1-Nexus"
|
||||
PKG_SHA256="b09dcb379bdc536117a956b10b37cf50c8afaa65337993c44a6847d382d7e2a5"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.gsf"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.modplug"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="619ba20ea19dd9aea15e7d30aa12a146b412c7fcd9e709528f6758e82a3d85e7"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.modplug"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.ncsf"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="31b25846a9b8213306456eb6f8ab8fdaeede5cad35627e77aff2c422f370b211"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.ncsf"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.nosefart"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="2f7a92bfaddcd5aa63e2ea7348ae9eeefd07dee2aba46840ce5376677e2abc19"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.nosefart"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.openmpt"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="388fb4c9fcb5bd9edc978e3db5f54fa531c7f397393f3e421757e4e0de2d9c54"
|
||||
PKG_REV="7"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.openmpt"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.organya"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="df5db2c94161c7c578d672a8cc36bdbde6c345142c9bb5212759ad0dc30fd59d"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.organya"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.qsf"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="3116bb31b3fe53b85675ba664a7a8d5885e157940a4bcf57b96050844b11a377"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.qsf"
|
||||
|
@ -4,7 +4,7 @@
|
||||
PKG_NAME="audiodecoder.sacd"
|
||||
PKG_VERSION="20.3.0-Nexus"
|
||||
PKG_SHA256="6d54f6cf81e13aadcec1b43689551feba6e9426453a758d955e96348ba996277"
|
||||
PKG_REV="4"
|
||||
PKG_REV="3"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.sacd"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.sidplay"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="ab1f89237c91bc7157557f42dadcff50a7191eb7285ee668543defce9f1efcf2"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.sidplay"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.snesapu"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="f216a7d25c864986618118236c575687ab62d129a16cb1f73c15860948d9ac92"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.snesapu"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.ssf"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="c2d5fbba35d2d73ed5891567d507f77bc64fa447dfcb4474f5d58594e9a07b2d"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.ssf"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.stsound"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="a8138fb075a480c59d7041a9408eca6e52dc88f188daed519cd9e684b430f333"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.stsound"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.timidity"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="ef1b384090df3c2c78d00ed33de1d989ce802702b0a9aa13575946409a5cd0f1"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.timidity"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.upse"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="d9f75e5cbab3ba5fc391cb40e0585bf22fad0eebfaf002d1d58bc896b6f2a5d6"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.upse"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.usf"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="3ce9ef8823c773d894fd0018455ea5000e9b5a64f3cd8d66ddb4cf8f6c9ea836"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.usf"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.vgmstream"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="72367d7196f8049ef1fae426d32d3de1eac56bd4cb5a8fc38a6ba0c3da1b23d8"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.vgmstream"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audiodecoder.wsr"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="e8f8e06b61fbf612d59d689c38a6acade485aabae2382f3fbbedb0ce0c00048d"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audiodecoder.wsr"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audioencoder.flac"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="71daf8c35bbf644591600fef93412cd068a6bf6173d2258dc243ee04c8e5b091"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audioencoder.flac"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audioencoder.lame"
|
||||
PKG_VERSION="20.3.0-Nexus"
|
||||
PKG_SHA256="90f36ee0b4972669ed2876eae2502e58d86287aacdbf4bb25180aca01385e1c1"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audioencoder.lame"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audioencoder.vorbis"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="359e972ddcc498727620ff224a82f970fa2ae22b71ea6ab30b96898dffe6f1f9"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audioencoder.vorbis"
|
||||
|
@ -5,7 +5,7 @@
|
||||
PKG_NAME="audioencoder.wav"
|
||||
PKG_VERSION="20.2.0-Nexus"
|
||||
PKG_SHA256="1baf69cca688ebd389705ea2bef2c5285ba75dcfd0d0b534b6ab1e61c0020979"
|
||||
PKG_REV="6"
|
||||
PKG_REV="5"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/xbmc/audioencoder.wav"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.2048"
|
||||
PKG_VERSION="1.0.0.134-Nexus"
|
||||
PKG_SHA256="f07dc1cd34f9e2746ebf3fbf666f5301df49a9aa59760049a66aef953d514f87"
|
||||
PKG_VERSION="1.0.0.133-Nexus"
|
||||
PKG_SHA256="64263ff32d22ea0301b26137ce59b1e6e82026b4a6d130dc3fd9699624d36011"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
|
@ -1,17 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (C) 2023-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.81"
|
||||
PKG_VERSION="1.0.0.21-Nexus"
|
||||
PKG_SHA256="a66f10511ecc30c2c76f73c018b56a45bab9c6783d180910cc7363ec66748ea7"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv3"
|
||||
PKG_SITE="https://github.com/kodi-game/game.libretro.81"
|
||||
PKG_URL="https://github.com/kodi-game/game.libretro.81/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain kodi-platform libretro-81"
|
||||
PKG_SECTION=""
|
||||
PKG_LONGDESC="game.libretro.81: 81 for Kodi"
|
||||
|
||||
PKG_IS_ADDON="yes"
|
||||
PKG_ADDON_TYPE="kodi.gameclient"
|
@ -1,17 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (C) 2023-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.a5200"
|
||||
PKG_VERSION="2.0.2.4-Nexus"
|
||||
PKG_SHA256="a0b1805581f244c2e0300f0821f96b93be017abc10813a9b8eb3c43da570c231"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="https://github.com/kodi-game/game.libretro.a5200"
|
||||
PKG_URL="https://github.com/kodi-game/game.libretro.a5200/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain kodi-platform libretro-a5200"
|
||||
PKG_SECTION=""
|
||||
PKG_LONGDESC="game.libretro.a5200: a5200 for Kodi"
|
||||
|
||||
PKG_IS_ADDON="yes"
|
||||
PKG_ADDON_TYPE="kodi.gameclient"
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.atari800"
|
||||
PKG_VERSION="3.1.0.25-Nexus"
|
||||
PKG_SHA256="dbd6c5719e5cb88841e213d7389d9416e6e623d6d09615f92c53c871045bf70a"
|
||||
PKG_VERSION="3.1.0.23-Nexus"
|
||||
PKG_SHA256="4839836a4bf8a461d9554ad4920c0e45e89a384149abc6e82d847f74208f28cc"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
|
@ -2,10 +2,10 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.beetle-bsnes"
|
||||
PKG_VERSION="0.9.26.24-Nexus"
|
||||
PKG_SHA256="fc356984fba343651d4c8a77834f2f5e6e86d4fcd78ab967de451abdf3e99816"
|
||||
PKG_VERSION="0.9.26.23-Nexus"
|
||||
PKG_SHA256="8f7830c484f5da5726fae1210c5cfe03ac1493c99a27cb9086f5b019052c688d"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="x86_64"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/kodi-game/game.libretro.beetle-bsnes"
|
||||
PKG_URL="https://github.com/kodi-game/game.libretro.beetle-bsnes/archive/${PKG_VERSION}.tar.gz"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.beetle-gba"
|
||||
PKG_VERSION="0.9.36.24-Nexus"
|
||||
PKG_SHA256="8b55b9936af1b61b66b3e15d512a5d3e701f70caabefd4b442ec40c535e88d4b"
|
||||
PKG_VERSION="0.9.36.23-Nexus"
|
||||
PKG_SHA256="f16c4faf9e52c75a20239854d76b678b1b6ab1dad354b34043941e4b0f08bb39"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="game.libretro.beetle-lynx"
|
||||
PKG_VERSION="1.24.0.47-Nexus"
|
||||
PKG_SHA256="54ce67dc0ac86842918b4e58d58b14f959128a1452dc72104a890bf60289ce2d"
|
||||
PKG_VERSION="1.24.0.43-Nexus"
|
||||
PKG_SHA256="63528c7ed0dabf79dc7e67228472d16da589ed49a9ab947966c1fee76c2936cb"
|
||||
PKG_REV="1"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user