- Merge branch 'development' of https://github.com/bigbluebutton/bigbluebutton into pedrobmarin-development-auto-reconnect

- fix webcam auto-reconnect issue
Conflicts:
	bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
This commit is contained in:
Richard Alam 2015-07-27 19:58:56 +00:00
commit df58235432
8 changed files with 120 additions and 46 deletions

View File

@ -42,11 +42,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import com.asfusion.mate.events.Dispatcher; import com.asfusion.mate.events.Dispatcher;
import mx.managers.PopUpManager; import mx.managers.PopUpManager;
import org.bigbluebutton.core.BBB; import org.bigbluebutton.core.BBB;
import org.bigbluebutton.main.api.JSAPI;
import org.bigbluebutton.main.api.JSLog; import org.bigbluebutton.main.api.JSLog;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.modules.phone.PhoneModel; import org.bigbluebutton.modules.phone.PhoneModel;
import org.bigbluebutton.modules.phone.PhoneOptions;
import org.bigbluebutton.modules.phone.events.WebRTCCallEvent; import org.bigbluebutton.modules.phone.events.WebRTCCallEvent;
import org.bigbluebutton.modules.phone.events.WebRTCEchoTestEvent; import org.bigbluebutton.modules.phone.events.WebRTCEchoTestEvent;
import org.bigbluebutton.modules.phone.events.WebRTCEchoTestStartedEvent; import org.bigbluebutton.modules.phone.events.WebRTCEchoTestStartedEvent;
@ -115,12 +112,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function noButtonClicked():void { private function noButtonClicked():void {
userClosed = true; userClosed = true;
trace(LOG + "Echo test failed."); trace(LOG + "Echo test failed.");
var logData:Object = new Object();
logData.reason = "User requested.";
logData.user = UsersUtil.getUserData();
JSLog.info("WebRtc Echo test failed.", logData);
var dispatcher:Dispatcher = new Dispatcher(); var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new WebRTCEchoTestEvent(WebRTCEchoTestEvent.WEBRTC_ECHO_TEST_NO_AUDIO)); dispatcher.dispatchEvent(new WebRTCEchoTestEvent(WebRTCEchoTestEvent.WEBRTC_ECHO_TEST_NO_AUDIO));
onCancelClicked(); onCancelClicked();

View File

@ -6,13 +6,13 @@ package org.bigbluebutton.modules.phone.managers
import flash.external.ExternalInterface; import flash.external.ExternalInterface;
import flash.utils.Timer; import flash.utils.Timer;
import flexlib.scheduling.timelineClasses.TimeRangeDescriptorUtil;
import mx.controls.Alert; import mx.controls.Alert;
import mx.events.CloseEvent; import mx.events.CloseEvent;
import org.bigbluebutton.main.api.JSLog;
import org.bigbluebutton.core.UsersUtil; import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.main.api.JSAPI; import org.bigbluebutton.main.api.JSAPI;
import org.bigbluebutton.main.api.JSLog;
import org.bigbluebutton.main.events.ClientStatusEvent; import org.bigbluebutton.main.events.ClientStatusEvent;
import org.bigbluebutton.modules.phone.PhoneModel; import org.bigbluebutton.modules.phone.PhoneModel;
import org.bigbluebutton.modules.phone.PhoneOptions; import org.bigbluebutton.modules.phone.PhoneOptions;
@ -29,7 +29,7 @@ package org.bigbluebutton.modules.phone.managers
import org.bigbluebutton.modules.phone.events.WebRTCMediaEvent; import org.bigbluebutton.modules.phone.events.WebRTCMediaEvent;
import org.bigbluebutton.modules.phone.models.Constants; import org.bigbluebutton.modules.phone.models.Constants;
import org.bigbluebutton.modules.phone.models.WebRTCModel; import org.bigbluebutton.modules.phone.models.WebRTCModel;
import org.bigbluebutton.util.i18n.ResourceUtil; import org.bigbluebutton.util.i18n.ResourceUtil;
public class WebRTCCallManager public class WebRTCCallManager
{ {
@ -196,6 +196,11 @@ package org.bigbluebutton.modules.phone.managers
errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError.unknown", [event.errorCode]); errorString = ResourceUtil.getInstance().getString("bbb.webrtcWarning.failedError.unknown", [event.errorCode]);
} }
var logData:Object = new Object();
logData.reason = errorString;
logData.user = UsersUtil.getUserData();
JSLog.warn("WebRtc Echo test failed.", logData);
sendWebRTCAlert(ResourceUtil.getInstance().getString("bbb.webrtcWarning.title"), ResourceUtil.getInstance().getString("bbb.webrtcWarning.message", [errorString]), errorString); sendWebRTCAlert(ResourceUtil.getInstance().getString("bbb.webrtcWarning.title"), ResourceUtil.getInstance().getString("bbb.webrtcWarning.message", [errorString]), errorString);
} }

