|
|
|
@ -44,11 +44,17 @@ class StreamDictationClient( |
|
|
|
private val isRecording = AtomicBoolean(false) |
|
|
|
private val mainHandler = Handler(Looper.getMainLooper()) |
|
|
|
|
|
|
|
private val candidateHosts: List<String> = listOf( |
|
|
|
host, |
|
|
|
if (host.contains("116.16.16.19")) "2.180.16.250:8999" else "116.16.16.19:8999" |
|
|
|
).filter { it.isNotBlank() }.distinct() |
|
|
|
private var currentHostIndex = 0 |
|
|
|
|
|
|
|
private val okHttpClient = OkHttpClient.Builder() |
|
|
|
.connectTimeout(12, TimeUnit.SECONDS) |
|
|
|
.connectTimeout(3500, TimeUnit.MILLISECONDS) |
|
|
|
.readTimeout(0, TimeUnit.MILLISECONDS) // Persistent WebSocket |
|
|
|
.writeTimeout(8, TimeUnit.SECONDS) |
|
|
|
.pingInterval(8, TimeUnit.SECONDS) |
|
|
|
.writeTimeout(5000, TimeUnit.MILLISECONDS) |
|
|
|
.pingInterval(4, TimeUnit.SECONDS) // 4s active heartbeat to keep NAT tables alive |
|
|
|
.retryOnConnectionFailure(true) |
|
|
|
.build() |
|
|
|
|
|
|
|
@ -68,18 +74,20 @@ class StreamDictationClient( |
|
|
|
if (isConnected.get() && activeWebSocket != null) return |
|
|
|
if (isConnecting.getAndSet(true)) return |
|
|
|
|
|
|
|
val cleanHost = host.removePrefix("http://").removePrefix("https://").removePrefix("ws://").removePrefix("wss://") |
|
|
|
val targetHost = candidateHosts[currentHostIndex % candidateHosts.size] |
|
|
|
val cleanHost = targetHost.removePrefix("http://").removePrefix("https://").removePrefix("ws://").removePrefix("wss://") |
|
|
|
val wsUrl = "ws://$cleanHost/ws/stream" |
|
|
|
AppLogger.log(tag, "اتصال به سوکت همگامسازی بلادرنگ: $wsUrl") |
|
|
|
AppLogger.log(tag, "اتصال به سوکت همگامسازی بلادرنگ ($targetHost): $wsUrl") |
|
|
|
|
|
|
|
val req = Request.Builder() |
|
|
|
.url(wsUrl) |
|
|
|
.header("User-Agent", "SonioxAndroidRemote/5.4") |
|
|
|
.header("User-Agent", "SonioxAndroidRemote/5.6") |
|
|
|
.build() |
|
|
|
|
|
|
|
activeWebSocket = okHttpClient.newWebSocket(req, object : WebSocketListener() { |
|
|
|
override fun onOpen(webSocket: WebSocket, response: Response) { |
|
|
|
AppLogger.log(tag, "🟢 سوکت همگامسازی بلادرنگ متصل شد") |
|
|
|
val connectedHost = candidateHosts[currentHostIndex % candidateHosts.size] |
|
|
|
AppLogger.log(tag, "🟢 سوکت همگامسازی بلادرنگ متصل شد ($connectedHost)") |
|
|
|
isConnected.set(true) |
|
|
|
isConnecting.set(false) |
|
|
|
retryAttempt = 0 |
|
|
|
@ -146,8 +154,10 @@ class StreamDictationClient( |
|
|
|
activeWebSocket = null |
|
|
|
mainHandler.post { onConnectionStateChanged(false) } |
|
|
|
|
|
|
|
// Fast failover between LAN and WAN |
|
|
|
currentHostIndex++ |
|
|
|
retryAttempt++ |
|
|
|
val delayMs = minOf(800L * (1L shl minOf(retryAttempt, 3)), 5000L) |
|
|
|
val delayMs = if (retryAttempt <= 2) 350L else minOf(500L * (1L shl minOf(retryAttempt, 2)), 2000L) |
|
|
|
mainHandler.postDelayed({ connectWebSocket() }, delayMs) |
|
|
|
} |
|
|
|
}) |
|
|
|
|