Browse Source

Fixed indentation.

pull/32/head
Simon Eisenmann 12 years ago
parent
commit
471b46c3f1
  1. 377
      static/js/mediastream/peercall.js

377
static/js/mediastream/peercall.js

@ -22,293 +22,292 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
var PeerCall = function(webrtc, id, from, to) { var PeerCall = function(webrtc, id, from, to) {
this.webrtc = webrtc; this.webrtc = webrtc;
this.id = id; this.id = id;
this.from = from; this.from = from;
this.to = to; this.to = to;
this.e = $({}) // events this.e = $({}) // events
this.mediaConstraints = $.extend(true, {}, this.webrtc.settings.mediaConstraints); this.mediaConstraints = $.extend(true, {}, this.webrtc.settings.mediaConstraints);
this.pcConfig = $.extend(true, {}, this.webrtc.settings.pcConfig); this.pcConfig = $.extend(true, {}, this.webrtc.settings.pcConfig);
this.pcConstraints = $.extend(true, {}, this.webrtc.settings.pcConstraints); this.pcConstraints = $.extend(true, {}, this.webrtc.settings.pcConstraints);
this.sdpConstraints = $.extend(true, {}, this.webrtc.settings.sdpConstraints); this.sdpConstraints = $.extend(true, {}, this.webrtc.settings.sdpConstraints);
this.offerConstraints = $.extend(true, {}, this.webrtc.settings.offerConstraints); this.offerConstraints = $.extend(true, {}, this.webrtc.settings.offerConstraints);
this.peerconnection = null; this.peerconnection = null;
this.datachannels = {}; this.datachannels = {};
this.streams= {}; this.streams= {};
this.initiate = false; this.initiate = false;
this.closed = false; this.closed = false;
}; };
PeerCall.prototype.setInitiate = function(initiate) { PeerCall.prototype.setInitiate = function(initiate) {
this.initiate = !!initiate; this.initiate = !!initiate;
//console.log("Set initiate", this.initiate, this); //console.log("Set initiate", this.initiate, this);
}; };
PeerCall.prototype.createPeerConnection = function(success_cb, error_cb) { PeerCall.prototype.createPeerConnection = function(success_cb, error_cb) {
var peerconnection = this.peerconnection = new PeerConnection(this.webrtc, this); var peerconnection = this.peerconnection = new PeerConnection(this.webrtc, this);
if (success_cb && peerconnection.pc) { if (success_cb && peerconnection.pc) {
success_cb(peerconnection); success_cb(peerconnection);
} }
if (error_cb && !peerconnection.pc) { if (error_cb && !peerconnection.pc) {
// TODO(longsleep): Check if this can happen? // TODO(longsleep): Check if this can happen?
error_cb(peerconnection); error_cb(peerconnection);
} }
return peerconnection; return peerconnection;
}; };
PeerCall.prototype.createOffer = function(cb) { PeerCall.prototype.createOffer = function(cb) {
var constraints = utils.mergeConstraints(this.offerConstraints, this.sdpConstraints); var constraints = utils.mergeConstraints(this.offerConstraints, this.sdpConstraints);
console.log('Creating offer with constraints: \n' + console.log('Creating offer with constraints: \n' +
' \'' + JSON.stringify(constraints, null, '\t') + '\'.') ' \'' + JSON.stringify(constraints, null, '\t') + '\'.')
this.peerconnection.createOffer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), constraints); this.peerconnection.createOffer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), constraints);
}; };
PeerCall.prototype.createAnswer = function(cb) { PeerCall.prototype.createAnswer = function(cb) {
console.log("Creating answer."); console.log("Creating answer.");
this.peerconnection.createAnswer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), this.peerconnection.sdpConstraints); this.peerconnection.createAnswer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), this.peerconnection.sdpConstraints);
}; };
PeerCall.prototype.onCreateAnswerOffer = function(cb, sessionDescription) { PeerCall.prototype.onCreateAnswerOffer = function(cb, sessionDescription) {
// Prefer Opus. // Prefer Opus.
sessionDescription.sdp = utils.preferOpus(sessionDescription.sdp); sessionDescription.sdp = utils.preferOpus(sessionDescription.sdp);
// Convert to object to allow custom property injection. // Convert to object to allow custom property injection.
var sessionDescriptionObj = sessionDescription; var sessionDescriptionObj = sessionDescription;
if (sessionDescriptionObj.toJSON) { if (sessionDescriptionObj.toJSON) {
sessionDescriptionObj = JSON.parse(JSON.stringify(sessionDescriptionObj)); sessionDescriptionObj = JSON.parse(JSON.stringify(sessionDescriptionObj));
} }
console.log("Created offer/answer", JSON.stringify(sessionDescriptionObj, null, "\t")); console.log("Created offer/answer", JSON.stringify(sessionDescriptionObj, null, "\t"));
// Allow external session description modifications. // Allow external session description modifications.
this.e.triggerHandler("sessiondescription", [sessionDescriptionObj, this]); this.e.triggerHandler("sessiondescription", [sessionDescriptionObj, this]);
// Always set local description. // Always set local description.
this.peerconnection.setLocalDescription(sessionDescription, _.bind(function() { this.peerconnection.setLocalDescription(sessionDescription, _.bind(function() {
console.log("Set local session description.", sessionDescription, this); console.log("Set local session description.", sessionDescription, this);
if (cb) { if (cb) {
cb(sessionDescriptionObj, this); cb(sessionDescriptionObj, this);
} }
}, this), _.bind(function(err) { }, this), _.bind(function(err) {
console.error("Set local session description failed", err); console.error("Set local session description failed", err);
this.close(); this.close();
this.e.triggerHandler("error", "failed_peerconnection_setup"); this.e.triggerHandler("error", "failed_peerconnection_setup");
}, this)); }, this));
}; };
PeerCall.prototype.onErrorAnswerOffer = function(event) { PeerCall.prototype.onErrorAnswerOffer = function(event) {
console.error("Failed to create answer/offer", event); console.error("Failed to create answer/offer", event);
}; };
PeerCall.prototype.setRemoteDescription = function(sessionDescription, cb) { PeerCall.prototype.setRemoteDescription = function(sessionDescription, cb) {
var peerconnection = this.peerconnection; var peerconnection = this.peerconnection;
if (!peerconnection) { if (!peerconnection) {
console.log("Got a remote description but not connected -> ignored."); console.log("Got a remote description but not connected -> ignored.");
return; return;
} }
peerconnection.setRemoteDescription(sessionDescription, _.bind(function() { peerconnection.setRemoteDescription(sessionDescription, _.bind(function() {
console.log("Set remote session description.", sessionDescription, this); console.log("Set remote session description.", sessionDescription, this);
if (cb) { if (cb) {
cb(sessionDescription, this); cb(sessionDescription, this);
} }
// NOTE(longsleep): There are several szenarios where onaddstream is never fired, when // NOTE(longsleep): There are several szenarios where onaddstream is never fired, when
// the peer does not provide a certain stream type (eg. has no camera). See // the peer does not provide a certain stream type (eg. has no camera). See
// for example https://bugzilla.mozilla.org/show_bug.cgi?id=998546. For this // for example https://bugzilla.mozilla.org/show_bug.cgi?id=998546. For this
// reason we always trigger onRemoteStream added for all streams which are available // reason we always trigger onRemoteStream added for all streams which are available
// after the remote SDP was set successfully. // after the remote SDP was set successfully.
_.defer(_.bind(function() { _.defer(_.bind(function() {
_.each(peerconnection.getRemoteStreams(), _.bind(function(stream) { _.each(peerconnection.getRemoteStreams(), _.bind(function(stream) {
console.log("got stream after remote sdp", stream); if (!this.streams.hasOwnProperty(stream)) {
if (!this.streams.hasOwnProperty(stream)) { console.log("Adding stream after remote SDP success.", stream);
console.log("adding stream", stream); this.onRemoteStreamAdded(stream);
this.onRemoteStreamAdded(stream); }
} }, this));
}, this)); }, this));
}, this)); }, this), _.bind(function(err) {
}, this), _.bind(function(err) { console.error("Set remote session description failed", err);
console.error("Set remote session description failed", err); this.close();
this.close(); this.e.triggerHandler("error", "failed_peerconnection_setup");
this.e.triggerHandler("error", "failed_peerconnection_setup"); }, this));
}, this));
}; };
PeerCall.prototype.onIceCandidate = function(event) { PeerCall.prototype.onIceCandidate = function(event) {
if (event.candidate) { if (event.candidate) {
//console.log("ice candidate", event.candidate); //console.log("ice candidate", event.candidate);
var payload = { var payload = {
type: 'candidate', type: 'candidate',
sdpMLineIndex: event.candidate.sdpMLineIndex, sdpMLineIndex: event.candidate.sdpMLineIndex,
sdpMid: event.candidate.sdpMid, sdpMid: event.candidate.sdpMid,
candidate: event.candidate.candidate candidate: event.candidate.candidate
}; };
// Allow external payload modifications. // Allow external payload modifications.
this.e.triggerHandler("icecandidate", [payload, this]); this.e.triggerHandler("icecandidate", [payload, this]);
// Send it. // Send it.
// TODO(longsleep): This id needs to be different for PeerXfers. // TODO(longsleep): This id needs to be different for PeerXfers.
// XXX(longsleep): This seems to be breaking conferences when this.to and not this.id. // XXX(longsleep): This seems to be breaking conferences when this.to and not this.id.
this.webrtc.api.sendCandidate(this.to, payload); this.webrtc.api.sendCandidate(this.to, payload);
//console.log("Sent candidate", event.candidate.sdpMid, event.candidate.sdpMLineIndex, event.candidate.candidate); //console.log("Sent candidate", event.candidate.sdpMid, event.candidate.sdpMLineIndex, event.candidate.candidate);
} else { } else {
console.log('End of candidates.'); console.log('End of candidates.');
} }
}; };
PeerCall.prototype.onIceConnectionStateChange = function(iceConnectionState) { PeerCall.prototype.onIceConnectionStateChange = function(iceConnectionState) {
this.e.triggerHandler("connectionStateChange", [iceConnectionState, this]); this.e.triggerHandler("connectionStateChange", [iceConnectionState, this]);
}; };
PeerCall.prototype.onRemoteStreamAdded = function(stream) { PeerCall.prototype.onRemoteStreamAdded = function(stream) {
this.streams[stream] = true; this.streams[stream] = true;
this.e.triggerHandler("remoteStreamAdded", [stream, this]); this.e.triggerHandler("remoteStreamAdded", [stream, this]);
}; };
PeerCall.prototype.onRemoteStreamRemoved = function(stream) { PeerCall.prototype.onRemoteStreamRemoved = function(stream) {
this.e.triggerHandler("remoteStreamRemoved", [stream, this]); this.e.triggerHandler("remoteStreamRemoved", [stream, this]);
if (stream) { if (stream) {
delete this.streams[stream]; delete this.streams[stream];
} }
}; };
PeerCall.prototype.onNegotiationNeeded = function(peerconnection) { PeerCall.prototype.onNegotiationNeeded = function(peerconnection) {
var remoteDescription = peerconnection.pc.remoteDescription; var remoteDescription = peerconnection.pc.remoteDescription;
console.log("Negotiation needed.", remoteDescription); console.log("Negotiation needed.", remoteDescription);
if (remoteDescription && remoteDescription.type === "offer") { if (remoteDescription && remoteDescription.type === "offer") {
// Need to answer. // Need to answer.
// XXX(longsleep): In cases where we are in answer state but need to // XXX(longsleep): In cases where we are in answer state but need to
// negotiate again, createAnswer will do nothing. We might need to call // negotiate again, createAnswer will do nothing. We might need to call
// createOffer and send it out as answer? Is that valid / makes sense? // createOffer and send it out as answer? Is that valid / makes sense?
this.createAnswer(_.bind(function(sessionDescription) { this.createAnswer(_.bind(function(sessionDescription) {
console.log("Sending new negotiation answer with sessionDescription", sessionDescription, this.id); console.log("Sending new negotiation answer with sessionDescription", sessionDescription, this.id);
this.webrtc.api.sendAnswer(this.to, sessionDescription); this.webrtc.api.sendAnswer(this.to, sessionDescription);
}, this)); }, this));
} else { } else {
// Send offer. // Send offer.
this.createOffer(_.bind(function(sessionDescription) { this.createOffer(_.bind(function(sessionDescription) {
console.log("Sending new negotiation offer with sessionDescription", sessionDescription, this.id); console.log("Sending new negotiation offer with sessionDescription", sessionDescription, this.id);
this.webrtc.api.sendOffer(this.to, sessionDescription); this.webrtc.api.sendOffer(this.to, sessionDescription);
}, this)); }, this));
} }
}; };
PeerCall.prototype.addIceCandidate = function(candidate) { PeerCall.prototype.addIceCandidate = function(candidate) {
if (this.closed) { if (this.closed) {
// Avoid errors when still receiving candidates but closed. // Avoid errors when still receiving candidates but closed.
return; return;
} }
this.peerconnection.addIceCandidate(candidate); this.peerconnection.addIceCandidate(candidate);
}; };
PeerCall.prototype.onDatachannel = function(datachannel) { PeerCall.prototype.onDatachannel = function(datachannel) {
//console.log("onDatachannel", datachannel); //console.log("onDatachannel", datachannel);
var label = datachannel.label; var label = datachannel.label;
if (this.datachannels.hasOwnProperty(label)) { if (this.datachannels.hasOwnProperty(label)) {
console.warn("Received duplicated datachannel label", label, datachannel, this.datachannels); console.warn("Received duplicated datachannel label", label, datachannel, this.datachannels);
return; return;
} }
// Remember it for correct cleanups. // Remember it for correct cleanups.
this.datachannels[label] = datachannel; this.datachannels[label] = datachannel;
this.e.triggerHandler("datachannel", ["new", datachannel, this]); this.e.triggerHandler("datachannel", ["new", datachannel, this]);
}; };
PeerCall.prototype.onDatachannelDefault = function(state, datachannel) { PeerCall.prototype.onDatachannelDefault = function(state, datachannel) {
if (state === "open") { if (state === "open") {
//console.log("Data ready", this); //console.log("Data ready", this);
_.defer(_.bind(function() { _.defer(_.bind(function() {
this.e.triggerHandler("dataReady", [this]); this.e.triggerHandler("dataReady", [this]);
}, this)); }, this));
} }
this.e.triggerHandler("datachannel.default", [state, datachannel, this]); this.e.triggerHandler("datachannel.default", [state, datachannel, this]);
}; };
PeerCall.prototype.onMessage = function(event) { PeerCall.prototype.onMessage = function(event) {
//console.log("Peer to peer channel message", event); //console.log("Peer to peer channel message", event);
var data = event.data; var data = event.data;
if (data instanceof Blob) { if (data instanceof Blob) {
console.warn("Blob data received - not implemented.", data); console.warn("Blob data received - not implemented.", data);
} else if (data instanceof ArrayBuffer) { } else if (data instanceof ArrayBuffer) {
console.warn("ArrayBuffer data received - not implemented.", data); console.warn("ArrayBuffer data received - not implemented.", data);
} else if (typeof data === "string") { } else if (typeof data === "string") {
if (data.charCodeAt(0) === 2) { if (data.charCodeAt(0) === 2) {
// Ignore whatever shit is this (sent by Chrome 34 and FireFox). Feel free to // Ignore whatever shit is this (sent by Chrome 34 and FireFox). Feel free to
// change the comment it you know what this is. // change the comment it you know what this is.
return; return;
} }
//console.log("Datachannel message", [event.data, event.data.length, event.data.charCodeAt(0)]); //console.log("Datachannel message", [event.data, event.data.length, event.data.charCodeAt(0)]);
var msg = JSON.parse(event.data); var msg = JSON.parse(event.data);
this.webrtc.api.received({Type: msg.Type, Data: msg, To: this.webrtc.api.id, From: this.id, p2p: true}); //XXX(longsleep): use event for this? this.webrtc.api.received({Type: msg.Type, Data: msg, To: this.webrtc.api.id, From: this.id, p2p: true}); //XXX(longsleep): use event for this?
} else { } else {
console.warn("Unknow data type received -> igored", typeof data, [data]); console.warn("Unknow data type received -> igored", typeof data, [data]);
} }
}; };
PeerCall.prototype.getDatachannel = function(label, init, create_cb) { PeerCall.prototype.getDatachannel = function(label, init, create_cb) {
//console.log("getDatachannel", label); //console.log("getDatachannel", label);
var datachannel = this.datachannels[label]; var datachannel = this.datachannels[label];
if (!datachannel) { if (!datachannel) {
console.log("Creating new datachannel", label, init); console.log("Creating new datachannel", label, init);
datachannel = this.peerconnection.createDatachannel(label, init); datachannel = this.peerconnection.createDatachannel(label, init);
if (create_cb) { if (create_cb) {
create_cb(datachannel); create_cb(datachannel);
} }
} }
return datachannel; return datachannel;
}; };
PeerCall.prototype.close = function() { PeerCall.prototype.close = function() {
if (this.closed) { if (this.closed) {
return; return;
} }
this.closed = true; this.closed = true;
_.each(this.datachannels, function(datachannel) { _.each(this.datachannels, function(datachannel) {
datachannel.close(); datachannel.close();
}); });
this.datachannels = {}; this.datachannels = {};
this.streams = {}; this.streams = {};
if (this.peerconnection) { if (this.peerconnection) {
this.peerconnection.close(); this.peerconnection.close();
this.peerconnection = null; this.peerconnection = null;
} }
console.log("Peercall close", this); console.log("Peercall close", this);
this.e.triggerHandler("closed", [this]); this.e.triggerHandler("closed", [this]);
}; };

Loading…
Cancel
Save