View File

@ -0,0 +1,39 @@
package org.bigbluebutton.modules.polling.views {
import com.asfusion.mate.events.Listener;
import mx.controls.Button;
import org.bigbluebutton.modules.present.events.PageLoadedEvent;
import org.bigbluebutton.modules.present.model.Page;
import org.bigbluebutton.modules.present.model.PresentationModel;
public class QuickPollButton extends Button {
public function QuickPollButton() {
super();
visible = false;
var listener:Listener = new Listener();
listener.type = PageLoadedEvent.PAGE_LOADED_EVENT;
listener.method = handlePageLoadedEvent;
}
private function handlePageLoadedEvent(e:PageLoadedEvent):void {
var page:Page = PresentationModel.getInstance().getPage(e.pageId);
if (page != null) {
parseSlideText(page.txtData);
}
}
private function parseSlideText(text:String):void {
var regEx:RegExp = new RegExp("\n[^\s]+[\.\)]", "g");
var matchedArray:Array = text.match(regEx);
trace("Parse Result: " + matchedArray.length + " " + matchedArray.join(" "));
if (matchedArray.length > 2) {
label = "A-" + (matchedArray.length < 8 ? matchedArray.length : 7);
visible = true;
} else {
visible = false;
}
}
}
}

View File

@ -39,7 +39,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
width="{DEFAULT_WINDOW_WIDTH}" height="{DEFAULT_WINDOW_HEIGHT}" width="{DEFAULT_WINDOW_WIDTH}" height="{DEFAULT_WINDOW_HEIGHT}"
x="{DEFAULT_X_POSITION}" y="{DEFAULT_Y_POSITION}" x="{DEFAULT_X_POSITION}" y="{DEFAULT_Y_POSITION}"
title="{ResourceUtil.getInstance().getString('bbb.presentation.titleWithPres',[currentPresentation])}" title="{ResourceUtil.getInstance().getString('bbb.presentation.titleWithPres',[currentPresentation])}"
xmlns:views="org.bigbluebutton.modules.present.ui.views.*" xmlns:views="org.bigbluebutton.modules.present.ui.views.*"
xmlns:poll="org.bigbluebutton.modules.polling.views.*"
> >
<mate:Dispatcher id="globalDispatcher" /> <mate:Dispatcher id="globalDispatcher" />
@ -631,6 +632,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
} }
} }
private function quickPollClicked(e:MouseEvent):void {
sendStartPollEvent(Button(e.target).label);
}
private function onPollStartButtonClicked():void { private function onPollStartButtonClicked():void {
openPollTypeMenu(); openPollTypeMenu();
} }
@ -780,30 +785,32 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Button id="pollStartBtn" visible="false" height="30" styleName="pollStartButtonStyle" <mx:Button id="pollStartBtn" visible="false" height="30" styleName="pollStartButtonStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.polling.startButton.tooltip')}" toolTip="{ResourceUtil.getInstance().getString('bbb.polling.startButton.tooltip')}"
click="onPollStartButtonClicked()" tabIndex="{baseIndex+6}"/> click="onPollStartButtonClicked()" tabIndex="{baseIndex+6}"/>
<poll:QuickPollButton id="quickPollBtn" height="30" tabIndex="{baseIndex+7}"
click="quickPollClicked(event)" />
<mx:Spacer width="100%" id="spacer1"/> <mx:Spacer width="100%" id="spacer1"/>
<mx:Button id="backButton" visible="false" width="45" height="30" styleName="presentationBackButtonStyle" <mx:Button id="backButton" visible="false" width="45" height="30" styleName="presentationBackButtonStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.backBtn.toolTip')}" click="gotoPreviousSlide()" toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.backBtn.toolTip')}" click="gotoPreviousSlide()"
tabIndex="{baseIndex+7}"/> tabIndex="{baseIndex+8}"/>
<mx:Button id="btnSlideNum" visible="false" label="" click="showThumbnails()" <mx:Button id="btnSlideNum" visible="false" label="" click="showThumbnails()"
toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.btnSlideNum.toolTip')}" toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.btnSlideNum.toolTip')}"
tabIndex="{baseIndex+8}"/> tabIndex="{baseIndex+9}"/>
<mx:Button id="forwardButton" visible="false" width="45" height="30" styleName="presentationForwardButtonStyle" <mx:Button id="forwardButton" visible="false" width="45" height="30" styleName="presentationForwardButtonStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.forwardBtn.toolTip')}" click="gotoNextSlide()" toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.forwardBtn.toolTip')}" click="gotoNextSlide()"
tabIndex="{baseIndex+9}"/> tabIndex="{baseIndex+10}"/>
<mx:Spacer width="50%" id="spacer3"/> <mx:Spacer width="50%" id="spacer3"/>
<mx:HSlider id="zoomSlider" visible="false" value="{slideView.zoomPercentage}" styleName="presentationZoomSliderStyle" <mx:HSlider id="zoomSlider" visible="false" value="{slideView.zoomPercentage}" styleName="presentationZoomSliderStyle"
minimum="100" maximum="400" dataTipPlacement="top" labels="['100%','400%']" minimum="100" maximum="400" dataTipPlacement="top" labels="['100%','400%']"
useHandCursor="true" snapInterval="5" allowTrackClick="true" liveDragging="true" useHandCursor="true" snapInterval="5" allowTrackClick="true" liveDragging="true"
dataTipFormatFunction="removeDecimalFromDataTip" change="onSliderZoom()" width="100" dataTipFormatFunction="removeDecimalFromDataTip" change="onSliderZoom()" width="100"
tabIndex="{baseIndex+10}" accessibilityName="{ResourceUtil.getInstance().getString('bbb.presentation.slider')}"/> tabIndex="{baseIndex+11}" accessibilityName="{ResourceUtil.getInstance().getString('bbb.presentation.slider')}"/>
<mx:Button id="btnFitToWidth" visible="false" width="30" height="30" styleName="presentationFitToWidthButtonStyle" <mx:Button id="btnFitToWidth" visible="false" width="30" height="30" styleName="presentationFitToWidthButtonStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.fitToWidth.toolTip')}" toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.fitToWidth.toolTip')}"
click="onFitToPage(false)" click="onFitToPage(false)"
tabIndex="{baseIndex+11}"/> tabIndex="{baseIndex+12}"/>
<mx:Button id="btnFitToPage" visible="false" width="30" height="30" styleName="presentationFitToPageButtonStyle" <mx:Button id="btnFitToPage" visible="false" width="30" height="30" styleName="presentationFitToPageButtonStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.fitToPage.toolTip')}" toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.fitToPage.toolTip')}"
click="onFitToPage(true)" click="onFitToPage(true)"
tabIndex="{baseIndex+12}"/> tabIndex="{baseIndex+13}"/>
<!-- This spacer is to prevent the whiteboard toolbar from overlapping the fit-ot-page button --> <!-- This spacer is to prevent the whiteboard toolbar from overlapping the fit-ot-page button -->
<mx:Spacer width="30" height="30" id="spacer4"/> <mx:Spacer width="30" height="30" id="spacer4"/>
</mx:HBox> </mx:HBox>

