0
votes

I would like get access to the audio samples being played from an AAC streaming radio station and perform some signal processing function on them before sending them on to the renderer.

I was able to get access to the byte stream using the URLStream ProgressEvent.PROGRESS callback. Within that callback I originally called urlStream.readBytes(Bytes) followed by netStream.appendBytes(Bytes). The audio would play for some number of seconds then stop with a netStatus of NetStream.Buffer.Empty.

I put a trace in my ProgressEvent handler to show the netStream.bufferLength and saw that this initially got bigger then get forever smaller until the buffer was empty. I've searched for information on what might be needed to throttle the buffer but nothing I found worked.

Interestingly, when I issue a netStream.play(url) rather than the netStream.play(null), which is needed for enabling the ProgressEvent handler, the audio plays fine but I have no visibility to the underlying audio samples.

So my question boils down to: How do I get access to the underlying audio samples and keep the buffer from becoming empty?

package
{
    import flash.display.Sprite;

    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.NetStreamAppendBytesAction;
    import flash.net.NetStreamPlayOptions;
    import flash.net.NetStreamInfo;

    import flash.events.NetStatusEvent;
    import flash.events.AsyncErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.Event;

    import flash.net.URLRequest;
    import flash.net.URLStream;

    import flash.utils.*;

    public class Main extends Sprite
    {
        private var connection:NetConnection = new NetConnection();
        private var netStream:NetStream = null;
        private var urlStream:URLStream = null;
        private var urlRequest:URLRequest = null;

        private var inputSamples:ByteArray = new ByteArray();
        private var outputSamples:ByteArray = new ByteArray();

        private var hTimer:uint = 0;
        private var nState:int = 1;

        private var url:String="*** replace this text with your favorite streaming AAC radio feed ***";

        // Main Constructor
        public function Main() : void
        {
            connectToStream();
        }

        private function connectToStream() : void
        {
            connection.close();
            connection = new NetConnection();

            connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
            connection.connect(null);           
        }

        private function netStatusHandler(event:NetStatusEvent) : void
        {
            trace("NetStatusEvent = " + event.info.code);
            switch (event.info.code)
            {
                case "NetConnection.Connect.Success":
                    requestAudio();
                    break;

                case "NetStream.Buffer.Empty":

                    //hTimer = setInterval(onTimerEvent, 1000);

                    break;

            }   // End switch
        }

        private function asyncErrorHandler(event:AsyncErrorEvent) : void
        {
            trace("Stream Error Handler - error = " + event);
        }

        public function onMetaData(info:Object) : void 
        {
            trace("metadata: duration=" + info.duration + " framerate=" + info.framerate);
        }   

        private function onTimerEvent() : void 
        {

        }

        private function requestAudio() : void
        {
            if (netStream !== null)
            {
                netStream.close();
            }

            netStream = new NetStream(this.connection);
            netStream.client = new Object();

            netStream.client.onMetaData = onMetaData;

            netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
            netStream.checkPolicyFile = false;

            //netStream.play(url);

            if (urlStream !== null)
            {
                urlStream.close();
            }

            urlStream = new URLStream();
            urlStream.addEventListener(ProgressEvent.PROGRESS, progressHandler);

            urlRequest = new URLRequest(url); 

            urlStream.load(urlRequest); 

            netStream.play(null);

            netStream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);

        }

        // Process audio samples from file
        private function progressHandler(event:ProgressEvent) : void 
        {  
            var streamByte:int;

            // Position to beginning of buffer
            inputSamples.position = 0; 

            urlStream.readBytes(inputSamples);

            // *** want to do some signal processing here ***
            // For now just copy the input to the output

            // Position to beginning of buffer
            outputSamples.position = 0; 

            // This output indicates that the buffer is being drained
            // until I get NetStream.Buffer.Empty and the audio stops playing
            trace("Buffer Length = " + netStream.bufferLength);

            while (inputSamples.bytesAvailable) 
            {   
                streamByte = inputSamples.readByte();

                outputSamples.writeByte(streamByte);
            }

            // Position to beginning of buffer
            outputSamples.position = 0;             

            netStream.appendBytes(outputSamples);                       
        }
    }
}
1
I tested your code but I did not receive the NetStream.Buffer.Empty event. Can you give me the url of the feed that you are using, if it's possible of course, to test it ?akmozo
Actually our customer requested that we not use the streaming URL we are supposed to perform signal processing on. However, I would be interested in trying the URL that you had success with if you would be kind enough to post it. Also, would you know if the bytes being received in the ProgressEvent handler represent 32-bit floating point audio samples as they do when using the Sound Extract method? When I tried to read and write samples using the Number datatype I no longer heard any audio output!BooRowan
I found a link you can use to test with.BooRowan
"2583.live.streamtheworld.com/KFMXFMAAC"; Give this a try and let me know if your buffer gets drained and the audio stops. Thanks...BooRowan
OK, I see, this is after two seconds for the event was triggered.akmozo

1 Answers

0
votes

Try this :

import flash.media.Video

var stream = 'http://2583.live.streamtheworld.com/KFMXFMAAC'

var http_stream:URLStream = null

var video:Video = new Video() // the video is used only to ensure that stream is playing
addChild(video)

var nc:NetConnection = new NetConnection()
    nc.connect(null)
var ns:NetStream = new NetStream(nc)
    ns.client = new Object()
    ns.client.onMetaData = function(e){}
    ns.play(null)

video.attachNetStream(ns)

http_stream = new URLStream();
http_stream.addEventListener(ProgressEvent.PROGRESS, on_Progress)
http_stream.load(new URLRequest(stream))

function on_Progress(e:ProgressEvent):void {

    var b:ByteArray = new ByteArray()
    http_stream.readBytes(b, 0, http_stream.bytesAvailable)
    ns.appendBytes(b)

    trace(ns.bufferLength)

}