Skip to content

Instantly share code, notes, and snippets.

@shacharz
Created March 20, 2014 11:37
Show Gist options
  • Save shacharz/9661930 to your computer and use it in GitHub Desktop.
Save shacharz/9661930 to your computer and use it in GitHub Desktop.
function PeerConnectionImpl(originId,targetId,initiator,reliability){
this.reliable = reliability;
this.originId = originId;
this.targetId = targetId;
//you can use adapter.js instead
if (window.webkitRTCPeerConnection) {
this.RTCPeerConnection = webkitRTCPeerConnection;
this.RTCSessionDescription = RTCSessionDescription;
} else if (window.mozRTCPeerConnection) {
//delete turn servers due to incompatablitiy now
peer5.config.TURN_SERVERS = []
this.RTCPeerConnection = mozRTCPeerConnection;
this.RTCSessionDescription = mozRTCSessionDescription;
RTCIceCandidate = mozRTCIceCandidate;
}
if (this.reliable)
this.dataChannelOptions = {};
else
this.dataChannelOptions = { outOfOrderAllowed:true, maxRetransmitNum:0 };
this.initiatePeerConnection(initiator);
},
PeerConnectionImpl.prototype = {
/** @public methods*/
setupCall:function () {
this.peerConnection.createOffer(
this.setLocalAndSendMessage_,
function (err) {
console.log('createOffer(): failed, ' + err)
},
this.createOfferConstraints);
},
handleMessage:function (message) {
parsed_msg = message.sdpMessage;
console.log('handling message ' + message);
if (parsed_msg.type) {
var session_description = new this.RTCSessionDescription(parsed_msg);
var thi$ = this;
if(!this.peerConnectionStateValid()) return;
this.peerConnection.setRemoteDescription(
session_description,
function () {
console.log('setRemoteDescription(): success.')
if (session_description.type == "offer") {
console.log('createAnswer with constraints: ' +
JSON.stringify(this.createAnswerConstraints, null, ' '));
if(!thi$.peerConnectionStateValid()) return;
thi$.peerConnection.createAnswer(
thi$.setLocalAndSendMessage_,
function (err) {
console.log('createAnswer(): failed, ' + err)
},
thi$.createAnswerConstraints);
}
},
function (err) {
console.log('setRemoteDescription(): failed, ' + err)
});
return;
} else if (parsed_msg.candidate) {
if (JSON.stringify(parsed_msg) in this.peerConnection.candidates) {
console.log('candidate was already added');
return; // no need to add this!
}
if(!this.peerConnectionStateValid()) return;
var candidate = new RTCIceCandidate(parsed_msg);
this.peerConnection.addIceCandidate(candidate);
this.peerConnection.candidates[JSON.stringify(parsed_msg)] = Date.now(); //memorize we have this candidate
return;
}
console.log("unknown message received");
// addTestFailure("unknown message received");
return;
},
//Uint8Array binaryMessage
send:function (binaryMessage) {
var message = binaryMessage.buffer;
var thi$ = this;
if (thi$.dataChannel.readyState.toLowerCase() == 'open') {
console.log("sending data on dataChannel");
thi$.dataChannel.send(message);
} else {
console.log('dataChannel was not ready, setting timeout');
setTimeout(function (dataChannel, message) {
thi$.send(dataChannel, message);
}, peer5.config.PC_RESEND_INTERVAL, thi$.dataChannel, message);
}
},
close:function(){
this.ready = false;
this.dataChannel.close();
this.peerConnection.close();
},
/** @private methods*/
initiatePeerConnection:function (initiator) {
this.initiatePeerConnectionCallbacks();
this.createPeerConnection();
if (initiator)
this.ensureHasDataChannel();
var id = setTimeout(function (thi$) {
if (!thi$.ready) {
console.log("ready state of PCImpl to " + thi$.targetId + " = " + thi$.ready);
thi$.failure = true;
console.log("couldn't connect to " + thi$.targetId);
thi$.handlePeerDisconnection(thi$.targetId);
}
}, peer5.config.PC_FAIL_TIMEOUT, this);
},
initiatePeerConnectionCallbacks:function () {
this.registerEvents();
},
registerEvents:function () {
var thi$ = this;
this.setLocalAndSendMessage_ = function (session_description) {
session_description.sdp = thi$.transformOutgoingSdp(session_description.sdp);
thi$.peerConnection.setLocalDescription(
session_description,
function () {
console.log('setLocalDescription(): success.');
},
function (err) {
console.log('setLocalDescription(): failed' + err)
});
console.log("Sending SDP message:\n" + session_description.sdp);
//---You'll need to send this SDP to the targetId peer --------//
//---Choose a signaling mechanism using a server to do that ---//
};
this.iceCallback_ = function (event) {
if (event.candidate && event.target.iceConnectionState != 'disconnected') {
var sdp = event.candidate;
//---You'll need to send this SDP to the targetId peer --------//
//---Choose a signaling mechanism using a server to do that ---//
}
};
this.iceStateChangedCallback_ = function (event) {
if (!!event.target && event.target.iceConnectionState === 'disconnected') {
console.log("iceStateChanged to disconnected");
thi$.handlePeerDisconnection();
}
};
this.signalingStateChangeCallback_ = function (event) {
if(event.target && event.target.signalingState == "closed"){
console.log("signalingStateChanged to closed");
thi$.handlePeerDisconnection();
}
};
this.onCreateDataChannelCallback_ = function (event) {
if (thi$.dataChannel != null && thi$.dataChannel.readyState != 'closed') {
console.log('Received DataChannel, but we already have one.');
}
thi$.dataChannel = event.channel;
console.log('DataChannel with label ' + thi$.dataChannel.label +
' initiated by remote peer.');
thi$.hookupDataChannelEvents();
};
this.onDataChannelReadyStateChange_ = function (event) {
var readyState = event.target.readyState;
console.log('DataChannel to ' + thi$.targetId + ' state:' + readyState);
if (readyState.toLowerCase() == 'open') {
thi$.ready = true;
//---Your connection is now ready bubble it up to higher logic level --------//
}
};
this.onDataChannelClose_ = function (event) {
console.log("data channel was closed");
thi$.handlePeerDisconnection();
};
this.onMessageCallback_ = function (message) {
console.log("receiving data on dataChannel");
//---You have received a message, bubble it up to higher logic level --------//
};
},
ensureHasDataChannel:function () {
if (this.peerConnection == null)
console.log('Tried to create data channel, ' +
'but have no peer connection.');
if (this.dataChannel != null && this.dataChannel != 'closed') {
console.log('Creating DataChannel, but we already have one.');
}
this.createDataChannel();
},
createPeerConnection:function () {
//----configure you stun_servers----//
//e.g: var servers = {"iceServers":[{url:"stun:stun.l.google.com:19302"}]}
try {
peer5.info("webkitRTCPeerConnection");
if(window.mozRTCPeerConnection)
this.peerConnection = new this.RTCPeerConnection(); //mozila has a default ice server hard coded
else
this.peerConnection = new this.RTCPeerConnection(
servers
);
this.peerConnection.candidates = {}; // to remember what candidates were added
} catch (exception) {
console.log('Failed to create peer connection: ' + exception);
}
this.peerConnection.onaddstream = this.addStreamCallback_;
this.peerConnection.onremovestream = this.removeStreamCallback_;
this.peerConnection.onicecandidate = this.iceCallback_;
this.peerConnection.oniceconnectionstatechange = this.iceStateChangedCallback_;
this.peerConnection.onicechange = this.iceStateChangedCallback_;
this.peerConnection.onsignalingstatechange = this.signalingStateChangeCallback_;
this.peerConnection.ondatachannel = this.onCreateDataChannelCallback_;
},
createDataChannel:function () {
console.log("createDataChannel");
this.dataChannel = this.peerConnection.createDataChannel(this.label, this.dataChannelOptions);
peer5.debug('DataChannel with label ' + this.dataChannel.label + ' initiated locally.');
this.hookupDataChannelEvents();
},
closeDataChannel:function () {
if (this.dataChannel == null)
console.log('Closing DataChannel, but none exists.');
console.log('DataChannel with label ' + this.dataChannel.label + ' is being closed.');
this.dataChannel.close();
},
hookupDataChannelEvents:function () {
this.dataChannel.binaryType = 'arraybuffer';
this.dataChannel.onmessage = this.onMessageCallback_;
this.dataChannel.onopen = this.onDataChannelReadyStateChange_;
this.dataChannel.onclose = this.onDataChannelClose_;
//connecting status:
console.log('data-channel-status: ' + this.dataChannel.readyState);
},
handlePeerDisconnection:function(){
if(this.dataChannel && this.dataChannel.readyState != "closed"){
peer5.info("handling peer disconnection: closing the datachannel");
this.dataChannel.close();
}
if(this.peerConnection.signalingState != "closed"){
console.log("handling peer disconnection: closing the peerconnection");
this.peerConnection.close();
}
//---Peer has disconnected inform higher level logic---
},
peerConnectionStateValid:function(){
if(this.peerConnection.iceConnectionState != 'closed' && this.peerConnection.signalingState != 'closed')
return true;
else{
console.log("peerConnection state to " + this.targetId + " is invalid - 'not usable'");
return false;
}
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment