Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/RTCPeerConnection.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Mandatory Object holding the [`RTCConfiguration`](http://w3c.github.io/webrtc-pc
There are also custom options not present in the WebRTC specification:

* `gatheringTimeout` {Number}: ICE gathering is terminated after the given time (milliseconds) and a faked `onicecandidate` event with `candidate = null` is fired. No more `onicecandidate` events are fired once this timeout.
* `gatheringTimeoutAfterHost` {Number}: Once the first "host" candidate is gathered, ICE gathering is terminated after the given time (milliseconds) and a faked `onicecandidate` event with `candidate = null` is fired. No more `onicecandidate` events are fired once this timeout.
* `gatheringTimeoutAfterRelay` {Number}: Once the first "relay" (TURN) candidate is gathered, ICE gathering is terminated after the given time (milliseconds) and a faked `onicecandidate` event with `candidate = null` is fired. No more `onicecandidate` events are fired once this timeout.


Expand Down
135 changes: 63 additions & 72 deletions lib/RTCPeerConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var merge = require('merge'),
REGEXP_NORMALIZED_CANDIDATE: new RegExp(/^candidate:/i),
REGEXP_FIX_CANDIDATE: new RegExp(/(^a=|\r|\n)/gi),
REGEXP_RELAY_CANDIDATE: new RegExp(/ relay /i),
REGEXP_HOST_CANDIDATE: / typ host/i,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May you follow the same syntax here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that.

Why do you use the RegExp constructor in the first place?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would accept the faster solution regardless which one it is. I expected that creating a RegExp instance is the same as creating a literal regexp.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The literal regexp already returns a RegExp instance. So what you're doing is basically taking a RegExp and constructing a new instance of it - 2 instances in total.

I'll update the PR with a commit that removes all unnecessary RegExp constructions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, thanks.

REGEXP_SDP_CANDIDATES: new RegExp(/^a=candidate:.*\r\n/igm),
REGEXP_SDP_NON_RELAY_CANDIDATES: new RegExp(/^a=candidate:(.(?!relay ))*\r\n/igm)
},
Expand Down Expand Up @@ -47,11 +48,13 @@ function RTCPeerConnection(pcConfig, pcConstraints) {
this.ourIceConnectionState = null;
this.ourIceGatheringState = null;

// Timer for options.gatheringTimeout.
this.timerGatheringTimeout = null;

// Timer for options.gatheringTimeoutAfterRelay.
this.timerGatheringTimeoutAfterRelay = null;
// Timers (used by installGatheringTimeoutTimer and clearGatheringTimers).
// Each timer corresponds to a key in options, e.g. options.gatheringTimeout.
this.timers = {
gatheringTimeout: null,
gatheringTimeoutAfterHost: null,
gatheringTimeoutAfterRelay: null
};

// Flag to ignore new gathered ICE candidates.
this.ignoreIceGathering = false;
Expand Down Expand Up @@ -143,11 +146,7 @@ RTCPeerConnection.prototype.setLocalDescription = function (description, success
}
debug('setLocalDescription() | success');

// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
clearGatheringTimers.call(self);

runTimerGatheringTimeout();
if (successCallback) {
Expand All @@ -171,37 +170,15 @@ RTCPeerConnection.prototype.setLocalDescription = function (description, success

// Handle gatheringTimeout.
function runTimerGatheringTimeout() {
if (typeof self.options.gatheringTimeout !== 'number') {
return;
}
// If setLocalDescription was already called, it may happen that
// ICE gathering is not needed, so don't run this timer.
if (self.pc.iceGatheringState === 'complete') {
return;
}

debug('setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)',
self.options.gatheringTimeout);

self.timerGatheringTimeout = setTimeout(function () {
if (isClosed.call(self)) {
return;
}

debug('forced end of candidates after gatheringTimeout timeout');

// Clear gathering timers.
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;

// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({ candidate: null }, null);
}

}, self.options.gatheringTimeout);
if (installGatheringTimeoutTimer.call(self, 'gatheringTimeout')) {
debug('setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)', self.options.gatheringTimeout);
}
}
};

Expand Down Expand Up @@ -324,11 +301,7 @@ RTCPeerConnection.prototype.close = function () {

this.closed = true;

// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
clearGatheringTimers.call(this);

this.pc.close();
};
Expand Down Expand Up @@ -388,11 +361,7 @@ RTCPeerConnection.prototype.reset = function (pcConfig) {
pc.onidpassertionerror = null;
pc.onidpvalidationerror = null;

// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
clearGatheringTimers.call(this);

// Silently close the old PC.
debug('reset() | closing current peerConnection');
Expand All @@ -419,11 +388,13 @@ function setConfigurationAndOptions(pcConfig) {
iceTransportsRelay: (this.pcConfig.iceTransports === 'relay'),
iceTransportsNone: (this.pcConfig.iceTransports === 'none'),
gatheringTimeout: this.pcConfig.gatheringTimeout,
gatheringTimeoutAfterHost: this.pcConfig.gatheringTimeoutAfterHost,
gatheringTimeoutAfterRelay: this.pcConfig.gatheringTimeoutAfterRelay
};

// Remove custom rtcninja.RTCPeerConnection options from pcConfig.
delete this.pcConfig.gatheringTimeout;
delete this.pcConfig.gatheringTimeoutAfterHost;
delete this.pcConfig.gatheringTimeoutAfterRelay;

debug('setConfigurationAndOptions | processed pcConfig: %o', this.pcConfig);
Expand All @@ -435,6 +406,44 @@ function isClosed() {
}


function clearGatheringTimers() {
clearTimeout(this.timers.gatheringTimeout);
clearTimeout(this.timers.gatheringTimeoutAfterHost);
clearTimeout(this.timers.gatheringTimeoutAfterRelay);
}


function installGatheringTimeoutTimer(timerOptionName) {
var self = this,
timeout = self.options[timerOptionName];
if (typeof timeout !== 'number' || self.timers[timerOptionName]) {
// Did not install a timer because the timer options is not set,
// or the timer already exists.
return false;
}

self.timers[timerOptionName] = setTimeout(function () {
if (isClosed.call(self)) {
return;
}

debug('forced end of candidates after ' + timerOptionName + ' timeout');

clearGatheringTimers.call(self);

// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({candidate: null}, null);
}
}, timeout);

// Successfully installed a timer.
return true;
}



function setEvents() {
var self = this,
pc = this.pc;
Expand All @@ -451,7 +460,7 @@ function setEvents() {
};

pc.onicecandidate = function (event) {
var candidate, isRelay, newCandidate;
var candidate, isRelay, isHost, newCandidate;

if (isClosed.call(self)) {
return;
Expand All @@ -469,35 +478,21 @@ function setEvents() {

if (candidate) {
isRelay = C.REGEXP_RELAY_CANDIDATE.test(candidate.candidate);
isHost = C.REGEXP_HOST_CANDIDATE.test(candidate.candidate);

// Ignore if just relay candidates are requested.
if (self.options.iceTransportsRelay && !isRelay) {
return;
}

// Handle gatheringTimeoutAfterHost.
if (isHost && installGatheringTimeoutTimer.call(self, 'gatheringTimeoutAfterHost')) {
debug('onicecandidate() | first host candidate found, ending gathering in %d ms', self.options.gatheringTimeoutAfterHost);
}

// Handle gatheringTimeoutAfterRelay.
if (isRelay && !self.timerGatheringTimeoutAfterRelay &&
(typeof self.options.gatheringTimeoutAfterRelay === 'number')) {
if (isRelay && installGatheringTimeoutTimer.call(self, 'gatheringTimeoutAfterRelay')) {
debug('onicecandidate() | first relay candidate found, ending gathering in %d ms', self.options.gatheringTimeoutAfterRelay);

self.timerGatheringTimeoutAfterRelay = setTimeout(function () {
if (isClosed.call(self)) {
return;
}

debug('forced end of candidates after timeout');

// Clear gathering timers.
delete self.timerGatheringTimeoutAfterRelay;
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;

// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({candidate: null}, null);
}
}, self.options.gatheringTimeoutAfterRelay);
}

newCandidate = new Adapter.RTCIceCandidate({
Expand Down Expand Up @@ -530,11 +525,7 @@ function setEvents() {
} else {
debug('onicecandidate() | end of candidates');

// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
clearGatheringTimers.call(self);
if (self.onicecandidate) {
self.onicecandidate(event, null);
}
Expand Down