Merge pull request #2947 from mconf/webrtc-reconnect

WebRTC reconnect
This commit is contained in:
Chad Pilkey 2016-01-13 15:25:33 -05:00
commit 008d59c85d
5 changed files with 75 additions and 22 deletions

View File

@ -495,6 +495,9 @@ trait UsersApp {
usersModel.getUser(msg.userId) match { usersModel.getUser(msg.userId) match {
case Some(user) => { case Some(user) => {
// this is used to restore the mute state on reconnect
val previouslyMuted = user.voiceUser.muted
val vu = new VoiceUser(msg.voiceUserId, msg.userId, msg.callerIdName, val vu = new VoiceUser(msg.voiceUserId, msg.userId, msg.callerIdName,
msg.callerIdNum, joined = true, locked = false, msg.callerIdNum, joined = true, locked = false,
msg.muted, msg.talking, msg.listenOnly) msg.muted, msg.talking, msg.listenOnly)
@ -504,10 +507,10 @@ trait UsersApp {
log.info("User joined voice. meetingId=" + mProps.meetingID + " userId=" + user.userID + " user=" + nu) log.info("User joined voice. meetingId=" + mProps.meetingID + " userId=" + user.userID + " user=" + nu)
outGW.send(new UserJoinedVoice(mProps.meetingID, mProps.recorded, mProps.voiceBridge, nu)) outGW.send(new UserJoinedVoice(mProps.meetingID, mProps.recorded, mProps.voiceBridge, nu))
if (meetingModel.isMeetingMuted()) { if (meetingModel.isMeetingMuted() || previouslyMuted) {
outGW.send(new MuteVoiceUser(mProps.meetingID, mProps.recorded, outGW.send(new MuteVoiceUser(mProps.meetingID, mProps.recorded,
nu.userID, nu.userID, mProps.voiceBridge, nu.userID, nu.userID, mProps.voiceBridge,
nu.voiceUser.userId, meetingModel.isMeetingMuted())) nu.voiceUser.userId, true))
} }
startRecordingVoiceConference() startRecordingVoiceConference()

View File

@ -80,6 +80,9 @@ bbb.webrtcWarning.failedError.1011 = Error 1011: ICE gathering timeout
bbb.webrtcWarning.failedError.unknown = Error {0}: Unknown error code bbb.webrtcWarning.failedError.unknown = Error {0}: Unknown error code
bbb.webrtcWarning.failedError.mediamissing = Could not get your microphone for a WebRTC call bbb.webrtcWarning.failedError.mediamissing = Could not get your microphone for a WebRTC call
bbb.webrtcWarning.failedError.endedunexpectedly = The WebRTC echo test ended unexpectedly bbb.webrtcWarning.failedError.endedunexpectedly = The WebRTC echo test ended unexpectedly
bbb.webrtcWarning.connection.dropped = WebRTC connection dropped
bbb.webrtcWarning.connection.reconnecting = Attempting to reconnect
bbb.webrtcWarning.connection.reestablished = WebRTC connection re-established
bbb.mainToolbar.helpBtn = Help bbb.mainToolbar.helpBtn = Help
bbb.mainToolbar.logoutBtn = Logout bbb.mainToolbar.logoutBtn = Logout
bbb.mainToolbar.logoutBtn.toolTip = Log Out bbb.mainToolbar.logoutBtn.toolTip = Log Out

View File

@ -80,6 +80,10 @@ function callIntoConference(voiceBridge, callback, isListenOnly) {
function joinWebRTCVoiceConference() { function joinWebRTCVoiceConference() {
console.log("Joining to the voice conference directly"); console.log("Joining to the voice conference directly");
inEchoTest = false; inEchoTest = false;
// set proper callbacks to previously created user agent
if(userAgent) {
setUserAgentListeners(webRTCCallback);
}
callIntoConference(conferenceVoiceBridge, webRTCCallback); callIntoConference(conferenceVoiceBridge, webRTCCallback);
} }
@ -184,10 +188,18 @@ function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc
uaConnected = false; uaConnected = false;
userAgent = new SIP.UA(configuration); userAgent = new SIP.UA(configuration);
setUserAgentListeners(callback, makeCallFunc);
userAgent.start();
};
function setUserAgentListeners(callback, makeCallFunc) {
console.log("reseting UA callbacks");
userAgent.off('connected');
userAgent.on('connected', function() { userAgent.on('connected', function() {
uaConnected = true; uaConnected = true;
makeCallFunc(); makeCallFunc();
}); });
userAgent.off('disconnected');
userAgent.on('disconnected', function() { userAgent.on('disconnected', function() {
if (userAgent) { if (userAgent) {
if (userAgent != null) { if (userAgent != null) {
@ -203,8 +215,6 @@ function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc
} }
} }
}); });
userAgent.start();
}; };
function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) { function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) {

View File

@ -31,11 +31,13 @@ package org.bigbluebutton.main.model.users
private var _backoff:Number = 2000; private var _backoff:Number = 2000;
private var _reconnectCallback:Function; private var _reconnectCallback:Function;
private var _reconnectParameters:Array; private var _reconnectParameters:Array;
private var _attempt:Number;
public function onDisconnect(callback:Function, parameters:Array):void { public function onDisconnect(callback:Function, parameters:Array):void {
LOGGER.debug("onDisconnect, parameters={0}", [parameters.toString()]); LOGGER.debug("onDisconnect, parameters={0}", [parameters.toString()]);
_reconnectCallback = callback; _reconnectCallback = callback;
_reconnectParameters = parameters; _reconnectParameters = parameters;
_attempt = 0;
attemptReconnect(0); attemptReconnect(0);
} }
@ -45,14 +47,19 @@ package org.bigbluebutton.main.model.users
} }
private function attemptReconnect(backoff:Number):void { private function attemptReconnect(backoff:Number):void {
LOGGER.debug("attemptReconnect backoff={0}", [backoff]); _attempt++;
LOGGER.debug("attemptReconnect backoff={0}, attempt={1}", [backoff, _attempt]);
var retryTimer:Timer = new Timer(backoff, 1); var retryTimer:Timer = new Timer(backoff, 1);
retryTimer.addEventListener(TimerEvent.TIMER, function():void { retryTimer.addEventListener(TimerEvent.TIMER, function():void {
LOGGER.debug("Reconnecting"); LOGGER.debug("Reconnecting");
_reconnectCallback.apply(null, _reconnectParameters); _reconnectCallback.apply(null, _reconnectParameters);
}); });
retryTimer.start(); retryTimer.start();
if (_backoff < 16000) _backoff = Math.max(backoff, 500) *2; if (_backoff < 16000) _backoff = Math.max(backoff, 500) *2;
} }
public function get attempts():Number {
return _attempt;
}
} }
} }

