Unverified Commit 277f8e10 authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

music-assistant: replace all pre-compiled binaries, music-assistant: bring...

 music-assistant: replace all pre-compiled binaries,  music-assistant: bring back airplay support  (#492341)
parents 3ec6e174 fbe6eb95
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ let
    ;

  inherit (types)
    bool
    listOf
    enum
    str
@@ -54,6 +55,15 @@ in
      '';
    };

    openFirewall = lib.mkOption {
      type = bool;
      default = false;
      description = ''
        Whether to open required ports for the configured providers.
        Currently airplay and sendspin need port to be opened to function.
      '';
    };

    providers = mkOption {
      type = listOf (enum cfg.package.providerNames);
      default = [ ];
@@ -68,6 +78,31 @@ in
  };

  config = mkIf cfg.enable {
    networking.firewall = lib.mkIf cfg.openFirewall {
      allowedTCPPorts =
        lib.optional cfg.enable 8097 # Music Assistant stream port
        ++ lib.optional (lib.elem "airplay" cfg.providers) 7000
        ++ lib.optional (lib.elem "sendspin" cfg.providers) 8927;
      # The information published by Apple 1 seem to not apply to libraop.
      # The closest we could find that represents the port range being used as observed by tcpdump is the ephemeral port range.
      # 1: https://support.apple.com/en-us/103229#:~:text=49152%E2%80%93-,65535,-TCP%2C%20UDP
      # 2: https://en.wikipedia.org/wiki/Ephemeral_port#Range
      allowedUDPPortRanges = lib.mkIf (lib.elem "airplay" cfg.providers) [
        {
          from = 32768;
          to = 65535;
        }
      ];
    };

    services.avahi = lib.mkIf (lib.elem "airplay_receiver" cfg.providers) {
      enable = true;
      publish = {
        enable = true;
        userServices = true;
      };
    };

    systemd.services.music-assistant = {
      description = "Music Assistant";
      documentation = [ "https://music-assistant.io" ];
@@ -87,6 +122,13 @@ in
        [
          lsof
        ]
        ++ lib.optionals (lib.elem "airplay" cfg.providers) [
          cliairplay
          libraop
        ]
        ++ lib.optionals (lib.elem "airplay_receiver" cfg.providers) [
          shairport-sync
        ]
        ++ lib.optionals (lib.elem "spotify" cfg.providers) [
          librespot-ma
        ]
+81 −0
Original line number Diff line number Diff line
{
  lib,
  autoreconfHook,
  bison,
  curl,
  fetchFromGitHub,
  fetchpatch,
  ffmpeg-headless,
  flex,
  gperf,
  json_c,
  libconfuse,
  libevent,
  libgcrypt,
  libgpg-error,
  libplist,
  libsodium,
  libunistring,
  libuuid,
  libxml2,
  pkg-config,
  stdenv,
  zlib,
}:

stdenv.mkDerivation {
  pname = "cliairplay";
  # see the beginning of configure.ac for the upstream version number
  version = "0.2-unstable-2025-12-30";

  src = fetchFromGitHub {
    owner = "music-assistant";
    repo = "cliairplay";
    # we try to closely match the commit used in the last music-assistant release from
    # https://github.com/music-assistant/server/tree/stable/music_assistant/providers/airplay/bin
    rev = "4660d886585d6bf8f32e889feec2a0e8975c51dc";
    fetchSubmodules = true;
    hash = "sha256-oDStn9LdLYWKhZNm7Qfdibs4qsct8gE3RZbTKooQeOM=";
  };

  patches = [
    # Support gettext 0.25
    (fetchpatch {
      url = "https://github.com/music-assistant/cliairplay/commit/92a2445d64c476d740feba1f31c7e5bc768701b7.patch";
      hash = "sha256-/YnopvAGHHnQhfr2X1OenLMoF4ZlUq9x8tQZha/XfbQ=";
    })
  ];

  nativeBuildInputs = [
    autoreconfHook
    bison
    flex
    gperf
    pkg-config
  ];

  buildInputs = [
    curl
    ffmpeg-headless
    json_c
    libconfuse
    libevent
    libgcrypt
    libgpg-error
    libplist
    libsodium
    libunistring
    libuuid
    libxml2
    zlib
  ];

  meta = {
    description = "Command line interface for audio streaming to AirPlay 2 devices";
    homepage = "https://github.com/music-assistant/cliairplay";
    license = lib.licenses.gpl2Plus;
    maintainers = with lib.maintainers; [ SuperSandro2000 ];
    mainProgram = "cliap2";
    platforms = lib.platforms.unix;
  };
}
+15 −0
Original line number Diff line number Diff line
diff --git a/Makefile b/Makefile
index 7d735b8..c3ea73a 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,9 @@ OBJECTS_BIN += $(patsubst %.cpp,$(BUILDDIR)/%.o,$(filter %.cpp,$(SOURCES_BIN)))
 
 LIBRARY	= $(CODECS)/$(HOST)/$(PLATFORM)/libcodecs.a $(MDNS)/$(HOST)/$(PLATFORM)/libmdns.a
 
-ifneq ($(STATIC),)
+ifeq ($(STATIC),)
+LDFLAGS += -lcrypto
+else
 LIBRARY	+= $(OPENSSL)/libopenssl.a
 DEFINES += -DSSL_STATIC_LIB
 endif
+83 −0
Original line number Diff line number Diff line
{
  lib,
  fetchFromGitHub,
  openssl,
  stdenv,
}:

let
  host =
    if stdenv.hostPlatform.isLinux then
      "linux"
    else if stdenv.hostPlatform.isDarwin then
      "macos"
    else
      throw "libraop does not support this platform, yet";
in
stdenv.mkDerivation {
  pname = "libraop";
  version = "0-unstable-2026-02-09";

  src = fetchFromGitHub {
    owner = "music-assistant";
    repo = "libraop";
    # we try to closely match the commit used in the last music-assistant release from
    # https://github.com/music-assistant/server/tree/stable/music_assistant/providers/airplay/bin
    rev = "f49284282ea4ea740d07fabc230b4182f8c69a74";
    fetchSubmodules = true;
    hash = "sha256-m1ll5vRZx4d/5IWCG24yY/SWEIIz2k/iU84vQKHlCdo=";
  };

  patches = [
    # https://github.com/philippe44/libraop/pull/48
    ./link-libssl.diff
  ];

  postPatch = ''
    # the most security critical part we build ourself
    rm -r libopenssl/

    # do not confuse the prebuilt binaries with the ones we build
    rm bin/*

    # easen debugging and we strip ourselves, too
    substituteInPlace Makefile \
      --replace-fail "LDFLAGS += -s" "LDFLAGS +="
  ''
  + lib.optionalString stdenv.hostPlatform.isDarwin ''
    # on darwin the direct dlopen to system libcrypto crashes with
    # WARNING: /nix/store/.../bin/cliraop is loading libcrypto in an unsafe way
    # Abort trap: 6
    substituteInPlace crosstools/src/cross_ssl.c \
      --replace-fail '"libcrypto.dylib"' '"${lib.getLib openssl}/lib/libcrypto.dylib"' \
      --replace-fail '"libssl.dylib"' '"${lib.getLib openssl}/lib/libssl.dylib"'
  '';

  buildInputs = [
    openssl
  ];

  makeFlags = [
    "HOST=${host}"
    "PLATFORM=${stdenv.hostPlatform.uname.processor}"
  ];

  installPhase = ''
    mkdir -p $out/bin
    cp bin/cliraop-${host}-${stdenv.hostPlatform.uname.processor} $out/bin/cliraop
  '';

  meta = {
    description = "RAOP player and library (AirPlay)";
    homepage = "https://github.com/music-assistant/libraop";
    # https://github.com/philippe44/libraop/issues/36
    license = with lib.licenses; [
      gpl2Only
      mit
    ];
    maintainers = with lib.maintainers; [ SuperSandro2000 ];
    mainProgram = "cliraop";
    platforms = with lib.platforms; linux ++ darwin;
    sourceProvenance = [ lib.sourceTypes.binaryNativeCode ];
  };
}
+29 −0
Original line number Diff line number Diff line
diff --git a/music_assistant/providers/airplay/helpers.py b/music_assistant/providers/airplay/helpers.py
index c5fef7eb..a628622d 100644
--- a/music_assistant/providers/airplay/helpers.py
+++ b/music_assistant/providers/airplay/helpers.py
@@ -6,6 +6,7 @@
 import os
 import platform
 import time
+from shutil import which
 from typing import TYPE_CHECKING
 
 from zeroconf import IPVersion
@@ -176,7 +177,6 @@ async def check_binary(cli_path: str) -> str | None:
             pass
         return None
 
-    base_path = os.path.join(os.path.dirname(__file__), "bin")
     system = platform.system().lower().replace("darwin", "macos")
     architecture = platform.machine().lower()
 
@@ -188,7 +188,7 @@ async def check_binary(cli_path: str) -> str | None:
         raise RuntimeError(f"Unsupported streaming protocol requested: {protocol}")
 
     if bridge_binary := await check_binary(
-        os.path.join(base_path, f"{package}-{system}-{architecture}")
+        which(package)
     ):
         return bridge_binary
 
Loading