diff --git a/client/Cargo.toml b/client/Cargo.toml index 9ad9448..4ca8d54 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -23,7 +23,7 @@ web-sys = { version = "0.3.77", features = [ "RtcConfiguration", "RtcIceServer", "RtcPeerConnection", - # "RtcSdpType", + "RtcSdpType", "RtcSessionDescription", "RtcSessionDescriptionInit", "Window", diff --git a/client/src/gui.rs b/client/src/gui.rs index 7285959..1d73da2 100644 --- a/client/src/gui.rs +++ b/client/src/gui.rs @@ -14,7 +14,11 @@ use leptos::{ use wasm_bindgen_futures::JsFuture; use web_sys::HtmlAudioElement; -use crate::{media::audio, rtc::offer, signal::start_signalling}; +use crate::{ + media::audio, + rtc::{answer, offer}, + signal::start_signalling, +}; pub fn app() -> impl IntoView { let audio_stream = LocalResource::new(|| audio()); @@ -42,7 +46,12 @@ pub fn app() -> impl IntoView { .fallback(|| button().child("Sad Button")) .build(); let username = signal(String::from("")); - (Show(props), signalling(username), rtc(username.0)) + ( + Show(props), + signalling(username), + rtc_offer(username.0), + rtc_answer(username.0), + ) } fn signalling(username: (ReadSignal, WriteSignal)) -> impl IntoView { @@ -70,16 +79,30 @@ fn signalling(username: (ReadSignal, WriteSignal)) -> impl IntoV (signalling_server_input, signalling_submit_button) } -fn rtc(username: ReadSignal) -> impl IntoView { - let rtc_trigger = move || { +fn rtc_offer(username: ReadSignal) -> impl IntoView { + let offer_trigger = move || { spawn_local(offer(username.get())); }; - let rtc_start_button = button() + let offer_button = button() .on(ev::click, move |event| { event.prevent_default(); - rtc_trigger(); + offer_trigger(); }) .child("RTC Offer"); - rtc_start_button + offer_button +} + +fn rtc_answer(username: ReadSignal) -> impl IntoView { + let answer_trigger = move || { + spawn_local(answer(username.get())); + }; + + let answer_button = button() + .on(ev::click, move |event| { + event.prevent_default(); + answer_trigger(); + }) + .child("RTC Answer"); + answer_button } diff --git a/client/src/lib.rs b/client/src/lib.rs index 07c2648..ad00192 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -2,3 +2,16 @@ pub mod gui; pub mod media; pub mod rtc; pub mod signal; + +pub async fn sleep(timeout: u16) { + let sleep_promise = web_sys::js_sys::Promise::new(&mut |resolve, _| { + web_sys::window() + .unwrap() + .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, timeout as i32) + .unwrap(); + }); + + wasm_bindgen_futures::JsFuture::from(sleep_promise) + .await + .unwrap(); +} diff --git a/client/src/rtc.rs b/client/src/rtc.rs index 84af0f4..1369509 100644 --- a/client/src/rtc.rs +++ b/client/src/rtc.rs @@ -1,14 +1,17 @@ use leptos::logging::log; use wasm_bindgen_futures::JsFuture; use web_sys::{ - RtcConfiguration, RtcIceServer, RtcPeerConnection, RtcSessionDescriptionInit, + RtcConfiguration, RtcIceServer, RtcPeerConnection, RtcSdpType, RtcSessionDescriptionInit, js_sys::{Array, Reflect}, wasm_bindgen::{JsCast, JsValue}, }; -use crate::signal::send_offer; +use crate::{ + signal::{receive_answer, receive_offer, send_answer, send_offer}, + sleep, +}; -pub async fn offer(username: String) { +async fn create_peer_connection_with_configuration() -> RtcPeerConnection { let ice_server_addresses = vec![JsValue::from("stun:stun.l.google.com:19302")] .into_iter() .collect::(); @@ -17,27 +20,89 @@ pub async fn offer(username: String) { let ice_servers = vec![ice_server].into_iter().collect::(); let rtc_configuration = RtcConfiguration::new(); rtc_configuration.set_ice_servers(&ice_servers); - let peer_connection = RtcPeerConnection::new_with_configuration(&rtc_configuration).unwrap(); - let peer_connection_create_offer_promise = peer_connection.create_offer(); - let rtc_session_offer = JsFuture::from(peer_connection_create_offer_promise) - .await - .unwrap(); - log!("{:#?}", rtc_session_offer); - let rtc_session_offer = rtc_session_offer - .as_ref() - .unchecked_ref::(); - log!("{:#?}", rtc_session_offer); - JsFuture::from(peer_connection.set_local_description(rtc_session_offer)) - .await - .unwrap(); - let rtc_session_offer = Reflect::get(&rtc_session_offer, &JsValue::from_str("sdp")) - .unwrap() - .as_string() - .unwrap(); - log!("{}", rtc_session_offer); - let data = rtc_session_offer; - - send_offer(&username, &data).await.unwrap(); + RtcPeerConnection::new_with_configuration(&rtc_configuration).unwrap() } -pub async fn answer() {} +pub async fn offer(username: String) { + let peer_connection = create_peer_connection_with_configuration().await; + let peer_connection_create_offer_promise = peer_connection.create_offer(); + let peer_connection_session_offer = JsFuture::from(peer_connection_create_offer_promise) + .await + .unwrap(); + log!("{:#?}", peer_connection_session_offer); + let peer_connection_session_offer = peer_connection_session_offer + .as_ref() + .unchecked_ref::(); + log!("{:#?}", peer_connection_session_offer); + JsFuture::from(peer_connection.set_local_description(peer_connection_session_offer)) + .await + .unwrap(); + let peer_connection_session_offer = + Reflect::get(&peer_connection_session_offer, &JsValue::from_str("sdp")) + .unwrap() + .as_string() + .unwrap(); + log!("{}", peer_connection_session_offer); + let data = peer_connection_session_offer; + + if let Err(err_val) = send_offer(&username, &data).await { + log!("Error: Send Offer | {}", err_val) + } + for _ in 0..10 { + match receive_answer(&username).await { + Ok(received_answer) => { + log!("{:#?}", received_answer); + let peer_connection_session_answer = + RtcSessionDescriptionInit::new(RtcSdpType::Answer); + peer_connection_session_answer.set_sdp(received_answer.get_data().as_str()); + JsFuture::from( + peer_connection.set_remote_description(&peer_connection_session_answer), + ) + .await + .unwrap(); + break; + } + Err(err_val) => log!("Error: Receive Answer | {}", err_val), + } + sleep(1000).await; + } +} + +pub async fn answer(username: String) { + for _ in 0..10 { + match receive_offer(&username).await { + Ok(offer) => { + let peer_connection = create_peer_connection_with_configuration().await; + let peer_connection_session_offer = + RtcSessionDescriptionInit::new(RtcSdpType::Offer); + peer_connection_session_offer.set_sdp(offer.get_data().as_str()); + JsFuture::from( + peer_connection.set_remote_description(&peer_connection_session_offer), + ) + .await + .unwrap(); + let peer_connection_create_answer_promise = peer_connection.create_answer(); + let peer_connection_answer = JsFuture::from(peer_connection_create_answer_promise) + .await + .unwrap(); + let peer_connection_answer = peer_connection_answer + .as_ref() + .unchecked_ref::(); + JsFuture::from(peer_connection.set_local_description(peer_connection_answer)) + .await + .unwrap(); + let session_answer = Reflect::get(&peer_connection_answer, &JsValue::from("sdp")) + .unwrap() + .as_string() + .unwrap(); + log!("{}", session_answer); + let data = session_answer; + + send_answer(&username, &data).await.unwrap(); + break; + } + Err(err_val) => log!("Error: Receive Offer | {}", err_val), + } + sleep(1000).await; + } +}