This commit is contained in:
2026-04-09 16:00:07 -03:00
parent e69fec5aea
commit 5921cd6562
13 changed files with 1104 additions and 0 deletions

11
media/client/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "cht-client"
version = "0.1.0"
edition = "2021"
[dependencies]
cht-common = { path = "../common" }
tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = { workspace = true }

102
media/client/src/main.rs Normal file
View File

@@ -0,0 +1,102 @@
use anyhow::Result;
use cht_common::protocol::{
self, AudioParams, ControlMessage, PacketHeader, PacketType, VideoParams, WirePacket,
FLAG_KEYFRAME,
};
use tokio::io::{AsyncWriteExt, BufWriter};
use tokio::net::TcpStream;
use tracing::info;
const DEFAULT_SERVER: &str = "mcrndeb:4444";
#[tokio::main]
async fn main() -> Result<()> {
cht_common::logging::init("client");
let server_addr = std::env::args()
.nth(1)
.unwrap_or_else(|| DEFAULT_SERVER.to_string());
info!("Connecting to {server_addr}...");
let stream = TcpStream::connect(&server_addr).await?;
info!("Connected");
let mut writer = BufWriter::new(stream);
// Send session_start
let session_start = ControlMessage::SessionStart {
id: chrono_session_id(),
video: VideoParams {
width: 1920,
height: 1080,
codec: "h264".into(),
fps: 30,
},
audio: AudioParams {
sample_rate: 48000,
channels: 2,
codec: "aac".into(),
},
};
protocol::write_packet(&mut writer, &session_start.to_wire_packet()?).await?;
info!("Sent session_start");
// Send test packets (placeholder — will be replaced by real capture)
let frame_interval_ns = 33_333_333u64; // ~30fps
for i in 0u64..300 {
let ts = i * frame_interval_ns;
let keyframe = i % 30 == 0;
// Fake video packet
let video = WirePacket {
header: PacketHeader {
packet_type: PacketType::Video,
flags: if keyframe { FLAG_KEYFRAME } else { 0 },
length: 1024,
timestamp_ns: ts,
},
payload: vec![0u8; 1024],
};
protocol::write_packet(&mut writer, &video).await?;
// Fake audio packet every 3 video frames
if i % 3 == 0 {
let audio = WirePacket {
header: PacketHeader {
packet_type: PacketType::Audio,
flags: 0,
length: 512,
timestamp_ns: ts,
},
payload: vec![0u8; 512],
};
protocol::write_packet(&mut writer, &audio).await?;
}
// Keepalive every 150 frames (~5s)
if i % 150 == 0 && i > 0 {
let keepalive = ControlMessage::Keepalive;
protocol::write_packet(&mut writer, &keepalive.to_wire_packet()?).await?;
}
tokio::time::sleep(std::time::Duration::from_nanos(frame_interval_ns)).await;
}
// Send session_stop and flush
let stop = ControlMessage::SessionStop;
protocol::write_packet(&mut writer, &stop.to_wire_packet()?).await?;
writer.flush().await?;
writer.shutdown().await?;
info!("Sent session_stop, done");
Ok(())
}
fn chrono_session_id() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
format!("{secs}")
}