hylarana_transport/package.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
use crate::adapter::StreamKind;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use xxhash_rust::xxh3::xxh3_64;
#[derive(Debug)]
pub struct PacketInfo {
pub kind: StreamKind,
pub flags: i32,
pub timestamp: u64,
}
/// Creates a BytesMut and copies from src to a buffer. The created buffer
/// contains the initial message header required for message encoding, which is
/// an optimization to reduce data copying in the process.
pub fn copy_from_slice(src: &[u8]) -> BytesMut {
let mut bytes = BytesMut::with_capacity(src.len() + Package::HEAD_SIZE);
bytes.put_bytes(0, Package::HEAD_SIZE);
bytes.put(src);
bytes
}
/// Create a BytesMut and initialize it according to the capacity. The created
/// buffer contains the initialization message header required for message
/// encoding, which is an optimization to reduce data copying in the process.
pub fn with_capacity(size: usize) -> BytesMut {
BytesMut::zeroed(size + Package::HEAD_SIZE)
}
/// Because of the need to transmit both audio and video data in srt, it is
/// necessary to identify the type of packet, this encoder is used to packetize
/// specific types of data for transmission over the network.
pub struct Package;
impl Package {
const HEAD_SIZE: usize = 26;
/// The result of the encoding may be null, this is because an empty packet
/// may be passed in from outside.
pub fn pack(info: PacketInfo, mut bytes: BytesMut) -> Bytes {
let size = bytes.len();
unsafe {
bytes.set_len(0);
}
bytes.put_u64(0);
bytes.put_u64(size as u64);
bytes.put_u8(info.kind as u8);
bytes.put_u8(info.flags as u8);
bytes.put_u64(info.timestamp);
unsafe {
bytes.set_len(size);
}
let hash = xxh3_64(&bytes[8..]);
bytes[0..8].copy_from_slice(&hash.to_be_bytes());
bytes.freeze()
}
}
/// Decode the packets received from the network and separate out the different
/// types of data.
pub struct UnPackage;
impl UnPackage {
pub fn unpack(mut bytes: Bytes) -> Option<(PacketInfo, Bytes)> {
let count = bytes.len();
if bytes.get_u64() == xxh3_64(&bytes) {
if bytes.get_u64() as usize == count {
Some((
PacketInfo {
kind: StreamKind::try_from(bytes.get_u8()).ok()?,
flags: bytes.get_u8() as i32,
timestamp: bytes.get_u64(),
},
bytes,
))
} else {
None
}
} else {
None
}
}
}