using System.Net.WebSockets;
using System.Text;
using System.Text.Json.Nodes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace HuoShanASR;
public class HuoShanControl
{
private ClientWebSocket ws = new();
public string appid = "";
public string token = "";
public string cluster = "volcengine_streaming_common";
public Guid uuid = Guid.NewGuid();
public string path = "D:\\C#Study\\HuoShanASR\\HuoShanASR\\Male-2_01.wav";
public void Start()
{
Connect();
Thread.Sleep(1000);
Thread thread = new Thread(Recevie);
thread.Start();
Console.ReadKey();
}
public string Payload()
{
var config = new
{
app = new
{
appid,
token,
cluster
},
user = new
{
uid = "streaming_asr_demo"
},
audio = new
{
format = "wav",
rate = 16000,
bits = 16,
channel = 1,
language = "zh-CN"
},
request = new
{
reqid = uuid,
workflow = "audio_in,resample,partition,vad,fe,decode,itn,nlu_ddc,nlu_punctuate",
sequence = 1,
nbest = 1,
show_utterances = true,
vad_signal = true,
start_silence_time = "2000",
vad_silence_time = "1000"
}
};
return JsonConvert.SerializeObject(config);
}
private byte[] BuildPacket(string data)
{
// ===== 构建 Header (4 字节) =====
byte protocolVersion = 0b0001; // bit7-4: version
byte headerSize = 0b0001; // bit3-0: header size = 1,即4字节
byte messageType = 0b0001; // audio only request
byte messageTypeFlags = 0b0000; // 不使用特定flags
byte serializationMethod = 0b0001; // JSON格式
byte compressionMethod = 0b0000; // 无压缩
byte headerByte0 = (byte)((protocolVersion << 4) | headerSize);
byte headerByte1 = (byte)((messageType << 4) | messageTypeFlags);
byte headerByte2 = (byte)((serializationMethod << 4) | compressionMethod);
byte headerByte3 = 0x00; // reserved
byte[] header = new byte[] { headerByte0, headerByte1, headerByte2, headerByte3 };
// ===== 构建 Payload =====
string jsonPayload = data;
byte[] payload = Encoding.UTF8.GetBytes(jsonPayload);
// ===== 构建 Payload size (4 字节,大端) =====
byte[] payloadSize = BitConverter.GetBytes(payload.Length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(payloadSize); // 转为大端
}
// ===== 拼接完整包 =====
byte[] packet = new byte[header.Length + payloadSize.Length + payload.Length];
Buffer.BlockCopy(header, 0, packet, 0, header.Length);
Buffer.BlockCopy(payloadSize, 0, packet, header.Length, payloadSize.Length);
Buffer.BlockCopy(payload, 0, packet, header.Length + payloadSize.Length, payload.Length);
return packet;
}
private byte[] BuildPacket(byte[] data)
{
// ===== 构建 Header (4 字节) =====
byte protocolVersion = 0b0001; // bit7-4: version
byte headerSize = 0b0001; // bit3-0: header size = 1,即4字节
byte messageType = 0b0010; // audio only request
byte messageTypeFlags = 0b0000; // 不使用特定flags
byte serializationMethod = 0b0000; // JSON格式
byte compressionMethod = 0b0000; // 无压缩
byte headerByte0 = (byte)((protocolVersion << 4) | headerSize);
byte headerByte1 = (byte)((messageType << 4) | messageTypeFlags);
byte headerByte2 = (byte)((serializationMethod << 4) | compressionMethod);
byte headerByte3 = 0x00; // reserved
byte[] header = new byte[] { headerByte0, headerByte1, headerByte2, headerByte3 };
// ===== 构建 Payload =====
byte[] payload = data;
// ===== 构建 Payload size (4 字节,大端) =====
byte[] payloadSize = BitConverter.GetBytes(payload.Length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(payloadSize); // 转为大端
}
// ===== 拼接完整包 =====
byte[] packet = new byte[header.Length + payloadSize.Length + payload.Length];
Buffer.BlockCopy(header, 0, packet, 0, header.Length);
Buffer.BlockCopy(payloadSize, 0, packet, header.Length, payloadSize.Length);
Buffer.BlockCopy(payload, 0, packet, header.Length + payloadSize.Length, payload.Length);
return packet;
}
public async Task Connect()
{
// 添加自定义 Header
ws.Options.SetRequestHeader("Authorization", "Bearer; oFpo3PLYW2M_Z2Gjkuh1yhGltq5Zkmea");
// 设置连接的 URI
Uri serverUri = new Uri("wss://openspeech.bytedance.com/api/v2/asr");
try
{
// 发起连接
await ws.ConnectAsync(serverUri, CancellationToken.None);
Console.WriteLine("WebSocket 已连接");
// // 示例:发送一条消息
var sendBuffer = BuildPacket(Payload());
await ws.SendAsync(new ArraySegment<byte>(sendBuffer), WebSocketMessageType.Binary, true,
CancellationToken.None);
await using FileStream file = File.Open(path, FileMode.Open);
using BinaryReader binary = new BinaryReader(file);
// file.Seek(44, SeekOrigin.Begin);
while (true)
{
byte[] bytes = binary.ReadBytes(3200);
Console.WriteLine(binary.BaseStream.Position);
if (bytes.Length == 0)
{
break;
}
sendBuffer = BuildPacket(bytes);
await ws.SendAsync(new ArraySegment<byte>(sendBuffer), WebSocketMessageType.Binary, true,
CancellationToken.None);
// Thread.Sleep(10);
}
// await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "关闭连接", CancellationToken.None);
// Console.WriteLine("关闭连接");
}
catch (Exception ex)
{
Console.WriteLine("连接错误: " + ex.Message);
}
}
public async void Recevie()
{
while (true)
{
if (ws.State == WebSocketState.Open)
{
// // 示例:接收响应
var receiveBuffer = new byte[10240];
var result = await ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
// 只处理从第5个字节开始(索引 4)之后的数据
int offset = 8;
int length = receiveBuffer.Length - offset;
// 创建一个新的数组用于保存有效数据
byte[] usefulData = new byte[length];
Array.Copy(receiveBuffer, offset, usefulData, 0, length);
JObject root = JObject.Parse(Encoding.UTF8.GetString(usefulData));
Console.WriteLine("收到消息:" + root["result"]?[0]?["text"]);
}
await Task.Delay(100);
}
}
}