bigbluebutton-Github/bigbluebutton-client/src/WebcamViewStandalone.mxml
2017-05-29 13:58:18 +01:00

389 lines
14 KiB
XML
Executable File

<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<mx:Application xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:fx="http://ns.adobe.com/mxml/2009"
creationComplete="onCreationComplete()"
pageTitle="WebcamView" layout="absolute">
<fx:Script>
<![CDATA[
import flash.filters.ConvolutionFilter;
import flash.net.NetConnection;
import mx.core.UIComponent;
import mx.utils.URLUtil;
private var _video:Video;
private var _videoHolder:UIComponent;
private var ns:NetStream;
private var nc:NetConnection;
private var aspectRatio:Number = 1;
private var camWidth:Number = 320;
private var camHeight:Number = 240;
private var _url:String;
private var _stream:String;
private var _avatarURL:String;
private var displayAvatar:Boolean = false;
private var smoothVideo:Boolean = true;
private var applyConvolutionFilter:Boolean = false;
private var convolutionFilter:Array = [-1, 0, -1, 0, 6, 0, -1, 0, -1];
private var filterBias:Number = 0;
private var filterDivisor:Number = 4;
private var enableH264:Boolean = false;
private var h264Level:String = "2.1";
private var h264Profile:String = "main";
private function onCreationComplete():void{
_videoHolder = new UIComponent();
_videoHolder.width = this.width;
_videoHolder.height = this.height;
trace("WebcamViewSA:: onCreationComplete [" + this.width + "," + this.height + "]");
this.addChild(_videoHolder);
_videoHolder.addChild(loader);
Security.allowDomain(determineHTMLURL());
trace("WebcamViewSA:: Security.allowDomain(" + determineHTMLURL() + ");");
initExternalInterface();
callWebcamViewStandaloneReady();
}
private function determineHTMLURL():String {
var serverName:String = "*";
if(ExternalInterface.available) {
try {
var htmlURL:String = String(ExternalInterface.call("window.location.href.toString"));
serverName = URLUtil.getServerName(htmlURL);
trace("WebcamViewSA::determineHTMLURL HTML URL [" + htmlURL + "]");
} catch(s:Error) {
trace("WebcamViewSA::determineHTMLURL Cannot determine HTML URL");
}
}
return serverName;
}
private function initExternalInterface():void {
trace('WebcamViewSA::initExternalInterface');
if (ExternalInterface.available) {
ExternalInterface.addCallback("startViewCameraStream", handleStartViewCameraRequest);
ExternalInterface.addCallback("stopViewCameraStream", handleStopViewCamera);
}
}
private function callWebcamViewStandaloneReady():void {
if (ExternalInterface.available) {
ExternalInterface.call("webcamViewStandaloneAppReady");
}
}
private function connect(url:String):void {
nc = new NetConnection();
nc.proxyType = "best";
nc.client = this;
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetConnectStatus);
nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
nc.connect(url);
}
public function onBWCheck(... rest):Number {
return 0;
}
public function onBWDone(... rest):void {
var p_bw:Number;
if (rest.length > 0) p_bw = rest[0];
// your application should do something here
// when the bandwidth check is complete
trace("WebcamViewSA:: bandwidth = " + p_bw + " Kbps.");
}
private function getVideoResolution(stream:String):void {
var pattern:RegExp = new RegExp("(\\d+x\\d+)-([A-Za-z0-9]+)-\\d+", "");
if (pattern.test(stream)) {
trace("WebcamViewSA:: The stream name is well formatted [" + stream + "]");
trace("WebcamViewSA:: Stream resolution is [" + pattern.exec(stream)[1] + "] Userid [" + pattern.exec(stream)[2] + "]");
var res:Array = pattern.exec(stream)[1].split("x");
camWidth = Number(res[0]);
camHeight = Number(res[1]);
} else {
camWidth = 320;
camHeight = 240;
}
}
private function onIOError(event:NetStatusEvent):void{
}
private function onNetConnectStatus(event:NetStatusEvent):void{
switch(event.info.code){
case "NetConnection.Connect.Success":
playWebcamStream();
break;
default:
trace("WebcamViewSA:: [" + event.info.code + "] for [" + _url + "]");
break;
}
}
private function onSecurityError(event:NetStatusEvent):void{
}
private function handleStartViewCameraRequest(url:String, stream:String, avatarURL:String):void {
displayAvatar = false;
_avatarURL = avatarURL;
_url = url;
_stream = stream;
trace("WebcamViewSA::handleStartViewCameraRequest avatar=[" + _avatarURL + "]");
connect(url);
}
private function handleStopViewCamera(avatarURL:String):void {
_avatarURL = avatarURL;
trace("WebcamViewSA::handleStopViewCamera avatar=[" + _avatarURL + "]");
stopViewing();
}
private var loader:Loader = new Loader();
private var request:URLRequest;
private function loadAvatar():void {
request = new URLRequest(_avatarURL);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadingComplete);
loader.load(request);
}
private var avatarWidth:Number = 320;
private var avatarHeight:Number = 240;
private function onLoadingComplete(event:Event):void {
if (!displayAvatar) {
// The user might have started sharing webcam again.
return;
}
if (_video != null) _videoHolder.removeChild(_video);
_videoHolder.addChild(loader);
// Save the size of the avatar image.
avatarWidth = loader.content.width;
avatarHeight = loader.content.height;
onResizeAvatar();
}
private function onResizeAvatar():void {
if (loader != null && _videoHolder != null) {
if (avatarIsSmallerThanWindow()) {
// The avatar image is smaller than the window. Just center the image.
_videoHolder.width = loader.width = avatarWidth;
_videoHolder.height = loader.height = avatarHeight;
} else {
// The avatar is bigger than the window. Fit into the window maintaining aspect ratio.
fitAvatarToWindow();
}
_videoHolder.x = (this.width - loader.width) / 2;
_videoHolder.y = (this.height - loader.height) / 2;
}
}
private function fitAvatarToWindow():void {
if (_videoHolder.width < _videoHolder.height) {
fitAvatarToHeightAndAdjustWidthToMaintainAspectRatio();
} else {
fitAvatarToWidthAndAdjustHeightToMaintainAspectRatio();
}
}
private function avatarIsSmallerThanWindow():Boolean {
return (avatarWidth < _videoHolder.width) && (avatarHeight < _videoHolder.height);
}
private function fitAvatarToWidthAndAdjustHeightToMaintainAspectRatio():void {
var aspect:Number = avatarHeight / avatarWidth;
loader.width = _videoHolder.width = this.width;
// Maintain aspect-ratio
_videoHolder.height= loader.height = loader.width * aspect;
}
private function resetVideoHolder():void {
_videoHolder.width = this.width;
_videoHolder.height = this.height;
_videoHolder.x = _videoHolder.y = 0;
}
private function fitAvatarToHeightAndAdjustWidthToMaintainAspectRatio():void {
var aspect:Number = avatarWidth / avatarHeight;
loader.height = _videoHolder.height = this.height;
// Maintain aspect-ratio
_videoHolder.width = loader.width = loader.height * aspect;
}
private function stopViewing():void {
resetVideoHolder();
if (_video != null) {
trace("WebcamViewSA:: removing video from holder");
_videoHolder.removeChild(_video);
_video.clear();
_video = null;
}
trace("WebcamViewSA:: closing stream");
if (ns != null) {
ns.close();
}
displayAvatar = true;
loadAvatar();
}
private function playWebcamStream():void {
ns = new NetStream(nc);
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
ns.client = this;
ns.bufferTime = 0;
ns.receiveVideo(true);
ns.receiveAudio(false);
getVideoResolution(_stream);
trace("WebcamViewSA:: WINDOW [" + this.width + "," + this.height + "]");
resetVideoHolder();
_video = new Video(camWidth, camHeight);
_video.width = camWidth;
_video.height = camHeight;
trace("WebcamViewSA:: resolution [" + _video.width + "," + _video.height + "]");
onResize();
_video.attachNetStream(ns);
_video.smoothing = smoothVideo;
if (applyConvolutionFilter) {
var filter:ConvolutionFilter = new flash.filters.ConvolutionFilter();
filter.matrixX = 3;
filter.matrixY = 3;
filter.matrix = convolutionFilter;
filter.bias = filterBias;
filter.divisor = filterDivisor;
_video.filters = [filter];
}
trace("WebcamViewSA:: adding video to video holder");
_videoHolder.removeChild(loader);
_videoHolder.addChild(_video);
_videoHolder.visible = true;
ns.play(_stream);
}
private function onAsyncError(e:AsyncErrorEvent):void{
trace("WebcamViewSA::asyncerror " + e.toString());
}
public function onMetaData(info:Object):void{
trace("WebcamViewSA:: metadata: width=" + info.width + " height=" + info.height);
}
private function onNetStatus(e:NetStatusEvent):void{
switch(e.info.code){
case "NetStream.Publish.Start":
trace("WebcamViewSA:: NetStream.Publish.Start");
break;
case "NetStream.Play.UnpublishNotify":
trace("WebcamViewSA:: NetStream.Play.UnpublishNotify");
stopViewing();
break;
case "NetStream.Play.Start":
trace("WebcamViewSA:: Netstatus: " + e.info.code);
break;
case "NetStream.Play.FileStructureInvalid":
trace("WebcamViewSA:: The MP4's file structure is invalid.");
break;
case "NetStream.Play.NoSupportedTrackFound":
trace("WebcamViewSA:: The MP4 doesn't contain any supported tracks");
break;
}
}
private function onResize():void {
if (_videoHolder != null) {
fitVideoToWindow();
_video.x = (this.width - _video.width) / 2;
_video.y = (this.height - _video.height) / 2;
}
}
private function fitVideoToWindow():void {
if (_videoHolder.width < _videoHolder.height) {
fitToHeightAndAdjustWidthToMaintainAspectRatio();
} else {
fitToWidthAndAdjustHeightToMaintainAspectRatio();
}
}
private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
var aspect:Number = camHeight / camWidth;
_video.width = _videoHolder.width;
// Maintain aspect-ratio
_video.height = _video.width * aspect;
}
private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
var aspect:Number = camWidth / camHeight;
_video.height = _videoHolder.height;
// Maintain aspect-ratio
_video.width = _video.height * aspect;
}
]]>
</fx:Script>
</mx:Application>