From 5a74b714b8b21518f27a9947c8a467bd178ad525 Mon Sep 17 00:00:00 2001 From: Marcus Hanestad Date: Thu, 21 Aug 2025 17:20:47 +0200 Subject: [PATCH] casting: update SDK to 0.2.1 --- app/build.gradle | 5 +++- .../dialogs/ConnectedCastingDialog.kt | 7 ++++- .../experimental_casting/CastingDevice.kt | 22 +++++++++----- .../experimental_casting/StateCasting.kt | 30 +++++++++---------- .../views/adapters/DeviceViewHolder.kt | 3 +- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e708fa1e..8d729051 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -233,5 +233,8 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' //Rust casting SDK - implementation "net.java.dev.jna:jna:5.12.0@aar" + implementation('org.futo.gitlab.videostreaming.fcast-sdk-jitpack:sender-sdk-minimal:0.2.1') { + // Polycentricandroid includes this + exclude group: 'net.java.dev.jna' + } } diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectedCastingDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectedCastingDialog.kt index 1dc9084b..a52fb38d 100644 --- a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectedCastingDialog.kt +++ b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectedCastingDialog.kt @@ -108,7 +108,12 @@ class ConnectedCastingDialog(context: Context?) : AlertDialog(context) { _buttonClose.setOnClickListener { dismiss(); }; _buttonDisconnect.setOnClickListener { if (Settings.instance.casting.experimentalCasting) { - ExpStateCasting.instance.activeDevice?.device?.stopCasting() + try { + ExpStateCasting.instance.activeDevice?.device?.stopPlayback() + ExpStateCasting.instance.activeDevice?.device?.disconnect() + } catch (e: Throwable) { + // Ignored + } } else { StateCasting.instance.activeDevice?.stopCasting(); } diff --git a/app/src/main/java/com/futo/platformplayer/experimental_casting/CastingDevice.kt b/app/src/main/java/com/futo/platformplayer/experimental_casting/CastingDevice.kt index 8be10138..6793b551 100644 --- a/app/src/main/java/com/futo/platformplayer/experimental_casting/CastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/experimental_casting/CastingDevice.kt @@ -19,6 +19,7 @@ import java.net.InetAddress import org.fcast.sender_sdk.CastingDevice as RsCastingDevice; import org.fcast.sender_sdk.DeviceEventHandler as RsDeviceEventHandler; import org.fcast.sender_sdk.DeviceConnectionState +import org.fcast.sender_sdk.LoadRequest class CastingDeviceHandle { class EventHandler : RsDeviceEventHandler { @@ -64,6 +65,10 @@ class CastingDeviceHandle { override fun mediaEvent(event: GenericMediaEvent) { // Unreachable } + + override fun playbackError(message: String) { + Logger.e(TAG, "Playback error: $message") + } } val eventHandler = EventHandler() @@ -91,17 +96,16 @@ class CastingDeviceHandle { eventHandler.onConnectionStateChanged.subscribe { newState -> if (newState == DeviceConnectionState.Disconnected) { try { - Logger.i("CastingDeviceHandle", "Stopping device") + Logger.i(TAG, "Stopping device") device.disconnect() } catch (e: Throwable) { - Logger.e("CastingDeviceHandle", "Failed to stop device: $e") + Logger.e(TAG, "Failed to stop device: $e") } } } } fun loadVideo( - streamType: String, contentType: String, contentId: String, resumePosition: Double, @@ -109,9 +113,9 @@ class CastingDeviceHandle { speed: Double? ) { try { - device.loadVideo(contentType, contentId, resumePosition, speed) + device.load(LoadRequest.Video(contentType, contentId, resumePosition, speed, duration)) } catch (e: Throwable) { - Logger.e("CastingDevice", "Failed to load video: $e") + Logger.e(TAG, "Failed to load video: $e") } } @@ -123,11 +127,15 @@ class CastingDeviceHandle { speed: Double? ) { try { - device.loadContent(contentType, content, resumePosition, duration, speed) + device.load(LoadRequest.Content(contentType, content, resumePosition, duration, speed)) } catch (e: Throwable) { - Logger.e("CastingDevice", "Failed to load content: $e") + Logger.e(TAG, "Failed to load content: $e") } } + + companion object { + private val TAG = "ExperimentalCastingDevice" + } } enum class CastConnectionState { diff --git a/app/src/main/java/com/futo/platformplayer/experimental_casting/StateCasting.kt b/app/src/main/java/com/futo/platformplayer/experimental_casting/StateCasting.kt index c34c6204..4589d537 100644 --- a/app/src/main/java/com/futo/platformplayer/experimental_casting/StateCasting.kt +++ b/app/src/main/java/com/futo/platformplayer/experimental_casting/StateCasting.kt @@ -7,6 +7,7 @@ import android.os.Looper import android.util.Log import androidx.annotation.OptIn import androidx.media3.common.util.UnstableApi +import com.futo.platformplayer.BuildConfig import com.futo.platformplayer.R import com.futo.platformplayer.Settings import com.futo.platformplayer.UIDialogs @@ -50,6 +51,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.fcast.sender_sdk.ApplicationInfo import java.net.Inet6Address import java.net.InetAddress import java.net.URLDecoder @@ -110,7 +112,9 @@ class ExpStateCasting { } init { - org.fcast.sender_sdk.initLogger(org.fcast.sender_sdk.LogLevelFilter.DEBUG) + if (BuildConfig.DEBUG) { + org.fcast.sender_sdk.initLogger(org.fcast.sender_sdk.LogLevelFilter.DEBUG) + } } fun handleUrl(context: Context, url: String) { @@ -382,7 +386,13 @@ class ExpStateCasting { } try { - device.device.connect(device.eventHandler) + device.device.connect( + ApplicationInfo( + "grayjay android", + "${BuildConfig.VERSION_NAME}-${BuildConfig.FLAVOR}", + "Grayjay" + ), device.eventHandler + ) Logger.i(TAG, "Requested manager to start device") } catch (e: Throwable) { Logger.w(TAG, "Failed to connect to device."); @@ -415,7 +425,7 @@ class ExpStateCasting { val rsDeviceInfo = device.device.getDeviceInfo() val deviceInfo = CastingDeviceInfo( name = device.device.name(), - type = when (rsDeviceInfo.type) { + type = when (rsDeviceInfo.protocol) { ProtocolType.CHROMECAST -> com.futo.platformplayer.casting.CastProtocolType.CHROMECAST ProtocolType.F_CAST -> com.futo.platformplayer.casting.CastProtocolType.FCAST }, @@ -547,7 +557,6 @@ class ExpStateCasting { val videoUrl = if (proxyStreams) url + videoPath else videoSource.getVideoUrl(); Logger.i(TAG, "Casting as singular video"); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", videoSource.container, videoUrl, resumePosition, @@ -559,7 +568,6 @@ class ExpStateCasting { val audioUrl = if (proxyStreams) url + audioPath else audioSource.getAudioUrl(); Logger.i(TAG, "Casting as singular audio"); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", audioSource.container, audioUrl, resumePosition, @@ -579,7 +587,6 @@ class ExpStateCasting { } else { Logger.i(TAG, "Casting as non-proxied HLS"); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", videoSource.container, videoSource.url, resumePosition, @@ -600,7 +607,6 @@ class ExpStateCasting { } else { Logger.i(TAG, "Casting as non-proxied audio HLS"); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", audioSource.container, audioSource.url, resumePosition, @@ -716,7 +722,6 @@ class ExpStateCasting { Logger.i(TAG, "Casting local video (videoUrl: $videoUrl)."); ad.loadVideo( - "BUFFERED", videoSource.container, videoUrl, resumePosition, @@ -747,7 +752,6 @@ class ExpStateCasting { Logger.i(TAG, "Casting local audio (audioUrl: $audioUrl)."); ad.loadVideo( - "BUFFERED", audioSource.container, audioUrl, resumePosition, @@ -941,7 +945,6 @@ class ExpStateCasting { "added new castLocalHls handlers (hlsPath: $hlsPath, videoPath: $videoPath, audioPath: $audioPath, subtitlePath: $subtitlePath)." ) ad.loadVideo( - "BUFFERED", "application/vnd.apple.mpegurl", hlsUrl, resumePosition, @@ -1021,7 +1024,6 @@ class ExpStateCasting { "added new castLocalDash handlers (dashPath: $dashPath, videoPath: $videoPath, audioPath: $audioPath, subtitlePath: $subtitlePath)." ); ad.loadVideo( - "BUFFERED", "application/dash+xml", dashUrl, resumePosition, @@ -1297,7 +1299,6 @@ class ExpStateCasting { val hackfixResumePosition = if (ad.device.castingProtocol() == ProtocolType.CHROMECAST && !video.isLive && resumePosition == 0.0) 0.1 else resumePosition; ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", "application/vnd.apple.mpegurl", hlsUrl, hackfixResumePosition, @@ -1570,7 +1571,6 @@ class ExpStateCasting { Logger.i(TAG, "added new castHls handlers (hlsPath: $hlsPath)."); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", "application/vnd.apple.mpegurl", hlsUrl, resumePosition, @@ -1686,7 +1686,6 @@ class ExpStateCasting { "added new castDash handlers (dashPath: $dashPath, videoPath: $videoPath, audioPath: $audioPath)." ); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", "application/dash+xml", dashUrl, resumePosition, @@ -1955,7 +1954,6 @@ class ExpStateCasting { "added new castDash handlers (dashPath: $dashPath, videoPath: $videoPath, audioPath: $audioPath)." ); ad.loadVideo( - if (video.isLive) "LIVE" else "BUFFERED", "application/dash+xml", dashUrl, resumePosition, @@ -1971,7 +1969,7 @@ class ExpStateCasting { deviceInfo.addresses.map { org.fcast.sender_sdk.tryIpAddrFromStr(it) } // Throws! val rsDeviceInfo = RsDeviceInfo( name = deviceInfo.name, - type = when (deviceInfo.type) { + protocol = when (deviceInfo.type) { com.futo.platformplayer.casting.CastProtocolType.CHROMECAST -> ProtocolType.CHROMECAST com.futo.platformplayer.casting.CastProtocolType.FCAST -> ProtocolType.F_CAST else -> throw IllegalArgumentException() diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt index e23a1622..d3f0f8c8 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt @@ -74,7 +74,8 @@ class DeviceViewHolder : ViewHolder { if (dev.handle.device.isReady()) { // NOTE: we assume experimental casting is used try { - ExpStateCasting.instance.activeDevice?.device?.stopCasting() + ExpStateCasting.instance.activeDevice?.device?.stopPlayback() + ExpStateCasting.instance.activeDevice?.device?.disconnect() } catch (e: Throwable) { //Ignored }