use super::sender_stream::SenderStream;
use crate::Interceptor;
use crate::stream_info::StreamInfo;
use crate::{AttributedPacket, Packet, TaggedPacket};
use rtcp::header::PacketType;
use sansio::Protocol;
use shared::TransportContext;
use shared::error::Error;
use std::collections::{HashMap, VecDeque};
use std::time::{Duration, Instant};
pub struct SenderReportBuilder {
interval: Duration,
use_latest_packet: bool,
}
impl Default for SenderReportBuilder {
fn default() -> Self {
Self {
interval: Duration::from_secs(1),
use_latest_packet: false,
}
}
}
impl SenderReportBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_interval(mut self, interval: Duration) -> Self {
self.interval = interval;
self
}
pub fn with_use_latest_packet(mut self) -> Self {
self.use_latest_packet = true;
self
}
pub fn build(self) -> SenderReportInterceptor {
SenderReportInterceptor::new(self.interval, self.use_latest_packet)
}
}
pub struct SenderReportInterceptor {
interval: Duration,
next_timeout: Option<Instant>,
use_latest_packet: bool,
streams: HashMap<u32, SenderStream>,
read_queue: VecDeque<TaggedPacket>,
write_queue: VecDeque<TaggedPacket>,
}
impl SenderReportInterceptor {
fn new(interval: Duration, use_latest_packet: bool) -> Self {
Self {
interval,
next_timeout: None,
use_latest_packet,
streams: HashMap::new(),
read_queue: VecDeque::new(),
write_queue: VecDeque::new(),
}
}
fn should_filter(packet_type: PacketType) -> bool {
packet_type == PacketType::ReceiverReport
|| (packet_type == PacketType::TransportSpecificFeedback)
}
}
impl Protocol<TaggedPacket, TaggedPacket, ()> for SenderReportInterceptor {
type Rout = TaggedPacket;
type Wout = TaggedPacket;
type Eout = ();
type Error = Error;
type Time = Instant;
fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
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 let Packet::Rtp(rtp_packet) = &msg.message.packet
&& let Some(stream) = self.streams.get_mut(&rtp_packet.header.ssrc)
{
stream.process_rtp(msg.now, rtp_packet);
if self.next_timeout.is_none() {
self.next_timeout = Some(msg.now + self.interval);
}
}
self.write_queue.push_back(msg);
Ok(())
}
fn poll_write(&mut self) -> Option<TaggedPacket> {
if let Some(pkt) = self.write_queue.pop_front() {
return Some(pkt);
}
None
}
fn handle_timeout(&mut self, now: Instant) -> Result<(), Error> {
if let Some(next_timeout) = self.next_timeout
&& now >= next_timeout
{
self.next_timeout = Some(now + self.interval);
for stream in self.streams.values_mut() {
if let Some(rr) = stream.generate_report(now) {
self.write_queue.push_back(TaggedPacket {
now,
transport: TransportContext::default(),
message: AttributedPacket::new(Packet::Rtcp(vec![Box::new(rr)])),
});
}
}
}
Ok(())
}
fn poll_timeout(&mut self) -> Option<Instant> {
self.next_timeout
}
}
impl Interceptor for SenderReportInterceptor {
fn bind_local_stream(&mut self, info: &StreamInfo) {
let stream = SenderStream::new(info.ssrc, info.clock_rate, self.use_latest_packet);
self.streams.insert(info.ssrc, stream);
}
fn unbind_local_stream(&mut self, info: &StreamInfo) {
self.streams.remove(&info.ssrc);
}
fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
}