Topic: How to buffer a streaming sound?

I'm trying to play a shoutcast from a widget, which works, but I'm having trouble with prebuffering. Often I'll get a few moments of sound, then a pause while I assume the sound is loaded further, and then it will start playing again. And then often it'll pause again to rebuffer.

Is there some way to control this? I see that movie clips have a _soundbuftime parameter to set the amount of buffering on a streaming sound, but I don't see anything like this for the Sound object.

Maybe there's some clever way to tell it to start playing, then pause it until so many seconds have been loaded using getBytesLoaded? Thoughts? Cbreeze, care to share how you're doing it?

Here's the code I'm using:

_level0.soundobject = new Sound(this);

_level0.soundobject._soundbuftime = 5; // ignored, unfortunately

url = "http://goodradio.org/stream/wfmu"
_level0.soundobject.loadSound(url, true);

Re: How to buffer a streaming sound?

What is the bit rate?  No matter how much you buffer it's going to pause at some point.  I use 128 kbs and 192 kbs sources with no real trouble, but 256 kbs MP3 sources are a challenge for all of the WiFi radios I own, not just the Chumby.

3 (edited by wrybread 2009-08-12 12:01:49)

Re: How to buffer a streaming sound?

The bitrates are pretty high, mostly in the 96k - 256k range, which stream just fine on a PC using iTunes or Winamp or whatever. The Chumby shouldn't be any different given the same internet connection, right?

I posted the widget:

http://www.chumby.com/guide/widget/Coll … io%20Tuner

Its a tuner for college and community radio stations. I was recently playing around with Sirius Satellite Radio, and I liked the idea of having "channels" as opposed to a list of jukebox-style choices. So this is a radio tuner with pre-defined channels.

I maintain a database of college radio stations at http://goodradio.org, so this is v1 of the client I've been meaning to build for the Chumby for ages. Its why I originally bought the thing. Actually I built a jukebox previously (http://gizmoware.net/chumby) but because of earlier restrictions on widgets I couldn't make it available as a widget.

This definitely has its problems with streaming: as far as I can tell there's no way to determine whether a given Sound is playing/loading/timed-out in Flash, so I think its the best that can be done given the current framework, but by all means correct me if I'm wrong. Is there a Listener for the Sound object? Is there a way to tell if a Sound is buffering? Or to increase the buffer? Or whether the stream is timed out?

I posted the source code as I do for all my widgets at http://gizmoware.net/chumby

The part that streams the shoutcasts is in the playStation() function. Basically I'm using the following code:

station_url = "http://goodradio.org/stream/" + station_name // for example station_name might be "wfmu"
_level0.soundobject = new Sound(this); 
_level0.soundobject.loadSound(station_url, true); 

