{"object_kind":"push","event_name":"push","before":"55cc4f0dec1ec4fd09de95020a180251d082e881","after":"4abf320c6d3b3a0f83f8c493a2cec3636a0325fb","ref":"refs/heads/master","ref_protected":true,"checkout_sha":"4abf320c6d3b3a0f83f8c493a2cec3636a0325fb","message":null,"user_id":3060,"user_name":"Wim Taymans","user_username":"wtaymans","user_email":"[REDACTED]","user_avatar":"https://secure.gravatar.com/avatar/1ca1bed246cb9b95b7ead6d6be96bb09f0c112953140c8bb38b41aedf4465270?s=80&d=identicon","project_id":4753,"project":{"id":4753,"name":"pipewire","description":"Multimedia processing graphs","web_url":"https://gitlab.freedesktop.org/pipewire/pipewire","avatar_url":"https://gitlab.freedesktop.org/uploads/-/system/project/avatar/4753/pipewire.png?v=1792592238","git_ssh_url":"git@ssh.gitlab.freedesktop.org:pipewire/pipewire.git","git_http_url":"https://gitlab.freedesktop.org/pipewire/pipewire.git","namespace":"PipeWire","visibility_level":20,"path_with_namespace":"pipewire/pipewire","default_branch":"master","ci_config_path":"","homepage":"https://gitlab.freedesktop.org/pipewire/pipewire","url":"git@ssh.gitlab.freedesktop.org:pipewire/pipewire.git","ssh_url":"git@ssh.gitlab.freedesktop.org:pipewire/pipewire.git","http_url":"https://gitlab.freedesktop.org/pipewire/pipewire.git"},"commits":[{"id":"c384ae2c54704941af42f3200a3e74b86bb0ba95","message":"module-raop-sink: prefix the legacy RAOP RTSP handlers with raop_\n\nNamespace the AirPlay 1 / RAOP RTSP request and reply handlers (announce,\nauth-setup, options, ...) with a raop_ prefix so the AirPlay 2 handlers added\nnext do not collide with them.\n\ntest-auth.c compiles module-raop-sink.c directly and calls the OPTIONS and\nauth-setup handlers by name, so update it to the new names.\n\nAssisted-by: LLM\n","title":"module-raop-sink: prefix the legacy RAOP RTSP handlers with raop_","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/c384ae2c54704941af42f3200a3e74b86bb0ba95","author":{"name":"Christian Glombek","email":"lorbus@fedoraproject.org"},"added":[],"modified":["src/modules/module-raop-sink.c","src/modules/module-raop/test-auth.c"],"removed":[]},{"id":"7eea284de6d1436640b951beaf400d13a84fe0e6","message":"module-raop: add the AirPlay 2 TLV8 codec\n\nHomeKit Accessory Protocol (HAP) TLV8 encode/decode with the AirPlay 2 pairing\nitem types and error codes, used by the pair-setup/pair-verify handshakes.\n\nAssisted-by: LLM\n","title":"module-raop: add the AirPlay 2 TLV8 codec","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/7eea284de6d1436640b951beaf400d13a84fe0e6","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":["src/modules/module-raop/tlv.c","src/modules/module-raop/tlv.h"],"modified":["src/modules/meson.build"],"removed":[]},{"id":"b5e74dfa919cb4e560724f77dd4c0b11a223e162","message":"module-raop: add the AirPlay 2 SRP-6a client\n\nSRP-6a client (user side) derived from RFC 5054 (incl. the 2048/3072-bit groups\nand the PAD() rule) and RFC 2945, on OpenSSL (BIGNUM + EVP). Drives HomeKit/HKP\ntransient pair-setup.\n\nAssisted-by: LLM\n","title":"module-raop: add the AirPlay 2 SRP-6a client","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/b5e74dfa919cb4e560724f77dd4c0b11a223e162","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":["src/modules/module-raop/srp.c","src/modules/module-raop/srp.h"],"modified":["src/modules/meson.build"],"removed":[]},{"id":"9d3a413694390cc53e63ec37b7645b3ce62dd2f7","message":"module-raop: implement AirPlay 2 pairing and encryption\n\nBuild out the AirPlay 2 handshake in module-raop-sink and module-raop-discover:\n\n- transient, HomeKit and Apple pair-setup and pair-verify;\n- RTSP cipher support for the encrypted control channel;\n- device-capability query via GET /info;\n- discovery of AirPlay 2 receivers, limited to those that accept transient\n pairing. Receivers that insist on persistent (HomeKit) or PIN pairing\n need a PIN typed in once, which takes a pairing UI that does not exist\n yet, so they are left out rather than exposed as sinks that cannot\n connect. They announce this in their status flags on both service types,\n \"flags\" in _airplay._tcp and \"sf\" in _raop._tcp (the same bitfield: pyatv\n reads either one and OwnTone keys its device verification off sf bit 9),\n and the legacy RAOP path cannot complete device verification either, so\n neither record gets a sink. Status flags are parsed as hex with or\n without a 0x prefix.\n\nAirPlay 2 devices advertise both _raop._tcp and _airplay._tcp; both resolve\nto the same host:port and would create two identical sinks. De-duplicate by\nthe device public key (raop.pk), present and identical in both records (the\nRAOP TXT record carries no deviceid), and keep a single tunnel per device,\npreferring the AirPlay path: Apple receivers running OS 27 and later still\naccept a legacy RAOP session but play nothing on it, while the AirPlay 2\npath works, so RAOP is only used when the device does not advertise\n_airplay._tcp. Tested with OS 27 HomePods by zk23 in !1658.\n\nThe AirPlay 2 path identifies itself as \"AirPlay/999.0.0\". Apple receivers\nrunning OS 27 and later gate GET /info on the User-Agent and answer\n403 Forbidden to anything that does not look like a recent AirPlay sender:\n\"PipeWire/1.7.0\" and \"AirPlay/1.0\" are rejected, \"AirPlay/380.20.1\" is\naccepted. A version far above any shipping one keeps the check passing;\nOwnTone settled on the same string (owntone/owntone-server#2042). Reported\nand tested against OS 27 HomePods by zk23 in !1658.\n\nThe remote device is untrusted input, so the handshake and streaming paths\nare hardened against malicious or malformed responses:\n\n- pair-setup: a degenerate SRP server key (B % N == 0) would make the\n SRP-6a safety check skip proof computation, leaving an all-zero,\n attacker-known session key that a zero M2 would \"verify\" against, a PIN\n bypass. Abort pair-setup when SRP produced no client proof (verify uses\n CRYPTO_memcmp).\n- pair-verify: refuse to proceed when the stored auth key carries no\n accessory public key, instead of skipping signature verification and\n leaving the X25519 exchange open to an active MITM.\n- bound the TLV parse of pairing replies by the buffered body rather than\n the peer-declared Content-Length, and gate the setup replies on 200.\n- stream/session SETUP: validate that port fields are PLIST_UINT and in\n range instead of using an uninitialised value on a non-integer node, and\n keep the local timing port instead of clobbering it with the receiver's.\n- NULL-check the device-driven allocations on the pairing paths.\n\nConnection resilience and lifecycle:\n\n- clear the recording flag on connection loss so the encode/send path\n stops instead of encrypting into a closed fd forever.\n- treat socket errors and failed reply handlers as terminal (schedule a\n single module destroy) so a bad or incompatible device does not leave a\n connected-but-silent zombie sink.\n- bound the connect+handshake window with a timeout.\n- arm the periodic /feedback keepalive for AirPlay 2 sessions so idle\n sessions are not dropped by the receiver.\n- the RTSP client drains all available input per wakeup, so it stops as\n soon as a reply handler disconnects the client: the socket is gone and\n so is any input still buffered for it (pw-test-raop-rtsp-client covers\n this with a TEARDOWN reply that disconnects).\n\nPairing persistence:\n\n- derive the HomeKit controller pairing identifier deterministically from\n the long-term Ed25519 identity so pair-verify presents the same\n Identifier that pair-setup registered, across restarts.\n- load raop.auth_key from raop.auth-key-file when no key is configured, so\n a once-paired device keeps working without hand-editing stream.rules.\n\nResource and key hygiene:\n\n- release per-session SRP state (SRPUser, pkB, salt, M2) on connection\n cleanup; destroy the timing source before closing its fd on the setup\n error path; cancel pending timers before freeing impl.\n- zeroize long-term and session key material (auth key, control cipher\n keys, shared secret, private keys) before freeing.\n\ntest-auth.c compiles module-raop-sink.c, so link the test against srp.c,\ntlv.c and libplist as well.\n\nAssisted-by: LLM\n","title":"module-raop: implement AirPlay 2 pairing and encryption","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/9d3a413694390cc53e63ec37b7645b3ce62dd2f7","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":[],"modified":["meson.build","src/modules/meson.build","src/modules/module-raop-discover.c","src/modules/module-raop-sink.c","src/modules/module-raop/rtsp-client.c","src/modules/module-raop/rtsp-client.h"],"removed":[]},{"id":"e7ae43a32e61cd7ad5387450ee517d328217b0aa","message":"ci: install libplist in the Fedora and Debian images to build AirPlay 2\n\nmodule-raop-sink's AirPlay 2 support requires libplist; with the raop\nfeature (forced on by -Dauto_features=enabled), meson makes it a hard\ndependency. The CI images didn't ship libplist, so the raop-enabled jobs\nfailed at configure:\n\n meson.build: ERROR: Dependency \"libplist-2.0\" not found\n\nAdd libplist to the two images that build raop (both also have openssl):\n- Fedora: libplist-devel in FDO_DISTRIBUTION_PACKAGES.\n- Debian cross: libplist-dev in setup-debian-cross-container.sh (verified\n available with libplist-2.0.pc for all cross arches).\nBump both image tags to trigger a rebuild. The Ubuntu and Alpine images\nuse raop=auto and ship no openssl, so they never build raop and are\nunchanged.\n\nAssisted-by: LLM\n","title":"ci: install libplist in the Fedora and Debian images to build AirPlay 2","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/e7ae43a32e61cd7ad5387450ee517d328217b0aa","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":[],"modified":[".gitlab-ci.yml",".gitlab/ci/setup-debian-cross-container.sh"],"removed":[]},{"id":"801cc4949af7a49e71b1a3b6c9f6ce2e55f02847","message":"module-raop-sink: on-screen PIN pairing\n\nSupport the /pair-pin-start flow for receivers that show a PIN on screen, and\naccept that PIN via node metadata so it can be supplied at runtime. The PIN\npoll timer is cancelled on connection cleanup, so a disconnect mid-pairing\ndoes not leave it firing against a torn-down connection.\n\nAssisted-by: LLM\n","title":"module-raop-sink: on-screen PIN pairing","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/801cc4949af7a49e71b1a3b6c9f6ce2e55f02847","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":[],"modified":["src/modules/module-raop-sink.c"],"removed":[]},{"id":"3b99e515eb8dc2bdcee2f10d6c2f08271eee873f","message":"module-raop: bound pw_base64_decode against malformed input\n\npw_base64_decode indexed its alphabet table with the raw input byte, so any\ncharacter outside '+'..'z' (or one of the holes in the table) read outside\nthe array, and it read data[i+1..3] past the end of the input when the\nlength was not a multiple of four. Reject invalid characters, decode only\nwhole quartets, and stop cleanly at the first bad input.\n\nAssisted-by: LLM\n","title":"module-raop: bound pw_base64_decode against malformed input","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/3b99e515eb8dc2bdcee2f10d6c2f08271eee873f","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":[],"modified":["src/modules/module-raop/base64.h"],"removed":[]},{"id":"4abf320c6d3b3a0f83f8c493a2cec3636a0325fb","message":"module-raop-sink: return an error when pw_rtsp_client_new fails\n\nThe error path returned res, which is still 0 at that point, so a failed\nclient allocation reported success after impl had already been destroyed.\n\nAssisted-by: LLM\n","title":"module-raop-sink: return an error when pw_rtsp_client_new fails","timestamp":"2026-10-21T14:44:53+00:00","url":"https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/4abf320c6d3b3a0f83f8c493a2cec3636a0325fb","author":{"name":"Christian Glombek","email":"c.glombek@cosa.systems"},"added":[],"modified":["src/modules/module-raop-sink.c"],"removed":[]}],"total_commits_count":8,"push_options":{},"repository":{"name":"pipewire","url":"git@ssh.gitlab.freedesktop.org:pipewire/pipewire.git","description":"Multimedia processing graphs","homepage":"https://gitlab.freedesktop.org/pipewire/pipewire","git_http_url":"https://gitlab.freedesktop.org/pipewire/pipewire.git","git_ssh_url":"git@ssh.gitlab.freedesktop.org:pipewire/pipewire.git","visibility_level":20}}