use super::track_local_static_rtp::TrackLocalStaticRTP;
use super::*;
use crate::error::flatten_errs;
use crate::track::RTP_OUTBOUND_MTU;
use media::Sample;
use tokio::sync::Mutex;
#[derive(Debug, Clone)]
struct TrackLocalStaticSampleInternal {
packetizer: Option<Box<dyn rtp::packetizer::Packetizer + Send + Sync>>,
sequencer: Option<Box<dyn rtp::sequence::Sequencer + Send + Sync>>,
clock_rate: f64,
}
#[derive(Debug)]
pub struct TrackLocalStaticSample {
rtp_track: TrackLocalStaticRTP,
internal: Mutex<TrackLocalStaticSampleInternal>,
}
impl TrackLocalStaticSample {
pub fn new(codec: RTCRtpCodecCapability, id: String, stream_id: String) -> Self {
let rtp_track = TrackLocalStaticRTP::new(codec, id, stream_id);
TrackLocalStaticSample {
rtp_track,
internal: Mutex::new(TrackLocalStaticSampleInternal {
packetizer: None,
sequencer: None,
clock_rate: 0.0f64,
}),
}
}
pub fn codec(&self) -> RTCRtpCodecCapability {
self.rtp_track.codec()
}
pub async fn write_sample(&self, sample: &Sample) -> Result<()> {
let mut internal = self.internal.lock().await;
if internal.packetizer.is_none() || internal.sequencer.is_none() {
return Ok(());
}
if let Some(sequencer) = &internal.sequencer {
for _ in 0..sample.prev_dropped_packets {
sequencer.next_sequence_number();
}
}
let clock_rate = internal.clock_rate;
let packets = if let Some(packetizer) = &mut internal.packetizer {
let samples = (sample.duration.as_secs_f64() * clock_rate) as u32;
if sample.prev_dropped_packets > 0 {
packetizer.skip_samples(samples * sample.prev_dropped_packets as u32);
}
packetizer.packetize(&sample.data, samples).await?
} else {
vec![]
};
let mut write_errs = vec![];
for p in packets {
if let Err(err) = self.rtp_track.write_rtp(&p).await {
write_errs.push(err);
}
}
flatten_errs(write_errs)
}
}
#[async_trait]
impl TrackLocal for TrackLocalStaticSample {
async fn bind(&self, t: &TrackLocalContext) -> Result<RTCRtpCodecParameters> {
let codec = self.rtp_track.bind(t).await?;
let mut internal = self.internal.lock().await;
if internal.packetizer.is_some() {
return Ok(codec);
}
let payloader = codec.capability.payloader_for_codec()?;
let sequencer: Box<dyn rtp::sequence::Sequencer + Send + Sync> =
Box::new(rtp::sequence::new_random_sequencer());
internal.packetizer = Some(Box::new(rtp::packetizer::new_packetizer(
RTP_OUTBOUND_MTU,
0, 0, payloader,
sequencer.clone(),
codec.capability.clock_rate,
)));
internal.sequencer = Some(sequencer);
internal.clock_rate = codec.capability.clock_rate as f64;
Ok(codec)
}
async fn unbind(&self, t: &TrackLocalContext) -> Result<()> {
self.rtp_track.unbind(t).await
}
fn id(&self) -> &str {
self.rtp_track.id()
}
fn stream_id(&self) -> &str {
self.rtp_track.stream_id()
}
fn kind(&self) -> RTPCodecType {
self.rtp_track.kind()
}
fn as_any(&self) -> &dyn Any {
self
}
}