From 04cad1c49b1a0c41e8af15822bc2667059d3fe62 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 17 Feb 2026 14:47:12 +0000 Subject: [PATCH] PTT semi focntionnel --- api_v1_voice.php | 249 ++++++++-- assets/js/main.js | 22 +- assets/js/voice.js | 520 +++++++++++---------- assets/pasted-20260217-141526-2008a77e.png | Bin 0 -> 49460 bytes assets/pasted-20260217-143739-c7f88b4b.png | Bin 0 -> 46718 bytes data/22.log | 2 + data/22.participants.json | 1 + data/3.log | 8 + data/3.participants.json | 1 + data/6.log | 10 + data/6.participants.json | 1 + data/test.participants.json | 1 + data/test.txt | 1 + data/test_www.txt | 1 + index.php | 72 +-- requests.log | 68 +++ 16 files changed, 649 insertions(+), 308 deletions(-) create mode 100644 assets/pasted-20260217-141526-2008a77e.png create mode 100644 assets/pasted-20260217-143739-c7f88b4b.png create mode 100644 data/22.log create mode 100644 data/22.participants.json create mode 100644 data/3.log create mode 100644 data/3.participants.json create mode 100644 data/6.log create mode 100644 data/6.participants.json create mode 100644 data/test.participants.json create mode 100644 data/test.txt create mode 100644 data/test_www.txt diff --git a/api_v1_voice.php b/api_v1_voice.php index e8c303b..b36d663 100644 --- a/api_v1_voice.php +++ b/api_v1_voice.php @@ -1,44 +1,239 @@ - false, 'error' => 'Unauthorized']); +$current_user_id = $user ? (int)$user["id"] : 0; + +function room_id(string $s): string { + $s = preg_replace("~[^a-zA-Z0-9_\-]~", "", $s); + return $s !== "" ? $s : "secours"; +} + +function peer_id(): string { + return bin2hex(random_bytes(8)); +} + +function room_log_file(string $room): string { + return __DIR__ . "/data/" . $room . ".log"; +} + +function room_participants_file(string $room): string { + return __DIR__ . "/data/" . $room . ".participants.json"; +} + +function chat_log_file_for_today(): string { + // Un fichier par jour : YYYY-MM-DD.chat.log + $d = date("Y-m-d"); + return __DIR__ . "/data/" . $d . ".chat.log"; +} + +function now_ms(): int { + return (int) floor(microtime(true) * 1000); +} + +function json_out($data, int $code = 200): void { + http_response_code($code); + header("Content-Type: application/json; charset=utf-8"); + echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $action = $_POST['action'] ?? ''; - $channel_id = $_POST['channel_id'] ?? null; +function read_json_file(string $path): array { + if (!file_exists($path)) return []; + $raw = @file_get_contents($path); + if ($raw === false || $raw === "") return []; + $j = json_decode($raw, true); + return is_array($j) ? $j : []; +} - if ($action === 'join' && $channel_id) { - $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE channel_id = ?"); - $stmt->execute([$user['id'], $channel_id, $channel_id]); - echo json_encode(['success' => true]); - } elseif ($action === 'leave') { - $stmt = db()->prepare("DELETE FROM voice_sessions WHERE user_id = ?"); - $stmt->execute([$user['id']]); - echo json_encode(['success' => true]); - } else { - echo json_encode(['success' => false, 'error' => 'Invalid action']); +function write_json_file(string $path, array $data): void { + file_put_contents($path, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), LOCK_EX); +} + +function tail_lines(string $path, int $maxLines = 120): array { + if (!is_file($path)) return []; + $fp = fopen($path, "rb"); + if (!$fp) return []; + + $lines = []; + fseek($fp, 0, SEEK_END); + $pos = ftell($fp); + $buffer = ""; + + while ($pos > 0 && count($lines) < $maxLines) { + $readSize = min($pos, 4096); + $pos -= $readSize; + fseek($fp, $pos); + $chunk = fread($fp, $readSize); + $buffer = $chunk . $buffer; + + $chunkLines = explode("\n", $buffer); + $buffer = array_shift($chunkLines); + + while (!empty($chunkLines)) { + $line = array_pop($chunkLines); + if (trim($line) !== "") { + array_unshift($lines, trim($line)); + if (count($lines) >= $maxLines) break; + } + } } - exit; + fclose($fp); + return $lines; } -if ($_SERVER['REQUEST_METHOD'] === 'GET') { - $action = $_GET['action'] ?? ''; - if ($action === 'sessions') { +// Logic for signaling +$action = $_REQUEST["action"] ?? ""; +$room = room_id($_REQUEST["room"] ?? "secours"); +$my_id = $_REQUEST["peer_id"] ?? ""; + +if ($action === "join") { + $name = $_REQUEST["name"] ?? "User"; + $p_file = room_participants_file($room); + $ps = read_json_file($p_file); + + // Cleanup old participants (> 10s) + $stale_time = now_ms() - 10000; + foreach ($ps as $id => $p) { + if (($p["last_seen"] ?? 0) < $stale_time) unset($ps[$id]); + } + + $new_id = peer_id(); + $ps[$new_id] = [ + "id" => $new_id, + "user_id" => $current_user_id, + "name" => $name, + "avatar_url" => $user["avatar_url"] ?? "", + "last_seen" => now_ms() + ]; + write_json_file($p_file, $ps); + + // DB Integration for sidebar + if ($current_user_id > 0) { + try { + $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id, last_seen) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE channel_id = ?, last_seen = ?"); + $stmt->execute([$current_user_id, $room, now_ms(), $room, now_ms()]); + } catch (Exception $e) {} + } + + json_out(["success" => true, "peer_id" => $new_id, "participants" => $ps]); +} + +if ($action === "poll") { + if (!$my_id) json_out(["error" => "Missing peer_id"], 400); + $p_file = room_participants_file($room); + $ps = read_json_file($p_file); + + if (isset($ps[$my_id])) { + $ps[$my_id]["last_seen"] = now_ms(); + } + + $stale_time = now_ms() - 10000; + foreach ($ps as $id => $p) { + if (($p["last_seen"] ?? 0) < $stale_time) unset($ps[$id]); + } + write_json_file($p_file, $ps); + + // Update DB last_seen + if ($current_user_id > 0) { + try { + $stmt = db()->prepare("UPDATE voice_sessions SET last_seen = ? WHERE user_id = ?"); + $stmt->execute([now_ms(), $current_user_id]); + } catch (Exception $e) {} + } + + // Read signals + $log_file = room_log_file($room); + $signals = []; + if (file_exists($log_file)) { + $lines = file($log_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $remaining = []; + $now = now_ms(); + foreach ($lines as $line) { + $sig = json_decode($line, true); + if ($sig && isset($sig["to"]) && $sig["to"] === $my_id) { + $signals[] = $sig; + } elseif ($sig && ($now - ($sig["time"] ?? 0) < 30000)) { + $remaining[] = $line; + } + } + file_put_contents($log_file, implode("\n", $remaining) . (empty($remaining) ? "" : "\n"), LOCK_EX); + } + + json_out(["success" => true, "participants" => $ps, "signals" => $signals]); +} + +if ($action === "signal") { + if (!$my_id) json_out(["error" => "Missing peer_id"], 400); + $to = $_REQUEST["to"] ?? ""; + $data = $_REQUEST["data"] ?? ""; + if (!$to || !$data) json_out(["error" => "Missing to/data"], 400); + + $sig = [ + "from" => $my_id, + "to" => $to, + "data" => json_decode($data, true), + "time" => now_ms() + ]; + + file_put_contents(room_log_file($room), json_encode($sig) . "\n", FILE_APPEND | LOCK_EX); + json_out(["success" => true]); +} + +if ($action === "list_all") { + // Periodic cleanup of the DB table (stale sessions > 15s) + if (rand(1, 10) === 1) { + try { + $stale_db_time = now_ms() - 15000; + $stmt = db()->prepare("DELETE FROM voice_sessions WHERE last_seen < ?"); + $stmt->execute([$stale_db_time]); + } catch (Exception $e) {} + } + + try { $stmt = db()->prepare(" SELECT vs.channel_id, vs.user_id, u.username, u.display_name, u.avatar_url FROM voice_sessions vs JOIN users u ON vs.user_id = u.id + WHERE vs.last_seen > ? "); - $stmt->execute(); - $sessions = $stmt->fetchAll(); - echo json_encode(['success' => true, 'sessions' => $sessions]); - exit; + $stale_db_time = now_ms() - 15000; + $stmt->execute([$stale_db_time]); + $sessions = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $by_channel = []; + foreach ($sessions as $s) { + $by_channel[$s['channel_id']][] = $s; + } + json_out(["success" => true, "channels" => $by_channel]); + } catch (Exception $e) { + json_out(["error" => $e->getMessage()], 500); } } -echo json_encode(['success' => false, 'error' => 'Invalid request']); +if ($action === "leave") { + if ($my_id) { + $p_file = room_participants_file($room); + $ps = read_json_file($p_file); + unset($ps[$my_id]); + write_json_file($p_file, $ps); + } + if ($current_user_id > 0) { + try { + $stmt = db()->prepare("DELETE FROM voice_sessions WHERE user_id = ?"); + $stmt->execute([$current_user_id]); + } catch (Exception $e) {} + } + json_out(["success" => true]); +} + +json_out(["error" => "Unknown action"], 404); \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index 85259d2..454c3b1 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -457,6 +457,18 @@ document.addEventListener('DOMContentLoaded', () => { let ws; let voiceHandler; + if (typeof VoiceChannel !== 'undefined') { + voiceHandler = new VoiceChannel(null, window.voiceSettings); + window.voiceHandler = voiceHandler; + console.log('VoiceHandler initialized'); + + // Start global voice sessions polling + setInterval(() => { + VoiceChannel.refreshAllVoiceUsers(); + }, 3000); + VoiceChannel.refreshAllVoiceUsers(); + } + function connectWS() { console.log('Connecting to WebSocket...'); try { @@ -466,6 +478,7 @@ document.addEventListener('DOMContentLoaded', () => { ws.onopen = () => { console.log('WebSocket connected'); + if (voiceHandler) voiceHandler.ws = ws; ws.send(JSON.stringify({ type: 'presence', user_id: window.currentUserId, @@ -473,12 +486,6 @@ document.addEventListener('DOMContentLoaded', () => { })); }; - if (typeof VoiceChannel !== 'undefined') { - voiceHandler = new VoiceChannel(ws, window.voiceSettings); - window.voiceHandler = voiceHandler; - console.log('VoiceHandler initialized'); - } - ws.onmessage = (e) => { const msg = JSON.parse(e.data); @@ -665,11 +672,12 @@ document.addEventListener('DOMContentLoaded', () => { // Handle Click Events document.addEventListener('click', (e) => { + console.log('Global click at:', e.target); // Voice Channel Click const voiceItem = e.target.closest('.voice-item'); if (voiceItem) { e.preventDefault(); - console.log('Voice item clicked:', voiceItem.dataset.channelId); + console.log('Voice item clicked, Channel ID:', voiceItem.dataset.channelId); const channelId = voiceItem.dataset.channelId; if (voiceHandler) { if (voiceHandler.currentChannelId == channelId) { diff --git a/assets/js/voice.js b/assets/js/voice.js index 70b1169..abbb492 100644 --- a/assets/js/voice.js +++ b/assets/js/voice.js @@ -1,13 +1,17 @@ +console.log('voice.js loaded'); + class VoiceChannel { constructor(ws, settings) { - this.ws = ws; + // ws is ignored now as we use PHP signaling, but kept for compatibility this.settings = settings || { mode: 'vox', pttKey: 'v', voxThreshold: 0.1 }; + console.log('VoiceChannel constructor called with settings:', this.settings); this.localStream = null; - this.screenStream = null; this.peers = {}; // userId -> RTCPeerConnection - this.participants = {}; // userId -> {username, avatarUrl} + this.participants = {}; // userId -> {name} this.currentChannelId = null; - this.isScreenSharing = false; + this.myPeerId = null; + this.pollInterval = null; + this.remoteAudios = {}; // userId -> Audio element this.audioContext = null; this.analyser = null; @@ -18,7 +22,10 @@ class VoiceChannel { this.pttPressed = false; this.voxActive = false; this.lastVoiceTime = 0; - this.voxHoldTime = 500; // ms to keep open after sound drops below threshold + this.voxHoldTime = 500; + + // Track who is speaking to persist across UI refreshes + this.speakingUsers = new Set(); this.setupPTTListeners(); window.addEventListener('beforeunload', () => this.leave()); @@ -26,8 +33,12 @@ class VoiceChannel { setupPTTListeners() { window.addEventListener('keydown', (e) => { + // Ignore if in input field + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; + if (this.settings.mode === 'ptt' && e.key.toLowerCase() === this.settings.pttKey.toLowerCase()) { if (!this.pttPressed) { + console.log('PTT Key Pressed:', e.key); this.pttPressed = true; this.updateMuteState(); } @@ -36,6 +47,7 @@ class VoiceChannel { window.addEventListener('keyup', (e) => { if (this.settings.mode === 'ptt' && e.key.toLowerCase() === this.settings.pttKey.toLowerCase()) { + console.log('PTT Key Released:', e.key); this.pttPressed = false; this.updateMuteState(); } @@ -43,69 +55,209 @@ class VoiceChannel { } async join(channelId) { - console.log('VoiceChannel.join called for channel:', channelId); + console.log('VoiceChannel.join process started for channel:', channelId); if (this.currentChannelId === channelId) { console.log('Already in this channel'); return; } - - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { - console.error('WebSocket not connected. State:', this.ws ? this.ws.readyState : 'null'); - alert('Unable to join voice: Connection to signaling server not established. Please wait a few seconds and try again.'); - return; + if (this.currentChannelId) { + console.log('Leaving previous channel:', this.currentChannelId); + this.leave(); } - if (this.currentChannelId) this.leave(); - - console.log('Joining voice channel:', channelId); this.currentChannelId = channelId; try { - if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { - throw new Error('Microphone access is only available on secure origins (HTTPS).'); - } + console.log('Requesting microphone access...'); this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); - - // Start muted + console.log('Microphone access granted'); this.setMute(true); if (this.settings.mode === 'vox') { this.setupVOX(); } - // Persist in DB - const fd = new FormData(); - fd.append('action', 'join'); - fd.append('channel_id', channelId); - fetch('api_v1_voice.php', { method: 'POST', body: fd }); + // Join via PHP + console.log('Calling API join...'); + const url = `api_v1_voice.php?action=join&room=${channelId}&name=${encodeURIComponent(window.currentUsername || 'Unknown')}`; + const resp = await fetch(url); + const data = await resp.json(); + console.log('API join response:', data); - this.ws.send(JSON.stringify({ - type: 'voice_join', - channel_id: channelId, - user_id: window.currentUserId, - username: window.currentUsername, - avatar_url: window.currentAvatarUrl - })); - - this.updateVoiceUI(); + if (data.success) { + this.myPeerId = data.peer_id; + console.log('Joined room with peer_id:', this.myPeerId); + + // Start polling + this.startPolling(); + this.updateVoiceUI(); + } else { + console.error('API join failed:', data.error); + } } catch (e) { - console.error('Failed to get local stream:', e); - alert('Could not access microphone.'); + console.error('Failed to join voice:', e); + alert('Microphone access required for voice channels. Error: ' + e.message); this.currentChannelId = null; } } + startPolling() { + if (this.pollInterval) clearInterval(this.pollInterval); + this.pollInterval = setInterval(() => this.poll(), 1000); + this.poll(); // Initial poll + } + + async poll() { + if (!this.myPeerId || !this.currentChannelId) return; + + try { + const resp = await fetch(`api_v1_voice.php?action=poll&room=${this.currentChannelId}&peer_id=${this.myPeerId}`); + const data = await resp.json(); + + if (data.success) { + // Update participants + const oldPs = Object.keys(this.participants); + this.participants = data.participants; + const newPs = Object.keys(this.participants); + + // If new people joined, initiate offer if I'm the "older" one (not really necessary here, can just offer to anyone I don't have a peer for) + newPs.forEach(pid => { + if (pid !== this.myPeerId && !this.peers[pid]) { + console.log('New peer found via poll:', pid); + this.createPeerConnection(pid, true); + } + }); + + // Cleanup left peers + oldPs.forEach(pid => { + if (!this.participants[pid] && this.peers[pid]) { + console.log('Peer left:', pid); + this.peers[pid].close(); + delete this.peers[pid]; + } + }); + + // Handle incoming signals + if (data.signals && data.signals.length > 0) { + for (const sig of data.signals) { + await this.handleSignaling(sig); + } + } + + this.updateVoiceUI(); + } + } catch (e) { + console.error('Polling error:', e); + } + } + + async sendSignal(to, data) { + if (!this.myPeerId || !this.currentChannelId) return; + await fetch(`api_v1_voice.php?action=signal&room=${this.currentChannelId}&peer_id=${this.myPeerId}&to=${to}&data=${encodeURIComponent(JSON.stringify(data))}`); + } + + createPeerConnection(userId, isOfferor) { + if (this.peers[userId]) return this.peers[userId]; + + console.log('Creating PeerConnection for:', userId, 'as offeror:', isOfferor); + const pc = new RTCPeerConnection({ + iceServers: [ + { urls: 'stun:stun.l.google.com:19302' }, + { urls: 'stun:stun1.l.google.com:19302' } + ] + }); + + this.peers[userId] = pc; + + pc.oniceconnectionstatechange = () => { + console.log(`ICE Connection State with ${userId}: ${pc.iceConnectionState}`); + }; + + if (this.localStream) { + this.localStream.getTracks().forEach(track => { + console.log(`Adding track ${track.kind} to peer ${userId}`); + pc.addTrack(track, this.localStream); + }); + } + + pc.onicecandidate = (event) => { + if (event.candidate) { + this.sendSignal(userId, { type: 'ice_candidate', candidate: event.candidate }); + } + }; + + pc.ontrack = (event) => { + console.log('Received remote track from:', userId, event); + if (this.remoteAudios[userId]) { + this.remoteAudios[userId].pause(); + this.remoteAudios[userId].remove(); + this.remoteAudios[userId].srcObject = null; + } + const remoteAudio = new Audio(); + remoteAudio.style.display = 'none'; + remoteAudio.srcObject = event.streams[0]; + document.body.appendChild(remoteAudio); + this.remoteAudios[userId] = remoteAudio; + remoteAudio.play().catch(e => console.warn('Autoplay prevented:', e)); + }; + + if (isOfferor) { + pc.createOffer().then(offer => { + return pc.setLocalDescription(offer); + }).then(() => { + this.sendSignal(userId, { type: 'offer', offer: pc.localDescription }); + }); + } + + return pc; + } + + async handleSignaling(sig) { + const from = sig.from; + const data = sig.data; + + console.log('Handling signaling from:', from, 'type:', data.type); + + switch (data.type) { + case 'offer': + await this.handleOffer(from, data.offer); + break; + case 'answer': + await this.handleAnswer(from, data.answer); + break; + case 'ice_candidate': + await this.handleCandidate(from, data.candidate); + break; + case 'voice_speaking': + this.updateSpeakingUI(data.user_id, data.speaking); + break; + } + } + + async handleOffer(from, offer) { + const pc = this.createPeerConnection(from, false); + await pc.setRemoteDescription(new RTCSessionDescription(offer)); + const answer = await pc.createAnswer(); + await pc.setLocalDescription(answer); + this.sendSignal(from, { type: 'answer', answer: pc.localDescription }); + } + + async handleAnswer(from, answer) { + const pc = this.peers[from]; + if (pc) await pc.setRemoteDescription(new RTCSessionDescription(answer)); + } + + async handleCandidate(from, candidate) { + const pc = this.peers[from]; + if (pc) await pc.addIceCandidate(new RTCIceCandidate(candidate)); + } + setupVOX() { if (this.audioContext) this.audioContext.close(); - this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.analyser = this.audioContext.createAnalyser(); this.microphone = this.audioContext.createMediaStreamSource(this.localStream); this.scriptProcessor = this.audioContext.createScriptProcessor(2048, 1, 1); - - this.analyser.smoothingTimeConstant = 0.8; - this.analyser.fftSize = 1024; - this.microphone.connect(this.analyser); this.analyser.connect(this.scriptProcessor); this.scriptProcessor.connect(this.audioContext.destination); @@ -114,13 +266,13 @@ class VoiceChannel { const array = new Uint8Array(this.analyser.frequencyBinCount); this.analyser.getByteFrequencyData(array); let values = 0; - for (let i = 0; i < array.length; i++) { - values += array[i]; - } + for (let i = 0; i < array.length; i++) values += array[i]; const average = values / array.length; - const normalized = average / 128; // 0 to 2 approx + + // Log sometimes for debugging VOX + if (Math.random() < 0.01) console.log('VOX Avg:', average, 'Threshold:', this.settings.voxThreshold * 255); - if (normalized > this.settings.voxThreshold) { + if (average > (this.settings.voxThreshold * 255)) { this.lastVoiceTime = Date.now(); if (!this.voxActive) { this.voxActive = true; @@ -137,207 +289,69 @@ class VoiceChannel { updateMuteState() { if (!this.currentChannelId || !this.localStream) return; - - let shouldTalk = false; - if (this.settings.mode === 'ptt') { - shouldTalk = this.pttPressed; - } else { - shouldTalk = this.voxActive; - } - + let shouldTalk = (this.settings.mode === 'ptt') ? this.pttPressed : this.voxActive; + console.log('updateMuteState: shouldTalk =', shouldTalk, 'mode =', this.settings.mode); if (this.isTalking !== shouldTalk) { this.isTalking = shouldTalk; this.setMute(!shouldTalk); - - // Notify others - this.ws.send(JSON.stringify({ - type: 'voice_speaking', - channel_id: this.currentChannelId, - user_id: window.currentUserId, - speaking: shouldTalk - })); - this.updateSpeakingUI(window.currentUserId, shouldTalk); + + // Notify others + const msg = { type: 'voice_speaking', channel_id: this.currentChannelId, user_id: window.currentUserId, speaking: shouldTalk }; + // ... (rest of method remains same, but I'll update it for clarity) + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(msg)); + } else { + Object.keys(this.peers).forEach(pid => { + this.sendSignal(pid, msg); + }); + } } } setMute(mute) { if (this.localStream) { - this.localStream.getAudioTracks().forEach(track => { - track.enabled = !mute; - }); + console.log('Setting mute to:', mute); + this.localStream.getAudioTracks().forEach(track => { track.enabled = !mute; }); } } leave() { if (!this.currentChannelId) return; - - this.stopScreenShare(); - - // Persist in DB - const fd = new FormData(); - fd.append('action', 'leave'); - fetch('api_v1_voice.php', { method: 'POST', body: fd }); - - this.ws.send(JSON.stringify({ - type: 'voice_leave', - channel_id: this.currentChannelId, - user_id: window.currentUserId - })); + console.log('Leaving voice channel:', this.currentChannelId); + if (this.pollInterval) clearInterval(this.pollInterval); + + fetch(`api_v1_voice.php?action=leave&room=${this.currentChannelId}&peer_id=${this.myPeerId}`); if (this.localStream) { this.localStream.getTracks().forEach(track => track.stop()); this.localStream = null; } - if (this.audioContext) { this.audioContext.close(); this.audioContext = null; } Object.values(this.peers).forEach(pc => pc.close()); + Object.values(this.remoteAudios).forEach(audio => { + audio.pause(); + audio.remove(); + audio.srcObject = null; + }); this.peers = {}; + this.remoteAudios = {}; this.participants = {}; this.currentChannelId = null; - this.isTalking = false; + this.myPeerId = null; + this.speakingUsers.clear(); this.updateVoiceUI(); } - async handleSignaling(data) { - const { type, from, to, offer, answer, candidate, channel_id, username, avatar_url, speaking } = data; - - if (channel_id != this.currentChannelId) return; - if (to && to != window.currentUserId) return; - - switch (type) { - case 'voice_join': - if (from != window.currentUserId) { - this.participants[from] = { username: username || `User ${from}`, avatar_url: avatar_url }; - this.createPeerConnection(from, true); - this.updateVoiceUI(); - } - break; - case 'voice_offer': - this.participants[from] = { username: username || `User ${from}`, avatar_url: avatar_url }; - await this.handleOffer(from, offer); - this.updateVoiceUI(); - break; - case 'voice_answer': - await this.handleAnswer(from, answer); - break; - case 'voice_ice_candidate': - await this.handleCandidate(from, candidate); - break; - case 'voice_speaking': - this.updateSpeakingUI(from, speaking); - break; - case 'voice_leave': - if (this.peers[from]) { - this.peers[from].close(); - delete this.peers[from]; - } - delete this.participants[from]; - this.updateVoiceUI(); - break; - } - } - - createPeerConnection(userId, isOfferor) { - if (this.peers[userId]) return this.peers[userId]; - - const pc = new RTCPeerConnection({ - iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] - }); - - this.peers[userId] = pc; - - if (this.localStream) { - this.localStream.getTracks().forEach(track => { - pc.addTrack(track, this.localStream); - }); - } - - pc.onicecandidate = (event) => { - if (event.candidate) { - this.ws.send(JSON.stringify({ - type: 'voice_ice_candidate', - to: userId, - from: window.currentUserId, - candidate: event.candidate, - channel_id: this.currentChannelId - })); - } - }; - - pc.ontrack = (event) => { - if (event.track.kind === 'audio') { - const remoteAudio = new Audio(); - remoteAudio.srcObject = event.streams[0]; - remoteAudio.play(); - } - }; - - if (isOfferor) { - pc.createOffer().then(offer => { - return pc.setLocalDescription(offer); - }).then(() => { - this.ws.send(JSON.stringify({ - type: 'voice_offer', - to: userId, - from: window.currentUserId, - username: window.currentUsername, - avatar_url: window.currentAvatarUrl, - offer: pc.localDescription, - channel_id: this.currentChannelId - })); - }); - } - - return pc; - } - - async handleOffer(from, offer) { - const pc = this.createPeerConnection(from, false); - await pc.setRemoteDescription(new RTCSessionDescription(offer)); - const answer = await pc.createAnswer(); - await pc.setLocalDescription(answer); - this.ws.send(JSON.stringify({ - type: 'voice_answer', - to: from, - from: window.currentUserId, - answer: pc.localDescription, - channel_id: this.currentChannelId - })); - } - - async handleAnswer(from, answer) { - const pc = this.peers[from]; - if (pc) await pc.setRemoteDescription(new RTCSessionDescription(answer)); - } - - async handleCandidate(from, candidate) { - const pc = this.peers[from]; - if (pc) await pc.addIceCandidate(new RTCIceCandidate(candidate)); - } - updateVoiceUI() { - document.querySelectorAll('.voice-users-list').forEach(el => el.innerHTML = ''); - - // Fetch all sessions to update all channels (or just rely on signaling for current one) - // For simplicity, we update the current channel from participants - if (this.currentChannelId) { - const listEls = document.querySelectorAll(`.voice-item[data-channel-id="${this.currentChannelId}"] + .voice-users-list`); - listEls.forEach(listEl => { - // Me - this.addVoiceUserToUI(listEl, window.currentUserId, window.currentUsername, window.currentAvatarUrl); - - // Others - Object.entries(this.participants).forEach(([uid, data]) => { - this.addVoiceUserToUI(listEl, uid, data.username, data.avatar_url); - }); - }); + // We now use a global update mechanism for all channels + VoiceChannel.refreshAllVoiceUsers(); - // Voice controls + if (this.currentChannelId) { if (!document.querySelector('.voice-controls')) { const controls = document.createElement('div'); controls.className = 'voice-controls p-2 d-flex justify-content-between align-items-center border-top bg-dark'; @@ -345,7 +359,7 @@ class VoiceChannel { controls.innerHTML = `
-
Voice Connected
+
Voice (${this.settings.mode.toUpperCase()})
`; - document.querySelector('.channels-sidebar').appendChild(controls); - document.getElementById('btn-voice-leave').onclick = () => this.leave(); + const sidebar = document.querySelector('.channels-sidebar'); + if (sidebar) sidebar.appendChild(controls); + const btnLeave = document.getElementById('btn-voice-leave'); + if (btnLeave) btnLeave.onclick = () => this.leave(); } } else { const controls = document.querySelector('.voice-controls'); @@ -362,38 +378,64 @@ class VoiceChannel { } } - addVoiceUserToUI(container, userId, username, avatarUrl) { - const userEl = document.createElement('div'); - userEl.className = 'voice-user small d-flex align-items-center mb-1'; - userEl.dataset.userId = userId; - userEl.style.paddingLeft = '8px'; - userEl.innerHTML = ` -
- ${username} - `; - container.appendChild(userEl); - } - updateSpeakingUI(userId, isSpeaking) { + if (isSpeaking) { + this.speakingUsers.add(userId); + } else { + this.speakingUsers.delete(userId); + } + const userEls = document.querySelectorAll(`.voice-user[data-user-id="${userId}"]`); userEls.forEach(el => { const avatar = el.querySelector('.message-avatar'); if (avatar) { - if (isSpeaking) { - avatar.style.boxShadow = '0 0 0 2px #23a559'; - } else { - avatar.style.boxShadow = 'none'; - } + avatar.style.boxShadow = isSpeaking ? '0 0 0 2px #23a559' : 'none'; } }); } - stopScreenShare() { - // Not requested but kept for compatibility - if (this.screenStream) { - this.screenStream.getTracks().forEach(track => track.stop()); - this.screenStream = null; + static async refreshAllVoiceUsers() { + try { + const resp = await fetch('api_v1_voice.php?action=list_all'); + const data = await resp.json(); + if (data.success) { + // Clear all lists first + document.querySelectorAll('.voice-users-list').forEach(el => el.innerHTML = ''); + + // Populate based on data + Object.keys(data.channels).forEach(channelId => { + // Fix: The voice-users-list is a sibling of the container of the voice-item + const voiceItem = document.querySelector(`.voice-item[data-channel-id="${channelId}"]`); + if (voiceItem) { + const container = voiceItem.closest('.channel-item-container'); + if (container) { + const listEl = container.querySelector('.voice-users-list'); + if (listEl) { + data.channels[channelId].forEach(p => { + const isSpeaking = window.voiceHandler && window.voiceHandler.speakingUsers.has(p.user_id); + VoiceChannel.renderUserToUI(listEl, p.user_id, p.display_name || p.username, p.avatar_url, isSpeaking); + }); + } + } + } + }); + } + } catch (e) { + console.error('Failed to refresh voice users:', e); } - this.isScreenSharing = false; + } + + static renderUserToUI(container, userId, username, avatarUrl, isSpeaking = false) { + const userEl = document.createElement('div'); + userEl.className = 'voice-user small text-muted d-flex align-items-center mb-1'; + userEl.dataset.userId = userId; + userEl.style.paddingLeft = '8px'; + const avatarStyle = avatarUrl ? `background-image: url('${avatarUrl}'); background-size: cover;` : "background-color: #555;"; + const boxShadow = isSpeaking ? 'box-shadow: 0 0 0 2px #23a559;' : ''; + userEl.innerHTML = ` +
+ ${username} + `; + container.appendChild(userEl); } } diff --git a/assets/pasted-20260217-141526-2008a77e.png b/assets/pasted-20260217-141526-2008a77e.png new file mode 100644 index 0000000000000000000000000000000000000000..544a593272b925cdf6d82635aa716a02a03a9edc GIT binary patch literal 49460 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 A<^TWy literal 0 HcmV?d00001 diff --git a/assets/pasted-20260217-143739-c7f88b4b.png b/assets/pasted-20260217-143739-c7f88b4b.png new file mode 100644 index 0000000000000000000000000000000000000000..3e0114782de2517d8ab2553b0012f29e4be7e6e2 GIT binary patch literal 46718 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 OICL}+@G7+jPyYi`^~X^F literal 0 HcmV?d00001 diff --git a/data/22.log b/data/22.log new file mode 100644 index 0000000..96c6b9e --- /dev/null +++ b/data/22.log @@ -0,0 +1,2 @@ +{"from":"a0645f38fb2bbdb5","to":"1ca650259dcce60e","data":{"type":"voice_speaking","channel_id":"22","user_id":3,"speaking":true},"time":1771339536024} +{"from":"a0645f38fb2bbdb5","to":"1ca650259dcce60e","data":{"type":"voice_speaking","channel_id":"22","user_id":3,"speaking":false},"time":1771339536956} diff --git a/data/22.participants.json b/data/22.participants.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/data/22.participants.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/data/3.log b/data/3.log new file mode 100644 index 0000000..16d88e7 --- /dev/null +++ b/data/3.log @@ -0,0 +1,8 @@ +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"offer","offer":{"type":"offer","sdp":"v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 2993514939591859431 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 E9:89:B8:DE:41:F8:AD:79:17:A8:4D:03:2D:53:FC:15:5A:3B:B4:CA:45:A6:F7:EB:C7:F0:01:7C:0B:29:91:F1\r\na=group:BUNDLE 0\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 109 9 0 8 101\r\nc=IN IP4 0.0.0.0\r\na=sendrecv\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2\/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap-allow-mixed\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:cacccb2562e0f73ce1667f9773fb670d\r\na=ice-ufrag:2b377091\r\na=mid:0\r\na=msid:{5d44acc3-9af3-4110-98ed-2de218fc7450} {ed9d31cb-0fc7-497e-8c79-4cc9159d5f97}\r\na=rtcp-mux\r\na=rtpmap:109 opus\/48000\/2\r\na=rtpmap:9 G722\/8000\/1\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:101 telephone-event\/8000\r\na=setup:actpass\r\na=ssrc:2872346815 cname:{74df363a-4160-4031-a110-5285ddfe55ff}\r\n"}},"time":1771339604154} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:0 1 UDP 2122252543 192.168.26.26 61807 typ host","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604155} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:2 1 TCP 2105524479 192.168.26.26 9 typ host tcptype active","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604161} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:2 2 TCP 2105524478 192.168.26.26 9 typ host tcptype active","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604164} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:0 2 UDP 2122252542 192.168.26.26 61808 typ host","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604170} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604171} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 1 UDP 1686052863 78.246.210.10 30532 typ srflx raddr 192.168.26.26 rport 61807","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604172} +{"from":"9afce7ba24e9091b","to":"a39fca0ca87f4e62","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 2 UDP 1686052862 78.246.210.10 30534 typ srflx raddr 192.168.26.26 rport 61808","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"2b377091"}},"time":1771339604175} diff --git a/data/3.participants.json b/data/3.participants.json new file mode 100644 index 0000000..942c50d --- /dev/null +++ b/data/3.participants.json @@ -0,0 +1 @@ +{"1e0fff021b7ad021":{"id":"1e0fff021b7ad021","user_id":3,"name":"swefheim","avatar_url":"","last_seen":1771339631904},"9afce7ba24e9091b":{"id":"9afce7ba24e9091b","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771339632155}} \ No newline at end of file diff --git a/data/6.log b/data/6.log new file mode 100644 index 0000000..e9bcc14 --- /dev/null +++ b/data/6.log @@ -0,0 +1,10 @@ +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"offer","offer":{"type":"offer","sdp":"v=0\r\no=mozilla...THIS_IS_SDPARTA-99.0 1705174900585877835 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 AA:37:B9:FA:14:15:DC:34:29:97:DC:55:77:28:8E:74:C0:94:15:08:DF:5B:E9:CC:36:81:E5:D9:5C:49:FB:46\r\na=group:BUNDLE 0\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 109 9 0 8 101\r\nc=IN IP4 0.0.0.0\r\na=sendrecv\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2\/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap-allow-mixed\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:075627a25c9f07d3908305504803057d\r\na=ice-ufrag:03d0add1\r\na=mid:0\r\na=msid:{7a2c5afc-d053-43fd-9196-3caf4510feb3} {8439b857-ead8-4cb1-8111-cb3400348461}\r\na=rtcp-mux\r\na=rtpmap:109 opus\/48000\/2\r\na=rtpmap:9 G722\/8000\/1\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:101 telephone-event\/8000\r\na=setup:actpass\r\na=ssrc:1663488241 cname:{7dcb8038-2b50-4e42-827c-c4617a225c01}\r\n"}},"time":1771336456644} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:0 1 UDP 2122252543 192.168.26.26 62572 typ host","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456645} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:2 1 TCP 2105524479 192.168.26.26 9 typ host tcptype active","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456647} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:2 2 TCP 2105524478 192.168.26.26 9 typ host tcptype active","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456652} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:0 2 UDP 2122252542 192.168.26.26 62573 typ host","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456654} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 1 UDP 1686052351 78.246.210.10 31184 typ srflx raddr 192.168.26.26 rport 62572","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456720} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 2 UDP 1686052350 78.246.210.10 31185 typ srflx raddr 192.168.26.26 rport 62573","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456757} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 1 UDP 1686052863 78.246.210.10 31184 typ srflx raddr 192.168.26.26 rport 62572","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456776} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"candidate:1 2 UDP 1686052862 78.246.210.10 31185 typ srflx raddr 192.168.26.26 rport 62573","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456802} +{"from":"75b3938d276e81e1","to":"0cce3619c0f299fa","data":{"type":"ice_candidate","candidate":{"candidate":"","sdpMLineIndex":0,"sdpMid":"0","usernameFragment":"03d0add1"}},"time":1771336456805} diff --git a/data/6.participants.json b/data/6.participants.json new file mode 100644 index 0000000..2879778 --- /dev/null +++ b/data/6.participants.json @@ -0,0 +1 @@ +{"0cce3619c0f299fa":{"id":"0cce3619c0f299fa","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771336452806},"75b3938d276e81e1":{"id":"75b3938d276e81e1","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771336462293}} \ No newline at end of file diff --git a/data/test.participants.json b/data/test.participants.json new file mode 100644 index 0000000..f1d0f40 --- /dev/null +++ b/data/test.participants.json @@ -0,0 +1 @@ +{"0fbf720bc2f110c0":{"id":"0fbf720bc2f110c0","name":"AI","last_seen":1771336229774}} \ No newline at end of file diff --git a/data/test.txt b/data/test.txt new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/data/test.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/data/test_www.txt b/data/test_www.txt new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/data/test_www.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/index.php b/index.php index d820167..82fc216 100644 --- a/index.php +++ b/index.php @@ -507,29 +507,46 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; return; } ?> -