Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 6ea30e7

Browse files
committed
Implement perfect negotiation for WebRTC collision.
1 parent e474ca5 commit 6ea30e7

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

src/sdk/p2p/p2pclient.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const P2PClient = function(configuration, signalingChannel) {
101101
return;
102102
}
103103
if (connectionIds.has(origin) &&
104-
connectionIds.get(origin) != connectionId && !isPolitePeer(origin)) {
104+
connectionIds.get(origin) !== connectionId && !isPolitePeer(origin)) {
105105
Logger.warning(
106106
// eslint-disable-next-line max-len
107107
'Collision detected, ignore this message because current endpoint is impolite peer.');
@@ -295,8 +295,8 @@ const P2PClient = function(configuration, signalingChannel) {
295295
if (!connectionId) {
296296
const connectionIdLimit = 100000;
297297
connectionId = Math.round(Math.random() * connectionIdLimit);
298-
connectionIds.set(remoteId, connectionId);
299298
}
299+
connectionIds.set(remoteId, connectionId);
300300
if (!channels.has(remoteId)) {
301301
// Construct an signaling sender/receiver for P2PPeerConnection.
302302
const signalingForChannel = Object.create(EventDispatcher);

src/sdk/p2p/peerconnection-channel.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class P2PPeerConnectionChannel extends EventDispatcher {
9393
this._dataSeq = 1; // Sequence number for data channel messages.
9494
this._sendDataPromises = new Map(); // Key is data sequence number, value is an object has |resolve| and |reject|.
9595
this._addedTrackIds = []; // Tracks that have been added after receiving remote SDP but before connection is established. Draining these messages when ICE connection state is connected.
96-
this._isCaller = true;
96+
this._isPolitePeer = localId < remoteId;
9797
this._infoSent = false;
9898
this._disposed = false;
9999
this._createPeerConnection();
@@ -416,6 +416,15 @@ class P2PPeerConnectionChannel extends EventDispatcher {
416416
_onOffer(sdp) {
417417
Logger.debug('About to set remote description. Signaling state: ' +
418418
this._pc.signalingState);
419+
if (this._pc.signalingState !== 'stable') {
420+
if (this._isPolitePeer) {
421+
// Rollback.
422+
this._pc.setLocalDescription();
423+
} else {
424+
// Ignore this offer.
425+
return;
426+
}
427+
}
419428
sdp.sdp = this._setRtpSenderOptions(sdp.sdp, this._config);
420429
// Firefox only has one codec in answer, which does not truly reflect its
421430
// decoding capability. So we set codec preference to remote offer, and let

test/unit/resources/scripts/fake-p2p-signaling.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export default class FakeP2PSignalingChannel {
3939
}
4040

4141
send(targetId, message) {
42-
Logger.debug(this.userId + ' -> ' + targetId + ': ' + message);
4342
return new Promise((resolve, reject) => {
4443
messageQueue.push({ target: targetId, message, resolve, reject, sender: this.userId });
4544
setTimeout(() => {

test/unit/resources/scripts/p2p.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,27 @@ describe('Unit tests for P2PClient', function() {
157157
//expect(Promise.all([p2pclient1.send('user2', 'message'), p2pclient2.send('user1', 'message')])).to.be.fulfilled.and.notify(done);
158158
// TODO: Check messages are received.
159159
});
160+
it('WebRTC collision should be resolved.', async () => {
161+
const c1Spy = new sinon.spy();
162+
const c2Spy = new sinon.spy();
163+
p2pclient1.addEventListener('messagereceived',c1Spy);
164+
p2pclient2.addEventListener('messagereceived',c2Spy);
165+
await p2pclient1.publish('user2', localStream);
166+
// Both sides create PeerConnection. It cannot 100% sure to trigger WebRTC
167+
// collision. But it has a high chance that `setRemoteDescription` get
168+
// failed. However, even `setRemoteDescription` is failed, the SDK stops
169+
// `PeerConnection` silently without firing an event. So this test case
170+
// cannot detect failures like this.
171+
await Promise.all([
172+
p2pclient1.send('user2', 'message'), p2pclient2.send('user1', 'message')
173+
]);
174+
await new Promise(resolve => {
175+
setTimeout(() => {
176+
expect(c1Spy.callCount).to.equal(1);
177+
expect(c2Spy.callCount).to.equal(1);
178+
resolve();
179+
}, 100);
180+
});
181+
});
160182
});
161183
});

0 commit comments

Comments
 (0)