UNPKG

mediasoup-server

Version:
499 lines (433 loc) 10.9 kB
<!doctype html> <html> <head> <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'> <title>Mediasoup Client</title> <style type="text/css"> .room { cursor: pointer; } </style> <script src="/socket.io/socket.io.js"></script> <script type='text/javascript'> let socket = null; let localVideo = null; let remoteContainer = null; let stateSpan = null; let localStream = null; let peerConnection = null; let usePlanB = false; let roomId = null; function init() { localVideo = document.getElementById('local_video'); remoteContainer = document.getElementById('remote_container'); stateSpan = document.getElementById('state_span'); if (window.window.webkitRTCPeerConnection) { usePlanB = true; } navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection; RTCSessionDescription = window.RTCSessionDescription || window.webkitRTCSessionDescription || window.mozRTCSessionDescription; initSocketIo(); updateView(); } function initSocketIo() { socket = io(); socket.on('error', function(err){ console.error('Socket.io error:', err); }); socket.on('list', function(rooms){ console.log('Receive [list]: ', rooms); listRooms(rooms); }); socket.on('room-created', function(room){ console.log('Receive [room-created]: ', room); joinNewRoom(room.id, room.name); }); socket.on('offer', function(sdp){ console.log('Receive [offer]: ', sdp); let offer = new RTCSessionDescription({ type: 'offer', sdp: sdp }); setOffer(offer); }); socket.on('answer', function(sdp){ console.log('Receive [answer]: ', sdp); let answer = new RTCSessionDescription({ type: 'answer', sdp: sdp }); setAnswer(answer); }); send('list'); } function sendOffer(sdp) { send('join', { planb: usePlanB, roomId: roomId, sdp: sdp }); } function sendAnswer(answer) { send('joined', answer); } function send(type, data) { console.log('Sending [' + type + ']: ', data); socket.emit(type, data); }; function appendRoom(id, name) { let roomsDiv = document.getElementById('rooms'); var newDiv = document.createElement("div"); newDiv.classList.add('room'); newDiv.onclick = function(){ joinRoom(id); }; var newContent = document.createTextNode(name); newDiv.appendChild(newContent); roomsDiv.appendChild(newDiv); } function joinNewRoom(id, name) { appendRoom(id, name); joinRoom(id); } function joinRoom(id) { roomId = id; startVideo(); } function listRooms(rooms) { for(let id in rooms) { appendRoom(id, rooms[id]); } } function createRoom() { let element = document.getElementById('newRoom'); let name = element.value; if(!name.length) { return alert('Please specify room name'); } send('create-room', name); } function startVideo() { getDeviceStream({video: true, audio: true}) .then(function (stream) { // success localStream = stream; logStream('Local stream', stream); playVideo(localVideo, stream); connect(); updateView(); }).catch(function (error) { // error console.error('getUserMedia error:', error); return; }); } function stopVideo() { pauseVideo(localVideo); stopLocalStream(localStream); localStream = null; updateView(); } function stopLocalStream(stream) { let tracks = stream.getTracks(); if (! tracks) { console.warn('NO tracks'); return; } for (let track of tracks) { track.stop(); } } function getDeviceStream(option) { if ('getUserMedia' in navigator.mediaDevices) { return navigator.mediaDevices.getUserMedia(option); } else { return new Promise(function(resolve, reject){ navigator.getUserMedia(option, resolve, reject ); }); } } function playVideo(element, stream) { if ('srcObject' in element) { element.srcObject = stream; } else { element.src = window.URL.createObjectURL(stream); } element.play(); element.volume = 0; } function pauseVideo(element) { element.pause(); if ('srcObject' in element) { element.srcObject = null; } else { if (element.src && (element.src !== '') ) { window.URL.revokeObjectURL(element.src); } element.src = ''; } } function prepareNewConnection() { let pc_config = {'iceServers':[]}; let peer = new RTCPeerConnection(pc_config); if ('ontrack' in peer) { peer.ontrack = function(event) { let stream = event.streams[0]; logStream('Remote stream on track', stream); if ( (stream.getVideoTracks().length > 0) && (stream.getAudioTracks().length > 0) ) { addRemoteVideo(stream.id, stream); } }; } else { peer.onaddstream = function(event) { let stream = event.stream; logStream('Remote stream added', stream); addRemoteVideo(stream.id, stream); }; } peer.onicecandidate = function (evt) { if (evt.candidate) { console.log(evt.candidate); } else { console.log('Empty ICE event'); } }; peer.onnegotiationneeded = function(evt) { console.log('Negotiation needed'); }; peer.onicecandidateerror = function (evt) { console.error('ICE candidate ERROR:', evt); }; peer.onsignalingstatechange = function() { console.log('Signaling state changed: ' + peer.signalingState); }; peer.oniceconnectionstatechange = function() { console.log('ICE connection state changed: ' + peer.iceConnectionState); showState('ICE connection state changed: ' + peer.iceConnectionState); if (peer.iceConnectionState === 'disconnected') { console.log('ICE disconnected'); hangUp(); } }; peer.onicegatheringstatechange = function() { console.log('ICE gathering state changed: ' + peer.iceGatheringState); }; peer.onconnectionstatechange = function() { console.log('Connection state changed: ' + peer.connectionState); }; peer.onremovestream = function(event) { console.log('Stream removed'); let stream = event.stream; removeRemoteVideo(stream.id, stream); }; if (localStream) { console.log('Adding local stream'); peer.addStream(localStream); } else { console.warn('No local stream found, continue anyway.'); } return peer; } function makeOffer() { peerConnection = prepareNewConnection(); peerConnection.createOffer({ offerToReceiveAudio : 1, offerToReceiveVideo : 1 }) .then(function (sessionDescription) { console.log('Offer created'); sendOffer(sessionDescription.sdp); }) .catch(function(err) { console.error(err); }); } function setOffer(sessionDescription) { if (peerConnection) { console.log('Peer connection alreay exist, reuse it'); } else { console.log('Create new Peer connection'); peerConnection = prepareNewConnection(); } peerConnection.setRemoteDescription(sessionDescription) .then(function() { console.log('Set remote description'); makeAnswer(); }).catch(function(err) { console.error('Set remote description error: ', err); }); } function makeAnswer() { console.log('Create remote session description' ); if (! peerConnection) { console.error('Peer connection doesn\'t exist'); return; } peerConnection.createAnswer() .then(function (sessionDescription) { console.log('Create answer'); return peerConnection.setLocalDescription(sessionDescription); }).then(function() { let answer = peerConnection.localDescription; sendAnswer(answer); }).catch(function(err) { console.error(err); }); } function setAnswer(sessionDescription) { if (! peerConnection) { console.error('Peer connection doesn\'t exist'); return; } peerConnection.setRemoteDescription(sessionDescription) .then(function() { console.log('Set remote description'); }).catch(function(err) { console.error('Set remote description error: ', err); }); } function connect() { makeOffer(); updateView(); } function dissconnect() { send('quit'); if (peerConnection) { console.log('Quiting'); peerConnection.close(); peerConnection = null; removeAllRemoteVideo(); } else { console.warn('Peer doesn\'t exist'); } stopVideo(); updateView(); } function showState(state) { stateSpan.innerText = state; } function logStream(msg, stream) { console.log(msg + ': id: ' + stream.id); let videoTracks = stream.getVideoTracks(); if (videoTracks) { console.log('Video tracks length: ' + videoTracks.length); videoTracks.forEach(function(track) { console.log(' track id: ' + track.id); }); } let audioTracks = stream.getAudioTracks(); if (audioTracks) { console.log('Audio tracks length: ' + audioTracks.length); audioTracks.forEach(function(track) { console.log(' track id: ' + track.id); }); } } function addRemoteVideo(id, stream) { let element = document.createElement('video'); remoteContainer.appendChild(element); element.id = 'remote_' + id; element.width = 640; element.height = 480; element.srcObject = stream; element.play(); element.volume = 0; element.controls = true; } function removeRemoteVideo(id, stream) { console.log('Remote video removed id: ' + id); let element = document.getElementById('remote_' + id); if (element) { element.pause(); element.srcObject = null; remoteContainer.removeChild(element); } else { console.log('Remote video element not found'); } } function removeAllRemoteVideo() { while (remoteContainer.firstChild) { remoteContainer.firstChild.pause(); remoteContainer.firstChild.srcObject = null; remoteContainer.removeChild(remoteContainer.firstChild); } } function updateView() { if (peerConnection) { hideElement('roomsSelect'); showElement('conference'); enabelElement('disconnect_button'); } else { showElement('roomsSelect'); hideElement('conference'); disableElement('disconnect_button'); } } function enabelElement(id) { let element = document.getElementById(id); if (element) { element.removeAttribute('disabled'); } } function disableElement(id) { let element = document.getElementById(id); if (element) { element.setAttribute('disabled', '1'); } } function hideElement(id) { let element = document.getElementById(id); if (element) { element.style.display = 'none'; } } function showElement(id) { let element = document.getElementById(id); if (element) { element.style.display = 'block'; } } </script> </head> <body onload="init();"> <h1>Mediasoup Client</h1> <div id="roomsSelect"> <b>Rooms:</b> <div id="rooms"></div> <br/> <b>New Room:</b> <input type="text" id="newRoom" /> <input type="button" value="Join" onclick="createRoom();" /> </div> <div id="conference"> <button id="disconnect_button" onclick="dissconnect();">Disconnect</button> <div> Local video<br /> <video id="local_video" autoplay style="width: 160px; height: 120px; border: 1px solid black;"></video> <br/> <span id="state_span"></span> </div> Remote videos <br /> <div id="remote_container"></div> </div> </body> </html>