providers/core/core.rtcpeerconnection.js
/*jslint indent:2,sloppy:true, node:true */
var PromiseCompat = require('es6-promise').Promise;
var wrtcClass, RTCPeerConnection, RTCSessionDescription, RTCIceCandidate;
var DataChannel = require('./core.rtcdatachannel');
var RTCPeerConnectionAdapter = function (cap, dispatchEvent, configuration) {
if (typeof wrtcClass === 'undefined') {
// only works in browser, so node should use setImpl (see exports)
var adapter = require('webrtc-adapter');
RTCPeerConnection = adapter.RTCPeerConnection;
RTCSessionDescription = adapter.RTCSessionDescription;
RTCIceCandidate = adapter.RTCIceCandidate;
} else {
RTCPeerConnection = wrtcClass.RTCPeerConnection;
RTCSessionDescription = wrtcClass.RTCSessionDescription;
RTCIceCandidate = wrtcClass.RTCIceCandidate;
}
this.dispatchEvent = dispatchEvent;
try {
this.connection = new RTCPeerConnection(configuration);
} catch (e) {
// Note: You can't ask the provider to close you synchronously, since
// the constructor has not yet returned, so there's no 'this' that
// the provider can know about yet.
setTimeout(cap.provider.close.bind(cap.provider, this), 0);
return;
}
this.events = [
'ondatachannel',
'onnegotiationneeded',
'onicecandidate',
'onsignalingstatechange',
'onaddstream',
'onremovestream',
'oniceconnectionstatechange'
];
this.manageEvents(true);
};
// Attach or detach listeners for events against the connection.
RTCPeerConnectionAdapter.prototype.manageEvents = function (attach) {
this.events.forEach(function (event) {
if (attach) {
this[event] = this[event].bind(this);
this.connection[event] = this[event];
} else if (this.connection) {
delete this.connection[event];
}
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.createOffer = function (constraints) {
return new PromiseCompat(function (resolve, reject) {
this.connection.createOffer(resolve, reject, constraints);
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.createAnswer = function () {
return new PromiseCompat(function (resolve, reject) {
this.connection.createAnswer(resolve, reject);
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.setLocalDescription = function (description) {
return new PromiseCompat(function (resolve, reject) {
this.connection.setLocalDescription(new RTCSessionDescription(description),
resolve, reject);
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.getLocalDescription = function () {
return PromiseCompat.resolve(this.connection.localDescription);
};
RTCPeerConnectionAdapter.prototype.setRemoteDescription = function (description) {
return new PromiseCompat(function (resolve, reject) {
this.connection.setRemoteDescription(new RTCSessionDescription(description),
resolve, reject);
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.getRemoteDescription = function () {
return PromiseCompat.resolve(this.connection.remoteDescription);
};
RTCPeerConnectionAdapter.prototype.getSignalingState = function () {
return PromiseCompat.resolve(this.connection.signalingState);
};
RTCPeerConnectionAdapter.prototype.updateIce = function (configuration) {
this.connection.updateIce(configuration);
return PromiseCompat.resolve();
};
RTCPeerConnectionAdapter.prototype.addIceCandidate = function (candidate) {
return new PromiseCompat(function (resolve, reject) {
this.connection.addIceCandidate(new RTCIceCandidate(candidate),
resolve, reject);
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.getIceGatheringState = function () {
return PromiseCompat.resolve(this.connection.iceGatheringState);
};
RTCPeerConnectionAdapter.prototype.getIceConnectionState = function () {
return PromiseCompat.resolve(this.connection.iceConnectionState);
};
RTCPeerConnectionAdapter.prototype.getConfiguration = function () {
var configuration = this.connection.getConfiguration();
return PromiseCompat.resolve(configuration);
};
RTCPeerConnectionAdapter.prototype.getLocalStreams = function () {
return PromiseCompat.reject({
errcode: -1,
message: "Not Implemented"
});
};
RTCPeerConnectionAdapter.prototype.getRemoteStreams = function () {
return PromiseCompat.reject({
errcode: -1,
message: "Not Implemented"
});
};
RTCPeerConnectionAdapter.prototype.getStreamById = function (id) {
return PromiseCompat.reject({
errcode: -1,
message: "Not Implemented"
});
};
RTCPeerConnectionAdapter.prototype.addStream = function (id) {
return PromiseCompat.reject({
errcode: -1,
message: "Not Implemented"
});
};
RTCPeerConnectionAdapter.prototype.removeStream = function (id) {
return PromiseCompat.reject({
errcode: -1,
message: "Not Implemented"
});
};
RTCPeerConnectionAdapter.prototype.close = function () {
if (!this.connection) {
return PromiseCompat.resolve();
}
this.manageEvents(false);
try {
this.connection.close();
return PromiseCompat.resolve();
} catch (e) {
return PromiseCompat.reject({
errcode: e.name,
message: e.message
});
}
};
RTCPeerConnectionAdapter.prototype.createDataChannel = function (label, dataChannelDict) {
var id = DataChannel.allocate(this.connection.createDataChannel(label, dataChannelDict));
return PromiseCompat.resolve(id);
};
RTCPeerConnectionAdapter.prototype.getStats = function (selector) {
return new PromiseCompat(function (resolve, reject) {
if (typeof wrtcClass === 'undefined') {
// used webrtc-adapter
this.connection.getStats(selector, resolve, reject);
} else {
// node-wrtc has different getStats API
this.connection.getStats(function(response) {
var standardReport = {};
var reports = response.result();
var id = 0; // nodewrtc stats report lacks id field
reports.forEach(function (report) {
report.id = String(id++); // string to use as object key
standardReport[report.id] = report;
});
resolve(standardReport);
}, reject);
}
}.bind(this));
};
RTCPeerConnectionAdapter.prototype.ondatachannel = function (event) {
var id = DataChannel.allocate(event.channel);
this.dispatchEvent('ondatachannel', {channel: id});
};
RTCPeerConnectionAdapter.prototype.onnegotiationneeded = function (event) {
this.dispatchEvent('onnegotiationneeded', event.message);
};
RTCPeerConnectionAdapter.prototype.onicecandidate = function (event) {
var msg;
if (event.candidate && event.candidate.candidate) {
msg = {
candidate: {
candidate: event.candidate.candidate,
sdpMid: event.candidate.sdpMid,
sdpMLineIndex: event.candidate.sdpMLineIndex
}
};
} else {
msg = {
candidate: null
};
}
this.dispatchEvent('onicecandidate', msg);
};
RTCPeerConnectionAdapter.prototype.onsignalingstatechange = function (event) {
this.dispatchEvent('onsignalingstatechange', event.message);
};
RTCPeerConnectionAdapter.prototype.onaddstream = function (event) {
//TODO: provide ID of allocated stream.
this.dispatchEvent('onaddstream', event.stream);
};
RTCPeerConnectionAdapter.prototype.onremovestream = function (event) {
//TODO: provide ID of deallocated stream.
this.dispatchEvent('onremovestream', event.stream);
};
RTCPeerConnectionAdapter.prototype.oniceconnectionstatechange = function (event) {
this.dispatchEvent('oniceconnectionstatechange', event.message);
};
exports.name = "core.rtcpeerconnection";
exports.provider = RTCPeerConnectionAdapter;
exports.style = "providePromises";
exports.flags = {provider: true};
exports.setImpl = function(impl) {
"use strict";
wrtcClass = impl;
};