index.html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>WebRTC 通话</title>
</head>
<body>
<button id="startCall">发起通话</button>
<button id="endCall" disabled>挂断通话</button>
<video id="localVideo" autoplay muted></video>
<video id="remoteVideo" autoplay></video>
<script>
let localStream;
let peerConnection;
const signalingServer = new WebSocket('ws://localhost:8080/ws');
// 获取本地媒体流
async function getMedia() {
try {
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
document.getElementById('localVideo').srcObject = localStream;
} catch (err) {
console.error('获取媒体设备失败:', err);
}
}
// 初始化 PeerConnection
function createPeerConnection() {
const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
peerConnection = new RTCPeerConnection(config);
// 添加本地流
localStream.getTracks().forEach(track => {
peerConnection.addTrack(track, localStream);
});
// 处理 ICE 候选
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
signalingServer.send(JSON.stringify({ type: 'candidate', candidate: event.candidate }));
}
};
// 处理远程流
peerConnection.ontrack = (event) => {
document.getElementById('remoteVideo').srcObject = event.streams[0];
};
}
// 发起通话按钮
document.getElementById('startCall').addEventListener('click', async () => {
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
signalingServer.send(JSON.stringify({ type: 'offer', offer }));
document.getElementById('startCall').disabled = true;
document.getElementById('endCall').disabled = false;
});
// 挂断按钮
document.getElementById('endCall').addEventListener('click', () => {
peerConnection.close();
peerConnection = null;
document.getElementById('startCall').disabled = false;
document.getElementById('endCall').disabled = true;
document.getElementById('remoteVideo').srcObject = null;
});
// 处理信令消息
signalingServer.onmessage = async (event) => {
const message = JSON.parse(event.data);
if (!peerConnection) createPeerConnection();
switch (message.type) {
case 'offer':
await peerConnection.setRemoteDescription(message.offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
signalingServer.send(JSON.stringify({ type: 'answer', answer }));
break;
case 'answer':
await peerConnection.setRemoteDescription(message.answer);
break;
case 'candidate':
await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
break;
}
};
async function start() {
await getMedia();
createPeerConnection();
}
start();
</script>
</body>
</html>
main.go
// server.go
package main
import (
"github.com/gorilla/websocket"
"log"
"net/http"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
type Client struct {
conn *websocket.Conn
send chan []byte
}
var clients = make(map[*Client]bool)
var broadcast = make(chan []byte)
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("WebSocket upgrade error:", err)
return
}
defer conn.Close()
client := &Client{conn: conn, send: make(chan []byte, 256)}
clients[client] = true
// 读取消息并广播给其他客户端
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
delete(clients, client)
break
}
// 将消息广播给所有其他客户端
for otherClient := range clients {
if otherClient != client {
otherClient.conn.WriteMessage(websocket.TextMessage, message)
}
}
}
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Println("信令服务器运行在 :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。