有人能想象为什么,基于WebRTC的屏幕共享不起作用吗? 我已经测试过了。 与某人一起在房间里时可以看到名字,但是为什么要共享屏幕时图片却变成白色?
套接字已启动,并且控制台中没有错误。 分割图像后,您什么也看不到。传输未显示,可能是问题所在。
HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/socket.io/socket.io.js"></script>
<script src="/assets/javascript/realtime/socketClient.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
</head>
<body>
<div id="available-users"></div>
<video id="remote-video"></video>
<video id="local-video"></video>
</body>
</html>
套接字连接器:
import SocketIO from 'socket.io';
import SocketSession from 'express-socket.io-session';
const connections = [];
export function startSocketServer(app, httpServer, session) {
const socketSession = SocketSession(session, {
autoSave: true
});
const socketServer = SocketIO(httpServer);
socketServer.use(socketSession);
socketServer.on('connection', (socket) => handleSocket(socketServer, socket));
}
function handleSocket(server, socket) {
const userData = socket.handshake.session.userData;
if(!userData) {
return;
}
connections.push({ data: userData, socket })
socket.on('disconnect', () => {
const index = connections.findIndex((v) => v.socket === socket);
if(index > -1) {
connections.splice(index, 1);
} else {
console.log('WARNING: Unindexed socket disconnected');
}
server.emit('available-users', connections.map((v) => v.data));
});
socket.on('send-connection-request', (target) => {
console.log(`Connection request from ${userData.user} to ${target.user}`);
const fullTarget = connections.find((v) => v.data.id === target.id);
if(fullTarget) {
fullTarget.socket.emit('connection-request', userData);
} else {
socket.emit('error-message', 'Invalid target user');
}
});
socket.on('rtc-offer', (message) => {
const fullTarget = connections.find((v) => v.data.id === message.target.id);
if(fullTarget) {
fullTarget.socket.emit('rtc-offer', {
description: message.description,
sender: userData
});
} else {
socket.emit('error-message', 'Invalid target user');
}
});
socket.on('rtc-answer', (message) => {
const fullTarget = connections.find((v) => v.data.id === message.target.id);
if(fullTarget) {
fullTarget.socket.emit('rtc-answer', message);
} else {
socket.emit('error-message', 'Invalid target user');
}
});
server.emit('available-users', connections.map((v) => v.data));
}
套接字客户端:
const socketClient = io();
socketClient.on('available-users', (users) => {
const availableUsersElement = document.getElementById('available-users');
let content = "";
for (const userDescription of users) {
content += `<button onclick='connectClicked(${JSON.stringify(userDescription)})'>${userDescription.user}</button>`
}
availableUsersElement.innerHTML = content;
});
let remoteUser;
let screenStream;
socketClient.on('connection-request', async (source) => {
console.log(`Connection request from ${source.user}!`);
remoteUser = source;
await createPeerConnection();
screenStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false
});
document.getElementById("local-video").srcObject = screenStream;
screenStream.getTracks().forEach(
transceiver = t => peerConnection.addTransceiver(t, {
streams: [screenStream]
})
);
});
socketClient.on('error-message', (message) => {
endCall();
console.error(`Error message from server: ${message}`)
});
socketClient.on('rtc-offer', handleRtcOffer);
socketClient.on('rtc-answer', handleRtcAnswer);
function connectClicked(target) {
console.log(`Requesting connection to ${target.user}...`)
socketClient.emit('send-connection-request', target);
}
let peerConnection;
let transceiver;
async function createPeerConnection() {
peerConnection = new RTCPeerConnection({
iceServers: [
{
url: 'stun:stun.stunprotocol.org'
}
]
});
peerConnection.onicecandidate = handleICECandidateEvent;
peerConnection.oniceconnectionstatechange = handleICEConnectionStateChangeEvent;
peerConnection.onsignalingstatechange = handleSignalingStateChangeEvent;
peerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
peerConnection.ontrack = handleTrackEvent;
}
function handleICECandidateEvent(event) {
if (event.candidate) {
socketClient.emit('ice-candidate', {
target: remoteUser,
candidate: event.candidate
})
}
}
function handleICEConnectionStateChangeEvent(event) {
switch (peerConnection.iceConnectionState) {
case 'closed':
case 'failed':
case 'disconnected':
endCall();
break;
}
}
function handleSignalingStateChangeEvent(event) {
switch (peerConnection.signalingState) {
case "closed":
endCall();
break;
}
}
async function handleNegotiationNeededEvent() {
const offer = peerConnection.createOffer();
if (peerConnection.signalingState !== 'stable') {
return;
}
await peerConnection.setLocalDescription(offer);
socketClient.emit('rtc-offer', {
target: remoteUser,
description: peerConnection.localDescription
})
}
function handleTrackEvent(event) {
console.log('Setting remote track');
document.getElementById('remote-video').srcObject = event.streams[0];
}
function endCall() {
console.log('Ending call');
if (peerConnection) {
peerConnection.onicecandidate = null;
peerConnection.oniceconnectionstatechange = null;
peerConnection.onsignalingstatechange = null;
peerConnection.onnegotiationneeded = null;
peerConnection.ontrack = null;
peerConnection.getTransceivers().forEach((t) => t.stop());
const localVideo = document.getElementById('local-video');
if(localVideo.srcObject) {
localVideo.pause();
localStorage.srcObject.getTracks().forEach(t => t.stop());
}
peerConnection.close();
}
peerConnection = null;
screenStream = null;
}
async function handleRtcOffer(message) {
remoteUser = message.sender;
if(!peerConnection) {
await createPeerConnection();
}
const description = new RTCSessionDescription(message.description);
if (peerConnection.signalingState !== 'stable') {
await Promise.all([
peerConnection.setLocalDescription({type: 'rollback'}),
peerConnection.setRemoteDescription(description)
]);
return;
}
await peerConnection.setRemoteDescription(description);
if (!screenStream) {
screenStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false
});
}
screenStream.getTracks().forEach(
transceiver = t => peerConnection.addTransceiver(t, {stream: [screenStream]})
);
await peerConnection.setLocalDescription(await peerConnection.createAnswer());
socketClient.emit('rtc-answer', {
target: remoteUser,
description: peerConnection.localDescription
})
}
async function handleRtcAnswer(message) {
const description = new RTCSessionDescription(message.description);
await peerConnection.setRemoteDescription(description);
}