Cast: Start a session when a Cast route is selected#3567
Open
peterhel wants to merge 1 commit into
Open
Conversation
CastContextImpl never registered a route-selection callback, so selecting a Chromecast via the Cast SDK (CastContext/SessionManager) did nothing: discovery worked but no session was ever started and the app's SessionManagerListener never fired. MediaRouterCallbackImpl already had the correct start-on-selection logic but was never instantiated or registered with the router. Register MediaRouterCallbackImpl via IMediaRouter (registerMediaRouterCallbackImpl + addCallback) so route selection starts a session. This goes through the IMediaRouter binder rather than touching androidx MediaRouter from the dynamite, which would throw Resources$NotFoundException (the dynamite uses the app's Resources but microG's resource IDs). Also resolve defaultSessionProvider by category prefix: the provider map is keyed by the full control category (with namespace/flag suffixes such as .../CC1AD845///ALLOW_IPV6), so the exact categoryForCast(appId) lookup missed and left defaultSessionProvider null. Harden MediaRouterCallbackImpl.onRouteSelected against a missing provider / non-SessionImpl and fall back to the route extras. Co-Authored-By: Claude Opus 4.8 <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.
Cast: start a session when a Cast route is selected
Problem
Apps using the modern Cast SDK (
play-services-cast-framework) — Prime Video, Netflix,Disney+, YouTube, and any app built on
CastContext/SessionManager— cannot start aCast session through microG. The Cast button discovers and lists Chromecasts (route
discovery works), but selecting a device does nothing: no session starts, no connection is
attempted, and the app's
SessionManagerListenernever fires. On the device this lookslike a silent failure (the symptom reported for Prime Video on /e/OS).
Root cause
CastContextImplbuilds the mergedMediaRouteSelectorand holds the app'sIMediaRouterand its
ISessionProviders, but it never registers a route-selection callback.MediaRouterCallbackImpl— which already contains the correct "on selection, start thesession" logic — is imported by
CastDynamiteModuleImplbut never instantiated orregistered with the router. As a result nothing observes route selection, so the session
lifecycle is never driven.
A second, latent bug sits in the provider lookup:
defaultSessionProvideris fetched withsessionProviders.get(categoryForCast(appId)), but the provider map is keyed by the fullcontrol-category string, which carries extra namespace/flag suffixes
(e.g.
…/CC1AD845///ALLOW_IPV6). The exact-key lookup misses, leavingdefaultSessionProvider == null, so even once selection is observed the session can't becreated (and
MediaRouterCallbackImpl.onRouteSelectedwould NPE on it).Fix
play-services-cast-frameworkonly — two files, no API changes:CastContextImpl— registerMediaRouterCallbackImplwith the app'sIMediaRouter(registerMediaRouterCallbackImpl+addCallback) in the constructor, soroute selection is observed and starts a session. This deliberately goes through the
IMediaRouterbinder rather than touching androidxMediaRouterdirectly: the dynamiteruns with the app's
Resourcesbut microG's resource IDs, so a directMediaRouter.getInstance(context)from the dynamite throwsResources$NotFoundException. The app'sMediaRouterProxyalready runs androidxMediaRouter correctly in-process.
CastContextImpl— fall back to a category-prefix match when the exactcategoryForCast(appId)key isn't present, so the default session provider resolvesdespite the flag suffixes.
MediaRouterCallbackImpl.onRouteSelected— null-safety hardening (skip cleanly ifthere is no provider / the unwrapped object isn't a
SessionImpl, and fall back to theroute's own extras when
getRouteInfoExtrasByIdreturns null).Verification
Built into a
vtmDefaultGmsCore APK and tested against Google's realplay-services-cast-framework(a minimal sender app) on:Before: selecting the Cast route only logs
unimplemented Method: onSelect; nothing elsehappens.
After: selecting the route drives the full session lifecycle —
i.e. the session now starts and proceeds to the device-connection/authentication handshake.
Note: completing the connection to a live device additionally requires microG signature
spoofing to be active on the device (so the app's GMS authenticity check passes) — that is
an existing environmental requirement of microG, independent of this change. On a device
without working signature spoofing the session correctly stalls at
CONNECTINGwith aSERVICE_INVALIDfrom the app'sGoogleApiManager; this patch is what gets the session tothat point in the first place.
🤖 Generated with Claude Code