From 16287c4915411486480e4001e3c36be0c5824f6b Mon Sep 17 00:00:00 2001 From: Felipe Cecagno Date: Fri, 4 Jan 2013 10:58:38 -0200 Subject: [PATCH 1/3] copying the implementation of the network monitor from master (almost 0.81-beta) to tag v0.8, so it can be easily integrated with an older version of BigBlueButton --- .../locale/en_US/bbbResources.properties | 9 + .../locale/pt_BR/bbbResources.properties | 11 +- .../core/services/BandwidthMonitor.as | 145 +++++++ .../core/services/StreamMonitor.as | 210 +++++++++ .../main/events/NetworkStatsEvent.as | 19 + .../main/maps/ApplicationEventMap.mxml | 2 + .../main/model/NetworkStatsData.as | 165 ++++++++ .../main/model/users/NetConnectionDelegate.as | 15 + .../main/views/MainApplicationShell.mxml | 397 ++++++++++-------- .../main/views/NetworkStatsWindow.mxml | 129 ++++++ .../red5/flash/bwcheck/BandwidthDetection.as | 53 +++ .../flash/bwcheck/ClientServerBandwidth.as | 143 +++++++ .../flash/bwcheck/ServerClientBandwidth.as | 55 +++ .../bwcheck/app/BandwidthDetectionApp.as | 131 ++++++ .../bwcheck/events/BandwidthDetectEvent.as | 30 ++ 15 files changed, 1333 insertions(+), 181 deletions(-) mode change 100755 => 100644 bigbluebutton-client/locale/en_US/bbbResources.properties create mode 100755 bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as create mode 100755 bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as create mode 100755 bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as mode change 100755 => 100644 bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml create mode 100644 bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as create mode 100644 bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml create mode 100644 bigbluebutton-client/src/org/red5/flash/bwcheck/BandwidthDetection.as create mode 100644 bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as create mode 100644 bigbluebutton-client/src/org/red5/flash/bwcheck/ServerClientBandwidth.as create mode 100644 bigbluebutton-client/src/org/red5/flash/bwcheck/app/BandwidthDetectionApp.as create mode 100644 bigbluebutton-client/src/org/red5/flash/bwcheck/events/BandwidthDetectEvent.as diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties old mode 100755 new mode 100644 index c345b3038a..5c0714e5c8 --- a/bigbluebutton-client/locale/en_US/bbbResources.properties +++ b/bigbluebutton-client/locale/en_US/bbbResources.properties @@ -167,3 +167,12 @@ bbb.settings.warning.close = Close this Warning bbb.settings.noissues = No outstanding issues have been detected. bbb.settings.instructions = Accept the Flash prompt that asks you for camera permissions. If you can see yourself and hear yourself, your browser has been set up correctly. Other potentials issues are shown bellow. Click on each to find a possible solution. bbb.videodock.title = Video dock +bbb.bwmonitor.title = Network monitor +bbb.bwmonitor.upload = Upload +bbb.bwmonitor.upload.short = Up +bbb.bwmonitor.download = Download +bbb.bwmonitor.download.short = Down +bbb.bwmonitor.total = Total +bbb.bwmonitor.current = Current +bbb.bwmonitor.available = Available +bbb.bwmonitor.latency = Latency diff --git a/bigbluebutton-client/locale/pt_BR/bbbResources.properties b/bigbluebutton-client/locale/pt_BR/bbbResources.properties index 61f906a3f0..871db22d92 100644 --- a/bigbluebutton-client/locale/pt_BR/bbbResources.properties +++ b/bigbluebutton-client/locale/pt_BR/bbbResources.properties @@ -167,5 +167,12 @@ bbb.settings.warning.close = Fechar esse aviso bbb.settings.noissues = Nenhum problema perceptível foi detectado. bbb.settings.instructions = Aceite a notificação do Flash quando ele pedir permissão para compatilhar sua câmera. Se você pode ver e ouvir a si mesmo, seu navegador foi configurado corretamente. Outros erros em potencial estão indicados abaixo. Clique em cada um para uma possível solução. bbb.videodock.title = Janela de vídeos -bbb.zzzzz.yyyy = - = +bbb.bwmonitor.title = Monitor de rede +bbb.bwmonitor.upload = Upload +bbb.bwmonitor.upload.short = Up +bbb.bwmonitor.download = Download +bbb.bwmonitor.download.short = Down +bbb.bwmonitor.total = Total +bbb.bwmonitor.current = Atual +bbb.bwmonitor.available = Disponível +bbb.bwmonitor.latency = Latência diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as b/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as new file mode 100755 index 0000000000..c8aef8314d --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as @@ -0,0 +1,145 @@ +package org.bigbluebutton.core.services +{ + import flash.events.AsyncErrorEvent; + import flash.events.NetStatusEvent; + import flash.events.TimerEvent; + import flash.net.NetConnection; + import flash.utils.Timer; + + import mx.utils.ObjectUtil; + + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.main.model.NetworkStatsData; + + import org.red5.flash.bwcheck.ClientServerBandwidth; + import org.red5.flash.bwcheck.ServerClientBandwidth; + import org.red5.flash.bwcheck.events.BandwidthDetectEvent; + + public class BandwidthMonitor { + private var _serverURL:String = "localhost"; + private var _serverApplication:String = "video"; + private var _clientServerService:String = "checkBandwidthUp"; + private var _serverClientService:String = "checkBandwidth"; + private var nc:NetConnection; + + private var bwTestTimer:Timer; + + public function BandwidthMonitor() { + + } + + public function set serverURL(url:String):void { + _serverURL = url; + } + + public function set serverApplication(app:String):void { + _serverApplication = app; + } + + public function start():void { + connect(); + } + + private function connect():void { + nc = new NetConnection(); + nc.objectEncoding = flash.net.ObjectEncoding.AMF0; + nc.client = this; + nc.addEventListener(NetStatusEvent.NET_STATUS, onStatus); + nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); + nc.connect("rtmp://" + _serverURL + "/" + _serverApplication); + } + + private function onAsyncError(event:AsyncErrorEvent):void + { + LogUtil.debug(event.error.toString()); + } + + private function onStatus(event:NetStatusEvent):void + { + switch (event.info.code) + { + case "NetConnection.Connect.Success": + LogUtil.debug("Starting to monitor bandwidth between client and server"); + monitor(); + break; + default: + LogUtil.debug("Cannot establish the connection to measure bandwidth"); + break; + } + } + + private function monitor():void { + LogUtil.debug("Starting to monitor bandwidth"); + bwTestTimer = new Timer(30000); + bwTestTimer.addEventListener(TimerEvent.TIMER, rtmptRetryTimerHandler); + bwTestTimer.start(); + } + + private function rtmptRetryTimerHandler(event:TimerEvent):void { + LogUtil.debug("Starting to detect bandwidth from server to client"); + ServerClient(); + } + + public function ClientServer():void + { + var clientServer:ClientServerBandwidth = new ClientServerBandwidth(); + //connect(); + clientServer.connection = nc; + clientServer.service = _clientServerService; + clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + clientServer.start(); + } + + public function ServerClient():void + { + var serverClient:ServerClientBandwidth = new ServerClientBandwidth(); + //connect(); + serverClient.connection = nc; + serverClient.service = _serverClientService; + serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + serverClient.start(); + } + + public function onDetectFailed(event:BandwidthDetectEvent):void + { + LogUtil.debug("Detection failed with error: " + event.info.application + " " + event.info.description); + } + + public function onClientServerComplete(event:BandwidthDetectEvent):void + { +// LogUtil.debug("Client-slient bandwidth detect complete"); + +// LogUtil.debug(ObjectUtil.toString(event.info)); + NetworkStatsData.getInstance().setUploadMeasuredBW(event.info); + } + + public function onClientServerStatus(event:BandwidthDetectEvent):void + { + if (event.info) { +// LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" overhead: "+event.info.overhead+" packet interval: " + event.info.pakInterval + " cumLatency: " + event.info.cumLatency); + } + } + + public function onServerClientComplete(event:BandwidthDetectEvent):void + { +// LogUtil.debug("Server-client bandwidth detect complete"); + +// LogUtil.debug(ObjectUtil.toString(event.info)); + NetworkStatsData.getInstance().setDownloadMeasuredBW(event.info); + +// LogUtil.debug("Detecting Client Server Bandwidth"); + ClientServer(); + } + + public function onServerClientStatus(event:BandwidthDetectEvent):void + { + if (event.info) { +// LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" cumLatency: " + event.info.cumLatency); + } + } + } +} \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as b/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as new file mode 100755 index 0000000000..b10d3f8b30 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as @@ -0,0 +1,210 @@ +package org.bigbluebutton.core.services +{ + import com.asfusion.mate.events.Dispatcher; + + import flash.events.NetDataEvent; + import flash.events.NetMonitorEvent; + import flash.events.NetStatusEvent; + import flash.events.StatusEvent; + import flash.events.TimerEvent; + import flash.net.NetMonitor; + import flash.net.NetStream; + import flash.utils.Dictionary; + import flash.utils.Timer; + import flash.utils.getDefinitionByName; + import flash.utils.getQualifiedClassName; + + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.main.events.NetworkStatsEvent; + import org.bigbluebutton.main.model.NetworkStatsData; + + public class StreamMonitor + { + /** + * https://github.com/ritzalam/red5-bw-check + * http://help.adobe.com/en_US/as3/dev/WS901d38e593cd1bac-1201e73713000d1f624-8000.html + * http://www.adobe.com/devnet/video/articles/media-measurement-flash.html + * http://help.adobe.com/en_US/air/reference/html/flash/net/NetMonitor.html + * http://help.adobe.com/en_US/flashmediaserver/devguide/WSae44d1d92c7021ff-1f5381712889cd7b56-8000.html#WSae44d1d92c7021ff-1f5381712889cd7b56-7ff7 + * http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStreamInfo.html + * http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html + * http://help.adobe.com/en_US/FlashMediaServer/3.5_Deving/WS5b3ccc516d4fbf351e63e3d11a0773d56e-7ffa.html + * https://groups.google.com/d/topic/red5interest/PiUDeH6jZBQ/discussion + * http://flowplayer.electroteque.org/bwcheck + * http://code.google.com/p/flowplayer-plugins/ + * http://osflash.org/pipermail/red5_osflash.org/2009-January/028906.html + */ + + private var _netmon:NetMonitor; + private var _heartbeat:Timer = new Timer( 2000 ); + private var _globalDispatcher:Dispatcher = new Dispatcher(); + private var _totalBytesCounter:Dictionary = new Dictionary(); + + public function StreamMonitor():void { + //Create NetMonitor object + _netmon = new NetMonitor(); + _netmon.addEventListener( NetMonitorEvent.NET_STREAM_CREATE, newNetStream ); + + //Start the heartbeat timer + _heartbeat.addEventListener( TimerEvent.TIMER, onHeartbeat ); + _heartbeat.start(); + } + + //On new NetStream + private function newNetStream(event:NetMonitorEvent):void + { + log("New Netstream object: " + event); + var stream:NetStream = event.netStream; + log("Stream info: " + stream.info); + stream.addEventListener(NetDataEvent.MEDIA_TYPE_DATA, onStreamData); + stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + stream.addEventListener(StatusEvent.STATUS, onStatus); + } + + //On data events from a NetStream object + private function onStreamData(event:NetDataEvent):void { + var netStream:NetStream = event.target as NetStream; +// log("Data event from " + netStream.info.uri + " at " + event.timestamp); + log("Data event: " + event); + switch(event.info.handler) { + case "onMetaData": + //handle metadata; + break; + case "onXMPData": + //handle XMP; + break; + case "onPlayStatus": + //handle NetStream.Play.Complete + break; + case "onImageData": + //handle image + break; + case "onTextData": + //handle text + break; + default: + //handle other events + break; + } + } + + //On status events from a NetStream object + private function onNetStatus(event:NetStatusEvent):void { +// log("Status event from " + event.target.info.uri + " at " + event.target.time); + log("NetStatus event code: " + event.info.code); + log("NetStatus event details: " + event.info.details); + log("Stream info: " + event.target.info); + } + + private function onStatus(event:StatusEvent):void { + log("Status event code: " + event.code); + log("Status event: " + event.target); + log("Stream info: " + event.currentTarget); + } + + private function isRemoteStream(stream:NetStream):Boolean { + return (stream != null && stream.info != null && stream.info.resourceName != null); + } + + //On heartbeat timer + private function onHeartbeat(event:TimerEvent):void { + var streams:Vector. = _netmon.listStreams(); + + var download:Dictionary = new Dictionary(); + var upload:Dictionary = new Dictionary(); + + download["byteCount"] = upload["byteCount"] + = download["currentBytesPerSecond"] = upload["currentBytesPerSecond"] = 0; + + for (var i:int = 0; i < streams.length; i++) { + if (streams[i] == null || streams[i].info == null) { + // stream info is null, returning + continue; + } + + //log("Heartbeat on " + streams[i].info); + + var remote:Boolean = isRemoteStream(streams[i]); + var ref:Dictionary = (remote? download: upload); + + if (streams[i].info.uri == null) { + //log("Stream URI is null, returning"); + continue; + } + var uri:String = streams[i].info.uri.toLowerCase(); + var pattern1:RegExp = /(?P.+):\/\/(?P.+)\/(?P.+)\/(?P.+)/; + var pattern2:RegExp = /(?P.+):\/\/(?P.+)\/(?P.+)/; + var result:Array; + var protocol:String = "", server:String = "", app:String = "", meeting:String = ""; + if (uri.match(pattern1)) { + result = pattern1.exec(uri); + protocol = result.protocol; + server = result.server; + app = result.app; + meeting = result.meeting; + } else if (uri.match(pattern2)) { + result = pattern2.exec(uri); + protocol = result.protocol; + server = result.server; + app = result.app; + } else { + log("***** NO MATCH *****"); + } + + var props:XMLList = flash.utils.describeType(streams[i].info)..accessor; + + for each (var s:XML in props) { + //log(s + ": " + streams[i].info[s]); + if (s.@type == "Number") { + var property:String = s.@name; + var num:Number = 0; + if (ref.hasOwnProperty(property)) + num = (ref[property] as Number); + num += (streams[i].info[property] as Number); + ref[property] = num; + } + } + var streamName:String = app + "/" + (remote? streams[i].info.resourceName: "local"); + var streamsName:String = (ref.hasOwnProperty("streams")? ref["streams"] + ";":"") + streamName; + ref["streams"] = streamsName; + + var totalReg:Object = new Object; + totalReg.streamName = streamName; + totalReg.remote = remote; + totalReg.byteCount = streams[i].info["byteCount"]; + if (_totalBytesCounter.hasOwnProperty(streamName) && _totalBytesCounter[streamName].byteCount > totalReg.byteCount) { + var curTime:Number = new Date().getTime(); + var newStreamName:String = streamName + "_" + curTime; + _totalBytesCounter[streamName].streamName = newStreamName; + _totalBytesCounter[newStreamName] = _totalBytesCounter[streamName]; + delete _totalBytesCounter[streamName]; + } + _totalBytesCounter[streamName] = totalReg; + } + + download["byteCount"] = upload["byteCount"] = 0; + for each (var value:Object in _totalBytesCounter) { + if (value.remote) + download["byteCount"] += value.byteCount; + else + upload["byteCount"] += value.byteCount; + //log(value.streamName + ": " + value.byteCount); + } + + NetworkStatsData.getInstance().updateConsumedBW(download["currentBytesPerSecond"], + upload["currentBytesPerSecond"], + download["byteCount"], + upload["byteCount"]); + } + + static public function printDictionary(dict:Dictionary):void { + for (var key:Object in dict) { + LogUtil.debug(key + ": " + dict[key]); + } + } + + private function log(s:String):void { + LogUtil.debug("[StreamMonitor] " + s); + } + } +} diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as new file mode 100755 index 0000000000..8250908dc6 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as @@ -0,0 +1,19 @@ +package org.bigbluebutton.main.events +{ + import flash.events.Event; + import flash.utils.Dictionary; + + public class NetworkStatsEvent extends Event + { + public static const NETWORK_STATS_EVENTS:String = "NETWORK_STATS_EVENTS"; + + public var downloadStats:Dictionary; + public var uploadStats:Dictionary; + + public function NetworkStatsEvent(bubbles:Boolean=true, cancelable:Boolean=false) + { + super(NETWORK_STATS_EVENTS, bubbles, cancelable); + } + + } +} \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml old mode 100755 new mode 100644 index f0715aa83c..bc66b15449 --- a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml @@ -31,6 +31,7 @@ + @@ -107,6 +108,7 @@ import org.bigbluebutton.core.managers.ConfigManager; import org.bigbluebutton.core.services.SkinningService; + import org.bigbluebutton.core.services.StreamMonitor; import org.bigbluebutton.main.events.ConfigEvent; import org.bigbluebutton.main.events.LogoutEvent; import org.bigbluebutton.main.events.ModuleLoadEvent; diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as new file mode 100644 index 0000000000..96567c4c69 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as @@ -0,0 +1,165 @@ +package org.bigbluebutton.main.model +{ + + import com.asfusion.mate.events.Dispatcher; + + import mx.formatters.NumberFormatter; + + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.main.events.NetworkStatsEvent; + + import flash.events.EventDispatcher; + + public class NetworkStatsData extends EventDispatcher + { + private static var _instance:NetworkStatsData = null; + private var _currentConsumedDownBW:Number = 0; // Kb + private var _currentConsumedUpBW:Number = 0; // Kb + private var _totalConsumedDownBW:Number = 0; // KB + private var _totalConsumedUpBW:Number = 0; // KB + private var _measuredDownBWCheck:Boolean = false; + private var _measuredDownBW:Number = 0; // Kb + private var _measuredDownLatency:int = 0; // ms + private var _measuredUpBWCheck:Boolean = false; + private var _measuredUpBW:Number = 0; // Kb + private var _measuredUpLatency:int = 0; // ms + private var _numberFormatter:NumberFormatter = new NumberFormatter(); + + /** + * This class is a singleton. Please initialize it using the getInstance() method. + */ + public function NetworkStatsData(enforcer:SingletonEnforcer) { + if (enforcer == null) { + throw new Error("There can only be one instance of this class"); + } + initialize(); + } + + private function initialize():void { + _numberFormatter.precision = 1; + _numberFormatter.useThousandsSeparator = true; + } + + /** + * Return the single instance of this class + */ + public static function getInstance():NetworkStatsData { + if (_instance == null){ + _instance = new NetworkStatsData(new SingletonEnforcer()); + } + return _instance; + } + + // all the numbers are in bytes + public function updateConsumedBW(down:Number, up:Number, downTotal:Number, upTotal:Number):void { + _currentConsumedDownBW = (down * 8) / 1024; + _currentConsumedUpBW = (up * 8) / 1024; + _totalConsumedDownBW = downTotal / 1024; + _totalConsumedUpBW = upTotal / 1024; + } + + /* + 12/8/2012 17:24:38.293 [DEBUG] (Array)#0 + [deltaDown] 2455.704 + [deltaTime] 170 + [kbitDown] 14445 + [latency] 10 + */ + public function setDownloadMeasuredBW(info:Object):void { + _measuredDownBWCheck = true; + _measuredDownBW = info["kbitDown"]; + _measuredDownLatency = info["latency"]; + } + + /* + 12/8/2012 17:24:39.556 [DEBUG] (Object)#0 + deltaTime = 1 + deltaUp = 10516 + kbitUp = 10516 + KBytes = 1283 + latency = 11 + */ + public function setUploadMeasuredBW(info:Object):void { + _measuredUpBWCheck = true; + _measuredUpBW = info.kbitUp; + _measuredUpLatency = info.latency; + } + + private function format_KB(n:Number):String { + var unit:String = "KB"; + if (n >= 1073741824) { + unit = "TB"; + n /= 1073741824; + } else if (n >= 1048576) { + unit = "GB"; + n /= 1048576; + } else if (n >= 1024) { + unit = "MB"; + n /= 1024; + } + return _numberFormatter.format(n) + " " + unit; + } + + private function format_Kbps(n:Number):String { + var unit:String = "Kbps"; + if (n >= 1000000000) { + unit = "Tbps"; + n /= 1000000000; + } else if (n >= 1000000) { + unit = "Gbps"; + n /= 1000000; + } else if (n >= 1000) { + unit = "Mbps"; + n /= 1000; + } + return _numberFormatter.format(n) + " " + unit; + } + + + public function get formattedCurrentConsumedDownBW():String { + return format_Kbps(_currentConsumedDownBW); + } + + public function get formattedCurrentConsumedUpBW():String { + return format_Kbps(_currentConsumedUpBW); + } + + public function get formattedTotalConsumedDownBW():String { + return format_KB(_totalConsumedDownBW); + } + + public function get formattedTotalConsumedUpBW():String { + return format_KB(_totalConsumedUpBW); + } + + public function get formattedMeasuredDownBW():String { + if (_measuredDownBWCheck) + return format_Kbps(_measuredDownBW); + else + return "-"; + } + + public function get formattedMeasuredDownLatency():String { + if (_measuredDownBWCheck) + return _measuredDownLatency + " ms"; + else + return "-"; + } + + public function get formattedMeasuredUpBW():String { + if (_measuredUpBWCheck) + return format_Kbps(_measuredUpBW); + else + return "-"; + } + + public function get formattedMeasuredUpLatency():String { + if (_measuredUpBWCheck) + return _measuredUpLatency + " ms"; + else + return "-"; + } + } +} + +class SingletonEnforcer{} \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as index ce3497b223..aebd1c603d 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as @@ -28,6 +28,7 @@ package org.bigbluebutton.main.model.users import mx.controls.Alert; import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.core.services.BandwidthMonitor; import org.bigbluebutton.main.model.ConferenceParameters; import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent; import org.bigbluebutton.main.model.users.events.UsersConnectionEvent; @@ -128,6 +129,17 @@ package org.bigbluebutton.main.model.users handleResult( event ); } + private var _bwMon:BandwidthMonitor = new BandwidthMonitor(); + + private function startMonitoringBandwidth():void { + trace("Start monitoring bandwidth."); + var pattern:RegExp = /(?P.+):\/\/(?P.+)\/(?P.+)/; + var result:Array = pattern.exec(_applicationURI); + _bwMon.serverURL = result.server; + _bwMon.serverApplication = "video"; + _bwMon.start(); + } + public function handleResult( event : Object ) : void { var info : Object = event.info; var statusCode : String = info.code; @@ -136,6 +148,9 @@ package org.bigbluebutton.main.model.users { case CONNECT_SUCCESS : LogUtil.debug(NAME + ":Connection to viewers application succeeded."); + + startMonitoringBandwidth(); + _netConnection.call( "getMyUserId",// Remote function name new Responder( diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml index 482c427ecf..3b8a4ee75b 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml @@ -73,199 +73,207 @@ import org.bigbluebutton.main.events.RecordStatusEvent; import org.bigbluebutton.main.events.SuccessfulLoginEvent; import org.bigbluebutton.main.model.LayoutOptions; + import org.bigbluebutton.main.model.NetworkStatsData; import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent; import org.bigbluebutton.util.i18n.ResourceUtil; - import org.bigbluebutton.util.logging.Logger; - - private var globalDispatcher:Dispatcher; - private var dispState:String; //full-screen? - private var images:Images = new Images(); - private var stoppedModules:ArrayCollection; - private var logs:Logger = new Logger(); + import org.bigbluebutton.util.logging.Logger; + + private var globalDispatcher:Dispatcher; + private var dispState:String; //full-screen? + private var images:Images = new Images(); + private var stoppedModules:ArrayCollection; + private var logs:Logger = new Logger(); private var logWindow:LogWindow; - private var logoutWindow:LoggedOutWindow; - private var connectionLostWindow:ConnectionLostWindow; + private var logoutWindow:LoggedOutWindow; + private var connectionLostWindow:ConnectionLostWindow; + + // LIVE or PLAYBACK + private var _mode:String = 'LIVE'; + [Bindable] public var appVersion:String = ' '; + private var localeVersion:String = 'old'; + [Bindable] public var numberOfModules:int = 0; + + [Bindable] private var fullscreen_icon:Class = images.full_screen; + [Bindable] private var logs_icon:Class = images.table; + [Bindable] private var reset_layout_icon:Class = images.layout; + + private var receivedConfigLocaleVer:Boolean = false; + private var receivedResourceLocaleVer:Boolean = false; + + public function get mode():String { + return _mode; + } + + [Bindable] private var layoutOptions:LayoutOptions; + + [Bindable] private var showToolbarOpt:Boolean = true; - // LIVE or PLAYBACK - private var _mode:String = 'LIVE'; - [Bindable] public var appVersion:String = ' '; - private var localeVersion:String = 'old'; - [Bindable] public var numberOfModules:int = 0; - - [Bindable] private var fullscreen_icon:Class = images.full_screen; - [Bindable] private var logs_icon:Class = images.table; - [Bindable] private var reset_layout_icon:Class = images.layout; - - private var receivedConfigLocaleVer:Boolean = false; - private var receivedResourceLocaleVer:Boolean = false; - - public function get mode():String { - return _mode; - } - - [Bindable] private var layoutOptions:LayoutOptions; - - [Bindable] private var showToolbarOpt:Boolean = true; - - public function initOptions(e:Event):void { + [Bindable] private var _bandwidthConsumedUp:String = "-"; + [Bindable] private var _bandwidthConsumedDown:String = "-"; + private var _updateBandwidthTimer:Timer = new Timer(1000); + + public function initOptions(e:Event):void { LogUtil.debug("**** Init layout options ***"); - layoutOptions = new LayoutOptions(); - layoutOptions.parseOptions(); - showToolbarOpt = layoutOptions.showToolbar; + layoutOptions = new LayoutOptions(); + layoutOptions.parseOptions(); + showToolbarOpt = layoutOptions.showToolbar; LogUtil.debug("*** show toolbar = " + layoutOptions.showToolbar); toolbar.displayToolbar(); - } - - protected function initializeShell():void { - globalDispatcher = new Dispatcher(); - } - - protected function initFullScreen():void { - /* Set up full screen handler. */ - stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler); - dispState = stage.displayState; - } - - private var sendStartModulesEvent:Boolean = true; - - private function handleApplicationVersionEvent(event:AppVersionEvent):void { - if (event.configLocaleVersion == true) { - receivedConfigLocaleVer = true; - appVersion = event.appVersion; - localeVersion = event.localeVersion; + + _updateBandwidthTimer.addEventListener(TimerEvent.TIMER, updateBandwidthTimerHandler); + _updateBandwidthTimer.start(); + } + + protected function initializeShell():void { + globalDispatcher = new Dispatcher(); + } + + protected function initFullScreen():void { + /* Set up full screen handler. */ + stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler); + dispState = stage.displayState; + } + + private var sendStartModulesEvent:Boolean = true; + + private function handleApplicationVersionEvent(event:AppVersionEvent):void { + if (event.configLocaleVersion == true) { + receivedConfigLocaleVer = true; + appVersion = event.appVersion; + localeVersion = event.localeVersion; LogUtil.debug("Received locale version fron config.xml"); - } else { - receivedResourceLocaleVer = true; - LogUtil.debug("Received locale version fron locale file."); - } - - if (receivedConfigLocaleVer && receivedResourceLocaleVer) { - LogUtil.debug("Comparing locale versions."); - if (!event.suppressLocaleWarning) checkLocaleVersion(localeVersion); + } else { + receivedResourceLocaleVer = true; + LogUtil.debug("Received locale version fron locale file."); + } + + if (receivedConfigLocaleVer && receivedResourceLocaleVer) { + LogUtil.debug("Comparing locale versions."); + if (!event.suppressLocaleWarning) checkLocaleVersion(localeVersion); if (sendStartModulesEvent) { - sendStartModulesEvent = false; - sendStartAllModulesEvent(); - } - } + sendStartModulesEvent = false; + sendStartAllModulesEvent(); + } + } + } + + public function sendStartAllModulesEvent():void{ + LogUtil.debug("Sending start all modules event"); + var dispatcher:Dispatcher = new Dispatcher(); + dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.START_ALL_MODULES)); + } + + private function fullScreenHandler(evt:FullScreenEvent):void { + dispState = stage.displayState + " (fullScreen=" + evt.fullScreen.toString() + ")"; + if (evt.fullScreen) { + LogUtil.debug("Switching to full screen"); + /* Do something specific here if we switched to full screen mode. */ + + } else { + LogUtil.debug("Switching to normal screen"); + /* Do something specific here if we switched to normal mode. */ + } + } + + private function openLogWindow():void { + if (logWindow == null){ + logWindow = new LogWindow(); + logWindow.logs = logs; + } + mdiCanvas.windowManager.add(logWindow); + mdiCanvas.windowManager.absPos(logWindow, 50, 50); + logWindow.width = mdiCanvas.width - 100; + logWindow.height = mdiCanvas.height - 100; } - - public function sendStartAllModulesEvent():void{ - LogUtil.debug("Sending start all modules event"); - var dispatcher:Dispatcher = new Dispatcher(); - dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.START_ALL_MODULES)); - } - - private function fullScreenHandler(evt:FullScreenEvent):void { - dispState = stage.displayState + " (fullScreen=" + evt.fullScreen.toString() + ")"; - if (evt.fullScreen) { - LogUtil.debug("Switching to full screen"); - /* Do something specific here if we switched to full screen mode. */ - - } else { - LogUtil.debug("Switching to normal screen"); - /* Do something specific here if we switched to normal mode. */ - } - } - - private function openLogWindow():void { - if (logWindow == null){ - logWindow = new LogWindow(); - logWindow.logs = logs; - } - mdiCanvas.windowManager.add(logWindow); - mdiCanvas.windowManager.absPos(logWindow, 50, 50); - logWindow.width = mdiCanvas.width - 100; - logWindow.height = mdiCanvas.height - 100; - } - - private function toggleFullScreen():void{ - LogUtil.debug("Toggling fullscreen"); - try { - switch (stage.displayState) { - case StageDisplayState.FULL_SCREEN: - LogUtil.debug("full screen mode"); - // If already in full screen mode, switch to normal mode. - stage.displayState = StageDisplayState.NORMAL; - break; - default: - LogUtil.debug("Normal screen mode"); - // If not in full screen mode, switch to full screen mode. - stage.displayState = StageDisplayState.FULL_SCREEN; - break; - } - } catch (err:SecurityError) { - // ignore - } - } - - private function handleOpenWindowEvent(event:OpenWindowEvent):void { + + private function toggleFullScreen():void{ + LogUtil.debug("Toggling fullscreen"); + try { + switch (stage.displayState) { + case StageDisplayState.FULL_SCREEN: + LogUtil.debug("full screen mode"); + // If already in full screen mode, switch to normal mode. + stage.displayState = StageDisplayState.NORMAL; + break; + default: + LogUtil.debug("Normal screen mode"); + // If not in full screen mode, switch to full screen mode. + stage.displayState = StageDisplayState.FULL_SCREEN; + break; + } + } catch (err:SecurityError) { + // ignore + } + } + + private function handleOpenWindowEvent(event:OpenWindowEvent):void { - var window:IBbbModuleWindow = event.window; - mdiCanvas.addWindow(window); - } - - private function handleCloseWindowEvent(event:CloseWindowEvent):void { - var window:IBbbModuleWindow = event.window; + var window:IBbbModuleWindow = event.window; + mdiCanvas.addWindow(window); + } + + private function handleCloseWindowEvent(event:CloseWindowEvent):void { + var window:IBbbModuleWindow = event.window; mdiCanvas.removeWindow(window); - } - - private function resetLayout():void{ - mdiCanvas.resetWindowLayout(); - } - - private function addComponentToCanvas(e:AddUIComponentToMainCanvas):void{ - mdiCanvas.addChild(e.component); - } - - public function checkLocaleVersion(localeVersion:String):void { - Alert.okLabel ="OK"; - var version:String = "old-locales"; - version = ResourceUtil.getInstance().getString('bbb.mainshell.locale.version'); - LogUtil.debug("Locale from config=" + localeVersion + ", from locale file=" + version); - - if ((version == "old-locales") || (version == "") || (version == null)) { - wrongLocaleVersion(); - } else { - if (version != localeVersion) wrongLocaleVersion(); - } - } - - private function showMicSettings(event:BBBEvent):void { - var micSettings:MicSettings = MicSettings(PopUpManager.createPopUp(mdiCanvas, MicSettings, true)); - var point1:Point = new Point(); - // Calculate position of TitleWindow in Application's coordinates. - point1.x = width/2; - point1.y = height/2; - micSettings.x = point1.x - (micSettings.width/2); - micSettings.y = point1.y - (micSettings.height/2); - } + } + + private function resetLayout():void{ + mdiCanvas.resetWindowLayout(); + } + + private function addComponentToCanvas(e:AddUIComponentToMainCanvas):void{ + mdiCanvas.addChild(e.component); + } + + public function checkLocaleVersion(localeVersion:String):void { + Alert.okLabel ="OK"; + var version:String = "old-locales"; + version = ResourceUtil.getInstance().getString('bbb.mainshell.locale.version'); + LogUtil.debug("Locale from config=" + localeVersion + ", from locale file=" + version); + + if ((version == "old-locales") || (version == "") || (version == null)) { + wrongLocaleVersion(); + } else { + if (version != localeVersion) wrongLocaleVersion(); + } + } + + private function showMicSettings(event:BBBEvent):void { + var micSettings:MicSettings = MicSettings(PopUpManager.createPopUp(mdiCanvas, MicSettings, true)); + var point1:Point = new Point(); + // Calculate position of TitleWindow in Application's coordinates. + point1.x = width/2; + point1.y = height/2; + micSettings.x = point1.x - (micSettings.width/2); + micSettings.y = point1.y - (micSettings.height/2); + } private function wrongLocaleVersion():void { - var localeWindow:OldLocaleWarnWindow = OldLocaleWarnWindow(PopUpManager.createPopUp(mdiCanvas, OldLocaleWarnWindow, false)); - - var point1:Point = new Point(); - // Calculate position of TitleWindow in Application's coordinates. - point1.x = width/2; - point1.y = height/2; - localeWindow.x = point1.x - (localeWindow.width/2); - localeWindow.y = point1.y - (localeWindow.height/2); + var localeWindow:OldLocaleWarnWindow = OldLocaleWarnWindow(PopUpManager.createPopUp(mdiCanvas, OldLocaleWarnWindow, false)); + + var point1:Point = new Point(); + // Calculate position of TitleWindow in Application's coordinates. + point1.x = width/2; + point1.y = height/2; + localeWindow.x = point1.x - (localeWindow.width/2); + localeWindow.y = point1.y - (localeWindow.height/2); } - - private function handleLogout(e:ConnectionFailedEvent):void { - if (layoutOptions.showLogoutWindow) { - if (logoutWindow != null) return; - logoutWindow = LoggedOutWindow(PopUpManager.createPopUp( mdiCanvas, LoggedOutWindow, false)); - - var point1:Point = new Point(); - // Calculate position of TitleWindow in Application's coordinates. - point1.x = width/2; - point1.y = height/2; - logoutWindow.x = point1.x - (logoutWindow.width/2); - logoutWindow.y = point1.y - (logoutWindow.height/2); - - if (e is ConnectionFailedEvent) logoutWindow.setReason((e as ConnectionFailedEvent).type); - else logoutWindow.setReason("You have logged out of the conference"); - + + private function handleLogout(e:ConnectionFailedEvent):void { + if (layoutOptions.showLogoutWindow) { + if (logoutWindow != null) return; + logoutWindow = LoggedOutWindow(PopUpManager.createPopUp( mdiCanvas, LoggedOutWindow, false)); + + var point1:Point = new Point(); + // Calculate position of TitleWindow in Application's coordinates. + point1.x = width/2; + point1.y = height/2; + logoutWindow.x = point1.x - (logoutWindow.width/2); + logoutWindow.y = point1.y - (logoutWindow.height/2); + + if (e is ConnectionFailedEvent) logoutWindow.setReason((e as ConnectionFailedEvent).type); + else logoutWindow.setReason("You have logged out of the conference"); + mdiCanvas.removeAllWindows(); } else { mdiCanvas.removeAllWindows(); @@ -298,6 +306,36 @@ Alert.show(evt.status, evt.module); } + private var networkStatsWindow:NetworkStatsWindow = new NetworkStatsWindow(); + + private function openNetworkStatsWindow(event:MouseEvent):void { + event.target.addEventListener(MouseEvent.MOUSE_MOVE, updateNetworkStatsWindowPosition); + networkStatsWindow.appear(this); + } + + private function updateNetworkStatsWindowPosition(event:MouseEvent):void { + var mousePosition:Point = new Point(event.localX, event.localY); + //LogUtil.debug("mouse position: " + mousePosition.x + " " + mousePosition.y); + + var mouseGlobal:Point = event.target.localToGlobal(mousePosition); + //LogUtil.debug("mouse global position: " + mouseGlobal.x + " " + mouseGlobal.y); + + var windowPosition:Point = this.globalToContent(mouseGlobal); + //LogUtil.debug("window position: " + windowPosition.x + " " + windowPosition.y); + + networkStatsWindow.x = windowPosition.x - networkStatsWindow.width - 10; + networkStatsWindow.y = windowPosition.y - networkStatsWindow.height - 10; + } + + private function closeNetworkStatsWindow(event:MouseEvent):void { + event.target.removeEventListener(MouseEvent.MOUSE_MOVE, updateNetworkStatsWindowPosition); + networkStatsWindow.disappear(); + } + + private function updateBandwidthTimerHandler(e:TimerEvent):void { + _bandwidthConsumedDown = NetworkStatsData.getInstance().formattedCurrentConsumedDownBW; + _bandwidthConsumedUp = NetworkStatsData.getInstance().formattedCurrentConsumedUpBW; + } ]]> @@ -306,11 +344,12 @@ - + + diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml new file mode 100644 index 0000000000..17b6fa3889 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/BandwidthDetection.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/BandwidthDetection.as new file mode 100644 index 0000000000..7d1160ab9b --- /dev/null +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/BandwidthDetection.as @@ -0,0 +1,53 @@ +package org.red5.flash.bwcheck +{ + import flash.events.EventDispatcher; + import flash.net.NetConnection; + import org.red5.flash.bwcheck.events.BandwidthDetectEvent; + + [Event(name=BandwidthDetectEvent.DETECT_STATUS, type="org.red5.flash.bwcheck.events.BandwidthDetectEvent")] + [Event(name=BandwidthDetectEvent.DETECT_COMPLETE, type="org.red5.flash.bwcheck.events.BandwidthDetectEvent")] + + public class BandwidthDetection extends EventDispatcher + { + protected var nc:NetConnection; + + public function BandwidthDetection() + { + + } + + protected function dispatch(info:Object, eventName:String):void + { + var event:BandwidthDetectEvent = new BandwidthDetectEvent(eventName); + event.info = info; + dispatchEvent(event); + } + + protected function dispatchStatus(info:Object):void + { + var event:BandwidthDetectEvent = new BandwidthDetectEvent(BandwidthDetectEvent.DETECT_STATUS); + event.info = info; + dispatchEvent(event); + } + + protected function dispatchComplete(info:Object):void + { + var event:BandwidthDetectEvent = new BandwidthDetectEvent(BandwidthDetectEvent.DETECT_COMPLETE); + event.info = info; + dispatchEvent(event); + } + + protected function dispatchFailed(info:Object):void + { + var event:BandwidthDetectEvent = new BandwidthDetectEvent(BandwidthDetectEvent.DETECT_FAILED); + event.info = info; + dispatchEvent(event); + } + + public function set connection(connect:NetConnection):void + { + nc = connect; + } + + } +} \ No newline at end of file diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as new file mode 100644 index 0000000000..22a97d3846 --- /dev/null +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as @@ -0,0 +1,143 @@ +package org.red5.flash.bwcheck +{ + + import flash.net.Responder; + + public class ClientServerBandwidth extends BandwidthDetection + { + + private var res:Responder; + private var payload:Array = new Array(); + + private var latency:int = 0; + private var cumLatency:int = 1; + private var bwTime:int = 0; + private var count:int = 0; + private var sent:int = 0; + private var kbitUp:int = 0; + private var KBytes:int = 0; + private var deltaUp:int = 0; + private var deltaTime:int = 0; + private var overhead:int = 0; + private var pakInterval:int = 0; + private var timePassed:int = 0; + private var now:int = 0; + + private var pakSent:Array = new Array(); + private var pakRecv:Array = new Array(); + private var beginningValues:Object = {}; + private var info:Object = new Object(); + + private var _service:String; + + public function ClientServerBandwidth() + { + for (var i:int = 0; i < 1200; i++){ + payload[i] = Math.random(); //16K approx + } + + res = new Responder(onResult, onStatus); + + + } + + public function set service(service:String):void + { + _service = service; + } + + public function start():void + { + nc.client = this; + var obj:Array = new Array(); + nc.call(_service, res); + } + + private function onResult(obj:Object):void + { + this.now = (new Date()).getTime()/1; + if(sent == 0) { + this.beginningValues = obj; + this.beginningValues.time = now; + this.pakSent[sent++] = now; + nc.call(_service, res, now); + } else { + this.pakRecv[this.count] = now; + this.pakInterval = (this.pakRecv[this.count] - this.pakSent[this.count])*1; + this.count++; + this.timePassed = (now - this.beginningValues.time); + + if (this.count == 1) { + this.latency = Math.min(timePassed, 800); + this.latency = Math.max(this.latency, 10); + this.overhead = obj.cOutBytes - this.beginningValues.cOutBytes; + + this.pakSent[sent++] = now; + nc.call(_service, res, now, payload); + dispatchStatus(info); + + } + // If we have a hi-speed network with low latency send more to determine + // better bandwidth numbers, send no more than 6 packets + if ( (this.count >= 1) && (timePassed<1000)) + { + this.pakSent[sent++] = now; + this.cumLatency++; + nc.call(_service, res, now, payload); + dispatchStatus(info); + } else if ( this.sent == this.count ) { + // See if we need to normalize latency + if ( this.latency >= 100 ) + { // make sure we detect sattelite and modem correctly + if ( this.pakRecv[1] - this.pakRecv[0] > 1000 ) + { + this.latency = 100; + } + } + payload = new Array(); + // Got back responses for all the packets compute the bandwidth. + var stats:Object = obj; + deltaUp = (stats.cOutBytes - this.beginningValues.cOutBytes)*8/1000; + deltaTime = ((now - this.beginningValues.time) - (this.latency * this.cumLatency) )/1000; + if ( deltaTime <= 0 ) + deltaTime = (now - this.beginningValues.time)/1000; + + kbitUp = Math.round(deltaUp/deltaTime); + KBytes = (stats.cOutBytes - this.beginningValues.cOutBytes)/1024; + + var info:Object = new Object(); + info.kbitUp = kbitUp; + info.deltaUp = deltaUp; + info.deltaTime = deltaTime; + info.latency = latency; + info.KBytes = KBytes; + + dispatchComplete(info); + } + } + } + + override protected function dispatchStatus(obj:Object):void + { + obj.count = this.count; + obj.sent = this.sent; + obj.timePassed = timePassed; + obj.latency = this.latency; + obj.overhead = this.overhead; + obj.pakInterval = this.pakInterval; + obj.cumLatency = this.cumLatency; + + super.dispatchStatus(info); + } + + private function onStatus(obj:Object):void + { + switch (obj.code) + { + case "NetConnection.Call.Failed": + dispatchFailed(obj); + break; + } + } + } +} diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/ServerClientBandwidth.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/ServerClientBandwidth.as new file mode 100644 index 0000000000..84b892589b --- /dev/null +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/ServerClientBandwidth.as @@ -0,0 +1,55 @@ +package org.red5.flash.bwcheck +{ + import flash.net.Responder; + + public class ServerClientBandwidth extends BandwidthDetection + { + + private var _service:String; + private var info:Object = new Object(); + private var res:Responder; + + public function ServerClientBandwidth() + { + res = new Responder(onResult, onStatus); + } + + public function onBWCheck(obj:Object):void + { + dispatchStatus(obj); + } + + public function onBWDone(obj:Object):void + { + dispatchComplete(obj); + } + + public function set service(service:String):void + { + _service = service; + } + + public function start():void + { + nc.client = this; + nc.call(_service,res); + } + + private function onResult(obj:Object):void + { + dispatchStatus(obj); + + } + + private function onStatus(obj:Object):void + { + switch (obj.code) + { + case "NetConnection.Call.Failed": + dispatchFailed(obj); + break; + } + + } + } +} diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/app/BandwidthDetectionApp.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/app/BandwidthDetectionApp.as new file mode 100644 index 0000000000..77b3e2f4b7 --- /dev/null +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/app/BandwidthDetectionApp.as @@ -0,0 +1,131 @@ +package org.red5.flash.bwcheck.app +{ + import flash.events.NetStatusEvent; + import flash.net.NetConnection; + import flash.net.Responder; + + import mx.core.Application; + + import org.bigbluebutton.common.LogUtil; + + import org.red5.flash.bwcheck.ClientServerBandwidth; + import org.red5.flash.bwcheck.ServerClientBandwidth; + import org.red5.flash.bwcheck.events.BandwidthDetectEvent; + + public class BandwidthDetectionApp extends Application + { + private var _serverURL:String = "localhost"; + private var _serverApplication:String = ""; + private var _clientServerService:String = ""; + private var _serverClientService:String = ""; + + private var nc:NetConnection; + + public function BandwidthDetectionApp() + { + + } + + public function set serverURL(url:String):void + { + _serverURL = url; + } + + public function set serverApplication(app:String):void + { + _serverApplication = app; + } + + public function set clientServerService(service:String):void + { + _clientServerService = service; + } + + public function set serverClientService(service:String):void + { + _serverClientService = service; + } + + public function connect():void + { + nc = new NetConnection(); + nc.objectEncoding = flash.net.ObjectEncoding.AMF0; + nc.client = this; + nc.addEventListener(NetStatusEvent.NET_STATUS, onStatus); + nc.connect("rtmp://" + _serverURL + "/" + _serverApplication); + } + + + private function onStatus(event:NetStatusEvent):void + { + switch (event.info.code) + { + case "NetConnection.Connect.Success": + LogUtil.debug(event.info.code); + LogUtil.debug("Detecting Server Client Bandwidth"); + ServerClient(); + break; + } + + } + + public function ClientServer():void + { + var clientServer:ClientServerBandwidth = new ClientServerBandwidth(); + //connect(); + clientServer.connection = nc; + clientServer.service = _clientServerService; + clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + clientServer.start(); + } + + public function ServerClient():void + { + var serverClient:ServerClientBandwidth = new ServerClientBandwidth(); + //connect(); + serverClient.connection = nc; + serverClient.service = _serverClientService; + serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + + serverClient.start(); + } + + public function onDetectFailed(event:BandwidthDetectEvent):void + { + LogUtil.debug("Detection failed with error: " + event.info.application + " " + event.info.description); + } + + public function onClientServerComplete(event:BandwidthDetectEvent):void + { + LogUtil.debug("kbitUp = " + event.info.kbitUp + ", deltaUp= " + event.info.deltaUp + ", deltaTime = " + event.info.deltaTime + ", latency = " + event.info.latency + " KBytes " + event.info.KBytes); + LogUtil.debug("Client to Server Bandwidth Detection Complete"); + } + + public function onClientServerStatus(event:BandwidthDetectEvent):void + { + if (event.info) { + LogUtil.debug("count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" overhead: "+event.info.overhead+" packet interval: " + event.info.pakInterval + " cumLatency: " + event.info.cumLatency); + } + } + + public function onServerClientComplete(event:BandwidthDetectEvent):void + { + LogUtil.debug("kbit Down: " + event.info.kbitDown + " Delta Down: " + event.info.deltaDown + " Delta Time: " + event.info.deltaTime + " Latency: " + event.info.latency); + LogUtil.debug("Server Client Bandwidth Detect Complete"); + LogUtil.debug("Detecting Client Server Bandwidth)"; + ClientServer(); + } + + public function onServerClientStatus(event:BandwidthDetectEvent):void + { + if (event.info) { + LogUtil.debug("count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" cumLatency: " + event.info.cumLatency); + } + } + + } +} diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/events/BandwidthDetectEvent.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/events/BandwidthDetectEvent.as new file mode 100644 index 0000000000..3720aad516 --- /dev/null +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/events/BandwidthDetectEvent.as @@ -0,0 +1,30 @@ +package org.red5.flash.bwcheck.events +{ + import flash.events.Event; + + public class BandwidthDetectEvent extends Event + { + public static const DETECT_STATUS:String = "detect_status"; + public static const DETECT_COMPLETE:String = "detect_complete"; + public static const DETECT_FAILED:String = "detect_failed"; + + private var _info:Object; + + public function BandwidthDetectEvent(eventName:String) + { + super (eventName); + } + + public function set info(obj:Object):void + { + _info = obj; + } + + public function get info():Object + { + return _info; + } + + + } +} \ No newline at end of file From aa903710ee19bbe7b8badda3887a9f8e0c51dd14 Mon Sep 17 00:00:00 2001 From: Felipe Cecagno Date: Wed, 9 Jan 2013 17:25:01 -0200 Subject: [PATCH 2/3] hiding also the total bandwidth consumed - it's not working properly in some situations, so it will be hidden for now --- .../org/bigbluebutton/main/views/NetworkStatsWindow.mxml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml index 17b6fa3889..ce300dc493 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml @@ -30,9 +30,9 @@ resizable="false" showCloseButton="false" implements="org.bigbluebutton.common.IBbbModuleWindow" - width="210" height="223" minHeight="0" minWidth="0" + width="210" height="186" minHeight="0" minWidth="0" resize="onResize()"> - + - + - + From c335f97243920bcf464510082987b860212f969a Mon Sep 17 00:00:00 2001 From: Felipe Cecagno Date: Fri, 12 Apr 2013 18:02:09 -0300 Subject: [PATCH 3/3] changed the way the network monitor window is presented; now there's a button that must be clicked in order to pop up the window; the bandwidth measurement is done only when the user clicks on the refresh icon, and it doesn't check twice in the 30 seconds interval; also fixed the window height, that is now calculated given the internal panel height --- .../src/org/bigbluebutton/common/Images.as | 6 + .../assets/images/arrow_refresh_small.png | Bin 0 -> 506 bytes .../common/assets/images/bandwidth.png | Bin 0 -> 880 bytes .../core/services/BandwidthMonitor.as | 222 +++++++++++------- .../main/model/users/NetConnectionDelegate.as | 19 +- .../main/views/MainApplicationShell.mxml | 38 +-- .../main/views/NetworkStatsWindow.mxml | 42 ++-- .../flash/bwcheck/ClientServerBandwidth.as | 10 + 8 files changed, 189 insertions(+), 148 deletions(-) create mode 100644 bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_refresh_small.png create mode 100644 bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as index 425075e6e8..7d2afed222 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as +++ b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as @@ -21,6 +21,12 @@ package org.bigbluebutton.common [Bindable] public class Images { + [Embed(source="assets/images/bandwidth.png")] + public var bandwidth:Class; + + [Embed(source="assets/images/arrow_refresh_small.png")] + public var refreshSmall:Class; + [Embed(source="assets/images/webcam_close.png")] public var webcamClose:Class; diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_refresh_small.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_refresh_small.png new file mode 100644 index 0000000000000000000000000000000000000000..d3087dfc920b1705cdebc5beeba8a62047c99b68 GIT binary patch literal 506 zcmV-LrYk6ae86R!cq$1)rW52v1)b7{)|O}AG6Uw?DO|Ft)k{$F)%(f{RF=l?I+ zlJnnhy4xL`1{54hojLt{-~Wv_SN(53T=hS3efa;Fl|lb2w&(vZ*_{2~XR7ONye`Pu zoA?0e-~T}W{*PZ9b_gaOFw5hT_Y~(tZoT$Qj_p>QLT-Dpnng!_d8sIiCa_~9WpM}{jZm=`Cltb^#NWN0R6i=Yh}{^)FrY1 zts6}Ln^hV9kC-0#zxPDb|Kx?y|5Z~IXW}#f=--za%M<=jKim6%%IU8E6Hm4O?>pJ@ zzvo2be~`FJvceg~cv%O$F0gC1*cmrB?0?kE;Q#uCTK~1P)&8reDgReaQaGRxhpHK8 wAOih+0O;RKWM?MbJPl^eOx0CX$&G|C05z+&w|oy)!1^@s6 literal 0 HcmV?d00001 diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..adb979ce5aa24832549312d1291605e4dfcc4cae GIT binary patch literal 880 zcmV-$1CRWPP)-Fu}YoloGoO1(Z8i}fZh`#KKvIe2zocruKhn-ya5_?37f@xhtYSSZ=sgX6kbwu5Pz zFfYP~_Vvxfsgrm>r*QhQ8Q z)9C8#B+}YC8H{$8b{?!PNvWy16GJ1T-&{OD?Yq0Qf;5z3t5T=7yTy7_2W8zNP|Bd5 zOwctlPG)(LL_CgZm{YbVd?v?w;+M~)#zOb+ucOzh zps{=hU-^(MaBARGTd`1hOZNHw^T~KG-z_ZQU{f#d63%WTR}XL<7XVol3E#SbP}{@y zJRX&F1_lR-L?iQZI2=+Mnoi9;pnJxLF6?11meJJ^p>P;c5UAJdj0!uv+3^R5JtJIO z?80$ee6p;_czCvLqgEOemt8#BhqVumq0`>phEJ9$A0AMWn)tObfSUEtbo-wS2qLoD z&@zH34%)hlx}qNoRZ}2<-|xdT46+7fD^UPKVG&6ZaXoieG)?2jT%kxpQLs$oX`6;l zSGS?m|{96l^PqnQMQ zAx;mElFMex`OMB&(q18}cD#@-x%bIR6a|Dws^~$*|b~0000 new Date().getTime()) + return; + + if (!_nc.connected) { + _pendingClientToServer = true; + connect(); + } if (_runningMeasurement) { + _pendingClientToServer = true; + } else { + _pendingClientToServer = false; + _runningMeasurement = true; + _lastClientToServerCheck = new Date(); + + LogUtil.debug("Start client-server bandwidth detection"); + var clientServer:ClientServerBandwidth = new ClientServerBandwidth(); + clientServer.connection = _nc; + clientServer.service = _clientServerService; + clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus); + clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + clientServer.start(); + } + } + + public function checkServerToClient():void { + if (_lastServerToClientCheck != null && _lastServerToClientCheck.getTime() + INTERVAL_BETWEEN_CHECKS > new Date().getTime()) + return; + + if (!_nc.connected) { + _pendingServerToClient = true; + connect(); + } if (_runningMeasurement) { + _pendingServerToClient = true; + } else { + _pendingServerToClient = false; + _runningMeasurement = true; + _lastServerToClientCheck = new Date(); + + LogUtil.debug("Start server-client bandwidth detection"); + var serverClient:ServerClientBandwidth = new ServerClientBandwidth(); + serverClient.connection = _nc; + serverClient.service = _serverClientService; + serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus); + serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); + serverClient.start(); + } + } + + private function checkPendingOperations():void { + if (_pendingClientToServer) checkClientToServer(); + if (_pendingServerToClient) checkServerToClient(); + } + + private function onAsyncError(event:AsyncErrorEvent):void { + LogUtil.debug(event.error.toString()); + } + + private function onIOError(event:IOErrorEvent):void { + LogUtil.debug(event.text); } private function onStatus(event:NetStatusEvent):void @@ -59,87 +155,49 @@ package org.bigbluebutton.core.services switch (event.info.code) { case "NetConnection.Connect.Success": - LogUtil.debug("Starting to monitor bandwidth between client and server"); - monitor(); + LogUtil.debug("Connection established to measure bandwidth"); break; default: LogUtil.debug("Cannot establish the connection to measure bandwidth"); break; - } + } + _connecting = false; + checkPendingOperations(); } - private function monitor():void { - LogUtil.debug("Starting to monitor bandwidth"); - bwTestTimer = new Timer(30000); - bwTestTimer.addEventListener(TimerEvent.TIMER, rtmptRetryTimerHandler); - bwTestTimer.start(); - } - - private function rtmptRetryTimerHandler(event:TimerEvent):void { - LogUtil.debug("Starting to detect bandwidth from server to client"); - ServerClient(); - } - - public function ClientServer():void - { - var clientServer:ClientServerBandwidth = new ClientServerBandwidth(); - //connect(); - clientServer.connection = nc; - clientServer.service = _clientServerService; - clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete); - clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus); - clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); - clientServer.start(); - } - - public function ServerClient():void - { - var serverClient:ServerClientBandwidth = new ServerClientBandwidth(); - //connect(); - serverClient.connection = nc; - serverClient.service = _serverClientService; - serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete); - serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus); - serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed); - serverClient.start(); - } - - public function onDetectFailed(event:BandwidthDetectEvent):void - { + public function onDetectFailed(event:BandwidthDetectEvent):void { LogUtil.debug("Detection failed with error: " + event.info.application + " " + event.info.description); + _runningMeasurement = false; } - public function onClientServerComplete(event:BandwidthDetectEvent):void - { -// LogUtil.debug("Client-slient bandwidth detect complete"); - + public function onClientServerComplete(event:BandwidthDetectEvent):void { + LogUtil.debug("Client-server bandwidth detection complete"); // LogUtil.debug(ObjectUtil.toString(event.info)); NetworkStatsData.getInstance().setUploadMeasuredBW(event.info); + _runningMeasurement = false; + checkPendingOperations(); } - public function onClientServerStatus(event:BandwidthDetectEvent):void - { - if (event.info) { + public function onClientServerStatus(event:BandwidthDetectEvent):void { +// if (event.info) { // LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" overhead: "+event.info.overhead+" packet interval: " + event.info.pakInterval + " cumLatency: " + event.info.cumLatency); - } +// } } - public function onServerClientComplete(event:BandwidthDetectEvent):void - { -// LogUtil.debug("Server-client bandwidth detect complete"); - + public function onServerClientComplete(event:BandwidthDetectEvent):void { + LogUtil.debug("Server-client bandwidth detection complete"); // LogUtil.debug(ObjectUtil.toString(event.info)); NetworkStatsData.getInstance().setDownloadMeasuredBW(event.info); - -// LogUtil.debug("Detecting Client Server Bandwidth"); - ClientServer(); + _runningMeasurement = false; + checkPendingOperations(); } - public function onServerClientStatus(event:BandwidthDetectEvent):void - { - if (event.info) { + public function onServerClientStatus(event:BandwidthDetectEvent):void { +// if (event.info) { // LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" cumLatency: " + event.info.cumLatency); - } +// } } } -} \ No newline at end of file +} + +class SingletonEnforcer{} \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as index aebd1c603d..4d32e2481d 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as @@ -74,6 +74,10 @@ package org.bigbluebutton.main.model.users _netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError ); _netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError ); _netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError ); + + var pattern:RegExp = /(?P.+):\/\/(?P.+)\/(?P.+)/; + var result:Array = pattern.exec(_applicationURI); + BandwidthMonitor.getInstance().serverURL = result.server; } public function get connection():NetConnection { @@ -129,17 +133,6 @@ package org.bigbluebutton.main.model.users handleResult( event ); } - private var _bwMon:BandwidthMonitor = new BandwidthMonitor(); - - private function startMonitoringBandwidth():void { - trace("Start monitoring bandwidth."); - var pattern:RegExp = /(?P.+):\/\/(?P.+)\/(?P.+)/; - var result:Array = pattern.exec(_applicationURI); - _bwMon.serverURL = result.server; - _bwMon.serverApplication = "video"; - _bwMon.start(); - } - public function handleResult( event : Object ) : void { var info : Object = event.info; var statusCode : String = info.code; @@ -148,9 +141,7 @@ package org.bigbluebutton.main.model.users { case CONNECT_SUCCESS : LogUtil.debug(NAME + ":Connection to viewers application succeeded."); - - startMonitoringBandwidth(); - + _netConnection.call( "getMyUserId",// Remote function name new Responder( diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml index 3b8a4ee75b..acc233c787 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml @@ -95,7 +95,8 @@ [Bindable] private var fullscreen_icon:Class = images.full_screen; [Bindable] private var logs_icon:Class = images.table; - [Bindable] private var reset_layout_icon:Class = images.layout; + [Bindable] private var reset_layout_icon:Class = images.layout; + [Bindable] private var statsIcon:Class = images.bandwidth; private var receivedConfigLocaleVer:Boolean = false; private var receivedResourceLocaleVer:Boolean = false; @@ -306,36 +307,22 @@ Alert.show(evt.status, evt.module); } - private var networkStatsWindow:NetworkStatsWindow = new NetworkStatsWindow(); + private var networkStatsWindow:NetworkStatsWindow = null; - private function openNetworkStatsWindow(event:MouseEvent):void { - event.target.addEventListener(MouseEvent.MOUSE_MOVE, updateNetworkStatsWindowPosition); - networkStatsWindow.appear(this); - } - - private function updateNetworkStatsWindowPosition(event:MouseEvent):void { - var mousePosition:Point = new Point(event.localX, event.localY); - //LogUtil.debug("mouse position: " + mousePosition.x + " " + mousePosition.y); - - var mouseGlobal:Point = event.target.localToGlobal(mousePosition); - //LogUtil.debug("mouse global position: " + mouseGlobal.x + " " + mouseGlobal.y); - - var windowPosition:Point = this.globalToContent(mouseGlobal); - //LogUtil.debug("window position: " + windowPosition.x + " " + windowPosition.y); - - networkStatsWindow.x = windowPosition.x - networkStatsWindow.width - 10; - networkStatsWindow.y = windowPosition.y - networkStatsWindow.height - 10; - } - - private function closeNetworkStatsWindow(event:MouseEvent):void { - event.target.removeEventListener(MouseEvent.MOUSE_MOVE, updateNetworkStatsWindowPosition); - networkStatsWindow.disappear(); + private function openNetworkStatsWindow():void { + if (networkStatsWindow == null) + networkStatsWindow = new NetworkStatsWindow(); + + mdiCanvas.windowManager.add(networkStatsWindow); + mdiCanvas.windowManager.absPos(networkStatsWindow, mdiCanvas.width - networkStatsWindow.width, mdiCanvas.height - networkStatsWindow.height); + mdiCanvas.windowManager.bringToFront(networkStatsWindow); } private function updateBandwidthTimerHandler(e:TimerEvent):void { _bandwidthConsumedDown = NetworkStatsData.getInstance().formattedCurrentConsumedDownBW; _bandwidthConsumedUp = NetworkStatsData.getInstance().formattedCurrentConsumedUpBW; } + ]]> @@ -349,7 +336,8 @@ - + + diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml index ce300dc493..7dada8a8eb 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml @@ -28,11 +28,10 @@ title="{ResourceUtil.getInstance().getString('bbb.bwmonitor.title')}" creationComplete="onCreationComplete()" resizable="false" - showCloseButton="false" + showCloseButton="true" implements="org.bigbluebutton.common.IBbbModuleWindow" - width="210" height="186" minHeight="0" minWidth="0" + width="210" minWidth="0" resize="onResize()"> - - @@ -123,6 +110,7 @@ + diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as index 22a97d3846..e16a3ec9b2 100644 --- a/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as +++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as @@ -139,5 +139,15 @@ package org.red5.flash.bwcheck break; } } + + public function onBWCheck(obj:Object):void + { +// dispatchStatus(obj); + } + + public function onBWDone(obj:Object):void + { +// dispatchComplete(obj); + } } }