chore: 初始化测试场景
This commit is contained in:
@@ -10,13 +10,13 @@ pub const DISCOVERY_PORT: u16 = 53530;
|
||||
pub struct Discovery;
|
||||
|
||||
impl Discovery {
|
||||
/// 主节点:启动广播,告知从节点自己的 TCP 端口
|
||||
/// 服务端:启动广播,告知客户端自己的 TCP 端口
|
||||
pub async fn start_broadcast(tcp_port: u16) -> Result<()> {
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
socket.set_broadcast(true)?;
|
||||
|
||||
let target: SocketAddr = format!("255.255.255.255:{}", DISCOVERY_PORT).parse()?;
|
||||
let msg = postcard::to_allocvec(&ControlPacket::ServerHello { udp_port: tcp_port })?;
|
||||
let msg = postcard::to_allocvec(&ControlPacket::ServerHello { tcp_port })?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
@@ -28,17 +28,17 @@ impl Discovery {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从节点:监听广播,发现主节点的 IP 和 TCP 端口
|
||||
pub async fn discover_master() -> Result<(IpAddr, u16)> {
|
||||
/// 客户端:监听广播,发现服务端的 IP 和 TCP 端口
|
||||
pub async fn discover_server() -> Result<(IpAddr, u16)> {
|
||||
let socket = UdpSocket::bind(format!("0.0.0.0:{}", DISCOVERY_PORT)).await?;
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
loop {
|
||||
let (len, addr) = socket.recv_from(&mut buf).await?;
|
||||
if let Ok(ControlPacket::ServerHello { udp_port }) =
|
||||
if let Ok(ControlPacket::ServerHello { tcp_port }) =
|
||||
postcard::from_bytes::<ControlPacket>(&buf[..len])
|
||||
{
|
||||
return Ok((addr.ip(), udp_port));
|
||||
return Ok((addr.ip(), tcp_port));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,6 @@ impl AudioSocket {
|
||||
Ok((packet, addr))
|
||||
}
|
||||
|
||||
pub async fn punch(&self, target: SocketAddr) -> Result<()> {
|
||||
self.socket.send_to(&[0u8; 1], target).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clone_inner(&self) -> Arc<UdpSocket> {
|
||||
self.socket.clone()
|
||||
}
|
||||
@@ -56,16 +51,20 @@ impl ControlConnection {
|
||||
|
||||
pub async fn send_packet(&mut self, packet: &ControlPacket) -> Result<()> {
|
||||
let bytes = postcard::to_allocvec(packet)?;
|
||||
let len = bytes.len() as u32;
|
||||
self.stream.write_u32(len).await?;
|
||||
self.stream.write_all(&bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn recv_packet(&mut self, buf: &mut [u8]) -> Result<ControlPacket> {
|
||||
let len = self.stream.read(buf).await?;
|
||||
if len == 0 {
|
||||
return Err(anyhow::anyhow!("连接已关闭"));
|
||||
pub async fn recv_packet(&mut self) -> Result<ControlPacket> {
|
||||
let len = self.stream.read_u32().await? as usize;
|
||||
if len > 10 * 1024 * 1024 {
|
||||
return Err(anyhow::anyhow!("Packet too large: {}", len));
|
||||
}
|
||||
let packet = postcard::from_bytes(&buf[..len])?;
|
||||
let mut buf = vec![0u8; len];
|
||||
self.stream.read_exact(&mut buf).await?;
|
||||
let packet = postcard::from_bytes(&buf)?;
|
||||
Ok(packet)
|
||||
}
|
||||
|
||||
@@ -77,19 +76,21 @@ impl ControlConnection {
|
||||
) {
|
||||
self.stream.into_split()
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> Result<SocketAddr> {
|
||||
self.stream.peer_addr().context("Failed to get peer addr")
|
||||
}
|
||||
}
|
||||
|
||||
/// 主节点网络管理器
|
||||
pub struct MasterNetwork {
|
||||
/// 服务端网络管理器
|
||||
pub struct ServerNetwork {
|
||||
listener: TcpListener,
|
||||
audio: AudioSocket,
|
||||
}
|
||||
|
||||
impl MasterNetwork {
|
||||
impl ServerNetwork {
|
||||
pub async fn setup(port: u16) -> Result<Self> {
|
||||
let listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
|
||||
let audio = AudioSocket::bind().await?;
|
||||
Ok(Self { listener, audio })
|
||||
Ok(Self { listener })
|
||||
}
|
||||
|
||||
pub async fn accept(&self) -> Result<(ControlConnection, SocketAddr)> {
|
||||
@@ -97,30 +98,29 @@ impl MasterNetwork {
|
||||
Ok((ControlConnection::new(stream), addr))
|
||||
}
|
||||
|
||||
pub fn audio_socket(&self) -> &AudioSocket {
|
||||
&self.audio
|
||||
pub fn local_addr(&self) -> Result<SocketAddr> {
|
||||
self.listener
|
||||
.local_addr()
|
||||
.context("Failed to get local addr")
|
||||
}
|
||||
}
|
||||
|
||||
/// 从节点网络管理器
|
||||
pub struct SlaveNetwork {
|
||||
/// 客户端网络管理器
|
||||
pub struct ClientNetwork {
|
||||
control: ControlConnection,
|
||||
audio: AudioSocket,
|
||||
}
|
||||
|
||||
impl SlaveNetwork {
|
||||
pub async fn connect(master_addr: SocketAddr) -> Result<Self> {
|
||||
let stream = TcpStream::connect(master_addr)
|
||||
impl ClientNetwork {
|
||||
pub async fn connect(server_addr: SocketAddr) -> Result<Self> {
|
||||
let stream = TcpStream::connect(server_addr)
|
||||
.await
|
||||
.context(format!("无法连接到主节点 TCP 地址: {}", master_addr))?;
|
||||
let audio = AudioSocket::bind().await?;
|
||||
.context(format!("无法连接到服务端 TCP 地址: {}", server_addr))?;
|
||||
Ok(Self {
|
||||
control: ControlConnection::new(stream),
|
||||
audio,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn split(self) -> (ControlConnection, AudioSocket) {
|
||||
(self.control, self.audio)
|
||||
pub fn into_control(self) -> ControlConnection {
|
||||
self.control
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,59 @@
|
||||
use crate::audio::config::AudioConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub enum ChannelRole {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl ChannelRole {
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
ChannelRole::Left => "左声道".to_string(),
|
||||
ChannelRole::Right => "右声道".to_string(),
|
||||
}
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct DeviceInfo {
|
||||
pub model: String,
|
||||
pub mac: String,
|
||||
pub version: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum ControlPacket {
|
||||
// 发现协议
|
||||
// 服务发现
|
||||
ServerHello {
|
||||
udp_port: u16, // UDP 音频流端口
|
||||
tcp_port: u16,
|
||||
},
|
||||
// 握手协议
|
||||
// 握手与认证
|
||||
ClientIdentify {
|
||||
role: ChannelRole,
|
||||
info: DeviceInfo,
|
||||
},
|
||||
// 时间同步 (持续进行)
|
||||
Ping {
|
||||
client_ts: u128,
|
||||
seq: u32,
|
||||
IdentifyOk,
|
||||
|
||||
// 音频控制
|
||||
StartRecording {
|
||||
config: AudioConfig,
|
||||
},
|
||||
Pong {
|
||||
client_ts: u128,
|
||||
server_ts: u128,
|
||||
seq: u32,
|
||||
StopRecording,
|
||||
StartPlayback {
|
||||
config: AudioConfig,
|
||||
},
|
||||
StopPlayback,
|
||||
|
||||
// RPC
|
||||
RpcRequest {
|
||||
id: u32,
|
||||
method: String,
|
||||
args: Vec<String>,
|
||||
},
|
||||
RpcResponse {
|
||||
id: u32,
|
||||
result: RpcResult,
|
||||
},
|
||||
|
||||
// 心跳
|
||||
Ping,
|
||||
Pong,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct RpcResult {
|
||||
pub stdout: String,
|
||||
pub stderr: String,
|
||||
pub code: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct AudioPacket {
|
||||
pub seq: u32, // 序列号,用于丢包检测
|
||||
pub timestamp: u128, // 目标播放时间 (主节点时间)
|
||||
pub data: Vec<u8>, // Opus 编码数据
|
||||
pub data: Vec<u8>, // Opus 编码数据
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user