123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- <!-- templates/room.html -->
- <!DOCTYPE html>
- <html>
- <head>
- <title>语音聊天室 - {{ room_id }}</title>
- <!-- 中文-->
- <meta charset="UTF-8"></meta>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
- </head>
- <body>
- <h1>语音聊天室 {{ room_id }}</h1>
- <button id="micButton" onclick="toggleMic()">🎤 点击说话</button>
- <div id="status"></div>
- <script>
- const room_id = "{{ room_id }}";
- let isMute = true;
- let localStream;
- let socket = io();
- const peers = {};
- // 初始化WebSocket连接
- socket.on("connect", () => {
- socket.emit("join", {room: room_id});
- });
- // 获取麦克风权限
- async function init() {
- try {
- localStream = await navigator.mediaDevices.getUserMedia({
- audio: true,
- });
- document.getElementById("status").innerHTML = "麦克风已就绪";
- document.getElementById("micButton").disabled = false;
- } catch (err) {
- console.error("Error accessing microphone:", err);
- document.getElementById("status").innerHTML = "无法访问麦克风: " + err.message;
- document.getElementById("micButton").disabled = true;
- }
- }
- // 切换麦克风状态
- async function toggleMic() {
- if (!localStream) {
- console.error("No localStream available");
- document.getElementById("status").innerHTML = "麦克风未就绪,请刷新页面重试";
- return;
- }
- isMute = !isMute;
- const button = document.getElementById("micButton");
- button.textContent = isMute ? "🎤 点击说话" : "🔴 正在说话";
- localStream
- .getAudioTracks()
- .forEach((track) => (track.enabled = !isMute));
- if (!isMute) {
- const peer = new RTCPeerConnection();
- peers[socket.id] = peer;
- localStream
- .getTracks()
- .forEach((track) => peer.addTrack(track, localStream));
- peer.onicecandidate = (e) => {
- if (e.candidate) {
- socket.emit("candidate", {
- candidate: e.candidate,
- room: room_id,
- target: socket.id, // 添加目标标识
- });
- }
- };
- try {
- const offer = await peer.createOffer();
- await peer.setLocalDescription(offer);
- socket.emit("offer", {
- sdp: offer,
- room: room_id, // 使用room字段
- });
- } catch (err) {
- console.error("Error creating or sending offer:", err);
- document.getElementById("status").innerHTML = "创建连接时出错,请刷新页面重试";
- }
- }
- }
- // WebRTC信令处理
- socket.on("offer", async (data) => {
- // 添加发送者过滤
- if (data.sender === socket.id) return;
- const peer = new RTCPeerConnection();
- peers[data.sender] = peer;
- peer.onicecandidate = (e) => {
- if (e.candidate) {
- socket.emit("candidate", {
- candidate: e.candidate,
- target: data.sender,
- room: room_id,
- });
- }
- };
- peer.ontrack = (e) => {
- const audio = document.createElement("audio");
- audio.srcObject = e.streams[0];
- audio.play();
- };
- await peer.setRemoteDescription(data.sdp);
- const answer = await peer.createAnswer();
- await peer.setLocalDescription(answer);
- socket.emit("answer", {
- sdp: answer,
- target: data.sender, // 指定目标用户
- room: room_id,
- });
- });
- socket.on("answer", (data) => {
- if (data.sender === socket.id) return;
- const peer = peers[data.sender];
- if (peer) {
- peer.setRemoteDescription(data.sdp);
- }
- });
- // 修改candidate处理逻辑
- socket.on("candidate", (data) => {
- if (data.sender === socket.id) return;
- const peer = peers[data.sender];
- peer.addIceCandidate(new RTCIceCandidate(data.candidate));
- });
- init();
- </script>
- </body>
- </html>
|