Difference between revisions of "Test LiveFeed"
(→LiveFeed Test) |
|||
Line 45: | Line 45: | ||
</body> | </body> | ||
</html> | </html> | ||
+ | ==2== | ||
+ | <html><?xml version="1.0" encoding="utf-8"?> | ||
+ | <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" | ||
+ | xmlns:s="library://ns.adobe.com/flex/spark" | ||
+ | xmlns:mx="library://ns.adobe.com/flex/mx" | ||
+ | xmlns:views="rtmfptest.views.*" | ||
+ | backgroundColor="#F2F0F0" | ||
+ | width="450" | ||
+ | height="592" creationComplete="init()" xmlns:local="*"> | ||
+ | <fx:Declarations> | ||
+ | |||
+ | </fx:Declarations> | ||
+ | |||
+ | <fx:Style> | ||
+ | .header { | ||
+ | fontSize: 36px; | ||
+ | } | ||
+ | </fx:Style> | ||
+ | |||
+ | <fx:Script> | ||
+ | <![CDATA[ | ||
+ | import mx.core.UIComponent; | ||
+ | import mx.utils.StringUtil; | ||
+ | private var nc:NetConnection; | ||
+ | private var cam:Camera; | ||
+ | private var mic:Microphone; | ||
+ | private var videoFarEnd:Video; | ||
+ | private var publishStream:NetStream; | ||
+ | private var subscribeStream:NetStream; | ||
+ | private var subscribeStreamObject:Object; | ||
+ | |||
+ | private function init():void{ | ||
+ | |||
+ | if (ExternalInterface.available) { | ||
+ | try { | ||
+ | var href:String = ExternalInterface.call("window.location.href.toString"); | ||
+ | var hostname:String = ExternalInterface.call("window.location.hostname.toString"); | ||
+ | connectUrl.text = "rtmp://" + hostname + ":1935"; | ||
+ | } catch (error:Error) { | ||
+ | Logger.info(error.message); | ||
+ | } | ||
+ | } else { | ||
+ | Logger.info("Error during set callback"); | ||
+ | } | ||
+ | cam = Camera.getCamera(); | ||
+ | videoMy.attachCamera(cam); | ||
+ | mic = Microphone.getEnhancedMicrophone(); | ||
+ | videoFarEnd = new Video(); | ||
+ | var container:UIComponent = new UIComponent(); | ||
+ | container.addChild(videoFarEnd); | ||
+ | canvas.addChild(container); | ||
+ | playBtn.enabled = false; | ||
+ | publishBtn.enabled = false; | ||
+ | stopBtn.visible = false; | ||
+ | unpublishBtn.visible = false; | ||
+ | disconnectBtn.visible = false; | ||
+ | var streamName:String = generateRandomString(4); | ||
+ | publishStreamName.text = "Stream-"+streamName; | ||
+ | playStreamName.text = "Stream-"+streamName; | ||
+ | |||
+ | } | ||
+ | |||
+ | // Reset button's state, clear status | ||
+ | private function reset():void { | ||
+ | connectBtn.visible = true; | ||
+ | disconnectBtn.visible = false; | ||
+ | |||
+ | unpublishBtn.visible = false; | ||
+ | |||
+ | publishBtn.enabled = false; | ||
+ | publishBtn.visible = true; | ||
+ | |||
+ | playBtn.visible = true; | ||
+ | playBtn.enabled = false; | ||
+ | |||
+ | stopBtn.visible = false; | ||
+ | |||
+ | setPublishStatus(""); | ||
+ | setPlayStatus(""); | ||
+ | } | ||
+ | |||
+ | private function initCam():void{ | ||
+ | cam.setMode(int(camWidth.text),int(camHeight.text),int(camFPS.text),true); | ||
+ | cam.setQuality(0,int(camQuality.text)); | ||
+ | cam.setKeyFrameInterval(int(camKeyFrame.text)); | ||
+ | cam.setMotionLevel(0,2000); | ||
+ | Logger.info("Cam initizlized "+cam.width+"x"+cam.height); | ||
+ | } | ||
+ | |||
+ | private function initMic():void{ | ||
+ | var options:MicrophoneEnhancedOptions = new MicrophoneEnhancedOptions(); | ||
+ | options.mode = MicrophoneEnhancedMode.FULL_DUPLEX; | ||
+ | options.echoPath = 128; | ||
+ | options.nonLinearProcessing = true; | ||
+ | mic.codec = SoundCodec.SPEEX; | ||
+ | mic.encodeQuality = 5; | ||
+ | mic.framesPerPacket=1; | ||
+ | mic.gain=50; | ||
+ | mic.setSilenceLevel(0,2000); | ||
+ | mic.enhancedOptions = options; | ||
+ | Logger.info("Mic initialized"); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * ************************** | ||
+ | * CONNECT / DISCONNECT | ||
+ | * ************************** | ||
+ | **/ | ||
+ | private function connect():void{ | ||
+ | var url:String = StringUtil.trim(connectUrl.text); | ||
+ | Logger.info("connect " + url); | ||
+ | nc = new NetConnection(); | ||
+ | //if (url.indexOf("rtmp") == 0){ | ||
+ | // nc.objectEncoding = ObjectEncoding.AMF0; | ||
+ | //} | ||
+ | nc.client = this; | ||
+ | nc.addEventListener(NetStatusEvent.NET_STATUS, handleConnectionStatus); | ||
+ | var obj:Object = new Object(); | ||
+ | obj.login = generateRandomString(20); | ||
+ | obj.appKey = "flashStreamingApp"; | ||
+ | nc.connect(url,obj); | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | //disconnect | ||
+ | private function disconnect():void{ | ||
+ | Logger.info("disconnect"); | ||
+ | nc.close(); | ||
+ | } | ||
+ | |||
+ | private function handleConnectionStatus(event:NetStatusEvent):void{ | ||
+ | Logger.info("handleConnectionStatus: "+event.info.code); | ||
+ | if (event.info.code=="NetConnection.Connect.Success"){ | ||
+ | Logger.info("near id: "+nc.nearID); | ||
+ | Logger.info("far id: "+nc.farID); | ||
+ | Logger.info("Connection opened"); | ||
+ | disconnectBtn.visible = true; | ||
+ | connectBtn.visible = false; | ||
+ | playBtn.enabled = true; | ||
+ | publishBtn.enabled = true; | ||
+ | setConnectionStatus("CONNECTED"); | ||
+ | } else if (event.info.code=="NetConnection.Connect.Closed" || event.info.code=="NetConnection.Connect.Failed"){ | ||
+ | nc.removeEventListener(NetStatusEvent.NET_STATUS,handleConnectionStatus); | ||
+ | unpublish(); | ||
+ | stop(); | ||
+ | Logger.info("Connection closed"); | ||
+ | setConnectionStatus("DISCONNECTED"); | ||
+ | reset(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private function setConnectionStatus(event:String): void { | ||
+ | connectionStatus.text = event; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * ************************* | ||
+ | * PUBLISH / UNPUBLISH | ||
+ | * ************************* | ||
+ | **/ | ||
+ | private function publish():void{ | ||
+ | if (publishStreamName.text == "") { | ||
+ | publishStatus.text = "Empty stream name"; | ||
+ | publishStatus.setStyle("color","#FF0000"); | ||
+ | return; | ||
+ | } | ||
+ | publishStatus.setStyle("color","#000000"); | ||
+ | Logger.info("publish audio: "+publishAudio.selected+" video: "+publishVideo.selected); | ||
+ | publishStream = new NetStream(nc); | ||
+ | if (publishAudio.selected){ | ||
+ | initMic(); | ||
+ | publishStream.attachAudio(mic); | ||
+ | Logger.info("Init audio stream"); | ||
+ | } | ||
+ | if (publishVideo.selected){ | ||
+ | initCam(); | ||
+ | publishStream.attachCamera(cam); | ||
+ | addH264(); | ||
+ | Logger.info("Init video stream"); | ||
+ | } | ||
+ | addListenerAndPublish(); | ||
+ | Logger.info("Publishing"); | ||
+ | |||
+ | } | ||
+ | |||
+ | //unpublish | ||
+ | private function unpublish():void{ | ||
+ | Logger.info("unpublish"); | ||
+ | if (publishStream!=null){ | ||
+ | publishStream.close(); | ||
+ | } | ||
+ | videoFarEnd.clear(); | ||
+ | } | ||
+ | |||
+ | private function addListenerAndPublish():void{ | ||
+ | publishStream.videoReliable=true; | ||
+ | publishStream.audioReliable=false; | ||
+ | publishStream.useHardwareDecoder=true; | ||
+ | publishStream.addEventListener(NetStatusEvent.NET_STATUS, handleStreamStatus); | ||
+ | publishStream.bufferTime=0; | ||
+ | publishStream.publish(publishStreamName.text); | ||
+ | } | ||
+ | |||
+ | public function addH264():void{ | ||
+ | var videoStreamSettings:H264VideoStreamSettings = new H264VideoStreamSettings(); | ||
+ | videoStreamSettings.setProfileLevel(H264Profile.MAIN,H264Level.LEVEL_3_1); | ||
+ | publishStream.videoStreamSettings = videoStreamSettings; | ||
+ | } | ||
+ | |||
+ | private function setPublishStatus(event:String): void { | ||
+ | publishStatus.text = event; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * ************************* | ||
+ | * PLAY / STOP | ||
+ | * ************************* | ||
+ | **/ | ||
+ | private function play():void{ | ||
+ | if (playStreamName.text == "") { | ||
+ | playStatus.text = "Empty stream name"; | ||
+ | playStatus.setStyle("color","#ff0000"); | ||
+ | return; | ||
+ | } | ||
+ | playBtn.enabled = false; | ||
+ | playStatus.setStyle("color","#000000"); | ||
+ | Logger.info("play"); | ||
+ | subscribeStream = new NetStream(nc); | ||
+ | addListenerAndPlay(); | ||
+ | } | ||
+ | |||
+ | private function stop():void{ | ||
+ | if (subscribeStream != null) { | ||
+ | stopBtn.enabled = false; | ||
+ | subscribeStream.close(); | ||
+ | subscribeStream = null; | ||
+ | } | ||
+ | subscribeStreamObject = null; | ||
+ | videoFarEnd.visible = false; | ||
+ | } | ||
+ | |||
+ | private function addListenerAndPlay():void{ | ||
+ | subscribeStream.videoReliable=true; | ||
+ | subscribeStream.audioReliable=false; | ||
+ | subscribeStream.useHardwareDecoder=true; | ||
+ | subscribeStream.addEventListener(NetStatusEvent.NET_STATUS, handleSubscribeStreamStatus); | ||
+ | if (playStreamName.text.indexOf("rtsp://") != -1) { | ||
+ | subscribeStream.bufferTime=0.5; | ||
+ | } else { | ||
+ | subscribeStream.bufferTime=0.0; | ||
+ | } | ||
+ | var soundTransform:SoundTransform = new SoundTransform(); | ||
+ | soundTransform.volume=0.7; | ||
+ | subscribeStream.soundTransform = soundTransform; | ||
+ | subscribeStreamObject = createStreamObject(); | ||
+ | subscribeStream.play(playStreamName.text); | ||
+ | videoFarEnd.attachNetStream(subscribeStream); | ||
+ | videoFarEnd.width = 320; | ||
+ | videoFarEnd.height = 240; | ||
+ | videoFarEnd.visible = true; | ||
+ | } | ||
+ | |||
+ | private function createStreamObject():Object{ | ||
+ | var ret:Object = new Object(); | ||
+ | ret.mediaSessionId = generateRandomString(8); | ||
+ | ret.name = playStreamName.text; | ||
+ | return ret; | ||
+ | } | ||
+ | |||
+ | private function generateRandomString(strlen:Number):String{ | ||
+ | var chars:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
+ | var num_chars:Number = chars.length - 1; | ||
+ | var randomChar:String = ""; | ||
+ | |||
+ | for (var i:Number = 0; i < strlen; i++){ | ||
+ | randomChar += chars.charAt(Math.floor(Math.random() * num_chars)); | ||
+ | } | ||
+ | return randomChar; | ||
+ | } | ||
+ | |||
+ | private function setPlayStatus(event:String): void { | ||
+ | playStatus.text = event; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * **************************** | ||
+ | * HANDLE CONNECTION STATE | ||
+ | * **************************** | ||
+ | **/ | ||
+ | |||
+ | private function handleStreamStatus(event:NetStatusEvent):void{ | ||
+ | Logger.info("handleStreamStatus: "+event.info.code); | ||
+ | switch (event.info.code) { | ||
+ | case "NetStream.Failed": | ||
+ | Logger.info("Publish failed"); | ||
+ | if (publishStream!=null){ | ||
+ | publishStream.close(); | ||
+ | publishStream.removeEventListener(NetStatusEvent.NET_STATUS, handleStreamStatus); | ||
+ | publishStream=null; | ||
+ | } | ||
+ | videoFarEnd.clear(); | ||
+ | setPublishStatus("PUBLISH STREAM FAILED"); | ||
+ | break; | ||
+ | case "NetStream.Publish.BadName": | ||
+ | Logger.info("Bad streamName. Please publish stream with other name"); | ||
+ | setPublishStatus("PUBLISH STREAM FAILED"); | ||
+ | break; | ||
+ | case "NetStream.Unpublish.Success": | ||
+ | publishStream.removeEventListener(NetStatusEvent.NET_STATUS, handleStreamStatus); | ||
+ | publishStream=null; | ||
+ | setPublishStatus("UNPUBLISHED"); | ||
+ | publishBtn.visible = true; | ||
+ | unpublishBtn.visible = false; | ||
+ | break; | ||
+ | case "NetStream.Publish.Start": | ||
+ | setPublishStatus("PUBLISHING"); | ||
+ | publishBtn.visible = false; | ||
+ | unpublishBtn.visible = true; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private function handleSubscribeStreamStatus(event:NetStatusEvent):void{ | ||
+ | Logger.info("handleSubscribeStreamStatus: "+event.info.code); | ||
+ | switch (event.info.code) { | ||
+ | case "NetStream.Play.PublishNotify": | ||
+ | case "NetStream.Play.Start": | ||
+ | setPlayStatus("PLAYING"); | ||
+ | playBtn.visible = false; | ||
+ | stopBtn.enabled = true; | ||
+ | stopBtn.visible = true; | ||
+ | break; | ||
+ | case "NetStream.Play.UnpublishNotify": | ||
+ | case "NetStream.Play.Stop": | ||
+ | setPlayStatus("STOPPED"); | ||
+ | playBtn.enabled = true; | ||
+ | playBtn.visible = true; | ||
+ | stopBtn.visible = false; | ||
+ | break; | ||
+ | case "NetStream.Play.StreamNotFound": | ||
+ | setPlayStatus("STREAM NOT FOUND"); | ||
+ | playBtn.enabled = true; | ||
+ | playBtn.visible = true; | ||
+ | stopBtn.visible = false; | ||
+ | break; | ||
+ | case "NetStream.Play.Failed": | ||
+ | setPlayStatus("STREAM FAILED"); | ||
+ | playBtn.enabled = true; | ||
+ | playBtn.visible = true; | ||
+ | stopBtn.visible = false; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private function asyncErrorHandler(event: AsyncErrorEvent):void{ | ||
+ | Logger.info("asyncErrorHandler: "+event); | ||
+ | } | ||
+ | |||
+ | private function securityErrorHandler(event: SecurityErrorEvent):void{ | ||
+ | Logger.info("securityErrorHandler: "+event); | ||
+ | } | ||
+ | public function ping():void{ | ||
+ | nc.call("pong", null); | ||
+ | } | ||
+ | |||
+ | public function OnDataEvent(data:Object):void{ | ||
+ | var message:Object = data.payload; | ||
+ | Logger.info(message.body); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | ************************* | ||
+ | * JavaScript callbacks | ||
+ | ************************* | ||
+ | **/ | ||
+ | |||
+ | private function getDataFromJS(value:String):void { | ||
+ | if (value != null || value != "") { | ||
+ | connectUrl.text = value; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ]]> | ||
+ | </fx:Script> | ||
+ | <s:Label x="96" y="34" width="265" styleName="header" text="Flash Streaming"/> | ||
+ | <!-- connect / disconnect --> | ||
+ | <s:Button id="connectBtn" x="325" y="93" width="90" label="Login" click="connect()"/> | ||
+ | <s:TextInput id="publishStreamName" x="99" y="143" width="199" text="StreamName"/> | ||
+ | <s:Button id="disconnectBtn" x="325" y="93" label="Logout" click="disconnect()" width="90" enabled="true"/> | ||
+ | <s:TextInput id="connectUrl" x="99" y="93" width="200"/> | ||
+ | |||
+ | <!-- publish / unpublish --> | ||
+ | <s:Button id="publishBtn" x="326" y="143" label="Start" width="90" height="21" click="publish()" enabled="true"/> | ||
+ | <s:CheckBox id="publishAudio" x="146" y="505" label="audio" selected="true" /> | ||
+ | <s:CheckBox id="publishVideo" x="223" y="505" label="video" selected="true"/> | ||
+ | |||
+ | <s:Label x="120" y="561" text="width"/> | ||
+ | <s:TextInput id="camWidth" x="120" y="531" width="32" text="320"/> | ||
+ | |||
+ | <s:Label x="159" y="561" text="height"/> | ||
+ | <s:TextInput id="camHeight" x="160" y="531" width="31" text="240"/> | ||
+ | |||
+ | <s:Label x="206" y="561" text="fps"/> | ||
+ | <s:TextInput id="camFPS" x="200" y="531" width="31" text="15"/> | ||
+ | |||
+ | <s:Label x="240" y="561" text="quality"/> | ||
+ | <s:TextInput id="camQuality" x="240" y="531" width="31" text="80"/> | ||
+ | |||
+ | <s:Label x="279" y="561" text="keyframe"/> | ||
+ | <s:TextInput id="camKeyFrame" x="280" y="531" width="31" text="15"/> | ||
+ | |||
+ | <!-- play / stop --> | ||
+ | <s:Button id="playBtn" x="325" y="193" label="Start" width="90" height="21" click="play()" enabled="true"/> | ||
+ | |||
+ | <!-- video view --> | ||
+ | <mx:Canvas id = "canvas" visible="true" x="65" y="257" width="320" height="240"> | ||
+ | <mx:VideoDisplay id="videoMy" visible="true" x="0" y="0" width="80" height="60" chromeColor="#EEA1A1"/> | ||
+ | </mx:Canvas> | ||
+ | <s:Label x="35" y="143" width="56" height="22" text="Publish" verticalAlign="middle"/> | ||
+ | <s:Label x="35" y="93" width="89" height="22" text="Server:" verticalAlign="middle"/> | ||
+ | <s:TextInput id="playStreamName" x="99" y="193" width="199" text="StreamName"/> | ||
+ | <s:Label x="35" y="193" height="22" text="Play" verticalAlign="middle"/> | ||
+ | <s:Button id="unpublishBtn" x="326" y="143" label="Stop" click="unpublish()" width="90" enabled="true"/> | ||
+ | <s:Button id="stopBtn" x="325" y="193" label="Stop" width="90" height="21" click="stop()" enabled="true"/> | ||
+ | <s:Label id="connectionStatus" x="123" y="119" width="150" height="20" textAlign="center" | ||
+ | verticalAlign="top"/> | ||
+ | <s:Label id="publishStatus" x="123" y="169" width="150" height="20" textAlign="center" | ||
+ | verticalAlign="middle"/> | ||
+ | <s:Label id="playStatus" x="123" y="219" width="150" height="20" textAlign="center" | ||
+ | verticalAlign="middle"/> | ||
+ | </s:Application></html> |
Revision as of 18:39, 4 September 2018
LiveFeed Test
<!DOCTYPE html>
2