using System; using System.IO; using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using NAudio.Wave; using System.Collections.Concurrent; namespace sharpFRN { public class WebSocketAudioStreamer { private WaveOutEvent waveOut; private BufferedWaveProvider bufferedWaveProvider; private HttpListener httpListener; private ConcurrentDictionary webSockets = new ConcurrentDictionary(); public WebSocketAudioStreamer() { InitializeGsmDecoder(); } private void InitializeGsmDecoder() { WaveFormat pcmFormat = new WaveFormat(8000, 16, 1); waveOut = new WaveOutEvent(); bufferedWaveProvider = new BufferedWaveProvider(pcmFormat) { BufferDuration = TimeSpan.FromSeconds(5) // Adjust if needed }; waveOut.Init(bufferedWaveProvider); waveOut.Play(); } public void PlayGSMChunk(byte[] voiceData) { if (voiceData.Length != 325) { Console.WriteLine($"Unexpected voice data length: {voiceData.Length}"); return; } int frameSize = 65; // GSM frame size int numFrames = voiceData.Length / frameSize; for (int i = 0; i < numFrames; i++) { byte[] gsmFrame = new byte[frameSize]; Array.Copy(voiceData, i * frameSize, gsmFrame, 0, frameSize); using (var gsmStream = new RawSourceWaveStream(new MemoryStream(gsmFrame), new Gsm610WaveFormat())) using (var pcmStream = WaveFormatConversionStream.CreatePcmStream(gsmStream)) { byte[] buffer = new byte[pcmStream.Length]; int bytesRead = pcmStream.Read(buffer, 0, buffer.Length); // Add the PCM data to the BufferedWaveProvider //bufferedWaveProvider.AddSamples(buffer, 0, bytesRead); // Send the PCM data to all connected WebSocket clients BroadcastToWebSockets(buffer, 0, bytesRead); } } } public async Task StartWebSocketServerAsync(string urlPrefix) { httpListener = new HttpListener(); httpListener.Prefixes.Add(urlPrefix); httpListener.Start(); Console.WriteLine($"WebSocket server started at {urlPrefix}"); while (true) { var httpContext = await httpListener.GetContextAsync(); if (httpContext.Request.IsWebSocketRequest) { var webSocketContext = await httpContext.AcceptWebSocketAsync(null); var webSocket = webSocketContext.WebSocket; string clientId = Guid.NewGuid().ToString(); webSockets.TryAdd(clientId, webSocket); Console.WriteLine($"WebSocket client connected: {clientId}"); _ = Task.Run(() => HandleWebSocketConnectionAsync(clientId, webSocket)); } else { httpContext.Response.StatusCode = 400; httpContext.Response.Close(); } } } private async Task HandleWebSocketConnectionAsync(string clientId, WebSocket webSocket) { var buffer = new byte[1024]; try { while (webSocket.State == WebSocketState.Open) { var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); } } } catch (Exception ex) { Console.WriteLine($"WebSocket error: {ex.Message}"); } finally { webSockets.TryRemove(clientId, out _); Console.WriteLine($"WebSocket client disconnected: {clientId}"); } } private void BroadcastToWebSockets(byte[] buffer, int offset, int count) { foreach (var webSocket in webSockets.Values) { if (webSocket.State == WebSocketState.Open) { webSocket.SendAsync(new ArraySegment(buffer, offset, count), WebSocketMessageType.Binary, true, CancellationToken.None).Wait(); } } } } }