summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock19
-rw-r--r--Cargo.toml1
-rw-r--r--client-native-export/Cargo.toml15
-rw-r--r--client-native-export/src/main.rs155
4 files changed, 190 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 45427dd..82c70d1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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 = [
diff --git a/Cargo.toml b/Cargo.toml
index 7d04604..020ff37 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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)?;
+ }
+ }
+}