Added MediaManager for WebRTC functions.
This commit is contained in:
parent
c6a119c494
commit
18a26c6bf1
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -2663,14 +2663,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "niom-webrtc2"
|
name = "niom-webrtc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-logger",
|
"dioxus-logger",
|
||||||
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
36
Cargo.toml
36
Cargo.toml
@ -1,26 +1,46 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "niom-webrtc2"
|
name = "niom-webrtc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["ghost <ma-koenig@gmx.net>"]
|
authors = ["ghost <ma-koenig@gmx.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { version = "0.6.0", features = [] }
|
# Dioxus Framework
|
||||||
console_error_panic_hook = "0.1.7"
|
dioxus = { version = "0.6.0", features = ["web"] }
|
||||||
tracing = "0.1"
|
|
||||||
dioxus-logger = "0.6.2"
|
dioxus-logger = "0.6.2"
|
||||||
|
console_error_panic_hook = "0.1.7"
|
||||||
|
|
||||||
|
# WebAssembly and Browser APIs
|
||||||
|
wasm-bindgen = "0.2.84"
|
||||||
|
wasm-bindgen-futures = "0.4.28"
|
||||||
|
js-sys = "0.3.61"
|
||||||
|
|
||||||
|
# web-sys with features for media devices
|
||||||
|
web-sys = { version = "0.3.77", features = [
|
||||||
|
"Navigator",
|
||||||
|
"MediaDevices",
|
||||||
|
"MediaStream",
|
||||||
|
"MediaStreamConstraints",
|
||||||
|
"MediaStreamTrack",
|
||||||
|
"MediaTrackSettings",
|
||||||
|
"MediaTrackConstraints",
|
||||||
|
"AudioContext"
|
||||||
|
]}
|
||||||
|
|
||||||
|
# Logging and Tracing
|
||||||
|
tracing = "0.1"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
|
|
||||||
|
# Serialization
|
||||||
|
serde = { version = "1.0.142", features = ["derive"] }
|
||||||
|
serde_json = "1.0.100"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["web"]
|
default = ["web"]
|
||||||
web = ["dioxus/web"]
|
web = ["dioxus/web"]
|
||||||
desktop = ["dioxus/desktop"]
|
desktop = ["dioxus/desktop"]
|
||||||
mobile = ["dioxus/mobile"]
|
mobile = ["dioxus/mobile"]
|
||||||
|
|
||||||
[profile]
|
|
||||||
|
|
||||||
[profile.wasm-dev]
|
[profile.wasm-dev]
|
||||||
inherits = "dev"
|
inherits = "dev"
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[web.app]
|
[web.app]
|
||||||
|
|
||||||
# HTML title tag content
|
# HTML title tag content
|
||||||
title = "niom-webrtc2"
|
title = "niom-webrtc"
|
||||||
|
|
||||||
# include `assets` in web platform
|
# include `assets` in web platform
|
||||||
[web.resource]
|
[web.resource]
|
||||||
|
|||||||
@ -207,6 +207,10 @@ button:disabled:hover {
|
|||||||
color: #10b981;
|
color: #10b981;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-value.requesting {
|
||||||
|
color: #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.main-content {
|
.main-content {
|
||||||
@ -259,3 +263,60 @@ button:disabled:hover {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mic Test */
|
||||||
|
.mic-test-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 16px;
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-test-section h3 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-test-btn {
|
||||||
|
background-color: #059669;
|
||||||
|
color: white;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-test-btn:hover:not(:disabled) {
|
||||||
|
background-color: #047857;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-test-btn:disabled {
|
||||||
|
background-color: #6b7280;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-stop-btn {
|
||||||
|
background-color: #ef4444;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-stop-btn:hover {
|
||||||
|
background-color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Warning Message */
|
||||||
|
.warning-message {
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #fef3c7;
|
||||||
|
border: 1px solid #f59e0b;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #92400e;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call Button mit zusätzlicher Disabled-State */
|
||||||
|
.call-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: #9ca3af !important;
|
||||||
|
}
|
||||||
|
|||||||
143
src/main.rs
143
src/main.rs
@ -1,16 +1,15 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
mod utils;
|
||||||
|
|
||||||
|
use dioxus::{html::{g::media, h3}, prelude::*};
|
||||||
|
use utils::{MediaManager, MediaState};
|
||||||
|
|
||||||
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||||
const MAIN_CSS: Asset = asset!("/assets/main.css");
|
const MAIN_CSS: Asset = asset!("/assets/main.css");
|
||||||
const HEADER_SVG: Asset = asset!("/assets/header.svg");
|
const HEADER_SVG: Asset = asset!("/assets/header.svg");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Logger initialisieren für besseres Debugging
|
|
||||||
// dioxus_logger::init(log::Level::Info).expect("failed to init logger");
|
|
||||||
// console_error_panic_hook::set_once();
|
|
||||||
|
|
||||||
dioxus::launch(App);
|
dioxus::launch(App);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,20 +19,32 @@ fn App() -> Element {
|
|||||||
document::Link { rel: "icon", href: FAVICON }
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
||||||
Content {}
|
Content {}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Content() ->Element {
|
pub fn Content() ->Element {
|
||||||
// State for connection status and audio
|
// State for connection status and audio
|
||||||
let mut connected = use_signal(|| false); // Status: Verbindung aufgebaut?
|
let mut connected = use_signal(|| false);
|
||||||
let mut audio_enabled = use_signal(|| true); // Status: Mikro aktiviert?
|
let mut audio_enabled = use_signal(|| true);
|
||||||
|
|
||||||
// State for Peer IDs
|
// State for Peer IDs
|
||||||
let mut local_peer_id = use_signal(|| generate_peer_id());
|
let mut local_peer_id = use_signal(|| generate_peer_id());
|
||||||
let mut remote_peer_id = use_signal(|| String::new());
|
let mut remote_peer_id = use_signal(|| String::new());
|
||||||
|
|
||||||
|
let mut media_manager = use_signal(|| MediaManager::new());
|
||||||
|
|
||||||
|
// On mount: Request microphone access if not already granted
|
||||||
|
use_effect(move || {
|
||||||
|
to_owned![media_manager];
|
||||||
|
spawn(async move {
|
||||||
|
match media_manager.write().request_microphone_access().await {
|
||||||
|
Ok(_) => log::info!("Microphone access granted"),
|
||||||
|
Err(e) => log::error!("Failed to request microphone access: {}", e)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "app-container",
|
class: "app-container",
|
||||||
@ -49,9 +60,9 @@ pub fn Content() ->Element {
|
|||||||
|
|
||||||
// Connection Panel
|
// Connection Panel
|
||||||
ConnectionPanel {
|
ConnectionPanel {
|
||||||
connected,
|
connected: connected.clone(),
|
||||||
local_peer_id,
|
local_peer_id: local_peer_id.clone(),
|
||||||
remote_peer_id,
|
remote_peer_id: remote_peer_id.clone(),
|
||||||
on_connect: move |_| {
|
on_connect: move |_| {
|
||||||
log::info!("Verbindung wird hergestellt...");
|
log::info!("Verbindung wird hergestellt...");
|
||||||
connected.set(true);
|
connected.set(true);
|
||||||
@ -60,14 +71,16 @@ pub fn Content() ->Element {
|
|||||||
|
|
||||||
// Call Controls
|
// Call Controls
|
||||||
CallControls {
|
CallControls {
|
||||||
connected,
|
connected: connected.clone(),
|
||||||
audio_enabled,
|
audio_enabled: audio_enabled.clone(),
|
||||||
|
media_manager: media_manager.clone(),
|
||||||
on_start_call: move |_| {
|
on_start_call: move |_| {
|
||||||
log::info!("Anruf wird gestartet mit Remote Peer: {}", remote_peer_id());
|
log::info!("Anruf wird gestartet mit Remote Peer: {}", remote_peer_id());
|
||||||
},
|
},
|
||||||
on_end_call: move |_| {
|
on_end_call: move |_| {
|
||||||
log::info!("Anruf wird beendet");
|
log::info!("Anruf wird beendet");
|
||||||
connected.set(false);
|
connected.set(false);
|
||||||
|
media_manager.write().stop_stream();
|
||||||
},
|
},
|
||||||
on_toggle_audio: move |_| {
|
on_toggle_audio: move |_| {
|
||||||
audio_enabled.set(!audio_enabled());
|
audio_enabled.set(!audio_enabled());
|
||||||
@ -77,10 +90,11 @@ pub fn Content() ->Element {
|
|||||||
|
|
||||||
// Status Display
|
// Status Display
|
||||||
StatusDisplay {
|
StatusDisplay {
|
||||||
connected,
|
connected: connected.clone(),
|
||||||
audio_enabled,
|
audio_enabled: audio_enabled.clone(),
|
||||||
local_peer_id,
|
local_peer_id: local_peer_id.clone(),
|
||||||
remote_peer_id
|
remote_peer_id: remote_peer_id.clone(),
|
||||||
|
media_manager: media_manager.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,12 +116,12 @@ fn ConnectionPanel(
|
|||||||
|
|
||||||
div {
|
div {
|
||||||
class: "input-group",
|
class: "input-group",
|
||||||
label { "for": "local-peer-id", "Ihre Peer ID:" }
|
label { r#for: "local-peer-id", "Ihre Peer ID:" }
|
||||||
input {
|
input {
|
||||||
id: "local-peer-id",
|
id: "local-peer-id",
|
||||||
class: "readonly-input",
|
class: "readonly-input",
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
value: "{local_peer_id}",
|
value: "{local_peer_id()}",
|
||||||
readonly: true
|
readonly: true
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
@ -122,7 +136,7 @@ fn ConnectionPanel(
|
|||||||
|
|
||||||
div {
|
div {
|
||||||
class: "input-group",
|
class: "input-group",
|
||||||
label { "for": "remote-peer-id", "Remote Peer-ID:" }
|
label { r#for: "remote-peer-id", "Remote Peer-ID:" }
|
||||||
input {
|
input {
|
||||||
id: "remote-peer-id",
|
id: "remote-peer-id",
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
@ -155,6 +169,7 @@ fn ConnectionPanel(
|
|||||||
fn CallControls(
|
fn CallControls(
|
||||||
connected: Signal<bool>,
|
connected: Signal<bool>,
|
||||||
audio_enabled: Signal<bool>,
|
audio_enabled: Signal<bool>,
|
||||||
|
mut media_manager: Signal<MediaManager>,
|
||||||
on_start_call: EventHandler<MouseEvent>,
|
on_start_call: EventHandler<MouseEvent>,
|
||||||
on_end_call: EventHandler<MouseEvent>,
|
on_end_call: EventHandler<MouseEvent>,
|
||||||
on_toggle_audio: EventHandler<MouseEvent>
|
on_toggle_audio: EventHandler<MouseEvent>
|
||||||
@ -166,16 +181,21 @@ fn CallControls(
|
|||||||
|
|
||||||
div {
|
div {
|
||||||
class: "control-buttons",
|
class: "control-buttons",
|
||||||
|
|
||||||
|
// Start Call
|
||||||
button {
|
button {
|
||||||
class: "call-btn primary",
|
class: "call-btn primary",
|
||||||
onclick: on_start_call,
|
onclick: on_start_call,
|
||||||
disabled: !connected(),
|
disabled: !connected(),
|
||||||
"📞 Anruf starten"
|
"📞 Anruf starten"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle Audio
|
||||||
button {
|
button {
|
||||||
class: if audio_enabled() {
|
class: if audio_enabled() {
|
||||||
"mute-btn"
|
"mute-btn"
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
"mute-btn-muted"
|
"mute-btn-muted"
|
||||||
},
|
},
|
||||||
onclick: on_toggle_audio,
|
onclick: on_toggle_audio,
|
||||||
@ -187,6 +207,8 @@ fn CallControls(
|
|||||||
"🔇 Stumm"
|
"🔇 Stumm"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End Call
|
||||||
button {
|
button {
|
||||||
class: "end-btn danger",
|
class: "end-btn danger",
|
||||||
onclick: on_end_call,
|
onclick: on_end_call,
|
||||||
@ -204,13 +226,59 @@ fn StatusDisplay(
|
|||||||
connected: Signal<bool>,
|
connected: Signal<bool>,
|
||||||
audio_enabled: Signal<bool>,
|
audio_enabled: Signal<bool>,
|
||||||
local_peer_id: Signal<String>,
|
local_peer_id: Signal<String>,
|
||||||
remote_peer_id: Signal<String>
|
remote_peer_id: Signal<String>,
|
||||||
|
media_manager: Signal<MediaManager>
|
||||||
) -> Element {
|
) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "status-display",
|
class: "status-display",
|
||||||
h2 { "Status" }
|
h2 { "Status" }
|
||||||
|
|
||||||
|
div {
|
||||||
|
class: "status-item",
|
||||||
|
span {
|
||||||
|
class: "status-label",
|
||||||
|
"Mikrofon Berechtigung:"
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
class: match &media_manager.read().state {
|
||||||
|
MediaState::Granted(_) => "status-value connected",
|
||||||
|
MediaState::Denied(_) => "status-value disconnected",
|
||||||
|
MediaState::Requesting => "status-value requesting",
|
||||||
|
_ => "status-value unknown"
|
||||||
|
},
|
||||||
|
match &media_manager.read().state {
|
||||||
|
MediaState::Granted(_) => "Erteilt",
|
||||||
|
MediaState::Denied(_) => "Verweigert",
|
||||||
|
MediaState::Requesting => "Anfrage läuft",
|
||||||
|
_ => "Nicht verfügbar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
class: "status-item",
|
||||||
|
span {
|
||||||
|
class: "status-label",
|
||||||
|
"Mikrofon:"
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
class:
|
||||||
|
if audio_enabled() {
|
||||||
|
"status-value connected"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"status-value disconnected"
|
||||||
|
},
|
||||||
|
if audio_enabled() {
|
||||||
|
"Entmuted"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"Stumm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
class: "status-item",
|
class: "status-item",
|
||||||
span {
|
span {
|
||||||
@ -248,25 +316,19 @@ fn StatusDisplay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
class: "status-item",
|
class:"status-item",
|
||||||
span {
|
span {
|
||||||
class: "status-label",
|
class: "status-label",
|
||||||
"Audio Status:"
|
"Mikrofon Status:"
|
||||||
}
|
}
|
||||||
span {
|
span {
|
||||||
class:
|
class: match &media_manager.read().state {
|
||||||
if audio_enabled() {
|
MediaState::Granted(_) => "status-value connected",
|
||||||
"status-value"
|
MediaState::Denied(_) => "status-value disconnected",
|
||||||
}
|
MediaState::Requesting => "status-value requesting",
|
||||||
else {
|
_ => "status-value"
|
||||||
"status-value disconnected"
|
},
|
||||||
},
|
"{media_manager.read().get_status_text()}"
|
||||||
if audio_enabled() {
|
|
||||||
"Aktiviert"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
"Stumm"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +357,13 @@ fn StatusDisplay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !MediaManager::is_webrtc_supported() {
|
||||||
|
div {
|
||||||
|
class: "warning-message",
|
||||||
|
"⚠️ WebRTC wird von diesem Browser nicht unterstützt"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
130
src/utils/media_manager.rs
Normal file
130
src/utils/media_manager.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use web_sys::{MediaDevices, MediaStream, MediaStreamConstraints, Navigator, Window};
|
||||||
|
|
||||||
|
// Enum für verschiedene Media-Zustände
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum MediaState {
|
||||||
|
Uninitialized,
|
||||||
|
Requesting,
|
||||||
|
Granted(MediaStream),
|
||||||
|
Denied(String),
|
||||||
|
NotSupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media Manager für WebRTC-Funktionalität
|
||||||
|
pub struct MediaManager {
|
||||||
|
pub state: MediaState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaManager {
|
||||||
|
// Creates a new MediaManager instance
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state: MediaState::Uninitialized,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if WebRTC is supported
|
||||||
|
pub fn is_webrtc_supported() -> bool {
|
||||||
|
let window: Window = match web_sys::window() {
|
||||||
|
Some(w) => w,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let navigator: Navigator = window.navigator();
|
||||||
|
navigator.media_devices().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn request_microphone_access(&mut self) -> Result<MediaStream, String> {
|
||||||
|
// Check if WebRTC is supported
|
||||||
|
if !Self::is_webrtc_supported() {
|
||||||
|
self.state = MediaState::NotSupported;
|
||||||
|
return Err("WebRTC wird von diesem Browser nicht unterstützt.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state = MediaState::Requesting;
|
||||||
|
|
||||||
|
// Get browser window and navigator
|
||||||
|
let window = web_sys::window().ok_or("Kein Browserfenster gefunden")?;
|
||||||
|
let navigator = window.navigator();
|
||||||
|
let media_devices = navigator.media_devices().map_err(|_| "MediaDevices API nicht verfügbar")?;
|
||||||
|
|
||||||
|
// Define media constraints: only audio, no video
|
||||||
|
let mut constraints = MediaStreamConstraints::new();
|
||||||
|
constraints.audio(&JsValue::from(true));
|
||||||
|
constraints.video(&JsValue::from(false));
|
||||||
|
|
||||||
|
// Request access to the microphone
|
||||||
|
let promise = media_devices
|
||||||
|
.get_user_media_with_constraints(&constraints)
|
||||||
|
.map_err(|e| format!("getUserMedia fehlgeschlagen: {:?}", e))?;
|
||||||
|
|
||||||
|
// Convert JavaScript Promise to Rust Future
|
||||||
|
let future = JsFuture::from(promise);
|
||||||
|
|
||||||
|
match future.await {
|
||||||
|
Ok(stream) => {
|
||||||
|
// Convert JsValue to MediaStream
|
||||||
|
let media_stream: MediaStream = stream.dyn_into().map_err(|_| "Fehler beim Konvertieren zu MediaStream")?;
|
||||||
|
self.state = MediaState::Granted(media_stream.clone());
|
||||||
|
|
||||||
|
log::info!("Mikrofon-Zugriff erfolgreich erhalten!");
|
||||||
|
|
||||||
|
Ok(media_stream)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let error_message = format!("Mikrofon-Zugriff verweigert: {:?}", e);
|
||||||
|
|
||||||
|
self.state = MediaState::Denied(error_message.clone());
|
||||||
|
log::error!("{}", error_message);
|
||||||
|
Err(error_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logs information about a media stream
|
||||||
|
fn log_stream_info(&self, stream: &MediaStream) {
|
||||||
|
let tracks = stream.get_audio_tracks();
|
||||||
|
log::info!("Audio-Tracks erhalten: {}", tracks.length());
|
||||||
|
|
||||||
|
for i in 0..tracks.length() {
|
||||||
|
let track = tracks.get(i);
|
||||||
|
let track: web_sys::MediaStreamTrack = track.dyn_into().unwrap();
|
||||||
|
log::info!("Track {}: {} ({})", i, track.label(), track.kind());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops the media stream and all its tracks
|
||||||
|
pub fn stop_stream(&mut self) {
|
||||||
|
if let MediaState::Granted(ref stream) = self.state {
|
||||||
|
let tracks = stream.get_tracks();
|
||||||
|
|
||||||
|
for i in 0..tracks.length() {
|
||||||
|
let track = tracks.get(i);
|
||||||
|
let track: web_sys::MediaStreamTrack = track.dyn_into().unwrap();
|
||||||
|
track.stop();
|
||||||
|
log::info!("Track gestoppt: {}", track.label());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state = MediaState::Uninitialized;
|
||||||
|
log::info!("MediaStream gestoppt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a user-friendly status text based on the current media state
|
||||||
|
pub fn get_status_text(&self) -> &str {
|
||||||
|
match self.state {
|
||||||
|
MediaState::Uninitialized => "Nicht initialisiert",
|
||||||
|
MediaState::Requesting => "Berechtigung wird angefragt...",
|
||||||
|
MediaState::Granted(_) => "Zugriff gewährt",
|
||||||
|
MediaState::Denied(_) => "Zugriff verweigert",
|
||||||
|
MediaState::NotSupported => "WebRTC wird nicht unterstützt",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the microphone is currently active
|
||||||
|
pub fn is_microphone_active(&self) -> bool {
|
||||||
|
matches!(self.state, MediaState::Granted(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/utils/mod.rs
Normal file
3
src/utils/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod media_manager;
|
||||||
|
|
||||||
|
pub use media_manager::*;
|
||||||
Loading…
x
Reference in New Issue
Block a user