0) { try { $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id, peer_id, name, last_seen) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE channel_id = ?, peer_id = ?, name = ?, last_seen = ?"); $stmt->execute([$current_user_id, $room, $new_id, $name, now_ms(), $room, $new_id, $name, now_ms()]); } catch (Exception $e) { json_out(["error" => "DB Error: " . $e->getMessage()], 500); } } else { json_out(["error" => "Not logged in"], 401); } // Fetch all participants in this room $ps = []; try { $stmt = db()->prepare("SELECT vs.*, u.avatar_url FROM voice_sessions vs JOIN users u ON vs.user_id = u.id WHERE vs.channel_id = ? AND vs.last_seen > ?"); $stmt->execute([$room, now_ms() - 7000]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { $ps[$row["peer_id"]] = [ "id" => $row["peer_id"], "user_id" => (int)$row["user_id"], "name" => $row["name"], "avatar_url" => $row["avatar_url"], "last_seen" => (int)$row["last_seen"] ]; } } 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); // Update last_seen if ($current_user_id > 0) { try { $stmt = db()->prepare("UPDATE voice_sessions SET last_seen = ? WHERE user_id = ? AND peer_id = ?"); $stmt->execute([now_ms(), $current_user_id, $my_id]); } catch (Exception $e) {} } // Fetch participants $ps = []; try { $stmt = db()->prepare("SELECT vs.*, u.avatar_url FROM voice_sessions vs JOIN users u ON vs.user_id = u.id WHERE vs.channel_id = ? AND vs.last_seen > ?"); $stmt->execute([$room, now_ms() - 7000]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { $ps[$row["peer_id"]] = [ "id" => $row["peer_id"], "user_id" => (int)$row["user_id"], "name" => $row["name"], "avatar_url" => $row["avatar_url"], "last_seen" => (int)$row["last_seen"] ]; } } catch (Exception $e) {} // Read signals $signals = []; try { $stmt = db()->prepare("SELECT * FROM voice_signals WHERE to_peer_id = ? AND room_id = ?"); $stmt->execute([$my_id, $room]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $ids_to_delete = []; foreach ($rows as $row) { $signals[] = [ "from" => $row["from_peer_id"], "to" => $row["to_peer_id"], "data" => json_decode($row["data"], true), "time" => (int)$row["created_at"] ]; $ids_to_delete[] = $row["id"]; } if (!empty($ids_to_delete)) { $placeholders = implode(',', array_fill(0, count($ids_to_delete), '?')); db()->prepare("DELETE FROM voice_signals WHERE id IN ($placeholders)")->execute($ids_to_delete); } // Occasional cleanup of old signals if (rand(1, 20) === 1) { $stale_sig = now_ms() - 60000; db()->prepare("DELETE FROM voice_signals WHERE created_at < ?")->execute([$stale_sig]); } } catch (Exception $e) {} 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); try { $stmt = db()->prepare("INSERT INTO voice_signals (room_id, from_peer_id, to_peer_id, data, created_at) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$room, $my_id, $to, $data, now_ms()]); } catch (Exception $e) { json_out(["error" => "Signal Error: " . $e->getMessage()], 500); } json_out(["success" => true]); } if ($action === "list_all") { 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 > ? "); $stale_db_time = now_ms() - 30000; $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); } } if ($action === "leave") { if ($my_id) { try { $stmt = db()->prepare("DELETE FROM voice_sessions WHERE peer_id = ?"); $stmt->execute([$my_id]); } catch (Exception $e) {} } elseif ($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);