SHOUTCast, SHOUTCast, Let It All Out

October 26, 2007 by nerdabilly

These are the things I could do without.

For the past couple of months, I have been working on a SHOUTCast player app in AIR. When I signed on to do the project, I had absolutely no idea that playing SHOUTCast streams in Flash is a Herculean task. It seems there’s this nagging little memory leak related to Flash loading a never-ending audio stream. Flash doesn’t release the memory for the audio already played, and eventually that audio data just builds and builds and builds until your CPU or memory maxes out. So far, I have found little to nothing in the form of a nice quick solution to this.

That being said, perhaps the most viable current solution was posted at MadArco’s DevBlog . It basically entails streaming the audio for 20-30 minutes, then recreating the audio stream in a new variable, and crossfading the two streams, at which point the original can be released from memory and garbage-collected. It’s a nice idea, but in CS3, after the first couple of swaps, I lost sound altogether, and this problem re-occured no matter which “swapping” method I attempted. MadArco’s solution is in AS2, and perhaps I lost something along the way while attempting to convert it to AS3, or perhaps AS3 isn’t able to handle this particular method.

There’s also a nice explanation of the “swapping” concept here.

So, after even more research (by “research” I mean thinking of new ways to search for a solution in Google) I found a post on FlashBrighton about generating audio and PCM wave data. I also found this on ActionScript.org, about using PHP to create a socket connection to read ID3 tags.

See where I’m going with this?

I’m proposing an all-in-one memory-leak-and-ID3-problem fix ShoutCast solution for Flash. Here’s my thoughts on it so far:

1.) Use Socket for getting the ID3 data, and, if possible, getting the stream as well.

2.) Use the FlashBrighton wave-data solution to create the audio from the ByteArray returned by the MP3 stream. This is possible using the URLStream class.

3.) Distribute it as a component or nice reusable class in order to allow beginners to use it easily.

I made some attempts at this yesterday, but the bytecode stuff is way over my head. If anyone has any input, or would like to have a go at this, please leave a comment and let me know what you think!

Disabling the FLVPlayback component’s controls (including seekbar!)

March 26, 2007 by nerdabilly

I’ve stumbled on another one of those “everyone wants to do it, but nobody knows how” issues in Flash: how to disable the controls on the FLVPlayback component.

After quite a bit of documentation-reading, web-searching, and forum-browsing, I’ve come up with a function for easy, on-the-fly toggling of controller-enable-ability.

with a FLVPlayback instance on the stage, add the following to your ActionScript:

mx.video.FLVPlayback.prototype.enableButtons = function(bEnabled:Boolean){
this.skin_mc.seekBar_mc.handle_mc._visible = bEnabled;
if(bEnabled){
this.stopButton =this.skin_mc.stop_mc;
this.backButton = this.skin_mc.back_mc;
this.forwardButton = this.skin_mc.forward_mc;
this.seekBar = this.skin_mc.seekBar_mc;
}else{
this.onEnterFrame = function(){
this.stopButton = this.skin_mc.stop_mc.disabled_mc
this.backButton = this.skin_mc.back_mc.disabled_mc;
this.forwardButton = this.skin_mc.forward_mc.disabled_mc;
this.seekBar = null;
updateAfterEvent();
delete this.onEnterFrame;
}
}
}

Now, for a bit of explanation:

The first step is to simply toggle the visibility of the SeekBar handle. With it invisible, there is no way the user can use it, and this seems to be the simplest solution, rather than digging through the MC structure of a component skin and figuring out how that handle is, uh, handled. So, the bEnabled value can double as the visibility value for the handled: true (visible) for enabled buttons, or false (invisible) for disabled.

For the rest of the buttons, it’s not so simple. Users have come to expect a “ghosted” or “grayed-out” appearance for a disabled button, so simply removing them as we did with the scrollbar handle would be bad form. Luckily, the pre-made skin SWFs for the FLVplayback component include disabled states for everything, and we can use these.

Because the component skins use bitmap caching and 9-slice scaling to maximize their flexibility, simply setting the button properties to the disabled MC won’t work, and it requires a bit more of a brute-force approach to get those buttons to appear. Hence, the onEnterFrame and updateAfterEvent() commands. updateAfterEvent() forces an update of the stage, so it will make those disabled-states appear, but it only works as part of a clip event, such as onEnterFrame. So we wrap the whole thing in an onEnterFrame, and then delete the onEnterFrame function to save on processing and memory.

I should note that I developed this using the SteelExternalAll.swf skin. The documentation indicates that the skins are built using a universal structure, so it should work for any of them, but I’m not making any promises.

, , , ,

Customing icons on the Flash 8 Tree Component

March 22, 2007 by nerdabilly

