Search code examples
apache-flexlive-streamingflex-sparkvideodisplay

Flex: Restore Spark VideoDisplay stream


EDIT If someone can at least tell me how to receive an event when the streams disconnects that would be great.

The documentation for this control is simply horrible. I have an application that will have a live video stream and I'm looking for a way to make the VideoDisplay control restore its connection in case of the occurrence of any of these specific scenarios:

  1. The application starts and the stream is not online yet.
  2. The application is streaming and the user is disconnected from the internet.
  3. The application is streaming and the video server crashes and reboots.

I'm using Wowza Media Server and Wirecast to test this. 1 and 3 don't work, I'm not sure number 2 does. I made number 1 work by adding this very questionable piece of code:

    protected function onMediaPlayerStateChange(event:MediaPlayerStateChangeEvent):void
    {
        if (event.state == MediaPlayerState.PLAYBACK_ERROR)
        {
            var videoSource:DynamicStreamingVideoSource = this.videoDisplay.source as DynamicStreamingVideoSource;

            try
            {
                this.videoDisplay.source = null;
                this.videoDisplay.source = videoSource;
            }
            catch (any:*) {}
        }
    }

As you can see I need a try/catch block since both calls to source cause exceptions, yet whatever happens before those exceptions seems to fix problem #1. This doesn't fix problem #3 because a media state change event apparently doesn't occur when you stop the video server.

This is my control declaration:

<s:VideoDisplay id="videoDisplay" click="onVideoStreamClick(event)" mediaPlayerStateChange="onMediaPlayerStateChange(event)" muted="{this.videoMuted}" top="10" width="280" height="220" autoPlay="true" horizontalCenter="0">
    <s:source>
        <s:DynamicStreamingVideoSource id="videoSource" streamType="live" host="{FlexGlobals.topLevelApplication.parameters.videoStreamURL}">
            <s:DynamicStreamingVideoItem id="videoItemLow" streamName="{FlexGlobals.topLevelApplication.parameters.videoLow}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoLowBitrate}" />
            <s:DynamicStreamingVideoItem id="videoItemMedium" streamName="{FlexGlobals.topLevelApplication.parameters.videoMedium}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoMediumBitrate}" />
            <s:DynamicStreamingVideoItem id="videoItemHigh" streamName="{FlexGlobals.topLevelApplication.parameters.videoHigh}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoHighBitrate}" />
        </s:DynamicStreamingVideoSource>
    </s:source>
</s:VideoDisplay>

Does anyone know how to make the VideoDisplay recover from these issues? Any help is appreciated, thanks.


Solution

  • If anyone has this problem, this is how I solved it. You need to set the video source to a blank image in order to stop the streaming, otherwise it will never, ever stop. This solution works for all scenarios described above:

        private function resetVideo():void
        {           
            //save current source object
            this.videoEventsDisabled = true;
            var videoSource:DynamicStreamingVideoSource = this.videoDisplay.source as DynamicStreamingVideoSource;
    
            try //switch to blank image, only this will stop the video stream
            {
                this.videoDisplay.source = "assets/images/video_offline.png";
            }
            catch (any:*) {}
    
            //wait a few seconds and reset video source
            setTimeout(resetVideoSource, 2000, videoSource);
        }
    
        private function resetVideoSource(videoSource:DynamicStreamingVideoSource):void
        {
            this.videoEventsDisabled = false;
            this.videoDisplay.source = videoSource;
        }
    
        protected function onMediaPlayerStateChange(event:MediaPlayerStateChangeEvent):void
        {
            if (this.videoEventsDisabled)
            {
                return;
            }
    
            //something went wrong
            if (event.state == MediaPlayerState.PLAYBACK_ERROR)
            {
                resetVideo();
            }
        }
    
        protected function onCurrentTimeChange(event:TimeEvent):void
        {
            if (this.videoEventsDisabled)
            {
                return;
            }
    
            //if there was a number before, and its suddendly NaN, video is offline
            if (isNaN(event.time) && !isNaN(this.previousVideoTime))
            {
                resetVideo();
            }
            else //store event time for future comparisons
            {
                this.previousVideoTime = event.time;
            }
        }
    

    MXML:

    <s:VideoDisplay id="videoDisplay" click="onVideoStreamClick(event)" mediaPlayerStateChange="onMediaPlayerStateChange(event)" currentTimeChange="onCurrentTimeChange(event)" muted="{this.videoMuted}" top="10" width="280" height="220" autoPlay="true" horizontalCenter="0">
        <s:source>
            <s:DynamicStreamingVideoSource id="videoSource" streamType="live" host="{FlexGlobals.topLevelApplication.parameters.videoStreamURL}">
                <s:DynamicStreamingVideoItem id="videoItemLow" streamName="{FlexGlobals.topLevelApplication.parameters.videoLow}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoLowBitrate}" />
                <s:DynamicStreamingVideoItem id="videoItemMedium" streamName="{FlexGlobals.topLevelApplication.parameters.videoMedium}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoMediumBitrate}" />
                <s:DynamicStreamingVideoItem id="videoItemHigh" streamName="{FlexGlobals.topLevelApplication.parameters.videoHigh}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoHighBitrate}" />
            </s:DynamicStreamingVideoSource>
        </s:source>
    </s:VideoDisplay>