Integrate AirPlay 2 receiver into the launcher - #170
Draft
rudysev wants to merge 1 commit into
Draft
Conversation
Add the :airplay module (vendored from jqssun/android-airplay-server) and wire it into Immortal as a native feature: audio streaming, screen mirroring, and AirPlay video from an iPhone/iPad/Mac. Host integration (com.immortal.launcher): - AirPlayConfig: SharedPreferences config mapped onto the module's AirPlayOptions. No server-name field — the Portal advertises under FleetConfig.name, the same name the phone remote and Home Assistant use. - AirPlayControl: runtime lifecycle. ensureRunning() from ImmortalApp/BootReceiver, applyConfig() from the settings hook, and a SessionWatcher that raises the cast surface only for video (audio-only stays headless) and makes AirPlay audio and multi-room mutually exclusive. - AirPlayActivity: full-screen cast surface. One SurfaceView per renderer, swapped at the mirror->video handover; letterboxes by scaling (not resizing) so the decoder is never disturbed mid-stream. - AirPlayPairActivity + the `airplay` SettingsDomain: one declarative definition drives the on-device screen and the phone remote. Home-header glyph + modal mirror the phone-remote quick-connect. Module facade fix: AirPlayEngine.reconfigure restarts via start() (ACTION_START_ SERVER) rather than service.startServer(), which ordered startForegroundService after startForeground and got the process killed on every settings change. Build: catalog gains media3 1.11.0-beta01 (shared with VideoTranscoder), oboe, lifecycle-service, androidx.media; app declares ndkVersion so AGP strips the packaged .so files. CI installs the NDK (AGP resolves it while configuring the module). Four native deps are submodules at upstream's pins. Verified on gen-1 Portal+ (aloha, Android 9) and gen-2 Portal 10" (omni, Android 10): Spotify audio, YouTube mirroring, and the mirror->video handover. Not for release: the native library links GPL-3.0 code, so any APK bundling :airplay is GPL-3.0 as a whole while Immortal is MIT. See the TODO(licensing) tripwire in airplay/build.gradle.kts. Dev/debug builds only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hey @starbrightlab ,
This PR implements a new feature: AirPlay 2 receiver — audio streaming, screen mirroring, and AirPlay video (HLS handoff, so a cast of e.g. YouTube hands over a video URL rather than mirroring pixels) for iOS/iPadOS/macOS devices. The Portal appears in Control Center like an Apple TV or HomePod, with optional PIN pairing and now-playing / transport control (DACP) from the sender.
It was tested mirroring Spotify and YouTube on Portal Gen2 and Portal+ Gen1. It relies on android-airplay-server (https://github.com/jqssun/android-airplay-server), vendored under
airplay/with a single local patch and a sync script (airplay/UPSTREAM.mddocuments the vendor line).It is tested to work with iOS but is a large feature, which affects:
:airplayGradle module bundling a native stack (UxPlay + OpenSSL + libplist + FFmpeg via JNI/CMake, arm64-only) and its four submodules — so the build now needs the NDK to configure.media31.5.1 → 1.11.0-beta01 andandroidx.core1.10.1 → 1.15.0, plus lifecycle/coroutines. media3 is shared with the screensaver'sVideoTranscoder, so that path moves onto the newer (beta) media3 too — worth a look on real hardware.AirPlayActivity, pairing flow), wired in the same "opt-in from a pairing screen" style as the phone remote.Care should be taken with the licensing — you have an MIT License but this uses GNU GPL-3.0 (the vendored FairPlay/UxPlay native code), and I don't want to push a licensing change to you. There's a tripwire comment in
airplay/build.gradle.ktsabout not cutting a public self-updating release that bundles it; it is not enforced in the build, so that would need a real gate before any release includes:airplay.I have further built this feature into a standalone application, but it really belongs in Immortal, similar to remote control via phone.
Please take your time to review this work and decide if and/or how you want to port or land it.