mgth/LittleBigMouse · error · WebSocketException
The Samsung display closed the remote-control channel.
Error message
The Samsung display closed the remote-control channel.
What it means
SamsungTizenClient.ReceiveTextLockedAsync reads WebSocket text frames from the display's remote-control channel. When the socket reports a Close frame instead of a text message, the client throws WebSocketException to signal that the Samsung display terminated the session. The library surfaces this as an exception rather than returning null so callers must explicitly re-connect or re-authorize.
Solutions
- Catch WebSocketException around receive/send calls and recreate the SamsungTizenClient, re-running the connection/handshake
- Check whether the display still shows the client as an allowed device and re-authorize if the token was revoked
- Send periodic keep-alive/ping frames to prevent idle disconnects
- Handle the Close frame by surfacing a user-facing 'display disconnected' state and retrying with backoff
Example fix
// before
var text = await client.ReceiveTextLockedAsync(ct);
// after
try { var text = await client.ReceiveTextLockedAsync(ct); }
catch (WebSocketException)
{
await client.ReconnectAsync(ct); // recreate socket and re-handshake with the display
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check socket state before receiving
if (client is not { IsConnected: true })
await ReconnectAsync(ct); Type guard
static bool IsUsable(SamsungTizenClient? c) => c is { IsConnected: true }; Try / catch
try
{
var text = await client.ReceiveTextLockedAsync(ct);
}
catch (WebSocketException ex)
{
// display closed the channel — reconnect and re-authorize
await ReconnectWithBackoffAsync(ct);
} Prevention
- Send periodic WebSocket pings/keep-alives to avoid idle timeouts
- Re-authorize the client in the TV's device settings if sessions are revoked
- Monitor connection state and recreate the client proactively on failures
- Retry with exponential backoff instead of immediate reconnect loops
When it happens
Trigger: Calling ReceiveTextLockedAsync (via the client's message loop) while the Samsung display sends a WebSocket Close frame — e.g. after the display revokes the remote-control session, times out idle connections, or the user rejects/ends control on the TV.
Common situations: The TV was turned off or rebooted mid-session; another client (phone app) took over the remote-control slot; the token was revoked in the TV's device-connection settings; the WebSocket sat idle until the display dropped it.
Related errors
- No VIDAA descriptor answered at
- No Hisense VIDAA device answered on
- Enter the projector Wi-Fi MAC address first.
- Could not find the network interface used to reach
- VIDAA returned an invalid MQTT connection response.
AI-assisted analysis of mgth/LittleBigMouse@7a42f01d47 (2026-09-16).
Data as JSON: /api/errors/9256a330f548f285.
Report an issue: GitHub.
Appendix: source
Thrown at LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/SamsungTizen/SamsungTizenClient.cs:147
void ResetSocketLocked()
{
if (_socket is null) return;
try { _socket.Abort(); }
catch { }
_socket.Dispose();
_socket = null;
}
async Task<string> ReceiveTextLockedAsync(CancellationToken cancellationToken)
{
var buffer = new byte[4096];
using var message = new MemoryStream();
while (true)
{
var result = await _socket!.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false);
if (result.MessageType == WebSocketMessageType.Close)
throw new WebSocketException("The Samsung display closed the remote-control channel.");
if (result.MessageType != WebSocketMessageType.Text) continue;
message.Write(buffer, 0, result.Count);
if (result.EndOfMessage) return Encoding.UTF8.GetString(message.GetBuffer(), 0, checked((int)message.Length));
}
}
public async ValueTask DisposeAsync()
=> await _commands.CloseAsync(async () =>
{
if (_socket?.State == WebSocketState.Open)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
try
{
await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "LittleBigMouse closing", timeout.Token)
.ConfigureAwait(false);
}View on GitHub (pinned to 7a42f01d47)