use std::sync::Arc;
use cxx::SharedPtr;
use webrtc_sys::packet_trailer::ffi as sys_pt;
use crate::{
peer_connection_factory::PeerConnectionFactory, rtp_receiver::RtpReceiver,
rtp_sender::RtpSender,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PublishTimingStage {
EncoderUpload,
EncoderOutput,
WebrtcPacketize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SubscribeTimingStage {
WebrtcReceive,
DecoderUpload,
DecoderOutput,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PublishTimingEvent {
pub stage: PublishTimingStage,
pub timestamp_us: u64,
pub capture_timestamp_us: u64,
pub frame_id: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubscribeTimingEvent {
pub stage: SubscribeTimingStage,
pub timestamp_us: u64,
pub capture_timestamp_us: u64,
pub frame_id: Option<u32>,
}
pub type PublishTimingObserver = Arc<dyn Fn(PublishTimingEvent) + Send + Sync + 'static>;
pub type SubscribeTimingObserver = Arc<dyn Fn(SubscribeTimingEvent) + Send + Sync + 'static>;
impl From<sys_pt::VideoPublishTimingStage> for PublishTimingStage {
fn from(stage: sys_pt::VideoPublishTimingStage) -> Self {
match stage {
sys_pt::VideoPublishTimingStage::EncoderUpload => Self::EncoderUpload,
sys_pt::VideoPublishTimingStage::EncoderOutput => Self::EncoderOutput,
sys_pt::VideoPublishTimingStage::WebrtcPacketize => Self::WebrtcPacketize,
_ => Self::WebrtcPacketize,
}
}
}
impl From<sys_pt::VideoPublishTimingEvent> for PublishTimingEvent {
fn from(event: sys_pt::VideoPublishTimingEvent) -> Self {
Self {
stage: event.stage.into(),
timestamp_us: event.timestamp_us,
capture_timestamp_us: event.capture_timestamp_us,
frame_id: (event.frame_id != 0).then_some(event.frame_id),
}
}
}
impl From<sys_pt::VideoSubscribeTimingStage> for SubscribeTimingStage {
fn from(stage: sys_pt::VideoSubscribeTimingStage) -> Self {
match stage {
sys_pt::VideoSubscribeTimingStage::WebrtcReceive => Self::WebrtcReceive,
sys_pt::VideoSubscribeTimingStage::DecoderUpload => Self::DecoderUpload,
sys_pt::VideoSubscribeTimingStage::DecoderOutput => Self::DecoderOutput,
_ => Self::DecoderOutput,
}
}
}
impl From<sys_pt::VideoSubscribeTimingEvent> for SubscribeTimingEvent {
fn from(event: sys_pt::VideoSubscribeTimingEvent) -> Self {
Self {
stage: event.stage.into(),
timestamp_us: event.timestamp_us,
capture_timestamp_us: event.capture_timestamp_us,
frame_id: (event.frame_id != 0).then_some(event.frame_id),
}
}
}
#[derive(Clone)]
pub struct PacketTrailerHandler {
sys_handle: SharedPtr<sys_pt::PacketTrailerHandler>,
}
impl PacketTrailerHandler {
pub fn set_enabled(&self, enabled: bool) {
self.sys_handle.set_enabled(enabled);
}
pub fn enabled(&self) -> bool {
self.sys_handle.enabled()
}
pub fn lookup_frame_metadata(&self, rtp_timestamp: u32) -> Option<(u64, u32)> {
let ts = self.sys_handle.lookup_timestamp(rtp_timestamp);
if ts != u64::MAX {
let frame_id = self.sys_handle.last_lookup_frame_id();
Some((ts, frame_id))
} else {
None
}
}
pub fn store_frame_metadata(
&self,
capture_timestamp_us: i64,
user_timestamp: u64,
frame_id: u32,
) {
self.sys_handle.store_frame_metadata(capture_timestamp_us, user_timestamp, frame_id);
}
pub(crate) fn sys_handle(&self) -> SharedPtr<sys_pt::PacketTrailerHandler> {
self.sys_handle.clone()
}
pub fn set_publish_timing_observer(&self, observer: Option<PublishTimingObserver>) {
if let Some(observer) = observer {
self.sys_handle.set_publish_timing_observer(Box::new(
webrtc_sys::packet_trailer::VideoPublishTimingObserverWrapper::new(Box::new(
move |event| observer(event.into()),
)),
));
} else {
self.sys_handle.clear_publish_timing_observer();
}
}
pub fn set_subscribe_timing_observer(&self, observer: Option<SubscribeTimingObserver>) {
if let Some(observer) = observer {
self.sys_handle.set_subscribe_timing_observer(Box::new(
webrtc_sys::packet_trailer::VideoSubscribeTimingObserverWrapper::new(Box::new(
move |event| observer(event.into()),
)),
));
} else {
self.sys_handle.clear_subscribe_timing_observer();
}
}
pub(crate) fn emit_subscribe_timing(
&self,
stage: SubscribeTimingStage,
capture_timestamp_us: u64,
frame_id: u32,
) {
let stage = match stage {
SubscribeTimingStage::WebrtcReceive => sys_pt::VideoSubscribeTimingStage::WebrtcReceive,
SubscribeTimingStage::DecoderUpload => sys_pt::VideoSubscribeTimingStage::DecoderUpload,
SubscribeTimingStage::DecoderOutput => sys_pt::VideoSubscribeTimingStage::DecoderOutput,
};
self.sys_handle.emit_subscribe_timing(stage, capture_timestamp_us, frame_id);
}
}
pub fn create_sender_handler(
peer_factory: &PeerConnectionFactory,
sender: &RtpSender,
) -> PacketTrailerHandler {
PacketTrailerHandler {
sys_handle: sys_pt::new_packet_trailer_sender(
peer_factory.handle.sys_handle.clone(),
sender.handle.sys_handle.clone(),
),
}
}
pub fn create_receiver_handler(
peer_factory: &PeerConnectionFactory,
receiver: &RtpReceiver,
) -> PacketTrailerHandler {
PacketTrailerHandler {
sys_handle: sys_pt::new_packet_trailer_receiver(
peer_factory.handle.sys_handle.clone(),
receiver.handle.sys_handle.clone(),
),
}
}