diff --git a/api_v1_voice.php b/api_v1_voice.php index 67ca1c7..dd125d4 100644 --- a/api_v1_voice.php +++ b/api_v1_voice.php @@ -156,22 +156,36 @@ if ($action === "poll") { } catch (Exception $e) {} } - // Read signals - $log_file = room_log_file($room); + // Read signals from DB $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; + try { + $stmt = db()->prepare("SELECT id, from_peer_id as `from`, data FROM voice_signals WHERE to_peer_id = ? ORDER BY id ASC"); + $stmt->execute([$my_id]); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (!empty($rows)) { + $ids = []; + foreach ($rows as $r) { + $signals[] = [ + "from" => $r["from"], + "data" => json_decode($r["data"], true) + ]; + $ids[] = $r["id"]; } + // Delete signals we just read + $placeholders = implode(',', array_fill(0, count($ids), '?')); + $stmt_del = db()->prepare("DELETE FROM voice_signals WHERE id IN ($placeholders)"); + $stmt_del->execute($ids); } - file_put_contents($log_file, implode("\n", $remaining) . (empty($remaining) ? "" : "\n"), LOCK_EX); + + // Periodic cleanup of old signals (> 1 minute) + if (rand(1, 20) === 1) { + $old_time = now_ms() - 60000; + $stmt_clean = db()->prepare("DELETE FROM voice_signals WHERE created_at_ms < ?"); + $stmt_clean->execute([$old_time]); + } + } catch (Exception $e) { + error_log("Signal poll error: " . $e->getMessage()); } json_out(["success" => true, "participants" => $ps, "signals" => $signals]); @@ -183,15 +197,13 @@ if ($action === "signal") { $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]); + try { + $stmt = db()->prepare("INSERT INTO voice_signals (room_id, from_peer_id, to_peer_id, data, created_at_ms) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$room, $my_id, $to, $data, now_ms()]); + json_out(["success" => true]); + } catch (Exception $e) { + json_out(["error" => "Signal send failed: " . $e->getMessage()], 500); + } } if ($action === "list_all") { diff --git a/assets/js/voice.js b/assets/js/voice.js index 329eded..fa78177 100644 --- a/assets/js/voice.js +++ b/assets/js/voice.js @@ -216,18 +216,31 @@ class VoiceChannel { }; pc.ontrack = (event) => { - console.log('Received remote track from:', userId, event); + console.log('Received remote track from:', userId, 'Stream count:', event.streams.length); + const stream = event.streams[0] || new MediaStream([event.track]); + if (this.remoteAudios[userId]) { + console.log('Replacing existing audio element for:', userId); this.remoteAudios[userId].pause(); - this.remoteAudios[userId].remove(); this.remoteAudios[userId].srcObject = null; + this.remoteAudios[userId].remove(); } + const remoteAudio = new Audio(); + remoteAudio.autoplay = true; remoteAudio.style.display = 'none'; - remoteAudio.srcObject = event.streams[0]; + remoteAudio.srcObject = stream; document.body.appendChild(remoteAudio); this.remoteAudios[userId] = remoteAudio; - remoteAudio.play().catch(e => console.warn('Autoplay prevented:', e)); + + console.log('Playing remote audio for:', userId); + remoteAudio.play().then(() => { + console.log('Remote audio playing successfully for:', userId); + }).catch(e => { + console.warn('Autoplay prevented or play failed for:', userId, e); + // In case of autoplay prevention, we might need a user gesture, + // but they just clicked a channel so it should be fine. + }); }; if (isOfferor) { @@ -454,6 +467,10 @@ class VoiceChannel { this.currentChannelId = null; this.myPeerId = null; this.speakingUsers.clear(); + + // Also remove 'active' class from all voice items + document.querySelectorAll('.voice-item').forEach(el => el.classList.remove('active')); + this.updateVoiceUI(); } @@ -521,8 +538,10 @@ class VoiceChannel { Object.keys(data.channels).forEach(channelId => { const voiceItem = document.querySelector(`.voice-item[data-channel-id="${channelId}"]`); if (voiceItem) { - // Highlight channel as connected if anyone is in it + // Highlight channel as connected only if I am in it + if (window.voiceHandler && window.voiceHandler.currentChannelId == channelId) { voiceItem.classList.add('connected'); + } const container = voiceItem.closest('.channel-item-container'); if (container) { diff --git a/assets/pasted-20260218-191112-132e95c8.png b/assets/pasted-20260218-191112-132e95c8.png new file mode 100644 index 0000000..642e98e Binary files /dev/null and b/assets/pasted-20260218-191112-132e95c8.png differ diff --git a/data/3.participants.json b/data/3.participants.json index a5beed1..482cef5 100644 --- a/data/3.participants.json +++ b/data/3.participants.json @@ -1 +1 @@ -{"3356a3073b77f72d":{"id":"3356a3073b77f72d","user_id":3,"name":"swefheim","avatar_url":"","last_seen":1771441757997},"d58aa0268cc9e8d0":{"id":"d58aa0268cc9e8d0","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771441758062}} \ No newline at end of file +{"b9cd47d7dce5c259":{"id":"b9cd47d7dce5c259","user_id":3,"name":"swefheim","avatar_url":"","last_seen":1771442163346},"28ab267700c18621":{"id":"28ab267700c18621","user_id":2,"name":"swefpifh ᵇʰᶠʳ","avatar_url":"","last_seen":1771442163368}} \ No newline at end of file diff --git a/db/migrations/20260218_voice_signals.sql b/db/migrations/20260218_voice_signals.sql new file mode 100644 index 0000000..a512415 --- /dev/null +++ b/db/migrations/20260218_voice_signals.sql @@ -0,0 +1,11 @@ +-- Create voice_signals table for reliable signaling +CREATE TABLE IF NOT EXISTS voice_signals ( + id INT AUTO_INCREMENT PRIMARY KEY, + room_id VARCHAR(50) NOT NULL, + from_peer_id VARCHAR(16) NOT NULL, + to_peer_id VARCHAR(16) NOT NULL, + data TEXT NOT NULL, + created_at_ms BIGINT NOT NULL, + INDEX (to_peer_id), + INDEX (created_at_ms) +); diff --git a/requests.log b/requests.log index 83a0242..0e56ebd 100644 --- a/requests.log +++ b/requests.log @@ -676,3 +676,11 @@ 2026-02-18 19:06:59 - GET /index.php - POST: [] 2026-02-18 19:07:22 - GET /index.php - POST: [] 2026-02-18 19:08:00 - GET /index.php?server_id=1&channel_id=6 - POST: [] +2026-02-18 19:11:46 - GET /index.php - POST: [] +2026-02-18 19:13:10 - GET /?fl_project=38443 - POST: [] +2026-02-18 19:14:15 - GET /index.php - POST: [] +2026-02-18 19:14:22 - GET /index.php - POST: [] +2026-02-18 19:14:31 - GET /index.php - POST: [] +2026-02-18 19:15:26 - GET /index.php - POST: [] +2026-02-18 19:15:30 - GET /index.php - POST: [] +2026-02-18 19:15:31 - GET /index.php - POST: []