use bytes::Bytes;
use std::collections::VecDeque;
use std::io::{self, IoSlice, Write};
use std::time::Instant;
const MAX_IOV: usize = 64;
const QUEUE_WARN_BYTES: usize = 1 * 1024 * 1024; const QUEUE_HIGH_BYTES: usize = 2 * 1024 * 1024; const QUEUE_MAX_BYTES: usize = 4 * 1024 * 1024; const QUEUE_MAX_AGE_SECS: u64 = 10; const AUDIO_ONLY_MAX_AGE_SECS: u64 = 5;
struct WriteEntry {
data: Bytes,
offset: usize,
timestamp: Instant,
#[allow(dead_code)]
is_keyframe: bool,
is_sequence_header: bool, }
impl WriteEntry {
fn remaining(&self) -> &[u8] {
&self.data[self.offset..]
}
fn advance(&mut self, n: usize) {
self.offset += n;
}
fn remaining_bytes(&self) -> usize {
self.data.len().saturating_sub(self.offset)
}
fn age_secs(&self) -> u64 {
self.timestamp.elapsed().as_secs()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BackpressureLevel {
Normal, Warning, High, Critical, }
#[derive(Debug)]
pub enum FlushResult {
Complete { bytes_written: usize },
WouldBlock { bytes_written: usize },
Closed,
}
pub struct WriteQueue {
queue: VecDeque<WriteEntry>,
total_bytes: usize,
has_video: bool, dropped_frames: u64,
}
impl WriteQueue {
pub fn new() -> Self {
Self {
queue: VecDeque::with_capacity(64),
total_bytes: 0,
has_video: false,
dropped_frames: 0,
}
}
pub fn backpressure_level(&self) -> BackpressureLevel {
if self.total_bytes >= QUEUE_MAX_BYTES {
BackpressureLevel::Critical
} else if self.total_bytes >= QUEUE_HIGH_BYTES {
BackpressureLevel::High
} else if self.total_bytes >= QUEUE_WARN_BYTES {
BackpressureLevel::Warning
} else {
BackpressureLevel::Normal
}
}
pub fn enqueue(
&mut self,
data: Bytes,
is_keyframe: bool,
is_sequence_header: bool,
is_video: bool,
) -> bool {
if is_video {
self.has_video = true;
}
if self.total_bytes.saturating_add(data.len()) >= QUEUE_MAX_BYTES {
return false;
}
let level = self.backpressure_level();
if is_sequence_header {
self.push_entry(data, is_keyframe, true);
return true;
}
match level {
BackpressureLevel::Normal => {
self.push_entry(data, is_keyframe, false);
}
BackpressureLevel::Warning => {
if is_keyframe || !is_video {
self.push_entry(data, is_keyframe, false);
} else {
self.dropped_frames += 1;
}
self.evict_old_entries();
}
BackpressureLevel::High => {
if is_keyframe {
self.push_entry(data, is_keyframe, false);
} else {
self.dropped_frames += 1;
}
self.evict_old_entries();
}
BackpressureLevel::Critical => unreachable!(),
}
true
}
fn push_entry(&mut self, data: Bytes, is_keyframe: bool, is_sequence_header: bool) {
let len = data.len();
self.queue.push_back(WriteEntry {
data,
offset: 0,
timestamp: Instant::now(),
is_keyframe,
is_sequence_header,
});
self.total_bytes += len;
}
fn evict_old_entries(&mut self) {
let max_age = if self.has_video {
QUEUE_MAX_AGE_SECS
} else {
AUDIO_ONLY_MAX_AGE_SECS
};
while let Some(entry) = self.queue.front() {
if entry.is_sequence_header {
break;
}
if entry.offset > 0 {
break;
}
if entry.age_secs() > max_age {
if let Some(removed) = self.queue.pop_front() {
self.total_bytes = self.total_bytes.saturating_sub(removed.remaining_bytes());
self.dropped_frames += 1;
}
} else {
break;
}
}
}
pub fn try_flush<W: Write>(&mut self, writer: &mut W) -> io::Result<FlushResult> {
let mut bytes_written = 0;
loop {
self.pop_completed_front();
if self.queue.is_empty() {
return Ok(FlushResult::Complete { bytes_written });
}
let mut gathered = 0usize;
let write_result = {
let mut iov: Vec<IoSlice> = Vec::with_capacity(MAX_IOV);
for entry in self.queue.iter() {
if iov.len() == MAX_IOV {
break;
}
let rem = entry.remaining();
if !rem.is_empty() {
gathered += rem.len();
iov.push(IoSlice::new(rem));
}
}
writer.write_vectored(&iov)
};
match write_result {
Ok(0) => return Ok(FlushResult::Closed),
Ok(n) => {
bytes_written += n;
self.advance_front(n);
if n < gathered {
return Ok(FlushResult::WouldBlock { bytes_written });
}
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
return Ok(FlushResult::WouldBlock { bytes_written });
}
Err(e) => return Err(e),
}
}
}
fn pop_completed_front(&mut self) {
while let Some(front) = self.queue.front() {
if front.remaining().is_empty() {
let full = front.data.len();
self.total_bytes = self.total_bytes.saturating_sub(full);
self.queue.pop_front();
} else {
break;
}
}
}
fn advance_front(&mut self, mut n: usize) {
while n > 0 {
let Some(front) = self.queue.front_mut() else {
break;
};
let rem = front.remaining_bytes();
if rem == 0 {
let full = front.data.len();
self.total_bytes = self.total_bytes.saturating_sub(full);
self.queue.pop_front();
continue;
}
if n >= rem {
let full = front.data.len();
self.total_bytes = self.total_bytes.saturating_sub(full);
self.queue.pop_front();
n -= rem;
} else {
front.advance(n);
n = 0;
}
}
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
#[cfg(test)]
pub fn pending_bytes(&self) -> usize {
self.total_bytes
}
#[cfg(test)]
pub fn pending_entries(&self) -> usize {
self.queue.len()
}
#[cfg(test)]
fn dropped_frames(&self) -> u64 {
self.dropped_frames
}
#[cfg(test)]
fn backdate_front(&mut self, secs: u64) {
if let Some(front) = self.queue.front_mut() {
if let Some(t) = Instant::now().checked_sub(std::time::Duration::from_secs(secs)) {
front.timestamp = t;
}
}
}
#[cfg(test)]
fn front_offset(&self) -> Option<usize> {
self.queue.front().map(|e| e.offset)
}
#[cfg(test)]
fn has_video(&self) -> bool {
self.has_video
}
}
impl Default for WriteQueue {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_data(size: usize) -> Bytes {
Bytes::from(vec![0u8; size])
}
#[test]
fn test_basic_enqueue_dequeue() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(100), false, false, true);
assert_eq!(queue.pending_bytes(), 100);
assert_eq!(queue.pending_entries(), 1);
assert_eq!(queue.backpressure_level(), BackpressureLevel::Normal);
}
#[test]
fn test_backpressure_levels() {
{
let mut queue = WriteQueue::new();
queue.enqueue(make_data(512 * 1024), true, false, true); assert_eq!(queue.backpressure_level(), BackpressureLevel::Normal);
}
{
let mut queue = WriteQueue::new();
queue.enqueue(make_data(1500 * 1024), true, false, true); assert_eq!(queue.backpressure_level(), BackpressureLevel::Warning);
}
{
let mut queue = WriteQueue::new();
queue.enqueue(make_data(3 * 1024 * 1024), true, false, true); assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
}
{
let mut queue = WriteQueue::new();
queue.enqueue(make_data(3500 * 1024), true, false, true);
assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
let result = queue.enqueue(make_data(600 * 1024), true, false, true);
assert!(
!result,
"Enqueue should be rejected when it would reach Critical"
);
assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
}
}
#[test]
fn test_sequence_header_never_dropped() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(3 * 1024 * 1024), false, false, true);
assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
let result = queue.enqueue(make_data(100), false, true, true);
assert!(result);
let _before = queue.pending_entries();
queue.enqueue(make_data(100), false, false, true);
assert!(queue.dropped_frames() > 0);
}
#[test]
fn test_keyframe_preserved_at_high_level() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(3 * 1024 * 1024), false, false, true);
assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
let before = queue.pending_entries();
queue.enqueue(make_data(100), true, false, true);
assert_eq!(queue.pending_entries(), before + 1);
}
#[test]
fn test_audio_preserved_at_warning_level() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(1500 * 1024), false, false, true);
assert_eq!(queue.backpressure_level(), BackpressureLevel::Warning);
let before = queue.pending_entries();
queue.enqueue(make_data(100), false, false, false);
assert_eq!(queue.pending_entries(), before + 1);
let dropped_before = queue.dropped_frames();
queue.enqueue(make_data(100), false, false, true);
assert!(queue.dropped_frames() > dropped_before);
}
#[test]
fn test_critical_rejects_all() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(3900 * 1024), true, false, true);
assert_eq!(queue.backpressure_level(), BackpressureLevel::High);
let result = queue.enqueue(make_data(200 * 1024), true, false, true);
assert!(
!result,
"Keyframe should be rejected when it would exceed Critical"
);
let result = queue.enqueue(make_data(200 * 1024), false, true, true);
assert!(
!result,
"Sequence header should be rejected when it would exceed Critical"
);
assert!(!result);
}
struct CapWriter {
inner: Vec<u8>,
capacity: usize,
}
impl Write for CapWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.inner.len() >= self.capacity {
return Err(io::Error::from(io::ErrorKind::WouldBlock));
}
let room = self.capacity - self.inner.len();
let n = buf.len().min(room);
self.inner.extend_from_slice(&buf[..n]);
Ok(n)
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
if self.inner.len() >= self.capacity {
return Err(io::Error::from(io::ErrorKind::WouldBlock));
}
let mut total = 0;
for b in bufs {
let room = self.capacity - self.inner.len();
if room == 0 {
break;
}
let n = b.len().min(room);
self.inner.extend_from_slice(&b[..n]);
total += n;
if n < b.len() {
break; }
}
Ok(total)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[test]
fn test_partial_write_walks_across_entries() {
let mut queue = WriteQueue::new();
queue.enqueue(Bytes::from_static(b"hello"), false, false, true);
queue.enqueue(Bytes::from_static(b"world"), false, false, true);
assert_eq!(queue.pending_bytes(), 10);
let mut writer = CapWriter {
inner: Vec::new(),
capacity: 7,
};
let result = queue.try_flush(&mut writer).unwrap();
assert!(matches!(
result,
FlushResult::WouldBlock { bytes_written: 7 }
));
assert_eq!(writer.inner, b"hellowo");
assert_eq!(queue.pending_entries(), 1);
assert_eq!(queue.front_offset(), Some(2));
assert_eq!(queue.pending_bytes(), 5);
writer.capacity = 100;
let result = queue.try_flush(&mut writer).unwrap();
assert!(matches!(result, FlushResult::Complete { bytes_written: 3 }));
assert_eq!(writer.inner, b"helloworld");
assert!(queue.is_empty());
assert_eq!(queue.pending_bytes(), 0);
}
#[test]
fn test_would_block_returns_bytes_written() {
let mut queue = WriteQueue::new();
queue.enqueue(Bytes::from_static(b"hello"), false, false, true);
queue.enqueue(Bytes::from_static(b"world"), false, false, true);
let mut writer = CapWriter {
inner: Vec::new(),
capacity: 3,
};
let result = queue.try_flush(&mut writer).unwrap();
assert!(matches!(
result,
FlushResult::WouldBlock { bytes_written: 3 }
));
assert_eq!(writer.inner, b"hel");
assert!(!queue.is_empty());
assert_eq!(queue.front_offset(), Some(3));
let result = queue.try_flush(&mut writer).unwrap();
assert!(matches!(
result,
FlushResult::WouldBlock { bytes_written: 0 }
));
assert_eq!(queue.front_offset(), Some(3));
}
#[test]
fn test_flush_batches_many_entries_into_few_writev() {
struct CountingWriter {
inner: Vec<u8>,
writev_calls: usize,
}
impl Write for CountingWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.extend_from_slice(buf);
Ok(buf.len())
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.writev_calls += 1;
let mut total = 0;
for b in bufs {
self.inner.extend_from_slice(b);
total += b.len();
}
Ok(total)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
let count = MAX_IOV * 2 + 5; let mut queue = WriteQueue::new();
let mut flat = Vec::new();
for i in 0..count {
let payload = vec![(i % 251) as u8; 3];
flat.extend_from_slice(&payload);
queue.enqueue(Bytes::from(payload), false, false, true);
}
let mut writer = CountingWriter {
inner: Vec::new(),
writev_calls: 0,
};
let result = queue.try_flush(&mut writer).unwrap();
assert!(matches!(result, FlushResult::Complete { .. }));
assert!(queue.is_empty());
assert_eq!(queue.pending_bytes(), 0);
assert_eq!(writer.inner, flat, "writev must preserve packet order");
let expected_calls = (count + MAX_IOV - 1) / MAX_IOV;
assert_eq!(
writer.writev_calls, expected_calls,
"should batch {} entries into {} writev calls",
count, expected_calls
);
}
#[test]
fn eviction_keeps_partially_written_front_entry() {
struct WouldBlockWriter {
written: usize,
block_after: usize,
}
impl Write for WouldBlockWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.written >= self.block_after {
return Err(io::Error::from(io::ErrorKind::WouldBlock));
}
let n = buf.len().min(self.block_after - self.written);
self.written += n;
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
let mut queue = WriteQueue::new();
queue.enqueue(Bytes::from_static(b"hello"), false, false, true);
let mut writer = WouldBlockWriter {
written: 0,
block_after: 3,
};
let _ = queue.try_flush(&mut writer).unwrap();
assert_eq!(queue.front_offset(), Some(3));
queue.backdate_front(60);
queue.enqueue(make_data(QUEUE_WARN_BYTES), true, false, true);
queue.enqueue(make_data(10), true, false, true);
assert_eq!(
queue.front_offset(),
Some(3),
"a partially written entry must never be evicted"
);
}
#[test]
fn test_stats() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(1000), false, false, true);
assert_eq!(queue.pending_bytes(), 1000);
assert_eq!(queue.pending_entries(), 1);
assert!(queue.has_video());
assert_eq!(queue.dropped_frames(), 0);
}
#[test]
fn test_pure_audio_stream() {
let mut queue = WriteQueue::new();
queue.enqueue(make_data(100), false, false, false);
queue.enqueue(make_data(100), false, false, false);
assert!(!queue.has_video());
}
}