135 lines
4.8 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|