From 5eaa6a76cc324e96bbcc5faa54a41acee89766eb Mon Sep 17 00:00:00 2001 From: The412Banner Date: Sat, 31 Oct 2026 04:13:34 +0000 Subject: [PATCH] fix(dual-screen): listen for game telemetry on 127.0.0.1, not ::1 Android's InetAddress.getLoopbackAddress() always returns the IPv6 loopback (libcore InetAddress.java, "Android-changed"), so the listeners were bound to [::1] and never saw the games' IPv4 packets to 127.0.0.1. A listener bound to 127.0.0.1:20777 on the same Duo received DiRT Showdown's packets. --- .../java/com/droiddeck/launcher/session/GameTelemetry.kt | 3 +++ .../java/com/droiddeck/launcher/ui/BottomTelemetryPage.kt | 3 +-- .../com/droiddeck/launcher/session/GameTelemetryTest.kt | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/droiddeck/launcher/session/GameTelemetry.kt b/app/src/main/java/com/droiddeck/launcher/session/GameTelemetry.kt index 91603608b..b7820e0f3 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/GameTelemetry.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/GameTelemetry.kt @@ -33,6 +33,9 @@ object GameTelemetry { const val OUTGAUGE_PORT = 4444 val PORTS = listOf(CODEMASTERS_PORT, FORZA_PORT, OUTGAUGE_PORT) + // Games send to 127.0.0.1; on Android InetAddress.getLoopbackAddress() is ::1, which IPv4 packets never reach. + val LISTEN_ADDRESS: java.net.InetAddress = java.net.InetAddress.getByAddress(byteArrayOf(127, 0, 0, 1)) + fun parse(port: Int, data: ByteArray, length: Int): Telemetry? = runCatching { val buf = ByteBuffer.wrap(data, 0, length).order(ByteOrder.LITTLE_ENDIAN) when (port) { diff --git a/app/src/main/java/com/droiddeck/launcher/ui/BottomTelemetryPage.kt b/app/src/main/java/com/droiddeck/launcher/ui/BottomTelemetryPage.kt index 5409ee8a8..8e18d71b0 100644 --- a/app/src/main/java/com/droiddeck/launcher/ui/BottomTelemetryPage.kt +++ b/app/src/main/java/com/droiddeck/launcher/ui/BottomTelemetryPage.kt @@ -49,7 +49,6 @@ import java.io.File import java.net.DatagramPacket import java.net.DatagramSocket import java.net.HttpURLConnection -import java.net.InetAddress import java.net.InetSocketAddress import java.net.SocketTimeoutException import java.net.URL @@ -92,7 +91,7 @@ fun BottomTelemetryPage(fps: () -> Float?) { DatagramSocket(null).apply { reuseAddress = true soTimeout = 500 - bind(InetSocketAddress(InetAddress.getLoopbackAddress(), port)) + bind(InetSocketAddress(GameTelemetry.LISTEN_ADDRESS, port)) } }.getOrNull() if (socket == null) { diff --git a/app/src/test/java/com/droiddeck/launcher/session/GameTelemetryTest.kt b/app/src/test/java/com/droiddeck/launcher/session/GameTelemetryTest.kt index f09217ef5..96e468e3a 100644 --- a/app/src/test/java/com/droiddeck/launcher/session/GameTelemetryTest.kt +++ b/app/src/test/java/com/droiddeck/launcher/session/GameTelemetryTest.kt @@ -2,6 +2,7 @@ package com.droiddeck.launcher.session import org.junit.Assert.assertEquals import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -112,6 +113,11 @@ class GameTelemetryTest { assertEquals(4000f, t.rpm!!, 0.01f) } + @Test fun listensOnIpv4Loopback() { + assertTrue(GameTelemetry.LISTEN_ADDRESS is java.net.Inet4Address) + assertEquals("127.0.0.1", GameTelemetry.LISTEN_ADDRESS.hostAddress) + } + @Test fun shortPacketsAreIgnored() { assertNull(GameTelemetry.parse(GameTelemetry.CODEMASTERS_PORT, ByteArray(148), 148)) assertNull(GameTelemetry.parse(GameTelemetry.OUTGAUGE_PORT, ByteArray(40), 40))