-
-
Save jpasquier/65e95707089f79d9406fa8e7f9e96eb0 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| set -euo pipefail | |
| # ── Preconditions ──────────────────────────────────────────────────────────── | |
| need() { command -v "$1" >/dev/null 2>&1 || { echo "$1 is required." >&2; exit 1; }; } | |
| need docker | |
| need dpkg-deb | |
| need fakeroot | |
| need dpkg-architecture | |
| if ! docker info > /dev/null 2>&1; then | |
| echo "This script uses docker, and it isn't running - please start docker and try again!" >&2 | |
| exit 1 | |
| fi | |
| # ── Detect versions from the system ────────────────────────────────────────── | |
| # Prefer the installed libspa-0.2-bluetooth version; fallback to pipewire if needed. | |
| DEB_VER="$(dpkg-query -W -f='${Version}\n' libspa-0.2-bluetooth 2>/dev/null || true)" | |
| if [ -z "${DEB_VER}" ] || [ "${DEB_VER}" = "unknown" ]; then | |
| DEB_VER="$(dpkg-query -W -f='${Version}\n' pipewire 2>/dev/null || true)" | |
| fi | |
| if [ -z "${DEB_VER}" ] || [ "${DEB_VER}" = "unknown" ]; then | |
| echo "Could not detect installed PipeWire/SPA version (libspa-0.2-bluetooth or pipewire). Install PipeWire first." >&2 | |
| exit 1 | |
| fi | |
| # Upstream tarball version (strip Debian revision like '-1', '-1+b1', etc.) | |
| UPSTREAM_VER="${DEB_VER%%-*}" | |
| # Some Debian versions may not have a hyphen; ensure UPSTREAM_VER non-empty. | |
| if [ -z "${UPSTREAM_VER}" ]; then | |
| UPSTREAM_VER="${DEB_VER}" | |
| fi | |
| # ── Setup ──────────────────────────────────────────────────────────────────── | |
| CURRENT_DIR="$(pwd)" | |
| BUILD_DIR="$(mktemp -d "${TMPDIR:-/tmp}/build-pipewire-aac.XXXXXXXX")" | |
| trap 'rm -rf "$BUILD_DIR"' EXIT | |
| IMAGE_NAME="pipewire-aac" | |
| CONTAINER_NAME="pipewire-aac" | |
| # Architecture / multiarch triplet | |
| ARCH="$(dpkg --print-architecture 2>/dev/null || echo amd64)" | |
| TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null || gcc -dumpmachine || echo "${ARCH}-linux-gnu")" | |
| echo "Detected libspa/pipewire version:" | |
| echo " Debian package version: ${DEB_VER}" | |
| echo " Upstream (tarball) ver: ${UPSTREAM_VER}" | |
| echo | |
| # ── Dockerfile ─────────────────────────────────────────────────────────────── | |
| # Keep variables inside the Dockerfile literal (use ARG/ENV inside Dockerfile). | |
| cat > "$BUILD_DIR/Dockerfile" << 'EOL' | |
| FROM debian:trixie-slim | |
| ARG PIPEWIRE_VER | |
| ENV PIPEWIRE_VER=${PIPEWIRE_VER} | |
| ENV DEBIAN_FRONTEND=noninteractive | |
| ENV USER=pipewire | |
| # Enable contrib + non-free (+ non-free-firmware) for trixie | |
| RUN printf "deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware\n\ | |
| deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware\n\ | |
| deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware\n" > /etc/apt/sources.list | |
| # Update and install necessary dependencies (build + fetch tools) | |
| RUN apt-get update && apt-get install -y \ | |
| build-essential \ | |
| meson ninja-build pkgconf \ | |
| libbluetooth-dev \ | |
| libasound2-dev \ | |
| libdbus-1-dev \ | |
| libglib2.0-dev \ | |
| libudev-dev \ | |
| libsbc-dev \ | |
| libopus-dev \ | |
| liblc3-dev \ | |
| libldacbt-enc-dev \ | |
| libfdk-aac-dev \ | |
| git \ | |
| wget \ | |
| python3 \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Create a non-root user and a drop location for the built .so | |
| RUN useradd -ms /bin/bash "$USER" \ | |
| && mkdir /pipewire-aac \ | |
| && chown "$USER":"$USER" /pipewire-aac | |
| USER $USER | |
| WORKDIR /home/$USER | |
| # Fetch the exact upstream PipeWire tarball | |
| RUN mkdir -p /home/$USER/build/pipewire-aac | |
| WORKDIR /home/$USER/build/pipewire-aac | |
| RUN wget -O pipewire_${PIPEWIRE_VER}.orig.tar.bz2 \ | |
| "https://deb.debian.org/debian/pool/main/p/pipewire/pipewire_${PIPEWIRE_VER}.orig.tar.bz2" | |
| RUN tar xf pipewire_${PIPEWIRE_VER}.orig.tar.bz2 | |
| WORKDIR /home/$USER/build/pipewire-aac/pipewire-${PIPEWIRE_VER} | |
| # Configure only the BlueZ5 AAC codec and build | |
| RUN meson setup build \ | |
| -Dbluez5=enabled \ | |
| -Dbluez5-codec-aac=enabled | |
| RUN ninja -C build | |
| # Copy the built library to the shared location (robust to path changes) | |
| RUN bash -lc 'set -euo pipefail; \ | |
| f=$(find build -type f -name libspa-codec-bluez5-aac.so | head -n1); \ | |
| if [ -z "$f" ]; then \ | |
| echo "libspa-codec-bluez5-aac.so not found under build/"; \ | |
| echo "Available bluez5 codec artifacts:"; \ | |
| find build -type f -name "libspa-codec-bluez5-*.so" -print || true; \ | |
| exit 1; \ | |
| fi; \ | |
| install -Dm644 "$f" /pipewire-aac/libspa-codec-bluez5-aac.so; \ | |
| ls -l /pipewire-aac/libspa-codec-bluez5-aac.so' | |
| EOL | |
| # ── Build and extract ──────────────────────────────────────────────────────── | |
| docker build --network=host --build-arg "PIPEWIRE_VER=${UPSTREAM_VER}" -t "$IMAGE_NAME" "$BUILD_DIR" | |
| # Create a container and run it (it will exit immediately, which is fine for docker cp) | |
| docker run --name "$CONTAINER_NAME" "$IMAGE_NAME" || true | |
| # Copy the binary from the container to the BUILD_DIR | |
| docker cp "$CONTAINER_NAME":/pipewire-aac/libspa-codec-bluez5-aac.so "$BUILD_DIR/" | |
| # Stop and remove the container; remove the image | |
| docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true | |
| docker image rm "$IMAGE_NAME" >/dev/null 2>&1 || true | |
| # Ensure the .so exists | |
| if [ ! -f "$BUILD_DIR/libspa-codec-bluez5-aac.so" ]; then | |
| echo "Failed to extract libspa-codec-bluez5-aac.so from the container." >&2 | |
| exit 1 | |
| fi | |
| # Fix ownership if run with sudo | |
| if [ "${SUDO_USER:-}" != "" ] && [ "$EUID" -eq 0 ]; then | |
| chown "$SUDO_USER:$SUDO_USER" "$BUILD_DIR/libspa-codec-bluez5-aac.so" | |
| fi | |
| # ── Package .deb ───────────────────────────────────────────────────────────── | |
| PKG_NAME="libspa-codec-bluez5-aac_${UPSTREAM_VER}_${ARCH}" | |
| PKG_DIR="$BUILD_DIR/$PKG_NAME" | |
| mkdir -p "$PKG_DIR/DEBIAN" \ | |
| "$PKG_DIR/usr/lib/$TRIPLET/spa-0.2/bluez5" | |
| # Place the built .so in the Debian-expected location | |
| cp "$BUILD_DIR/libspa-codec-bluez5-aac.so" \ | |
| "$PKG_DIR/usr/lib/$TRIPLET/spa-0.2/bluez5/libspa-codec-bluez5-aac.so" | |
| # Control file | |
| # - Package version = upstream (e.g., 1.4.2) — it's the plugin's build version. | |
| # - Depends on libspa-0.2-bluetooth (>= DEB_VER) to match the exact ABI we built against. | |
| cat > "$PKG_DIR/DEBIAN/control" <<CTRL | |
| Package: libspa-codec-bluez5-aac | |
| Version: ${UPSTREAM_VER} | |
| Section: libs | |
| Priority: optional | |
| Architecture: ${ARCH} | |
| Depends: libfdk-aac2t64 (>= 2.0.3), libspa-0.2-bluetooth (>= ${DEB_VER}) | |
| Maintainer: Your Name <you@example.com> | |
| Description: AAC codec plugin for PipeWire BlueZ5 (built from PipeWire ${UPSTREAM_VER}) | |
| Installs /usr/lib/${TRIPLET}/spa-0.2/bluez5/libspa-codec-bluez5-aac.so | |
| CTRL | |
| # Build the package | |
| fakeroot dpkg-deb --build "$PKG_DIR" >/dev/null | |
| # Move final .deb to the original working directory | |
| FINAL_DEB="${PKG_DIR}.deb" | |
| mv -f "$FINAL_DEB" "$CURRENT_DIR/" | |
| # Fix ownership of the .deb if run with sudo | |
| if [ "${SUDO_USER:-}" != "" ] && [ "$EUID" -eq 0 ]; then | |
| chown "$SUDO_USER:$SUDO_USER" "$CURRENT_DIR/$(basename "$FINAL_DEB")" | |
| fi | |
| echo | |
| echo "✅ Built: $(basename "$FINAL_DEB")" | |
| echo " Location: $CURRENT_DIR/$(basename "$FINAL_DEB")" | |
| echo " To install: sudo apt install ./$(basename "$FINAL_DEB")" |
Hello, the script only builds a Debian package. When the package is built, you still have to install it with sudo apt install ./libspa-codec-bluez5-aac_0.3.65_amd64.deb. After that, you're done.
Has this been tested on Debian 13 (Trixie)? I followed a different guide to install the aac.so file but since upgrading from 12 to 13 i have yet been able to get the aac codec working again.
i chose to be the guinea pig, appears i had already tried your script, no luck it seems.
user@debian:~/Downloads/bluez5$ sudo ./build-aac.sh
--2025-09-28 18:47:12-- https://ppa.launchpadcontent.net/aglasgall/pipewire-extra-bt-codecs/ubuntu/pool/main/p/pipewire/libspa-0.2-bluetooth_0.3.65-4%7Eglasgall1_amd64.deb
Resolving ppa.launchpadcontent.net (ppa.launchpadcontent.net)... 185.125.190.80, 2620:2d:4000:1::81
Connecting to ppa.launchpadcontent.net (ppa.launchpadcontent.net)|185.125.190.80|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 341944 (334K) [application/x-debian-package]
Saving to: ‘libspa-0.2-bluetooth_0.3.65-4~glasgall1_amd64.deb’
libspa-0.2-bluetooth_0.3.65-4~glasgall1_amd64.deb 100%[==========================================================================================================>] 333.93K 724KB/s in 0.5s
2025-09-28 18:47:14 (724 KB/s) - ‘libspa-0.2-bluetooth_0.3.65-4~glasgall1_amd64.deb’ saved [341944/341944]
dpkg-deb: building package 'libspa-codec-bluez5-aac' in 'libspa-codec-bluez5-aac_0.3.65_amd64.deb'.
user@debian:~/Downloads/bluez5$ ls
total 40
drwxrwxr-x 3 user user 4096 Sep 28 18:47 .
drwxr-xr-x 16 user user 12288 Sep 28 18:37 ..
drwxr-xr-x 24 user user 4096 Sep 28 12:26 bluez-5.66
-rwxrwxr-x 1 user user 1118 Sep 28 18:46 build-aac.sh
-rw-r--r-- 1 root root 12632 Sep 28 18:47 libspa-codec-bluez5-aac_0.3.65_amd64.deb
user@debian:~/Downloads/bluez5$ sudo apt install libsp
Display all 120 possibilities? (y or n)^C
user@debian:~/Downloads/bluez5$ ^C
user@debian:~/Downloads/bluez5$ sudo apt install libspa
libspa-0.2-bluetooth libspa-0.2-libcamera libspandsp2t64 libsparsehash-dev libspatial4j-0.4-java libspatialaudio-dev libspatialindex-dev
libspa-0.2-dev libspa-0.2-modules libspandsp-dev libsparskit2.0 libspatial4j-java libspatialindex8 libspatialite8t64
libspa-0.2-jack libspa-codec-bluez5-aac libspandsp-doc libsparskit-dev libspatialaudio0t64 libspatialindex-c8 libspatialite-dev
user@debian:~/Downloads/bluez5$ sudo apt install ./libspa-codec-bluez5-aac_0.3.65_amd64.deb
Note, selecting 'libspa-codec-bluez5-aac' instead of './libspa-codec-bluez5-aac_0.3.65_amd64.deb'
libspa-codec-bluez5-aac is already the newest version (0.3.65).
Summary:
Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
user@debian:~/Downloads/bluez5$ sudo apt reinstall ./libspa-codec-bluez5-aac_0.3.65_amd64.deb
Note, selecting 'libspa-codec-bluez5-aac' instead of './libspa-codec-bluez5-aac_0.3.65_amd64.deb'
Summary:
Upgrading: 0, Installing: 0, Reinstalling: 1, Removing: 0, Not Upgrading: 0
Download size: 0 B / 12.6 kB
Space needed: 0 B / 55.3 GB available
Get:1 /home/user/Downloads/bluez5/libspa-codec-bluez5-aac_0.3.65_amd64.deb libspa-codec-bluez5-aac amd64 0.3.65 [12.6 kB]
(Reading database ... 475985 files and directories currently installed.)
Preparing to unpack .../libspa-codec-bluez5-aac_0.3.65_amd64.deb ...
Unpacking libspa-codec-bluez5-aac:amd64 (0.3.65) over (0.3.65) ...
Setting up libspa-codec-bluez5-aac:amd64 (0.3.65) ...
Notice: Download is performed unsandboxed as root as file '/home/user/Downloads/bluez5/libspa-codec-bluez5-aac_0.3.65_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
I suppose that the library has been updated upstream. Somebody proposed an updated version based on my gist: https://blog.fernvenue.com/archives/airpods-pro-2-on-debian/. Thanks to him/her.
I face the same issue as @BugZappa; the AAC codec doesn't show.
I suppose that the library has been updated upstream. Somebody proposed an updated version based on my gist: https://blog.fernvenue.com/archives/airpods-pro-2-on-debian/. Thanks to him/her.
@jpasquier There is no update in this blog with respect your gist. Moreover, the author should have reported the commands evoked by @tlk which would have been better, e.g., if you plan to update your gist.
For now, I guess we have to follow these steps. If someone can detail those steps to rebuild libspa-codec-bluez5-aac*.deb from scratch under Debian, it would be helpful.
wireplumber| Dependency libpipewire-0.3 found: NO found 0.3.65 but need: '>= 1.0.2' (overridden)
subprojects/wireplumber/meson.build:72:15: ERROR: Dependency 'libpipewire-0.3' is required but not found.
A full log can be found at /home/pipewire/build/pipewire-aac/pipewire-0.3.65/build/meson-logs/meson-log.txt
The command '/bin/sh -c meson setup build -Dbluez5=enabled -Dbluez5-codec-aac=enabled' returned a non-zero code: 1
Please HELP!!!
cat /etc/debian_version
12.12

is it enough to run the script one time? or need i run it every time when i connect my wireless headphone or when i restart my Pc