Loading...
Loading...
Compare original and translation side by side
>= 1.9.0>= 1.9.0CastPlayerPlayerRemoteCastPlayerPlayerOptionsProviderCastContextCastPlayerPlayerRemoteCastPlayerPlayerOptionsProviderCastContextmedia3-castimplementation("androidx.media3:media3-cast:1.10.1")androidx.media3:media3-exoplayerandroidx.media3:media3-sessionandroidx.media3:media3-ui-composemedia3-uilibs.play.services.cast.frameworkmedia3-castimplementation("androidx.media3:media3-cast:1.10.1")androidx.media3:media3-exoplayerandroidx.media3:media3-sessionandroidx.media3:media3-ui-composemedia3-uilibs.play.services.cast.framework<application>DefaultCastOptionsProviderOptionsProviderINTERNET<application>DefaultCastOptionsProviderOptionsProviderINTERNETExoPlayerExoPlayerPlayerRemoteMediaClientMediaSessionForwardingPlayerMediaSessionServiceMediaLibraryServiceonCreate()ExoPlayerCastPlayerCastPlayerRemoteCastPlayerCastPlayerMediaSession.BuilderExoPlayerExoPlayerRemoteMediaClientPlayerMediaSessionForwardingPlayerMediaSessionServiceMediaLibraryServiceonCreate()ExoPlayerCastPlayerCastPlayerRemoteCastPlayerCastPlayerMediaSession.BuilderRemoteCastPlayerRemoteCastPlayerRemoteCastPlayerMediaSessionlocalPlayerSessionAvailabilityListenerRemoteCastPlayeroverride fun onCreate() {
super.onCreate()
localPlayer = ExoPlayer.Builder(this).build()
remotePlayer = RemoteCastPlayer.Builder(this).build()
mediaSession = MediaSession.Builder(this, localPlayer).build()
remotePlayer.setSessionAvailabilityListener(
object : SessionAvailabilityListener {
override fun onCastSessionAvailable() {
transferPlaybackState(localPlayer, remotePlayer)
}
override fun onCastSessionUnavailable() {
transferPlaybackState(remotePlayer, localPlayer)
}
}
)
}
private fun transferPlaybackState(previousPlayer: Player, newPlayer: Player) {
if (previousPlayer.mediaItemCount > 0) {
val transferStateBuilder = PlayerTransferState.builderFromPlayer(previousPlayer)
if (previousPlayer.playbackState == Player.STATE_ENDED ||
previousPlayer.currentPosition == C.TIME_END_OF_SOURCE) {
transferStateBuilder.setCurrentMediaItemIndex(0)
transferStateBuilder.setCurrentPosition(0)
}
transferStateBuilder.build().setToPlayer(newPlayer)
}
previousPlayer.stop()
previousPlayer.clearMediaItems()
newPlayer.prepare()
mediaSession?.setPlayer(newPlayer)
}RemoteCastPlayerlocalPlayerMediaSessionRemoteCastPlayerSessionAvailabilityListeneroverride fun onCreate() {
super.onCreate()
localPlayer = ExoPlayer.Builder(this).build()
remotePlayer = RemoteCastPlayer.Builder(this).build()
mediaSession = MediaSession.Builder(this, localPlayer).build()
remotePlayer.setSessionAvailabilityListener(
object : SessionAvailabilityListener {
override fun onCastSessionAvailable() {
transferPlaybackState(localPlayer, remotePlayer)
}
override fun onCastSessionUnavailable() {
transferPlaybackState(remotePlayer, localPlayer)
}
}
)
}
private fun transferPlaybackState(previousPlayer: Player, newPlayer: Player) {
if (previousPlayer.mediaItemCount > 0) {
val transferStateBuilder = PlayerTransferState.builderFromPlayer(previousPlayer)
if (previousPlayer.playbackState == Player.STATE_ENDED ||
previousPlayer.currentPosition == C.TIME_END_OF_SOURCE) {
transferStateBuilder.setCurrentMediaItemIndex(0)
transferStateBuilder.setCurrentPosition(0)
}
transferStateBuilder.build().setToPlayer(newPlayer)
}
previousPlayer.stop()
previousPlayer.clearMediaItems()
newPlayer.prepare()
mediaSession?.setPlayer(newPlayer)
}MediaRouteButtonandroidx.media3.castAndroidViewMediaRouteButtonPlayerSurfacePlayerDeviceInfo@OptIn(UnstableApi::class)
@Composable
fun MainScreen() {
val player = rememberMediaController()
val deviceInfo = rememberDeviceInfo(player)
player?.let { activePlayer -> key(deviceInfo) { PlayerScreen(player = activePlayer) } }
}
@Composable
private fun rememberMediaController(): Player? {
// Logic to connect MediaController to MediaSession and release it
}
@Composable
private fun rememberDeviceInfo(player: Player?): DeviceInfo? {
var deviceInfo by remember(player) { mutableStateOf(player?.deviceInfo) }
DisposableEffect(player) {
val activePlayer = player ?: return@DisposableEffect onDispose {}
deviceInfo = activePlayer.deviceInfo
val listener = object : Player.Listener {
override fun onDeviceInfoChanged(info: DeviceInfo) {
deviceInfo = info
}
}
activePlayer.addListener(listener)
onDispose { activePlayer.removeListener(listener) }
}
return deviceInfo
}androidx.media3.castMediaRouteButtonAndroidViewMediaRouteButtonPlayerSurfacePlayerDeviceInfo@OptIn(UnstableApi::class)
@Composable
fun MainScreen() {
val player = rememberMediaController()
val deviceInfo = rememberDeviceInfo(player)
player?.let { activePlayer -> key(deviceInfo) { PlayerScreen(player = activePlayer) } }
}
@Composable
private fun rememberMediaController(): Player? {
// 将MediaController连接到MediaSession并释放的逻辑
}
@Composable
private fun rememberDeviceInfo(player: Player?): DeviceInfo? {
var deviceInfo by remember(player) { mutableStateOf(player?.deviceInfo) }
DisposableEffect(player) {
val activePlayer = player ?: return@DisposableEffect onDispose {}
deviceInfo = activePlayer.deviceInfo
val listener = object : Player.Listener {
override fun onDeviceInfoChanged(info: DeviceInfo) {
deviceInfo = info
}
}
activePlayer.addListener(listener)
onDispose { activePlayer.removeListener(listener) }
}
return deviceInfo
}AppCompatActivityFragmentActivityTheme.AppCompatAppCompatActionBarMediaRouteButtonCastButtonFactoryMediaRouteButtonFactoryPlayerView.playeronDeviceInfoChangedprivate val playerListener: Player.Listener =
object : Player.Listener {
override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) {
// Resetting to null bypasses PlayerView.setPlayer()'s instance equality check
// (this.player == player), forcing it to re-bind the video surface to the controller.
playerView.player = null
playerView.player = controller
}
}AndroidViewPlayerViewPlayerMediaRouteButtonAppCompatActivityFragmentActivityTheme.AppCompatMediaRouteButtonAppCompatActionBarCastButtonFactoryMediaRouteButtonFactoryonDeviceInfoChangedPlayerView.playerprivate val playerListener: Player.Listener =
object : Player.Listener {
override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) {
// 重置为null可绕过PlayerView.setPlayer()的实例相等性检查
// (this.player == player),强制将视频表面重新绑定到控制器。
playerView.player = null
playerView.player = controller
}
}AndroidViewPlayerViewPlayerMediaRouteButton[!WARNING] Warning: Don't perform cleanup directly. Remove legacy files and dependencies only when explicitly requested by the user.
libs.play.services.cast.frameworklibs.androidx.mediarouterOptionsProviderDefaultCastOptionsProviderMediaTransferReceiverRemoteMediaClientPlayerView[!WARNING] **警告:**不要直接执行清理操作。仅在用户明确要求时,再删除旧版文件和依赖。
libs.play.services.cast.frameworklibs.androidx.mediarouterDefaultCastOptionsProviderOptionsProviderMediaTransferReceiverRemoteMediaClientPlayerView