casting: add helper functions for dispatching to active backend

This commit is contained in:
Marcus Hanestad 2025-08-28 10:37:14 +02:00
commit 58e08f5ea3
6 changed files with 236 additions and 293 deletions

View file

@ -21,6 +21,7 @@ import com.futo.platformplayer.casting.ChromecastCastingDevice
import com.futo.platformplayer.casting.FCastCastingDevice
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.experimental_casting.ExpStateCasting
import com.futo.platformplayer.experimental_casting.StateCastingDispatcher
import com.futo.platformplayer.fragment.mainactivity.main.VideoDetailFragment
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateApp
@ -74,30 +75,18 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
_buttonPlay = findViewById(R.id.button_play);
_buttonPlay.setOnClickListener {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.resumePlayback()
} else {
StateCasting.instance.activeDevice?.resumeVideo()
}
StateCastingDispatcher.resumeVideo()
}
_buttonPause = findViewById(R.id.button_pause);
_buttonPause.setOnClickListener {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.pausePlayback()
} else {
StateCasting.instance.activeDevice?.pauseVideo()
}
StateCastingDispatcher.pauseVideo()
}
_buttonStop = findViewById(R.id.button_stop);
_buttonStop.setOnClickListener {
(ownerActivity as MainActivity?)?.getFragment<VideoDetailFragment>()?.closeVideoDetails()
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.stopPlayback()
} else {
StateCasting.instance.activeDevice?.stopVideo()
}
StateCastingDispatcher.stopVideo()
}
_buttonNext = findViewById(R.id.button_next);
@ -125,21 +114,7 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
return@OnChangeListener
}
if (Settings.instance.casting.experimentalCasting) {
val activeDevice = ExpStateCasting.instance.activeDevice ?: return@OnChangeListener;
try {
activeDevice.device.seek(value.toDouble());
} catch (e: Throwable) {
Logger.e(TAG, "Failed to seek.", e);
}
} else {
val activeDevice = StateCasting.instance.activeDevice ?: return@OnChangeListener;
try {
activeDevice.seekVideo(value.toDouble());
} catch (e: Throwable) {
Logger.e(TAG, "Failed to seek.", e);
}
}
StateCastingDispatcher.videoSeekTo(value.toDouble())
});
//TODO: Check if volume slider is properly hidden in all cases
@ -148,25 +123,7 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
return@OnChangeListener
}
if (Settings.instance.casting.experimentalCasting) {
val activeDevice = ExpStateCasting.instance.activeDevice ?: return@OnChangeListener;
if (activeDevice.device.supportsFeature(DeviceFeature.SET_VOLUME)) {
try {
activeDevice.device.changeVolume(value.toDouble());
} catch (e: Throwable) {
Logger.e(TAG, "Failed to change volume.", e);
}
}
} else {
val activeDevice = StateCasting.instance.activeDevice ?: return@OnChangeListener;
if (activeDevice.canSetVolume) {
try {
activeDevice.changeVolume(value.toDouble());
} catch (e: Throwable) {
Logger.e(TAG, "Failed to change volume.", e);
}
}
}
StateCastingDispatcher.changeVolume(value.toDouble())
});
setLoading(false);

View file

