Last active
April 2, 2022 08:19
-
-
Save AdeyinkaAdegbenro/a6f0bb7a7be9f0c240599e8be2e4b04c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>WebRTC</title> | |
</head> | |
<body> | |
<h1>WebRTC PeerConnection</h1> | |
<video id="localVideo" autoplay playsinline></video> | |
<video id="remoteVideo" autoplay playsinline></video> | |
<div> | |
<button id="startButton">Start</button> | |
<button id="callButton">Call</button> | |
<button id="hangupButton">Hang Up</button> | |
</div> | |
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> | |
<script src="peerconnection.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const mediaStreamConstraints = { | |
video: true, | |
}; | |
// Set up to exchange only video. | |
const offerOptions = { | |
offerToReceiveVideo: 1, | |
}; | |
let startTime = null; | |
const localVideo = document.getElementById('localVideo'); | |
const remoteVideo = document.getElementById('remoteVideo'); | |
let localStream; | |
let remoteStream; | |
let localPeerConnection; | |
let remotePeerConnection; | |
// Define MediaStreams callbacks. | |
// Sets the MediaStream as the video element src. | |
function gotLocalMediaStream(mediaStream) { | |
localVideo.srcObject = mediaStream; | |
localStream = mediaStream; | |
callButton.disabled = false; // Enable call button. | |
} | |
// Handles error by logging a message to the console. | |
function handleLocalMediaStreamError(error) { | |
console.log('media stream error', error) | |
} | |
// Handles remote MediaStream success by adding it as the remoteVideo src. | |
function gotRemoteMediaStream(event) { | |
const mediaStream = event.stream; | |
remoteVideo.srcObject = mediaStream; | |
remoteStream = mediaStream; | |
} | |
// Connects with new peer candidate. | |
function handleConnection(event) { | |
const peerConnection = event.target; | |
const iceCandidate = event.candidate; | |
if (iceCandidate) { | |
const newIceCandidate = new RTCIceCandidate(iceCandidate); | |
const otherPeer = getOtherPeer(peerConnection); | |
otherPeer.addIceCandidate(newIceCandidate) | |
.then(() => { | |
handleConnectionSuccess(peerConnection); | |
}).catch((error) => { | |
handleConnectionFailure(peerConnection, error); | |
}); | |
} | |
} | |
// Logs that the connection succeeded. | |
function handleConnectionSuccess(peerConnection) { | |
trace(`${getPeerName(peerConnection)} addIceCandidate success.`); | |
}; | |
// Logs that the connection failed. | |
function handleConnectionFailure(peerConnection, error) { | |
trace(`${getPeerName(peerConnection)} failed to add ICE Candidate:\n`+ | |
`${error.toString()}.`); | |
} | |
// Logs changes to the connection state. | |
function handleConnectionChange(event) { | |
const peerConnection = event.target; | |
console.log('ICE state change event: ', event); | |
trace(`${getPeerName(peerConnection)} ICE state: ` + | |
`${peerConnection.iceConnectionState}.`); | |
} | |
// Logs error when setting session description fails. | |
function setSessionDescriptionError(error) { | |
trace(`Failed to create session description: ${error.toString()}.`); | |
} | |
// Logs success when setting session description. | |
function setDescriptionSuccess(peerConnection, functionName) { | |
const peerName = getPeerName(peerConnection); | |
trace(`${peerName} ${functionName} complete.`); | |
} | |
// Logs success when localDescription is set. | |
function setLocalDescriptionSuccess(peerConnection) { | |
setDescriptionSuccess(peerConnection, 'setLocalDescription'); | |
} | |
// Logs success when remoteDescription is set. | |
function setRemoteDescriptionSuccess(peerConnection) { | |
setDescriptionSuccess(peerConnection, 'setRemoteDescription'); | |
} | |
// Logs offer creation and sets peer connection session descriptions. | |
function createdOffer(description) { | |
trace(`Offer from localPeerConnection:\n${description.sdp}`); | |
trace('localPeerConnection setLocalDescription start.'); | |
localPeerConnection.setLocalDescription(description) | |
.then(() => { | |
setLocalDescriptionSuccess(localPeerConnection); | |
}).catch(setSessionDescriptionError); | |
trace('remotePeerConnection setRemoteDescription start.'); | |
remotePeerConnection.setRemoteDescription(description) | |
.then(() => { | |
setRemoteDescriptionSuccess(remotePeerConnection); | |
}).catch(setSessionDescriptionError); | |
trace('remotePeerConnection createAnswer start.'); | |
remotePeerConnection.createAnswer() | |
.then(createdAnswer) | |
.catch(setSessionDescriptionError); | |
} | |
// Logs answer to offer creation and set peer connection session descriptions. | |
function createdAnswer(description) { | |
trace(`Answer from remotePeerConnection:\n${description.sdp}.`); | |
trace('remotePeerConnection setLocalDescription start.'); | |
remotePeerConnection.setLocalDescription(description) | |
.then(() => { | |
setLocalDescriptionSuccess(remotePeerConnection); | |
}).catch(setSessionDescriptionError); | |
trace('localPeerConnection setRemoteDescription start.'); | |
localPeerConnection.setRemoteDescription(description) | |
.then(() => { | |
setRemoteDescriptionSuccess(localPeerConnection); | |
}).catch(setSessionDescriptionError); | |
} | |
// Define and add behavior to buttons. | |
// Define action buttons. | |
const startButton = document.getElementById('startButton'); | |
const callButton = document.getElementById('callButton'); | |
const hangupButton = document.getElementById('hangupButton'); | |
// Set up initial action buttons status: disable call and hangup. | |
callButton.disabled = true; | |
hangupButton.disabled = true; | |
// Handles start button action: creates local MediaStream. | |
function startAction() { | |
startButton.disabled = true; | |
navigator.mediaDevices.getUserMedia(mediaStreamConstraints) | |
.then(gotLocalMediaStream).catch(handleLocalMediaStreamError); | |
trace('Requesting local stream.'); | |
} | |
// Handles call button action: creates peer connection. | |
function callAction() { | |
callButton.disabled = true; | |
hangupButton.disabled = false; | |
const servers = null; // Allows for RTC server configuration. | |
// Create peer connections and add behavior. | |
localPeerConnection = new RTCPeerConnection(servers); | |
trace('Created local peer connection object localPeerConnection.'); | |
localPeerConnection.addEventListener('icecandidate', handleConnection); | |
localPeerConnection.addEventListener( | |
'iceconnectionstatechange', handleConnectionChange); | |
remotePeerConnection = new RTCPeerConnection(servers); | |
trace('Created remote peer connection object remotePeerConnection.'); | |
remotePeerConnection.addEventListener('icecandidate', handleConnection); | |
remotePeerConnection.addEventListener( | |
'iceconnectionstatechange', handleConnectionChange); | |
remotePeerConnection.addEventListener('addstream', gotRemoteMediaStream); | |
// Add local stream to connection and create offer to connect. | |
localPeerConnection.addStream(localStream); | |
trace('Added local stream to localPeerConnection.'); | |
trace('localPeerConnection createOffer start.'); | |
localPeerConnection.createOffer(offerOptions) | |
.then(createdOffer).catch(setSessionDescriptionError); | |
} | |
// Handles hangup action: ends up call, closes connections and resets peers. | |
function hangupAction() { | |
localPeerConnection.close(); | |
remotePeerConnection.close(); | |
localPeerConnection = null; | |
remotePeerConnection = null; | |
hangupButton.disabled = true; | |
callButton.disabled = false; | |
} | |
// Add click event handlers for buttons. | |
startButton.addEventListener('click', startAction); | |
callButton.addEventListener('click', callAction); | |
hangupButton.addEventListener('click', hangupAction); | |
// Define helper functions. | |
// Gets the "other" peer connection. | |
function getOtherPeer(peerConnection) { | |
return (peerConnection === localPeerConnection) ? | |
remotePeerConnection : localPeerConnection; | |
} | |
// Gets the name of a certain peer connection. | |
function getPeerName(peerConnection) { | |
return (peerConnection === localPeerConnection) ? | |
'localPeerConnection' : 'remotePeerConnection'; | |
} | |
// Logs an action (text) and the time when it happened on the console. | |
function trace(text) { | |
text = text.trim(); | |
const now = (window.performance.now() / 1000).toFixed(3); | |
console.log(now, text); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment