Я делаю приложение, которое использует WebRTC для настройки однорангового соединения между пользователями. Когда пользователь присоединяется к приложению. Они будут помещены в комнату Socket.io, где только 2 пользователя смогут войти и получить запрос только на их аудиовход. Когда второй пользователь подключается к тому же URL. Я отправляю событие на сервер, чтобы поместить их в ту же комнату Socket.io, что и первый пользователь, и запускаю весь код WebRTC, например, создание экземпляров RTCPeerConnection, RTCInceCandidates и RTCSessionDescription, в зависимости от того, какие события транслируются с сервера на другой подключен к узлу, но по какой-то причине я не могу воспроизвести аудио удаленного пользователя там, где я его слышу, и они меня слышат.
Файл p2p.js (Весь код отвечает за настройку соединения)
// roomURL.addEventListener('click', function (e) {
// document.execCommand('copy')
// });
// roomURL.addEventListener('copy', function (e) {
// e.preventDefault();
// if (e.clipboardData) {
// e.clipboardData.setData('text/plain', roomURL.textContent);
// }
// });
let isInitializer = false;
let isChannelReady = false;
let isStarted = false;
let pc;
let localStream;
let remoteStream;
/**
* - Create new RTCPeerConnection
* - Listen for events on newly created RTCPeerConnection (onicecandidate, onaddstream, onremovestream)
*/
const pcConfig = {
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
};
const room = 'foo';
const socket = io();
if (room !== '') {
socket.emit('create or join', room);
console.log('Attempted to create or join room ' + room);
}
socket.on('created', function (room) {
isInitializer = true;
console.log('Created room ' + room);
});
socket.on('full', function (room) {
console.log('Room ' + room + ' is full');
});
socket.on('join', function (room) {
console.log('Another peer made a request to join room ' + room);
console.log('This peer is the initiator of room ' + room + '!');
isChannelReady = true;
});
socket.on('joined', function (room) {
console.log('joined: ' + room);
isChannelReady = true;
});
function sendMessage(message) {
socket.emit('message', message);
}
//////////////////////////////////////////////////////////////////////////////////
socket.on('message', function (message) {
if (message === 'got user media') {
start();
console.log('Got user media');
} else if (message.type === 'offer') {
if (!isInitializer && !isStarted) {
start();
}
pc.setRemoteDescription(new RTCSessionDescription(message));
answer();
console.log('Offer')
} else if (message.type === 'answer' && isStarted) {
pc.setRemoteDescription(new RTCSessionDescription(message));
console.log('Answer');
} else if (message.type === 'candidate' && isStarted) {
const candidate = new RTCIceCandidate({
sdpMLineIndex: message.label,
candidate: message.candidate
});
pc.addIceCandidate(candidate);
console.log('Candidate');
}
});
/////////////////////////////////////////////////////////////////////////////////
var localVideo = document.querySelector('#localVideo');
var remoteVideo = document.querySelector('#remoteVideo');
navigator.mediaDevices.getUserMedia({
audio: true, video: false
}).then((stream) => {
localStream = stream;
console.log('My Stream', stream);
localVideo.srcObject = stream;
sendMessage('got user media');
if (isInitializer) {
start();
}
});
//////////////////////////////////////////////////////////////////////////////////
function start() {
if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
createPeerConnection();
const tracks = localStream.getTracks();
for (const track of tracks) {
pc.addTrack(track);
}
isStarted = true;
if (isInitializer) {
call();
}
}
}
function createPeerConnection() {
pc = new RTCPeerConnection(null);
pc.onicecandidate = function (e) {
if (e.candidate) {
sendMessage({
type: 'candidate',
label: e.candidate.sdpMLineIndex,
id: e.candidate.sdpMid,
candidate: e.candidate.candidate
});
}
}
pc.ontrack = function (e) {
console.log('Remote track added', e);
remoteStream = e.streams[0];
remoteVideo.srcObject = remoteStream;
}
}
//////////////////////////////////////////////////////////////////////////////////
function call() {
pc.createOffer(null).then((sessionDescription) => {
pc.setLocalDescription(sessionDescription);
sendMessage(sessionDescription);
}).catch(e => console.log(e));
}
function answer() {
pc.createAnswer(null).then((sessionDescription) => {
pc.setLocalDescription(sessionDescription);
sendMessage(sessionDescription);
});
}
index.js (Экспресс-сервер для прослушивания событий Socket.io)
const express = require('express');
const path = require('path');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
const os = require('os');
app.use(express.static(path.resolve(__dirname, '../public')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../public/index.html'));
});
const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log(('Server listening on port ' + port));
});
io.on('connection', (socket) => {
socket.on('create or join', (room) => {
const clientsRoom = (io.sockets.adapter.rooms[room]);
const roomSize = (clientsRoom ? clientsRoom.length : 0);
if (roomSize === 0) {
console.log('Joined room with no one');
socket.join(room);
console.log(('Room ' + room + ' now has ' + roomSize + ' connected client(s)'));
socket.emit('created', room, socket.id);
} else if (roomSize === 1) {
console.log(('Client ID ' + socket.id + ' created room ' + room));
io.sockets.in(room).emit('join', room);
socket.join(room);
console.log(('Room ' + room + ' now has ' + roomSize + ' connected client(s) and is full'));
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else {
console.log(('Room ' + room + ' is full'));
socket.emit('full', room);
}
});
socket.on('message', (message) => {
socket.broadcast.emit('message', message);
});
});