use anyhow::Context;
use bytes::Bytes;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
moq_native::Log::new(tracing::Level::DEBUG).init()?;
let origin = moq_net::Origin::random().produce();
tokio::select! {
res = run_session(origin.clone()) => res,
res = run_broadcast(origin) => res,
}
}
async fn run_session(origin: moq_net::origin::Producer) -> anyhow::Result<()> {
let client = moq_native::ClientConfig::default().init()?;
let url = url::Url::parse("https://cdn.moq.dev/anon/video-example").unwrap();
let reconnect = client.with_publisher(&origin).reconnect(url);
Ok(reconnect.closed().await?)
}
fn create_track(broadcast: &mut moq_net::broadcast::Producer) -> anyhow::Result<moq_net::track::Producer> {
let video_track = "video";
let mut video_config = hang::catalog::VideoConfig::new(hang::catalog::H264 {
profile: 0x4D, constraints: 0,
level: 0x28, inline: true, });
video_config.coded_width = Some(1920);
video_config.coded_height = Some(1080);
video_config.bitrate = Some(5_000_000); video_config.framerate = Some(30.0);
video_config.container = hang::catalog::Container::Legacy;
let mut catalog = hang::catalog::Catalog::default();
catalog.video.insert(video_track, video_config)?;
let mut catalog_track = broadcast.create_track(hang::Catalog::DEFAULT_NAME, hang::Catalog::default_track_info())?;
let mut group = catalog_track.append_group()?;
group.write_frame(moq_net::Timestamp::now(), catalog.to_json()?)?;
group.finish()?;
let track = broadcast.create_track(video_track, hang::container::track_info())?;
Ok(track)
}
async fn run_broadcast(origin: moq_net::origin::Producer) -> anyhow::Result<()> {
let mut broadcast = origin
.create_broadcast("", moq_net::broadcast::Route::new().with_announce(true))
.context("failed to create broadcast")?;
let track = create_track(&mut broadcast)?;
let mut producer = moq_mux::container::Producer::new(track, moq_mux::catalog::hang::Container::Legacy);
let frame = moq_mux::container::Frame {
timestamp: moq_net::Timestamp::from_secs(1).unwrap(),
payload: Bytes::from_static(b"keyframe NAL data"),
keyframe: true,
duration: None,
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let frame = moq_mux::container::Frame {
timestamp: moq_net::Timestamp::from_secs(2).unwrap(),
payload: Bytes::from_static(b"delta NAL data"),
keyframe: false,
duration: None,
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let frame = moq_mux::container::Frame {
timestamp: moq_net::Timestamp::from_secs(3).unwrap(),
payload: Bytes::from_static(b"keyframe NAL data"),
keyframe: true,
duration: None,
};
producer.write(frame)?;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
Ok(())
}