déconnexion du canal vocal

This commit is contained in:
Flatlogic Bot 2026-02-18 19:16:04 +00:00
parent e6a755b1d6
commit 04e745874e
6 changed files with 78 additions and 28 deletions

View File

@ -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") {

View File

@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -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}}
{"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}}

View File

@ -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)
);

View File

@ -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: []