use bytes::{Buf, BufMut, Bytes, BytesMut};
use derive_more::Debug;
use moq_net::VarInt;
use crate::Error;
pub use moq_net::{Timescale, Timestamp};
pub const TIMESCALE: Timescale = Timescale::MICRO;
pub fn track_info() -> moq_net::track::Info {
moq_net::track::Info::default().with_timescale(TIMESCALE)
}
#[derive(Clone, Debug)]
pub struct Frame {
pub timestamp: Timestamp,
#[debug("{} bytes", payload.len())]
pub payload: Bytes,
}
impl Frame {
pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), Error> {
self.encode_header(buf)?;
buf.put_slice(&self.payload);
Ok(())
}
pub fn decode(mut buf: impl Buf) -> Result<Self, Error> {
let value: u64 = VarInt::decode_quic(&mut buf).map_err(moq_net::Error::from)?.into();
let timestamp = Timestamp::new(value, TIMESCALE)?;
let payload = buf.copy_to_bytes(buf.remaining());
Ok(Self { timestamp, payload })
}
pub fn write_to(&self, group: &mut moq_net::group::Producer) -> Result<(), Error> {
let mut header = BytesMut::new();
self.encode_header(&mut header)?;
let header = header.freeze();
let size = (header.len() + self.payload.len()) as u64;
let info = moq_net::frame::Info {
size,
timestamp: self.timestamp,
};
let mut chunked = group.create_frame(info)?;
chunked.write(header)?;
chunked.write(self.payload.clone())?;
chunked.finish()?;
Ok(())
}
fn encode_header(&self, buf: &mut impl BufMut) -> Result<(), Error> {
let timestamp = self.timestamp.convert(TIMESCALE)?;
let value = VarInt::try_from(timestamp.value()).map_err(moq_net::Error::from)?;
value.encode_quic(buf).map_err(moq_net::Error::from)?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn encode_decode_roundtrip() {
let frame = Frame {
timestamp: Timestamp::from_micros(1_234_567).expect("timestamp"),
payload: Bytes::from_static(b"hello"),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf).expect("encode");
let decoded = Frame::decode(buf.freeze()).expect("decode");
assert_eq!(decoded.timestamp, frame.timestamp);
assert_eq!(decoded.payload, frame.payload);
}
#[test]
fn encode_normalizes_timescale() {
let frame = Frame {
timestamp: Timestamp::new(1_234_567_000, Timescale::NANO).expect("timestamp"),
payload: Bytes::from_static(b"hello"),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf).expect("encode");
let decoded = Frame::decode(buf.freeze()).expect("decode");
assert_eq!(decoded.timestamp, Timestamp::from_micros(1_234_567).expect("timestamp"));
}
#[test]
fn track_info_uses_container_timescale() {
assert_eq!(track_info().timescale, TIMESCALE);
}
}