Realtime MP3 Decoding in Actionscript 3
So did you ever try to play Shoutcast streams in Flash? Did you run into memory leaks? Did the playback sound pitched or otherwise screwed? Fear no more. Let me introduce you to as3icy.
as3icy is a drop-in replacement for the Flash Player’s Sound object that can reliably play Shoutcast, Icecast and Limewire MP3 streams. And it extracts metadata info from the stream in real time. It also reliably plays VBR MP3.
DISCLAIMER IN CAPITAL LETTERS. This is experimental code. I basically threw this code together in two 24 hour coding sessions. Also, i know as much about sound engineering as i know about pottery – i blind-ported a big chunk of Java code (the excellent JLayer MP3 decoder, originally ported from C if i’m not mistaken) to Actionscript 3 without really knowing what i was doing. So expect a few WTF moments when reading through the code, and do not expect everything to work perfectly just yet.
Some known issues
- IT IS SLOW AND STRESSES YOUR CPU. Depending on the encoding, i get around 20-50% load on my 2.4GHz Core 2 Duo (Vista), which is way too much. On my MacBook Air 2.16 GHz: full load and playback chokes, which is unacceptable. There is plenty of room for optimization though, the code is currently not optimized at all. It’s probably worth taking a look at Apparat, or Alchemy in general for more performant alternatives to decode MP3..
- Only Layer III is supported (Layer I and II decoders not ported yet).
- Only 44100Hz playback is supported (up/down-sampling to 44100Hz not implemented yet).
- Only stereo modes are supported (mono not implemented yet).
- The stream parser seems to be with problems yet, sometimes it happens that it runs out of sync for some reason.
Also, Adobe AIR is recommended to play Shoutcast streams, for two reasons: The meta data interval is passed back to the client via HTTP response headers, which are not available in the plugin version of the Flash Player, and as soon as you put the thing online you need the streaming server to host a crossdomain.xml file. If you happen to have access to the streaming server, you can of course solve these issues by hardcoding the meta data interval and have the streaming server serve an appropriate crossdomain.xml, or by using a proxy script of some sort. Also, this only applies to playing Shoutcast streams. You can play static MP3 files (for example VBR MP3s) using as3swf in the plugin version of the Flash Player without any problem (security restrictions still apply of course).
A simple example: Shoutcast stream playback
package
{
import com.codeazur.as3icy.ICYSound;
import com.codeazur.as3icy.events.ICYMetaDataEvent;
import flash.display.Sprite;
import flash.events.HTTPStatusEvent;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
public class SimpleShoutcastPlayer extends Sprite
{
protected static const URL:String = "http://72.233.14.70/hype";
protected var icySound:ICYSound;
public function SimpleShoutcastPlayer()
{
var req:URLRequest = new URLRequest(URL);
req.requestHeaders = [ new URLRequestHeader("Icy-Metadata", "1") ];
icySound = new ICYSound();
icySound.addEventListener(ICYMetaDataEvent.METADATA, metaDataHandler);
icySound.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, httpResponseStatusHandler);
icySound.load(req);
icySound.play();
}
protected function httpResponseStatusHandler(e:HTTPStatusEvent):void {
// The HTTP_RESPONSE_STATUS event is fired when the stream is opened and starting to load.
var s:String = "Connected!";
if (icySound.icyName.length > 0) { s += "\rName: " + icySound.icyName; }
if (icySound.icyDescription.length > 0) { s += "\rDescription: " + icySound.icyDescription; }
if (icySound.icyUrl.length > 0) { s += "\rURL: " + icySound.icyUrl; }
if (icySound.icyServer.length > 0) { s += "\rServer: " + icySound.icyServer; }
if (icySound.icyMetaInterval > 0) { s += "\rMeta Interval: " + icySound.icyMetaInterval; }
trace(s);
}
protected function metaDataHandler(e:ICYMetaDataEvent):void {
// The METADATA event is fired when new metadata is available.
if (e.metaData.length > 0) {
trace("Now playing: " + e.metaData.slice(13, -2));
}
}
}
}
This code (Adobe AIR required) plays the Hype Machine live radio stream, and traces out general information about the station, as well as the names of currently playing songs.
Note that we set a custom request header, Icy-Metadata: 1. This tells the server to periodically send meta data with the stream. Under the hood, as3icy transparently extracts this meta data from the stream in real time and passes it to the application via the ICYMetaDataEvent. This event won’t be fired when the request header above is not sent.
The trace output should look something like this:
Connected!
Name: Hype Radio
Description: Radio powered by music blogs
URL: http://hypem.com/radio/
Server: Icecast 2.3.1
Meta Interval: 16000
Now playing: Collider - Time Concerns
Now playing: Rogue Wave - Birds (Neil Young cover)
Now playing: The Big Pink – Dominos
[..]

February 15th, 2010 at 07:59
Very nice! Really curious if the performance can be improved. It would be awesome if this could soon replace my hacky: http://code.google.com/p/as3mp3streamplayer/
Keep up the good work!
Greetz Erik
March 8th, 2010 at 04:35
This really works well! Do you need help completing this? Would love to get all formats working? If so let me know what you need.
March 9th, 2010 at 12:13
Shaun, sure, i would apprechiate that a lot! Although, as i already said in my post, non-native MP3 decoding is very heavy on the CPU, so i don’t know if this project will be useful at all
April 22nd, 2010 at 10:14
Are there any updates on this?
July 10th, 2010 at 14:50
What’s going on here? Is this going to happen? I downloaded your code and couldn’t get it to work, are there any compiler errors that I should be aware of? Obviously somebody made it work.
August 6th, 2010 at 13:28
I am unable to get VBR MP3′s to play using as3swf as you say. You have the error “This mp3 is encoded with variable bitrates. VBR is not allowed. Please use CBR mp3s” on line 146 of TagDefineSound. Am I missing something? Thanks!
August 6th, 2010 at 15:01
Patrick, i took out the check for VBR in TagDefineSound. I was under the false impression that the Flash Player doesn’t support VBR. It does. Thanks!