Permalink
Browse files

fix(P2P): multiplex between JVB and P2P ICE status

Will make sure that when in P2P mode the conference will be updated
with the ICE state coming from P2P and when in the JVB mode will get
the JVB one.
  • Loading branch information...
paweldomas committed Feb 21, 2017
1 parent 2a0d4d1 commit 80369256df2af6eba3d0d084c10d77e1bf215d21
Showing with 162 additions and 21 deletions.
  1. +38 −0 JitsiConference.js
  2. +6 −16 JitsiConferenceEventManager.js
  3. +118 −5 P2PEnabledConference.js
View
@@ -21,6 +21,7 @@ import ParticipantConnectionStatus
from "./modules/connectivity/ParticipantConnectionStatus";
import TalkMutedDetection from "./modules/TalkMutedDetection";
import ConnectionQuality from "./modules/connectivity/ConnectionQuality";
import * as XMPPEvents from "./service/xmpp/XMPPEvents";
/**
* Creates a JitsiConference object with the given name and properties.
@@ -106,6 +107,16 @@ JitsiConference.prototype._init = function (options) {
this.room = this.xmpp.createRoom(this.options.name, this.options.config);
// Connection interrupted/restored listeners
this._onIceConnectionInterrupted
= this._onIceConnectionInterrupted.bind(this);
this.room.addListener(
XMPPEvents.CONNECTION_INTERRUPTED, this._onIceConnectionInterrupted);
this._onIceConnectionRestored = this._onIceConnectionRestored.bind(this);
this.room.addListener(
XMPPEvents.CONNECTION_RESTORED, this._onIceConnectionRestored);
this.room.updateDeviceAvailability(RTC.getDeviceAvailability());
if(!this.rtc) {
@@ -180,6 +191,15 @@ JitsiConference.prototype.leave = function () {
// leave the conference
if (this.room) {
let room = this.room;
// Unregister connection state listeners
room.removeListener(
XMPPEvents.CONNECTION_INTERRUPTED,
this._onIceConnectionInterrupted);
room.removeListener(
XMPPEvents.CONNECTION_RESTORED,
this._onIceConnectionRestored);
this.room = null;
return room.leave().catch(() => {
// remove all participants because currently the conference won't
@@ -1502,4 +1522,22 @@ JitsiConference.prototype.isConnectionInterrupted = function () {
return this.connectionIsInterrupted;
};
/**
* Handles {@link XMPPEvents.CONNECTION_INTERRUPTED}
* @private
*/
JitsiConference.prototype._onIceConnectionInterrupted = function () {
this.connectionIsInterrupted = true;
this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
};
/**
* Handles {@link XMPPEvents.CONNECTION_RESTORED}
* @private
*/
JitsiConference.prototype._onIceConnectionRestored = function () {
this.connectionIsInterrupted = false;
this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);
};
module.exports = JitsiConference;
@@ -25,6 +25,12 @@ function JitsiConferenceEventManager(conference) {
conference.statistics.sendMuteEvent(track.isMuted(),
track.getType());
});
conference.on(
JitsiConferenceEvents.CONNECTION_INTERRUPTED,
Statistics.sendEventToAll.bind(Statistics, 'connection.interrupted'));
conference.on(
JitsiConferenceEvents.CONNECTION_RESTORED,
Statistics.sendEventToAll.bind(Statistics, 'connection.restored'));
}
/**
@@ -160,28 +166,12 @@ JitsiConferenceEventManager.prototype.setupChatRoomListeners = function () {
chatRoom.addListener(XMPPEvents.SESSION_ACCEPT_TIMEOUT,
eventLogHandler.bind(null, "sessionAcceptTimeout"));
this.chatRoomForwarder.forward(XMPPEvents.CONNECTION_INTERRUPTED,
JitsiConferenceEvents.CONNECTION_INTERRUPTED);
chatRoom.addListener(XMPPEvents.CONNECTION_INTERRUPTED,
() => {
Statistics.sendEventToAll('connection.interrupted');
this.conference.connectionIsInterrupted = true;
});
this.chatRoomForwarder.forward(XMPPEvents.RECORDER_STATE_CHANGED,
JitsiConferenceEvents.RECORDER_STATE_CHANGED);
this.chatRoomForwarder.forward(XMPPEvents.PHONE_NUMBER_CHANGED,
JitsiConferenceEvents.PHONE_NUMBER_CHANGED);
this.chatRoomForwarder.forward(XMPPEvents.CONNECTION_RESTORED,
JitsiConferenceEvents.CONNECTION_RESTORED);
chatRoom.addListener(XMPPEvents.CONNECTION_RESTORED,
() => {
Statistics.sendEventToAll('connection.restored');
this.conference.connectionIsInterrupted = false;
});
this.chatRoomForwarder.forward(XMPPEvents.CONFERENCE_SETUP_FAILED,
JitsiConferenceEvents.CONFERENCE_FAILED,
JitsiConferenceErrors.SETUP_FAILED);
View
@@ -39,6 +39,12 @@ export default class P2PEnabledConference extends JitsiConference {
*/
constructor(options) {
super(options);
// Original this.eventEmitter.emit method, stored to skip the event
// filtering logic
this._originalEmit = this.eventEmitter.emit.bind(this.eventEmitter);
// Intercepts original event emitter calls to filter out some of
// the conference events
this.eventEmitter.emit = this._emitIntercept.bind(this);
/**
* Stores reference to deferred start P2P task. It's created when 3rd
* participant leaves the room in order to avoid ping pong effect (it
@@ -56,6 +62,13 @@ export default class P2PEnabledConference extends JitsiConference {
this.backToP2PDelay = isNaN(delay) ? 5 : delay;
logger.info("backToP2PDelay: " + this.backToP2PDelay);
/**
* If set to <tt>true</tt> it means the P2P ICE is no longer connected.
* When <tt>false</tt> it means that P2P ICE (media) connection is up
* and running.
* @type {boolean}
*/
this.isP2PConnectionInterrupted = false;
/**
* Flag set to <tt>true</tt> when P2P session has been established
* (ICE has been connected).
@@ -197,6 +210,26 @@ export default class P2PEnabledConference extends JitsiConference {
return Promise.all(allPromises);
}
/**
* Intercepts events emitted by parent <tt>JitsiConference</tt>
* @private
*/
_emitIntercept(eventType) {
const shouldBlock = this._shouldBlockEvent(eventType);
switch (eventType) {
// Log events which may be of interest for the P2P implementation
case JitsiConferenceEvents.CONNECTION_INTERRUPTED:
case JitsiConferenceEvents.CONNECTION_RESTORED:
case JitsiConferenceEvents.P2P_STATUS:
logger.debug(
"_emitIntercept: block? " + shouldBlock, arguments);
break;
}
if (!shouldBlock) {
this._originalEmit.apply(this.eventEmitter, arguments);
}
}
/**
* @inheritDoc
* @override
@@ -226,10 +259,8 @@ export default class P2PEnabledConference extends JitsiConference {
logger.error("CONNECTION_ESTABLISHED - not P2P session ?!");
return;
}
logger.info("Peer to peer connection established!");
this.p2pEstablished = true;
this.eventEmitter.emit(
JitsiConferenceEvents.P2P_STATUS, this, this.p2pEstablished);
// Update P2P status and emit events
this._setP2PStatus(true);
// Remove remote tracks
this._removeRemoteJVBTracks();
@@ -315,6 +346,53 @@ export default class P2PEnabledConference extends JitsiConference {
return Promise.all(allPromises);
}
/**
* Sets new P2P status and updates some events/states hijacked from
* the <tt>JitsiConference</tt>.
* @param {boolean} newStatus the new P2P status value, <tt>true</tt> means
* that P2P is now in use, <tt>false</tt> means that the JVB connection is
* now in use.
* @private
*/
_setP2PStatus (newStatus) {
if (this.p2pEstablished === newStatus) {
logger.error(
"Called _setP2PStatus with the same status: " + newStatus);
return;
}
this.p2pEstablished = newStatus;
if (newStatus) {
logger.info("Peer to peer connection established!");
} else {
logger.info("Peer to peer connection closed!");
}
// Update P2P status
this.eventEmitter.emit(
JitsiConferenceEvents.P2P_STATUS, this, this.p2pEstablished);
// Refresh connection interrupted/restored
this._originalEmit(
this.isConnectionInterrupted()
? JitsiConferenceEvents.CONNECTION_INTERRUPTED
: JitsiConferenceEvents.CONNECTION_RESTORED);
}
/**
* Checks whether or not given event coming from
* the <tt>JitsiConference</tt> should be blocked or not.
* @param {string} eventType the event type name
* @return {boolean} <tt>true</tt> to block or <tt>false</tt> to let through
* @private
*/
_shouldBlockEvent (eventType) {
switch (eventType) {
case JitsiConferenceEvents.CONNECTION_INTERRUPTED:
case JitsiConferenceEvents.CONNECTION_RESTORED:
return this.p2pEstablished;
default:
return false;
}
}
/**
* Starts new P2P session.
* @param {string} peerJid the JID of the remote participant
@@ -473,7 +551,7 @@ export default class P2PEnabledConference extends JitsiConference {
// Clear fake room state
this.p2pFakeRoom = null;
// Update P2P status and other affected events/states
this._setNewP2PStatus(false);
this._setP2PStatus(false);
// Start remote stats
logger.info("Starting remote stats with JVB connection");
@@ -482,6 +560,17 @@ export default class P2PEnabledConference extends JitsiConference {
}
}
/**
* Tells whether or not the media connection has been interrupted based on
* the current P2P vs JVB status.
* @inheritDoc
* @override
*/
isConnectionInterrupted () {
return this.p2pEstablished
? this.isP2PConnectionInterrupted : super.isConnectionInterrupted();
}
/**
* @inheritDoc
* @override
@@ -624,6 +713,26 @@ export default class P2PEnabledConference extends JitsiConference {
this._startStopP2PSession(true /* triggered by user left event */);
}
/**
* Called when {@link XMPPEvents.CONNECTION_INTERRUPTED} occurs on the P2P
* connection.
*/
onP2PIceConnectionInterrupted () {
this.isP2PConnectionInterrupted = true;
if (this.p2pEstablished)
this._originalEmit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
}
/**
* Called when {@link XMPPEvents.CONNECTION_RESTORED} occurs on the P2P
* connection.
*/
onP2PIceConnectionRestored () {
this.isP2PConnectionInterrupted = false;
if (this.p2pEstablished)
this._originalEmit(JitsiConferenceEvents.CONNECTION_RESTORED);
}
/**
* @inheritDoc
* @override
@@ -729,6 +838,10 @@ class FakeChatRoomLayer {
logger.debug("Fake emit: ", type, arguments);
if (type === XMPPEvents.CONNECTION_ESTABLISHED) {
self.p2pConf._onP2PConnectionEstablished(arguments[1]);
} else if (type === XMPPEvents.CONNECTION_INTERRUPTED) {
self.p2pConf.onP2PIceConnectionInterrupted();
} else if (type === XMPPEvents.CONNECTION_RESTORED) {
self.p2pConf.onP2PIceConnectionRestored();
}
}
};

0 comments on commit 8036925

Please sign in to comment.