<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" preinitialize="presetup()" width="250" height="150" xmlns:local="*"> <mx:Script> <![CDATA[ import flash.external.*; import flash.net.NetConnection; import flash.net.NetStream; import mx.utils.ObjectUtil; import mx.core.FlexGlobals; import flash.system.Security; import flash.system.SecurityPanel; import flash.media.*; import com.adobe.crypto.MD5; import com.adobe.serialization.json.JSON; [Bindable] public var netConnection:NetConnection = null; private var incomingNetStream:NetStream = null; private var outgoingNetStream:NetStream = null; private var mic:Microphone = null; [Bindable] private var microphoneList:Array; private var sessionid:String; private var auth_user:String; private var auth_domain:String; private var mic_index:int = -1; private var attachedUUID:String = ""; [Embed(source="Sound_of_phone_ringing2.mp3")] [Bindable] private var soundOfPhoneRinging_MP3:Class; private var ringChannel:SoundChannel = null; private var ringUUID:String = ""; private var soundOfPhoneRinging:Sound; public function presetup():void { /* Load config here */ soundOfPhoneRinging = new soundOfPhoneRinging_MP3(); } /********* JavaScript functions *********/ public function makeCall(number:String, account:String, evt:Object):void { if (netConnection != null) { if (incomingNetStream == null) { setupStreams(); } netConnection.call("makeCall", null, number, account, evt); } } public function sendDTMF(digits:String, duration:int):void { if (netConnection != null) { netConnection.call("sendDTMF", null, digits, duration); } } public function answer(uuid:String):void { if (ringChannel != null) { ringChannel.stop(); ringChannel = null; } if (incomingNetStream == null) { setupStreams(); } if (netConnection != null) { netConnection.call("answer", null, uuid); } } public function hangup(uuid:String):void { if (uuid == attachedUUID) { destroyStreams(); } if (netConnection != null) { netConnection.call("hangup", null, uuid); } } public function register(account:String, nickname:String):void { if (netConnection != null) { netConnection.call("register", null, account, nickname); } } public function unregister(account:String, nickname:String):void { if (netConnection != null) { netConnection.call("unregister", null, account, nickname); } } public function attach(uuid:String):void { if (netConnection != null) { netConnection.call("attach", null, uuid); } } public function transfer(uuid:String, number:String):void { if (netConnection != null) { netConnection.call("transfer", null, uuid, number); } } public function three_way(uuid1:String, uuid2:String):void { if (netConnection != null) { netConnection.call("three_way", null, uuid1, uuid2); } } public function join(uuid1:String, uuid2:String):void { if (netConnection != null) { netConnection.call("join", null, uuid1, uuid2); } } public function sendevent(data:Object):void { if (netConnection != null) { netConnection.call("sendevent", null, data); } } public function getMic():int { return mic_index; } public function micList():Object { return JSON.encode(microphoneList); } public function setMic(index:int):void { mic_index = index; setupMic(); } public function isMuted():Boolean { if (mic != null) { return mic.muted; } else { return false; } } public function showPrivacy():void { Security.showSettings(SecurityPanel.PRIVACY); } public function login(username:String, password:String):void { if (netConnection != null) { netConnection.call("login", null, username, MD5.hash(sessionid + ":" + username + ":" + password)); } } public function logout(account:String):void { if (netConnection != null) { netConnection.call("logout", null, account); } } public function setVolume(value:Number):void { if (incomingNetStream != null) { var st:SoundTransform = new SoundTransform(value); incomingNetStream.soundTransform = st; } } public function setMicVolume(value:Number):void { if (outgoingNetStream != null) { var st:SoundTransform = new SoundTransform(value); outgoingNetStream.soundTransform = st; } } /********* FreeSWITCH functions *********/ /* XXX: TODO: Move those in a separate object so a malicious server can't setup streams and spy on the user */ public function connected(sid:String):void{ sessionid = sid; if (ExternalInterface.available) { ExternalInterface.call("onConnected", sid); } } public function onHangup(uuid:String, cause:String):void { if (ringUUID == uuid && ringChannel != null) { ringChannel.stop(); ringChannel = null; } if (ExternalInterface.available) { ExternalInterface.call("onHangup", uuid, cause); } } public function onLogin(result:String, user:String, domain:String):void { if (result == "success") { auth_user = user; auth_domain = domain; } if (ExternalInterface.available) { ExternalInterface.call("onLogin", result, user, domain); } } public function onLogout(user:String, domain:String):void { if (ExternalInterface.available) { ExternalInterface.call("onLogout", user, domain); } } public function onAttach(uuid:String):void { attachedUUID = uuid; if (ringChannel != null && uuid != "") { ringChannel.stop(); ringChannel = null; } if (attachedUUID == "") { destroyStreams(); } else if (incomingNetStream == null || outgoingNetStream == null) { setupStreams(); } if (ExternalInterface.available) { ExternalInterface.call("onAttach", uuid); } } public function onMakeCall(uuid:String, number:String, account:String):void { if (ExternalInterface.available) { ExternalInterface.call("onMakeCall", uuid, number, account); } } public function callState(uuid:String, state:String):void { if (ExternalInterface.available) { ExternalInterface.call("onCallState", uuid, state); } } public function displayUpdate(uuid:String, name:String, number:String):void { if (ExternalInterface.available) { ExternalInterface.call("onDisplayUpdate", uuid, name, number); } } public function incomingCall(uuid:String, name:String, number:String, account:String, evt:Object):void { if (attachedUUID == "" && ringChannel == null) { ringUUID = uuid; ringChannel = soundOfPhoneRinging.play(0, 3); } if (evt != null) { if (evt.hasOwnProperty("rtmp_auto_answer")) { if (evt.rtmp_auto_answer == "true") { answer(uuid); } } } if (ExternalInterface.available) { ExternalInterface.call("onIncomingCall", uuid, name, number, account, evt); } } public function event(event:Object):void { if (ExternalInterface.available) { ExternalInterface.call("onEvent", JSON.encode(event)); } } /********* Internal functions *********/ private function onDebug(message:String):void { //statusTxt.text = (statusTxt.text != "") ? statusTxt.text + "\n" + message : message; if (ExternalInterface.available) { ExternalInterface.call("onDebug", message); } } private function init():void { NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0; try { Security.allowDomain("*"); } catch(e:Error) { onDebug("Exception: " + e.toString()); } if (ExternalInterface.available) { try { ExternalInterface.marshallExceptions = true; ExternalInterface.addCallback("login", this.login); ExternalInterface.addCallback("logout", this.logout); ExternalInterface.addCallback("makeCall", this.makeCall); ExternalInterface.addCallback("attach", this.attach); ExternalInterface.addCallback("answer", this.answer); ExternalInterface.addCallback("hangup", this.hangup); ExternalInterface.addCallback("sendDTMF", this.sendDTMF); ExternalInterface.addCallback("register", this.register); ExternalInterface.addCallback("unregister", this.unregister); ExternalInterface.addCallback("transfer", this.transfer); ExternalInterface.addCallback("three_way", this.three_way); ExternalInterface.addCallback("getMic", this.getMic); ExternalInterface.addCallback("micList", this.micList); ExternalInterface.addCallback("setMic", this.setMic); ExternalInterface.addCallback("isMuted", this.isMuted); ExternalInterface.addCallback("showPrivacy", this.showPrivacy); ExternalInterface.addCallback("connect", this.connect); ExternalInterface.addCallback("disconnect", this.disconnect); ExternalInterface.addCallback("join", this.join); ExternalInterface.addCallback("sendevent", this.sendevent); ExternalInterface.addCallback("setVolume", this.setVolume); ExternalInterface.addCallback("setMicVolume", this.setMicVolume); //txtStatus.text = "Connecting..."; } catch(e:Error) { //txtStatus.text = e.toString(); onDebug("Exception: " + e.toString()); } } else { onDebug("ExternalInterface is disabled"); } try { microphoneList = Microphone.names; setupMic(); connect(); } catch(e:Error) { onDebug("Exception: " + e.toString()); } if (ExternalInterface.available) { ExternalInterface.call("onInit"); } } public function connect():void{ if (netConnection != null) { disconnect(); } netConnection = new NetConnection(); netConnection.client = this; netConnection.addEventListener( NetStatusEvent.NET_STATUS , netStatus ); netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); netConnection.connect(FlexGlobals.topLevelApplication.parameters.rtmp_url); } public function disconnect():void { if (netConnection != null) { netConnection.close(); netConnection = null; incomingNetStream = null; outgoingNetStream = null; } } private function destroyStreams():void { if (outgoingNetStream != null) { onDebug("Closing media streams") outgoingNetStream.close(); outgoingNetStream = null; } if (incomingNetStream != null) { incomingNetStream.close(); incomingNetStream = null; } } private function setupMic():void { try { mic = Microphone.getMicrophone(mic_index); mic.addEventListener(ActivityEvent.ACTIVITY, activityHandler); mic.addEventListener(StatusEvent.STATUS, statusHandler); mic.codec = SoundCodec.SPEEX; mic.setUseEchoSuppression(true); mic.setLoopBack(false); mic.setSilenceLevel(0,20000); mic.framesPerPacket = 1; mic.gain = 55; mic.rate = 16; mic_index = mic.index; if (outgoingNetStream != null) { outgoingNetStream.close(); outgoingNetStream = new NetStream(netConnection); outgoingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus); outgoingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler); outgoingNetStream.attachAudio(mic); outgoingNetStream.publish("publish", "live"); } } catch(e:Error) { onDebug("Couldn't setup microphone: " + e.message); } } private function setupStreams():void { onDebug("Setup media streams"); if (mic == null || mic.index != mic_index) { setupMic(); } incomingNetStream = new NetStream(netConnection); incomingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus); incomingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler); incomingNetStream.client = this; incomingNetStream.bufferTime = 0.2; incomingNetStream.play("play"); incomingNetStream.receiveAudio(true); outgoingNetStream = new NetStream(netConnection); outgoingNetStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus); outgoingNetStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler); outgoingNetStream.attachAudio(mic); outgoingNetStream.publish("publish", "live"); } private function onDisconnected():void { if (ExternalInterface.available) { ExternalInterface.call("onDisconnected"); } } private function securityErrorHandler(event:SecurityErrorEvent):void { onDebug("securityErrorHandler: " + event.text); } private function asyncErrorHandler(event:AsyncErrorEvent):void { onDebug("asyncErrorHandler: " + event.text); } private function activityHandler(event:ActivityEvent):void { onDebug("activityHandler: " + event); } private function statusHandler(event:StatusEvent):void { onDebug("statusHandler: " + event); } private function netStatus (evt:NetStatusEvent ):void { onDebug("netStatus: " + evt.info.code); switch(evt.info.code) { case "NetConnection.Connect.Success": //txtStatus.text = "Connected"; break; case "NetConnection.Connect.Failed": netConnection = null; incomingNetStream = null; outgoingNetStream = null; //btnCall.label = "Connect"; //txtStatus.text = "Failed"; onDisconnected(); break; case "NetConnection.Connect.Closed": netConnection = null; incomingNetStream = null; outgoingNetStream = null; //btnCall.label = "Connect"; //txtStatus.text = "Disconnected"; onDisconnected(); break; case "NetConnection.Connect.Rejected": netConnection = null; incomingNetStream = null; outgoingNetStream = null; //btnCall.label = "Connect"; //txtStatus.text = "Rejected"; onDisconnected(); break; case "NetStream.Play.StreamNotFound": break; case "NetStream.Play.Failed": break; case "NetStream.Play.Start": break; case "NetStream.Play.Stop": break; case "NetStream.Buffer.Full": break; default: } } ]]> </mx:Script> <!--<mx:Panel id="reader" title="Test" width="500"> <mx:TextArea width="500" color="#FF0000" id="statusTxt"/> </mx:Panel>--> </mx:Application>