feat: ✨ audio communication through webrtc
This commit is contained in:
parent
87f7d0763f
commit
52615c3d27
4 changed files with 70 additions and 5 deletions
|
@ -5,17 +5,18 @@ use leptos::{
|
||||||
prelude::{OnAttribute, Read, Show, ShowProps, ToChildren},
|
prelude::{OnAttribute, Read, Show, ShowProps, ToChildren},
|
||||||
server::LocalResource,
|
server::LocalResource,
|
||||||
};
|
};
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::{JsFuture, spawn_local};
|
||||||
|
use web_sys::{HtmlAudioElement, MediaStreamTrack};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
media::audio,
|
media,
|
||||||
signal::{send_auth, wait_until_communication_is_ready},
|
signal::{send_auth, wait_until_communication_is_ready},
|
||||||
sleep,
|
sleep,
|
||||||
webrtc::WebRTC,
|
webrtc::WebRTC,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn app() -> impl IntoView {
|
pub fn app() -> impl IntoView {
|
||||||
let audio_stream = LocalResource::new(|| audio());
|
let audio_stream = LocalResource::new(|| media::audio());
|
||||||
let wait_until_communication_is_ready =
|
let wait_until_communication_is_ready =
|
||||||
LocalResource::new(|| wait_until_communication_is_ready());
|
LocalResource::new(|| wait_until_communication_is_ready());
|
||||||
|
|
||||||
|
@ -30,8 +31,12 @@ pub fn app() -> impl IntoView {
|
||||||
let webrtc = WebRTC::new(Some(audio_stream), None, None).unwrap();
|
let webrtc = WebRTC::new(Some(audio_stream), None, None).unwrap();
|
||||||
let webrtc_state = webrtc.clone();
|
let webrtc_state = webrtc.clone();
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
|
let mut webrtc_status = webrtc_state.get_status();
|
||||||
loop {
|
loop {
|
||||||
log!("{:#?}", webrtc_state.get_status());
|
if webrtc_status != webrtc_state.get_status() {
|
||||||
|
webrtc_status = webrtc_state.get_status();
|
||||||
|
log!("{:#?}", webrtc_status);
|
||||||
|
}
|
||||||
sleep(1000).await;
|
sleep(1000).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -39,11 +44,13 @@ pub fn app() -> impl IntoView {
|
||||||
let webrtc_offer = webrtc.clone();
|
let webrtc_offer = webrtc.clone();
|
||||||
let offer_button = button()
|
let offer_button = button()
|
||||||
.on(leptos::ev::click, move |_| {
|
.on(leptos::ev::click, move |_| {
|
||||||
|
log!("Offer");
|
||||||
send_auth(&String::from("Offer")).unwrap();
|
send_auth(&String::from("Offer")).unwrap();
|
||||||
let webrtc_offer = webrtc_offer.clone();
|
let webrtc_offer = webrtc_offer.clone();
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
if let Err(err_val) = webrtc_offer.offer().await {
|
if let Err(err_val) = webrtc_offer.offer().await {
|
||||||
log!("Error: WebRTC Offer | {}", err_val);
|
log!("Error: WebRTC Offer | {}", err_val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -52,17 +59,51 @@ pub fn app() -> impl IntoView {
|
||||||
let webrtc_answer = webrtc.clone();
|
let webrtc_answer = webrtc.clone();
|
||||||
let answer_button = button()
|
let answer_button = button()
|
||||||
.on(leptos::ev::click, move |_| {
|
.on(leptos::ev::click, move |_| {
|
||||||
|
log!("Answer");
|
||||||
send_auth(&String::from("Answer")).unwrap();
|
send_auth(&String::from("Answer")).unwrap();
|
||||||
let webrtc_answer = webrtc_answer.clone();
|
let webrtc_answer = webrtc_answer.clone();
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
if let Err(err_val) = webrtc_answer.answer().await {
|
if let Err(err_val) = webrtc_answer.answer().await {
|
||||||
log!("Error: WebRTC Answer | {}", err_val);
|
log!("Error: WebRTC Answer | {}", err_val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.child("Answer");
|
.child("Answer");
|
||||||
|
|
||||||
(offer_button, answer_button)
|
let webrtc_audio = webrtc.clone();
|
||||||
|
let play_remote_audio_button = button()
|
||||||
|
.on(leptos::ev::click, move |_| {
|
||||||
|
let audio_element = HtmlAudioElement::new().unwrap();
|
||||||
|
|
||||||
|
let audio_streams = webrtc_audio.get_remote_streams().unwrap();
|
||||||
|
log!("Streams = {:#?}", audio_streams);
|
||||||
|
let audio_stream = audio_streams.get(0);
|
||||||
|
match audio_stream {
|
||||||
|
Some(audio_stream) => {
|
||||||
|
audio_element.set_src_object(Some(audio_stream));
|
||||||
|
let audio_tracks = audio_stream
|
||||||
|
.get_audio_tracks()
|
||||||
|
.iter()
|
||||||
|
.map(|audio_track| MediaStreamTrack::from(audio_track))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log!("How many tracks = {}", audio_tracks.len());
|
||||||
|
log!(
|
||||||
|
"Constraints = {:#?}",
|
||||||
|
audio_tracks.first().unwrap().get_constraints()
|
||||||
|
);
|
||||||
|
|
||||||
|
let audio_element_play_promise = audio_element.play().unwrap();
|
||||||
|
spawn_local(async move {
|
||||||
|
JsFuture::from(audio_element_play_promise).await.ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => todo!(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.child("Play");
|
||||||
|
|
||||||
|
(offer_button, answer_button, play_remote_audio_button)
|
||||||
}))
|
}))
|
||||||
.fallback(|| label().child("NOOOOOOOOOOOO"))
|
.fallback(|| label().child("NOOOOOOOOOOOO"))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use leptos::logging::log;
|
||||||
use protocol::Error;
|
use protocol::Error;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
|
@ -38,6 +39,11 @@ pub async fn audio() -> Result<MediaStream, Error> {
|
||||||
.first()
|
.first()
|
||||||
.ok_or(Error::MediaStream("Get First Media Track".to_owned()))?;
|
.ok_or(Error::MediaStream("Get First Media Track".to_owned()))?;
|
||||||
|
|
||||||
|
log!(
|
||||||
|
"Local Constraints = {:#?}",
|
||||||
|
audio_stream_track.get_constraints()
|
||||||
|
);
|
||||||
|
|
||||||
let audio_stream_track_apply_constraints_promise = audio_stream_track
|
let audio_stream_track_apply_constraints_promise = audio_stream_track
|
||||||
.apply_constraints_with_constraints(&media_track_constraints)
|
.apply_constraints_with_constraints(&media_track_constraints)
|
||||||
.map_err(|err_val| Error::MediaStream(format!("{:?}", err_val)))?;
|
.map_err(|err_val| Error::MediaStream(format!("{:?}", err_val)))?;
|
||||||
|
|
|
@ -238,4 +238,21 @@ impl WebRTC {
|
||||||
}
|
}
|
||||||
Err(Error::WebRTCAnswer)
|
Err(Error::WebRTCAnswer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_remote_streams(&self) -> Result<Vec<MediaStream>, Error> {
|
||||||
|
let media_streams = self
|
||||||
|
.peer_connection
|
||||||
|
.get_remote_streams()
|
||||||
|
.iter()
|
||||||
|
.map(|media_stream| MediaStream::from(media_stream))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if media_streams.len() > 0 {
|
||||||
|
Ok(media_streams)
|
||||||
|
} else {
|
||||||
|
Err(Error::MediaStream(
|
||||||
|
"There are no remote media stream".to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ async fn websocket_handler(websocket: UpgradeFut) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sleep(Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue