diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_Syntax.kt b/app/src/main/java/com/futo/platformplayer/Extensions_Syntax.kt index 442304d4..63f4bd31 100644 --- a/app/src/main/java/com/futo/platformplayer/Extensions_Syntax.kt +++ b/app/src/main/java/com/futo/platformplayer/Extensions_Syntax.kt @@ -33,10 +33,18 @@ fun Boolean?.toYesNo(): String { fun InetAddress?.toUrlAddress(): String { return when (this) { is Inet6Address -> { - "[${hostAddress}]" + val hostAddr = this.hostAddress ?: throw Exception("Invalid address: hostAddress is null") + val index = hostAddr.indexOf('%') + if (index != -1) { + val addrPart = hostAddr.substring(0, index) + val scopeId = hostAddr.substring(index + 1) + "[${addrPart}%25${scopeId}]" // %25 is URL-encoded '%' + } else { + "[$hostAddr]" + } } is Inet4Address -> { - hostAddress + this.hostAddress ?: throw Exception("Invalid address: hostAddress is null") } else -> { throw Exception("Invalid address type") diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt index eb593c5b..81a2b791 100644 --- a/app/src/main/java/com/futo/platformplayer/Settings.kt +++ b/app/src/main/java/com/futo/platformplayer/Settings.kt @@ -590,7 +590,7 @@ class Settings : FragmentedStorageFileJson() { @FormField(R.string.allow_ipv6, FieldForm.TOGGLE, R.string.allow_ipv6_description, 4) @Serializable(with = FlexibleBooleanSerializer::class) - var allowIpv6: Boolean = false; + var allowIpv6: Boolean = true; /*TODO: Should we have a different casting quality? @FormField("Preferred Casting Quality", FieldForm.DROPDOWN, "", 3) 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 2bf6c1ce..0cc1bebc 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/AirPlayCastingDevice.kt @@ -149,6 +149,7 @@ class AirPlayCastingDevice : CastingDevice { break; } catch (e: Throwable) { Logger.w(TAG, "Failed to get setup initial connection to AirPlay device.", e) + delay(1000); } } 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 0b763675..32bee98d 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt @@ -322,6 +322,7 @@ class ChromecastCastingDevice : CastingDevice { break; } catch (e: Throwable) { Logger.w(TAG, "Failed to get setup initial connection to ChromeCast device.", e) + Thread.sleep(1000); } } diff --git a/app/src/main/java/com/futo/platformplayer/casting/FCastCastingDevice.kt b/app/src/main/java/com/futo/platformplayer/casting/FCastCastingDevice.kt index 74440194..dcfaf63d 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/FCastCastingDevice.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/FCastCastingDevice.kt @@ -25,6 +25,7 @@ import com.futo.platformplayer.toInetAddress import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.serialization.encodeToString @@ -289,6 +290,7 @@ class FCastCastingDevice : CastingDevice { break; } catch (e: Throwable) { Logger.w(TAG, "Failed to get setup initial connection to FastCast device.", e) + Thread.sleep(1000); } } 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 03145a78..ff997d3d 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt @@ -45,6 +45,8 @@ import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.CastingDeviceInfo import com.futo.platformplayer.parsers.HLS import com.futo.platformplayer.states.StateApp +import com.futo.platformplayer.states.StateSync +import com.futo.platformplayer.states.StateSync.Companion import com.futo.platformplayer.stores.CastingDeviceInfoStorage import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.toUrlAddress @@ -179,7 +181,7 @@ class StateCasting { try { stopServiceDiscovery(it.value) } catch (e: Throwable) { - //Ignored + Logger.w(TAG, "Failed to stop service discovery", e) } } } @@ -228,12 +230,20 @@ class StateCasting { override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed for $serviceType: Error code:$errorCode") - _nsdManager?.stopServiceDiscovery(this) + try { + _nsdManager?.stopServiceDiscovery(this) + } catch (e: Throwable) { + Logger.w(TAG, "Failed to stop service discovery", e) + } } override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Stop discovery failed for $serviceType: Error code:$errorCode") - _nsdManager?.stopServiceDiscovery(this) + try { + _nsdManager?.stopServiceDiscovery(this) + } catch (e: Throwable) { + Logger.w(TAG, "Failed to stop service discovery", e) + } } override fun onServiceFound(service: NsdServiceInfo) { diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt index 845359b7..811d89d8 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt @@ -148,12 +148,20 @@ class StateSync { override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed for $serviceType: Error code:$errorCode") - _nsdManager?.stopServiceDiscovery(this) + try { + _nsdManager?.stopServiceDiscovery(this) + } catch (e: Throwable) { + Logger.w(TAG, "Failed to stop service discovery", e) + } } override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Stop discovery failed for $serviceType: Error code:$errorCode") - _nsdManager?.stopServiceDiscovery(this) + try { + _nsdManager?.stopServiceDiscovery(this) + } catch (e: Throwable) { + Logger.w(TAG, "Failed to stop service discovery", e) + } } fun addOrUpdate(name: String, adrs: Array, port: Int, attributes: Map) { @@ -469,8 +477,6 @@ class StateSync { } }.apply { start() } } - - } private fun getDeviceName(): String { diff --git a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt index 5d7db083..910957b0 100644 --- a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt +++ b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt @@ -447,14 +447,14 @@ class SyncSocketSession { ensureNotMainThread() synchronized(_sendLockObject) { - ByteBuffer.wrap(_sendBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(2) + ByteBuffer.wrap(_sendBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(HEADER_SIZE - 4) _sendBuffer.asUByteArray()[4] = opcode _sendBuffer.asUByteArray()[5] = subOpcode _sendBuffer.asUByteArray()[6] = ContentEncoding.Raw.value //Logger.i(TAG, "Encrypting message (opcode = ${opcode}, subOpcode = ${subOpcode}, size = ${HEADER_SIZE})") - val len = _cipherStatePair!!.sender.encryptWithAd(null, _sendBuffer, 0, _sendBufferEncrypted, 0, HEADER_SIZE) + val len = _cipherStatePair!!.sender.encryptWithAd(null, _sendBuffer, 0, _sendBufferEncrypted, 4, HEADER_SIZE) //Logger.i(TAG, "Sending encrypted message (size = ${len})") ByteBuffer.wrap(_sendBufferEncrypted, 0, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(len)