// .NET (System.Net.WebSockets) subscription to CodeB Signal WebSocket events. // European Digital Identity Wallet-enabled tenants use the same signalling. // [realtime-events-cookbook 2026-07-23] // // Endpoint: wss:///signal.ashx?room=&name= // Server-emitted event names verified in signal.ashx: welcome, peer-joined, // peer-left, mode-changed, ring, ring-cancelled, ring-cleared, dial-result, // office-call-result, office-call-answered, office-call-timeout, // office-registered, sfu-answer, sfu-subscribe-answer, sfu-offer-failed, // sfu-subscribe-failed, signal, breakout-list, breakout-assigned, // breakout-end, breakout-rejected, knock, knock-pending, dup-ip-warning, // denied, pong, error. using System; using System.Net.WebSockets; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; class SignalWs { static async Task Main() { var host = Environment.GetEnvironmentVariable("CODEB_TENANT_HOST") ?? "phone.example.tld"; var room = Environment.GetEnvironmentVariable("ROOM") ?? "lobby"; var name = Environment.GetEnvironmentVariable("NAME") ?? "ops-dashboard"; var uri = new Uri("wss://" + host + "/signal.ashx?room=" + Uri.EscapeDataString(room) + "&name=" + Uri.EscapeDataString(name)); var backoff = TimeSpan.FromSeconds(1); while (true) { using var ws = new ClientWebSocket(); try { await ws.ConnectAsync(uri, CancellationToken.None); backoff = TimeSpan.FromSeconds(1); Console.WriteLine("[ws] open " + uri); var buf = new byte[64 * 1024]; while (ws.State == WebSocketState.Open) { var sb = new StringBuilder(); WebSocketReceiveResult r; do { r = await ws.ReceiveAsync(buf, CancellationToken.None); if (r.MessageType == WebSocketMessageType.Close) break; sb.Append(Encoding.UTF8.GetString(buf, 0, r.Count)); } while (!r.EndOfMessage); if (sb.Length == 0) continue; using var doc = JsonDocument.Parse(sb.ToString()); var type = doc.RootElement.TryGetProperty("type", out var t) ? t.GetString() : ""; Console.WriteLine("[event] " + type); } } catch (Exception e) { Console.WriteLine("[ws] " + e.Message + "; retry in " + backoff.TotalSeconds + "s"); await Task.Delay(backoff); if (backoff < TimeSpan.FromSeconds(30)) backoff = backoff + backoff; } } } }