use super::pacer::Pacer as LeakyBucket;
use crate::Interceptor;
use crate::StreamInfo;
use crate::{Attribute, Packet, TaggedPacket};
use sansio::Protocol;
use shared::error::Error;
use shared::marshal::MarshalSize;
use std::collections::VecDeque;
use std::time::Instant;
pub const DEFAULT_BITRATE: f64 = 1_000_000.0;
pub const DEFAULT_QUEUE_LIMIT: usize = 4096;
pub struct PacerBuilder {
bitrate: f64,
burst_bits: Option<f64>,
queue_limit: usize,
}
impl Default for PacerBuilder {
fn default() -> Self {
Self {
bitrate: DEFAULT_BITRATE,
burst_bits: None,
queue_limit: DEFAULT_QUEUE_LIMIT,
}
}
}
impl PacerBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_target_bitrate(mut self, bits_per_second: f64) -> Self {
self.bitrate = bits_per_second;
self
}
pub fn with_burst_bits(mut self, burst_bits: f64) -> Self {
self.burst_bits = Some(burst_bits);
self
}
pub fn with_queue_limit(mut self, queue_limit: usize) -> Self {
self.queue_limit = queue_limit;
self
}
pub fn build(self) -> PacerInterceptor {
let bucket = match self.burst_bits {
Some(burst_bits) => LeakyBucket::new(self.bitrate).with_burst_bits(burst_bits),
None => LeakyBucket::new(self.bitrate),
};
PacerInterceptor::new(bucket, self.queue_limit)
}
}
pub struct PacerInterceptor {
pacer: LeakyBucket,
queue: VecDeque<TaggedPacket>,
queue_limit: usize,
dropped: u64,
released: VecDeque<TaggedPacket>,
read_queue: VecDeque<TaggedPacket>,
write_queue: VecDeque<TaggedPacket>,
}
impl PacerInterceptor {
fn new(pacer: LeakyBucket, queue_limit: usize) -> Self {
Self {
read_queue: VecDeque::new(),
write_queue: VecDeque::new(),
released: VecDeque::new(),
pacer,
queue: VecDeque::new(),
queue_limit: queue_limit.max(1),
dropped: 0,
}
}
pub fn pacer(&self) -> &LeakyBucket {
&self.pacer
}
pub fn pacer_mut(&mut self) -> &mut LeakyBucket {
&mut self.pacer
}
pub fn queued(&self) -> usize {
self.queue.len()
}
pub fn dropped(&self) -> u64 {
self.dropped
}
fn bits_of(packet: &TaggedPacket) -> f64 {
match &packet.message.packet {
Packet::Rtp(rtp) => (rtp.marshal_size() * 8) as f64,
Packet::Rtcp(_) => 0.0,
}
}
fn next_release(&self) -> Option<Instant> {
let head = self.queue.front()?;
self.pacer.releasable_at(Self::bits_of(head))
}
}
impl Protocol<TaggedPacket, TaggedPacket, ()> for PacerInterceptor {
type Rout = TaggedPacket;
type Wout = TaggedPacket;
type Eout = ();
type Error = Error;
type Time = Instant;
fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
if let Some(Attribute::TargetBitrateChanged { bits_per_second }) =
msg.message.get(&Attribute::TargetBitrateChanged {
bits_per_second: 0.0,
})
{
self.pacer.set_target_bitrate(*bits_per_second);
}
self.read_queue.push_back(msg);
Ok(())
}
fn poll_read(&mut self) -> Option<Self::Rout> {
self.read_queue.pop_front()
}
fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
if matches!(msg.message.packet, Packet::Rtcp(_)) {
self.write_queue.push_back(msg);
return Ok(());
}
self.pacer.refill(msg.now);
if self.queue.len() >= self.queue_limit {
self.dropped += 1;
return Ok(());
}
self.queue.push_back(msg);
Ok(())
}
fn poll_write(&mut self) -> Option<TaggedPacket> {
self.write_queue
.pop_front()
.or_else(|| self.released.pop_front())
}
fn handle_timeout(&mut self, now: Instant) -> Result<(), Error> {
self.pacer.refill(now);
while let Some(head) = self.queue.front() {
let bits = Self::bits_of(head);
if !self.pacer.can_release(bits) {
break;
}
let mut packet = self.queue.pop_front().expect("front just checked");
self.pacer.consume(bits);
packet.now = now;
self.released.push_back(packet);
}
Ok(())
}
fn poll_timeout(&mut self) -> Option<Instant> {
self.next_release()
}
}
impl Interceptor for PacerInterceptor {
fn bind_local_stream(&mut self, _info: &StreamInfo) {}
fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
}