mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-10 19:46:10 +00:00
casting: catch exceptions for playback control functions
# Conflicts: # app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt # app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt
This commit is contained in:
parent
7169cd1b82
commit
0fd83cbd74
10 changed files with 104 additions and 79 deletions
|
@ -128,7 +128,7 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
synchronized(ExpStateCasting.instance.devices) {
|
||||
_devices.addAll(ExpStateCasting.instance.devices.values.map { it.device.name() })
|
||||
}
|
||||
_rememberedDevices.addAll(StateCasting.instance.getRememberedCastingDeviceNames())
|
||||
_rememberedDevices.addAll(ExpStateCasting.instance.getRememberedCastingDeviceNames())
|
||||
} else {
|
||||
synchronized(StateCasting.instance.devices) {
|
||||
_devices.addAll(StateCasting.instance.devices.values.mapNotNull { it.name })
|
||||
|
@ -203,10 +203,17 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
override fun dismiss() {
|
||||
super.dismiss()
|
||||
(_imageLoader.drawable as Animatable?)?.stop()
|
||||
StateCasting.instance.onDeviceAdded.remove(this)
|
||||
StateCasting.instance.onDeviceChanged.remove(this)
|
||||
StateCasting.instance.onDeviceRemoved.remove(this)
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this)
|
||||
if (Settings.instance.casting.experimentalCasting) {
|
||||
ExpStateCasting.instance.onDeviceAdded.remove(this)
|
||||
ExpStateCasting.instance.onDeviceChanged.remove(this)
|
||||
ExpStateCasting.instance.onDeviceRemoved.remove(this)
|
||||
ExpStateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this)
|
||||
} else {
|
||||
StateCasting.instance.onDeviceAdded.remove(this)
|
||||
StateCasting.instance.onDeviceChanged.remove(this)
|
||||
StateCasting.instance.onDeviceRemoved.remove(this)
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateUnifiedList() {
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.futo.platformplayer.experimental_casting.ExpStateCasting
|
|||
import com.futo.platformplayer.fragment.mainactivity.main.VideoDetailFragment
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.views.adapters.GenericCastingDevice
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.slider.Slider.OnChangeListener
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -49,7 +50,7 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
private lateinit var _buttonStop: ImageButton;
|
||||
private lateinit var _buttonNext: ImageButton;
|
||||
|
||||
private var _device: CastingDevice? = null;
|
||||
private var _device: GenericCastingDevice? = null;
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -178,7 +179,7 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
}
|
||||
|
||||
ExpStateCasting.instance.onActiveDeviceTimeChanged.remove(this)
|
||||
StateCasting.instance.onActiveDeviceTimeChanged.subscribe {
|
||||
ExpStateCasting.instance.onActiveDeviceTimeChanged.subscribe {
|
||||
_sliderPosition.value = it.toFloat().coerceAtLeast(0.0f).coerceAtMost(_sliderPosition.valueTo)
|
||||
}
|
||||
|
||||
|
@ -189,16 +190,18 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
_sliderPosition.valueTo = dur
|
||||
}
|
||||
|
||||
_device = StateCasting.instance.activeDevice
|
||||
val d = _device
|
||||
val isConnected = d != null && d.connectionState == CastConnectionState.CONNECTED
|
||||
val ad = ExpStateCasting.instance.activeDevice
|
||||
if (ad != null) {
|
||||
_device = GenericCastingDevice.Experimental(ad)
|
||||
}
|
||||
val isConnected = ad != null && ad.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED
|
||||
setLoading(!isConnected)
|
||||
ExpStateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState ->
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||
setLoading(connectionState != com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED)
|
||||
}
|
||||
updateDevice();
|
||||
};
|
||||
updateDevice()
|
||||
}
|
||||
} else {
|
||||
StateCasting.instance.onActiveDeviceVolumeChanged.remove(this);
|
||||
StateCasting.instance.onActiveDeviceVolumeChanged.subscribe {
|
||||
|
@ -217,14 +220,16 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
_sliderPosition.valueTo = dur
|
||||
};
|
||||
|
||||
_device = StateCasting.instance.activeDevice;
|
||||
val d = _device;
|
||||
val isConnected = d != null && d.connectionState == CastConnectionState.CONNECTED;
|
||||
val ad = StateCasting.instance.activeDevice
|
||||
if (ad != null) {
|
||||
_device = GenericCastingDevice.Normal(ad)
|
||||
}
|
||||
val isConnected = ad != null && ad.connectionState == CastConnectionState.CONNECTED;
|
||||
setLoading(!isConnected);
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState ->
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { setLoading(connectionState != CastConnectionState.CONNECTED); };
|
||||
updateDevice();
|
||||
};
|
||||
updateDevice()
|
||||
}
|
||||
}
|
||||
|
||||
updateDevice();
|
||||
|
@ -235,12 +240,12 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) {
|
|||
StateCasting.instance.onActiveDeviceVolumeChanged.remove(this);
|
||||
StateCasting.instance.onActiveDeviceDurationChanged.remove(this);
|
||||
StateCasting.instance.onActiveDeviceTimeChanged.remove(this);
|
||||
_device = null;
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
ExpStateCasting.instance.onActiveDeviceVolumeChanged.remove(this);
|
||||
ExpStateCasting.instance.onActiveDeviceDurationChanged.remove(this);
|
||||
ExpStateCasting.instance.onActiveDeviceTimeChanged.remove(this);
|
||||
ExpStateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
_device = null;
|
||||
}
|
||||
|
||||
private fun updateDevice() {
|
||||
|
|
|
@ -110,7 +110,7 @@ class CastingDeviceHandle {
|
|||
) {
|
||||
try {
|
||||
device.loadVideo(contentType, contentId, resumePosition, speed)
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
Logger.e("CastingDevice", "Failed to load video: $e")
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,11 @@ class CastingDeviceHandle {
|
|||
duration: Double,
|
||||
speed: Double?
|
||||
) {
|
||||
device.loadContent(contentType, content, resumePosition, duration, speed)
|
||||
try {
|
||||
device.loadContent(contentType, content, resumePosition, duration, speed)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e("CastingDevice", "Failed to load content: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,11 @@ class ExpStateCasting {
|
|||
_resumeCastingDevice = ad.device.getDeviceInfo()
|
||||
Log.i(TAG, "_resumeCastingDevice set to '${ad.device.name()}'")
|
||||
Logger.i(TAG, "Stopping active device because of onStop.")
|
||||
ad.device.disconnect()
|
||||
try {
|
||||
ad.device.disconnect()
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to disconnect from device: $e")
|
||||
}
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
|
@ -248,7 +252,11 @@ class ExpStateCasting {
|
|||
device.eventHandler.onTimeChanged.clear();
|
||||
device.eventHandler.onVolumeChanged.clear();
|
||||
device.eventHandler.onDurationChanged.clear();
|
||||
ad.device.disconnect();
|
||||
try {
|
||||
ad.device.disconnect();
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to disconnect from device: $e")
|
||||
}
|
||||
}
|
||||
|
||||
device.eventHandler.onConnectionStateChanged.subscribe { castConnectionState ->
|
||||
|
@ -441,6 +449,10 @@ class ExpStateCasting {
|
|||
return Settings.instance.casting.alwaysProxyRequests || deviceHandle.device.castingProtocol() != ProtocolType.F_CAST || hasRequestModifier
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
_castId.incrementAndGet()
|
||||
}
|
||||
|
||||
suspend fun castIfAvailable(
|
||||
contentResolver: ContentResolver,
|
||||
video: IPlatformVideoDetails,
|
||||
|
@ -541,7 +553,7 @@ class ExpStateCasting {
|
|||
resumePosition,
|
||||
video.duration.toDouble(),
|
||||
speed
|
||||
);
|
||||
)
|
||||
} else if (audioSource is IAudioUrlSource) {
|
||||
val audioPath = "/audio-${id}"
|
||||
val audioUrl = if (proxyStreams) url + audioPath else audioSource.getAudioUrl();
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
|||
import com.futo.platformplayer.casting.StateCasting
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.experimental_casting.ExpStateCasting
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.models.PlatformVideoWithTime
|
||||
import com.futo.platformplayer.models.UrlVideoWithTime
|
||||
|
@ -437,7 +438,7 @@ class VideoDetailFragment() : MainFragment() {
|
|||
|
||||
fun onUserLeaveHint() {
|
||||
val viewDetail = _viewDetail;
|
||||
Logger.i(TAG, "onUserLeaveHint preventPictureInPicture=${viewDetail?.preventPictureInPicture} isCasting=${StateCasting.instance.isCasting} isBackgroundPictureInPicture=${Settings.instance.playback.isBackgroundPictureInPicture()} allowBackground=${viewDetail?.isAudioOnlyUserAction}");
|
||||
Logger.i(TAG, "onUserLeaveHint preventPictureInPicture=${viewDetail?.preventPictureInPicture} isCasting=${StateCasting.instance.isCasting} isBackgroundPictureInPicture=${Settings.instance.playback.isBackgroundPictureInPicture()} allowBackground=${viewDetail?.allowBackground}");
|
||||
|
||||
if (viewDetail === null) {
|
||||
return
|
||||
|
@ -446,7 +447,7 @@ class VideoDetailFragment() : MainFragment() {
|
|||
if (viewDetail.shouldEnterPictureInPicture) {
|
||||
_leavingPiP = false
|
||||
}
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.S && viewDetail.preventPictureInPicture == false && !StateCasting.instance.isCasting && Settings.instance.playback.isBackgroundPictureInPicture() && !viewDetail.isAudioOnlyUserAction) {
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.S && viewDetail.preventPictureInPicture == false && !StateCasting.instance.isCasting && Settings.instance.playback.isBackgroundPictureInPicture() && !viewDetail.allowBackground) {
|
||||
val params = _viewDetail?.getPictureInPictureParams();
|
||||
if(params != null) {
|
||||
Logger.i(TAG, "enterPictureInPictureMode")
|
||||
|
@ -526,7 +527,7 @@ class VideoDetailFragment() : MainFragment() {
|
|||
|
||||
private fun stopIfRequired() {
|
||||
var shouldStop = true;
|
||||
if (_viewDetail?.isAudioOnlyUserAction == true) {
|
||||
if (_viewDetail?.allowBackground == true) {
|
||||
shouldStop = false;
|
||||
} else if (Settings.instance.playback.isBackgroundPictureInPicture() && !_leavingPiP) {
|
||||
shouldStop = false;
|
||||
|
|
|
@ -325,7 +325,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
val onEnterPictureInPicture = Event0();
|
||||
val onVideoChanged = Event2<Int, Int>()
|
||||
|
||||
var isAudioOnlyUserAction: Boolean = false
|
||||
var allowBackground: Boolean = false
|
||||
private set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
|
@ -337,7 +337,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
get() = !preventPictureInPicture &&
|
||||
!StateCasting.instance.isCasting &&
|
||||
Settings.instance.playback.isBackgroundPictureInPicture() &&
|
||||
!isAudioOnlyUserAction &&
|
||||
!allowBackground &&
|
||||
isPlaying
|
||||
|
||||
val onShouldEnterPictureInPictureChanged = Event0();
|
||||
|
@ -808,7 +808,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
MediaControlReceiver.onBackgroundReceived.subscribe(this) {
|
||||
Logger.i(TAG, "MediaControlReceiver.onBackgroundReceived")
|
||||
_player.switchToAudioMode(video);
|
||||
isAudioOnlyUserAction = true;
|
||||
allowBackground = true;
|
||||
StateApp.instance.contextOrNull?.let {
|
||||
try {
|
||||
if (it is MainActivity) {
|
||||
|
@ -1052,26 +1052,15 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
}
|
||||
_slideUpOverlay?.hide();
|
||||
} else if(video is JSVideoDetails && (video as JSVideoDetails).hasVODEvents())
|
||||
RoundButton(context, R.drawable.ic_chat, context.getString(R.string.vod_chat), TAG_VODCHAT) {
|
||||
video?.let {
|
||||
try {
|
||||
loadVODChat(it);
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to reopen vod chat", ex);
|
||||
}
|
||||
}
|
||||
_slideUpOverlay?.hide();
|
||||
} else null,
|
||||
if (!isLimitedVersion) RoundButton(context, R.drawable.ic_screen_share, if (isAudioOnlyUserAction) context.getString(R.string.background_revert) else context.getString(R.string.background), TAG_BACKGROUND) {
|
||||
if (!isAudioOnlyUserAction) {
|
||||
if (!isLimitedVersion) RoundButton(context, R.drawable.ic_screen_share, if (allowBackground) context.getString(R.string.background_revert) else context.getString(R.string.background), TAG_BACKGROUND) {
|
||||
if (!allowBackground) {
|
||||
_player.switchToAudioMode(video);
|
||||
isAudioOnlyUserAction = true;
|
||||
allowBackground = true;
|
||||
it.text.text = resources.getString(R.string.background_revert);
|
||||
} else {
|
||||
_player.switchToVideoMode();
|
||||
isAudioOnlyUserAction = false;
|
||||
allowBackground = false;
|
||||
it.text.text = resources.getString(R.string.background);
|
||||
}
|
||||
_slideUpOverlay?.hide();
|
||||
|
@ -1187,23 +1176,19 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
|
||||
//Lifecycle
|
||||
var isLoginStop = false; //TODO: This is a bit jank, but easiest solution for now without reworking flow. (Alternatively, fix MainActivity getting stopped/disposing video)
|
||||
fun onResume() {
|
||||
Logger.v(TAG, "onResume");
|
||||
_onPauseCalled = false;
|
||||
|
||||
val wasLoginCall = isLoginStop;
|
||||
isLoginStop = false;
|
||||
|
||||
Logger.i(TAG, "_video: ${video?.name ?: "no video"}");
|
||||
Logger.i(TAG, "_didStop: $_didStop");
|
||||
|
||||
//Recover cancelled loads
|
||||
if(video == null) {
|
||||
val t = (lastPositionMilliseconds / 1000.0f).roundToLong();
|
||||
if(_searchVideo != null && !wasLoginCall)
|
||||
if(_searchVideo != null)
|
||||
setVideoOverview(_searchVideo!!, true, t);
|
||||
else if(_url != null && !wasLoginCall)
|
||||
else if(_url != null)
|
||||
setVideo(_url!!, t, _playWhenReady);
|
||||
}
|
||||
else if(_didStop) {
|
||||
|
@ -1215,14 +1200,11 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
if(_player.isAudioMode) {
|
||||
//Requested behavior to leave it in audio mode. leaving it commented if it causes issues, revert?
|
||||
if(!isAudioOnlyUserAction) {
|
||||
if(!allowBackground) {
|
||||
_player.switchToVideoMode();
|
||||
isAudioOnlyUserAction = false;
|
||||
allowBackground = false;
|
||||
_buttonPins.getButtonByTag(TAG_BACKGROUND)?.text?.text = resources.getString(R.string.background);
|
||||
}
|
||||
else {
|
||||
_buttonPins.getButtonByTag(TAG_BACKGROUND)?.text?.text = resources.getString(R.string.video);
|
||||
}
|
||||
}
|
||||
if(!_player.isFitMode && !_player.isFullScreen && !fragment.isInPictureInPicture)
|
||||
_player.fitHeight();
|
||||
|
@ -1243,7 +1225,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
return;
|
||||
}
|
||||
|
||||
if(isAudioOnlyUserAction)
|
||||
if(allowBackground)
|
||||
StatePlayer.instance.startOrUpdateMediaSession(context, video);
|
||||
else {
|
||||
when (Settings.instance.playback.backgroundPlay) {
|
||||
|
@ -1251,6 +1233,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
1 -> {
|
||||
if(!(video?.isLive ?: false)) {
|
||||
_player.switchToAudioMode(video);
|
||||
allowBackground = true;
|
||||
}
|
||||
StatePlayer.instance.startOrUpdateMediaSession(context, video);
|
||||
}
|
||||
|
@ -1273,7 +1256,6 @@ class VideoDetailView : ConstraintLayout {
|
|||
_taskLoadVideo.cancel();
|
||||
handleStop();
|
||||
_didStop = true;
|
||||
onShouldEnterPictureInPictureChanged.emit()
|
||||
Logger.i(TAG, "_didStop set to true");
|
||||
|
||||
StatePlayer.instance.rotationLock = false;
|
||||
|
@ -2048,10 +2030,10 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
if (isLimitedVersion && _player.isAudioMode) {
|
||||
_player.switchToVideoMode()
|
||||
isAudioOnlyUserAction = false;
|
||||
allowBackground = false;
|
||||
} else {
|
||||
val thumbnail = video.thumbnails.getHQThumbnail();
|
||||
if ((videoSource == null) && !thumbnail.isNullOrBlank()) // || _player.isAudioMode
|
||||
if ((videoSource == null || _player.isAudioMode) && !thumbnail.isNullOrBlank())
|
||||
Glide.with(context).asBitmap().load(thumbnail)
|
||||
.into(object: CustomTarget<Bitmap>() {
|
||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||
|
@ -2626,7 +2608,6 @@ class VideoDetailView : ConstraintLayout {
|
|||
_player.play();
|
||||
}
|
||||
}
|
||||
onShouldEnterPictureInPictureChanged.emit()
|
||||
|
||||
//TODO: This was needed because handleLowerVolume was done.
|
||||
//_player.setVolume(1.0f);
|
||||
|
@ -2649,7 +2630,6 @@ class VideoDetailView : ConstraintLayout {
|
|||
_player.pause()
|
||||
}
|
||||
}
|
||||
onShouldEnterPictureInPictureChanged.emit()
|
||||
}
|
||||
private fun handleSeek(ms: Long) {
|
||||
Logger.i(TAG, "handleSeek(ms=$ms)")
|
||||
|
@ -3483,13 +3463,8 @@ class VideoDetailView : ConstraintLayout {
|
|||
val id = e.config.let { if(it is SourcePluginConfig) it.id else null };
|
||||
val didLogin = if(id == null)
|
||||
false
|
||||
else {
|
||||
isLoginStop = true;
|
||||
StatePlugins.instance.loginPlugin(context, id) {
|
||||
fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||
fetchVideo();
|
||||
}
|
||||
}
|
||||
else StatePlugins.instance.loginPlugin(context, id) {
|
||||
fetchVideo();
|
||||
}
|
||||
if(!didLogin)
|
||||
UIDialogs.showDialogOk(context, R.drawable.ic_error_pred, "Failed to login");
|
||||
|
@ -3667,7 +3642,6 @@ class VideoDetailView : ConstraintLayout {
|
|||
const val TAG_SHARE = "share";
|
||||
const val TAG_OVERLAY = "overlay";
|
||||
const val TAG_LIVECHAT = "livechat";
|
||||
const val TAG_VODCHAT = "vodchat";
|
||||
const val TAG_CHAPTERS = "chapters";
|
||||
const val TAG_OPEN = "open";
|
||||
const val TAG_SEND_TO_DEVICE = "send_to_device";
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.futo.platformplayer.casting.StateCasting
|
|||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
|
||||
import com.futo.platformplayer.experimental_casting.ExpStateCasting
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.HomeFragment
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.SourceDetailFragment
|
||||
import com.futo.platformplayer.logging.AndroidLogConsumer
|
||||
|
@ -759,7 +760,11 @@ class StateApp {
|
|||
_connectivityManager?.unregisterNetworkCallback(_connectivityEvents);
|
||||
|
||||
StatePlayer.instance.closeMediaSession();
|
||||
StateCasting.instance.stop();
|
||||
if (Settings.instance.casting.experimentalCasting) {
|
||||
ExpStateCasting.instance.stop()
|
||||
} else {
|
||||
StateCasting.instance.stop()
|
||||
}
|
||||
StateSync.instance.stop();
|
||||
StatePlayer.dispose();
|
||||
Companion.dispose();
|
||||
|
|
|
@ -73,7 +73,11 @@ class DeviceViewHolder : ViewHolder {
|
|||
is GenericCastingDevice.Experimental -> {
|
||||
if (dev.handle.device.isReady()) {
|
||||
// NOTE: we assume experimental casting is used
|
||||
ExpStateCasting.instance.activeDevice?.device?.stopCasting()
|
||||
try {
|
||||
ExpStateCasting.instance.activeDevice?.device?.stopCasting()
|
||||
} catch (e: Throwable) {
|
||||
//Ignored
|
||||
}
|
||||
ExpStateCasting.instance.connectDevice(dev.handle)
|
||||
onConnect.emit(dev)
|
||||
} else {
|
||||
|
@ -125,7 +129,7 @@ class DeviceViewHolder : ViewHolder {
|
|||
_textNotReady.visibility = View.GONE;
|
||||
|
||||
val dev = StateCasting.instance.activeDevice;
|
||||
if (dev == d) {
|
||||
if (dev == d.device) {
|
||||
if (dev.connectionState == CastConnectionState.CONNECTED) {
|
||||
_imageLoader.visibility = View.GONE;
|
||||
_textNotReady.visibility = View.GONE;
|
||||
|
@ -180,9 +184,9 @@ class DeviceViewHolder : ViewHolder {
|
|||
} else {
|
||||
_textNotReady.visibility = View.GONE;
|
||||
|
||||
val dev = StateCasting.instance.activeDevice;
|
||||
if (dev == d) {
|
||||
if (dev.connectionState == CastConnectionState.CONNECTED) {
|
||||
val dev = ExpStateCasting.instance.activeDevice;
|
||||
if (dev == d.handle) {
|
||||
if (dev.connectionState == com.futo.platformplayer.experimental_casting.CastConnectionState.CONNECTED) {
|
||||
_imageLoader.visibility = View.GONE;
|
||||
_textNotReady.visibility = View.GONE;
|
||||
_imagePin.visibility = View.VISIBLE;
|
||||
|
|
|
@ -12,6 +12,7 @@ import androidx.core.content.ContextCompat
|
|||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||
import com.futo.platformplayer.casting.CastConnectionState
|
||||
import com.futo.platformplayer.casting.StateCasting
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
|
@ -81,7 +82,10 @@ class CastButton : androidx.appcompat.widget.AppCompatImageButton {
|
|||
|
||||
fun cleanup() {
|
||||
setOnClickListener(null);
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
ExpStateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
if (Settings.instance.casting.experimentalCasting) {
|
||||
ExpStateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
} else {
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import com.futo.platformplayer.constructs.Event1
|
|||
import com.futo.platformplayer.constructs.Event2
|
||||
import com.futo.platformplayer.experimental_casting.ExpStateCasting
|
||||
import com.futo.platformplayer.formatDuration
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateHistory
|
||||
import com.futo.platformplayer.states.StatePlayer
|
||||
import com.futo.platformplayer.views.TargetTapLoaderView
|
||||
|
@ -103,9 +104,17 @@ class CastView : ConstraintLayout {
|
|||
_speedHoldWasPlaying = d.isPlaying
|
||||
_speedHoldPrevRate = d.speed
|
||||
if (d.device.supportsFeature(DeviceFeature.SET_SPEED)) {
|
||||
d.device.changeSpeed(Settings.instance.playback.getHoldPlaybackSpeed())
|
||||
try {
|
||||
d.device.changeSpeed(Settings.instance.playback.getHoldPlaybackSpeed())
|
||||
} catch (e: Throwable) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
try {
|
||||
d.device.resumePlayback()
|
||||
} catch (e: Throwable) {
|
||||
// Ignored
|
||||
}
|
||||
d.device.resumePlayback()
|
||||
} else {
|
||||
val d = StateCasting.instance.activeDevice ?: return@subscribe;
|
||||
_speedHoldWasPlaying = d.isPlaying
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue