diff --git a/Makefile b/Makefile index 620f6c8c..3ff4080c 100644 --- a/Makefile +++ b/Makefile @@ -79,7 +79,11 @@ dev: ## Start backend + desktop app (parallel) @echo -e "$(YELLOW)Note: If Tauri fails, run 'make build-server' first or use separate terminals$(NC)" @trap 'kill 0' EXIT; \ $(MAKE) dev-backend & \ - sleep 2 && $(MAKE) dev-frontend & \ + sleep 2 && if [ "$$(uname)" = "Linux" ] && lspci 2>/dev/null | grep -qi nvidia; then \ + WEBKIT_DISABLE_DMABUF_RENDERER=1 $(MAKE) dev-frontend; \ + else \ + $(MAKE) dev-frontend; \ + fi & \ wait dev-backend: ## Start FastAPI backend server diff --git a/tauri/src-tauri/Cargo.lock b/tauri/src-tauri/Cargo.lock index 35b15188..1ee065f2 100644 --- a/tauri/src-tauri/Cargo.lock +++ b/tauri/src-tauri/Cargo.lock @@ -5041,7 +5041,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "voicebox" -version = "0.1.12" +version = "0.1.13" dependencies = [ "base64 0.22.1", "core-foundation-sys", @@ -5064,6 +5064,7 @@ dependencies = [ "tauri-plugin-updater", "tokio", "wasapi", + "webkit2gtk", "windows 0.62.2", ] diff --git a/tauri/src-tauri/Cargo.toml b/tauri/src-tauri/Cargo.toml index aa3b1a9c..1f3654d0 100644 --- a/tauri/src-tauri/Cargo.toml +++ b/tauri/src-tauri/Cargo.toml @@ -37,6 +37,9 @@ core-foundation-sys = "0.8" wasapi = "0.22" windows = { version = "0.62", features = ["Win32_Foundation", "Win32_UI_WindowsAndMessaging", "Win32_System_Com"] } +[target.'cfg(target_os = "linux")'.dependencies] +webkit2gtk = "2.0" + [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-updater = "2.0" tauri-plugin-process = "2.0" diff --git a/tauri/src-tauri/src/main.rs b/tauri/src-tauri/src/main.rs index 255655aa..83629070 100644 --- a/tauri/src-tauri/src/main.rs +++ b/tauri/src-tauri/src/main.rs @@ -635,6 +635,43 @@ pub fn run() { } } + // Enable microphone access on Linux (WebKitGTK denies getUserMedia by default) + #[cfg(target_os = "linux")] + { + use tauri::Manager; + if let Some(window) = app.get_webview_window("main") { + let _ = window.with_webview(|webview| { + use webkit2gtk::{WebViewExt, SettingsExt, PermissionRequestExt}; + use webkit2gtk::glib::ObjectExt; + let wk_webview = webview.inner(); + + // Enable media stream support in WebKitGTK settings + if let Some(settings) = WebViewExt::settings(&wk_webview) { + settings.set_enable_media_stream(true); + } + + // Auto-grant UserMediaPermissionRequest (microphone access) + // Only for trusted local origins (Tauri dev server or custom protocol) + wk_webview.connect_permission_request(move |webview, request: &webkit2gtk::PermissionRequest| { + if request.is::() { + let uri = WebViewExt::uri(webview).unwrap_or_default(); + let is_trusted = uri.starts_with("tauri://") + || uri.starts_with("https://tauri.localhost") + || uri.starts_with("http://localhost") + || uri.starts_with("http://127.0.0.1"); + if is_trusted { + request.allow(); + return true; + } + request.deny(); + return true; + } + false + }); + }); + } + } + Ok(()) }) .invoke_handler(tauri::generate_handler![