Add Android route manager backend in C# (PAR-020) - #371
Draft
MaxHeimbrock wants to merge 1 commit into
Draft
Conversation
Implement the PAR-019 routing seam on Android as an SDK-owned backend, hardened from the device-validated sample hotfix (PR #364): - AndroidRouteController (API 31+) pins the communication device to the sticky SelectOutput override while its device is available, else the highest-ranked available kind per OutputPreference; kinds missing from the ranking are never auto-selected (pin released, OS default applies) - session-scoped MODE_IN_COMMUNICATION with save/restore of the prior mode; optional audio-focus request (internal, default off) - change detection via OnCommunicationDeviceChangedListener plus a 1.5 s poll thread for the trace-verified transitions that fire no OS event (device added while pinned; BT headset leaving the available list ~10 s after the route already fell back); no-op re-pin guard stops the feedback loop from our own setCommunicationDevice - GetDevices playout list and DevicesChanged now report real Android communication devices with Kind and IsSelected; recording stays the FFI default-input placeholder - StartRecording re-asserts the policy: since Android 13 the mode request is only honored while voice-communication capture is active - pre-API-31 stays a documented unsupported placeholder, matching the hotfix gate; platform notes on the public API updated accordingly Co-Authored-By: Claude Fable 5 <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.
Background
PAR-019 (#370) defined the public audio output routing API, but on Android it was wired to a documented unsupported placeholder —
OutputPreferenceround-tripped without effect,SelectOutputthrew, andDevicesChangednever fired. The two customer-reported routing bugs (a headset connected mid-call is ignored; a headset disconnect falls back to the earpiece instead of the loudspeaker) were so far only addressed by disposable sample-level code (PR #364). This PR moves that routing into the SDK as the PAR-019 Android backend, hardened with the device findings from the hotfix work, and kept behind the internalIRouteControllerseam so phase B can later replace it with the FFI-driven router mechanically.Stacked on #370 (
max/par-019-routing-api-surface) — merge that first.Changes
AndroidRouteController(#if UNITY_ANDROID && !UNITY_EDITOR, Android 12/API 31+), all JNI contained in the class:MODE_IN_COMMUNICATIONwith save/restore of the prior mode, communication-device pin viasetCommunicationDevice/clearCommunicationDeviceSelectOutputoverride while its device is available (dropped once it disappears), else the highest-ranked available kind perOutputPreference; unranked kinds are never auto-selected (pin released, OS default applies)OnCommunicationDeviceChangedListenerplus a 1.5 s poll on a JVM-attached background thread — the poll covers the device-verified transitions that fire no OS event (device added while pinned; a powered-off BT headset leaving the available list ~10 s after the route already fell back). A no-op re-pin guard stops the feedback loop from our own pin firing the listener; teardown unregisters the listener before clearing the pinGetDevices().PlayoutandDevicesChangednow report real communication devices withKindandIsSelected(recording stays the FFI default-input placeholder); events are marshalled to the Unity main thread byPlatformAudiointernal— the PAR-019 public surface stays frozenPlatformAudio.StartRecordingre-asserts the routing policy once capture is active: since Android 13 the mode request — and with it the pin — is only honored while the app has active voice-communication captureOutputPreference(BT > wired > speaker > earpiece, defined in PAR-019) does not rankUsb/HearingAid, so unlike the hotfix's fixed ranking those are not auto-pinned — apps can add them to the list; when nothing ranked is available the OS default route appliesTesting
LiveKit.rspunder editor and Android-player define sets, plus the Meet sample assemblySelectOutput(earpiece)survives a BT connect until cleared;DevicesChangeddelivered kinds/selection on the Unity main thread🤖 Generated with Claude Code