use actr_protocol::{ActorResult, ActrId};
use dashmap::DashMap;
use futures_util::future::BoxFuture;
use std::sync::Arc;
use actr_framework::MediaSample;
pub type MediaTrackCallback =
Arc<dyn Fn(MediaSample, ActrId) -> BoxFuture<'static, ActorResult<()>> + Send + Sync>;
pub struct MediaFrameRegistry {
callbacks: DashMap<String, MediaTrackCallback>,
}
impl Default for MediaFrameRegistry {
fn default() -> Self {
Self::new()
}
}
impl MediaFrameRegistry {
pub fn new() -> Self {
Self {
callbacks: DashMap::new(),
}
}
pub fn register(&self, track_id: String, callback: MediaTrackCallback) {
self.callbacks.insert(track_id.clone(), callback);
tracing::info!("🎬 Registered MediaTrack: {}", track_id);
}
pub fn unregister(&self, track_id: &str) {
self.callbacks.remove(track_id);
tracing::info!("🚫 Unregistered MediaTrack: {}", track_id);
}
pub async fn dispatch(&self, track_id: &str, sample: MediaSample, sender_id: ActrId) {
let start = std::time::Instant::now();
if let Some(callback) = self.callbacks.get(track_id) {
let callback = callback.clone();
tokio::spawn(async move {
if let Err(e) = callback(sample, sender_id).await {
tracing::error!("❌ MediaTrack callback error: {:?}", e);
}
});
tracing::debug!("🎬 Dispatched media sample in {:?}", start.elapsed());
} else {
tracing::warn!("⚠️ No callback registered for track: {}", track_id);
}
}
pub fn active_tracks(&self) -> usize {
self.callbacks.len()
}
}