From f6cfea162174ed8c9f9fec4258dcaaf3e26076ed Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 26 Aug 2026 14:31:26 +0200 Subject: [PATCH] Testing voice chat UDP --- src-tauri/src/commands/audio.rs | 12 ++++++------ src-tauri/src/lib.rs | 1 + src/app/app.ts | 4 ++++ src/app/protocol.ts | 9 +++++++++ src/app/server.ts | 1 + src/components/page/channel/VoiceChannel.tsx | 14 +++++++++++++- src/components/settings/SettingsDialog.tsx | 2 +- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/commands/audio.rs b/src-tauri/src/commands/audio.rs index 7cfaa84..c32ba92 100644 --- a/src-tauri/src/commands/audio.rs +++ b/src-tauri/src/commands/audio.rs @@ -66,10 +66,9 @@ pub fn connect_to_vc( let socket = UdpSocket::bind("0.0.0.0:0").map_err(|e| e.to_string())?; socket.connect(&hostname).map_err(|e| e.to_string())?; - socket.set_nonblocking(true).map_err(|e| e.to_string())?; let socket = Arc::new(socket); - // Send the pin as the very first packet — this is your UDP "initialize" + // Send the pin as the very first packet — authenticates this UDP session socket .send(&pin.to_be_bytes()) .map_err(|e| format!("Failed to send pincode: {e}"))?; @@ -118,16 +117,17 @@ pub fn connect_to_vc( .build_input_stream( input_config, move |data: &[f32], _| { - // convert f32 -> i16 PCM, prefix with pin, send over UDP let pcm: Vec = data .iter() .map(|s| (s.clamp(-1.0, 1.0) * i16::MAX as f32) as i16) .collect(); - let mut packet = pin.to_be_bytes().to_vec(); - packet.extend(pcm.iter().flat_map(|s| s.to_be_bytes())); + let mut packet = Vec::with_capacity(pcm.len() * 2); + for sample in &pcm { + packet.extend_from_slice(&sample.to_be_bytes()); + } - let _ = input_socket.send(&packet); // non-blocking, drop on failure + let _ = input_socket.send(&packet); }, |err| eprintln!("Input stream error: {err}"), None, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5753e73..cd3b64b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -10,6 +10,7 @@ pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_opener::init()) .manage(ConfigState(Mutex::new(commands::config::Config::default()))) + .manage(commands::audio::VoiceState::default()) .invoke_handler(tauri::generate_handler![ commands::server_list::save_server_list, commands::server_list::get_server_list, diff --git a/src/app/app.ts b/src/app/app.ts index c02b33d..a34731d 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -206,6 +206,10 @@ export default class Enclave

{ server.messages[msg.channel_id][msg.message.id] = msg.message; this.forceRender(); return; + + case "JoinVoice": + server.voiceJoin && server.voiceJoin(msg.pin, msg.channel_id); + return; } } } diff --git a/src/app/protocol.ts b/src/app/protocol.ts index 0d1c204..db6a5af 100644 --- a/src/app/protocol.ts +++ b/src/app/protocol.ts @@ -29,6 +29,11 @@ export type ClientMethod = method: "MessageDeleted"; channel_id: string; message_id: string; + } + | { + method: "JoinVoice"; + channel_id: string; + pin: number; }; export type ServerMethod = @@ -71,4 +76,8 @@ export type ServerMethod = method: "DeleteMessage"; channel_id: string; message_id: string; + } + | { + method: "JoinVoice"; + channel_id: string; }; diff --git a/src/app/server.ts b/src/app/server.ts index 37ed228..525e121 100644 --- a/src/app/server.ts +++ b/src/app/server.ts @@ -31,6 +31,7 @@ export default class EnclaveServer { public meta?: ServerMeta; public messages: Record>; public users: Record; + public voiceJoin?: (pin: number, channelId: string) => void; public constructor(hostname: string, isSecure: boolean) { this.hostname = hostname; diff --git a/src/components/page/channel/VoiceChannel.tsx b/src/components/page/channel/VoiceChannel.tsx index f342e63..86ec3a8 100644 --- a/src/components/page/channel/VoiceChannel.tsx +++ b/src/components/page/channel/VoiceChannel.tsx @@ -20,7 +20,19 @@ export default function VoiceChannel({ lastChannelId.current = channel.id; invoke("disconnect_from_vc"); - invoke("connect_to_vc", { hostname }); + + if (channel.kind !== "voice" || !appRef.current?.server) return; + + appRef.current.server.voiceJoin = (pin, channelId) => { + invoke("connect_to_vc", { hostname, pin, channelId }).catch( + console.error, + ); + }; + + appRef.current.server.websocket?.send({ + method: "JoinVoice", + channel_id: channel.id, + }); }, [channel.id]); return ( diff --git a/src/components/settings/SettingsDialog.tsx b/src/components/settings/SettingsDialog.tsx index ade9c34..2b6f19c 100644 --- a/src/components/settings/SettingsDialog.tsx +++ b/src/components/settings/SettingsDialog.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { Dialog, DialogContent } from "@/components/ui/dialog"; import { cn } from "@/lib/utils"; -import { User, Palette, Mic, Volume2 } from "lucide-react"; +import { User, Palette, Volume2 } from "lucide-react"; import { ProfileSettings } from "./ProfileSettings"; import { AppearanceSettings } from "./AppearanceSettings"; import { AudioVideoSettings } from "./AudioVideoSettings";