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