use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::debug;
use crate::api::client::transport::MediaSyncInfo;
use crate::api::common::error::MediaTransportError;
use crate::packet::rtcp::NtpTimestamp;
pub async fn enable_media_sync(
media_sync_enabled: &Arc<std::sync::atomic::AtomicBool>,
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
clock_rate: u32,
) -> Result<bool, MediaTransportError> {
if media_sync_enabled.load(std::sync::atomic::Ordering::SeqCst) {
return Ok(true);
}
let mut sync_guard = media_sync.write().await;
if sync_guard.is_none() {
*sync_guard = Some(crate::sync::MediaSync::new());
}
media_sync_enabled.store(true, std::sync::atomic::Ordering::SeqCst);
if let Some(sync) = &mut *sync_guard {
sync.register_stream(ssrc, clock_rate);
}
Ok(true)
}
pub fn is_media_sync_enabled(media_sync_enabled: &Arc<std::sync::atomic::AtomicBool>) -> bool {
media_sync_enabled.load(std::sync::atomic::Ordering::SeqCst)
}
pub async fn register_sync_stream(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
clock_rate: u32,
) -> Result<(), MediaTransportError> {
let mut sync_guard = media_sync.write().await;
if let Some(sync) = &mut *sync_guard {
sync.register_stream(ssrc, clock_rate);
debug!(
"Registered sync stream: SSRC={:08x}, clock_rate={}",
ssrc, clock_rate
);
Ok(())
} else {
Err(MediaTransportError::ConfigError(
"Media synchronization context not initialized".to_string(),
))
}
}
pub async fn set_sync_reference_stream(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
) -> Result<(), MediaTransportError> {
let mut sync_guard = media_sync.write().await;
if let Some(sync) = &mut *sync_guard {
sync.set_reference_stream(ssrc);
debug!("Set sync reference stream: SSRC={:08x}", ssrc);
Ok(())
} else {
Err(MediaTransportError::ConfigError(
"Media synchronization context not initialized".to_string(),
))
}
}
pub async fn get_sync_info(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
) -> Result<Option<MediaSyncInfo>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let streams = sync.get_streams();
if let Some(stream_data) = streams.get(&ssrc) {
let sync_info = MediaSyncInfo {
ssrc: stream_data.ssrc,
clock_rate: stream_data.clock_rate,
last_ntp: stream_data.last_ntp,
last_rtp: stream_data.last_rtp,
clock_drift_ppm: stream_data.clock_drift_ppm,
};
debug!(
"Retrieved sync info for SSRC={:08x}: drift={:.2} PPM",
ssrc, sync_info.clock_drift_ppm
);
Ok(Some(sync_info))
} else {
debug!("No sync info found for SSRC={:08x}", ssrc);
Ok(None)
}
} else {
Ok(None)
}
}
pub async fn get_all_sync_info(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
) -> Result<HashMap<u32, MediaSyncInfo>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let mut result = HashMap::new();
for (ssrc, stream_data) in sync.get_streams() {
let sync_info = MediaSyncInfo {
ssrc: *ssrc,
clock_rate: stream_data.clock_rate,
last_ntp: stream_data.last_ntp,
last_rtp: stream_data.last_rtp,
clock_drift_ppm: stream_data.clock_drift_ppm,
};
result.insert(*ssrc, sync_info);
}
debug!(
"Retrieved sync info for {} registered streams",
result.len()
);
Ok(result)
} else {
Ok(HashMap::new())
}
}
pub async fn convert_timestamp(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
from_ssrc: u32,
to_ssrc: u32,
rtp_ts: u32,
) -> Result<Option<u32>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let result = sync.convert_timestamp(from_ssrc, to_ssrc, rtp_ts);
if result.is_some() {
debug!(
"Converted timestamp {} from SSRC={:08x} to SSRC={:08x}: result={:?}",
rtp_ts, from_ssrc, to_ssrc, result
);
} else {
debug!("Failed to convert timestamp {} from SSRC={:08x} to SSRC={:08x} - insufficient sync data",
rtp_ts, from_ssrc, to_ssrc);
}
Ok(result)
} else {
Ok(None)
}
}
pub async fn rtp_to_ntp(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
rtp_ts: u32,
) -> Result<Option<NtpTimestamp>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let result = sync.rtp_to_ntp(ssrc, rtp_ts);
debug!(
"Converted RTP timestamp {} to NTP for SSRC={:08x}: success={}",
rtp_ts,
ssrc,
result.is_some()
);
Ok(result)
} else {
Ok(None)
}
}
pub async fn ntp_to_rtp(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
ntp: NtpTimestamp,
) -> Result<Option<u32>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let result = sync.ntp_to_rtp(ssrc, ntp);
debug!(
"Converted NTP timestamp to RTP for SSRC={:08x}: success={}",
ssrc,
result.is_some()
);
Ok(result)
} else {
Ok(None)
}
}
pub async fn get_clock_drift_ppm(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc: u32,
) -> Result<Option<f64>, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let drift = sync.get_clock_drift_ppm(ssrc);
if let Some(drift_val) = drift {
debug!("Clock drift for SSRC={:08x}: {:.2} PPM", ssrc, drift_val);
}
Ok(drift)
} else {
Ok(None)
}
}
pub async fn are_streams_synchronized(
media_sync: &Arc<RwLock<Option<crate::sync::MediaSync>>>,
ssrc1: u32,
ssrc2: u32,
tolerance_ms: f64,
) -> Result<bool, MediaTransportError> {
let sync_guard = media_sync.read().await;
if let Some(sync) = sync_guard.as_ref() {
let synchronized = sync.are_synchronized(ssrc1, ssrc2, tolerance_ms);
debug!(
"Streams synchronized check: SSRC1={:08x}, SSRC2={:08x}, tolerance={}ms, result={}",
ssrc1, ssrc2, tolerance_ms, synchronized
);
Ok(synchronized)
} else {
Ok(false)
}
}