Browse Source

save

master
eta 2 years ago
commit
3fcf753096
  1. 1
      .gitignore
  2. 14
      Cargo.lock
  3. 10
      Cargo.toml
  4. BIN
      noise.dat
  5. 156
      src/main.rs
  6. BIN
      wakeup.dat
  7. BIN
      wakeup2.dat

1
.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
/target

14
Cargo.lock generated

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "showtime"
version = "0.1.0"
dependencies = [
"byteorder",
]

10
Cargo.toml

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
[package]
name = "showtime"
version = "0.1.0"
authors = ["eta <eta@theta.eu.org>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
byteorder = "1.4"

BIN
noise.dat

Binary file not shown.

156
src/main.rs

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
use std::net::{UdpSocket, Ipv4Addr, SocketAddr};
use byteorder::{BigEndian, WriteBytesExt, ByteOrder};
use std::io::Write;
struct FrameChunker<'a> {
inner: &'a [u8],
frame_no: u16,
seq_no: u16
}
impl<'a> FrameChunker<'a> {
fn new(frame_no: u16, inner: &'a [u8]) -> Self {
Self {
inner,
frame_no,
seq_no: 0
}
}
fn empty() -> Self {
Self {
inner: &[],
frame_no: 0,
seq_no: 0
}
}
fn next_chunk(&mut self) -> Vec<u8> {
let mut ret = Vec::with_capacity(1024);
let (remaining, last) = if self.inner.len() > 1020 {
(1020, false)
}
else {
(self.inner.len(), true)
};
ret.write_u16::<BigEndian>(self.frame_no).unwrap();
ret.write_u16::<BigEndian>(self.seq_no).unwrap();
if last {
ret[2] |= 0b1000_0000;
}
ret.extend(&self.inner[..remaining]);
self.inner = &self.inner[remaining..];
self.seq_no += 1;
ret
}
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
const MAGIC_ADDRESS: Ipv4Addr = Ipv4Addr::new(226, 2, 2, 2);
fn make_vsync(frame_no: u16) -> Vec<u8> {
let mut ret = Vec::with_capacity(20);
ret.write_all(&[0, 0, 0, 0]).unwrap();
ret.write_u16::<BigEndian>(frame_no).unwrap();
for _ in 0..14 {
ret.write_all(&[0]).unwrap();
}
ret
}
fn make_heartbeat(seq_no: u16, cur_ts: u16, init: bool) -> Vec<u8> {
let mut ret = Vec::with_capacity(1024);
ret.write_all(&[0x54, 0x46, 0x36, 0x7a, 0x63, 0x01, 0x00]).unwrap();
ret.write_u16::<BigEndian>(seq_no).unwrap();
ret.write_all(&[0x00, 0x00, 0x03, 0x03, 0x03, 0x00, 0x24, 0x00, 0x00]).unwrap();
for _ in 0..8 {
ret.write_all(&[0]).unwrap();
}
let (mode, a, b, c, d, e, f) = if init {
(3, 1920, 1080, 599, 1920, 1080, 120)
}
else {
(10, 0, 0, 0, 0, 0, 120)
};
for thing in &[mode, a, b, c, d, e, f] {
ret.write_u16::<BigEndian>(*thing).unwrap();
}
ret.write_all(&[0, 0]).unwrap();
ret.write_u16::<BigEndian>(cur_ts).unwrap();
ret.write_all(&[0, 1, 0, 0, 0, 0, 0x03, 0x0a]).unwrap();
for _ in ret.len()..1024 {
ret.write_all(&[0]).unwrap();
}
assert_eq!(ret.len(), 1024);
ret
}
#[test]
fn test_frame_chunker() {
let test_frame = include_bytes!("../test.mjpeg");
let mut chonker = FrameChunker::new(0, test_frame as &[u8]);
let mut test = Vec::new();
let mut expected_seq = 0;
while !chonker.is_empty() {
let buf = chonker.next_chunk();
test.extend(&buf[4..]);
assert_eq!(BigEndian::read_u16(&buf[2..]) & 0b0111_1111, expected_seq);
expected_seq += 1;
}
assert_eq!(test_frame as &[u8], &test as &[u8]);
}
fn main() {
let test_frame = include_bytes!("../test.mjpeg");
let wakeup_frame = include_bytes!("../wakeup.dat");
let noise_frame = include_bytes!("../noise.dat");
let mut wakeup_mut = include_bytes!("../wakeup2.dat").to_vec();
let mut vsync = UdpSocket::bind("192.168.168.55:2067").unwrap();
let vsync_dest: SocketAddr = "226.2.2.2:2067".parse().unwrap();
let mut mjpeg = UdpSocket::bind("192.168.168.55:2068").unwrap();
let mjpeg_dest: SocketAddr = "226.2.2.2:2068".parse().unwrap();
let mut sound = UdpSocket::bind("192.168.168.55:2065").unwrap();
let sound_dest: SocketAddr = "226.2.2.2:2066".parse().unwrap();
let mut wakeup = UdpSocket::bind("192.168.168.55:48689").unwrap();
let wakeup_dest: SocketAddr = "255.255.255.255:48689".parse().unwrap();
println!("bound");
vsync.join_multicast_v4(&MAGIC_ADDRESS, &"192.168.168.55".parse().unwrap()).unwrap();
mjpeg.join_multicast_v4(&MAGIC_ADDRESS, &"192.168.168.55".parse().unwrap()).unwrap();
sound.join_multicast_v4(&MAGIC_ADDRESS, &"192.168.168.55".parse().unwrap()).unwrap();
println!("joined");
let mut chonker = FrameChunker::empty();
let mut frame_no = 0;
println!("enable broadcast");
wakeup.set_broadcast(true).unwrap();
println!("send initial wakeup");
wakeup.send_to(wakeup_frame, &wakeup_dest).unwrap();
println!("{:0x}", wakeup_frame[42]);
wakeup_mut[8] = 1;
println!("spawning audio thread");
std::thread::spawn(move || {
loop {
sound.send_to(noise_frame, &sound_dest).unwrap();
std::thread::sleep(std::time::Duration::from_micros(2800));
}
});
println!("going brr");
loop {
if (frame_no % 30) == 0 {
let cur_ts = BigEndian::read_u16(&wakeup_mut[41..]);
println!("sending wakeup: wakeup[8] = {:0x}, cur_ts = {}", wakeup_mut[8], cur_ts);
wakeup_mut[8] += 1;
BigEndian::write_u16(&mut wakeup_mut[41..], cur_ts.overflowing_add(1002).0);
wakeup.send_to(&wakeup_mut, &wakeup_dest).unwrap();
}
chonker = FrameChunker::new(frame_no, test_frame as &[u8]);
frame_no += 1;
let vsync_pkt = make_vsync(frame_no);
vsync.send_to(&vsync_pkt, &vsync_dest).unwrap();
while !chonker.is_empty() {
let buf = chonker.next_chunk();
mjpeg.send_to(&buf, mjpeg_dest).unwrap();
}
::std::thread::sleep_ms(33);
}
}

BIN
wakeup.dat

Binary file not shown.

BIN
wakeup2.dat

Binary file not shown.
Loading…
Cancel
Save