index.html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>WebRTC 通話(huà)</title>
</head>
<body>
<button id="startCall">發(fā)起通話(huà)</button>
<button id="endCall" disabled>掛斷通話(huà)</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('獲取媒體設(shè)備失敗:', 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 }));
}
};
// 處理遠(yuǎn)程流
peerConnection.ontrack = (event) => {
document.getElementById('remoteVideo').srcObject = event.streams[0];
};
}
// 發(fā)起通話(huà)按鈕
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
// 讀取消息并廣播給其他客戶(hù)端
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
delete(clients, client)
break
}
// 將消息廣播給所有其他客戶(hù)端
for otherClient := range clients {
if otherClient != client {
otherClient.conn.WriteMessage(websocket.TextMessage, message)
}
}
}
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Println("信令服務(wù)器運(yùn)行在 :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。