mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-09-20 06:34:00 +00:00
fix(remote-control): update connection handling and improve logging for remote control events
This commit is contained in:
parent
df3a6dcbd2
commit
c5d35bfc93
@ -101,13 +101,16 @@ class RemoteControlClient {
|
||||
|
||||
private suspend fun receiveLoop(host: String, port: Int) {
|
||||
val currentSession = session ?: return
|
||||
logger.d { "Starting receive loop for $host:$port" }
|
||||
try {
|
||||
for (frame in currentSession.incoming) {
|
||||
when (frame) {
|
||||
is Frame.Text -> {
|
||||
val text = frame.readText()
|
||||
logger.d { "Received frame: $text" }
|
||||
try {
|
||||
val event = json.decodeFromString(RemoteControlEvent.serializer(), text)
|
||||
logger.d { "Parsed event: $event" }
|
||||
when (event) {
|
||||
is RemoteControlEvent.Connected -> {
|
||||
logger.i { "Connection authorized by server" }
|
||||
@ -136,6 +139,7 @@ class RemoteControlClient {
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
logger.d { "Receive loop exited normally" }
|
||||
} catch (e: Exception) {
|
||||
logger.e(e) { "Error in receive loop" }
|
||||
_connectionState.value = ConnectionState.Error(e.message ?: "Connection lost")
|
||||
|
||||
@ -74,7 +74,7 @@ class RemoteControlHandler(
|
||||
val waitingMessage = RemoteControlEvent.WaitingForPermission(
|
||||
"Waiting for permission from $deviceName..."
|
||||
)
|
||||
session.send(Frame.Text(json.encodeToString(RemoteControlEvent.WaitingForPermission.serializer(), waitingMessage)))
|
||||
session.send(Frame.Text(json.encodeToString(RemoteControlEvent.serializer(), waitingMessage)))
|
||||
|
||||
val request = ConnectionRequest(
|
||||
deviceId = deviceId ?: "unknown",
|
||||
@ -99,14 +99,18 @@ class RemoteControlHandler(
|
||||
}
|
||||
|
||||
// Send connected message
|
||||
session.send(Frame.Text(json.encodeToString(RemoteControlEvent.Connected.serializer(), RemoteControlEvent.Connected)))
|
||||
session.send(Frame.Text(json.encodeToString(RemoteControlEvent.serializer(), RemoteControlEvent.Connected)))
|
||||
logger.i { "Remote control connection established from $deviceName ($deviceId)" }
|
||||
|
||||
// Broadcast initial player state so the controller shows current track info
|
||||
broadcastState(session)
|
||||
|
||||
try {
|
||||
handleControlLoop(session)
|
||||
} catch (e: Exception) {
|
||||
logger.w(e) { "Error in remote control session" }
|
||||
} finally {
|
||||
logger.d { "Closing session in finally block" }
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
@ -129,9 +133,11 @@ class RemoteControlHandler(
|
||||
}
|
||||
|
||||
private suspend fun handleControlLoop(session: WebSocketServerSession) {
|
||||
logger.d { "Starting control loop for session" }
|
||||
for (frame in session.incoming) {
|
||||
if (frame is Frame.Text) {
|
||||
val text = frame.readText()
|
||||
logger.d { "Received command: $text" }
|
||||
try {
|
||||
val envelope = json.decodeFromString(CommandEnvelope.serializer(), text)
|
||||
handleCommand(session, envelope)
|
||||
@ -141,6 +147,7 @@ class RemoteControlHandler(
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.d { "Control loop exited normally" }
|
||||
}
|
||||
|
||||
private suspend fun handleCommand(session: WebSocketServerSession, envelope: CommandEnvelope) {
|
||||
@ -197,12 +204,12 @@ class RemoteControlHandler(
|
||||
}
|
||||
|
||||
private suspend fun sendAck(session: WebSocketServerSession, commandId: String) {
|
||||
val text = json.encodeToString(RemoteControlEvent.Ack.serializer(), RemoteControlEvent.Ack(commandId))
|
||||
val text = json.encodeToString(RemoteControlEvent.serializer(), RemoteControlEvent.Ack(commandId))
|
||||
session.send(Frame.Text(text))
|
||||
}
|
||||
|
||||
private suspend fun sendError(session: WebSocketServerSession, message: String) {
|
||||
val text = json.encodeToString(RemoteControlEvent.Error.serializer(), RemoteControlEvent.Error(message))
|
||||
val text = json.encodeToString(RemoteControlEvent.serializer(), RemoteControlEvent.Error(message))
|
||||
session.send(Frame.Text(text))
|
||||
}
|
||||
|
||||
@ -221,7 +228,7 @@ class RemoteControlHandler(
|
||||
currentTrackAlbum = current?.albumOrNull(),
|
||||
currentTrackCoverUrl = current?.coverUrlOrNull(),
|
||||
)
|
||||
val text = json.encodeToString(RemoteControlEvent.PlayerState.serializer(), state)
|
||||
val text = json.encodeToString(RemoteControlEvent.serializer(), state)
|
||||
session.send(Frame.Text(text))
|
||||
}
|
||||
|
||||
|
||||
@ -72,7 +72,8 @@ fun DevicesScreen(
|
||||
viewModel.startDiscovery()
|
||||
onDispose {
|
||||
viewModel.stopDiscovery()
|
||||
viewModel.disconnect()
|
||||
// Don't disconnect here - the connection should persist when navigating to RemoteControlScreen
|
||||
// The RemoteControlViewModel will manage the connection lifecycle
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@ import dev.krtirtho.spotube.core.ui.base.GhostIconButton
|
||||
import dev.krtirtho.spotube.core.ui.base.IconButton
|
||||
import dev.krtirtho.spotube.core.ui.base.Slider
|
||||
import dev.krtirtho.spotube.core.ui.component.ApplicationMainBar
|
||||
import dev.krtirtho.spotube.modules.shell.LocalAppShellBottomInset
|
||||
import dev.krtirtho.spotube.resources.iconsax.Iconsax
|
||||
import dev.krtirtho.spotube.resources.iconsax.IconsaxCloseSquare
|
||||
import dev.krtirtho.spotube.resources.iconsax.IconsaxNext
|
||||
@ -77,6 +78,7 @@ fun RemoteControlScreen(
|
||||
val viewModel = koinViewModel<RemoteControlViewModel>()
|
||||
val playerState by viewModel.playerState.collectAsStateWithLifecycle()
|
||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
val shellBottomInset = LocalAppShellBottomInset.current
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@ -110,14 +112,15 @@ fun RemoteControlScreen(
|
||||
onSetVolume = viewModel::setVolume,
|
||||
onToggleShuffle = viewModel::toggleShuffle,
|
||||
onCycleLoopMode = viewModel::cycleLoopMode,
|
||||
modifier = Modifier.padding(padding)
|
||||
modifier = Modifier.padding(padding).padding(bottom = shellBottomInset)
|
||||
)
|
||||
}
|
||||
is ConnectionState.Connecting -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
.padding(padding)
|
||||
.padding(bottom = shellBottomInset),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text("Connecting...")
|
||||
@ -127,7 +130,8 @@ fun RemoteControlScreen(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
.padding(padding)
|
||||
.padding(bottom = shellBottomInset),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text("Disconnected")
|
||||
@ -137,7 +141,8 @@ fun RemoteControlScreen(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
.padding(padding)
|
||||
.padding(bottom = shellBottomInset),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text("Connection error: ${(connectionState as ConnectionState.Error).message}")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user