View File

@ -41,6 +41,7 @@ package org.bigbluebutton.modules.videoconf.business
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent; import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent; import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions; import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
import org.bigbluebutton.main.api.JSLog;
public class VideoProxy public class VideoProxy
@ -52,7 +53,7 @@ package org.bigbluebutton.modules.videoconf.business
private var nc:NetConnection; private var nc:NetConnection;
private var _url:String; private var _url:String;
private var camerasPublishing:Object = new Object(); private var camerasPublishing:Object = new Object();
private var logoutOnUserCommand:Boolean = false; private var reconnect:Boolean = false;
private var reconnecting:Boolean = false; private var reconnecting:Boolean = false;
private var dispatcher:Dispatcher = new Dispatcher(); private var dispatcher:Dispatcher = new Dispatcher();
@ -74,6 +75,10 @@ package org.bigbluebutton.modules.videoconf.business
nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
} }
public function reconnectWhenDisconnected(connect:Boolean):void {
reconnect = connect;
}
public function connect():void { public function connect():void {
nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID()); nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
} }
@ -87,32 +92,41 @@ package org.bigbluebutton.modules.videoconf.business
} }
private function onConnectedToVideoApp():void{ private function onConnectedToVideoApp():void{
dispatcher.dispatchEvent(new ConnectedEvent(ConnectedEvent.VIDEO_CONNECTED)); dispatcher.dispatchEvent(new ConnectedEvent(reconnecting));
if (reconnecting) {
reconnecting = false;
var attemptSucceeded:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_SUCCEEDED_EVENT);
attemptSucceeded.payload.type = ReconnectionManager.VIDEO_CONNECTION;
dispatcher.dispatchEvent(attemptSucceeded);
}
} }
private function onNetStatus(event:NetStatusEvent):void{ private function onNetStatus(event:NetStatusEvent):void{
trace(LOG + "[" + event.info.code + "] for [" + _url + "]"); trace(LOG + "[" + event.info.code + "] for [" + _url + "]");
var logData:Object = new Object();
logData.user = UsersUtil.getUserData();
switch(event.info.code){ switch(event.info.code){
case "NetConnection.Connect.Success": case "NetConnection.Connect.Success":
if (reconnecting) {
reconnecting = false;
var attemptSucceeded:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_SUCCEEDED_EVENT);
attemptSucceeded.payload.type = ReconnectionManager.VIDEO_CONNECTION;
dispatcher.dispatchEvent(attemptSucceeded);
}
onConnectedToVideoApp(); onConnectedToVideoApp();
break; break;
case "NetStream.Play.Failed": case "NetStream.Play.Failed":
disconnect(); if (reconnect) {
JSLog.warn("NetStream.Play.Failed from bbb-video", logData);
}
break; break;
case "NetStream.Play.Stop": case "NetStream.Play.Stop":
disconnect(); if (reconnect) {
JSLog.warn("NetStream.Play.Stop from bbb-video", logData);
}
break; break;
case "NetConnection.Connect.Closed": case "NetConnection.Connect.Closed":
if (!logoutOnUserCommand) { dispatcher.dispatchEvent(new StopBroadcastEvent());
dispatcher.dispatchEvent(new StopBroadcastEvent());
if (reconnect) {
reconnecting = true; reconnecting = true;
var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT); var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
@ -129,6 +143,18 @@ package org.bigbluebutton.modules.videoconf.business
attemptFailedEvent.payload.type = ReconnectionManager.VIDEO_CONNECTION; attemptFailedEvent.payload.type = ReconnectionManager.VIDEO_CONNECTION;
dispatcher.dispatchEvent(attemptFailedEvent); dispatcher.dispatchEvent(attemptFailedEvent);
} }
if (reconnect) {
JSLog.warn("Disconnected from bbb-video", logData);
}
disconnect();
break;
case "NetConnection.Connect.NetworkChange":
JSLog.warn("Detected network change on bbb-video", logData);
break;
default:
trace("[" + event.info.code + "] for [" + _url + "]");
break; break;
} }
} }
@ -147,11 +173,8 @@ package org.bigbluebutton.modules.videoconf.business
ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError ); ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError );
ns.client = this; ns.client = this;
ns.attachCamera(e.camera); ns.attachCamera(e.camera);
// Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011)
// if (Capabilities.version.search("11,0") != -1) {
if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) { if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) {
// if (BBB.getFlashPlayerVersion() >= 11) {
LogUtil.info("Using H264 codec for video.");
var h264:H264VideoStreamSettings = new H264VideoStreamSettings(); var h264:H264VideoStreamSettings = new H264VideoStreamSettings();
var h264profile:String = H264Profile.MAIN; var h264profile:String = H264Profile.MAIN;
if (e.videoProfile.h264Profile != "main") { if (e.videoProfile.h264Profile != "main") {
@ -177,7 +200,6 @@ package org.bigbluebutton.modules.videoconf.business
case "5.1": h264Level = H264Level.LEVEL_5_1; break; case "5.1": h264Level = H264Level.LEVEL_5_1; break;
} }
LogUtil.info("Codec used: " + h264Level);
h264.setProfileLevel(h264profile, h264Level); h264.setProfileLevel(h264profile, h264Level);
ns.videoStreamSettings = h264; ns.videoStreamSettings = h264;
@ -209,7 +231,6 @@ package org.bigbluebutton.modules.videoconf.business
} }
public function disconnect():void { public function disconnect():void {
logoutOnUserCommand = true;
trace("VideoProxy:: disconnecting from Video application"); trace("VideoProxy:: disconnecting from Video application");
stopAllBroadcasting(); stopAllBroadcasting();
if (nc != null) nc.close(); if (nc != null) nc.close();

View File

@ -24,9 +24,12 @@ package org.bigbluebutton.modules.videoconf.events
{ {
public static const VIDEO_CONNECTED:String = "connected to video app event"; public static const VIDEO_CONNECTED:String = "connected to video app event";
public function ConnectedEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false) public var reconnection:Boolean = false;
public function ConnectedEvent(reconnection:Boolean)
{ {
super(type, true, false); super(VIDEO_CONNECTED, true, false);
this.reconnection = reconnection;
} }
} }
} }

