mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-21 18:00:49 +00:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
b9239b6177
2 changed files with 134 additions and 124 deletions
|
@ -438,10 +438,11 @@ class StateCasting {
|
||||||
_castId.incrementAndGet()
|
_castId.incrementAndGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun castIfAvailable(contentResolver: ContentResolver, video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, ms: Long = -1, speed: Double?, onLoadingEstimate: ((Int) -> Unit)? = null, onLoading: ((Boolean) -> Unit)? = null): Boolean {
|
suspend fun castIfAvailable(contentResolver: ContentResolver, video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, ms: Long = -1, speed: Double?, onLoadingEstimate: ((Int) -> Unit)? = null, onLoading: ((Boolean) -> Unit)? = null): Boolean {
|
||||||
val ad = activeDevice ?: return false;
|
return withContext(Dispatchers.IO) {
|
||||||
|
val ad = activeDevice ?: return@withContext false;
|
||||||
if (ad.connectionState != CastConnectionState.CONNECTED) {
|
if (ad.connectionState != CastConnectionState.CONNECTED) {
|
||||||
return false;
|
return@withContext false;
|
||||||
}
|
}
|
||||||
|
|
||||||
val resumePosition = if (ms > 0L) (ms.toDouble() / 1000.0) else 0.0;
|
val resumePosition = if (ms > 0L) (ms.toDouble() / 1000.0) else 0.0;
|
||||||
|
@ -466,17 +467,11 @@ class StateCasting {
|
||||||
castLocalDash(video, videoSource as LocalVideoSource?, audioSource as LocalAudioSource?, subtitleSource as LocalSubtitleSource?, resumePosition, speed);
|
castLocalDash(video, videoSource as LocalVideoSource?, audioSource as LocalAudioSource?, subtitleSource as LocalSubtitleSource?, resumePosition, speed);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
StateApp.instance.scope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
val isRawDash = videoSource is JSDashManifestRawSource || audioSource is JSDashManifestRawAudioSource
|
val isRawDash = videoSource is JSDashManifestRawSource || audioSource is JSDashManifestRawAudioSource
|
||||||
if (isRawDash) {
|
if (isRawDash) {
|
||||||
Logger.i(TAG, "Casting as raw DASH");
|
Logger.i(TAG, "Casting as raw DASH");
|
||||||
|
|
||||||
try {
|
|
||||||
castDashRaw(contentResolver, video, videoSource as JSDashManifestRawSource?, audioSource as JSDashManifestRawAudioSource?, subtitleSource, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
castDashRaw(contentResolver, video, videoSource as JSDashManifestRawSource?, audioSource as JSDashManifestRawAudioSource?, subtitleSource, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to start casting DASH raw videoSource=${videoSource} audioSource=${audioSource}.", e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (ad is FCastCastingDevice) {
|
if (ad is FCastCastingDevice) {
|
||||||
Logger.i(TAG, "Casting as DASH direct");
|
Logger.i(TAG, "Casting as DASH direct");
|
||||||
|
@ -489,10 +484,6 @@ class StateCasting {
|
||||||
castDashIndirect(contentResolver, video, videoSource as IVideoUrlSource?, audioSource as IAudioUrlSource?, subtitleSource, resumePosition, speed);
|
castDashIndirect(contentResolver, video, videoSource as IVideoUrlSource?, audioSource as IAudioUrlSource?, subtitleSource, resumePosition, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to start casting DASH videoSource=${videoSource} audioSource=${audioSource}.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val proxyStreams = Settings.instance.casting.alwaysProxyRequests;
|
val proxyStreams = Settings.instance.casting.alwaysProxyRequests;
|
||||||
|
@ -533,24 +524,10 @@ class StateCasting {
|
||||||
castLocalAudio(video, audioSource, resumePosition, speed);
|
castLocalAudio(video, audioSource, resumePosition, speed);
|
||||||
} else if (videoSource is JSDashManifestRawSource) {
|
} else if (videoSource is JSDashManifestRawSource) {
|
||||||
Logger.i(TAG, "Casting as JSDashManifestRawSource video");
|
Logger.i(TAG, "Casting as JSDashManifestRawSource video");
|
||||||
|
|
||||||
StateApp.instance.scope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
castDashRaw(contentResolver, video, videoSource as JSDashManifestRawSource?, null, null, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
castDashRaw(contentResolver, video, videoSource as JSDashManifestRawSource?, null, null, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to start casting DASH raw videoSource=${videoSource}.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (audioSource is JSDashManifestRawAudioSource) {
|
} else if (audioSource is JSDashManifestRawAudioSource) {
|
||||||
Logger.i(TAG, "Casting as JSDashManifestRawSource audio");
|
Logger.i(TAG, "Casting as JSDashManifestRawSource audio");
|
||||||
|
|
||||||
StateApp.instance.scope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
castDashRaw(contentResolver, video, null, audioSource as JSDashManifestRawAudioSource?, null, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
castDashRaw(contentResolver, video, null, audioSource as JSDashManifestRawAudioSource?, null, resumePosition, speed, castId, onLoadingEstimate, onLoading);
|
||||||
} catch (e: Throwable) {
|
|
||||||
Logger.e(TAG, "Failed to start casting DASH raw audioSource=${audioSource}.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
var str = listOf(
|
var str = listOf(
|
||||||
if(videoSource != null) "Video: ${videoSource::class.java.simpleName}" else null,
|
if(videoSource != null) "Video: ${videoSource::class.java.simpleName}" else null,
|
||||||
|
@ -561,7 +538,8 @@ class StateCasting {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return@withContext true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resumeVideo(): Boolean {
|
fun resumeVideo(): Boolean {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.app.PictureInPictureParams
|
||||||
import android.app.RemoteAction
|
import android.app.RemoteAction
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
@ -79,7 +80,9 @@ import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
||||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.models.JSVideo
|
||||||
import com.futo.platformplayer.api.media.platforms.js.models.JSVideoDetails
|
import com.futo.platformplayer.api.media.platforms.js.models.JSVideoDetails
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSSource
|
||||||
import com.futo.platformplayer.api.media.structures.IPager
|
import com.futo.platformplayer.api.media.structures.IPager
|
||||||
import com.futo.platformplayer.casting.CastConnectionState
|
import com.futo.platformplayer.casting.CastConnectionState
|
||||||
import com.futo.platformplayer.casting.StateCasting
|
import com.futo.platformplayer.casting.StateCasting
|
||||||
|
@ -1900,17 +1903,46 @@ class VideoDetailView : ConstraintLayout {
|
||||||
}
|
}
|
||||||
private fun loadCurrentVideoCast(video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, resumePositionMs: Long, speed: Double?) {
|
private fun loadCurrentVideoCast(video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, resumePositionMs: Long, speed: Double?) {
|
||||||
Logger.i(TAG, "loadCurrentVideoCast(video=$video, videoSource=$videoSource, audioSource=$audioSource, resumePositionMs=$resumePositionMs)")
|
Logger.i(TAG, "loadCurrentVideoCast(video=$video, videoSource=$videoSource, audioSource=$audioSource, resumePositionMs=$resumePositionMs)")
|
||||||
|
castIfAvailable(context.contentResolver, video, videoSource, audioSource, subtitleSource, resumePositionMs, speed)
|
||||||
|
}
|
||||||
|
|
||||||
val castSucceeded = StateCasting.instance.castIfAvailable(context.contentResolver, video, videoSource, audioSource, subtitleSource, resumePositionMs, speed, onLoading = {
|
private fun castIfAvailable(contentResolver: ContentResolver, video: IPlatformVideoDetails, videoSource: IVideoSource?, audioSource: IAudioSource?, subtitleSource: ISubtitleSource?, resumePositionMs: Long, speed: Double?) {
|
||||||
|
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val plugin = if (videoSource is JSSource) videoSource.getUnderlyingPlugin()
|
||||||
|
else if (audioSource is JSSource) audioSource.getUnderlyingPlugin()
|
||||||
|
else null
|
||||||
|
|
||||||
|
val startId = plugin?.getUnderlyingPlugin()?.runtimeId
|
||||||
|
try {
|
||||||
|
val castingSucceeded = StateCasting.instance.castIfAvailable(contentResolver, video, videoSource, audioSource, subtitleSource, resumePositionMs, speed, onLoading = {
|
||||||
_cast.setLoading(it)
|
_cast.setLoading(it)
|
||||||
}, onLoadingEstimate = {
|
}, onLoadingEstimate = {
|
||||||
_cast.setLoading(it)
|
_cast.setLoading(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (castSucceeded) {
|
if (castingSucceeded) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
_cast.setVideoDetails(video, resumePositionMs / 1000);
|
_cast.setVideoDetails(video, resumePositionMs / 1000);
|
||||||
setCastEnabled(true);
|
setCastEnabled(true);
|
||||||
} else throw IllegalStateException("Disconnected cast during loading");
|
}
|
||||||
|
}
|
||||||
|
} catch (e: ScriptReloadRequiredException) {
|
||||||
|
Log.i(TAG, "Reload required exception", e)
|
||||||
|
if (plugin == null)
|
||||||
|
throw e
|
||||||
|
|
||||||
|
if (startId != -1 && plugin.getUnderlyingPlugin().runtimeId != startId)
|
||||||
|
throw e
|
||||||
|
|
||||||
|
StatePlatform.instance.handleReloadRequired(e, {
|
||||||
|
fetchVideo()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.e(TAG, "loadCurrentVideoCast", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Events
|
//Events
|
||||||
|
@ -2423,7 +2455,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
val d = StateCasting.instance.activeDevice;
|
val d = StateCasting.instance.activeDevice;
|
||||||
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
||||||
StateCasting.instance.castIfAvailable(context.contentResolver, video, videoSource, _lastAudioSource, _lastSubtitleSource, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
|
castIfAvailable(context.contentResolver, video, videoSource, _lastAudioSource, _lastSubtitleSource, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
|
||||||
else if(!_player.swapSources(videoSource, _lastAudioSource, true, true, true))
|
else if(!_player.swapSources(videoSource, _lastAudioSource, true, true, true))
|
||||||
_player.hideControls(false); //TODO: Disable player?
|
_player.hideControls(false); //TODO: Disable player?
|
||||||
|
|
||||||
|
@ -2438,7 +2470,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
val d = StateCasting.instance.activeDevice;
|
val d = StateCasting.instance.activeDevice;
|
||||||
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
||||||
StateCasting.instance.castIfAvailable(context.contentResolver, video, _lastVideoSource, audioSource, _lastSubtitleSource, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
|
castIfAvailable(context.contentResolver, video, _lastVideoSource, audioSource, _lastSubtitleSource, (d.expectedCurrentTime * 1000.0).toLong(), d.speed)
|
||||||
else(!_player.swapSources(_lastVideoSource, audioSource, true, true, true))
|
else(!_player.swapSources(_lastVideoSource, audioSource, true, true, true))
|
||||||
_player.hideControls(false); //TODO: Disable player?
|
_player.hideControls(false); //TODO: Disable player?
|
||||||
|
|
||||||
|
@ -2454,7 +2486,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
val d = StateCasting.instance.activeDevice;
|
val d = StateCasting.instance.activeDevice;
|
||||||
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
if (d != null && d.connectionState == CastConnectionState.CONNECTED)
|
||||||
StateCasting.instance.castIfAvailable(context.contentResolver, video, _lastVideoSource, _lastAudioSource, toSet, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
|
castIfAvailable(context.contentResolver, video, _lastVideoSource, _lastAudioSource, toSet, (d.expectedCurrentTime * 1000.0).toLong(), d.speed);
|
||||||
else
|
else
|
||||||
_player.swapSubtitles(fragment.lifecycleScope, toSet);
|
_player.swapSubtitles(fragment.lifecycleScope, toSet);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue