From f6cc00f4717e9708b617391bca21d343b72debf6 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 8 Mar 2024 08:17:38 +0100 Subject: [PATCH] Casting. --- .../casting/AirPlayCastingDevice.kt | 5 +- .../casting/ChomecastCastingDevice.kt | 74 +++++++++++-------- .../platformplayer/casting/StateCasting.kt | 1 + 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt b/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt index 42fcc992..2bf6c1ce 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt @@ -163,24 +163,25 @@ class AirPlayCastingDevice : CastingDevice { } connectionState = CastConnectionState.CONNECTED; - delay(1000); val progressIndex = progressInfo.lowercase().indexOf("position: "); if (progressIndex == -1) { + delay(1000); continue; } val progress = progressInfo.substring(progressIndex + "position: ".length).toDoubleOrNull() ?: continue; setTime(progress); - val durationIndex = progressInfo.lowercase().indexOf("duration: "); if (durationIndex == -1) { + delay(1000); continue; } val duration = progressInfo.substring(durationIndex + "duration: ".length).toDoubleOrNull() ?: continue; setDuration(duration); + delay(1000); } catch (e: Throwable) { Logger.w(TAG, "Failed to get server info from AirPlay device.", e) } 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 a0a9695c..0b763675 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt @@ -44,7 +44,9 @@ class ChromecastCastingDevice : CastingDevice { private var _socket: SSLSocket? = null; private var _outputStream: DataOutputStream? = null; + private var _outputStreamLock = Object(); private var _inputStream: DataInputStream? = null; + private var _inputStreamLock = Object(); private var _scopeIO: CoroutineScope? = null; private var _requestId = 1; private var _started: Boolean = false; @@ -383,39 +385,44 @@ class ChromecastCastingDevice : CastingDevice { getStatus(); - val buffer = ByteArray(4096); + val buffer = ByteArray(409600); Logger.i(TAG, "Started receiving."); while (_scopeIO?.isActive == true) { try { val inputStream = _inputStream ?: break; - Log.d(TAG, "Receiving next packet..."); - val b1 = inputStream.readUnsignedByte(); - val b2 = inputStream.readUnsignedByte(); - val b3 = inputStream.readUnsignedByte(); - val b4 = inputStream.readUnsignedByte(); - val size = ((b1.toLong() shl 24) or (b2.toLong() shl 16) or (b3.toLong() shl 8) or b4.toLong()).toInt(); - if (size > buffer.size) { - Logger.w(TAG, "Skipping packet that is too large $size bytes.") - inputStream.skip(size.toLong()); - continue; - } - Log.d(TAG, "Received header indicating $size bytes. Waiting for message."); - inputStream.read(buffer, 0, size); + synchronized(_inputStreamLock) + { + Log.d(TAG, "Receiving next packet..."); + val b1 = inputStream.readUnsignedByte(); + val b2 = inputStream.readUnsignedByte(); + val b3 = inputStream.readUnsignedByte(); + val b4 = inputStream.readUnsignedByte(); + val size = + ((b1.toLong() shl 24) or (b2.toLong() shl 16) or (b3.toLong() shl 8) or b4.toLong()).toInt(); + if (size > buffer.size) { + Logger.w(TAG, "Skipping packet that is too large $size bytes.") + inputStream.skip(size.toLong()); + return@synchronized + } - //TODO: In the future perhaps this size-1 will cause issues, why is there a 0 on the end? - val messageBytes = buffer.sliceArray(IntRange(0, size - 1)); - Log.d(TAG, "Received $size bytes: ${messageBytes.toHexString()}."); - val message = ChromeCast.CastMessage.parseFrom(messageBytes); - if (message.namespace != "urn:x-cast:com.google.cast.tp.heartbeat") { - Logger.i(TAG, "Received message: $message"); - } + Log.d(TAG, "Received header indicating $size bytes. Waiting for message."); + inputStream.read(buffer, 0, size); - try { - handleMessage(message); - } catch (e:Throwable) { - Logger.w(TAG, "Failed to handle message.", e); + //TODO: In the future perhaps this size-1 will cause issues, why is there a 0 on the end? + val messageBytes = buffer.sliceArray(IntRange(0, size - 1)); + Log.d(TAG, "Received $size bytes: ${messageBytes.toHexString()}."); + val message = ChromeCast.CastMessage.parseFrom(messageBytes); + if (message.namespace != "urn:x-cast:com.google.cast.tp.heartbeat") { + Logger.i(TAG, "Received message: $message"); + } + + try { + handleMessage(message); + } catch (e: Throwable) { + Logger.w(TAG, "Failed to handle message.", e); + } } } catch (e: java.net.SocketException) { Logger.e(TAG, "Socket exception while receiving.", e); @@ -588,13 +595,16 @@ class ChromecastCastingDevice : CastingDevice { return; } - val serializedSizeBE = ByteArray(4); - serializedSizeBE[0] = (data.size shr 24 and 0xff).toByte(); - serializedSizeBE[1] = (data.size shr 16 and 0xff).toByte(); - serializedSizeBE[2] = (data.size shr 8 and 0xff).toByte(); - serializedSizeBE[3] = (data.size and 0xff).toByte(); - outputStream.write(serializedSizeBE); - outputStream.write(data); + synchronized(_outputStreamLock) + { + val serializedSizeBE = ByteArray(4); + serializedSizeBE[0] = (data.size shr 24 and 0xff).toByte(); + serializedSizeBE[1] = (data.size shr 16 and 0xff).toByte(); + serializedSizeBE[2] = (data.size shr 8 and 0xff).toByte(); + serializedSizeBE[3] = (data.size and 0xff).toByte(); + outputStream.write(serializedSizeBE); + outputStream.write(data); + } //Log.d(TAG, "Sent ${data.size} bytes."); } diff --git a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt index 885a629f..fbda6bfa 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt @@ -242,6 +242,7 @@ class StateCasting { jmDNS.addServiceListener("_googlecast._tcp.local.", _chromecastServiceListener); jmDNS.addServiceListener("_airplay._tcp.local.", _airPlayServiceListener); jmDNS.addServiceListener("_fastcast._tcp.local.", _fastCastServiceListener); + jmDNS.addServiceListener("_fcast._tcp.local.", _fastCastServiceListener); if (BuildConfig.DEBUG) { jmDNS.addServiceTypeListener(_serviceTypeListener);