Flash RED5 1.0录制问题NetStream.Buffer.Empty

Flash RED5 1.0录制问题NetStream.Buffer.Empty,flash,red5,recording,Flash,Red5,Recording,我已经在我的Windows8系统上安装了RED5 1.0 Final,我正在努力使录制正常工作。我读过的一篇教程说,在客户端(闪存中)缓冲数据,然后一旦缓冲区为空,关闭连接 我遇到的问题是,当我开始记录缓冲区时,会立即报告它是空的(NetStream.buffer.empty)。我曾经让它在缓冲区确实填满的地方工作过一两次,但由于某种原因,它停止了工作 我可以看到,即使在我将摄像头从netstream中分离出来之后,客户端仍在向服务器发送数据,因为服务器端的文件继续增长。我目前的解决方案是在录音

我已经在我的Windows8系统上安装了RED5 1.0 Final,我正在努力使录制正常工作。我读过的一篇教程说,在客户端(闪存中)缓冲数据,然后一旦缓冲区为空,关闭连接

我遇到的问题是,当我开始记录缓冲区时,会立即报告它是空的(NetStream.buffer.empty)。我曾经让它在缓冲区确实填满的地方工作过一两次,但由于某种原因,它停止了工作

我可以看到,即使在我将摄像头从netstream中分离出来之后,客户端仍在向服务器发送数据,因为服务器端的文件继续增长。我目前的解决方案是在录音停止后等待60秒,然后再关闭连接

有趣的是,当没有更多的数据包要发送时,我在服务器端看到文件从mystream.ser切换到mystream.flv并停止增长。我正在考虑在服务器端编写一些代码,等待事件发生,然后让客户端知道它可以关闭流

这是我第一次尝试动作脚本,所以我可能在这里做了一些完全错误的事情。请让我知道

编辑以下是客户端代码

