In my next.js project, I’m trying to create a way to have p2p video calls; however, the remote caller’s video isn’t showing up. This works fin in different tabs but not different browsers or computers. I’m trying to figure out what the problem is. I tried using an open relay turn server, but that didn’t yield different results. Here is my code:
import { useEffect, useRef, useState } from 'react';
import Peer from 'peerjs';
const VideoChat = () => {
const [peerId, setPeerId] = useState(null);
const [remoteStreams, setRemoteStreams] = useState([]);
const userVideoRef = useRef();
const peerRef = useRef();
useEffect(() => {
const peer = new Peer(undefined, {
path: '/myapp',
host: 'my-server-url',
port: 443,
secure: true,
config: {
iceServers: [
{ url: 'stun:stun.l.google.com:19302' },
{
url: 'turn:open-relay-app-url.metered.live',
credential: 'open-relay-API-key',
username: 'open-relay-username'
}
]
}
});
peerRef.current = peer;
peer.on('open', id => {
setPeerId(id);
console.log('My Peer ID:', id);
});
peer.on('call', call => {
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(localStream => {
if (userVideoRef.current) {
userVideoRef.current.srcObject = localStream;
userVideoRef.current.play().catch(err => console.error('Error playing local video:', err));
}
call.answer(localStream);
call.on('stream', remoteStream => {
if (remoteStream && remoteStream.getTracks().length > 0) {
const remoteVideo = document.createElement('video');
remoteVideo.autoplay = true;
remoteVideo.style.width = '300px';
remoteVideo.style.height = '200px';
document.getElementById('remote-videos').appendChild(remoteVideo);
remoteVideo.srcObject = remoteStream;
remoteVideo.play().catch(err => console.error('Error playing remote video:', err));
setRemoteStreams(prev => [...prev, { id: call.peer, stream: remoteStream }]);
} else {
console.error('Remote stream not available.');
alert('Error: Remote stream not available.');
}
});
call.on('error', err => {
console.error('Call error:', err);
alert('Error during call: ' + err.message);
});
}).catch(err => {
console.error('Error accessing media devices.', err);
alert('Error accessing media devices: ' + err.message);
});
});
peer.on('error', err => {
console.error('Peer error:', err);
alert('Error with peer connection: ' + err.message);
});
return () => {
peer.destroy();
};
}, []);
const callPeer = peerIdToCall => {
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(localStream => {
if (userVideoRef.current) {
userVideoRef.current.srcObject = localStream;
userVideoRef.current.play().catch(err => console.error('Error playing local video:', err));
}
const call = peerRef.current.call(peerIdToCall, localStream);
call.on('stream', remoteStream => {
if (remoteStream && remoteStream.getTracks().length > 0) {
const remoteVideo = document.createElement('video');
remoteVideo.autoplay = true;
remoteVideo.style.width = '300px';
remoteVideo.style.height = '200px';
document.getElementById('remote-videos').appendChild(remoteVideo);
remoteVideo.srcObject = remoteStream;
remoteVideo.play().catch(err => console.error('Error playing remote video:', err));
setRemoteStreams(prev => [...prev, { id: peerIdToCall, stream: remoteStream }]);
} else {
console.error('Remote stream not available.');
alert('Error: Remote stream not available.');
}
});
call.on('error', err => {
console.error('Call error:', err);
alert('Error during call: ' + err.message);
});
}).catch(err => {
console.error('Error accessing media devices.', err);
alert('Error accessing media devices: ' + err.message);
});
};
return (
<div className="bg-red-500">
<h1>Video Chat</h1>
<p>Your Peer ID: <strong>{peerId}</strong></p>
<div id="user-video">
<video ref={userVideoRef} autoPlay muted style={{ width: '300px', height: '200px' }} />
</div>
<div id="remote-videos">
{remoteStreams.length > 0 ? (
remoteStreams.map(({ id, stream }) => (
<div key={id}>
<video
ref={el => {
if (el) {
el.srcObject = stream;
el.play().catch(err => console.error('Error playing remote video:', err));
}
}}
autoPlay
style={{ width: '300px', height: '200px' }}
/>
</div>
))
) : (
<p>No remote video streams available.</p>
)}
</div>
<button onClick={() => callPeer(prompt('Enter peer ID to call:'))}>
Call Peer
</button>
</div>
);
};
export default VideoChat;
I’m using an express server. Here is my code for that:
// server.js
const { PeerServer } = require('peer');
const peerServer = PeerServer({ port: 9000, path: '/myapp' });