@ -110,12 +110,17 @@ class CastingDeviceHandle {
contentType: String,
contentId: String,
resumePosition: Double,
duration: Double,
speed: Double?,
metadata: Metadata? = null
) {
try {
device.load(LoadRequest.Video(contentType, contentId, resumePosition, speed, duration, metadata))
device.load(LoadRequest.Video(
contentType = contentType,
url = contentId,
resumePosition = resumePosition,
speed = speed,
metadata = metadata
))
} catch (e: Throwable) {
Logger.e(TAG, "Failed to load video: $e")
}
@ -125,11 +130,15 @@ class CastingDeviceHandle {
contentType: String,
content: String,
resumePosition: Double,
duration: Double,
speed: Double?
) {
try {
device.load(LoadRequest.Content(contentType, content, resumePosition, duration, speed))
device.load(LoadRequest.Content(
contentType =contentType,
content = content,
resumePosition = resumePosition,
speed = speed
))
} catch (e: Throwable) {
Logger.e(TAG, "Failed to load content: $e")
}

View file

@ -569,7 +569,6 @@ class ExpStateCasting {
videoSource.container,
videoUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
)
@ -581,7 +580,6 @@ class ExpStateCasting {
audioSource.container,
audioUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -601,7 +599,6 @@ class ExpStateCasting {
videoSource.container,
videoSource.url,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -622,7 +619,6 @@ class ExpStateCasting {
audioSource.container,
audioSource.url,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -738,7 +734,6 @@ class ExpStateCasting {
videoSource.container,
videoUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -769,7 +764,6 @@ class ExpStateCasting {
audioSource.container,
audioUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -963,7 +957,6 @@ class ExpStateCasting {
"application/vnd.apple.mpegurl",
hlsUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
)
@ -1043,7 +1036,6 @@ class ExpStateCasting {
"application/dash+xml",
dashUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -1139,7 +1131,6 @@ class ExpStateCasting {
"application/dash+xml",
content,
resumePosition,
video.duration.toDouble(),
speed
);
@ -1319,7 +1310,6 @@ class ExpStateCasting {
"application/vnd.apple.mpegurl",
hlsUrl,
hackfixResumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -1487,7 +1477,6 @@ class ExpStateCasting {
"application/dash+xml",
dashUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);
@ -1756,7 +1745,6 @@ class ExpStateCasting {
"application/dash+xml",
dashUrl,
resumePosition,
video.duration.toDouble(),
speed,
metadataFromVideo(video)
);

View file

@ -0,0 +1,134 @@
package com.futo.platformplayer.experimental_casting
import com.futo.platformplayer.Settings
import com.futo.platformplayer.casting.CastConnectionState
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.dialogs.ConnectedCastingDialog.Companion.TAG
import com.futo.platformplayer.logging.Logger
import org.fcast.sender_sdk.DeviceFeature
class StateCastingDispatcher {
companion object {
fun canActiveDeviceSetSpeed(): Boolean {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.supportsFeature(DeviceFeature.SET_SPEED) == true
} else {
StateCasting.instance.activeDevice?.canSetSpeed == true
}
}
fun getActiveDeviceSpeed(): Double? {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.speed
} else {
StateCasting.instance.activeDevice?.speed
}
}
fun activeDeviceSetSpeed(speed: Double) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.changeSpeed(speed)
} else {
StateCasting.instance.activeDevice?.changeSpeed(speed)
}
}
fun resumeVideo(): Boolean {
return try {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.resumeVideo()
} else {
StateCasting.instance.resumeVideo()
}
} catch (_: Throwable) {
false
}
}
fun pauseVideo(): Boolean {
return try {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.pauseVideo()
} else {
StateCasting.instance.pauseVideo()
}
} catch (_: Throwable) {
false
}
}
fun videoSeekTo(timeSeconds: Double): Boolean {
return try {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.videoSeekTo(timeSeconds)
} else {
StateCasting.instance.videoSeekTo(timeSeconds)
}
} catch (_: Throwable) {
false
}
}
fun stopVideo(): Boolean {
return try {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.stopVideo()
} else {
StateCasting.instance.stopVideo()
}
} catch (_: Throwable) {
false
}
}
fun isCasting(): Boolean {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.isCasting
} else {
StateCasting.instance.isCasting
}
}
fun isConnected(): Boolean {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED
} else {
StateCasting.instance.activeDevice?.connectionState == CastConnectionState.CONNECTED
}
}
fun isPlaying(): Boolean {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.isPlaying == true
} else {
StateCasting.instance.activeDevice?.isPlaying == true
}
}
fun getExpectedCurrentTime(): Double? {
return if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.expectedCurrentTime
} else {
StateCasting.instance.activeDevice?.expectedCurrentTime
}
}
fun changeVolume(volume: Double) {
try {
if (Settings.instance.casting.experimentalCasting) {
val activeDevice =
ExpStateCasting.instance.activeDevice ?: return;
if (activeDevice.device.supportsFeature(DeviceFeature.SET_VOLUME)) {
activeDevice.device.changeVolume(volume);
}
} else {
val activeDevice =
StateCasting.instance.activeDevice ?: return;
if (activeDevice.canSetVolume) {
activeDevice.changeVolume(volume);
}
}
} catch (_: Throwable) {}
}
}
}