Using my goodradio.org interface, you can stream a station (for example wfmu) in a webbrowser like this: goodradio.org/wfmu. To play it from a Chumby widget that expects a stream (cbreeze, I've been meaning to mention this for use in your Streams widget), you'd use goodradio.org/stream/wfmu.

One way I was thinking the Chumby admins might improve the usefulness of Chumby widgets is by giving us widget developers more ASNative calls. For example the BTPlay program on the Chumby does a much better job of streaming sounds than the widget/Flash interface as far as I can tell. Why not give widgets access to BTPlay via ASNative calls and callbacks, which would protect the security of the Chumby user while still greatly improving the functionality of the Chumby? Additional ASNative calls could be made available for harmless system programs like ping, tracert, ifconfig... I mean honestly, can you think of a single malicious use for any of those programs? Personally I think if Chumbies continue to rely on the Flash security model they can't possibly keep up with iPhones and gPhones and whatever comes next. But what do I know, I still do silly things like spend a whole day building a widget for a Chumby.

Anyway, I'm curious to hear other people's reports on how reliable this widget is for them. Remember you can always test whether a stream is up with goodradio.org/[stream_name]. For example goodradio.org/kdvs.

Re: How to buffer a streaming sound?

The link to the source code doesn't seem to be working, unless I am looking in the wrong place.

http://gizmoware.net/chumby/chumbyjukebox2.zip

Any ideas?  Would love to help out if I can.

Cheers.

Re: How to buffer a streaming sound?

Oops, I'll fix the link on the page, but for now here it is:

http://gizmoware.net/chumby/jukebox2.zip

Re: How to buffer a streaming sound?

wrybread wrote:

For example the BTPlay program on the Chumby does a much better job of streaming sounds than the widget/Flash interface as far as I can tell. Why not give widgets access to BTPlay via ASNative calls and callbacks, which would protect the security of the Chumby user while still greatly improving the functionality of the Chumby?

Pretty please?  The stability is like night and day. smile

--

I ran the widget (very cool btw) and unless I'm just picking the lucky stations, I had no issues with buffering.  It seems to be handling fine in the "memory" department.

The main issue I notice (at least with Streams) is the bit-rate.  While I agree in theory that there shouldn't be any difference between a PC and a Chumby as far as streaming, I have found that it may not be the case.  My assumption is that there must be some type of processing necessary to "decode" the stream, and being that the Chumby runs pretty "hot" as it is, the power to "decode" a higher bit-rate stream via Flash may not be available (please educate me otherwise, if that is not the case).

--

As far as listeners, there are a couple for the Sound object.  Unfortunately when it comes to a streaming audio source, they appear serverly crippled.  The only one I have been able to get a response from is when a stream stops, and even that is sketchy at best.

For example (code snippet):

import mx.utils.Delegate;

var stream_audio = new Sound(_root);
stream_audio.onSoundComplete = Delegate.create(Streams, audioIsDone);

...elsewhere in the Streams class...

public function audioIsDone ():Void {
    trace("All done!");
}

But as I mentioned, I have rarely run across this being triggered.

--

More random notes:

You are not required to call start() when specifically loading a streaming sound (not sure if it actually makes any difference at all, but there it is smile ).

The "_soundbuftime" is actually a global property, though I do not use it.  It can be set like so:

_soundbuftime = 10;

Of course in this case we run into some classic Flash voodoo:

Adobe Documentation wrote:

_soundbuftime (TextField._soundbuftime property)

Although you can specify this property for a TextField object, it is actually a global property that applies to all sounds loaded, and you can specify its value simply as _soundbuftime. Setting this property for a TextField object actually sets the global property.

Ummm...really Adobe?  A text field?  I have no idea if there is any difference between the two approaches.

--

You mentioned a Shoutcast stream specifically.  Are these the only ones you are having issues with?

Hopefully something here might help.  Please keep us posted on your results.

Cheers.

Re: How to buffer a streaming sound?

Adobe has the _soundbuftime property for any Object type that has a graphical presence - they're all just aliases for the global _soundbuftime property.

So, if you look in the docs, you'll see the same property on Button and MovieClip, as well as the global one.

Support for streaming audio is a very recent addition to Flash Lite, starting with Flash Lite 3.1 (we're currently deploying 3.1.5), so it's possible that it has some limitations and potential issues.  The code for this is stock from Adobe - we've done nothing special to it for chumby.

It is true that goofy bitrates and sampling will tend to overload the processor - you've only got so much CPU to work with here.  Streams that operate at 44100 Hz are preferred, since that's the default base sampling rate for which we configure Flash's PCM audio output before it's fed to ALSA.  Streams at 22050 Hz and 11025 Hz require a little bit more processing, while streams at other sampling will tend to take a lot more effort to resample.  There are also a lot of streams that utilize non-standard sampling rates - all bets are off on those.

Re: How to buffer a streaming sound?

Thanks Duane. I've been looking exclusively at bitrate, and lo and behold some of the problemed streams are indeed super odd sampling rates.

And thanks for the tips cbreeze.

One question: in your Streams widget, when you play a new stream, how are you stopping the old stream? I was trying to just load a new sound into _level0.mysound, but it would create a separate sound and both would play at once. I'm now using stopAllSounds(), which works, but I'd rather have more direct control over the specific sound.

9 (edited by wrybread 2009-08-13 11:00:34)

Re: How to buffer a streaming sound?

I made a Music Source (non widget) version of my college radio tuner and indeed its much more reliable. You can find it here if you want to try it:

http://gizmoware.net/chumby/jukebox2.zip

To run as a music source:

1) Copy jukebox-ms.swf to a USB key and insert in your Chumby

2) SSH into your Chumby and stop the control panel by typing stop_control_panel

3) cd /mnt/usb

4) chumbyflashplayer.x -i jukebox-ms.swf

[edit: I included a "debugchumby" file, which will run the jukebox automatically when the Chumby starts up if you copy it to the root of your thumb drive. See the file "Music Source Instructions.txt" in the zip]

The source code is included if anyone's interested. Note the "use_flash" variable at the top: set that to "false" to use BTPlay, set it to "true" if you're streaming in straight Flash.

I still haven't been able to open the sample BTPlay interface (see http://forum.chumby.com/viewtopic.php?id=3987) so I'm not at all sure I'm doing it right, and I'm still not able to get playing status. But I am able to get the accelleromater data, which is nice, so give the Chumby a whack to play a random station. I love that feature. Can widgets do this?

Also the way I'm controlling the volume could use some work. As it is it overloads the exec interface and there's a bit of a lag between setting the volume and the volume levels catching up.

It can also react to the top button, but for now I'm not doing anything with it, but I suppose it could be used for mute.

10 (edited by cbreeze 2009-08-13 12:08:46)

Re: How to buffer a streaming sound?

wrybread wrote:

One question: in your Streams widget, when you play a new stream, how are you stopping the old stream? I was trying to just load a new sound into _level0.mysound, but it would create a separate sound and both would play at once. I'm now using stopAllSounds(), which works, but I'd rather have more direct control over the specific sound.

The issue with multiple sounds is most likely due to how you're creating the sound object.  In the most recent code I have, a new Sound object is being created each time you call the "play" functionality.  The other approach (and the one used in Streams) is to create one Sound object and reuse it.  In that case, any new sound "source" will replace whatever is currently playing.  The other option is to make sure to clear and remove the Sound object each time.

If you're interested, here is an example of a "global" approach:

_sound = new Sound(_root);
/* assign any Sound listeners here */

... elsewhere in a function...

public function playMyAudio ():Void {
     _sound.stop();
     _sound.loadSound("soundfile.mp3", true);
}

You can adjust any of the common properties directly on the _sound instance, and they will stay that way throughout the session.

--

As far as the accelerometer is concerned, you can use it in "public" widgets.  There is a really good overview here http://www.adobe.com/devnet/devices/art … nt_06.html

Hope that helps.  Keep up the awesome work!

Cheers.