feat: detached audio playback - #148
Open
brunoro wants to merge 1 commit into
Open
Conversation
Tools can move playback into an SDK-owned MediaSessionService so it survives the screen that started it. newPlayer(playback = Detached) returns a handle backed by a MediaController instead of an in-process ExoPlayer; both modes share one public surface for queue, transport, position, metadata and errors. Opt in with `capabilities = ["detached-audio"]` in lighttool.toml. The Gradle plugin turns that one entry into the foreground-service permissions, the service declaration, and a meta-data marker under our own namespace. The marker is what the SDK checks at runtime, because a platform permission can be contributed by any transitive dependency and says nothing about what the tool asked for. Detached ownership differs from attached in two ways the docs lead with: release() disconnects the handle without stopping playback, and a reconnecting player may find a live session, so it awaits readiness and reuses a non-empty queue rather than replacing it. The service stops itself 60 seconds after playback pauses with no handle open. Playback failures surface as SDK-owned LightAudioError values in both modes, so no media3 type reaches the public API.
Contributor
Author
|
@brunoro this looks great!! |
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.
Tools can move playback into an SDK-owned
MediaSessionService, so audio survives the screen that started it.newPlayer(playback = Detached)returns a handle backed by aMediaControllerinstead of an in-processExoPlayer.Both modes share one public surface for queue, transport, position, metadata and errors, so nothing from media3 reaches the public API.
A detailed explanation of the architecture can be found in
docs/design_decisions/detached_audio.md.Some noteworthy details:
release()on a detached handle disconnects without stopping playback. Callstop()first to actually end it.awaitReady()and reuse a non-empty queue rather than replacing it.LightAudioUsage. Reconnecting with a different one throws.LightAudioErrorin both modes; player-creation failures throwLightAudioPlayerException.Opting in
[tool].capabilitiesis new. The Gradle plugin expandsdetached-audiointo the two foreground-service permissions, theLightAudioServicedeclaration, and acom.thelightphone.sdk.CAPABILITY_DETACHED_AUDIOmetadata marker.The metada marker is what the SDK checks at runtime.
androidx.workcontributesFOREGROUND_SERVICEtransitively to every tool, so a platform permission can never be a statement about what the tool asked for. A metadata key under our own namespace can only come from our generator.Both permissions were removed from
ALLOWED_PERMISSIONS; hand-writing one now fails the build with an error naming the capability to declare instead.LightAudioServicealso moved out of the SDK library manifest, so tools that never touch audio no longer ship amediaPlaybackclaim.Testing
The audio demo Player tab has a DETACHED toggle that switches between the playback modes. With DETACHED: ON, you should be able to lock the phone and navigate in the UI without stopping playback. The player state should be updated when you come back to it.