Hi,
I'm trying to build media streaming platform. I'm currently experiencing low quality audio. Do you know what should I do to improve quality ?
here is a video
my code:
use leptos::{
IntoView, ev,
html::{ElementChild, button},
logging::log,
prelude::{OnAttribute, Read, Show, ShowProps, ToChildren},
server::LocalResource,
task::spawn_local,
};
use wasm_bindgen_futures::JsFuture;
use web_sys::{
HtmlAudioElement, MediaStream, MediaStreamConstraints,
wasm_bindgen::{JsCast, JsValue},
window,
};
pub fn app() -> impl IntoView {
let audio_stream = LocalResource::new(|| media());
let props = ShowProps::builder()
.when(move || audio_stream.read().is_some())
.children(ToChildren::to_children(move || {
let audio_element = HtmlAudioElement::new().unwrap();
let audio_stream = audio_stream.read();
let audio_stream = audio_stream.as_deref();
audio_element.set_src_object(audio_stream);
button()
.on(ev::click, move |_| match audio_element.play() {
Ok(audio_element_play_promise) => {
log!("{}", "Play will");
spawn_local(async move {
JsFuture::from(audio_element_play_promise).await.ok();
});
log!("{}", "Play must");
}
Err(err_val) => log!("{:#?}", err_val),
})
.child("Happy Button")
.into_view()
}))
.fallback(|| button().child("Sad Button"))
.build();
Show(props)
}
async fn media() -> MediaStream {
let media_devices = window().unwrap().navigator().media_devices().unwrap();
let constraints = MediaStreamConstraints::new();
constraints.set_audio(&JsValue::TRUE);
let media_stream_promise = media_devices
.get_user_media_with_constraints(&constraints)
.unwrap();
let media_stream = JsFuture::from(media_stream_promise)
.await
.unwrap()
.dyn_into::<MediaStream>()
.unwrap();
let audio_tracks = media_stream.get_audio_tracks();
MediaStream::new_with_tracks(&audio_tracks).unwrap()
}
This problem also happens in pure JavaScript too.
I got code from: audio - Access microphone from a browser - Javascript - Stack Overflow
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<audio id="audioCapture"></audio>
<button onclick=audioCapture.Init()>
start microphone
</button>
<p style="font-size: 42pt;">
This is a blank page for live captions like CNN video.
</p>
<script type="text/javascript">
var audioCapture = (function ()
{
var init = function ()
{
initCapture();
};
function initCapture()
{
var constraints = { audio: true, video: false };
navigator.mediaDevices.getUserMedia(constraints).then(function (stream)
{
var audio = document.getElementById('audioCapture');
audio.srcObject = stream;
audio.play();
}).catch(function (err)
{
console.log(err);
});
}
return {
Init: init
}
})();
</script>
</body>
</html>
Alright solved.
tldr: need to disable echo cancellation.
details: How to improve audio performance · leptos-rs/leptos · Discussion #3809 · GitHub
improved code:
use leptos::{
IntoView, ev,
html::{ElementChild, button},
logging::log,
prelude::{OnAttribute, Read, Show, ShowProps, ToChildren},
server::LocalResource,
task::spawn_local,
};
use wasm_bindgen_futures::JsFuture;
use web_sys::{
HtmlAudioElement, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints,
wasm_bindgen::{JsCast, JsValue},
window,
};
pub fn app() -> impl IntoView {
let audio_stream = LocalResource::new(|| media());
let props = ShowProps::builder()
.when(move || audio_stream.read().is_some())
.children(ToChildren::to_children(move || {
let audio_element = HtmlAudioElement::new().unwrap();
let audio_stream = audio_stream.read();
let audio_stream = audio_stream.as_deref();
audio_element.set_src_object(audio_stream);
button()
.on(ev::click, move |_| match audio_element.play() {
Ok(audio_element_play_promise) => {
log!("{}", "Play will");
spawn_local(async move {
JsFuture::from(audio_element_play_promise).await.ok();
});
log!("{}", "Play must");
}
Err(err_val) => log!("{:#?}", err_val),
})
.child("Happy Button")
.into_view()
}))
.fallback(|| button().child("Sad Button"))
.build();
Show(props)
}
async fn media() -> MediaStream {
let media_devices = window().unwrap().navigator().media_devices().unwrap();
let media_stream_constraints = MediaStreamConstraints::new();
let media_track_constraints = MediaTrackConstraints::new();
media_stream_constraints.set_audio(&JsValue::TRUE);
media_track_constraints.set_echo_cancellation(&JsValue::FALSE);
media_track_constraints.set_noise_suppression(&JsValue::FALSE);
media_track_constraints.set_auto_gain_control(&JsValue::FALSE);
let media_stream_promise = media_devices
.get_user_media_with_constraints(&media_stream_constraints)
.unwrap();
let media_stream = JsFuture::from(media_stream_promise)
.await
.unwrap()
.dyn_into::<MediaStream>()
.unwrap();
let audio_tracks = media_stream.get_audio_tracks();
let audio_tracks = audio_tracks
.iter()
.map(|audio_track| audio_track.dyn_into::<MediaStreamTrack>().unwrap())
.collect::<Vec<_>>();
log!("{:#?}, len = {}", audio_tracks, audio_tracks.len());
let audio_track = audio_tracks.first().unwrap();
let media_track_apply_constraints_promise = audio_track
.apply_constraints_with_constraints(&media_track_constraints)
.unwrap();
JsFuture::from(media_track_apply_constraints_promise)
.await
.unwrap();
let media_stream = MediaStream::new().unwrap();
log!("{:#?}", audio_track.get_constraints());
media_stream.add_track(audio_track);
media_stream
}
2 Likes