frnsharp/FRNWebSocket/WSAudioStream.cs
2024-11-22 16:55:57 +01:00

135 lines
4.8 KiB
C#

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<string, WebSocket> webSockets = new ConcurrentDictionary<string, WebSocket>();
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<byte>(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<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, CancellationToken.None).Wait();
}
}
}
}
}