89 lines
2.6 KiB
Rust
89 lines
2.6 KiB
Rust
//! ADP frame protocol definition
|
|
//!
|
|
//! Frame format (8-byte header):
|
|
//! ```text
|
|
//! 0 1 2 3
|
|
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//! | Magic (0xAD) | Version | Type | Flags |
|
|
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//! | Sequence Number | Payload Length |
|
|
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//! ```
|
|
//!
|
|
//! Types:
|
|
//! - 0x01: Capability Request/Response (handshake)
|
|
//! - 0x02: Video Frame (H.264 NAL unit)
|
|
//! - 0x03: Keepalive
|
|
//! - 0x04: UIBC Event (touch/keyboard from phone to PC)
|
|
//! - 0x05: Resolution Change Notification
|
|
|
|
pub const ADP_MAGIC: u16 = 0x0BAD;
|
|
pub const ADP_VERSION: u8 = 1;
|
|
pub const ADP_DEFAULT_PORT: u16 = 7935;
|
|
|
|
#[repr(u8)]
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum FrameType {
|
|
Capability = 0x01,
|
|
VideoFrame = 0x02,
|
|
Keepalive = 0x03,
|
|
UibcEvent = 0x04,
|
|
ResolutionChange = 0x05,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone)]
|
|
pub struct FrameHeader {
|
|
pub magic: u16, // 0x0BAD
|
|
pub version: u8, // 1
|
|
pub frame_type: u8, // FrameType
|
|
pub flags: u8, // reserved
|
|
pub sequence: u32, // sequence number
|
|
pub payload_len: u32, // payload length
|
|
}
|
|
|
|
impl FrameHeader {
|
|
pub const SIZE: usize = 12;
|
|
|
|
pub fn new(frame_type: FrameType, sequence: u32, payload_len: u32) -> Self {
|
|
Self {
|
|
magic: ADP_MAGIC,
|
|
version: ADP_VERSION,
|
|
frame_type: frame_type as u8,
|
|
flags: 0,
|
|
sequence,
|
|
payload_len,
|
|
}
|
|
}
|
|
|
|
pub fn to_bytes(&self) -> Vec<u8> {
|
|
let mut buf = Vec::with_capacity(Self::SIZE);
|
|
buf.extend_from_slice(&self.magic.to_be_bytes());
|
|
buf.push(self.version);
|
|
buf.push(self.frame_type);
|
|
buf.push(self.flags);
|
|
buf.extend_from_slice(&self.sequence.to_be_bytes());
|
|
buf.extend_from_slice(&self.payload_len.to_be_bytes());
|
|
buf
|
|
}
|
|
|
|
pub fn from_bytes(data: &[u8]) -> Option<Self> {
|
|
if data.len() < Self::SIZE {
|
|
return None;
|
|
}
|
|
let magic = u16::from_be_bytes([data[0], data[1]]);
|
|
if magic != ADP_MAGIC {
|
|
return None;
|
|
}
|
|
Some(Self {
|
|
magic,
|
|
version: data[2],
|
|
frame_type: data[3],
|
|
flags: data[4],
|
|
sequence: u32::from_be_bytes([data[5], data[6], data[7], data[8]]),
|
|
payload_len: u32::from_be_bytes([data[9], data[10], data[11], data[12]]),
|
|
})
|
|
}
|
|
}
|