View File

@ -115,7 +115,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</EventHandlers> </EventHandlers>
<EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}"> <EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}">
<MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp"/> <MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp" arguments="{event}"/>
</EventHandlers> </EventHandlers>
<EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}"> <EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}">

View File

@ -284,6 +284,7 @@ package org.bigbluebutton.modules.videoconf.maps
public function connectToVideoApp():void { public function connectToVideoApp():void {
proxy = new VideoProxy(uri); proxy = new VideoProxy(uri);
proxy.reconnectWhenDisconnected(true);
proxy.connect(); proxy.connect();
} }
@ -404,6 +405,7 @@ package org.bigbluebutton.modules.videoconf.maps
public function stopModule():void { public function stopModule():void {
trace("VideoEventMapDelegate:: stopping video module"); trace("VideoEventMapDelegate:: stopping video module");
closeAllWindows(); closeAllWindows();
proxy.reconnectWhenDisconnected(false);
proxy.disconnect(); proxy.disconnect();
} }
@ -436,11 +438,16 @@ package org.bigbluebutton.modules.videoconf.maps
} }
} }
public function connectedToVideoApp():void{ public function connectedToVideoApp(event: ConnectedEvent):void{
trace("VideoEventMapDelegate:: [" + me + "] Connected to video application."); trace("VideoEventMapDelegate:: [" + me + "] Connected to video application.");
_ready = true; _ready = true;
addToolbarButton(); if (event.reconnection) {
openWebcamWindows(); closeAllWindows()
} else {
addToolbarButton();
}
openWebcamWindows();
} }
public function handleCameraSetting(event:BBBEvent):void { public function handleCameraSetting(event:BBBEvent):void {