Skip to content

Instantly share code, notes, and snippets.

@mganeko
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save mganeko/cc491e1657d414a3a56b to your computer and use it in GitHub Desktop.

Select an option

Save mganeko/cc491e1657d414a3a56b to your computer and use it in GitHub Desktop.
WebRTC Signaling by Hand
<!DOCTYPE html>
<html>
<head>
<title>WebRTC 1 to 1 handshake V3</title>
</head>
<body>
<button type="button" onclick="startVideo();">Start video</button>
<button type="button" onclick="stopVideo();">Stop video</button>
&nbsp;&nbsp;&nbsp;&nbsp;
<button type="button" onclick="connect();">Connect</button>
<button type="button" onclick="hangUp();">Hang Up</button>
<br />
<div>
<video id="local-video" autoplay style="width: 240px; height: 180px; border: 1px solid black;"></video>
<video id="remote-video" autoplay style="width: 240px; height: 180px; border: 1px solid black;"></video>
</div>
<p>
SDP to send:<br />
<textarea id="text-for-send-sdp" rows="5" cols="100" disabled="1">SDP to send</textarea>
</p>
<p>
SDP to receive:<br />
<textarea id="text-for-receive-sdp" rows="5" cols="100"></textarea><br />
<button type="button" onclick="onSDP();">Receive SDP</button>
</p>
<p>
ICE Candidate to send:<br />
<textarea id="text-for-send-ice" rows="5" cols="100" disabled="1" onclick="this.focus(); this.select();">ICE Candidate to send</textarea>
</p>
<p>
ICE Candidates to receive:<br />
<textarea id="text-for-receive-ice" rows="5" cols="100"></textarea><br />
<button type="button" onclick="onICE();">Receive ICE Candidates</button>
</p>
<script>
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');
var localStream = null;
var peerConnection = null;
var peerStarted = false;
var mediaConstraints = {'mandatory': {'OfferToReceiveAudio':true, 'OfferToReceiveVideo':true }};
// ----------------- handshake --------------
var textForSendSDP = document.getElementById('text-for-send-sdp');
var textForSendICE = document.getElementById('text-for-send-ice');
var textToReceiveSDP = document.getElementById('text-for-receive-sdp');
var textToReceiveICE = document.getElementById('text-for-receive-ice');
var iceSeparator = '------ ICE Candidate -------';
var CR = String.fromCharCode(13);
function onSDP() {
var text = textToReceiveSDP.value;
var evt = JSON.parse(text);
if (peerConnection) {
onAnswer(evt);
textForSendICE.focus();
textForSendICE.select();
}
else {
onOffer(evt);
}
textToReceiveSDP.value ="";
}
//--- multi ICE candidate ---
function onICE() {
var text = textToReceiveICE.value;
var arr = text.split(iceSeparator);
for (var i = 1, len = arr.length; i < len; i++) {
var evt = JSON.parse(arr[i]);
onCandidate(evt);
}
textToReceiveICE.value ="";
textForSendICE.focus();
textForSendICE.select();
}
function onOffer(evt) {
console.log("Received offer...")
console.log(evt);
setOffer(evt);
sendAnswer(evt);
}
function onAnswer(evt) {
console.log("Received Answer...")
console.log(evt);
setAnswer(evt);
}
function onCandidate(evt) {
var candidate = new RTCIceCandidate({sdpMLineIndex:evt.sdpMLineIndex, sdpMid:evt.sdpMid, candidate:evt.candidate});
console.log("Received Candidate...")
console.log(candidate);
peerConnection.addIceCandidate(candidate);
}
function sendSDP(sdp) {
var text = JSON.stringify(sdp);
console.log("---sending sdp text ---");
console.log(text);
textForSendSDP.value = text;
textForSendSDP.focus();
textForSendSDP.select();
}
function sendCandidate(candidate) {
var text = JSON.stringify(candidate);
console.log("---sending candidate text ---");
console.log(text);
textForSendICE.value = (textForSendICE.value + CR + iceSeparator + CR + text + CR);
textForSendICE.scrollTop = textForSendICE.scrollHeight;
}
// ---------------------- video handling -----------------------
// start local video
function startVideo() {
navigator.webkitGetUserMedia({video: true, audio: false},
function (stream) { // success
localStream = stream;
localVideo.src = window.webkitURL.createObjectURL(stream);
localVideo.play();
localVideo.volume = 0;
},
function (error) { // error
console.error('getUserMedia error occurred');
console.log(error);
return;
}
);
}
// stop local video
function stopVideo() {
localVideo.src = "";
localStream.stop();
}
// ---------------------- connection handling -----------------------
function prepareNewConnection() {
var pc_config = {"iceServers":[]};
var peer = null;
try {
peer = new webkitRTCPeerConnection(pc_config);
} catch (e) {
console.log("Failed to create peerConnection, exception: " + e.message);
}
// send any ice candidates to the other peer
peer.onicecandidate = function (evt) {
if (evt.candidate) {
console.log(evt.candidate);
sendCandidate({type: "candidate",
sdpMLineIndex: evt.candidate.sdpMLineIndex,
sdpMid: evt.candidate.sdpMid,
candidate: evt.candidate.candidate
});
} else {
console.log("ice event phase =" + evt.eventPhase);
}
};
console.log('Adding local stream...');
peer.addStream(localStream);
peer.addEventListener("addstream", onRemoteStreamAdded, false);
peer.addEventListener("removestream", onRemoteStreamRemoved, false)
// when remote adds a stream, hand it on to the local video element
function onRemoteStreamAdded(event) {
console.log("Added remote stream");
remoteVideo.src = window.webkitURL.createObjectURL(event.stream);
}
// when remote removes a stream, remove it from the local video element
function onRemoteStreamRemoved(event) {
console.log("Remove remote stream");
remoteVideo.src = "";
}
return peer;
}
function sendOffer() {
peerConnection = prepareNewConnection();
peerConnection.createOffer(function (sessionDescription) { // in case of success
peerConnection.setLocalDescription(sessionDescription);
console.log("Sending: SDP");
console.log(sessionDescription);
sendSDP(sessionDescription);
}, function () { // in case of error
console.log("Create Offer failed");
}, mediaConstraints);
}
function setOffer(evt) {
if (peerConnection) {
console.error('peerConnection alreay exist!');
}
peerConnection = prepareNewConnection();
peerConnection.setRemoteDescription(new RTCSessionDescription(evt));
}
function sendAnswer(evt) {
console.log('sending Answer. Creating remote session description...' );
if (! peerConnection) {
console.error('peerConnection NOT exist!');
return;
}
peerConnection.createAnswer(function (sessionDescription) { // in case of success
peerConnection.setLocalDescription(sessionDescription);
console.log("Sending: SDP");
console.log(sessionDescription);
sendSDP(sessionDescription);
}, function () { // in case of error
console.log("Create Answer failed");
}, mediaConstraints);
}
function setAnswer(evt) {
if (! peerConnection) {
console.error('peerConnection NOT exist!');
return;
}
peerConnection.setRemoteDescription(new RTCSessionDescription(evt));
}
// -------- handling user UI event -----
// start the connection upon user request
function connect() {
//if (!peerStarted && localStream && channelReady) {
if (!peerStarted && localStream) {
sendOffer();
peerStarted = true;
} else {
alert("Local stream not running yet - try again.");
}
}
// stop the connection upon user request
function hangUp() {
console.log("Hang up.");
stop();
}
function stop() {
peerConnection.close();
peerConnection = null;
peerStarted = false;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment