use std::sync::mpsc::{Receiver, SyncSender, TrySendError};
use crate::encoder::EncodedSample;
pub struct Fork {
record_tx: Option<SyncSender<EncodedSample>>,
stream_tx: Option<SyncSender<EncodedSample>>,
dropped_stream_frames: u64,
}
pub struct ForkReceivers {
pub record: Option<Receiver<EncodedSample>>,
pub stream: Option<Receiver<EncodedSample>>,
}
impl Fork {
pub fn new(record: bool, stream: bool, bound: usize) -> (Fork, ForkReceivers) {
let (record_tx, record_rx) = if record {
let (tx, rx) = std::sync::mpsc::sync_channel(bound);
(Some(tx), Some(rx))
} else {
(None, None)
};
let (stream_tx, stream_rx) = if stream {
let (tx, rx) = std::sync::mpsc::sync_channel(bound);
(Some(tx), Some(rx))
} else {
(None, None)
};
(
Fork {
record_tx,
stream_tx,
dropped_stream_frames: 0,
},
ForkReceivers {
record: record_rx,
stream: stream_rx,
},
)
}
pub fn distribute(&mut self, sample: EncodedSample) -> bool {
let mut any_alive = false;
if let Some(tx) = &self.record_tx {
match tx.send(sample.clone()) {
Ok(()) => any_alive = true,
Err(_) => self.record_tx = None, }
}
if let Some(tx) = &self.stream_tx {
match tx.try_send(sample.clone()) {
Ok(()) => any_alive = true,
Err(TrySendError::Full(s)) => {
if s.is_keyframe {
match tx.send(s) {
Ok(()) => any_alive = true,
Err(_) => self.stream_tx = None,
}
} else {
self.dropped_stream_frames += 1;
any_alive = true; }
}
Err(TrySendError::Disconnected(_)) => self.stream_tx = None,
}
}
any_alive
}
pub fn dropped_stream_frames(&self) -> u64 {
self.dropped_stream_frames
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
fn sample(keyframe: bool) -> EncodedSample {
EncodedSample {
data: vec![0u8; 4],
timestamp: Duration::ZERO,
is_keyframe: keyframe,
}
}
#[test]
fn stream_drops_non_keyframes_when_full_but_keeps_keyframes() {
let (mut fork, rx) = Fork::new(false, true, 1);
assert!(fork.distribute(sample(false))); assert!(fork.distribute(sample(false))); assert_eq!(fork.dropped_stream_frames(), 1);
let stream_rx = rx.stream.unwrap();
assert!(stream_rx.recv().is_ok());
}
#[test]
fn record_branch_receives_every_sample() {
let (mut fork, rx) = Fork::new(true, false, 8);
for _ in 0..5 {
assert!(fork.distribute(sample(false)));
}
let record_rx = rx.record.unwrap();
let mut count = 0;
while record_rx.try_recv().is_ok() {
count += 1;
}
assert_eq!(count, 5);
assert_eq!(fork.dropped_stream_frames(), 0);
}
#[test]
fn distribute_returns_false_when_all_consumers_gone() {
let (mut fork, rx) = Fork::new(true, false, 2);
drop(rx); assert!(!fork.distribute(sample(false)));
}
}