feat(librepods): backport PR #519 for AirPods Max 2 support#178
Conversation
Recognise AirPods Max 2nd Gen (BLE id 0x2D20, model A3454) so the Linux Qt client gives it the Max icon and the single-headset battery layout instead of falling through to the unknown-model defaults. The patch is the squashed end-state diff of upstream PR kavishdevar/librepods#519, with paths rewritten relative to `linux/` (the nixpkgs derivation's `sourceRoot`) and the docs-only `Proximity Pairing Message.md` change omitted. Drop the patch once upstream merges PR #519 and a release shipping it is pinned. Allow `ANC` (Active Noise Cancellation) in `.typos.toml` so the patch file's `AirPods4ANC` enum value does not trip the spell-check hook. Validation: - nix flake check --accept-flake-config --no-build --offline - nix build .#nixosConfigurations.system76.pkgs.librepods - strings $out/bin/.librepods-wrapped | rg 'AirPodsMax2|A3454' -> both present
|
Claude finished @Bad3r's task in 2m 45s —— View job Claude PR Review
Verdict: LGTM. Small, faithful, well-documented backport. The four code hunks are byte-identical to upstream PR #519 (verified via Code quality
Correctness concerns (none blocking)
Minor nits (optional)
Testing
Maintenance hookOnce upstream PR #519 merges and a librepods release pinning it ships in nixpkgs (or in your overlay's version bump), drop:
The overlay comment already records this. ✓ --- · Branch |
There was a problem hiding this comment.
Code Review
This pull request introduces support for AirPods Max 2 by adding a backported patch to the librepods package and updating the Nix overlay. The review identifies that the backport is incomplete as it lacks updates to the toString function, which may cause display issues in the UI. Additionally, it is recommended to explicitly define the patches list in the Nix overlay rather than appending to the existing list to prevent the inheritance of incompatible patches from previous versions.
Two AirPods Max follow-ups on top of the PR #519 backport: 1. Stop the QQuickImage warning about `qrc:/icons/assets/max_case.png is not installed`. Upstream librepods never shipped the asset and there is no canonical Apple artwork for it (AirPods Max has no charging case, just a non-electronic Smart Case sleeve), so the case PodColumn is hidden anyway via `caseAvailable`. The QML engine still resolves the dangling `iconSource` URL on creation, hence the warning. Point the case slot at the existing `podmax.png` so the image resolves; the column stays hidden in normal operation but no longer trips the loader. 2. Disable WirePlumber's SBC-XQ codec for all bluetooth sinks. The AirPods Max 2 reporter on PR #519 traced left-channel-only audio to SBC-XQ negotiation; the same workaround is documented there. The property `bluez5.enable-sbc-xq` is daemon-wide in WirePlumber's bluez monitor, so this matches the upstream workaround's scope. Other sinks fall back to plain SBC (or AAC where supported), which is the codec all non-Max AirPods and most generic bluetooth speakers default to. Validation: - nix flake check --accept-flake-config --no-build --offline -> all checks passed - nix build .#nixosConfigurations.system76.pkgs.librepods -> rebuilt - strings $out/bin/.librepods-wrapped | rg max_case -> no matches (fixed) - strings $out/bin/.librepods-wrapped | rg 'AirPodsMax2|A3454' -> 2 matches (preserved)
|
Claude finished @Bad3r's task in 2m 11s —— View job Re-review after gemini-code-assist commentsBoth gemini comments are addressed below. Short version: the toString concern is incorrect (no such hunk in upstream PR #519 and no
gemini comment 1 — "missing toString hunk in enums.h": INCORRECT, no change neededI pulled upstream PR #519's file list via I also fetched gemini comment 2 — "explicitly define
|
The truncated `#issuecomment` URL fragment lacked the comment id, so clicking it scrolled to the top of PR #519 instead of the workaround report. Pin to issuecomment-4230312279 (the comment that documents the left-channel-only audio bug and `bluez5.enable-sbc-xq = false` fix).
"Paths are rooted at `linux/`" was ambiguous: the patch entries do not actually contain a `linux/` prefix. Reword to make explicit that paths are relative to the `linux/` build root selected by `sourceRoot`, and spell out the upstream-to-patch path mapping so a future maintainer diffing this against PR #519 can see why the prefix is stripped.
Review pass: addressed and rejected itemsWorked through every reviewer comment, validated each against the upstream sources, and split the accepted changes into two atomic commits (pushed in a moment so this reply lands first per request). Accepted (with implementation)1. Source: Claude review, "consider also linking the upstream WirePlumber issue (or PR for per-device opt-out)" plus a follow-up audit of the existing reference. Found that the comment in Searched for an upstream WirePlumber issue tracking per-device SBC-XQ opt-out (GitHub via 2. Source: Claude first-review nit, "Slightly ambiguous -- the patch paths don't include a Reworded the patch header from "Paths are rooted at Rejected (with rationale, threads resolved)Gemini #1 (high) -- "missing
Gemini #2 (medium) -- "explicitly define Verified against Out of scope, not acted on
Validation |
|
Claude finished @Bad3r's task in 1m 34s —— View job Re-review after Bad3r's reply + clarification commits
Verdict: LGTM, ready to merge. Both clarification commits land exactly what the prior reviews flagged, and the rejection rationale on the gemini items checks out against upstream sources.
|
Summary
modules/base/custom-packages-overlay.nixso AirPods Max 2nd Gen (BLE id0x2D20, modelA3454) is recognised by the Linux Qt client.Unknownenum branch: it gets the generic pod icon, the dual-stem battery layout (which doesn't match a single-headset device), and BLE scans report it as an unknown model id.packages/librepods/airpods-max-2.patchand is wired into the existingprev.librepods.overrideAttrsblock viapatches = (old.patches or [ ]) ++ [ ../../packages/librepods/airpods-max-2.patch ];.linux/because the nixpkgs librepods derivation setssourceRoot = "source/linux". The upstream PR'sProximity Pairing Message.mddocs change is intentionally omitted because it lives outside the build root and has no runtime effect..typos.tomlgains anANC = "ANC"entry (Active Noise Cancellation) so the patch'sAirPods4ANCenum value does not trip the spell-check hook.Test plan
nix flake check --accept-flake-config --no-build --offline→ all checks passednix build .#nixosConfigurations.system76.pkgs.librepods→ builds cleanly with the patch appliedstrings $out/bin/.librepods-wrapped | rg 'AirPodsMax2|A3454'→ both symbols present in the resulting binary, confirming the patch's enum and model-number additions made it into the build output