Implementation done during the 2nd BigBlueButton Hackfest on April 2013; implemented the concept of video profiles - the sysadmin can specify in a XML file the video profiles that the users will use to broadcast video; it includes width, height, key interval, fps, enableH264 among other parameters; a hack was done to enable the user subscribe to a different profile than the one that is being broadcasted - on the server-side there will be a transcoder component that will handle this kind of subscription

This commit is contained in:
Felipe Cecagno 2013-04-28 18:18:17 -04:00
parent 0b055b1672
commit 99d6d959f9
21 changed files with 724 additions and 412 deletions

View File

@ -40,7 +40,7 @@ Panel {
paddingRight: 3;
}
Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle {
Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .cameraDisplaySettingsWindowProfileComboStyle {
textIndent: 0;
paddingLeft: 10;
paddingRight: 10;
@ -58,7 +58,6 @@ Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle {
fontSize: 12;
}
.helpLinkButtonStyle {
rollOverColor: #cccccc;
selectionColor: #999999;

View File

@ -432,6 +432,7 @@
<copy file="${PROD_RESOURCES_DIR}/expressInstall.swf" todir="${OUTPUT_DIR}" overwrite="true"/>
<copy file="${PROD_RESOURCES_DIR}/example-info-data.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
<copy file="${PROD_RESOURCES_DIR}/layout.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
<copy file="${PROD_RESOURCES_DIR}/profiles.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
<if>
<equals arg1="${BUILD_ENV}" arg2="DEV"/>
<then>

View File

@ -66,28 +66,19 @@
<module name="VideoconfModule" url="http://HOST/client/VideoconfModule.swf?v=VERSION"
uri="rtmp://HOST/video"
dependson = "UsersModule"
videoQuality = "100"
presenterShareOnly = "false"
controlsForPresenter = "false"
resolutions = "320x240,640x480,1280x720"
autoStart = "false"
showButton = "true"
showCloseButton = "true"
publishWindowVisible = "true"
viewerWindowMaxed = "false"
viewerWindowLocation = "top"
camKeyFrameInterval = "30"
camModeFps = "10"
camQualityBandwidth = "0"
camQualityPicture = "90"
smoothVideo="false"
applyConvolutionFilter="false"
convolutionFilter="-1, 0, -1, 0, 6, 0, -1, 0, -1"
filterBias="0"
filterDivisor="4"
enableH264 = "true"
h264Level = "2.1"
h264Profile = "main"
displayAvatar = "false"
focusTalking = "false"
glowColor = "0x4A931D"

View File

@ -0,0 +1,73 @@
<?xml version="1.0"?>
<profiles fallbackLocale="en_US">
<profile id="hd">
<locale>
<en_US>High definition</en_US>
<pt_BR>Alta definição</pt_BR>
</locale>
<width>1280</width>
<height>720</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>15</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="vga">
<locale>
<en_US>VGA</en_US>
</locale>
<width>640</width>
<height>480</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>10</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="low1" default="true">
<locale>
<en_US>Low bandwidth</en_US>
<pt_BR>Baixa banda</pt_BR>
</locale>
<width>320</width>
<height>240</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>10</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
<profile id="low2">
<locale>
<en_US>Low latency + low CPU</en_US>
<pt_BR>Baixa banda + baixo CPU</pt_BR>
</locale>
<width>320</width>
<height>240</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>5</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>false</enableH264>
</profile>
<profile id="pic">
<locale>
<en_US>One frame per second</en_US>
<pt_BR>Um quadro por segundo</pt_BR>
</locale>
<width>320</width>
<height>240</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>1</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>false</enableH264>
</profile>
</profiles>

View File

@ -67,6 +67,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
setupAPI();
EventBroadcaster.getInstance().addEventListener("configLoadedEvent", configLoadedEventHandler);
BBB.initConfigManager();
BBB.initVideoProfileManager();
modifier = ExternalInterface.call("determineModifier");
}

View File

@ -74,14 +74,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
return _attributes.userrole as String;
}
public function get quality():Number{
return Number(_attributes.videoQuality);
}
public function get resolutions():String {
return _attributes.resolutions;
}
public function get presenterShareOnly():Boolean{
if (_attributes.presenterShareOnly == "true") return true;
else return false;

View File

@ -22,7 +22,9 @@ package org.bigbluebutton.core
import org.bigbluebutton.core.managers.ConnectionManager;
import org.bigbluebutton.core.managers.UserConfigManager;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.managers.VideoProfileManager;
import org.bigbluebutton.core.model.Session;
import org.bigbluebutton.core.model.VideoProfile;
import flash.system.Capabilities;
public class BBB {
@ -30,6 +32,7 @@ package org.bigbluebutton.core
private static var connectionManager:ConnectionManager = null;
private static var session:Session = null;
private static var userConfigManager:UserConfigManager = null;
private static var videoProfileManager:VideoProfileManager = null;
public static function initUserConfigManager():UserConfigManager {
if (userConfigManager == null) {
@ -46,10 +49,34 @@ package org.bigbluebutton.core
return configManager;
}
public static function initVideoProfileManager():VideoProfileManager {
if (videoProfileManager == null) {
videoProfileManager = new VideoProfileManager();
videoProfileManager.loadProfiles();
}
return videoProfileManager;
}
public static function getConfigForModule(module:String):XML {
return initConfigManager().config.getConfigFor(module);
}
public static function get videoProfiles():Array {
return initVideoProfileManager().profiles;
}
public static function getVideoProfileById(id:String):VideoProfile {
return initVideoProfileManager().getVideoProfileById(id);
}
public static function get defaultVideoProfile():VideoProfile {
return initVideoProfileManager().defaultVideoProfile;
}
public static function get fallbackVideoProfile():VideoProfile {
return initVideoProfileManager().fallbackVideoProfile;
}
public static function initConnectionManager():ConnectionManager {
if (connectionManager == null) {
connectionManager = new ConnectionManager();

View File

@ -0,0 +1,119 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3.0 of the License, or (at your option) any later
* version.
*
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.core.managers
{
import com.asfusion.mate.events.Dispatcher;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.core.FlexGlobals;
import mx.utils.URLUtil;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.EventBroadcaster;
import org.bigbluebutton.core.model.VideoProfile;
public class VideoProfileManager extends EventDispatcher {
public static const PROFILES_XML:String = "client/conf/profiles.xml";
public static const DEFAULT_FALLBACK_LOCALE:String = "en_US";
private var _profiles:Array = new Array();
public function loadProfiles():void {
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, handleComplete);
var date:Date = new Date();
var localeReqURL:String = buildRequestURL() + "?a=" + date.time;
trace("VideoProfileManager::loadProfiles [" + localeReqURL + "]");
urlLoader.load(new URLRequest(localeReqURL));
}
private function buildRequestURL():String {
var swfURL:String = FlexGlobals.topLevelApplication.url;
var protocol:String = URLUtil.getProtocol(swfURL);
var serverName:String = URLUtil.getServerNameWithPort(swfURL);
return protocol + "://" + serverName + "/" + PROFILES_XML;
}
private function handleComplete(e:Event):void{
trace("VideoProfileManager::handleComplete [" + new XML(e.target.data) + "]");
// first clear the array
_profiles.splice(0);
var profiles:XML = new XML(e.target.data);
var fallbackLocale:String = profiles.@fallbackLocale != undefined? profiles.@fallbackLocale.toString(): DEFAULT_FALLBACK_LOCALE;
for each (var profile:XML in profiles.children()) {
_profiles.push(new VideoProfile(profile, fallbackLocale));
}
}
public function get profiles():Array {
if (_profiles.length > 0) {
return _profiles;
} else {
return [ fallbackVideoProfile ];
}
}
public function getVideoProfileById(id:String):VideoProfile {
for each (var profile:VideoProfile in _profiles) {
if (profile.id == id) {
return profile;
}
}
return null;
}
public function get defaultVideoProfile():VideoProfile {
for each (var profile:VideoProfile in _profiles) {
if (profile.defaultProfile) {
return profile;
}
}
if (_profiles.length > 0) {
return _profiles[0];
} else {
return null;
}
}
public function get fallbackVideoProfile():VideoProfile {
return new VideoProfile(
<profile id="4L7344ZoBYGTocbHOIvzXsrGiBGoohFv" default="true">
<locale>
<en_US>Fallback profile</en_US>
</locale>
<width>320</width>
<height>240</height>
<keyFrameInterval>5</keyFrameInterval>
<modeFps>10</modeFps>
<qualityBandwidth>0</qualityBandwidth>
<qualityPicture>90</qualityPicture>
<enableH264>true</enableH264>
<h264Level>2.1</h264Level>
<h264Profile>main</h264Profile>
</profile>
, DEFAULT_FALLBACK_LOCALE);
}
}
}

View File

@ -0,0 +1,168 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3.0 of the License, or (at your option) any later
* version.
*
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.core.model
{
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.util.i18n.ResourceUtil;
import flash.utils.Dictionary;
public class VideoProfile
{
private var _fallbackLanguage:String;
private static var _nextId:int = -1;
private var _id:String;
private var _default:Boolean = false;
private var _name:Dictionary = new Dictionary();
private var _width:int = 320;
private var _height:int = 240;
private var _keyFrameInterval:int = 30;
private var _modeFps:int = 10;
private var _qualityBandwidth:int = 0;
private var _qualityPicture:int = 90;
private var _enableH264:Boolean = true;
private var _h264Level:String = "2.1";
private var _h264Profile:String = "main";
public function VideoProfile(vxml:XML, fallbackLanguage:String)
{
_fallbackLanguage = fallbackLanguage;
if (vxml.@id != undefined) {
_id = vxml.@id.toString();
} else {
_id = String(nextId());
}
if (vxml.@default != undefined) {
_default = (vxml.@default.toString().toUpperCase() == "TRUE") ? true : false;
}
if (vxml.locale != undefined) {
for each (var locale:XML in vxml.locale.children()) {
_name[locale.localName()] = locale.toString();
}
}
if (vxml.width != undefined) {
_width = vxml.width;
}
if (vxml.height != undefined) {
_height = vxml.height;
}
if (vxml.keyFrameInterval != undefined) {
_keyFrameInterval = vxml.keyFrameInterval;
}
if (vxml.modeFps != undefined) {
_modeFps = vxml.modeFps;
}
if (vxml.qualityBandwidth != undefined) {
_qualityBandwidth = vxml.qualityBandwidth;
}
if (vxml.qualityPicture != undefined) {
_qualityPicture = vxml.qualityPicture;
}
if (vxml.enableH264 != undefined) {
_enableH264 = (vxml.enableH264.toString().toUpperCase() == "TRUE") ? true : false;
}
if (vxml.h264Level != undefined) {
_h264Level = vxml.h264Level.toString();
}
if (vxml.h264Profile != undefined) {
_h264Profile = vxml.h264Profile.toString();
}
trace("This is a new video profile");
trace(this.toString());
}
public function toString():String {
return "VideoProfile [ "
+ "id: " + this.id + ", "
+ "default: " + this.defaultProfile + ", "
+ "name: " + this.name + ", "
+ "width: " + this.width + ", "
+ "height: " + this.height + ", "
+ "keyFrameInterval: " + this.keyFrameInterval + ", "
+ "modeFps: " + this.modeFps + ", "
+ "qualityBandwidth: " + this.qualityBandwidth + ", "
+ "qualityPicture: " + this.qualityPicture + ", "
+ "enableH264: " + this.enableH264 + ", "
+ "h264Level: " + this.h264Level + ", "
+ "h264Profile: " + this.h264Profile + " ]";
}
private static function nextId():int {
_nextId++;
return _nextId;
}
public function get id():String {
return _id;
}
public function get defaultProfile():Boolean {
return _default;
}
public function get name():String {
var locale:String = ResourceUtil.getInstance().getCurrentLanguageCode();
if (_name.hasOwnProperty(locale)) {
return _name[locale];
} else if (_name.hasOwnProperty(_fallbackLanguage)) {
return _name[_fallbackLanguage];
} else {
return "";
}
}
public function get width():int {
return _width;
}
public function get height():int {
return _height;
}
public function get keyFrameInterval():int {
return _keyFrameInterval;
}
public function get modeFps():int {
return _modeFps;
}
public function get qualityBandwidth():int {
return _qualityBandwidth;
}
public function get qualityPicture():int {
return _qualityPicture;
}
public function get enableH264():Boolean {
return _enableH264;
}
public function get h264Level():String {
return _h264Level;
}
public function get h264Profile():String {
return _h264Profile;
}
}
}

View File

@ -18,11 +18,12 @@
*/
package org.bigbluebutton.core.vo
{
import org.bigbluebutton.core.model.VideoProfile;
public class CameraSettingsVO
{
public var camIndex:int = 0;
public var camWidth:int = 0;
public var camHeight:int = 0;
public var videoProfile:VideoProfile = null;
public var isPublishing:Boolean = false;
}

View File

@ -147,15 +147,12 @@ package org.bigbluebutton.main.api
var camSettings:CameraSettingsVO = UsersUtil.amIPublishing();
obj.isPublishing = camSettings.isPublishing;
obj.camIndex = camSettings.camIndex;
obj.camWidth = camSettings.camWidth;
obj.camHeight = camSettings.camHeight;
var vidConf:VideoConfOptions = new VideoConfOptions();
obj.camKeyFrameInterval = vidConf.camKeyFrameInterval;
obj.camModeFps = vidConf.camModeFps;
obj.camQualityBandwidth = vidConf.camQualityBandwidth;
obj.camQualityPicture = vidConf.camQualityPicture;
obj.camWidth = camSettings.videoProfile.width;
obj.camHeight = camSettings.videoProfile.height;
obj.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
obj.camModeFps = camSettings.videoProfile.modeFps;
obj.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
obj.camQualityPicture = camSettings.videoProfile.qualityPicture;
return obj;
}

View File

@ -107,38 +107,35 @@ package org.bigbluebutton.main.api
}
public function handleBroadcastStartedEvent(event:BroadcastStartedEvent):void {
var vidConf:VideoConfOptions = new VideoConfOptions();
var payload:Object = new Object();
payload.eventName = EventConstants.BROADCASTING_CAM_STARTED;
payload.isPresenter = UsersUtil.amIPresenter();
payload.streamName = event.stream;
payload.isPublishing = event.camSettings.isPublishing;
payload.camIndex = event.camSettings.camIndex;
payload.camWidth = event.camSettings.camWidth;
payload.camHeight = event.camSettings.camHeight;
payload.camKeyFrameInterval = vidConf.camKeyFrameInterval;
payload.camModeFps = vidConf.camModeFps;
payload.camQualityBandwidth = vidConf.camQualityBandwidth;
payload.camQualityPicture = vidConf.camQualityPicture;
payload.camWidth = event.camSettings.videoProfile.width;
payload.camHeight = event.camSettings.videoProfile.height;
payload.camKeyFrameInterval = event.camSettings.videoProfile.keyFrameInterval;
payload.camModeFps = event.camSettings.videoProfile.modeFps;
payload.camQualityBandwidth = event.camSettings.videoProfile.qualityBandwidth;
payload.camQualityPicture = event.camSettings.videoProfile.qualityPicture;
broadcastEvent(payload);
}
public function handleAmISharingCamQueryEvent(event:AmISharingWebcamQueryEvent):void {
var camSettings:CameraSettingsVO = UsersUtil.amIPublishing();
var vidConf:VideoConfOptions = new VideoConfOptions();
var payload:Object = new Object();
payload.eventName = EventConstants.AM_I_SHARING_CAM_RESP;
payload.isPublishing = camSettings.isPublishing;
payload.camIndex = camSettings.camIndex;
payload.camWidth = camSettings.camWidth;
payload.camHeight = camSettings.camHeight;
payload.camKeyFrameInterval = vidConf.camKeyFrameInterval;
payload.camModeFps = vidConf.camModeFps;
payload.camQualityBandwidth = vidConf.camQualityBandwidth;
payload.camQualityPicture = vidConf.camQualityPicture;
payload.camWidth = camSettings.videoProfile.width;
payload.camHeight = camSettings.videoProfile.height;
payload.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
payload.camModeFps = camSettings.videoProfile.modeFps;
payload.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
payload.camQualityPicture = camSettings.videoProfile.qualityPicture;
broadcastEvent(payload);
}

View File

@ -28,11 +28,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flash.ui.Keyboard;
import mx.collections.ArrayCollection;
import mx.events.CloseEvent;
import mx.events.ItemClickEvent;
import mx.managers.PopUpManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
@ -47,11 +50,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private var cancelIcon:Class = images.control_play;
[Bindable]
public var resolutions:Array;
public var _videoProfiles:ArrayCollection = new ArrayCollection();
public var selectedVideoProfile:VideoProfile;
public var publishInClient:Boolean;
public var camWidth:Number = 320;
public var camHeight:Number = 240;
private var _camera:Camera = null;
// Timer used to enable the start publishing button, only after get any activity on the camera.
@ -67,7 +69,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function onCreationComplete():void {
changeDefaultCamForMac();
if (resolutions.length > 1) {
var idx:int = 0;
var defaultProfile:VideoProfile = BBB.defaultVideoProfile;
for each (var value:VideoProfile in BBB.videoProfiles) {
var item:Object = {index:idx, label:value.width + "x" + value.height + " " + value.name, profile:value};
_videoProfiles.addItem(item);
if (value.id == defaultProfile.id) {
cmbVideoProfile.selectedIndex = idx;
}
idx++;
}
if (_videoProfiles.length > 1) {
showResControls(true);
}
@ -130,17 +145,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function displayVideoPreview():void {
setComboResolution();
selectedVideoProfile = cmbVideoProfile.selectedItem.profile as VideoProfile;
trace("Using this video profile:: " + selectedVideoProfile.toString());
setAspectRatio(selectedVideoProfile.width, selectedVideoProfile.height);
var videoOptions:VideoConfOptions = new VideoConfOptions();
_camera.setMotionLevel(5, 1000);
_camera.setKeyFrameInterval(videoOptions.camKeyFrameInterval);
_camera.setMode(camWidth, camHeight, videoOptions.camModeFps);
_camera.setQuality(videoOptions.camQualityBandwidth, videoOptions.camQualityPicture);
_camera.setKeyFrameInterval(selectedVideoProfile.keyFrameInterval);
_camera.setMode(selectedVideoProfile.width, selectedVideoProfile.height, selectedVideoProfile.modeFps);
_camera.setQuality(selectedVideoProfile.qualityBandwidth, selectedVideoProfile.qualityPicture);
if (_camera.width != camWidth || _camera.height != camHeight) {
LogUtil.debug("Resolution " + camWidth + "x" + camHeight + " is not supported, using " + _camera.width + "x" + _camera.height + " instead");
setResolution(_camera.width, _camera.height);
if (_camera.width != selectedVideoProfile.width || _camera.height != selectedVideoProfile.height) {
LogUtil.debug("Resolution " + selectedVideoProfile.width + "x" + selectedVideoProfile.height + " is not supported, using " + _camera.width + "x" + _camera.height + " instead");
setAspectRatio(_camera.width, _camera.height);
}
if (_video != null) {
@ -168,13 +185,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function showResControls(show:Boolean):void {
if (show) cmbResolution.visible = true;
else cmbResolution.visible = false;
}
private function setComboResolution():void {
var res:Array = cmbResolution.selectedLabel.split( "x" );
setResolution(Number(res[0]), Number(res[1]));
if (show) cmbVideoProfile.visible = true;
else cmbVideoProfile.visible = false;
}
private function setAspectRatio(width:int, height:int):void {
@ -182,12 +194,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
this.minHeight = Math.floor((this.minWidth - PADDING_HORIZONTAL) / aspectRatio) + PADDING_VERTICAL;
}
private function setResolution(width:int, height:int):void {
camWidth = width;
camHeight = height;
setAspectRatio(camWidth, camHeight);
}
private function startPublishing():void {
updateCamera();
@ -199,8 +205,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var globalDispatcher:Dispatcher = new Dispatcher();
var camEvent:BBBEvent = new BBBEvent(BBBEvent.CAMERA_SETTING);
camEvent.payload.cameraIndex = camIndex;
camEvent.payload.cameraWidth = camWidth;
camEvent.payload.cameraHeight = camHeight;
camEvent.payload.videoProfile = selectedVideoProfile;
camEvent.payload.publishInClient = publishInClient;
globalDispatcher.dispatchEvent(camEvent);
@ -291,8 +296,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
toolTip="{ResourceUtil.getInstance().getString('bbb.publishVideo.changeCamera.toolTip')}"
click="showCameraSettings()"/>
<mx:Spacer width="70%"/>
<mx:ComboBox id="cmbResolution" styleName="cameraDisplaySettingsWindowChangeResolutionCombo"
dataProvider="{resolutions}" visible="false" change="updateCamera()"/>
<mx:ComboBox id="cmbVideoProfile" styleName="cameraDisplaySettingsWindowProfileComboStyle"
dataProvider="{_videoProfiles}" visible="false" change="updateCamera()"/>
<mx:Spacer width="5"/>
<mx:Button id="btnStartPublish" toolTip="{ResourceUtil.getInstance().getString('bbb.publishVideo.startPublishBtn.toolTip')}"
click="startPublishing()" enabled="true" styleName="cameraDisplaySettingsWindowStartBtn"

View File

@ -289,7 +289,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function openVideoPreviewWindow(event:BBBEvent):void {
var camSettings:CameraDisplaySettings = CameraDisplaySettings(PopUpManager.createPopUp(mdiCanvas, CameraDisplaySettings, true));
camSettings.resolutions = (event.payload.resolutions as String).split(",");
camSettings.publishInClient = event.payload.publishInClient;
var point1:Point = new Point();

View File

@ -110,47 +110,32 @@ package org.bigbluebutton.modules.videoconf.business
ns.attachCamera(e.camera);
// Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011)
// if (Capabilities.version.search("11,0") != -1) {
if ((BBB.getFlashPlayerVersion() >= 11) && videoOptions.enableH264) {
if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) {
// if (BBB.getFlashPlayerVersion() >= 11) {
LogUtil.info("Using H264 codec for video.");
var h264:H264VideoStreamSettings = new H264VideoStreamSettings();
var h264profile:String = H264Profile.MAIN;
if (videoOptions.h264Profile != "main") {
if (e.videoProfile.h264Profile != "main") {
h264profile = H264Profile.BASELINE;
}
var h264Level:String = H264Level.LEVEL_4_1;
if (videoOptions.h264Level == "1") {
h264Level = H264Level.LEVEL_1;
} else if (videoOptions.h264Level == "1.1") {
h264Level = H264Level.LEVEL_1_1;
} else if (videoOptions.h264Level == "1.2") {
h264Level = H264Level.LEVEL_1_2;
} else if (videoOptions.h264Level == "1.3") {
h264Level = H264Level.LEVEL_1_3;
} else if (videoOptions.h264Level == "1b") {
h264Level = H264Level.LEVEL_1B;
} else if (videoOptions.h264Level == "2") {
h264Level = H264Level.LEVEL_2;
} else if (videoOptions.h264Level == "2.1") {
h264Level = H264Level.LEVEL_2_1;
} else if (videoOptions.h264Level == "2.2") {
h264Level = H264Level.LEVEL_2_2;
} else if (videoOptions.h264Level == "3") {
h264Level = H264Level.LEVEL_3;
} else if (videoOptions.h264Level == "3.1") {
h264Level = H264Level.LEVEL_3_1;
} else if (videoOptions.h264Level == "3.2") {
h264Level = H264Level.LEVEL_3_2;
} else if (videoOptions.h264Level == "4") {
h264Level = H264Level.LEVEL_4;
} else if (videoOptions.h264Level == "4.1") {
h264Level = H264Level.LEVEL_4_1;
} else if (videoOptions.h264Level == "4.2") {
h264Level = H264Level.LEVEL_4_2;
} else if (videoOptions.h264Level == "5") {
h264Level = H264Level.LEVEL_5;
} else if (videoOptions.h264Level == "5.1") {
h264Level = H264Level.LEVEL_5_1;
switch (e.videoProfile.h264Level) {
case "1": h264Level = H264Level.LEVEL_1; break;
case "1.1": h264Level = H264Level.LEVEL_1_1; break;
case "1.2": h264Level = H264Level.LEVEL_1_2; break;
case "1.3": h264Level = H264Level.LEVEL_1_3; break;
case "1b": h264Level = H264Level.LEVEL_1B; break;
case "2": h264Level = H264Level.LEVEL_2; break;
case "2.1": h264Level = H264Level.LEVEL_2_1; break;
case "2.2": h264Level = H264Level.LEVEL_2_2; break;
case "3": h264Level = H264Level.LEVEL_3; break;
case "3.1": h264Level = H264Level.LEVEL_3_1; break;
case "3.2": h264Level = H264Level.LEVEL_3_2; break;
case "4": h264Level = H264Level.LEVEL_4; break;
case "4.1": h264Level = H264Level.LEVEL_4_1; break;
case "4.2": h264Level = H264Level.LEVEL_4_2; break;
case "5": h264Level = H264Level.LEVEL_5; break;
case "5.1": h264Level = H264Level.LEVEL_5_1; break;
}
LogUtil.info("Codec used: " + h264Level);

View File

@ -37,10 +37,12 @@ package org.bigbluebutton.modules.videoconf.business
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.events.DragWindowEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.EventConstants;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.CoreEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.main.model.users.events.KickUserEvent;
import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
@ -76,8 +78,6 @@ package org.bigbluebutton.modules.videoconf.business
protected var _controlButtons:ControlButtons = new ControlButtons();
[Bindable] public var resolutions:Array;
protected var videoConfOptions:VideoConfOptions = new VideoConfOptions();
public function getWindowType():String {
@ -88,19 +88,23 @@ package org.bigbluebutton.modules.videoconf.business
_controlButtons.handleNewRoleEvent(presenter);
}
protected function getVideoResolution(stream:String):Array {
var pattern:RegExp = new RegExp("(\\d+x\\d+)-([A-Za-z0-9]+)-\\d+", "");
protected function getVideoProfile(stream:String):VideoProfile {
trace("Parsing stream name [" + stream + "]");
var pattern:RegExp = new RegExp("([A-Za-z0-9]+)-([A-Za-z0-9]+)-\\d+", "");
if (pattern.test(stream)) {
LogUtil.debug("The stream name is well formatted [" + stream + "]");
var uid:String = UserManager.getInstance().getConference().getMyUserId();
LogUtil.debug("Stream resolution is [" + pattern.exec(stream)[1] + "]");
LogUtil.debug("Userid [" + pattern.exec(stream)[2] + "]");
trace("The stream name is well formatted");
trace("Video profile resolution is [" + pattern.exec(stream)[1] + "]");
trace("Userid [" + pattern.exec(stream)[2] + "]");
userID = pattern.exec(stream)[2];
addControlButtons();
return pattern.exec(stream)[1].split("x");
return BBB.getVideoProfileById(pattern.exec(stream)[1]);
} else {
LogUtil.error("The stream name doesn't follow the pattern <width>x<height>-<userId>-<timestamp>. However, the video resolution will be set to the lowest defined resolution in the config.xml: " + resolutions[0]);
return resolutions[0].split("x");
trace("Bad stream name format");
var profile:VideoProfile = BBB.defaultVideoProfile;
if (profile == null) {
profile = BBB.fallbackVideoProfile;
}
return profile;
}
}

View File

@ -21,12 +21,15 @@ package org.bigbluebutton.modules.videoconf.events
import flash.events.Event;
import flash.media.Camera;
import org.bigbluebutton.core.model.VideoProfile;
public class StartBroadcastEvent extends Event
{
public static const START_BROADCAST:String = "startBroadcastEvent";
public var stream:String;
public var camera:Camera;
public var videoProfile:VideoProfile;
public function StartBroadcastEvent(type:String = START_BROADCAST)
{

View File

@ -26,9 +26,11 @@ package org.bigbluebutton.modules.videoconf.maps
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.common.events.ToolbarButtonEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.ConnectAppEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.core.vo.CameraSettingsVO;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.MadePresenterEvent;
@ -185,15 +187,13 @@ package org.bigbluebutton.modules.videoconf.maps
dockWindow(window);
}
private function openPublishWindowFor(userID:String, camIndex:int, camWidth:int, camHeight:int):void {
private function openPublishWindowFor(userID:String, camIndex:int, videoProfile:VideoProfile):void {
var publishWindow:PublishWindow = new PublishWindow();
publishWindow.userID = userID;
publishWindow.title = UsersUtil.getUserName(userID);
publishWindow.camIndex = camIndex;
publishWindow.setResolution(camWidth, camHeight);
publishWindow.videoOptions = options;
publishWindow.quality = options.videoQuality;
publishWindow.resolutions = options.resolutions.split(",");
publishWindow.selectedVideoProfile = videoProfile;
trace("VideoEventMapDelegate:: [" + me + "] openPublishWindowFor:: Closing window for [" + userID + "] [" + UsersUtil.getUserName(userID) + "]");
@ -231,12 +231,17 @@ package org.bigbluebutton.modules.videoconf.maps
var window:VideoWindow = new VideoWindow();
window.userID = userID;
window.videoOptions = options;
window.resolutions = options.resolutions.split(",");
window.title = UsersUtil.getUserName(userID);
closeWindow(userID);
var bbbUser:BBBUser = UsersUtil.getUser(userID);
// HERE BEGINS THE HACK
// var pattern:RegExp = new RegExp("([A-Za-z0-9]+)-([A-Za-z0-9]+)-(\\d+)", "");
// var streamName:String = BBB.defaultVideoProfile.id + "-" + pattern.exec(bbbUser.streamName)[2] + "-" + pattern.exec(bbbUser.streamName)[3];
// trace("Changing the streamName from " + bbbUser.streamName + " to " + streamName);
// bbbUser.streamName = streamName;
// HERE FINISHES THE HACK
window.startVideo(proxy.connection, bbbUser.streamName);
webcamWindows.addWindow(window);
@ -325,7 +330,6 @@ package org.bigbluebutton.modules.videoconf.maps
private function openWebcamPreview(publishInClient:Boolean):void {
var openEvent:BBBEvent = new BBBEvent(BBBEvent.OPEN_WEBCAM_PREVIEW);
openEvent.payload.publishInClient = publishInClient;
openEvent.payload.resolutions = options.resolutions;
_dispatcher.dispatchEvent(openEvent);
}
@ -375,17 +379,15 @@ package org.bigbluebutton.modules.videoconf.maps
public function handleCameraSetting(event:BBBEvent):void {
var cameraIndex:int = event.payload.cameraIndex;
var camWidth:int = event.payload.cameraWidth;
var camHeight:int = event.payload.cameraHeight;
trace("VideoEventMapDelegate::handleCameraSettings [" + cameraIndex + "," + camWidth + "," + camHeight + "]");
var videoProfile:VideoProfile = event.payload.videoProfile;
trace("VideoEventMapDelegate::handleCameraSettings [" + cameraIndex + "," + videoProfile.id + "]");
var camSettings:CameraSettingsVO = new CameraSettingsVO();
camSettings.camIndex = cameraIndex;
camSettings.camWidth = camWidth;
camSettings.camHeight = camHeight;
camSettings.videoProfile = videoProfile;
UsersUtil.setCameraSettings(camSettings);
openPublishWindowFor(UsersUtil.getMyUserID(), cameraIndex, camWidth, camHeight);
openPublishWindowFor(UsersUtil.getMyUserID(), cameraIndex, videoProfile);
}
public function handleStoppedViewingWebcamEvent(event:StoppedViewingWebcamEvent):void {

View File

@ -24,12 +24,6 @@ package org.bigbluebutton.modules.videoconf.model
{
public var uri:String = "rtmp://localhost/video";
[Bindable]
public var videoQuality:Number = 100;
[Bindable]
public var resolutions:String = "320x240,640x480,1280x720";
[Bindable]
public var autoStart:Boolean = false;
@ -48,15 +42,6 @@ package org.bigbluebutton.modules.videoconf.model
[Bindable]
public var viewerWindowLocation:String = "middle";
[Bindable]
public var camKeyFrameInterval:Number = 5;
[Bindable]
public var camModeFps:Number = 15;
[Bindable]
public var camQualityBandwidth:Number = 0;
[Bindable]
public var smoothVideo:Boolean = false;
@ -72,18 +57,6 @@ package org.bigbluebutton.modules.videoconf.model
[Bindable]
public var filterDivisor:Number = 4;
[Bindable]
public var enableH264:Boolean = false;
[Bindable]
public var h264Level:String = "2.1";
[Bindable]
public var h264Profile:String = "main";
[Bindable]
public var camQualityPicture:Number = 50;
[Bindable] public var baseTabIndex:int;
[Bindable]
@ -114,12 +87,6 @@ package org.bigbluebutton.modules.videoconf.model
if (vxml.@uri != undefined) {
uri = vxml.@uri.toString();
}
if (vxml.@videoQuality != undefined) {
videoQuality = Number(vxml.@videoQuality.toString());
}
if (vxml.@resolutions != undefined) {
resolutions = vxml.@resolutions.toString();
}
if (vxml.@showCloseButton != undefined) {
showCloseButton = (vxml.@showCloseButton.toString().toUpperCase() == "TRUE") ? true : false;
}
@ -147,18 +114,6 @@ package org.bigbluebutton.modules.videoconf.model
if (vxml.@viewerWindowLocation != undefined) {
viewerWindowLocation = vxml.@viewerWindowLocation.toString().toUpperCase();
}
if (vxml.@camKeyFrameInterval != undefined) {
camKeyFrameInterval = Number(vxml.@camKeyFrameInterval.toString());
}
if (vxml.@camModeFps != undefined) {
camModeFps = Number(vxml.@camModeFps.toString());
}
if (vxml.@camQualityBandwidth != undefined) {
camQualityBandwidth = Number(vxml.@camQualityBandwidth.toString());
}
if (vxml.@camQualityPicture != undefined) {
camQualityPicture = Number(vxml.@camQualityPicture.toString());
}
if (vxml.@smoothVideo != undefined) {
smoothVideo = (vxml.@smoothVideo.toString().toUpperCase() == "TRUE") ? true : false;
}
@ -178,15 +133,6 @@ package org.bigbluebutton.modules.videoconf.model
if (vxml.@filterDivisor != undefined) {
filterDivisor = Number(vxml.@filterDivisor.toString());
}
if (vxml.@enableH264 != undefined) {
enableH264 = (vxml.@enableH264.toString().toUpperCase() == "TRUE") ? true : false;
}
if (vxml.@h264Level != undefined) {
h264Level = vxml.@h264Level.toString();
}
if (vxml.@h264Profile != undefined) {
h264Profile = vxml.@h264Profile.toString();
}
if (vxml.@baseTabIndex != undefined) {
baseTabIndex = vxml.@baseTabIndex;

View File

@ -53,10 +53,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.common.Role;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.events.LocaleChangeEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.EventConstants;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.CoreEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.SwitchedPresenterEvent;
import org.bigbluebutton.main.views.MainCanvas;
@ -73,10 +75,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
[Bindable] private var defaultHeight:Number = 240;
public var camIndex:int = 0;
private var camWidth:Number = 320;
private var camHeight:Number = 240;
public var selectedVideoProfile:VideoProfile;
private var _camera:Camera = null;
public var quality:Number = 0;
// Timer to auto-publish webcam. We need this timer to delay
// the auto-publishing until after the Viewers's window has loaded
@ -114,8 +114,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
this.glowBlurSize = videoOptions.glowBlurSize;
_videoHolder = new UIComponent();
_videoHolder.width = camWidth;
_videoHolder.height = camHeight;
_videoHolder.width = defaultWidth;
_videoHolder.height = defaultHeight;
this.addChild(_videoHolder);
this.minWidth = _minWidth;
@ -218,14 +218,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
_camera.addEventListener(ActivityEvent.ACTIVITY, onActivityEvent);
_camera.addEventListener(StatusEvent.STATUS, onStatusEvent);
_camera.setKeyFrameInterval(videoOptions.camKeyFrameInterval);
_camera.setMode(camWidth, camHeight, videoOptions.camModeFps);
_camera.setQuality(videoOptions.camQualityBandwidth, videoOptions.camQualityPicture);
_camera.setKeyFrameInterval(selectedVideoProfile.keyFrameInterval);
_camera.setMode(selectedVideoProfile.width, selectedVideoProfile.height, selectedVideoProfile.modeFps);
_camera.setQuality(selectedVideoProfile.qualityBandwidth, selectedVideoProfile.qualityPicture);
if (_camera.width != camWidth || _camera.height != camHeight) {
trace("Resolution " + camWidth + "x" + camHeight + " is not supported, using " + _camera.width + "x" + _camera.height + " instead");
setResolution(_camera.width, _camera.height);
}
setResolution();
_video = new Video;
_video.attachCamera(_camera);
@ -308,6 +305,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var e:StartBroadcastEvent = new StartBroadcastEvent();
e.stream = this.streamName;
e.camera = _camera;
e.videoProfile = selectedVideoProfile;
dispatchEvent(e);
maximizeRestoreBtn.visible = true;
@ -355,10 +353,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
public function setResolution(width:int, height:int):void {
camWidth = originalWidth = width;
camHeight = originalHeight = height;
setAspectRatio(camWidth, camHeight);
public function setResolution():void {
originalWidth = selectedVideoProfile.width;
originalHeight = selectedVideoProfile.height;
setAspectRatio(selectedVideoProfile.width, selectedVideoProfile.height);
/**
* Add timestamp to create a unique stream name. This way we can record
@ -366,8 +364,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*/
var curTime:Number = new Date().getTime();
var uid:String = UserManager.getInstance().getConference().getMyUserId();
var res:String = camWidth + "x" + camHeight;
this.streamName = res.concat("-" + uid) + "-" + curTime;
this.streamName = selectedVideoProfile.id + "-" + uid + "-" + curTime;
trace("Using as streamName " + this.streamName);
}
private function isPresenter():Boolean{

View File

@ -51,6 +51,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.core.EventConstants;
import org.bigbluebutton.core.events.CoreEvent;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.StoppedViewingWebcamEvent;
import org.bigbluebutton.main.events.SwitchedPresenterEvent;
@ -163,13 +164,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
ns.receiveVideo(true);
ns.receiveAudio(false);
var res:Array = getVideoResolution(stream);
if (res == null) // error
var pro:VideoProfile = getVideoProfile(stream);
trace("Remote video profile: " + pro.toString());
if (pro == null) // error
return;
_video = new Video(Number(res[0]), Number(res[1]));
_video.width = originalWidth = Number(res[0]);
_video.height = originalHeight = Number(res[1]);
setAspectRatio(Number(res[0]), Number(res[1]));
_video = new Video(pro.width, pro.height);
_video.width = originalWidth = pro.width;
_video.height = originalHeight = pro.height;
setAspectRatio(pro.width, pro.height);
_video.attachNetStream(ns);
@ -209,6 +211,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function onNetStatus(e:NetStatusEvent):void{
trace("VideoWindow::onNetStatus get on the stream " + streamName + " the event code " + e.info.code);
switch(e.info.code){
case "NetStream.Publish.Start":
LogUtil.debug("NetStream.Publish.Start for broadcast stream " + streamName);