Merge branch 'master' of github.com:bigbluebutton/bigbluebutton into guest-mobile-access

This commit is contained in:
Richard Alam 2018-02-26 07:25:45 -08:00
commit 7b2d2279f9
56 changed files with 1714 additions and 792 deletions

View File

@ -10,6 +10,7 @@
@namespace chat "org.bigbluebutton.lib.settings.views.chat.*";
@namespace lock "org.bigbluebutton.lib.settings.views.lock.*";
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace ex "http://flex.apache.org/experimental/ns";
@font-face {
src : url("../../shared/assets/fonts/SourceSansPro/SourceSansPro-Regular.ttf");
@ -84,7 +85,7 @@ global {
/* Classes */
s|Application {
backgroundColor : PropertyReference("bbbBlack");
backgroundColor : PropertyReference("bbbBlack");
}
s|Button {
@ -93,7 +94,7 @@ s|Button {
/* Loading screen */
main|LoadingScreen {
color : PropertyReference("white");
color : PropertyReference("white");
backgroundColor : PropertyReference("bbbBlack");
textAlign : center;
}
@ -101,7 +102,7 @@ main|LoadingScreen {
/* Main view */
main|MainView {
backgroundColor : PropertyReference("bbbBlack");
backgroundColor : PropertyReference("bbbBlack");
}
main|TopToolbarAIR {
@ -110,7 +111,7 @@ main|TopToolbarAIR {
participants|ParticipantsViewBase, users|UsersViewBase {
backgroundColor : PropertyReference("grey100");
color : PropertyReference("blue900");
color : PropertyReference("blue900");
}
settings|SettingsViewBase, audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase, camera|CameraSettingsViewBase {
@ -119,7 +120,7 @@ settings|SettingsViewBase, audio|AudioSettingsViewBase, chat|ChatSettingsViewBas
separatorColor : PropertyReference("grey200");
}
participants|ParticipantsViewBase s|List{
participants|ParticipantsViewBase s|List {
contentBackgroundColor : PropertyReference("white");
}
@ -134,6 +135,14 @@ libChat|ChatViewBase {
inputBorderColor : PropertyReference("grey300");
}
ex|ProgressBar {
skinClass : ClassReference("org.bigbluebutton.air.common.views.skins.ProgressBarSkin");
fontFamily : SourceSansProMX;
trackBackgroundColor : PropertyReference("grey100");
barColor : PropertyReference("bbbBlue");
percentColor : PropertyReference("white");
}
s|ToggleSwitch {
accentColor : PropertyReference("green500");
color : PropertyReference("white");
@ -142,7 +151,7 @@ s|ToggleSwitch {
}
s|HSlider {
skinClass : ClassReference("spark.skins.ios7.HSliderSkin");
skinClass : ClassReference("spark.skins.ios7.HSliderSkin");
}
s|CheckBox {
@ -177,7 +186,7 @@ libChat|ChatItemRenderer {
}
users|UserItemRenderer {
color : PropertyReference("grey700");
color : PropertyReference("grey700");
}
settings|SettingsItemRenderer {
@ -215,23 +224,27 @@ settings|SettingsItemRenderer {
}
.settingsIcon {
iconColor : PropertyReference("grey700");
iconColor : PropertyReference("grey700");
}
.chatIcon {
color : PropertyReference("grey700");
}
.menuButton {
.menuButton, .menuButtonRed {
fontFamily : SourceSansPro;
backgroundColor : PropertyReference("bbbBlue");
selectedBackgroundColor : PropertyReference("bbbGrey");
color : PropertyReference("white");
iconFont : BBBIcons;
iconColor : PropertyReference("white");
iconFont : BBBIcons;
iconColor : PropertyReference("white");
skinClass : ClassReference("org.bigbluebutton.lib.main.views.skins.MenuButtonSkin");
}
.menuButtonRed {
backgroundColor : PropertyReference("bbbRed");
}
.participantIcon {
color : PropertyReference("grey700");
circleColor : PropertyReference("grey700");
@ -262,3 +275,7 @@ settings|SettingsItemRenderer {
.leaveLabel {
color : PropertyReference("blue500");
}
.micLevelProgressBar {
showLabel : false;
}

View File

@ -4,7 +4,7 @@
applicationComplete="applicationCompleteHandler(event)"
preinitialize="preinitializeHandler(event)"
styleName="mainshell"
xmlns:main="org.bigbluebutton.air.main.views.*">
xmlns:main="org.bigbluebutton.air.main.views.*" xmlns:setup="org.as3commons.logging.setup.*">
<fx:Style source="../../shared/assets/css/common.css" />
<fx:Style source="../../shared/assets/css/bbb-icons.css" />
<fx:Style source="Default.css" />
@ -107,6 +107,7 @@
visible="false"
gap="0"
horizontalAlign="center">
<main:BannerView id="bannerView" width="100%" height="30" visible="false" includeInLayout="false"/>
<main:PagesNavigatorView id="pagesNavigatorView"
width="100%"
height="100%" />

View File

@ -24,6 +24,8 @@
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 240) {
main|LoadingScreen {
fontSize: 25.50;
@ -59,12 +61,12 @@
}
libChat|ChatItemRenderer {
padding: 10.50;
gap: 6.00;
leftIndent: 33.00;
fontSize: 21.00;
nameFontSize: 21.00;
timeFontSize: 21.00;
padding: 10.50;
gap: 6.00;
leftIndent: 33.00;
fontSize: 21.00;
nameFontSize: 21.00;
timeFontSize: 21.00;
}
settings|SettingsViewBase, camera|CameraSettingsViewBase {
@ -74,10 +76,14 @@
audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase {
padding: 22.50;
}
usersAIR|UserDetailsView {
groupsPadding : 15.00;
}
voice|EchoTestViewBase {
padding: 22.50;
}
usersAIR|UserDetailsView {
groupsPadding: 15.00;
}
settings|SettingsItemRenderer {
fontSize: 25.50;
@ -98,6 +104,10 @@
iconSize: 33.00;
}
voice|EchoTestViewBase {
padding: 22.50;
}
s|ToggleSwitch {
fontSize: 18.00;
}
@ -179,4 +189,8 @@
borderWeight: 1.50;
cornerRadius: 3.00;
}
.echoTestLabel {
padding: 24.00;
}
}

View File

@ -24,6 +24,8 @@
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 120) {
main|LoadingScreen {
fontSize: 12.750;
@ -59,12 +61,12 @@
}
libChat|ChatItemRenderer {
padding: 5.25;
gap: 3.00;
leftIndent: 16.50;
fontSize: 10.50;
nameFontSize: 10.50;
timeFontSize: 10.50;
padding: 5.250;
gap: 3.000;
leftIndent: 16.500;
fontSize: 10.500;
nameFontSize: 10.500;
timeFontSize: 10.500;
}
settings|SettingsViewBase, camera|CameraSettingsViewBase {
@ -74,10 +76,14 @@
audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase {
padding: 11.250;
}
usersAIR|UserDetailsView {
groupsPadding : 7.500;
}
voice|EchoTestViewBase {
padding: 11.250;
}
usersAIR|UserDetailsView {
groupsPadding: 7.500;
}
settings|SettingsItemRenderer {
fontSize: 12.750;
@ -98,6 +104,10 @@
iconSize: 16.500;
}
voice|EchoTestViewBase {
padding: 11.250;
}
s|ToggleSwitch {
fontSize: 9.000;
}
@ -179,4 +189,8 @@
borderWeight: .750;
cornerRadius: 1.500;
}
.echoTestLabel {
padding: 12.000;
}
}

View File

@ -24,6 +24,8 @@
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 160) {
main|LoadingScreen {
fontSize: 17.0;
@ -59,12 +61,12 @@
}
libChat|ChatItemRenderer {
padding: 7.00;
gap: 4.00;
leftIndent: 22.00;
fontSize: 14.00;
nameFontSize: 14.00;
timeFontSize: 14.00;
padding: 7.0;
gap: 4.0;
leftIndent: 22.0;
fontSize: 14.0;
nameFontSize: 14.0;
timeFontSize: 14.0;
}
settings|SettingsViewBase, camera|CameraSettingsViewBase {
@ -74,10 +76,14 @@
audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase {
padding: 15.0;
}
usersAIR|UserDetailsView {
groupsPadding : 10;
}
voice|EchoTestViewBase {
padding: 15.0;
}
usersAIR|UserDetailsView {
groupsPadding: 10.0;
}
settings|SettingsItemRenderer {
fontSize: 17.0;
@ -98,6 +104,10 @@
iconSize: 22.0;
}
voice|EchoTestViewBase {
padding: 15.0;
}
s|ToggleSwitch {
fontSize: 12.0;
}
@ -179,4 +189,8 @@
borderWeight: 1.0;
cornerRadius: 2.0;
}
.echoTestLabel {
padding: 16.0;
}
}

View File

@ -11,6 +11,7 @@
@namespace chat "org.bigbluebutton.lib.settings.views.chat.*";
@namespace lock "org.bigbluebutton.lib.settings.views.lock.*";
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 320) {
main|LoadingScreen {
@ -63,6 +64,10 @@
padding: 30;
}
voice|EchoTestViewBase {
padding: 30;
}
usersAIR|UserDetailsView {
groupsPadding : 20;
}
@ -86,6 +91,10 @@
iconSize : 44;
}
voice|EchoTestViewBase {
padding: 30;
}
s|ToggleSwitch {
fontSize : 24;
}
@ -167,4 +176,8 @@
borderWeight : 2;
cornerRadius : 4;
}
.echoTestLabel {
padding : 32;
}
}

View File

@ -24,6 +24,8 @@
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 480) {
main|LoadingScreen {
fontSize: 51.0;
@ -59,12 +61,12 @@
}
libChat|ChatItemRenderer {
padding: 21.00;
gap: 12.00;
leftIndent: 66.00;
fontSize: 42.00;
nameFontSize: 42.00;
timeFontSize: 42.00;
padding: 21.0;
gap: 12.0;
leftIndent: 66.0;
fontSize: 42.0;
nameFontSize: 42.0;
timeFontSize: 42.0;
}
settings|SettingsViewBase, camera|CameraSettingsViewBase {
@ -74,10 +76,14 @@
audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase {
padding: 45.0;
}
usersAIR|UserDetailsView {
groupsPadding : 30.0;
}
voice|EchoTestViewBase {
padding: 45.0;
}
usersAIR|UserDetailsView {
groupsPadding: 30.0;
}
settings|SettingsItemRenderer {
fontSize: 51.0;
@ -98,6 +104,10 @@
iconSize: 66.0;
}
voice|EchoTestViewBase {
padding: 45.0;
}
s|ToggleSwitch {
fontSize: 36.0;
}
@ -179,4 +189,8 @@
borderWeight: 3.0;
cornerRadius: 6.0;
}
.echoTestLabel {
padding: 48.0;
}
}

View File

@ -24,6 +24,8 @@
@namespace camera "org.bigbluebutton.lib.settings.views.camera.*";
@namespace voice "org.bigbluebutton.lib.voice.views.*";
@media (application-dpi: 640) {
main|LoadingScreen {
fontSize: 68;
@ -59,12 +61,12 @@
}
libChat|ChatItemRenderer {
padding: 28.00;
gap: 16.00;
leftIndent: 88.00;
fontSize: 56.00;
nameFontSize: 56.00;
timeFontSize: 56.00;
padding: 28;
gap: 16;
leftIndent: 88;
fontSize: 56;
nameFontSize: 56;
timeFontSize: 56;
}
settings|SettingsViewBase, camera|CameraSettingsViewBase {
@ -74,10 +76,14 @@
audio|AudioSettingsViewBase, chat|ChatSettingsViewBase, lock|LockSettingsViewBase {
padding: 60;
}
usersAIR|UserDetailsView {
groupsPadding : 40;
}
voice|EchoTestViewBase {
padding: 60;
}
usersAIR|UserDetailsView {
groupsPadding: 40;
}
settings|SettingsItemRenderer {
fontSize: 68;
@ -98,6 +104,10 @@
iconSize: 88;
}
voice|EchoTestViewBase {
padding: 60;
}
s|ToggleSwitch {
fontSize: 48;
}
@ -179,4 +189,8 @@
borderWeight: 4;
cornerRadius: 8;
}
.echoTestLabel {
padding: 64;
}
}

View File

@ -42,8 +42,6 @@ package org.bigbluebutton.air {
import org.bigbluebutton.lib.video.services.VideoConnection;
import org.bigbluebutton.lib.voice.services.IVoiceConnection;
import org.bigbluebutton.lib.voice.services.VoiceConnection;
import org.bigbluebutton.lib.whiteboard.services.IWhiteboardService;
import org.bigbluebutton.lib.whiteboard.services.WhiteboardService;
import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
import robotlegs.bender.framework.api.IConfig;

View File

@ -7,10 +7,11 @@ package org.bigbluebutton.air.common {
import org.bigbluebutton.air.participants.views.ParticipantsView;
import org.bigbluebutton.air.settings.views.SettingsView;
import org.bigbluebutton.air.settings.views.audio.AudioSettingsView;
import org.bigbluebutton.air.voice.views.EchoTestView;
import org.bigbluebutton.air.settings.views.camera.CameraSettingsView;
import org.bigbluebutton.air.settings.views.chat.ChatSettingsView;
import org.bigbluebutton.air.settings.views.lock.LockSettingsView;
import org.bigbluebutton.air.users.views.UserDetailsView;
import org.bigbluebutton.air.users.views.UserDetailsView;
public class PageEnum {
public static const MAIN:String = "main";
@ -39,6 +40,8 @@ package org.bigbluebutton.air.common {
public static const SETTINGS:String = "Settings";
public static const ECHOTEST:String = "EchoTest";
public static const APPLICATION_SETTINGS:String = "ApplicationSettings";
/**
@ -52,6 +55,7 @@ package org.bigbluebutton.air.common {
dic[PARTICIPANTS] = ParticipantsView;
dic[CHAT] = ChatRoomView;
dic[SETTINGS] = SettingsView;
dic[ECHOTEST] = EchoTestView;
dic[AUDIOSETTINGS] = AudioSettingsView;
dic[CAMERASETTINGS] = CameraSettingsView;
dic[CHATSETTINGS] = ChatSettingsView;

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<!--
Original file
https://github.com/akamud/FlatSpark/blob/master/FlatSparkSkin/src/flatSpark/skins/ProgressBarSkin.mxml
-->
<fx:Metadata>
[HostComponent("spark.components.ProgressBar")]
</fx:Metadata>
<fx:Script>
<![CDATA[
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
bgColor.color = getStyle("trackBackgroundColor");
bar.color = getStyle("barColor");
percentDisplay.setStyle("color", getStyle("percentColor"));
percentDisplay.visible = percentDisplay.includeInLayout = getStyle("showLabel");
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<s:Rect left="0"
minHeight="14"
top="0"
bottom="0"
right="0"
radiusX="4">
<s:fill>
<s:SolidColor id="bgColor" />
</s:fill>
</s:Rect>
<s:Group id="progressGroup"
top="0"
bottom="0"
left="{hostComponent.direction=='left' ? 0 : NaN}"
right="{hostComponent.direction=='right' ? 0 : NaN}">
<s:Rect left="0"
top="0"
bottom="0"
right="0"
radiusX="4">
<s:fill>
<s:SolidColor id="bar" />
</s:fill>
</s:Rect>
<!--
Variant #2 (looks nicer) - uncomment this and remove last Label declaration
<s:Label id="percentDisplay"
right="2" verticalCenter="0" verticalAlign="middle"
visible="{progressBox.width > percentDisplay.width + 4}"
includeInLayout="{progressBox.width > percentDisplay.width + 4}"/>
-->
</s:Group>
<s:Label id="percentDisplay"
left="2"
right="2"
verticalCenter="0"
verticalAlign="middle"
fontFamily="Lato"
fontWeight="bold"
fontSize="13"
textAlign="center" />
</s:Skin>

View File

@ -4,8 +4,11 @@ package org.bigbluebutton.air.main {
import org.bigbluebutton.air.main.commands.JoinMeetingCommandAIR;
import org.bigbluebutton.air.main.commands.NavigateToCommand;
import org.bigbluebutton.air.main.commands.NavigateToSignal;
import org.bigbluebutton.air.main.views.BannerView;
import org.bigbluebutton.air.main.views.BannerViewMediator;
import org.bigbluebutton.air.main.views.LoadingScreen;
import org.bigbluebutton.air.main.views.LoadingScreenMediator;
import org.bigbluebutton.air.main.views.MenuButtonsMediatorAIR;
import org.bigbluebutton.air.main.views.PagesNavigatorView;
import org.bigbluebutton.air.main.views.PagesNavigatorViewMediator;
import org.bigbluebutton.air.main.views.TopToolbarAIR;
@ -13,7 +16,6 @@ package org.bigbluebutton.air.main {
import org.bigbluebutton.lib.main.commands.ConnectingFailedSignal;
import org.bigbluebutton.lib.main.commands.JoinMeetingSignal;
import org.bigbluebutton.lib.main.views.MenuButtonsBase;
import org.bigbluebutton.lib.main.views.MenuButtonsMediatorBase;
import org.bigbluebutton.lib.main.views.TopToolbarBase;
import robotlegs.bender.extensions.matching.TypeMatcher;
@ -52,8 +54,9 @@ package org.bigbluebutton.air.main {
*/
mediatorMap.map(LoadingScreen).toMediator(LoadingScreenMediator);
mediatorMap.map(PagesNavigatorView).toMediator(PagesNavigatorViewMediator);
mediatorMap.map(BannerView).toMediator(BannerViewMediator);
mediatorMap.mapMatcher(new TypeMatcher().allOf(TopToolbarBase, TopToolbarAIR)).toMediator(TopToolbarMediatorAIR);
mediatorMap.map(MenuButtonsBase).toMediator(MenuButtonsMediatorBase);
mediatorMap.map(MenuButtonsBase).toMediator(MenuButtonsMediatorAIR);
}
/**

View File

@ -1,6 +1,4 @@
package org.bigbluebutton.air.main.commands {
import mx.core.FlexGlobals;
import org.bigbluebutton.air.common.PageEnum;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.lib.main.models.IConferenceParameters;

View File

@ -0,0 +1,35 @@
package org.bigbluebutton.air.main.views
{
import spark.components.Label;
import spark.components.SkinnableContainer;
import spark.layouts.HorizontalAlign;
import spark.layouts.VerticalAlign;
import spark.layouts.VerticalLayout;
public class BannerView extends SkinnableContainer
{
private var _stateLabel:Label;
public function get stateLabel():Label {
return _stateLabel;
}
public function BannerView()
{
super();
var layout:VerticalLayout = new VerticalLayout();
layout.horizontalAlign = HorizontalAlign.CENTER;
layout.verticalAlign = VerticalAlign.MIDDLE;
this.layout = layout;
_stateLabel = new Label();
_stateLabel.text = "";
_stateLabel.percentWidth = 80;
addElement(_stateLabel);
}
public function dispose():void {
}
}
}

View File

@ -0,0 +1,32 @@
package org.bigbluebutton.air.main.views
{
import org.bigbluebutton.lib.main.models.IConferenceParameters;
import robotlegs.bender.bundles.mvcs.Mediator;
public class BannerViewMediator extends Mediator
{
[Inject]
public var view:BannerView;
[Inject]
public var confParams:IConferenceParameters;
override public function initialize():void {
confParams.confParamsLoadedSignal.add(onConfParameLoadedSignal);
}
private function onConfParameLoadedSignal():void {
if (confParams.bannerText != null) {
view.visible = true;
view.includeInLayout = true;
view.stateLabel.text = confParams.bannerText;
if (confParams.bannerColor != null) {
view.setStyle('backgroundColor', confParams.bannerColor);
}
}
}
}
}

View File

@ -0,0 +1,23 @@
package org.bigbluebutton.air.main.views {
import flash.events.MouseEvent;
import org.bigbluebutton.air.common.PageEnum;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.lib.main.views.MenuButtonsMediatorBase;
public class MenuButtonsMediatorAIR extends MenuButtonsMediatorBase {
[Inject]
public var uiSession:IUISession;
override protected function audioOnOff(e:MouseEvent):void {
if (!meetingData.users.me.voiceJoined) {
uiSession.pushPage(PageEnum.ECHOTEST);
} else {
var audioOptions:Object = new Object();
audioOptions.shareMic = !meetingData.users.me.voiceJoined;
shareMicrophoneSignal.dispatch(audioOptions);
}
}
}
}

View File

@ -6,7 +6,7 @@ package org.bigbluebutton.air.main.views {
import org.bigbluebutton.lib.chat.models.GroupChat;
import org.bigbluebutton.lib.chat.models.IChatMessagesSession;
import org.bigbluebutton.lib.main.views.TopToolbarMediatorBase;
import org.bigbluebutton.lib.user.models.User2x;
import org.bigbluebutton.lib.voice.commands.StopEchoTestSignal;
public class TopToolbarMediatorAIR extends TopToolbarMediatorBase {
@ -16,6 +16,9 @@ package org.bigbluebutton.air.main.views {
[Inject]
public var chatMessagesSession:IChatMessagesSession;
[Inject]
public var stopEchoTestSignal : StopEchoTestSignal;
override protected function setTitle():void {
if (uiSession.currentPage == PageEnum.CHAT) {
var chatData:Object = uiSession.currentPageDetails;
@ -32,6 +35,8 @@ package org.bigbluebutton.air.main.views {
view.titleLabel.text = uiSession.currentPage.replace(/([A-Z])/g, ' $1');
} else if (uiSession.currentPage == PageEnum.USER_DETAILS) {
view.titleLabel.text = "User Details";
} else if (uiSession.currentPage == PageEnum.ECHOTEST) {
view.titleLabel.text = "Echo Test";
} else {
view.titleLabel.text = conferenceParameters.meetingName;
}
@ -40,6 +45,9 @@ package org.bigbluebutton.air.main.views {
override protected function leftButtonClickHandler(e:MouseEvent):void {
if (uiSession.currentPage == PageEnum.MAIN) {
uiSession.pushPage(PageEnum.PARTICIPANTS);
} else if (uiSession.currentPage == PageEnum.ECHOTEST) {
stopEchoTestSignal.dispatch();
uiSession.popPage();
} else {
uiSession.popPage();
}

View File

@ -1,191 +1,192 @@
package org.bigbluebutton.air.presentation.views.selectwebcam {
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.events.FlexMouseEvent;
import mx.resources.ResourceManager;
import spark.components.SkinnablePopUpContainer;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.user.models.UserList;
import org.bigbluebutton.lib.video.models.UserStreamName;
import robotlegs.bender.bundles.mvcs.Mediator;
public class SelectStreamPopUpMediator extends Mediator {
[Inject]
public var view:ISelectStreamPopUp;
[Inject]
public var userSession:IUserSession;
[Inject]
public var userUISession:IUISession;
protected var dataProvider:ArrayCollection;
private var speaker:User = null;
private var selectedIndex:int = -1;
private var indexChange:Boolean = false;
private var displayWebcam:Boolean;
override public function initialize():void {
userSession.userList.userRemovedSignal.add(userRemovedHandler);
userSession.userList.userAddedSignal.add(userAddedHandler);
userSession.userList.userChangeSignal.add(userChangeHandler);
view.streamList.addEventListener(MouseEvent.CLICK, onSelectStream);
view.actionButton.addEventListener(MouseEvent.CLICK, clickedActionButton);
dataProvider = new ArrayCollection();
view.streamList.dataProvider = dataProvider;
var users:ArrayCollection = userSession.userList.users;
for each (var u:User in users) {
if (u.streamName && u.streamName != "" && !dataProvider.contains(u)) {
addUserStreamNames(u);
}
}
updateSelectedIndex();
view.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, closePopUp);
}
private function closePopUp(e:FlexMouseEvent):void {
view.close(false);
}
/**
*
*/
private function updateSelectedIndex():void {
view.streamList.selectedIndex = selectedIndex;
if (selectedIndex == -1) {
view.actionButton.enabled = false;
view.actionButton.skin.setCurrentState("disabled");
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.viewWebcam');
} else {
view.actionButton.enabled = true
view.actionButton.skin.setCurrentState("up");
if (userUISession.currentStreamName == "" || indexChange) {
displayWebcam = true;
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.viewWebcam');
} else {
displayWebcam = false;
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.hideWebcam');
}
}
}
private function clickedActionButton(e:MouseEvent):void {
var selectedStream:Object = null;
if (displayWebcam) {
selectedStream = dataProvider.getItemAt(view.streamList.selectedIndex);
}
(view as SkinnablePopUpContainer).close(true, selectedStream);
}
private function addUserStreamNames(u:User):void {
var existingStreamNames:Array = getUserStreamNamesByUserID(u.userID);
var streamNames:Array = u.streamName.split("|");
for each (var streamName:String in streamNames) {
var addNew:Boolean = true;
for each (var existingUserStreamName:UserStreamName in existingStreamNames) {
if (streamName == existingUserStreamName.streamName) {
addNew = false;
}
}
if (addNew) {
var userStreamName:UserStreamName = new UserStreamName(streamName, u);
dataProvider.addItem(userStreamName);
if (streamName == userUISession.currentStreamName) {
selectedIndex = dataProvider.getItemIndex(userStreamName);
}
}
}
dataProvider.refresh();
}
private function onSelectStream(event:MouseEvent):void {
if (view.streamList.selectedIndex != selectedIndex) {
indexChange = true;
}
selectedIndex = view.streamList.selectedIndex;
updateSelectedIndex();
}
override public function destroy():void {
userSession.userList.userRemovedSignal.remove(userRemovedHandler);
userSession.userList.userAddedSignal.remove(userAddedHandler);
userSession.userList.userChangeSignal.remove(userChangeHandler);
view.streamList.removeEventListener(MouseEvent.CLICK, onSelectStream);
view.actionButton.removeEventListener(MouseEvent.CLICK, clickedActionButton);
view.removeEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, closePopUp);
view.dispose();
view = null;
super.destroy();
}
private function userAddedHandler(user:User):void {
if (user.streamName && user.streamName != "") {
var streamNames:Array = user.streamName.split("|");
for each (var streamName:String in streamNames) {
var userStreamName:UserStreamName = new UserStreamName(streamName, user);
dataProvider.addItem(userStreamName);
}
}
}
private function removeUserFromDataProvider(userID:String):void {
for (var item:int; item < dataProvider.length; item++) {
if ((dataProvider.getItemAt(item).user as User).userID == userID) {
// -- in the end. see: http://stackoverflow.com/questions/4255226/how-to-remove-an-item-while-iterating-over-collection
dataProvider.removeItemAt(item--);
}
}
}
private function userRemovedHandler(userID:String):void {
removeUserFromDataProvider(userID);
}
private function getUserStreamNamesByUserID(userID:String):Array {
var userStreamNames:Array = new Array();
for each (var userStreamName:UserStreamName in dataProvider) {
if (userStreamName.user.userID == userID) {
userStreamNames.push(userStreamName);
}
}
return userStreamNames;
}
private function userChangeHandler(user:User, property:int):void {
if (property == UserList.HAS_STREAM) {
var userStreamNames:Array = getUserStreamNamesByUserID(user.userID);
for each (var userStreamName:UserStreamName in userStreamNames) {
if (!(userStreamName.user.streamName.indexOf(userStreamName.streamName) >= 0)) {
dataProvider.removeItemAt(dataProvider.getItemIndex(userStreamName));
}
}
if (user.streamName.split("|").length > userStreamNames.length && user.streamName.length > 0) {
var camNumber:int = dataProvider.length;
addUserStreamNames(user);
}
dataProvider.refresh();
}
}
private function getDisplayedUser():User {
for each (var userStreamName:UserStreamName in dataProvider) {
if (userStreamName.streamName == userUISession.currentStreamName) {
return userStreamName.user;
}
}
return null;
}
}
}
package org.bigbluebutton.air.presentation.views.selectwebcam {
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.events.FlexMouseEvent;
import mx.resources.ResourceManager;
import spark.components.SkinnablePopUpContainer;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.user.models.User2x;
import org.bigbluebutton.lib.user.models.UserList;
import org.bigbluebutton.lib.video.models.UserStreamName;
import robotlegs.bender.bundles.mvcs.Mediator;
public class SelectStreamPopUpMediator extends Mediator {
[Inject]
public var view:ISelectStreamPopUp;
[Inject]
public var userSession:IUserSession;
[Inject]
public var userUISession:IUISession;
protected var dataProvider:ArrayCollection;
private var speaker:User = null;
private var selectedIndex:int = -1;
private var indexChange:Boolean = false;
private var displayWebcam:Boolean;
override public function initialize():void {
userSession.userList.userRemovedSignal.add(userRemovedHandler);
userSession.userList.userAddedSignal.add(userAddedHandler);
userSession.userList.userChangeSignal.add(userChangeHandler);
view.streamList.addEventListener(MouseEvent.CLICK, onSelectStream);
view.actionButton.addEventListener(MouseEvent.CLICK, clickedActionButton);
dataProvider = new ArrayCollection();
view.streamList.dataProvider = dataProvider;
var users:ArrayCollection = userSession.userList.users;
for each (var u:User in users) {
if (u.streamName && u.streamName != "" && !dataProvider.contains(u)) {
addUserStreamNames(u);
}
}
updateSelectedIndex();
view.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, closePopUp);
}
private function closePopUp(e:FlexMouseEvent):void {
view.close(false);
}
/**
*
*/
private function updateSelectedIndex():void {
view.streamList.selectedIndex = selectedIndex;
if (selectedIndex == -1) {
view.actionButton.enabled = false;
view.actionButton.skin.setCurrentState("disabled");
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.viewWebcam');
} else {
view.actionButton.enabled = true
view.actionButton.skin.setCurrentState("up");
if (userUISession.currentStreamName == "" || indexChange) {
displayWebcam = true;
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.viewWebcam');
} else {
displayWebcam = false;
view.actionButton.label = ResourceManager.getInstance().getString('resources', 'selectStream.hideWebcam');
}
}
}
private function clickedActionButton(e:MouseEvent):void {
var selectedStream:Object = null;
if (displayWebcam) {
selectedStream = dataProvider.getItemAt(view.streamList.selectedIndex);
}
(view as SkinnablePopUpContainer).close(true, selectedStream);
}
private function addUserStreamNames(u:User):void {
var existingStreamNames:Array = getUserStreamNamesByUserID(u.userID);
var streamNames:Array = u.streamName.split("|");
for each (var streamName:String in streamNames) {
var addNew:Boolean = true;
for each (var existingUserStreamName:UserStreamName in existingStreamNames) {
if (streamName == existingUserStreamName.streamName) {
addNew = false;
}
}
if (addNew) {
var userStreamName:UserStreamName = new UserStreamName(streamName, u);
dataProvider.addItem(userStreamName);
if (streamName == userUISession.currentStreamName) {
selectedIndex = dataProvider.getItemIndex(userStreamName);
}
}
}
dataProvider.refresh();
}
private function onSelectStream(event:MouseEvent):void {
if (view.streamList.selectedIndex != selectedIndex) {
indexChange = true;
}
selectedIndex = view.streamList.selectedIndex;
updateSelectedIndex();
}
override public function destroy():void {
userSession.userList.userRemovedSignal.remove(userRemovedHandler);
userSession.userList.userAddedSignal.remove(userAddedHandler);
userSession.userList.userChangeSignal.remove(userChangeHandler);
view.streamList.removeEventListener(MouseEvent.CLICK, onSelectStream);
view.actionButton.removeEventListener(MouseEvent.CLICK, clickedActionButton);
view.removeEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, closePopUp);
view.dispose();
view = null;
super.destroy();
}
private function userAddedHandler(user:User):void {
if (user.streamName && user.streamName != "") {
var streamNames:Array = user.streamName.split("|");
for each (var streamName:String in streamNames) {
var userStreamName:UserStreamName = new UserStreamName(streamName, user);
dataProvider.addItem(userStreamName);
}
}
}
private function removeUserFromDataProvider(userID:String):void {
for (var item:int; item < dataProvider.length; item++) {
if ((dataProvider.getItemAt(item).user as User).userID == userID) {
// -- in the end. see: http://stackoverflow.com/questions/4255226/how-to-remove-an-item-while-iterating-over-collection
dataProvider.removeItemAt(item--);
}
}
}
private function userRemovedHandler(userID:String):void {
removeUserFromDataProvider(userID);
}
private function getUserStreamNamesByUserID(userID:String):Array {
var userStreamNames:Array = new Array();
for each (var userStreamName:UserStreamName in dataProvider) {
if (userStreamName.user.userID == userID) {
userStreamNames.push(userStreamName);
}
}
return userStreamNames;
}
private function userChangeHandler(user:User2x, property:int):void {
if (property == UserList.HAS_STREAM) {
var userStreamNames:Array = getUserStreamNamesByUserID(user.userID);
for each (var userStreamName:UserStreamName in userStreamNames) {
if (!(userStreamName.user.streamName.indexOf(userStreamName.streamName) >= 0)) {
dataProvider.removeItemAt(dataProvider.getItemIndex(userStreamName));
}
}
if (user.streamName.split("|").length > userStreamNames.length && user.streamName.length > 0) {
var camNumber:int = dataProvider.length;
addUserStreamNames(user);
}
dataProvider.refresh();
}
}
private function getDisplayedUser():User {
for each (var userStreamName:UserStreamName in dataProvider) {
if (userStreamName.streamName == userUISession.currentStreamName) {
return userStreamName.user;
}
}
return null;
}
}
}

View File

@ -1,59 +1,59 @@
package org.bigbluebutton.air.settings {
import org.bigbluebutton.air.settings.views.SettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.audio.AudioSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.audio.AudioSettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.camera.CameraSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.camera.CameraSettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.chat.ChatSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.lock.LockSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.lock.LockSettingsViewMediatorAIR;
import org.bigbluebutton.lib.main.commands.SaveLockSettingsCommand;
import org.bigbluebutton.lib.main.commands.SaveLockSettingsSignal;
import org.bigbluebutton.lib.settings.views.SettingsViewBase;
import org.bigbluebutton.lib.settings.views.audio.AudioSettingsViewBase;
import org.bigbluebutton.lib.settings.views.camera.CameraSettingsViewBase;
import org.bigbluebutton.lib.settings.views.chat.ChatSettingsViewBase;
import org.bigbluebutton.lib.settings.views.chat.ChatSettingsViewMediatorBase;
import org.bigbluebutton.lib.settings.views.lock.LockSettingsViewBase;
import org.bigbluebutton.lib.video.commands.CameraQualityCommand;
import org.bigbluebutton.lib.video.commands.CameraQualitySignal;
import robotlegs.bender.extensions.matching.TypeMatcher;
import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
import robotlegs.bender.framework.api.IConfig;
public class SettingsConfig implements IConfig {
[Inject]
public var mediatorMap:IMediatorMap;
[Inject]
public var signalCommandMap:ISignalCommandMap;
public function configure():void {
mediators();
signals();
}
/**
* Maps view mediators to views.
*/
private function mediators():void {
mediatorMap.map(SettingsViewBase).toMediator(SettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(AudioSettingsViewBase, AudioSettingsViewBaseAIR)).toMediator(AudioSettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(CameraSettingsViewBase, CameraSettingsViewBaseAIR)).toMediator(CameraSettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(ChatSettingsViewBase, ChatSettingsViewBaseAIR)).toMediator(ChatSettingsViewMediatorBase);
mediatorMap.mapMatcher(new TypeMatcher().allOf(LockSettingsViewBase, LockSettingsViewBaseAIR)).toMediator(LockSettingsViewMediatorAIR);
}
/**
* Maps signals to commands using the signalCommandMap.
*/
private function signals():void {
signalCommandMap.map(SaveLockSettingsSignal).toCommand(SaveLockSettingsCommand);
signalCommandMap.map(CameraQualitySignal).toCommand(CameraQualityCommand);
}
}
}
package org.bigbluebutton.air.settings {
import org.bigbluebutton.air.settings.views.SettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.audio.AudioSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.audio.AudioSettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.camera.CameraSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.camera.CameraSettingsViewMediatorAIR;
import org.bigbluebutton.air.settings.views.chat.ChatSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.lock.LockSettingsViewBaseAIR;
import org.bigbluebutton.air.settings.views.lock.LockSettingsViewMediatorAIR;
import org.bigbluebutton.lib.main.commands.SaveLockSettingsCommand;
import org.bigbluebutton.lib.main.commands.SaveLockSettingsSignal;
import org.bigbluebutton.lib.settings.views.SettingsViewBase;
import org.bigbluebutton.lib.settings.views.audio.AudioSettingsViewBase;
import org.bigbluebutton.lib.settings.views.camera.CameraSettingsViewBase;
import org.bigbluebutton.lib.settings.views.chat.ChatSettingsViewBase;
import org.bigbluebutton.lib.settings.views.chat.ChatSettingsViewMediatorBase;
import org.bigbluebutton.lib.settings.views.lock.LockSettingsViewBase;
import org.bigbluebutton.lib.video.commands.CameraQualityCommand;
import org.bigbluebutton.lib.video.commands.CameraQualitySignal;
import robotlegs.bender.extensions.matching.TypeMatcher;
import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
import robotlegs.bender.framework.api.IConfig;
public class SettingsConfig implements IConfig {
[Inject]
public var mediatorMap:IMediatorMap;
[Inject]
public var signalCommandMap:ISignalCommandMap;
public function configure():void {
mediators();
signals();
}
/**
* Maps view mediators to views.
*/
private function mediators():void {
mediatorMap.map(SettingsViewBase).toMediator(SettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(AudioSettingsViewBase, AudioSettingsViewBaseAIR)).toMediator(AudioSettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(CameraSettingsViewBase, CameraSettingsViewBaseAIR)).toMediator(CameraSettingsViewMediatorAIR);
mediatorMap.mapMatcher(new TypeMatcher().allOf(ChatSettingsViewBase, ChatSettingsViewBaseAIR)).toMediator(ChatSettingsViewMediatorBase);
mediatorMap.mapMatcher(new TypeMatcher().allOf(LockSettingsViewBase, LockSettingsViewBaseAIR)).toMediator(LockSettingsViewMediatorAIR);
}
/**
* Maps signals to commands using the signalCommandMap.
*/
private function signals():void {
signalCommandMap.map(SaveLockSettingsSignal).toCommand(SaveLockSettingsCommand);
signalCommandMap.map(CameraQualitySignal).toCommand(CameraQualityCommand);
}
}
}

View File

@ -2,8 +2,6 @@ package org.bigbluebutton.air.users.views {
import flash.events.MouseEvent;
import org.bigbluebutton.air.common.PageEnum;
import org.bigbluebutton.air.common.TransitionAnimationEnum;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.air.users.views.models.UserDetailsVM;
import org.bigbluebutton.lib.chat.commands.StartPrivateChatSignal;

View File

@ -1,38 +1,50 @@
package org.bigbluebutton.air.voice {
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneCommand;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
import robotlegs.bender.framework.api.IConfig;
public class VoiceConfig implements IConfig {
[Inject]
public var mediatorMap:IMediatorMap;
[Inject]
public var signalCommandMap:ISignalCommandMap;
public function configure():void {
mediators();
signals();
}
/**
* Maps view mediators to views.
*/
private function mediators():void {
//mediatorMap.map(IMicButton).toMediator(MicButtonMediator);
}
/**
* Maps signals to commands using the signalCommandMap.
*/
private function signals():void {
signalCommandMap.map(ShareMicrophoneSignal).toCommand(ShareMicrophoneCommand);
//signalCommandMap.map(MicrophoneMuteSignal).toCommand(MicrophoneMuteCommand);
}
}
}
package org.bigbluebutton.air.voice {
import org.bigbluebutton.air.voice.views.EchoTestViewMediatorAIR;
import org.bigbluebutton.lib.voice.commands.MicrophoneMuteCommand;
import org.bigbluebutton.lib.voice.commands.MicrophoneMuteSignal;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneCommand;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import org.bigbluebutton.lib.voice.commands.StartEchoTestCommand;
import org.bigbluebutton.lib.voice.commands.StartEchoTestSignal;
import org.bigbluebutton.lib.voice.commands.StopEchoTestCommand;
import org.bigbluebutton.lib.voice.commands.StopEchoTestSignal;
import org.bigbluebutton.lib.voice.views.EchoTestViewBase;
import robotlegs.bender.extensions.matching.TypeMatcher;
import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
import robotlegs.bender.framework.api.IConfig;
public class VoiceConfig implements IConfig {
[Inject]
public var mediatorMap:IMediatorMap;
[Inject]
public var signalCommandMap:ISignalCommandMap;
public function configure():void {
mediators();
signals();
}
/**
* Maps view mediators to views.
*/
private function mediators():void {
//mediatorMap.map(IMicButton).toMediator(MicButtonMediator);
mediatorMap.mapMatcher(new TypeMatcher().allOf(EchoTestViewBase)).toMediator(EchoTestViewMediatorAIR);
}
/**
* Maps signals to commands using the signalCommandMap.
*/
private function signals():void {
signalCommandMap.map(ShareMicrophoneSignal).toCommand(ShareMicrophoneCommand);
signalCommandMap.map(StartEchoTestSignal).toCommand(StartEchoTestCommand);
signalCommandMap.map(StopEchoTestSignal).toCommand(StopEchoTestCommand);
signalCommandMap.map(MicrophoneMuteSignal).toCommand(MicrophoneMuteCommand);
}
}
}

View File

@ -0,0 +1,30 @@
package org.bigbluebutton.air.voice.views {
import spark.layouts.VerticalLayout;
import org.bigbluebutton.air.common.views.NoTabView;
import org.bigbluebutton.air.main.views.TopToolbarAIR;
import org.bigbluebutton.lib.voice.views.EchoTestViewBase;
import org.osmf.layout.HorizontalAlign;
public class EchoTestView extends NoTabView {
private var _echoTestView:EchoTestViewBase;
public function EchoTestView() {
super();
var vLayout:VerticalLayout = new VerticalLayout();
vLayout.gap = 0;
vLayout.horizontalAlign = HorizontalAlign.CENTER;
layout = vLayout;
_echoTestView = new EchoTestViewBase();
addElement(_echoTestView);
}
override protected function createToolbar():TopToolbarAIR {
return new TopToolbarEchoTest();
}
}
}

View File

@ -0,0 +1,22 @@
package org.bigbluebutton.air.voice.views {
import flash.events.MouseEvent;
import org.bigbluebutton.air.main.models.IUISession;
import org.bigbluebutton.lib.voice.views.EchoTestViewMediator;
public class EchoTestViewMediatorAIR extends EchoTestViewMediator {
[Inject]
public var uiSession:IUISession;
public function EchoTestViewMediatorAIR() {
super();
}
override protected function yesButtonHandler(e:MouseEvent):void {
super.yesButtonHandler(e);
uiSession.popPage();
}
}
}

View File

@ -0,0 +1,10 @@
package org.bigbluebutton.air.voice.views {
import org.bigbluebutton.air.main.views.TopToolbarAIR;
public class TopToolbarEchoTest extends TopToolbarAIR {
public function TopToolbarEchoTest() {
leftButton.styleName = "icon-left-arrow topButton topLeftButton";
rightButton.setVisible(false);
}
}
}

View File

@ -6,7 +6,6 @@ package org.bigbluebutton.lib.chat.views {
import mx.utils.StringUtil;
import spark.components.VScrollBar;
import spark.core.NavigationUnit;
import org.bigbluebutton.lib.chat.models.ChatMessageVO;
import org.bigbluebutton.lib.chat.models.GroupChat;

View File

@ -20,7 +20,7 @@ package org.bigbluebutton.lib.main.commands {
import org.bigbluebutton.lib.voice.services.IVoiceConnection;
import org.bigbluebutton.lib.whiteboard.services.IWhiteboardService;
import robotlegs.bender.bundles.mvcs.Command;
import robotlegs.bender.bundles.mvcs.Command;
public class ConnectCommand extends Command {
private const LOG:String = "ConnectCommand::";

View File

@ -12,6 +12,7 @@ package org.bigbluebutton.lib.main.models {
*/
public class ConferenceParameters implements IConferenceParameters {
private var _changedSignal:Signal;
private var _confParamsLoadedSignal:Signal = new Signal();
private var _meetingName:String;
@ -84,6 +85,9 @@ package org.bigbluebutton.lib.main.models {
private var _guest:Boolean;
private var _bannerText:String;
private var _bannerColor:String;
public function ConferenceParameters(signal:Signal = null) {
if (signal) {
_changedSignal = signal;
@ -100,6 +104,10 @@ package org.bigbluebutton.lib.main.models {
return _changedSignal;
}
public function get confParamsLoadedSignal():ISignal {
return _confParamsLoadedSignal;
}
public function get meetingName():String {
return _meetingName;
}
@ -264,6 +272,9 @@ package org.bigbluebutton.lib.main.models {
_avatarUrl = obj.avatarURL;
_authToken = obj.authToken;
_guest = obj.guest;
_bannerColor = obj.bannerColor;
_bannerText = obj.bannerText;
_changedSignal.dispatch();
_metadata = new Object();
for (var n:String in obj.metadata) {
@ -280,6 +291,8 @@ package org.bigbluebutton.lib.main.models {
var value:Object = obj[key];
trace(key + " = " + value);
}
_confParamsLoadedSignal.dispatch();
}
public function set muteOnStart(mute:Boolean):void {
@ -305,5 +318,21 @@ package org.bigbluebutton.lib.main.models {
public function set guest(value:Boolean):void {
_guest = value;
}
public function get bannerColor():String {
return _bannerColor;
}
public function set bannerColor(value:String):void {
_bannerColor = value;
}
public function get bannerText():String {
return _bannerText;
}
public function set bannerText(value:String):void {
_bannerText = value;
}
}
}

View File

@ -6,6 +6,7 @@ package org.bigbluebutton.lib.main.models {
public interface IConferenceParameters {
function get changedSignal():ISignal;
function get confParamsLoadedSignal():ISignal;
function get meetingName():String;
function set meetingName(meetingName:String):void;
function get externMeetingID():String;
@ -46,5 +47,9 @@ package org.bigbluebutton.lib.main.models {
function set avatarUrl(value:String):void;
function get guest():Boolean;
function set guest(v:Boolean):void;
function get bannerColor():String;
function set bannerColor(value:String):void;
function get bannerText():String;
function set bannerText(value:String):void;
}
}

View File

@ -12,12 +12,12 @@ package org.bigbluebutton.lib.main.models {
//public var voiceUsers: VoiceUsers2x = new VoiceUsers2x();
//public var guestsWaiting: GuestsApp = new GuestsApp();
private var _meetingStatus: MeetingStatus = new MeetingStatus();
private var _meetingStatus:MeetingStatus = new MeetingStatus();
public function get meetingStatus():MeetingStatus {
return _meetingStatus;
}
//public var meeting: Meeting = new Meeting();
//public var config: Config;
//public var sharedNotes: SharedNotes = new SharedNotes();

View File

@ -97,7 +97,17 @@ package org.bigbluebutton.lib.main.services {
protected function afterEnter(result:Object):void {
if (result.returncode == 'SUCCESS') {
trace("Join SUCCESS");
var user:Object = {username: result.fullname, conference: result.conference, conferenceName: result.confname, externMeetingID: result.externMeetingID, meetingID: result.meetingID, externUserID: result.externUserID, internalUserId: result.internalUserID, role: result.role, room: result.room, authToken: result.authToken, record: result.record, webvoiceconf: result.webvoiceconf, dialnumber: result.dialnumber, voicebridge: result.voicebridge, mode: result.mode, welcome: result.welcome, logoutUrl: result.logoutUrl, defaultLayout: result.defaultLayout, avatarURL: result.avatarURL};
var user:Object = {username: result.fullname, conference: result.conference,
conferenceName: result.confname, externMeetingID: result.externMeetingID,
meetingID: result.meetingID, externUserID: result.externUserID,
internalUserId: result.internalUserID, role: result.role, room: result.room,
authToken: result.authToken, record: result.record, webvoiceconf: result.webvoiceconf,
dialnumber: result.dialnumber, voicebridge: result.voicebridge,
mode: result.mode, welcome: result.welcome, logoutUrl: result.logoutUrl,
defaultLayout: result.defaultLayout, avatarURL: result.avatarURL,
bannerColor: result.bannerColor,
bannerText: result.bannerText};
user.customdata = new Object();
if (result.customdata) {
for (var key:String in result.customdata) {

View File

@ -6,7 +6,14 @@ package org.bigbluebutton.lib.main.views {
[Style(name = "bottom", inherit = "no", type = "Number")]
[Style(name = "gap", inherit = "no", type = "Number")]
[Style(name = "top", inherit = "no", type = "Number")]
public class MenuButtonsBase extends HGroup {
private var _audioButton:Button;
public function get audioButton():Button {
return _audioButton;
}
private var _micButton:Button;
public function get micButton():Button {
@ -28,6 +35,12 @@ package org.bigbluebutton.lib.main.views {
public function MenuButtonsBase() {
super();
_audioButton = new Button();
_audioButton.percentWidth = 100;
_audioButton.percentHeight = 100;
_audioButton.label = "Join";
_audioButton.styleName = "icon-audio-on menuButton";
addElement(_audioButton);
_micButton = new Button();
_micButton.percentWidth = 100;

View File

@ -1,90 +1,119 @@
package org.bigbluebutton.lib.main.views {
import flash.events.MouseEvent;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.video.commands.ShareCameraSignal;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import robotlegs.bender.bundles.mvcs.Mediator;
public class MenuButtonsMediatorBase extends Mediator {
[Inject]
public var userSession:IUserSession;
[Inject]
public var view:MenuButtonsBase;
[Inject]
public var shareCameraSignal:ShareCameraSignal;
[Inject]
public var shareMicrophoneSignal:ShareMicrophoneSignal;
public override function initialize():void {
userSession.userList.userChangeSignal.add(userChanged);
view.camButton.addEventListener(MouseEvent.CLICK, camOnOff);
view.micButton.addEventListener(MouseEvent.CLICK, micOnOff);
view.statusButton.addEventListener(MouseEvent.CLICK, changeStatus);
}
private function changeStatus(e:MouseEvent):void {
/*var changeStatusPopUp:ChangeStatusPopUp = new ChangeStatusPopUp();
mediatorMap.mediate(changeStatusPopUp);
changeStatusPopUp.width = view.width;
changeStatusPopUp.height = view.height;
changeStatusPopUp.open(view as DisplayObjectContainer, true);
if (FlexGlobals.topLevelApplication.aspectRatio == "landscape") {
changeStatusPopUp.x = view.x + view.statusButton.x;
changeStatusPopUp.y = view.y - changeStatusPopUp.height * 2;
} else {
changeStatusPopUp.x = -(view.width - view.statusButton.x - view.statusButton.width) / 2 - (view.statusButton.width - (view.statusButton.skin as PresentationButtonSkin).backgroundEllipse.width) / 2 + 6;
changeStatusPopUp.y = view.y - changeStatusPopUp.height * changeStatusPopUp.statusList.dataProvider.length;
}
*/
}
private function micOnOff(e:MouseEvent):void {
var audioOptions:Object = new Object();
audioOptions.shareMic = !userSession.userList.me.voiceJoined;
audioOptions.listenOnly = false;
shareMicrophoneSignal.dispatch(audioOptions);
}
private function camOnOff(e:MouseEvent):void {
shareCameraSignal.dispatch(!userSession.userList.me.hasStream, userSession.videoConnection.cameraPosition);
}
private function userChanged(user:User, property:String = null):void {
if (user && user.me) {
if (user.hasStream) {
view.camButton.label = "Cam off";// ResourceManager.getInstance().getString('resources', 'menuButtons.camOff');
view.camButton.styleName = "icon-video-off menuButton"
} else {
view.camButton.label = "Cam on";// ResourceManager.getInstance().getString('resources', 'menuButtons.camOn');
view.camButton.styleName = "icon-video menuButton"
}
if (userSession.userList.me.voiceJoined) {
view.micButton.label = "Mic off";// ResourceManager.getInstance().getString('resources', 'menuButtons.micOff');
view.micButton.styleName = "icon-mute menuButton"
} else {
view.micButton.label = "Mic on";// ResourceManager.getInstance().getString('resources', 'menuButtons.micOn');
view.micButton.styleName = "icon-unmute menuButton"
}
}
}
public override function destroy():void {
userSession.userList.userChangeSignal.remove(userChanged);
view.camButton.removeEventListener(MouseEvent.CLICK, camOnOff);
view.micButton.removeEventListener(MouseEvent.CLICK, micOnOff);
view.statusButton.removeEventListener(MouseEvent.CLICK, changeStatus);
super.destroy();
view = null;
}
}
}
package org.bigbluebutton.lib.main.views {
import flash.events.MouseEvent;
import org.bigbluebutton.lib.main.models.IMeetingData;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.User2x;
import org.bigbluebutton.lib.video.commands.ShareCameraSignal;
import org.bigbluebutton.lib.voice.commands.MicrophoneMuteSignal;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import robotlegs.bender.bundles.mvcs.Mediator;
public class MenuButtonsMediatorBase extends Mediator {
[Inject]
public var userSession:IUserSession;
[Inject]
public var view:MenuButtonsBase;
[Inject]
public var microphoneMuteSignal:MicrophoneMuteSignal;
[Inject]
public var shareCameraSignal:ShareCameraSignal;
[Inject]
public var shareMicrophoneSignal:ShareMicrophoneSignal;
[Inject]
public var meetingData:IMeetingData;
public override function initialize():void {
meetingData.users.userChangeSignal.add(userChanged);
view.audioButton.addEventListener(MouseEvent.CLICK, audioOnOff);
view.camButton.addEventListener(MouseEvent.CLICK, camOnOff);
view.micButton.addEventListener(MouseEvent.CLICK, micOnOff);
view.statusButton.addEventListener(MouseEvent.CLICK, changeStatus);
updateButtons();
}
private function changeStatus(e:MouseEvent):void {
/*var changeStatusPopUp:ChangeStatusPopUp = new ChangeStatusPopUp();
mediatorMap.mediate(changeStatusPopUp);
changeStatusPopUp.width = view.width;
changeStatusPopUp.height = view.height;
changeStatusPopUp.open(view as DisplayObjectContainer, true);
if (FlexGlobals.topLevelApplication.aspectRatio == "landscape") {
changeStatusPopUp.x = view.x + view.statusButton.x;
changeStatusPopUp.y = view.y - changeStatusPopUp.height * 2;
} else {
changeStatusPopUp.x = -(view.width - view.statusButton.x - view.statusButton.width) / 2 - (view.statusButton.width - (view.statusButton.skin as PresentationButtonSkin).backgroundEllipse.width) / 2 + 6;
changeStatusPopUp.y = view.y - changeStatusPopUp.height * changeStatusPopUp.statusList.dataProvider.length;
}
*/
}
protected function micOnOff(e:MouseEvent):void {
microphoneMuteSignal.dispatch(meetingData.users.me);
}
protected function audioOnOff(e:MouseEvent):void {
}
private function camOnOff(e:MouseEvent):void {
shareCameraSignal.dispatch(!meetingData.users.me.hasStream, userSession.videoConnection.cameraPosition);
}
private function updateButtons():void {
if (!meetingData.users.me) {
return;
}
if (meetingData.users.me.hasStream) {
view.camButton.label = "Cam off"; // ResourceManager.getInstance().getString('resources', 'menuButtons.camOff');
view.camButton.styleName = "icon-video-off menuButton"
} else {
view.camButton.label = "Cam on"; // ResourceManager.getInstance().getString('resources', 'menuButtons.camOn');
view.camButton.styleName = "icon-video menuButton"
}
if (meetingData.users.me.voiceJoined) {
view.micButton.visible = view.micButton.includeInLayout = true;
view.audioButton.styleName = "icon-audio-off menuButtonRed";
view.audioButton.label = "Hang Up";
if (!meetingData.users.me.muted) {
view.micButton.label = "Mic on"; // ResourceManager.getInstance().getString('resources', 'menuButtons.micOn');
view.micButton.styleName = "icon-unmute menuButton"
} else {
view.micButton.label = "Mic off"; // ResourceManager.getInstance().getString('resources', 'menuButtons.micOff');
view.micButton.styleName = "icon-mute menuButton"
}
} else {
view.audioButton.label = "Join";
view.audioButton.styleName = "icon-audio-on menuButton";
view.micButton.visible = view.micButton.includeInLayout = false;
}
}
private function userChanged(user:User2x, property:String = null):void {
if (user && meetingData.users.me.intId == user.intId) {
updateButtons();
}
}
public override function destroy():void {
meetingData.users.userChangeSignal.remove(userChanged);
view.audioButton.removeEventListener(MouseEvent.CLICK, audioOnOff);
view.camButton.removeEventListener(MouseEvent.CLICK, camOnOff);
view.micButton.removeEventListener(MouseEvent.CLICK, micOnOff);
view.statusButton.removeEventListener(MouseEvent.CLICK, changeStatus);
super.destroy();
view = null;
}
}
}

View File

@ -107,6 +107,9 @@ package org.bigbluebutton.lib.settings.views.audio {
_gainSlider = new HSlider();
_gainSlider.percentWidth = 100;
_gainSlider.maximum = 100;
_gainSlider.snapInterval = 1;
_gainSlider.value = 60;
gainSliderGroup.addElement(_gainSlider);
var fullMicGroup:VGroup = new VGroup();

View File

@ -1,16 +1,32 @@
package org.bigbluebutton.lib.user.models {
public class User2x {
public var intId: String;
public var extId: String;
public var name: String;
public var role: String;
public var guest: Boolean;
public var authed: Boolean;
public var waitingForAcceptance: Boolean;
public var emoji: String;
public var locked: Boolean;
public var presenter: Boolean;
public var avatar: String;
public var intId:String;
public var extId:String;
public var name:String;
public var role:String;
public var guest:Boolean;
public var authed:Boolean;
public var waitingForAcceptance:Boolean;
public var emoji:String;
public var locked:Boolean;
public var presenter:Boolean;
public var avatar:String;
public var voiceJoined:Boolean;
public var muted:Boolean;
public var hasStream:Boolean = false;
}
}

View File

@ -12,5 +12,9 @@ package org.bigbluebutton.lib.user.models {
public static const EMOJI:int = 4;
public static const ROLE:int = 5;
public static const AUDIO_JOIN:int = 6;
public static const AUDIO_LEAVE:int = 7;
}
}

View File

@ -26,6 +26,8 @@ package org.bigbluebutton.lib.user.models {
public static const LISTEN_ONLY:int = 8;
public static const LEAVE_AUDIO:int = 9;
private var _users:ArrayCollection;
[Bindable]
@ -325,7 +327,7 @@ package org.bigbluebutton.lib.user.models {
if (user != null) {
user.talking = false;
user.voiceJoined = false;
userChangeSignal.dispatch(user, JOIN_AUDIO);
userChangeSignal.dispatch(user, LEAVE_AUDIO);
} else {
trace("UserList: User leave audio failed - user not found");
}

View File

@ -1,6 +1,7 @@
package org.bigbluebutton.lib.user.models {
import mx.collections.ArrayCollection;
import org.as3commons.lang.StringUtils;
import org.osflash.signals.Signal;
public class Users2x {
@ -8,7 +9,17 @@ package org.bigbluebutton.lib.user.models {
private var _userChangeSignal:Signal = new Signal();
public var me:User2x;
private var _me:User2x;
public function get me():User2x {
return _me;
}
public function set me(value:User2x):void {
if (StringUtils.isEmpty(_me.extId)) {
_me = value;
}
}
public function get userChangeSignal():Signal {
return _userChangeSignal;
@ -16,6 +27,7 @@ package org.bigbluebutton.lib.user.models {
public function Users2x() {
_users = new ArrayCollection();
_me = new User2x();
}
public function getUsers():Array {
@ -78,6 +90,24 @@ package org.bigbluebutton.lib.user.models {
return null;
}
public function joinAudioConference(intId:String, muted:Boolean):void {
var user:User2x = getUser(intId);
if (user) {
user.muted = muted;
user.voiceJoined = true;
_userChangeSignal.dispatch(user, UserChangeEnum.AUDIO_JOIN);
}
}
public function leaveAudioConference(intId:String):void {
var user:User2x = getUser(intId);
if (user) {
user.muted = false;
user.voiceJoined = false;
_userChangeSignal.dispatch(user, UserChangeEnum.AUDIO_LEAVE);
}
}
public function changeUserLocked(intId:String, locked:Boolean):void {
var user:User2x = getUser(intId);
if (user != null) {

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.lib.user.services {
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.user.models.User2x;
public interface IUsersService {
function setupMessageSenderReceiver():void;
@ -25,8 +25,8 @@ package org.bigbluebutton.lib.user.services {
function saveLockSettings(newLockSettings:Object):void;
function muteMe():void;
function unmuteMe():void;
function mute(user:User):void;
function unmute(user:User):void;
function mute(user:User2x):void;
function unmute(user:User2x):void;
function validateToken():void;
function joinMeeting():void;
}

View File

@ -8,7 +8,7 @@ package org.bigbluebutton.lib.user.services {
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.main.models.LockSettings2x;
import org.bigbluebutton.lib.main.utils.DisconnectEnum;
import org.bigbluebutton.lib.user.models.User2x;
import org.bigbluebutton.lib.user.models.User2x;
public class UsersMessageReceiver implements IMessageListener {
private const LOG:String = "UsersMessageReceiver::";
@ -29,12 +29,6 @@ package org.bigbluebutton.lib.user.services {
case "voiceUserTalking":
handleVoiceUserTalking(message);
break;
case "userJoinedVoice":
handleUserJoinedVoice(message);
break;
case "userLeftVoice":
handleUserLeftVoice(message);
break;
case "userSharedWebcam":
handleUserSharedWebcam(message);
break;
@ -71,9 +65,12 @@ package org.bigbluebutton.lib.user.services {
handleMeetingMuted(message);
break;
case "UserJoinedVoiceConfToClientEvtMsg":
handleUserJoinedVoiceConfToClientEvtMsg(message);
break;
case "UserLeftVoiceConfToClientEvtMsg":
handleUserLeftVoiceConfToClientEvtMsg(message);
break;
case "GetUsersMeetingRespMsg":
handleGetUsersMeetingRespMsg(message);
@ -135,16 +132,7 @@ package org.bigbluebutton.lib.user.services {
}
private function handleUserJoinedVoice(m:Object):void {
var msg:Object = JSON.parse(m.msg);
var voiceUser:Object = msg.user.voiceUser;
trace(LOG + "handleUserJoinedVoice() -- user [" + msg.user.userId + "] has joined voice with voiceId [" + voiceUser.userId + "]");
userSession.userList.userJoinAudio(msg.user.userId, voiceUser.userId, voiceUser.muted, voiceUser.talking, voiceUser.locked);
}
private function handleUserLeftVoice(m:Object):void {
var msg:Object = JSON.parse(m.msg);
trace(LOG + "handleUserLeftVoice() -- user [" + msg.user.userId + "] has left voice");
userSession.userList.userLeaveAudio(msg.user.userId);
}
private function handleUserSharedWebcam(m:Object):void {
@ -196,19 +184,24 @@ package org.bigbluebutton.lib.user.services {
userSession.recordingStatusChanged(msg.recording);
}
private function handleUserJoinedVoiceConfToClientEvtMsg(msg:Object):void {
var user:Object = msg.body as Object;
// @todo : update lock value
userSession.userList.userJoinAudio(user.intId, user.voiceUserId, user.muted, user.talking, false);
// @fixme : to be used later
meetingData.users.joinAudioConference(user.intId, user.muted);
}
private function handleUserLeftVoiceConfToClientEvtMsg(msg:Object):void {
trace(LOG + "handleUserLeftVoiceConfToClientEvtMsg() -- user [" + msg.body.intId + "] has left the voice conference");
userSession.userList.userLeaveAudio(msg.body.intId);
// @fixme : to be used later
meetingData.users.leaveAudioConference(msg.body.intId);
}
private function handleGetUsersMeetingRespMsg(msg:Object):void {
var users:Array = msg.body.users as Array;
@ -246,7 +239,7 @@ package org.bigbluebutton.lib.user.services {
private function handleUserLeftMeetingEvtMsg(msg:Object):void {
trace(LOG + "handleUserLeftMeetingEvtMsg() -- user [" + msg.body.intId + "] has left the meeting");
meetingData.users.remove(msg.intId);
}
}
private function handleUserLockedInMeetingEvtMsg(msg:Object):void {
trace(LOG + "handleUserLockedInMeetingEvtMsg: " + ObjectUtil.toString(msg));
@ -293,6 +286,7 @@ package org.bigbluebutton.lib.user.services {
private function handleValidateAuthTokenRespMsg(msg:Object):void {
var tokenValid:Boolean = msg.body.valid as Boolean;
trace(LOG + "handleValidateAuthTokenReply() valid=" + tokenValid);
meetingData.users.me.intId = msg.body.userId;
userSession.userId = msg.body.userId;
userSession.authTokenSignal.dispatch(tokenValid);
}

View File

@ -5,7 +5,7 @@ package org.bigbluebutton.lib.user.services {
import org.bigbluebutton.lib.main.models.IMeetingData;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.user.models.EmojiStatus;
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.user.models.User2x;
public class UsersService implements IUsersService {
@ -42,24 +42,24 @@ package org.bigbluebutton.lib.user.services {
}
public function muteMe():void {
mute(userSession.userList.me);
mute(meetingData.users.me);
}
public function unmuteMe():void {
unmute(userSession.userList.me);
unmute(meetingData.users.me);
}
public function mute(user:User):void {
public function mute(user:User2x):void {
muteUnmute(user, true);
}
public function unmute(user:User):void {
public function unmute(user:User2x):void {
muteUnmute(user, false);
}
private function muteUnmute(user:User, mute:Boolean):void {
private function muteUnmute(user:User2x, mute:Boolean):void {
if (user.voiceJoined) {
usersMessageSender.muteUnmuteUser(user.userId, mute);
usersMessageSender.muteUnmuteUser(user.intId, mute);
}
}

View File

@ -1,27 +1,27 @@
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.user.models.User;
import org.bigbluebutton.lib.user.services.IUsersService;
import robotlegs.bender.bundles.mvcs.Command;
public class MicrophoneMuteCommand extends Command {
[Inject]
public var user:User;
[Inject]
public var userService:IUsersService;
override public function execute():void {
trace("MicrophoneMuteCommand.execute() - user.muted = " + user.muted);
if (user != null) {
if (user.muted) {
userService.unmute(user);
} else {
userService.mute(user);
}
}
}
}
}
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.user.models.User2x;
import org.bigbluebutton.lib.user.services.IUsersService;
import robotlegs.bender.bundles.mvcs.Command;
public class MicrophoneMuteCommand extends Command {
[Inject]
public var user:User2x;
[Inject]
public var userService:IUsersService;
override public function execute():void {
trace("MicrophoneMuteCommand.execute() - user.muted = " + user.muted);
if (user != null) {
if (user.muted) {
userService.unmute(user);
} else {
userService.mute(user);
}
}
}
}
}

View File

@ -1,14 +1,14 @@
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.user.models.User;
import org.osflash.signals.Signal;
public class MicrophoneMuteSignal extends Signal {
public function MicrophoneMuteSignal() {
/**
* @1 microphone enabled
*/
super(User);
}
}
}
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.user.models.User2x;
import org.osflash.signals.Signal;
public class MicrophoneMuteSignal extends Signal {
public function MicrophoneMuteSignal() {
/**
* @1 microphone enabled
*/
super(User2x);
}
}
}

View File

@ -0,0 +1,16 @@
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.main.models.IUserSession;
import robotlegs.bender.bundles.mvcs.Command;
public class StartEchoTestCommand extends Command {
private const LOG:String = "StartEchoTestCommand::";
[Inject]
public var userSession:IUserSession;
override public function execute():void {
userSession.voiceConnection.call(false, userSession.phoneOptions.echoTestApp);
}
}
}

View File

@ -0,0 +1,9 @@
package org.bigbluebutton.lib.voice.commands {
import org.osflash.signals.Signal;
public class StartEchoTestSignal extends Signal {
public function StartEchoTestSignal() {
super();
}
}
}

View File

@ -0,0 +1,16 @@
package org.bigbluebutton.lib.voice.commands {
import org.bigbluebutton.lib.main.models.IUserSession;
import robotlegs.bender.bundles.mvcs.Command;
public class StopEchoTestCommand extends Command {
private const LOG:String = "StopEchoTestCommand::";
[Inject]
public var userSession:IUserSession;
override public function execute():void {
userSession.voiceConnection.hangUp();
}
}
}

View File

@ -0,0 +1,9 @@
package org.bigbluebutton.lib.voice.commands {
import org.osflash.signals.Signal;
public class StopEchoTestSignal extends Signal {
public function StopEchoTestSignal() {
super();
}
}
}

View File

@ -1,24 +1,24 @@
package org.bigbluebutton.lib.voice.services {
import flash.net.NetConnection;
import org.bigbluebutton.lib.main.models.IConferenceParameters;
import org.osflash.signals.ISignal;
public interface IVoiceConnection {
function get connectionFailureSignal():ISignal
function get connectionSuccessSignal():ISignal
function set uri(uri:String):void
function get uri():String
function get connection():NetConnection
function get callActive():Boolean
function get hangUpSuccessSignal():ISignal;
function connect(confParams:IConferenceParameters, listenOnly:Boolean):void
function disconnect(onUserCommand:Boolean):void
function failedToJoinVoiceConferenceCallback(msg:String):*
function disconnectedFromJoinVoiceConferenceCallback(msg:String):*
function successfullyJoinedVoiceConferenceCallback(publishName:String, playName:String, codec:String):*
function call(listenOnly:Boolean = false):void
function hangUp():void
}
}
package org.bigbluebutton.lib.voice.services {
import flash.net.NetConnection;
import org.bigbluebutton.lib.main.models.IConferenceParameters;
import org.osflash.signals.ISignal;
public interface IVoiceConnection {
function get connectionFailureSignal():ISignal
function get connectionSuccessSignal():ISignal
function set uri(uri:String):void
function get uri():String
function get connection():NetConnection
function get callActive():Boolean
function get hangUpSuccessSignal():ISignal;
function connect(confParams:IConferenceParameters, listenOnly:Boolean):void
function disconnect(onUserCommand:Boolean):void
function failedToJoinVoiceConferenceCallback(msg:String):*
function disconnectedFromJoinVoiceConferenceCallback(msg:String):*
function successfullyJoinedVoiceConferenceCallback(publishName:String, playName:String, codec:String):*
function call(listenOnly:Boolean = false, dialStr:String = null):void
function hangUp():void
}
}

View File

@ -5,13 +5,14 @@ package org.bigbluebutton.lib.voice.services {
import mx.utils.ObjectUtil;
import org.as3commons.lang.StringUtils;
import org.bigbluebutton.lib.common.services.DefaultConnectionCallback;
import org.bigbluebutton.lib.common.services.IBaseConnection;
import org.bigbluebutton.lib.main.models.IConferenceParameters;
import org.bigbluebutton.lib.main.models.IUserSession;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import org.osflash.signals.ISignal;
import org.osflash.signals.Signal;
import org.osflash.signals.Signal;
public class VoiceConnection extends DefaultConnectionCallback implements IVoiceConnection {
public const LOG:String = "VoiceConnection::";
@ -67,7 +68,7 @@ package org.bigbluebutton.lib.voice.services {
private function onConnectionSuccess():void {
userSession.userList.me.listenOnly = _listenOnly;
call(_listenOnly);
// call(_listenOnly);
}
public function get connectionFailureSignal():ISignal {
@ -103,7 +104,7 @@ package org.bigbluebutton.lib.voice.services {
_conferenceParameters = confParams;
_listenOnly = listenOnly;
_username = encodeURIComponent(confParams.internalUserID + "-bbbID-" + confParams.username);
trace("Voice app connect");
trace("Voice app connect");
baseConnection.connect(_applicationURI, confParams.meetingID, confParams.externUserID, _username, confParams.authToken);
}
@ -137,10 +138,13 @@ package org.bigbluebutton.lib.voice.services {
// SIP Actions //
// //
//**********************************************//
public function call(listenOnly:Boolean = false):void {
public function call(listenOnly:Boolean = false, dialStr:String = null):void {
if (!callActive) {
trace(LOG + "call(): starting voice call");
baseConnection.connection.call("voiceconf.call", new Responder(onCallSuccess, onCallFailure), "default", _username, _conferenceParameters.webvoiceconf, listenOnly.toString());
if (StringUtils.isEmpty(dialStr)) {
dialStr = _conferenceParameters.webvoiceconf;
}
baseConnection.connection.call("voiceconf.call", new Responder(onCallSuccess, onCallFailure), "default", _username, dialStr, listenOnly.toString());
} else {
trace(LOG + "call(): voice call already active");
}

View File

@ -1,212 +1,232 @@
package org.bigbluebutton.lib.voice.services {
import flash.events.AsyncErrorEvent;
import flash.events.NetDataEvent;
import flash.events.NetStatusEvent;
import flash.events.StatusEvent;
import flash.events.TimerEvent;
import flash.media.Microphone;
import flash.media.MicrophoneEnhancedMode;
import flash.media.MicrophoneEnhancedOptions;
import flash.media.SoundCodec;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.Timer;
import mx.utils.ObjectUtil;
public class VoiceStreamManager {
protected var _incomingStream:NetStream = null;
protected var _outgoingStream:NetStream = null;
protected var _connection:NetConnection = null;
protected var _mic:Microphone = null;
protected var _defaultMicGain:Number = 50;
protected var _heartbeat:Timer = new Timer(2000);
public function setDefaultMicGain(value:Number):void {
_defaultMicGain = value
}
public function get mic():Microphone {
return _mic;
}
public function VoiceStreamManager() {
_heartbeat.addEventListener(TimerEvent.TIMER, onHeartbeat);
}
protected function onHeartbeat(event:TimerEvent):void {
trace("+++ heartbeat +++");
trace(ObjectUtil.toString(_incomingStream.audioCodec));
}
public function muteMicGain(value:Boolean):void {
if (_mic) {
_mic.gain = value ? 0 : _defaultMicGain;
}
}
public function play(connection:NetConnection, streamName:String):void {
_incomingStream = new NetStream(connection);
_incomingStream.client = this;
_incomingStream.addEventListener(NetDataEvent.MEDIA_TYPE_DATA, onNetDataEvent);
_incomingStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_incomingStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
/*
* Set the bufferTime to 0 (zero) for live stream as suggested in the doc.
* http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/flash/net/NetStream.html#bufferTime
* If we don't, we'll have a long audio delay when a momentary network congestion occurs. When the congestion
* disappears, a flood of audio packets will arrive at the client and Flash will buffer them all and play them.
* http://stackoverflow.com/questions/1079935/actionscript-netstream-stutters-after-buffering
* ralam (Dec 13, 2010)
*/
_incomingStream.bufferTime = 0;
_incomingStream.receiveAudio(true);
_incomingStream.receiveVideo(false);
_incomingStream.play(streamName);
// _heartbeat.start();
}
protected function onNetDataEvent(event:NetDataEvent):void {
// trace(ObjectUtil.toString(event));
}
public function publish(connection:NetConnection, streamName:String, codec:String, pushToTalk:Boolean):void {
_outgoingStream = new NetStream(connection);
_outgoingStream.client = this;
_outgoingStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_outgoingStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
setupMicrophone(codec, pushToTalk);
if (_mic) {
_outgoingStream.attachAudio(_mic);
_outgoingStream.publish(streamName, "live");
}
}
private function noMicrophone():Boolean {
return ((Microphone.getMicrophone() == null) || (Microphone.names.length == 0) || ((Microphone.names.length == 1) && (Microphone.names[0] == "Unknown Microphone")));
}
private function setupMicrophone(codec:String, pushToTalk:Boolean):void {
if (noMicrophone()) {
_mic = null;
return;
}
_mic = getMicrophone(codec);
_mic.gain = pushToTalk ? 0 : _defaultMicGain;
}
/**
* first try to use the enhanced microphone
* if it doesn't work, get the regular one
*/
private function getMicrophone(codec:String):Microphone {
var mic:Microphone = null;
mic = Microphone.getEnhancedMicrophone();
if (mic) {
var options:MicrophoneEnhancedOptions = new MicrophoneEnhancedOptions();
options.mode = MicrophoneEnhancedMode.FULL_DUPLEX;
options.autoGain = false;
options.echoPath = 128;
options.nonLinearProcessing = true;
mic['enhancedOptions'] = options;
mic.setUseEchoSuppression(true);
} else {
mic = Microphone.getMicrophone();
}
if (mic == null) {
trace("No microphone! <o>");
} else {
mic.addEventListener(StatusEvent.STATUS, onMicStatusEvent);
mic.setLoopBack(false);
mic.setSilenceLevel(0, 20000);
mic.gain = 60;
if (codec == "SPEEX") {
mic.encodeQuality = 6;
mic.codec = SoundCodec.SPEEX;
mic.framesPerPacket = 1;
mic.rate = 16;
trace("Using SPEEX wideband codec");
} else {
mic.codec = SoundCodec.NELLYMOSER;
mic.rate = 8;
trace("Using Nellymoser codec");
}
}
return mic;
}
protected function onMicStatusEvent(event:StatusEvent):void {
trace("New microphone status event");
//trace(ObjectUtil.toString(event));
switch (event.code) {
case "Microphone.Muted":
break;
case "Microphone.Unmuted":
break;
default:
break;
}
}
public function close():void {
if (_incomingStream) {
_incomingStream.removeEventListener(NetDataEvent.MEDIA_TYPE_DATA, onNetDataEvent);
_incomingStream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_incomingStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
_incomingStream.close();
_incomingStream = null;
}
if (_outgoingStream) {
_outgoingStream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_outgoingStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
_outgoingStream.attachAudio(null);
_outgoingStream.close();
_outgoingStream = null;
}
}
protected function onNetStatusEvent(event:NetStatusEvent):void {
trace("VoiceStreamManager: onNetStatusEvent - " + event.info.code);
switch (event.info.code) {
case "NetStream.Play.Reset":
break;
case "NetStream.Play.StreamNotFound":
break;
case "NetStream.Play.Failed":
break;
case "NetStream.Play.Start":
break;
case "NetStream.Play.Stop":
break;
case "NetStream.Publish.Start":
break;
case "NetStream.Buffer.Full":
break;
default:
break;
}
}
protected function onAsyncErrorEvent(event:AsyncErrorEvent):void {
trace(ObjectUtil.toString(event));
}
public function onPlayStatus(... rest):void {
trace("onPlayStatus() " + ObjectUtil.toString(rest));
}
public function onMetaData(... rest):void {
trace("onMetaData() " + ObjectUtil.toString(rest));
}
public function onHeaderData(... rest):void {
trace("onHeaderData() " + ObjectUtil.toString(rest));
}
}
}
package org.bigbluebutton.lib.voice.services {
import flash.events.AsyncErrorEvent;
import flash.events.NetDataEvent;
import flash.events.NetStatusEvent;
import flash.events.StatusEvent;
import flash.events.TimerEvent;
import flash.media.Microphone;
import flash.media.MicrophoneEnhancedMode;
import flash.media.MicrophoneEnhancedOptions;
import flash.media.SoundCodec;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.Timer;
import mx.utils.ObjectUtil;
public class VoiceStreamManager {
protected var _incomingStream:NetStream = null;
protected var _outgoingStream:NetStream = null;
protected var _connection:NetConnection = null;
protected var _mic:Microphone = null;
protected var _defaultMicGain:Number = 50;
protected var _heartbeat:Timer = new Timer(2000);
public function setDefaultMicGain(value:Number):void {
_defaultMicGain = value
}
public function get mic():Microphone {
return _mic;
}
public function VoiceStreamManager() {
_heartbeat.addEventListener(TimerEvent.TIMER, onHeartbeat);
}
protected function onHeartbeat(event:TimerEvent):void {
trace("+++ heartbeat +++");
trace(ObjectUtil.toString(_incomingStream.audioCodec));
}
public function muteMicGain(value:Boolean):void {
if (_mic) {
_mic.gain = value ? 0 : _defaultMicGain;
}
}
public function play(connection:NetConnection, streamName:String):void {
_incomingStream = new NetStream(connection);
_incomingStream.client = this;
_incomingStream.addEventListener(NetDataEvent.MEDIA_TYPE_DATA, onNetDataEvent);
_incomingStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_incomingStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
/*
* Set the bufferTime to 0 (zero) for live stream as suggested in the doc.
* http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/flash/net/NetStream.html#bufferTime
* If we don't, we'll have a long audio delay when a momentary network congestion occurs. When the congestion
* disappears, a flood of audio packets will arrive at the client and Flash will buffer them all and play them.
* http://stackoverflow.com/questions/1079935/actionscript-netstream-stutters-after-buffering
* ralam (Dec 13, 2010)
*/
_incomingStream.bufferTime = 0;
_incomingStream.receiveAudio(true);
_incomingStream.receiveVideo(false);
_incomingStream.play(streamName);
// _heartbeat.start();
}
protected function onNetDataEvent(event:NetDataEvent):void {
// trace(ObjectUtil.toString(event));
}
public function publish(connection:NetConnection, streamName:String, codec:String, pushToTalk:Boolean):void {
_outgoingStream = new NetStream(connection);
_outgoingStream.client = this;
_outgoingStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_outgoingStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
setupMicrophone(codec, pushToTalk);
if (_mic) {
_outgoingStream.attachAudio(_mic);
_outgoingStream.publish(streamName, "live");
}
}
private function noMicrophone():Boolean {
return ((Microphone.getMicrophone() == null) || (Microphone.names.length == 0) || ((Microphone.names.length == 1) && (Microphone.names[0] == "Unknown Microphone")));
}
private function setupMicrophone(codec:String, pushToTalk:Boolean):void {
if (noMicrophone()) {
_mic = null;
return;
}
_mic = getMicrophone(codec);
_mic.gain = pushToTalk ? 0 : _defaultMicGain;
}
/**
* first try to use the enhanced microphone
* if it doesn't work, get the regular one
*/
private function getMicrophone(codec:String):Microphone {
var mic:Microphone = null;
mic = Microphone.getEnhancedMicrophone();
if (mic) {
var options:MicrophoneEnhancedOptions = new MicrophoneEnhancedOptions();
options.mode = MicrophoneEnhancedMode.FULL_DUPLEX;
options.autoGain = false;
options.echoPath = 128;
options.nonLinearProcessing = true;
mic['enhancedOptions'] = options;
mic.setUseEchoSuppression(true);
} else {
mic = Microphone.getMicrophone();
}
if (mic == null) {
trace("No microphone! <o>");
} else {
mic.addEventListener(StatusEvent.STATUS, onMicStatusEvent);
mic.setLoopBack(false);
mic.setSilenceLevel(0, 20000);
mic.gain = 60;
if (codec == "SPEEX") {
mic.encodeQuality = 6;
mic.codec = SoundCodec.SPEEX;
mic.framesPerPacket = 1;
mic.rate = 16;
trace("Using SPEEX wideband codec");
} else {
mic.codec = SoundCodec.NELLYMOSER;
mic.rate = 8;
trace("Using Nellymoser codec");
}
}
return mic;
}
protected function onMicStatusEvent(event:StatusEvent):void {
trace("New microphone status event");
//trace(ObjectUtil.toString(event));
switch (event.code) {
case "Microphone.Muted":
break;
case "Microphone.Unmuted":
break;
default:
break;
}
}
private function callIntoEchoTest():void {
/*
if (isConnected()) {
var destination:String = options.echoTestApp;
if (destination != null && destination != "") {
LOGGER.debug("Calling into echo test =[{0}]", [destination]);
state = CALLING_INTO_ECHO_TEST;
VoiceConnection.doCall(destination);
} else {
LOGGER.debug("Invalid echo test destination [{0}]", [destination]);
dispatcher.dispatchEvent(new FlashErrorEvent(FlashErrorEvent.INVALID_ECHO_TEST_DESTINATION));
}
} else {
LOGGER.debug("Need to connect before we can call into echo test.");
state = DO_ECHO_TEST;
connect();
}
*/
}
public function close():void {
if (_incomingStream) {
_incomingStream.removeEventListener(NetDataEvent.MEDIA_TYPE_DATA, onNetDataEvent);
_incomingStream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_incomingStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
_incomingStream.close();
_incomingStream = null;
}
if (_outgoingStream) {
_outgoingStream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
_outgoingStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent);
_outgoingStream.attachAudio(null);
_outgoingStream.close();
_outgoingStream = null;
}
}
protected function onNetStatusEvent(event:NetStatusEvent):void {
trace("VoiceStreamManager: onNetStatusEvent - " + event.info.code);
switch (event.info.code) {
case "NetStream.Play.Reset":
break;
case "NetStream.Play.StreamNotFound":
break;
case "NetStream.Play.Failed":
break;
case "NetStream.Play.Start":
break;
case "NetStream.Play.Stop":
break;
case "NetStream.Publish.Start":
break;
case "NetStream.Buffer.Full":
break;
default:
break;
}
}
protected function onAsyncErrorEvent(event:AsyncErrorEvent):void {
trace(ObjectUtil.toString(event));
}
public function onPlayStatus(... rest):void {
trace("onPlayStatus() " + ObjectUtil.toString(rest));
}
public function onMetaData(... rest):void {
trace("onMetaData() " + ObjectUtil.toString(rest));
}
public function onHeaderData(... rest):void {
trace("onHeaderData() " + ObjectUtil.toString(rest));
}
}
}

View File

@ -0,0 +1,85 @@
package org.bigbluebutton.lib.voice.views {
import spark.components.Button;
import spark.components.Label;
import spark.components.ProgressBar;
import spark.components.VGroup;
import spark.layouts.HorizontalAlign;
public class EchoTestViewBase extends VGroup {
[Bindable]
public var echoTestButton:Button;
[Bindable]
public var micLevelProgressBar:ProgressBar;
[Bindable]
public var yesButton:Button;
[Bindable]
public var noButton:Button;
public var echoLabel:Label;
private var echoValidationGroup:VGroup;
private var echoButtonGroup:VGroup;
public function EchoTestViewBase() {
super();
// Echo Button Group
echoButtonGroup = new VGroup();
echoButtonGroup.percentWidth = 100;
echoButtonGroup.horizontalAlign = HorizontalAlign.CENTER;
addElement(echoButtonGroup);
micLevelProgressBar = new ProgressBar();
micLevelProgressBar.percentWidth = 80;
micLevelProgressBar.height = 40;
micLevelProgressBar.styleName = "micLevelProgressBar";
echoButtonGroup.addElement(micLevelProgressBar);
echoTestButton = new Button();
echoTestButton.label = "Start Echo Test";
echoButtonGroup.addElement(echoTestButton);
// Echo Validation Group
echoValidationGroup = new VGroup();
echoValidationGroup.percentWidth = 100;
echoValidationGroup.horizontalAlign = HorizontalAlign.CENTER;
addElement(echoValidationGroup);
echoValidationGroup.visible = echoValidationGroup.includeInLayout = false;
echoLabel = new Label();
echoLabel.maxDisplayedLines = 5;
echoLabel.percentWidth = 80;
echoLabel.styleName = "echoTestLabel";
echoLabel.text = "This is a private echo test. Speak a few words. Did you hear audio?";
//echoLabel.maxWidth = echoValidationGroup.width - 40;
echoValidationGroup.addElement(echoLabel);
yesButton = new Button();
yesButton.label = "Yes";
echoValidationGroup.addElement(yesButton);
noButton = new Button();
noButton.label = "No";
echoValidationGroup.addElement(noButton);
}
public function setTestingState(connected:Boolean):void {
echoButtonGroup.visible = echoButtonGroup.includeInLayout = !connected;
echoValidationGroup.visible = echoValidationGroup.includeInLayout = connected;
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
this.padding = getStyle("padding");
echoButtonGroup.padding = getStyle("padding");
}
}
}

View File

@ -0,0 +1,170 @@
package org.bigbluebutton.lib.voice.views {
import flash.events.MouseEvent;
import flash.events.StatusEvent;
import flash.events.TimerEvent;
import flash.media.Microphone;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.ObjectEncoding;
import flash.utils.Timer;
import org.bigbluebutton.lib.main.models.IMeetingData;
import org.bigbluebutton.lib.voice.commands.ShareMicrophoneSignal;
import org.bigbluebutton.lib.voice.commands.StartEchoTestSignal;
import org.bigbluebutton.lib.voice.commands.StopEchoTestSignal;
import robotlegs.bender.bundles.mvcs.Mediator;
public class EchoTestViewMediator extends Mediator {
[Inject]
public var view:EchoTestViewBase;
[Inject]
public var startEchoTestSignal:StartEchoTestSignal;
[Inject]
public var shareMicrophoneSignal:ShareMicrophoneSignal;
[Inject]
public var stopEchoTestSignal:StopEchoTestSignal;
[Inject]
public var meetingData:IMeetingData;
private var selectedMicrophone:Microphone;
private var micActivityTimer:Timer;
private var microphoneNetConnection:NetConnection;
private var netStream:NetStream;
private var audioMicLevelDetected:int = 0;
private var doingEchoTest:Boolean = false;
public override function initialize():void {
view.echoTestButton.addEventListener(MouseEvent.CLICK, echoTestButtonHandler);
view.yesButton.addEventListener(MouseEvent.CLICK, yesButtonHandler);
view.noButton.addEventListener(MouseEvent.CLICK, noButtonHandler);
testMicrophoneLoopback();
}
private function testMicrophoneLoopback():void {
reInitialize();
selectedMicrophone = Microphone.getMicrophone(0);
if (selectedMicrophone != null) {
view.echoTestButton.enabled = true;
selectedMicrophone.addEventListener(StatusEvent.STATUS, micStatusEventHandler)
netStream.attachAudio(selectedMicrophone);
startMicLevelListener();
audioMicLevelDetected = 0;
} else {
view.echoTestButton.enabled = false;
}
}
private function startMicLevelListener():void {
micActivityTimer = new Timer(100);
micActivityTimer.addEventListener(TimerEvent.TIMER, updateMicLevel);
micActivityTimer.start();
}
private function updateMicLevel(e:TimerEvent):void {
if (selectedMicrophone != null) {
if (selectedMicrophone.activityLevel > audioMicLevelDetected) {
audioMicLevelDetected = selectedMicrophone.activityLevel;
}
view.micLevelProgressBar.currentProgress = selectedMicrophone.activityLevel;
view.micLevelProgressBar.totalProgress = 100;
}
}
private function reInitialize():void {
if (microphoneNetConnection) {
microphoneNetConnection.close();
}
if (netStream) {
netStream.close();
}
microphoneNetConnection = new NetConnection();
microphoneNetConnection.objectEncoding = ObjectEncoding.AMF3;
microphoneNetConnection.proxyType = "best";
microphoneNetConnection.connect(null);
netStream = new NetStream(microphoneNetConnection);
if (selectedMicrophone != null && !selectedMicrophone.hasEventListener(StatusEvent.STATUS)) {
selectedMicrophone.removeEventListener(StatusEvent.STATUS, micStatusEventHandler);
}
if (micActivityTimer != null && micActivityTimer.running) {
micActivityTimer.stop();
}
selectedMicrophone = null;
}
private function micStatusEventHandler(event:StatusEvent):void {
switch (event.code) {
case "Microphone.Muted":
view.echoLabel.text = "You did not allow Flash to access your mic.";
break;
case "Microphone.Unmuted":
// @fixme : use => saveData.read("micGain") as Number; later
selectedMicrophone.gain = 60;
break;
default:
// LOGGER.debug("unknown micStatusHandler event: {0}", [event]);
}
}
private function echoTestButtonHandler(e:MouseEvent):void {
micActivityTimer.stop();
doingEchoTest = true;
view.setTestingState(true);
startEchoTestSignal.dispatch();
}
protected function yesButtonHandler(e:MouseEvent):void {
stopEchoTest();
var audioOptions:Object = new Object();
audioOptions.shareMic = !meetingData.users.me.voiceJoined;
audioOptions.listenOnly = false;
shareMicrophoneSignal.dispatch(audioOptions);
}
private function stopEchoTest():void {
if (doingEchoTest) {
doingEchoTest = false;
stopEchoTestSignal.dispatch();
}
}
private function noButtonHandler(e:MouseEvent):void {
stopEchoTest();
view.setTestingState(false);
testMicrophoneLoopback();
}
override public function destroy():void {
super.destroy();
microphoneNetConnection.close();
netStream.close();
view.echoTestButton.removeEventListener(MouseEvent.CLICK, echoTestButtonHandler);
view.yesButton.removeEventListener(MouseEvent.CLICK, yesButtonHandler);
view.noButton.removeEventListener(MouseEvent.CLICK, noButtonHandler);
if (selectedMicrophone && selectedMicrophone.hasEventListener(StatusEvent.STATUS)) {
selectedMicrophone.removeEventListener(StatusEvent.STATUS, micStatusEventHandler)
}
micActivityTimer.removeEventListener(TimerEvent.TIMER, updateMicLevel);
}
}
}

View File

@ -175,3 +175,96 @@
.icon-mute {
icon: "\ue932";
}
.icon-about {
content: "\ue933";
}
.icon-send {
content: "\ue934";
}
.icon-exit-fullscreen {
content: "\ue935";
}
.icon-delete {
content: "\ue936";
}
.icon-unmute-filled {
content: "\ue937";
}
.icon-mute-filled {
content: "\ue938";
}
.icon-listen_filled {
content: "\ue939";
}
.icon-template-upload {
content: "\ue93a";
}
.icon-template-download {
content: "\ue93b";
}
.icon-save-notes {
content: "\ue93c";
}
.icon-multi-whiteboard {
content: "\ue93d";
}
.icon-whiteboard {
content: "\ue93e";
}
.icon-rooms {
content: "\ue93f";
}
.icon-unlock {
content: "\ue940";
}
.icon-record {
content: "\ue941";
}
.icon-network {
content: "\ue942";
}
.icon-redo {
content: "\ue943";
}
.icon-thumbs-down-filled {
content: "\ue944";
}
.icon-thumbs-up-filled {
content: "\ue945";
}
.icon-checkmark {
content: "\ue946";
}
.icon-speak-louder {
content: "\ue947";
}
.icon-help {
content: "\ue940";
}
.icon-unlock {
content: "\ue948";
}
.icon-refresh {
content: "\ue949";
}
.icon-copy {
content: "\ue94a";
}
.icon-shortcuts {
content: "\ue94b";
}
.icon-warning {
content: "\ue94c";
}
.icon-transfer-audio {
content: "\ue94d";
}
.icon-room {
content: "\ue94e";
}
.icon-new_file {
content: "\ue94f";
}
.icon-pointer {
content: "\ue950";
}

View File

@ -6,3 +6,7 @@
views|TopToolbarBase {
textAlign : center;
}
.echoTestLabel {
textAlign : center;
}