Back to one of my favorite topics – UI Component customization. Flash’s Tree Component provides a Windows Explorer-like hierarchical menu for displaying data in a “folder” structure.

The structure it displays uses 2 separate icons, a “folder” icon for folder nodes, and a “disclosure” arrow for opening and closing the folders.

To see an example of this, place a tree component on the stage and give it an instance name of “myTree.” Then, use the following loops for some dummy data in the tree:
[as]
for(i=1;i

The Tree Component Documentation lists various styles that can be set on the component, and it seems that these properties work without first installing a theme.

I’m not sure the exact reason for this, but the component seems to want to open and close folders based on clicking the “disclosure” arrow, not the folder icon.

So, what if you wanted one icon only? For this example, I’ll use the +/- metaphor that the Windows registry and some other apps use. first, create your “plus” and “minus” movie clips, and give them linkage IDs of “plus” and “minus”, respectively.

Then, use setStyle to apply these to the tree:

[as]myTree.setStyle(”disclosureOpenIcon”,”minus”);
myTree.setStyle(”disclosureClosedIcon”,”plus”);
[/as]
This turns the disclosure arrows into plus an minus signs, but the cliché folders are still there:

tree_plusd_w_folders.gif

The solution is to create a blank movieclip and set it as the folder icon. To do this, create a new MovieClip symbol and give it a linkage ID of “blankicon.” Then, add the following to assign the empty icon:

[as]myTree.setStyle(”folderOpenIcon”,”blankicon”);
myTree.setStyle(”folderClosedIcon”,”blankicon”); [/as]

And there you have it…

tree_plusminus_final.gif

, , ,

Apologies

March 7, 2007 by nerdabilly

Sorry for the XML parsing errors in the feed and the general slowness of the site. After a lot of back-and-forth with my web host, we determined that the issue was temp files clogging up the cache. I deleted nearly 200,000 files and it seems to run well again!

A Better Way To Determine a Function’s Caller

February 6, 2007 by nerdabilly

There are some rare instances, mainly during debugging, where you may need to determine which function called the current function. For example, you may have a function that is repeatedly called at many places in your code, and you need to determine which function calls it at a specific time.

ActionScript provides arguments.caller for this. However, using arguments.caller returns only a reference to the caller function, and leaves out details such as its name, type, etc. Take a look at this example:

[as]function test(){
trace(”this function was called by ” + arguments.caller);
}
function callTest(){
test();
}
callTest();
[/as]

The output of this is:

[code]this function was called by [type Function][/code]

Um, thanks, I guess.

My function was called by a function. This is about as helpful as [Object object] or, my personal favorite, “undefined is not defined.”

The trace output is giving us a [type Function] because it’s the only way Flash can trace a reference. The way around this is to check the reference against everything and test for equality. Let’s add a new function to the above code:

[as]function getCaller(callerObj){
var str:String = callerObj + newline + “”;
for(i in _root){
if(callerObj == _root[i]) {
return i.toString();
}
}
}

function test(){
trace(”this function was called by ” + getCaller(arguments.caller));
}
function callTest(){
test();
}
callTest();[/as]

The output has changed for the better:

[code]this function was called by callTest[/code]

Presto! You’ve gotten your caller function’s name. The getCaller function is looping through everything in _root. When the loop encounters a function, it is really encountering a reference to that function, just like arguments.caller is a reference to the caller function. Therefore, the if statement is comparing references to references and is able to accurately determine whether the caller property passed to it is the same as an existing function, and then return its name (or, more accurately, the name of the index of that reference in the _root object) as a string.

Please keep in mind, however….

This method is not perfect. I’ll admit it. It only works for functions that are defined on a frame in the main timeline. It won’t work for anonymous (inline) functions, calls made from a nested object such as a movie clip, component, or class, or outside calls coming in from JavaScript or any other external interface.

None of these flaws are unfixable, and time permitting, I’ll work on ways to improve this method, but the basic concept of this code (comparing references) will remain the same.

,

Why wouldn’t they just say that?

January 26, 2007 by nerdabilly

A reader commented on my ScrollPane article, saying “why wouldn’t they just say that?”

I’ve found myself asking this question more and more as I’ve been diving into Flex and ActionScript 3.

For example, here is how to get the name of the root node of an XML object:

AS2:
[as]myXML.childNodes[0].nodeName;[/as]

AS3:
[as]myXML.name();[/as]

In AS3, nodeName has mysteriously disappeared, and the Migration Guide makes no mention of name() as its new equivalent.

In fact, the XML Class Definition for ActionScript 3 describes name() as “Gives the qualified name for the XML object.”, which led me to believe it was relevant only namespace-qualified XML tags and not useful for getting a root node’s name.

Splitting hairs, perhaps, but a good little tip nonetheless.

, , ,

WPF, WTF?

December 6, 2006 by nerdabilly

There’s been quite a bit of buzz lately about “WPF/E”, or “Windows Presentation Foundation Everywhere,” a code word for Microsoft’s newest browser plugin and implementation of their Windows Presentation Foundation. This week, Microsoft released a Community Technology Preview (CTP) of WPF/E. I downloaded and installed their plugin and SDK and decided to see what I could do.

The plugin, and its drawing capabilities, were decidedly Flash-like. However, the documentation led me to believe that the entire “movie” – all the shapes, strokes, motions, and events – must be scripted in Microsoft’s XAML language, as opposed to being created in a nice drawing interface such as Flash or Illustrator would offer.

This couldn’t be. There is no way your average graphic designer would take kindly to coding all of this into XML. In fact most designers shriek, run away, and hide at the very thought of code. There has to be some kind of GUI to do this if WPF/E is ever going to be taken seriously by the design community.

After a bit more investigation, I found that Microsoft recommends “Expression Web Designer” to develop pages and “Expression Web Blend” for creation of WPF/E objects. Of course, this information was buried, in that special MSDN way of hiding information in plain sight. Initially, the Expression pages said that to use Expression Web Designer, one must first install the .NET Framework 2.0, and then install the designer software, and the Expression Web Blend was no longer available.

So after some more downloading, I installed the framework and Expression Designer, and fired it up to have a look at the latest Macromedia-Killer, which turned out to be a clone of Dreamweaver, with no mention of WPF/E anywhere.

After even more investigation, I found the trial download of Expression Blend, once again hidden in MSDN’s own unique way of hiding only the stuff someone might actually want to see, hidden amongst endless blobs of buzzwords and Microsoft horn-tooting. Plus, I now had to upgrade to .NET Framework 3.0.

Another round of downloading and installing, and finally, I was ready to for this ever-so-hyped and cleverly-hidden masterpiece of Microsoft innovation and competition-killing.

What I got was, well, stupid:Microsoft Blend - look familiar?

I always get a kick out the general assumption that monochromatic gray colors automatically makes you “edgy” and “hip.”

Also, I couldn’t find any way to change the fill color of the objects I had drawn onto the Stage …err, sorry, I mean the “Canvas”… The Paint Bucket seemed incapable of its basic Paint Bucket duties.

Scripted events were clumsily assembled in a panel drop-down interface, allowing the user to select first the object, then the event, then the action. For lack of a better example, it reminded me of the email-filtering in Outlook.

On the other hand, I did get an answer to my question: Yes, there is a graphical drawing interface to create XAML for a WPF/E page.

But why would you use it?

, , ,

Technorati

November 15, 2006 by nerdabilly

I’m attempting to claim this on Technorati.

Technorati Profile

Oh say, can you CDATA?

November 15, 2006 by nerdabilly

I worked really hard on that title.

An astute reader wrote in regarding my previous post about using Array.join("") to pull HTML tags from XML. He said that all this can be avoided by simply using CDATA in the XML document and pulling out the data with the .nodeValue property.

This, as Luther would have us say, is most certainly true, and it’s the simplest solution to the problem. I’ll even admit to being teh st00pidz for not mentioning this right from the start.

However, what if we needed to do both? Suppose, for example, you need to write an XML parser to parse data from a variety of publishers. Publishers, as we all know, are an unpredictable bunch. So publisher #1 sends out an XML file with their content enclosed in CDATA, and publisher #2 does not. Now what?

We’ll need a function to convert both CDATA and non-CDATA data into a universal format that can be displayed in an HTML textfield. Because the nodeValue method will only reliably return CDATA, I’m going to use the Array.join("") method.

Again, assuming we’ve loaded and parsed the XML file, let’s first get a string out of it:

[as]
var str:String = mx.xpath.XPathAPI.selectSingleNode(xml.firstChild.childNodes[0], “item/description”).childNodes.join(”");
[/as]

Now, because the function requires some searching and replacing, let’s add a replace() function to the String prototype:

[as]String.prototype.replace = function(replaceString, withString) {
var myArray = this.split(replaceString);
return(myArray.join(withString));
};[/as]

And finally,the conversion function:

[as]function convert(str) {
if( str.indexOf(”>”,0) != -1) { // if the string has come in as CDATA, it will not have “>”,”>”);
}

var mc:MovieClip = _root.createEmptyMovieClip(”converterMC”,0);
var htmlconverter = mc.createTextField(”htmlconverter”,mc.getNextHighestDepth(), -500,-500,100,25)
htmlconverter.html = true;
htmlconverter.htmlText = str;
var converted:String = htmlconverter.text;
mc.removeMovieClip();
delete mc;
return converted;
}
[/as]

What in the world is going on here, anyway?

When Flash pulls CDATA out of an XML document, all of the HTML entities will become escaped. So, “<” becomes “&lt;“, etc. If there’s already an escaped “&lt;” in the data, it comes back “double-escaped,” like this: &amp;lt;.

The first part of the function, the if block, checks for the existence of a “<” character. If one of these exists, then the text has not been escaped, and therefore, we can safely assume it is not coming in as CDATA. Then, the replace calls turn the HTML less-than and greater-than tag markers into escaped entities, and “double-escapes” any already-escaped entities. In other words, it converts the string into the same format as any CDATA. Now, it’s conversion time!

First, the function creates a text field on the stage and sets the html property to true. Then, it places the newly converted string into the htmlText property, which will cause the textfield to interpret the HTML. In this case, it takes escaped HTML text and converts it to non-escaped text. The contents of the textfield will now be proper HTML, with <> symbols around the tags, and escaped entities elsewhere, if necessary. This can then be set as the htmlText of another field, and will display properly.

If there’s ever a need to convert HTML text to non-HTML text, I highly recommend this method. Basically, it’s a nice quick way to strip any HTML tags, or in this case, interpret escaped entities. You could also put an HTML textfield on the stage, set its htmlText, and then pull out its text property, but I prefer this way because it’s a purely ActionScript solution.

By the way, does anyone know if there’s a proper term for “non-CDATA“?

, ,

On ScrollPane (or, “Scroll Pain”) Customization

September 26, 2006 by nerdabilly

It seems that documentation and clear examples for how to customize Flash 8’s ScrollPane component are somewhat scarce. In fact, just a quick Google search yields many messageboard postings bemoaning the difficulty of using ScrollPane, with little to nothing in response.

It’s important to note that the old methods of UI Component customization – setting values for “face”, “arrow,” “scrollTrack,” and the like, seem to have fallen by the wayside.

The recommended method these days is something much more in-depth and complicated, with poor documentation thrown in just to make sure you don’t get it right the first time. For example, the documentation on LiveDocs provides the following table of applicable styles for ScrollPane:

Style Theme Description
themeColor Halo The base color scheme of a component. Possible values are "haloGreen", "haloBlue", and "haloOrange". The default value is "haloGreen".
borderStyle Both The ScrollPane component uses a RectBorder instance as its border and responds to the styles defined on that class. See RectBorder class.The default border style is "inset".
scrollTrackColor Sample The background color for the scroll track. The default value is 0xCCCCCC (light gray).
symbolColor Sample The color of the arrows on the scrollbar buttons. The default value is 0×000000 (black).
symbolDisabledColor Sample The color of disabled arrows on the scrollbar buttons. The default value is 0×848384 (dark gray).

Great! Looks like we can change the arrow or track color of the scrollbar on a ScrollPain instance. All you need to do is set myScrollPane.scrollTrackColor, right?

Wrong.

Try it. Put a ScrollPane on the stage and set that scrollTrackColor. Set it all day long until you’re 0×0000FF in the face. You won’t see any changes to the scrollbar’s appearance.

Why?

Pay close attention to that “theme” column. It provides the key to why your customization isn’t going as planned. If you want to customize the scroll track or arrow color, those properties are available but what isn’t mentioned here is that you must first install the “Sample” theme from Macromedia’s libraries. A detailed description of how to do this is available in “About Themes” on LiveDocs.

So, we’ve dragged the Library over, installed the sample theme, and Presto! We now have a customized scrollbar color. We can also set symbolColor to change the color of the arrows.

It’s only a slight improvement. The problem is, we’ve now been left with chunky, gray, Windows 3.1-style scrollbars, and the only ActionScript customization options are for the arrows and the track.

You can improve the look and feel of the arrows manually, by editing the symbols in the Scrollbar Assets folder we dragged over during the Sample theme install. But who has the time or energy for that?

A little bit of digging around in the symbols that the Sample theme carried over reveals some hidden, undocumented goodness: there is also a highlightColor and shadowColor property available to these scrollbars. highlightColor applies to the “main” color of the arrow buttons and “thumb” element, while shadowColor is the small shadow to the bottom right of each piece.

(To see this for yourself, have a look at the “BrdrHilght,” “BrdrFace”, “BrdrBlk”, and “BrdrShdw” symbols.)

Here’s a diagram of the different parts of the scrollbar and where the different colors apply. Note: Please, never, under any circumstances, for any reason, use a color scheme like this. I only did it so I can show where the different parts are.

Sometime’s, it’s really amazing what you can find just by poking around in Macromedia’s samples.

, ,