<?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:ns1="*"
               minWidth="955" minHeight="600" applicationComplete="init()" >

    <fx:Script>
        <![CDATA[

            import flash.display.DisplayObject;
            import flash.display.Sprite;
            import flash.events.NetStatusEvent;
            import flash.media.Camera;
            import flash.media.H264Level;
            import flash.media.H264Profile;
            import flash.media.H264VideoStreamSettings;
            import flash.media.Video;
            import flash.net.NetConnection;
            import flash.net.NetStream;


            var cam:Camera = Camera.getCamera();
            var mic:Microphone = Microphone.getMicrophone();
            var nc:NetConnection = new NetConnection();
            var activeStream:NetStream;
            private var bufferCheckTimer:Timer;
            var recordHalted:Boolean = false;


            protected function init(): void{
                recordButton.enabled = false;
                stopButton.enabled = false;
                nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);            
                nc.connect("rtmp://localhost/oflaDemo");
                nc.client = this;
            }

            public function onMetaData(info:Object):void {

                trace("playback called onMetaData");        
            }

            public function onBWDone(... rest) : void {
                // have to have this for an RTMP connection
                trace('onBWDone');
            }

            public function onBWCheck(... rest) : uint {
                trace('onBWCheck');
                //have to return something, so returning anything :)
                return 0;
            }


            protected function onNetStatus(event:NetStatusEvent):void{
                trace(event.info.code);
                if(nc.connected)
                {
                    SetupCameraAndMic();
                    recordButton.enabled = true;
                    stopButton.enabled = true;
                }           
            }

            protected function SetupCameraAndMic(): void{
                activeStream = new NetStream(nc);
                activeStream.bufferTime = 60;   
                activeStream.client = this;
                activeStream.addEventListener(NetStatusEvent.NET_STATUS, handleStreamStatus,false,0,true);


                var h264Settings:H264VideoStreamSettings = new H264VideoStreamSettings();
                h264Settings.setProfileLevel(H264Profile.BASELINE, H264Level.LEVEL_2);
                activeStream.videoStreamSettings = h264Settings;

                cam.addEventListener(StatusEvent.STATUS, handleCameraStatus, false, 0, true);
                mic.addEventListener(StatusEvent.STATUS, handleMicrophoneStatus, false, 0, true);

                cam.setMode(320,240, 15);
                cam.setQuality(0, 80);
                cam.setKeyFrameInterval(7);

                mic.rate = 44;
                mic.gain = 75;
                mic.setSilenceLevel(0);
                mic.setUseEchoSuppression(true);



                activeStream.attachCamera(cam);
                activeStream.attachAudio(mic);  
                videoContainer.attachCamera(cam);






            }

            private function handleCameraStatus(e:StatusEvent):void {
                trace("handleCameraStatus - " + e.code);
                switch(e.code) {
                    case 'Camera.muted':
                        // Show a message
                        break;
                    case 'Camera.Unmuted':              
                        //finishCamAndMicSetup();
                        break;
                }
            }


            private function handleMicrophoneStatus(e:StatusEvent):void {
                trace("handleMicrophoneStatus - " + e.code);
                switch(e.code) {
                    case 'Microphone.Muted':
                        // Show a message
                        break;
                    case 'Microphone.Unmuted':              
                        //finishCamAndMicSetup();
                        break;
                }
            }


            private function handleStreamStatus(e:NetStatusEvent):void {
                switch(e.info.code) {
                    case 'NetStream.Buffer.Empty':
                        trace("NetStream.Buffer.Empty");
                        break;
                    case 'NetStream.Buffer.Full':
                        trace("NetStream.Buffer.Full");
                        break;
                    case 'NetStream.Buffer.Flush':
                        trace("NetStream.Buffer.Flush");
                        break;
                }
            }

            protected function recordButton_clickHandler(event:MouseEvent):void
            {
                if(activeStream == null)
                {
                    SetupCameraAndMic();
                }
                if(activeStream != null){
                    var tempDate:Date = new Date();
                    var uniqueFileName:String = "RecordME_" + String(tempDate.getMinutes()) + String(tempDate.getMilliseconds());

                    bufferLabel.text = ""+ activeStream.bufferTime;
                    activeStream.publish(uniqueFileName, "record");
                    bufferCheckTimer = new Timer(100);
                    bufferCheckTimer.addEventListener(TimerEvent.TIMER, handleBufferCheck, false, 0, true);
                    bufferCheckTimer.start();

                }

            }

            private function handleBufferCheck(e:TimerEvent):void {
                if(activeStream != null) {
                    trace("Buffer: " + activeStream.bufferLength);
                    statusLabel.text = "Buffer: " + activeStream.bufferLength;
                    if (recordHalted == true) {
                        if ( activeStream.bufferLength == 0 ) {
                            activeStream.close();
                            activeStream = null;



                            bufferCheckTimer.stop();
                            bufferCheckTimer.removeEventListener(TimerEvent.TIMER, handleBufferCheck);
                            bufferCheckTimer = null;

                            // OK - playback time
                            //doRecordingPlayback();
                        }
                    }


                if (bufferCheckTimer != null) {
                    bufferCheckTimer.reset();
                    bufferCheckTimer.start();
                }
            }
            }

            protected function stopButton_clickHandler(event:MouseEvent):void
            {

                activeStream.attachCamera(null);
                activeStream.attachAudio(null); 
                videoContainer.attachCamera(null);                      
                recordHalted = true;

            }

        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <mx:VideoDisplay id="videoContainer" x="158" y="53" width="640" height="480"
                    chromeColor="#3C2020" />
    <s:Button id="recordButton" x="396" y="546" label="Record"
              click="recordButton_clickHandler(event)"/>
    <s:Button id="stopButton" x="491" y="546" label="Stop Recording"
              click="stopButton_clickHandler(event)"/>
    <s:Label id="statusLabel" x="158" y="555" width="207"/>
    <s:Label x="14" y="408" text="Buffer Set to:"/>
    <s:Label id="bufferLabel" x="91" y="408" text="0"/>
</s:Application>


谢谢

我现在没有正在运行的RTMP服务器,所以我只是对我在您的代码中看到的内容进行评论

我认为在发布(录制)流时,您得到的关于先缓冲内容的建议可能不是一个好主意。也许本教程不是关于发布,而是订阅现有流,在这种情况下,缓冲是一个好主意

您正在将
缓冲时间设置为60秒。他们说,对于实时录制,您应该将
bufferTime
设置为0。也就是说,您希望在摄像头/麦克风生成数据后立即发送数据

接下来是您正在使用的
计时器。这似乎是在检查缓冲区长度,以检测录制是否已停止。实际上只有两种情况会停止录制:

  • 当用户单击“停止”按钮时,您的代码会将其停止
  • 服务器或其他东西导致其停止的任何场景(网络问题等)
我建议您使用
NetStatusEvent
处理程序方法(
handleStreamStatus()
)检查消息“NetStream.Record.Stop”,而不是使用计时器检查
缓冲区长度。这允许您的代码检测录制何时因用户单击“停止”以外的其他原因停止

计时器可能是问题的原因。即使您已经设置了一个大的
bufferTime
值,它在红色5服务器上也可能无法工作或表现不同,或者可能会被服务器端设置覆盖。无论如何,关键是不要使用
bufferLength
来检测录制是否已停止

有许多是随
NetStatusEvent
一起发送的,我建议您仔细阅读它们,看看它们中是否有对您的场景有用的。他们相当可靠,似乎能处理几乎所有可能出现的情况

我注意到的最后一件事(不是问题,但值得纠正):您在麦克风上启用回声抑制,但除非您使用增强型麦克风,否则将无法工作:

var mic:Microphone = Microphone.getEnhancedMicrophone();

我认为这是RED5最终版本V1.0中的一个bug造成的。我恢复到0.80版本,我可以记录良好

通过更改队列阈值,录制在Red5 V1.0.2上运行良好。我看到一个叫jobma的人录得很好。似乎他们正在使用red5,如果没有看到您的客户机代码,他们真的帮不上忙。我们需要看看你在做什么来设置/启动录音。感谢Sunil的详细回复,我非常感谢。我将尝试使用NetStream.Record.Stop而不是现有的计时器方法,并很快作出响应。我一直在关注这两个地方的教程,它们都提到使用长度为60.5的缓冲区。我曾经处理过几个应用程序,在这些应用程序中,我们在录制时没有缓冲任何内容。我不确定在这种情况下缓冲的好处是什么。例如,您当然不希望在“实时视频聊天”应用程序中使用缓冲区。但它可能在其他场景中有一些用途。问题是如果没有缓冲区,我只是关闭流,保存的视频只是完整录制的一小段。我注意到的是,当我停止录制并设置activeStream.Attachudio(null)和activeStream.attachCamera(null)时服务器停止接收数据包,但继续将FLV文件写入磁盘。因此,问题可能不在客户端,因为red5拥有所有数据包。文件写入磁盘后,我才能关闭activeStream。我尝试等待Record.Stop事件,但只有在执行activeStream.close后才会触发该事件。