airsdk / Adobe-Runtime-Support

Report, track and discuss issues in Adobe AIR. Monitored by Adobe - and HARMAN - and maintained by the AIR community.
204 stars 11 forks source link

Crackling sound on `NetStream` stop #3260

Open itlancer opened 5 months ago

itlancer commented 5 months ago

Problem Description

NetStream stop via NetStream::close() or NetStream::dispose() cause sound crackling. May be under hood AIR should send some extra data at NetStream::close() or NetStream::dispose() to audio decoder to prevent such behavior.

Reproduced with multiple AIR versions, even with latest AIR 51.0.1.1 with multiple different platforms (Windows, macOS, Android, iOS) with different devices, applications and videos. Same issue in all cases. But with some audio devices (or audio drivers) and some videos/sound it not noticeable. There is no such issue using many other (non-AIR) video/audio applications, especially wich uses ffmpeg. Setting SoundTransform::volume to 0 just before NetStream::close() or NetStream::dispose() didn't help. Playing with NetStreamAppendBytesAction.END_SEQUENCE just before NetStream::close() or NetStream::dispose() didn't help. Didn't test with FLV videos. Didn't test with Sound.

Related issues: https://github.com/airsdk/Adobe-Runtime-Support/issues/1939 https://github.com/airsdk/Adobe-Runtime-Support/issues/224 https://github.com/airsdk/Adobe-Runtime-Support/issues/211 https://github.com/airsdk/Adobe-Runtime-Support/issues/202 https://github.com/airsdk/Adobe-Runtime-Support/issues/155 https://github.com/airsdk/Adobe-Runtime-Support/issues/15

Steps to Reproduce

Launch application with code below. It just play video with audio in a loop. Click anywhere on stage to restart video (it will be stopped and new one started). You need to click in a "correct" moment to hear crackling noticeable and clear. Please take a look at demonstration video below.

Application example with sources and video sample attached. netstream_stop_crackling_bug.zip

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.media.Video;
    import flash.events.NetStatusEvent;
    import flash.desktop.SystemIdleMode;
    import flash.filesystem.File;
    import flash.events.MouseEvent;

    public class NetStreamStopCracklingBug extends Sprite {
        private var nc:NetConnection;
        private var ns:NetStream;
        private var video:Video = new Video(640, 480);

        public function NetStreamStopCracklingBug() {
            addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            addChild(video);

            stage.addEventListener(MouseEvent.CLICK, click);

            restartVideo();
        }

        private function click(e:MouseEvent):void {
            trace("click");
            restartVideo();
        }

        private function restartVideo():void {
            if (ns != null){
                ns.removeEventListener(NetStatusEvent.NET_STATUS, nsHandler);

                //These two lines cause audio crackling
                ns.close();
                ns.dispose();
            }
            if (nc != null){
                nc.removeEventListener(NetStatusEvent.NET_STATUS, ncHandler);
                nc.close();
            }

            nc = new NetConnection();
            nc.addEventListener(NetStatusEvent.NET_STATUS, ncHandler);
            nc.connect(null);
        }

        private function ncHandler(e:NetStatusEvent):void {
            if (e.info.code == "NetConnection.Connect.Success"){
                ns = new NetStream(nc);
                ns.client = {onMetaData:getMeta};
                ns.addEventListener(NetStatusEvent.NET_STATUS, nsHandler);
                video.attachNetStream(ns);

                ns.play("video.mp4");
            }
        }

        private function nsHandler(e:NetStatusEvent):void {
            trace(e.info.code);
            if (e.info.code == "NetStream.Play.Stop"){
                ns.play("video.mp4");
            }
        }

        private function getMeta(mdata:Object):void { }

    }
}

Actual Result: Audio crackling at video restart (NetStream::close() or NetStream::dispose() call). Video demonstration:

https://github.com/airsdk/Adobe-Runtime-Support/assets/10899066/342a0636-a2b2-48ca-82f5-a55544d32998

Expected Result: No audio crackling at video restart (or stop).

Known Workarounds

1) After video playback change volume to mute (via soundTransform), wait ~30 frames (via ENTER_FRAME) and only after call NetStream::dispose(). 2) Write your own native extension to play video.

itlancer commented 3 months ago

Found workaround. After video playback change volume to mute (via soundTransform), wait ~30 frames (via ENTER_FRAME) and only after call NetStream::dispose(). But for iOS it doesn't work. Seems this issue https://github.com/airsdk/Adobe-Runtime-Support/issues/15#issuecomment-2249029466