Feature/mediacontrol api#785
Conversation
043c11c to
7246a54
Compare
93ba7c2 to
0a8a959
Compare
864adcb to
8381de3
Compare
# Conflicts: # CHANGELOG.md
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…t-native-theoplayer into feature/mediacontrol-api
…destruction or mediasessionEnable update
| // https://developer.android.com/media/legacy/media-buttons#restarting-inactive-mediasessions | ||
| this.mediaSession.setMediaButtonReceiver(null) | ||
| mediaSession.setMediaButtonReceiver(null) | ||
|
|
||
| // Install a queue navigator, but only if we want to handle skip buttons. | ||
| if (mediaSessionConfig.convertSkipToSeek) { | ||
| queueNavigator = MediaQueueNavigator(mediaSessionConfig) | ||
| } | ||
| addListener(mediaSessionListener) | ||
| // Route all media control actions through the MediaControlProxy, which will decide whether to | ||
| // invoke the action or not. | ||
| mediaControlProxy.attach(player, this, binder, config) |
There was a problem hiding this comment.
🔍 Live/ad play-pause no longer restricted at the media-session action level on Android
The removed applyAllowedMediaControls() used to set mediaSessionConnector.enabledPlaybackActions to 0 (or play/pause only) for live streams and ads, which hides/disables the corresponding lock-screen buttons. The new MediaControlProxy only guards the handlers (playPauseEnabled/trickPlayEnabled early-returns in onPlay/onPause/onFastForward/onRewind/onSeekTo at android/src/main/java/com/theoplayer/media/MediaControlProxy.kt:92-147) but no longer restricts the advertised enabledPlaybackActions on the connector. Depending on the media-session connector defaults, live streams (with allowLivePlayPause=false) and ads may now display play/pause/seek controls on the lock screen that do nothing when pressed. The PR description explicitly notes "Android needs an update of the media-session connector", so this may be a known, tracked gap — worth confirming the connector still gates the advertised actions.
Was this helpful? React with 👍 or 👎 to provide feedback.
| useEffect(() => { | ||
| if (!player) return; | ||
|
|
||
| const handleNext = () => { | ||
| setCurrentIndex((index) => { | ||
| const newIndex = (index + 1) % filteredSources.length; | ||
| player.source = filteredSources[newIndex].source; | ||
| return newIndex; | ||
| }); | ||
| }; | ||
|
|
||
| const handlePrevious = () => { | ||
| setCurrentIndex((index) => { | ||
| const newIndex = (index - 1 + filteredSources.length) % filteredSources.length; | ||
| player.source = filteredSources[newIndex].source; | ||
| return newIndex; | ||
| }); | ||
| }; | ||
|
|
||
| // Install handlers for media control actions to enable playlist navigation using the media session API (e.g. lock | ||
| // screen controls, bluetooth controls, etc.) | ||
| player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_NEXT, handleNext); | ||
| player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_PREVIOUS, handlePrevious); | ||
| }, [player, filteredSources]); |
There was a problem hiding this comment.
🟡 Lock-screen skip controls keep using a closed menu's stale state
The playlist hook registers its next/previous handlers (player.mediaControl?.setHandler at example/src/hooks/usePlaylist.ts:81-82) but never removes them, so when a second copy of the hook stops being used its handlers stay active and keep driving playback from outdated data.
Impact: After opening the source menu once, using the lock-screen/Bluetooth skip buttons navigates the playlist based on the closed menu's frozen position instead of the app's actual current item, sending playback to the wrong source.
Shared single handler slot with no effect cleanup
Both App (example/src/App.tsx:102) and SourceMenuView (example/src/custom/SourceMenuButton.tsx:22) call usePlaylist with the same player. The player exposes a single mediaControl adapter, whose native handler map holds one handler per action (src/internal/adapter/media/MediaControlNativeAdapter.ts:20-23), so the most recent setHandler call wins. When the menu opens, SourceMenuView's effect overwrites App's SKIP_TO_NEXT/SKIP_TO_PREVIOUS handlers with closures bound to the menu's own filteredSources/currentIndex state. The useEffect at example/src/hooks/usePlaylist.ts:60-83 returns no cleanup, so after the menu unmounts those handlers remain registered; subsequent lock-screen skips run setCurrentIndex on the unmounted instance and set player.source from the menu's state.
Was this helpful? React with 👍 or 👎 to provide feedback.
| fun detach() { | ||
| connector?.apply { | ||
| queueNavigator = null | ||
| playbackCallback = null | ||
| } | ||
| } |
There was a problem hiding this comment.
🔍 Shared MediaSessionConnector across multiple players: detach can clobber the active player
With the background service enabled, all ReactTHEOplayerContext instances share the service's single mediaSessionConnector (MediaPlaybackService), but each context owns its own MediaControlProxy. applyMediaSessionConfig calls mediaControlProxy.detach() then attach(...) on that shared connector (ReactTHEOplayerContext.kt:280,299). detach() sets connector.queueNavigator = null and connector.playbackCallback = null (MediaControlProxy.kt:56-61) on the shared connector. If player B has taken ownership (set the connector's callback to proxyB) and player A subsequently re-applies its config, proxyA.detach() nulls out proxyB's callbacks, and proxyA.attach() then rebinds to A — a hand-off ordering hazard. The PR docs acknowledge single-owner responsibility, and the Android connector reportedly still needs updating (per PR caution note), so this is expected-fragile, but worth confirming the ownership guards in setMediaSessionEnabled fully cover this.
Was this helpful? React with 👍 or 👎 to provide feedback.
Add MediaControl API.
usePlaylisthook to allow switching sources through mediaSession & lock-screen controls.Caution
Android needs an update of the media-session connector.