use bytes::Bytes;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
moq_native::Log::new(tracing::Level::DEBUG).init();
let origin = moq_lite::Origin::produce();
tokio::select! {
res = run_session(origin.consume()) => res,
res = run_broadcast(origin) => res,
}
}
async fn run_session(origin: moq_lite::OriginConsumer) -> anyhow::Result<()> {
let client = moq_native::ClientConfig::default().init()?;
let url = url::Url::parse("https://cdn.moq.dev/anon/video-example").unwrap();
let session = client.with_publish(origin).connect(url).await?;
session.closed().await.map_err(Into::into)
}
fn create_track(broadcast: &mut moq_lite::BroadcastProducer) -> anyhow::Result<moq_lite::TrackProducer> {
let video_track = moq_lite::Track {
name: "video".to_string(),
priority: 1, };
let video_config = hang::catalog::VideoConfig {
codec: hang::catalog::H264 {
profile: 0x4D, constraints: 0,
level: 0x28, inline: true, }
.into(),
description: None,
coded_width: Some(1920),
coded_height: Some(1080),
bitrate: Some(5_000_000), framerate: Some(30.0),
display_ratio_width: None,
display_ratio_height: None,
optimize_for_latency: None,
container: hang::catalog::Container::Legacy,
jitter: None,
};
let mut renditions = std::collections::BTreeMap::new();
renditions.insert(video_track.name.clone(), video_config);
let catalog = hang::catalog::Catalog {
video: hang::catalog::Video {
renditions,
display: None,
rotation: None,
flip: None,
},
..Default::default()
};
let mut catalog_track = broadcast.create_track(hang::Catalog::default_track())?;
let mut group = catalog_track.append_group()?;
group.write_frame(catalog.to_string()?)?;
group.finish()?;
let track = broadcast.create_track(video_track)?;
Ok(track)
}
async fn run_broadcast(origin: moq_lite::OriginProducer) -> anyhow::Result<()> {
let mut broadcast = moq_lite::Broadcast::produce();
let track = create_track(&mut broadcast)?;
origin.publish_broadcast("", broadcast.consume());
let mut producer = hang::container::OrderedProducer::new(track);
producer.keyframe()?;
let frame = hang::container::Frame {
timestamp: hang::container::Timestamp::from_secs(1).unwrap(),
payload: Bytes::from_static(b"keyframe NAL data").into(),
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let frame = hang::container::Frame {
timestamp: hang::container::Timestamp::from_secs(2).unwrap(),
payload: Bytes::from_static(b"delta NAL data").into(),
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
producer.keyframe()?;
let frame = hang::container::Frame {
timestamp: hang::container::Timestamp::from_secs(3).unwrap(),
payload: Bytes::from_static(b"keyframe NAL data").into(),
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
Ok(())
}