View File

@ -16,6 +16,7 @@ package org.bigbluebutton.modules.phone.managers
import org.bigbluebutton.main.api.JSAPI; import org.bigbluebutton.main.api.JSAPI;
import org.bigbluebutton.main.api.JSLog; import org.bigbluebutton.main.api.JSLog;
import org.bigbluebutton.main.events.ClientStatusEvent; import org.bigbluebutton.main.events.ClientStatusEvent;
import org.bigbluebutton.main.model.users.AutoReconnect;
import org.bigbluebutton.modules.phone.PhoneModel; import org.bigbluebutton.modules.phone.PhoneModel;
import org.bigbluebutton.modules.phone.PhoneOptions; import org.bigbluebutton.modules.phone.PhoneOptions;
import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent; import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent;
@ -32,6 +33,7 @@ package org.bigbluebutton.modules.phone.managers
public class WebRTCCallManager public class WebRTCCallManager
{ {
private static const LOGGER:ILogger = getClassLogger(WebRTCCallManager); private static const LOGGER:ILogger = getClassLogger(WebRTCCallManager);
private const MAX_RETRIES:Number = 5;
private var browserType:String = "unknown"; private var browserType:String = "unknown";
private var browserVersion:int = 0; private var browserVersion:int = 0;
@ -42,6 +44,9 @@ package org.bigbluebutton.modules.phone.managers
private var options:PhoneOptions; private var options:PhoneOptions;
private var model:WebRTCModel = PhoneModel.getInstance().webRTCModel; private var model:WebRTCModel = PhoneModel.getInstance().webRTCModel;
private var reconnect:AutoReconnect = new AutoReconnect();
private var reconnecting:Boolean = false;
public function WebRTCCallManager() { public function WebRTCCallManager() {
var browserInfo:Array = JSAPI.getInstance().getBrowserInfo(); var browserInfo:Array = JSAPI.getInstance().getBrowserInfo();
@ -127,7 +132,12 @@ package org.bigbluebutton.modules.phone.managers
LOGGER.debug("setting state to IN_CONFERENCE"); LOGGER.debug("setting state to IN_CONFERENCE");
model.state = Constants.IN_CONFERENCE; model.state = Constants.IN_CONFERENCE;
dispatcher.dispatchEvent(new WebRTCJoinedVoiceConferenceEvent()); dispatcher.dispatchEvent(new WebRTCJoinedVoiceConferenceEvent());
if(reconnecting) {
dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.SUCCESS_MESSAGE_EVENT,
ResourceUtil.getInstance().getString("bbb.webrtcWarning.connection.reestablished"),
ResourceUtil.getInstance().getString("bbb.webrtcWarning.connection.reestablished")));
reconnecting = false;
}
} }
public function handleWebRTCCallEndedEvent():void { public function handleWebRTCCallEndedEvent():void {
@ -216,22 +226,42 @@ package org.bigbluebutton.modules.phone.managers
var errorString:String; var errorString:String;
model.state = Constants.INITED; model.state = Constants.INITED;
if (event.errorCode == 1004) { if(!reconnecting) {
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError." + event.errorCode, [event.cause]); LOGGER.debug("WebRTC call failed, attempting reconnection");
} else { reconnecting = true;
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError." + event.errorCode); dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.WARNING_MESSAGE_EVENT,
ResourceUtil.getInstance().getString("bbb.webrtcWarning.connection.dropped"),
ResourceUtil.getInstance().getString("bbb.webrtcWarning.connection.reconnecting")));
reconnect.onDisconnect(joinVoiceConference, []);
} }
else {
if (!errorString) { LOGGER.debug("WebRTC call reconnection failed");
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError.unknown", [event.errorCode]); if( reconnect.attempts < MAX_RETRIES ) {
LOGGER.debug("Retrying, attempt " + reconnect.attempts);
reconnect.onConnectionAttemptFailed();
}
else {
LOGGER.debug("Giving up");
reconnecting = false;
if (event.errorCode == 1004) {
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError." + event.errorCode, [event.cause]);
} else {
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError." + event.errorCode);
}
if (!errorString) {
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError.unknown", [event.errorCode]);
}
var logData:Object = new Object();
logData.user = UsersUtil.getUserData();
logData.user.reason = errorString;
LOGGER.info(jsonXify(logData));
sendWebRTCAlert(ResourceUtil.getInstance().getString("bbb.webrtcWarning.title"), ResourceUtil.getInstance().getString("bbb.webrtcWarning.message", [errorString]), errorString);
}
} }
var logData:Object = new Object();
logData.user = UsersUtil.getUserData();
logData.user.reason = errorString;
LOGGER.info(jsonXify(logData));
sendWebRTCAlert(ResourceUtil.getInstance().getString("bbb.webrtcWarning.title"), ResourceUtil.getInstance().getString("bbb.webrtcWarning.message", [errorString]), errorString);
} }
public function handleWebRTCMediaFailedEvent():void { public function handleWebRTCMediaFailedEvent():void {
@ -279,4 +309,4 @@ package org.bigbluebutton.modules.phone.managers
dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.FAIL_MESSAGE_EVENT, title, error)); dispatcher.dispatchEvent(new ClientStatusEvent(ClientStatusEvent.FAIL_MESSAGE_EVENT, title, error));
} }
} }
} }