use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, MutexGuard};
#[derive(Clone)]
pub struct CatalogProducer {
pub hang_track: moq_lite::TrackProducer,
pub msf_track: moq_lite::TrackProducer,
current: Arc<Mutex<hang::Catalog>>,
}
impl CatalogProducer {
pub fn new(broadcast: &mut moq_lite::BroadcastProducer) -> Result<Self, moq_lite::Error> {
Self::with_catalog(broadcast, hang::Catalog::default())
}
pub fn with_catalog(
broadcast: &mut moq_lite::BroadcastProducer,
catalog: hang::Catalog,
) -> Result<Self, moq_lite::Error> {
let hang_track = broadcast.create_track(hang::Catalog::default_track())?;
let msf_track = broadcast.create_track(moq_lite::Track {
name: moq_msf::DEFAULT_NAME.to_string(),
priority: 100,
})?;
Ok(Self {
hang_track,
msf_track,
current: Arc::new(Mutex::new(catalog)),
})
}
pub fn lock(&mut self) -> CatalogGuard<'_> {
CatalogGuard {
catalog: self.current.lock().unwrap(),
hang_track: &mut self.hang_track,
msf_track: &mut self.msf_track,
updated: false,
}
}
pub fn consume(&self) -> hang::CatalogConsumer {
hang::CatalogConsumer::new(self.hang_track.consume())
}
pub fn finish(&mut self) -> Result<(), moq_lite::Error> {
self.hang_track.finish()?;
self.msf_track.finish()?;
Ok(())
}
}
pub struct CatalogGuard<'a> {
catalog: MutexGuard<'a, hang::Catalog>,
hang_track: &'a mut moq_lite::TrackProducer,
msf_track: &'a mut moq_lite::TrackProducer,
updated: bool,
}
impl<'a> Deref for CatalogGuard<'a> {
type Target = hang::Catalog;
fn deref(&self) -> &Self::Target {
&self.catalog
}
}
impl<'a> DerefMut for CatalogGuard<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.updated = true;
&mut self.catalog
}
}
impl Drop for CatalogGuard<'_> {
fn drop(&mut self) {
if !self.updated {
return;
}
let Ok(mut group) = self.hang_track.append_group() else {
return;
};
let frame = self.catalog.to_string().expect("invalid catalog");
let _ = group.write_frame(frame);
let _ = group.finish();
crate::msf::publish(&self.catalog, self.msf_track);
}
}