diff options
author | metamuffin <metamuffin@disroot.org> | 2022-12-09 21:28:43 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-12-09 21:28:43 +0100 |
commit | 1f3fd177a6ea526ef6104ea9148b8a473c9aa701 (patch) | |
tree | 45db8efa0dfb82145d239bedfb636f771f356e90 | |
parent | 9cd8e549796bdc6b4ed574c2f4afd7ed2f8338cd (diff) | |
download | keks-meet-1f3fd177a6ea526ef6104ea9148b8a473c9aa701.tar keks-meet-1f3fd177a6ea526ef6104ea9148b8a473c9aa701.tar.bz2 keks-meet-1f3fd177a6ea526ef6104ea9148b8a473c9aa701.tar.zst |
add binary package to export stream tracks
-rw-r--r-- | Cargo.lock | 19 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | client-native-export/Cargo.toml | 15 | ||||
-rw-r--r-- | client-native-export/src/main.rs | 155 |
4 files changed, 190 insertions, 0 deletions
@@ -171,6 +171,12 @@ dependencies = [ ] [[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] name = "arboard" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -666,6 +672,19 @@ dependencies = [ ] [[package]] +name = "client-native-export" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "clap", + "client-native-lib", + "env_logger", + "log", + "tokio", +] + +[[package]] name = "client-native-lib" version = "0.1.0" dependencies = [ @@ -4,4 +4,5 @@ members = [ "client-native-rift", "client-native-lib", "client-native-gui", + "client-native-export", ] diff --git a/client-native-export/Cargo.toml b/client-native-export/Cargo.toml new file mode 100644 index 0000000..8a5ef62 --- /dev/null +++ b/client-native-export/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "client-native-export" +version = "0.1.0" +edition = "2021" + +[dependencies] +client-native-lib = { path = "../client-native-lib" } + +clap = { version = "3.2.21", features = ["derive"] } +env_logger = "0.8" +log = "0.4" + +tokio = { version = "1.21", features = ["full"] } +bytes = "1.2.1" +anyhow = "1.0.66" diff --git a/client-native-export/src/main.rs b/client-native-export/src/main.rs new file mode 100644 index 0000000..f4dffd6 --- /dev/null +++ b/client-native-export/src/main.rs @@ -0,0 +1,155 @@ +/* + This file is part of keks-meet (https://codeberg.org/metamuffin/keks-meet) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2022 metamuffin <metamuffin@disroot.org> +*/ +#![feature(box_syntax)] + +use clap::Parser; +use client_native_lib::{ + instance::Instance, + peer::{Peer, TransportChannel}, + protocol::ProvideInfo, + webrtc::{ + rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication, + rtp::{codecs::h264::H264Packet, packetizer::Depacketizer}, + track::track_remote::TrackRemote, + }, + Config, DynFut, EventHandler, +}; +use log::{debug, error, info, warn}; +use std::{ + io::{stdout, Write}, + sync::Arc, + time::Duration, +}; + +fn main() { + env_logger::builder() + .filter_module("rift", log::LevelFilter::Info) + .filter_module("client_native_lib", log::LevelFilter::Info) + .parse_env("LOG") + .init(); + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(run()) +} + +#[derive(Parser, Clone)] +pub struct Args { + /// keks-meet server used for establishing p2p connection + #[clap(long, default_value = "wss://meet.metamuffin.org")] + signaling_uri: String, + /// username for the `identify` packet + #[clap(short, long, default_value = "guest")] + username: String, + /// pre-shared secret (aka. room name) + #[clap(short, long)] + secret: String, +} + +async fn run() { + let args = Args::parse(); + + let inst = Instance::new( + Config { + secret: args.secret.clone(), + signaling_uri: args.signaling_uri.clone(), + username: args.username.clone(), + }, + Arc::new(Handler { + _args: Arc::new(args.clone()), + }), + ) + .await; + + inst.spawn_ping().await; + inst.receive_loop().await; + + tokio::signal::ctrl_c().await.unwrap(); + error!("interrupt received, exiting"); +} + +#[derive(Clone)] +struct Handler { + _args: Arc<Args>, +} + +impl EventHandler for Handler { + fn peer_join(&self, _peer: Arc<Peer>) -> client_native_lib::DynFut<()> { + Box::pin(async move {}) + } + + fn peer_leave(&self, _peer: Arc<Peer>) -> client_native_lib::DynFut<()> { + Box::pin(async move {}) + } + + fn resource_added( + &self, + peer: Arc<Peer>, + info: client_native_lib::protocol::ProvideInfo, + ) -> DynFut<()> { + let id = info.id.clone(); + Box::pin(async move { + if info.kind == "track" { + peer.request_resource(id).await; + } + }) + } + fn resource_removed(&self, _peer: Arc<Peer>, _id: String) -> DynFut<()> { + Box::pin(async {}) + } + + fn resource_connected( + &self, + peer: Arc<Peer>, + _resource: &ProvideInfo, + channel: TransportChannel, + ) -> client_native_lib::DynFut<()> { + // let resource = resource.clone(); + // let s = self.clone(); + let peer = Arc::downgrade(&peer); + Box::pin(async move { + match channel { + TransportChannel::Track(track) => { + let media_ssrc = track.ssrc(); + let peer = peer.clone(); + tokio::spawn(async move { + loop { + tokio::time::sleep(Duration::from_secs(3)).await; + let peer = peer.upgrade().unwrap(); + let r = peer + .peer_connection + .write_rtcp(&[Box::new(PictureLossIndication { + sender_ssrc: 0, + media_ssrc, + })]) + .await; + if r.is_err() { + break; + } + debug!("trigger keyframe"); + } + }); + + export(track).await.unwrap(); + } + TransportChannel::DataChannel(_) => warn!("wrong type"), + } + }) + } +} + +async fn export(track: Arc<TrackRemote>) -> anyhow::Result<()> { + let mut cached_packet = H264Packet::default(); + info!("depacketizing rtp to stdout"); + loop { + let (packet, _) = track.read_rtp().await?; + if !packet.payload.is_empty() { + let raw_payload = cached_packet.depacketize(&packet.payload)?; + stdout().write_all(&raw_payload)?; + } + } +} |