diff --git a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt index 226a0a66..f6582055 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt @@ -62,6 +62,7 @@ class ChromecastCastingDevice : CastingDevice { private val MAX_LAUNCH_RETRIES = 3 private var _lastLaunchTime_ms = 0L private var _retryJob: Job? = null + private var _autoLaunchEnabled = true constructor(name: String, addresses: Array, port: Int) : super() { this.name = name; @@ -305,6 +306,7 @@ class ChromecastCastingDevice : CastingDevice { return; } + _autoLaunchEnabled = true _started = true; _sessionId = null; _launchRetries = 0 @@ -546,6 +548,7 @@ class ChromecastCastingDevice : CastingDevice { if (appId == "CC1AD845") { sessionIsRunning = true; + _autoLaunchEnabled = false if (_sessionId == null) { connectionState = CastConnectionState.CONNECTED; @@ -558,7 +561,6 @@ class ChromecastCastingDevice : CastingDevice { _transportId = transportId; requestMediaStatus(); - playVideo(); } } } @@ -568,21 +570,22 @@ class ChromecastCastingDevice : CastingDevice { if (System.currentTimeMillis() - _lastLaunchTime_ms > 5000) { _sessionId = null _mediaSessionId = null - setTime(0.0) _transportId = null - if (_launching && _launchRetries < MAX_LAUNCH_RETRIES) { - Logger.i(TAG, "No player yet; attempting launch #${_launchRetries + 1}") - _launchRetries++ - launchPlayer() - } else if (!_launching && _launchRetries < MAX_LAUNCH_RETRIES) { - // Maybe the first GET_STATUS came back empty; still try launching - Logger.i(TAG, "Player not found; triggering launch #${_launchRetries + 1}") - _launching = true - _launchRetries++ - launchPlayer() + if (_autoLaunchEnabled) { + if (_launching && _launchRetries < MAX_LAUNCH_RETRIES) { + Logger.i(TAG, "No player yet; attempting launch #${_launchRetries + 1}") + _launchRetries++ + launchPlayer() + } else { + // Maybe the first GET_STATUS came back empty; still try launching + Logger.i(TAG, "Player not found; triggering launch #${_launchRetries + 1}") + _launching = true + _launchRetries++ + launchPlayer() + } } else { - Logger.e(TAG, "Player not found after $_launchRetries attempts; giving up.") + Logger.e(TAG, "Player not found ($_launchRetries, _autoLaunchEnabled = $_autoLaunchEnabled); giving up.") Logger.i(TAG, "Unable to start media receiver on device") stop() } @@ -599,6 +602,7 @@ class ChromecastCastingDevice : CastingDevice { } else { _launching = false _launchRetries = 0 + _autoLaunchEnabled = false } val volume = status.getJSONObject("volume"); @@ -636,10 +640,16 @@ class ChromecastCastingDevice : CastingDevice { stopVideo(); } } + + val needsLoad = statuses.length() == 0 || (statuses.getJSONObject(0).getString("playerState") == "IDLE") + if (needsLoad && _contentId != null && _mediaSessionId == null) { + Logger.i(TAG, "Receiver idle, sending initial LOAD") + playVideo() + } } else if (type == "CLOSE") { if (message.sourceId == "receiver-0") { Logger.i(TAG, "Close received."); - stop(); + stopCasting(); } else if (_transportId == message.sourceId) { throw Exception("Transport id closed.") } @@ -676,6 +686,10 @@ class ChromecastCastingDevice : CastingDevice { localAddress = null; _started = false; + _contentId = null + _contentType = null + _streamType = null + _retryJob?.cancel() _retryJob = null diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index ce783fa5..3dbde51b 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -649,7 +649,7 @@ class VideoDetailView : ConstraintLayout { } if (!isInEditMode) { - StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState -> + StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { device, connectionState -> if (_onPauseCalled) { return@subscribe; } @@ -661,7 +661,7 @@ class VideoDetailView : ConstraintLayout { setCastEnabled(true); } CastConnectionState.DISCONNECTED -> { - loadCurrentVideo(lastPositionMilliseconds); + loadCurrentVideo(lastPositionMilliseconds, playWhenReady = device.isPlaying); updatePillButtonVisibilities(); setCastEnabled(false); @@ -1880,7 +1880,7 @@ class VideoDetailView : ConstraintLayout { } //Source Loads - private fun loadCurrentVideo(resumePositionMs: Long = 0) { + private fun loadCurrentVideo(resumePositionMs: Long = 0, playWhenReady: Boolean = true) { _didStop = false; val video = (videoLocal ?: video) ?: return; @@ -1925,7 +1925,7 @@ class VideoDetailView : ConstraintLayout { else _player.setArtwork(null); } - _player.setSource(videoSource, audioSource, _playWhenReady, false, resume = resumePositionMs > 0); + _player.setSource(videoSource, audioSource, _playWhenReady && playWhenReady, false, resume = resumePositionMs > 0); if(subtitleSource != null) _player.swapSubtitles(fragment.lifecycleScope, subtitleSource); _player.seekTo(resumePositionMs); diff --git a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt index 5ab75011..8141d191 100644 --- a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt +++ b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt @@ -48,6 +48,7 @@ class DownloadService : Service() { private val _scope: CoroutineScope = CoroutineScope(Dispatchers.Default); private var _notificationManager: NotificationManager? = null; private var _notificationChannel: NotificationChannel? = null; + private var _isForeground = false private val _client = ManagedHttpClient(OkHttpClient.Builder() //.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress(InetAddress.getByName("192.168.1.175"), 8081))) @@ -66,6 +67,7 @@ class DownloadService : Service() { if(!FragmentedStorage.isInitialized) { Logger.i(TAG, "Attempted to start DownloadService without initialized files"); + stopSelf() closeDownloadSession(); return START_NOT_STICKY; } @@ -116,6 +118,22 @@ class DownloadService : Service() { override fun onCreate() { Logger.i(TAG, "onCreate"); super.onCreate() + + setupNotificationRequirements() + + val bootstrapNotif = NotificationCompat.Builder(this, DOWNLOAD_NOTIF_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_download) + .setContentTitle("Preparing downloads...") + .setOngoing(true) + .setSilent(true) + .build() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + startForeground(DOWNLOAD_NOTIF_ID, bootstrapNotif, FOREGROUND_SERVICE_TYPE_DATA_SYNC) + else + startForeground(DOWNLOAD_NOTIF_ID, bootstrapNotif) + + _isForeground = true } override fun onBind(p0: Intent?): IBinder? { @@ -246,15 +264,14 @@ class DownloadService : Service() { } private fun notifyDownload(download: VideoDownload?) { - val channel = _notificationChannel ?: return; - + val channelId = DOWNLOAD_NOTIF_CHANNEL_ID val bringUpIntent = Intent(this, MainActivity::class.java); bringUpIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); bringUpIntent.action = "TAB"; bringUpIntent.putExtra("TAB", "Downloads"); - var builder = if(download != null) - NotificationCompat.Builder(this, DOWNLOAD_NOTIF_TAG) + val builder = if(download != null) + NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_download) .setOngoing(true) .setSilent(true) @@ -262,16 +279,16 @@ class DownloadService : Service() { .setContentTitle("${download.state}: ${download.name}") .setContentText(download.getDownloadInfo()) .setProgress(100, (download.progress * 100).toInt(), download.progress == 0.0) - .setChannelId(channel.id) + .setChannelId(channelId) else - NotificationCompat.Builder(this, DOWNLOAD_NOTIF_TAG) + NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_download) .setOngoing(true) .setSilent(true) .setContentIntent(PendingIntent.getActivity(this, 5, bringUpIntent, PendingIntent.FLAG_IMMUTABLE)) .setContentTitle("Preparing for download...") .setContentText("Initializing download process...") - .setChannelId(channel.id) + .setChannelId(channelId) val notif = builder.build(); notif.flags = notif.flags or NotificationCompat.FLAG_ONGOING_EVENT or NotificationCompat.FLAG_NO_CLEAR;