= document.getElementById('callButton'); var hangupButton = document.getElementById('hangupButton'); callButton.disabled = true; hangupButton.disabled = true; startButton.onclick = start; callButton.onclick = call; hangupButton.onclick = hangup; var startTime; var localVideo = document.getElementById('localVideo'); var remoteVideo = document.getElementById('remoteVideo'); localVideo.addEventListener('loadedmetadata', function() { trace('Local video videoWidth: ' + this.videoWidth + 'px, videoHeight: ' + this.videoHeight + 'px'); }); remoteVideo.addEventListener('loadedmetadata', function() { trace('Remote video videoWidth: ' + this.videoWidth + 'px, videoHeight: ' + this.videoHeight + 'px'); }); remoteVideo.onresize = function() { trace('Remote video size changed to ' + remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight); // We'll use the first onsize callback as an indication that video has started // playing out. if (startTime) { var elapsedTime = window.performance.now() - startTime; trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms'); startTime = null; } }; var localStream; var pc1; var pc2; var offerOptions = { offerToReceiveAudio: 1, offerToReceiveVideo: 1 }; function getName(pc) { return (pc === pc1) ? 'pc1' : 'pc2'; } function getOtherPc(pc) { return (pc === pc1) ? pc2 : pc1; } function gotStream(stream) { trace('Received local stream'); localVideo.srcObject = stream; localStream = stream; callButton.disabled = false; } function start() { trace('Requesting local stream'); startButton.disabled = true; navigator.mediaDevices.getUserMedia({ audio: true, video: true }) .then(gotStream) .catch(function(e) { alert('getUserMedia() error: ' + e.name); }); } function call() { callButton.disabled = true; hangupButton.disabled = false; trace('Starting call'); startTime = window.performance.now(); var videoTracks = localStream.getVideoTracks(); var audioTracks = localStream.getAudioTracks(); if (videoTracks.length > 0) { trace('Using video device: ' + videoTracks[0].label); } if (audioTracks.length > 0) { trace('Using audio device: ' + audioTracks[0].label); } var servers = null; pc1 = new RTCPeerConnection(servers); trace('Created local peer connection object pc1'); pc1.onicecandidate = function(e) { onIceCandidate(pc1, e); }; pc2 = new RTCPeerConnection(servers); trace('Created remote peer connection object pc2'); pc2.onicecandidate = function(e) { onIceCandidate(pc2, e); }; pc1.oniceconnectionstatechange = function(e) { onIceStateChange(pc1, e); }; pc2.oniceconnectionstatechange = function(e) { onIceStateChange(pc2, e); }; pc2.onaddstream = gotRemoteStream; pc1.addStream(localStream); trace('Added local stream to pc1'); trace('pc1 createOffer start'); pc1.createOffer(onCreateOfferSuccess, onCreateSessionDescriptionError, offerOptions); } 209 lines of code function onCreateSessionDescriptionError(error) { trace('Failed to create session description: ' + error.toString()); } function onCreateOfferSuccess(desc) { trace('Offer from pc1\n' + desc.sdp); trace('pc1 setLocalDescription start'); pc1.setLocalDescription(desc, function() { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc, function() { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError); trace('pc2 createAnswer start'); // Since the 'remote' side has no media stream we need // to pass in the right constraints in order for it to // accept the incoming offer of audio and video. pc2.createAnswer(onCreateAnswerSuccess, onCreateSessionDescriptionError); } function onSetLocalSuccess(pc) { trace(getName(pc) + ' setLocalDescription complete'); } function onSetRemoteSuccess(pc) { trace(getName(pc) + ' setRemoteDescription complete'); } function onSetSessionDescriptionError(error) { trace('Failed to set session description: ' + error.toString()); } function gotRemoteStream(e) { remoteVideo.srcObject = e.stream; trace('pc2 received remote stream'); } function onCreateAnswerSuccess(desc) { trace('Answer from pc2:\n' + desc.sdp); trace('pc2 setLocalDescription start'); pc2.setLocalDescription(desc, function() { onSetLocalSuccess(pc2); }, onSetSessionDescriptionError); trace('pc1 setRemoteDescription start'); pc1.setRemoteDescription(desc, function() { onSetRemoteSuccess(pc1); }, onSetSessionDescriptionError); } function onIceCandidate(pc, event) { if (event.candidate) { getOtherPc(pc).addIceCandidate(new RTCIceCandidate(event.candidate), function() { onAddIceCandidateSuccess(pc); }, function(err) { onAddIceCandidateError(pc, err); } ); trace(getName(pc) + ' ICE candidate: \n' + event.candidate.candidate); } } function onAddIceCandidateSuccess(pc) { trace(getName(pc) + ' addIceCandidate success'); } function onAddIceCandidateError(pc, error) { trace(getName(pc) + ' failed to add ICE Candidate: ' + error.toString()); } function onIceStateChange(pc, event) { if (pc) { trace(getName(pc) + ' ICE state: ' + pc.iceConnectionState); console.log('ICE state change event: ', event); } } function hangup() { trace('Ending call'); pc1.close(); pc2.close(); pc1 = null; pc2 = null; hangupButton.disabled = true; callButton.disabled = false; } https://github.com/webrtc/samples/blob/gh-pages/src/content/peerconnection/pc1/js/main.js