diff --git a/assets/js/voice.js b/assets/js/voice.js index 9e77e8d..7232825 100644 --- a/assets/js/voice.js +++ b/assets/js/voice.js @@ -6,6 +6,7 @@ class VoiceChannel { this.settings = settings || { mode: 'vox', pttKey: 'v', voxThreshold: 0.1 }; console.log('VoiceChannel constructor called with settings:', this.settings); this.localStream = null; + this.analysisStream = null; this.peers = {}; // userId -> RTCPeerConnection this.participants = {}; // userId -> {name} this.currentChannelId = null; @@ -85,9 +86,8 @@ class VoiceChannel { console.log('Microphone access granted'); this.setMute(true); - if (this.settings.mode === 'vox') { - this.setupVOX(); - } + // Always setup VOX logic for volume meter and detection + this.setupVOX(); // Join via PHP console.log('Calling API join...'); @@ -292,12 +292,25 @@ class VoiceChannel { this.analyser = this.audioContext.createAnalyser(); this.analyser.fftSize = 512; - this.microphone = this.audioContext.createMediaStreamSource(this.localStream); + + // Use a cloned stream for analysis so VOX works even when localStream is muted/disabled + if (this.analysisStream) { + this.analysisStream.getTracks().forEach(t => t.stop()); + } + this.analysisStream = this.localStream.clone(); + this.analysisStream.getAudioTracks().forEach(t => t.enabled = true); // Ensure analysis stream is NOT muted + + this.microphone = this.audioContext.createMediaStreamSource(this.analysisStream); this.scriptProcessor = this.audioContext.createScriptProcessor(2048, 1, 1); this.microphone.connect(this.analyser); this.analyser.connect(this.scriptProcessor); - this.scriptProcessor.connect(this.audioContext.destination); + + // Avoid feedback: connect to a gain node with 0 volume then to destination + const silence = this.audioContext.createGain(); + silence.gain.value = 0; + this.scriptProcessor.connect(silence); + silence.connect(this.audioContext.destination); this.voxActive = false; this.currentVolume = 0; @@ -378,6 +391,10 @@ class VoiceChannel { this.localStream.getTracks().forEach(track => track.stop()); this.localStream = null; } + if (this.analysisStream) { + this.analysisStream.getTracks().forEach(track => track.stop()); + this.analysisStream = null; + } if (this.scriptProcessor) { try { diff --git a/data/22.log b/data/22.log index ab069b2..e69de29 100644 --- a/data/22.log +++ b/data/22.log @@ -1,3 +0,0 @@ -{"from":"fc0c84d0eacc14ca","to":"3183519aeadc9f64","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 1 UDP 1686052863 78.246.210.10 31075 typ srflx raddr 192.168.26.26 rport 52078","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"0e646e7c"}},"time":1771341579696} -{"from":"fc0c84d0eacc14ca","to":"3183519aeadc9f64","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 2 UDP 1686052862 78.246.210.10 31078 typ srflx raddr 192.168.26.26 rport 52079","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"0e646e7c"}},"time":1771341579740} -{"from":"fc0c84d0eacc14ca","to":"3183519aeadc9f64","data":{"type":"ice_candidate","candidate":{"candidate":"","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"0e646e7c"}},"time":1771341579742} diff --git a/data/22.participants.json b/data/22.participants.json index 0637a08..3caf8fb 100644 --- a/data/22.participants.json +++ b/data/22.participants.json @@ -1 +1 @@ -[] \ No newline at end of file +{"de65a0b0b1a29c9a":{"id":"de65a0b0b1a29c9a","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771343410040}} \ No newline at end of file diff --git a/data/3.participants.json b/data/3.participants.json index e929308..486a3e1 100644 --- a/data/3.participants.json +++ b/data/3.participants.json @@ -1 +1 @@ -{"f9f747081f54c6e3":{"id":"f9f747081f54c6e3","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771341691097}} \ No newline at end of file +{"920464469dc771ed":{"id":"920464469dc771ed","user_id":3,"name":"swefheim","avatar_url":"","last_seen":1771343410598}} \ No newline at end of file diff --git a/requests.log b/requests.log index a8de67a..d8b5db0 100644 --- a/requests.log +++ b/requests.log @@ -618,3 +618,17 @@ {"date":"2026-02-17 15:19:53","method":"POST","post":{"avatar_url":"","display_name":"swefpifh \u1d47\u02b0\u1da0\u02b3","theme":"dark","voice_mode":"vox","voice_ptt_key":"0","voice_vox_threshold":"0.06","dnd_mode":"1","sound_notifications":"1"},"session":{"user_id":2},"user_id":2,"db_success":true} 2026-02-17 15:19:56 - GET /index.php?server_id=1&channel_id=1 - POST: [] 2026-02-17 15:20:01 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-17 15:23:33 - GET /?fl_project=38443 - POST: [] +2026-02-17 15:23:33 - GET /?fl_project=38443 - POST: [] +2026-02-17 15:32:11 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-17 15:32:29 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-17 15:33:22 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-17 15:35:42 - GET / - POST: [] +2026-02-17 15:36:35 - GET /?fl_project=38443 - POST: [] +2026-02-17 15:36:35 - GET /?fl_project=38443 - POST: [] +2026-02-17 15:46:33 - GET /index.php?server_id=1&channel_id=1 - POST: [] +2026-02-17 15:46:36 - GET /index.php - POST: [] +{"date":"2026-02-17 15:47:00","method":"POST","post":{"avatar_url":"","display_name":"swefheim","theme":"light","voice_mode":"vox","voice_ptt_key":"v","voice_vox_threshold":"0","dnd_mode":"0","sound_notifications":"0"},"session":{"user_id":3},"user_id":3,"db_success":true} +{"date":"2026-02-17 15:47:36","method":"POST","post":{"avatar_url":"","display_name":"swefpifh \u1d47\u02b0\u1da0\u02b3","theme":"dark","voice_mode":"ptt","voice_ptt_key":"v","voice_vox_threshold":"0.06","dnd_mode":"1","sound_notifications":"1"},"session":{"user_id":2},"user_id":2,"db_success":true} +{"date":"2026-02-17 15:48:00","method":"POST","post":{"avatar_url":"","display_name":"swefheim","theme":"light","voice_mode":"vox","voice_ptt_key":"v","voice_vox_threshold":"0","dnd_mode":"0","sound_notifications":"0"},"session":{"user_id":3},"user_id":3,"db_success":true} +{"date":"2026-02-17 15:48:41","method":"POST","post":{"avatar_url":"","display_name":"swefpifh \u1d47\u02b0\u1da0\u02b3","theme":"dark","voice_mode":"vox","voice_ptt_key":"v","voice_vox_threshold":"0.06","dnd_mode":"1","sound_notifications":"1"},"session":{"user_id":2},"user_id":2,"db_success":true}