WebRTC 進階
Last updated
Last updated
let localVideoEnabled = true;
let localAudioEnabled = true;
function handleVideoDisconnect() {
localVideoEnabled = !localVideoEnabled;
localStream.getTracks()[1].enabled = localVideoEnabled;
}
function handleAudioDisconnect() {
localAudioEnabled = !localAudioEnabled;
localStream.getTracks()[0].enabled = localAudioEnabled;
}
// 如果用 track.stop() 會永久關閉
可選擇關音訊或視訊。
首先斷線時發送 websocket 訊息給對方,並且關閉 peerConnection,然後清空 video srcObject。
function handleWebRTCDisconnect() {
serverConnection.send(JSON.stringify({ event: "peer disconnect", uuid }));
peerConnection.close();
localStream = "";
localVideo.current.srcObject = null; // 這邊用 React ref 所以是 .current
remoteVideo.current.srcObject = null;
init();
}
對方接收到訊息後
function gotMessageFromServer(message) {
var signal = JSON.parse(message.data);
if (signal.event === "peer disconnect") {
console.log("peer disconnect");
peerConnection.close();
remoteVideo.current.srcObject = null;
init();
return;
}
....
}
init
function 如下,即為初始化連線與獲取 media 等設備
const init = () => {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
const constraints = {
video: true,
audio: true,
};
serverConnection.onmessage = gotMessageFromServer;
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
localStream = stream;
localVideo.current.srcObject = stream;
peerConnection.ontrack = (event) => {
console.log("got remote stream");
if (!remoteVideo.current.srcObject) {
remoteVideo.current.srcObject = event.streams[0];
!isCaller && peerConnection.addStream(localStream);
}
};
})
.catch(errorHandler);
} else {
alert("Your browser does not support getUserMedia API");
}
};
建立 channel
let sendChannel;
let receiveChannel;
const handleConnect = (_isCaller) => {
if (_isCaller) {
....
sendChannel = peerConnection.createDataChannel("sendDataChannel");
sendChannel.onopen = (e) => {
console.log('send channel open')
}
sendChannel.onmessage = onChannelMessage;
peerConnection.addStream(localStream);
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
....
}
}
const onChannelMessage = (e) => {
console.log(`on channel message: ${e.data}`)
}
只用建立一個 channel 即可,撥打方建立,然後 createOffer 後會把 channel 送給遠端
2. 之後監聽接收 channel
peerConnection.ondatachannel = (e) => {
receiveChannel = e.channel;
receiveChannel.onmessage = onChannelMessage;
}
3. 發送訊息到 channel
const handleSendMessage = (value) => {
if(receiveChannel) {
receiveChannel.send(value);
} else {
sendChannel.send(value);
}
}
可參考:https://webrtc.github.io/samples/src/content/datachannel/basic/js/main.js
重新發起 createOffer
async function handleShareScreen() {
try {
captureStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true,
});
captureStream.getVideoTracks()[0].onended = () => { // Click on browser UI stop sharing button
console.info("ScreenShare has ended");
// Switch to camera stream
localVideo.current.srcObject = localStream;
peerConnection.removeStream(captureStream);
peerConnection.addStream(localStream);
peerConnection.createOffer().then(sendDescription).catch(errorHandler);
};
} catch (err) {
console.error("Error: " + err);
}
// Switch to shareScreen stream
localVideo.current.srcObject = captureStream;
peerConnection.removeStream(localStream);
peerConnection.addStream(captureStream);
peerConnection.createOffer().then(sendDescription).catch(errorHandler);
}
function sendDescription(description) {
console.log("got description");
console.log(description);
peerConnection
.setLocalDescription(description)
.then(function () {
serverConnection.send(
JSON.stringify({ sdp: peerConnection.localDescription, uuid })
);
})
.catch(errorHandler);
}
從後端與其他 peer 連線