View file

@ -99,6 +99,7 @@ import com.futo.platformplayer.engine.exceptions.ScriptReloadRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptUnavailableException
import com.futo.platformplayer.exceptions.UnsupportedCastException
import com.futo.platformplayer.experimental_casting.ExpStateCasting
import com.futo.platformplayer.experimental_casting.StateCastingDispatcher
import com.futo.platformplayer.fixHtmlLinks
import com.futo.platformplayer.fixHtmlWhitespace
import com.futo.platformplayer.getNowDiffSeconds
@ -1217,12 +1218,8 @@ class VideoDetailView : ConstraintLayout {
_onPauseCalled = true;
_taskLoadVideo.cancel();
if (Settings.instance.casting.experimentalCasting) {
if(ExpStateCasting.instance.isCasting)
return;
} else {
if(StateCasting.instance.isCasting)
return;
if (StateCastingDispatcher.isCasting()) {
return
}
if(allowBackground)
@ -2014,12 +2011,7 @@ class VideoDetailView : ConstraintLayout {
return;
}
val isCasting = if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.isCasting
} else {
StateCasting.instance.isCasting
}
if (!isCasting) {
if (!StateCastingDispatcher.isCasting()) {
setCastEnabled(false);
val isLimitedVersion = StatePlatform.instance.getContentClientOrNull(video.url)?.let {
@ -2303,11 +2295,7 @@ class VideoDetailView : ConstraintLayout {
}
val currentPlaybackRate = (if (_isCasting) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.speed
} else {
StateCasting.instance.activeDevice?.speed
}
StateCastingDispatcher.getActiveDeviceSpeed()
} else _player.getPlaybackRate()) ?: 1.0
_overlay_quality_selector?.groupItems?.firstOrNull { it is SlideUpMenuButtonList && it.id == "playback_rate" }?.let {
(it as SlideUpMenuButtonList).setSelected(currentPlaybackRate.toString())
@ -2426,18 +2414,12 @@ class VideoDetailView : ConstraintLayout {
?.distinct()
?.toList() ?: listOf() else audioSources?.toList() ?: listOf();
val canSetSpeed = !_isCasting || if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.device?.supportsFeature(DeviceFeature.SET_SPEED) == true
} else {
StateCasting.instance.activeDevice?.canSetSpeed == true
}
val canSetSpeed = !_isCasting || StateCastingDispatcher.canActiveDeviceSetSpeed();
val currentPlaybackRate = if (_isCasting) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.speed
} else {
StateCasting.instance.activeDevice?.speed
}
} else _player.getPlaybackRate()
StateCastingDispatcher.getActiveDeviceSpeed()
} else {
_player.getPlaybackRate()
}
val qualityPlaybackSpeedTitle = if (canSetSpeed) SlideUpMenuTitle(this.context).apply { setTitle(context.getString(R.string.playback_rate) + " (${String.format("%.2f", currentPlaybackRate)})"); } else null;
_overlay_quality_selector = SlideUpMenuOverlay(this.context, _overlay_quality_container, context.getString(
R.string.quality), null, true,
@ -2452,11 +2434,7 @@ class VideoDetailView : ConstraintLayout {
setButtons(playbackLabels, String.format(Locale.US, format, currentPlaybackRate));
onClick.subscribe { v ->
val currentPlaybackSpeed = if (_isCasting) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.speed
} else {
StateCasting.instance.activeDevice?.speed
}
StateCastingDispatcher.getActiveDeviceSpeed()
} else _player.getPlaybackRate();
var playbackSpeedString = v;
val stepSpeed = Settings.instance.playback.getPlaybackSpeedStep();
@ -2465,26 +2443,10 @@ class VideoDetailView : ConstraintLayout {
else if(v == "-")
playbackSpeedString = String.format(Locale.US, "%.2f", Math.max(0.1, (currentPlaybackSpeed?.toDouble() ?: 1.0) - stepSpeed)).toString();
val newPlaybackSpeed = playbackSpeedString.toDouble();
if (_isCasting) {
if (Settings.instance.casting.experimentalCasting) {
val ad = ExpStateCasting.instance.activeDevice ?: return@subscribe
if (!ad.device.supportsFeature(DeviceFeature.SET_SPEED)) {
return@subscribe
}
qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format(Locale.US, "%.2f", newPlaybackSpeed)})");
ad.device.changeSpeed(newPlaybackSpeed)
setSelected(playbackSpeedString);
} else {
val ad = StateCasting.instance.activeDevice ?: return@subscribe
if (!ad.canSetSpeed) {
return@subscribe
}
qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format(Locale.US, "%.2f", newPlaybackSpeed)})");
ad.changeSpeed(newPlaybackSpeed)
setSelected(playbackSpeedString);
}
if (_isCasting && StateCastingDispatcher.canActiveDeviceSetSpeed()) {
qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format(Locale.US, "%.2f", newPlaybackSpeed)})");
StateCastingDispatcher.activeDeviceSetSpeed(newPlaybackSpeed)
setSelected(playbackSpeedString);
} else {
qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format(Locale.US, "%.2f", newPlaybackSpeed)})");
_player.setPlaybackRate(playbackSpeedString.toFloat());
@ -2599,14 +2561,8 @@ class VideoDetailView : ConstraintLayout {
//Handlers
private fun handlePlay() {
Logger.i(TAG, "handlePlay")
if (Settings.instance.casting.experimentalCasting) {
if (!ExpStateCasting.instance.resumeVideo()) {
_player.play()
}
} else {
if (!StateCasting.instance.resumeVideo()) {
_player.play();
}
if (!StateCastingDispatcher.resumeVideo()) {
_player.play()
}
//TODO: This was needed because handleLowerVolume was done.
@ -2621,60 +2577,31 @@ class VideoDetailView : ConstraintLayout {
private fun handlePause() {
Logger.i(TAG, "handlePause")
if (Settings.instance.casting.experimentalCasting) {
if (!ExpStateCasting.instance.pauseVideo()) {
_player.pause()
}
} else {
if (!StateCasting.instance.pauseVideo()) {
_player.pause()
}
if (!StateCastingDispatcher.pauseVideo()) {
_player.pause()
}
}
private fun handleSeek(ms: Long) {
Logger.i(TAG, "handleSeek(ms=$ms)")
if (Settings.instance.casting.experimentalCasting) {
if (!ExpStateCasting.instance.videoSeekTo(ms.toDouble() / 1000.0)) {
_player.seekTo(ms)
}
} else {
if (!StateCasting.instance.videoSeekTo(ms.toDouble() / 1000.0)) {
_player.seekTo(ms)
}
if (!StateCastingDispatcher.videoSeekTo(ms.toDouble() / 1000.0)) {
_player.seekTo(ms)
}
}
private fun handleStop() {
Logger.i(TAG, "handleStop")
if (Settings.instance.casting.experimentalCasting) {
if (!ExpStateCasting.instance.stopVideo()) {
_player.stop()
}
} else {
if (!StateCasting.instance.stopVideo()) {
_player.stop()
}
if (!StateCastingDispatcher.stopVideo()) {
_player.stop()
}
}
private fun handlePlayChanged(playing: Boolean) {
Logger.i(TAG, "handlePlayChanged(playing=$playing)")
if (Settings.instance.casting.experimentalCasting) {
val ad = ExpStateCasting.instance.activeDevice;
if (ad != null) {
_cast.setIsPlaying(playing);
} else {
StatePlayer.instance.updateMediaSession( null);
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, _player.exoPlayer?.player?.currentPosition ?: 0);
}
if (StateCastingDispatcher.isCasting()) {
_cast.setIsPlaying(playing);
} else {
val ad = StateCasting.instance.activeDevice;
if (ad != null) {
_cast.setIsPlaying(playing);
} else {
StatePlayer.instance.updateMediaSession( null);
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, _player.exoPlayer?.player?.currentPosition ?: 0);
}
StatePlayer.instance.updateMediaSession( null);
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, _player.exoPlayer?.player?.currentPosition ?: 0);
}
if(playing) {
@ -2712,26 +2639,20 @@ class VideoDetailView : ConstraintLayout {
fragment.lifecycleScope.launch(Dispatchers.Main) {
try {
if (Settings.instance.casting.experimentalCasting) {
val d = ExpStateCasting.instance.activeDevice;
if (d != null && d.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED)
castIfAvailable(
context.contentResolver,
video,
videoSource,
_lastAudioSource,
_lastSubtitleSource,
(d.expectedCurrentTime * 1000.0).toLong(),
d.speed
);
else if(!_player.swapSources(videoSource, _lastAudioSource, true, true, true))
_player.hideControls(false); //TODO: Disable player?
} else {
val d = StateCasting.instance.activeDevice;
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
castIfAvailable(context.contentResolver, video, videoSource, _lastAudioSource, _lastSubtitleSource, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
else if(!_player.swapSources(videoSource, _lastAudioSource, true, true, true))
_player.hideControls(false); //TODO: Disable player?
if (StateCastingDispatcher.isConnected()) {
val expectedCurrentTime = StateCastingDispatcher.getExpectedCurrentTime() ?: 0.0
val speed = StateCastingDispatcher.getActiveDeviceSpeed() ?: 1.0
castIfAvailable(
context.contentResolver,
video,
videoSource,
_lastAudioSource,
_lastSubtitleSource,
(expectedCurrentTime * 1000.0).toLong(),
speed
)
} else if(!_player.swapSources(videoSource, _lastAudioSource, true, true, true)) {
_player.hideControls(false); //TODO: Disable player?
}
} catch (e: Throwable) {
Logger.e(TAG, "handleSelectVideoTrack failed", e)
@ -2749,34 +2670,20 @@ class VideoDetailView : ConstraintLayout {
fragment.lifecycleScope.launch(Dispatchers.Main) {
try {
if (Settings.instance.casting.experimentalCasting) {
val d = ExpStateCasting.instance.activeDevice;
if (d != null && d.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED)
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
audioSource,
_lastSubtitleSource,
(d.expectedCurrentTime * 1000.0).toLong(),
d.speed
)
else if (!_player.swapSources(_lastVideoSource, audioSource, true, true, true))
_player.hideControls(false); //TODO: Disable player?
} else {
val d = StateCasting.instance.activeDevice;
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
audioSource,
_lastSubtitleSource,
(d.expectedCurrentTime * 1000.0).toLong(),
d.speed
)
else if (!_player.swapSources(_lastVideoSource, audioSource, true, true, true))
_player.hideControls(false); //TODO: Disable player?
if (StateCastingDispatcher.isConnected()) {
val expectedCurrentTime = StateCastingDispatcher.getExpectedCurrentTime() ?: 0.0
val speed = StateCastingDispatcher.getActiveDeviceSpeed() ?: 1.0
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
audioSource,
_lastSubtitleSource,
(expectedCurrentTime * 1000.0).toLong(),
speed
)
} else if (!_player.swapSources(_lastVideoSource, audioSource, true, true, true)) {
_player.hideControls(false); //TODO: Disable player?
}
} catch (e: Throwable) {
Logger.e(TAG, "handleSelectAudioTrack failed", e)
@ -2795,36 +2702,20 @@ class VideoDetailView : ConstraintLayout {
fragment.lifecycleScope.launch(Dispatchers.Main) {
try {
if (Settings.instance.casting.experimentalCasting) {
val d = ExpStateCasting.instance.activeDevice;
if (d != null && d.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED)
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
_lastAudioSource,
toSet,
(d.expectedCurrentTime * 1000.0).toLong(),
d.speed
);
else {
_player.swapSubtitles(toSet);
}
if (StateCastingDispatcher.isConnected()) {
val expectedCurrentTime = StateCastingDispatcher.getExpectedCurrentTime() ?: 0.0
val speed = StateCastingDispatcher.getActiveDeviceSpeed() ?: 1.0
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
_lastAudioSource,
toSet,
(expectedCurrentTime * 1000.0).toLong(),
speed
)
} else {
val d = StateCasting.instance.activeDevice;
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
castIfAvailable(
context.contentResolver,
video,
_lastVideoSource,
_lastAudioSource,
toSet,
(d.expectedCurrentTime * 1000.0).toLong(),
d.speed
);
else {
_player.swapSubtitles(toSet);
}
_player.swapSubtitles(toSet);
}
} catch (e: Throwable) {
Logger.e(TAG, "handleSelectSubtitleTrack failed", e)

View file

@ -28,6 +28,7 @@ import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.experimental_casting.ExpStateCasting
import com.futo.platformplayer.experimental_casting.StateCastingDispatcher
import com.futo.platformplayer.formatDuration
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateHistory
@ -142,13 +143,8 @@ class CastView : ConstraintLayout {
}
_gestureControlView.onSeek.subscribe {
if (Settings.instance.casting.experimentalCasting) {
val d = ExpStateCasting.instance.activeDevice ?: return@subscribe;
ExpStateCasting.instance.videoSeekTo(d.expectedCurrentTime + it / 1000);
} else {
val d = StateCasting.instance.activeDevice ?: return@subscribe;
StateCasting.instance.videoSeekTo(d.expectedCurrentTime + it / 1000);
}
val expectedCurrentTime = StateCastingDispatcher.getExpectedCurrentTime() ?: return@subscribe
StateCastingDispatcher.videoSeekTo(expectedCurrentTime + it / 1000)
};
_buttonLoop.setOnClickListener {
@ -159,45 +155,25 @@ class CastView : ConstraintLayout {
_timeBar.addListener(object : TimeBar.OnScrubListener {
override fun onScrubStart(timeBar: TimeBar, position: Long) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.videoSeekTo(position.toDouble());
} else {
StateCasting.instance.videoSeekTo(position.toDouble());
}
StateCastingDispatcher.videoSeekTo(position.toDouble())
}
override fun onScrubMove(timeBar: TimeBar, position: Long) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.videoSeekTo(position.toDouble());
} else {
StateCasting.instance.videoSeekTo(position.toDouble());
}
StateCastingDispatcher.videoSeekTo(position.toDouble())
}
override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.videoSeekTo(position.toDouble());
} else {
StateCasting.instance.videoSeekTo(position.toDouble());
}
StateCastingDispatcher.videoSeekTo(position.toDouble())
}
});
_buttonMinimize.setOnClickListener { onMinimizeClick.emit(); };
_buttonSettings.setOnClickListener { onSettingsClick.emit(); };
_buttonPlay.setOnClickListener {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.resumeVideo()
} else {
StateCasting.instance.resumeVideo()
}
StateCastingDispatcher.resumeVideo()
}
_buttonPause.setOnClickListener {
if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.pauseVideo()
} else {
StateCasting.instance.pauseVideo()
}
StateCastingDispatcher.pauseVideo()
}
if (!isInEditMode) {
@ -311,11 +287,7 @@ class CastView : ConstraintLayout {
_buttonPlay.visibility = View.VISIBLE;
}
val position = if (Settings.instance.casting.experimentalCasting) {
ExpStateCasting.instance.activeDevice?.expectedCurrentTime?.times(1000.0)?.toLong()
} else {
StateCasting.instance.activeDevice?.expectedCurrentTime?.times(1000.0)?.toLong();
}
val position = StateCastingDispatcher.getExpectedCurrentTime()?.times(1000.0)?.toLong()
if(StatePlayer.instance.hasMediaSession()) {
StatePlayer.instance.updateMediaSession(null);
StatePlayer.instance.updateMediaSessionPlaybackState(getPlaybackStateCompat(), (position ?: 0));
@ -379,20 +351,12 @@ class CastView : ConstraintLayout {
}
private fun getPlaybackStateCompat(): Int {
if (Settings.instance.casting.experimentalCasting) {
val d = ExpStateCasting.instance.activeDevice ?: return PlaybackState.STATE_NONE;
return when(d.isPlaying) {
true -> PlaybackStateCompat.STATE_PLAYING;
else -> PlaybackStateCompat.STATE_PAUSED;
}
} else {
val d = StateCasting.instance.activeDevice ?: return PlaybackState.STATE_NONE;
return when(d.isPlaying) {
true -> PlaybackStateCompat.STATE_PLAYING;
else -> PlaybackStateCompat.STATE_PAUSED;
}
if (!StateCastingDispatcher.isConnected()) {
return PlaybackState.STATE_NONE
}
return when(StateCastingDispatcher.isPlaying()) {
true -> PlaybackStateCompat.STATE_PLAYING;
else -> PlaybackStateCompat.STATE_PAUSED;
}
}