Bees Are Social By Nature

Transcribed thoughts and experiences about computer programming.

Creating a Simple MP3 Player using ActionScript 3.0 and Flex 2

After creating a Simple FLV Player using ActionScript 3.0, I decided to extend my learning by going through the process of creating a simple MP3 player using ActionScript 3.0 and Flex 2. For requirements, all I wanted my MP3 player to do was play from a static list of MP3 files and have controls allowing me to play, pause, stop, go to the next song in playlist, and go to a previous song in the playlist. I have seen quite a few of these floating around the internet, so I figured it should be pretty easy and, as expected, it was.

Prerequisites:

Flex 2 SDK: http://www.adobe.com/products/flex/sdk/
Public Domain MP3 Files: http://www.publicdomain4u.com/

1) Install Flex 2 SDK

After downloading the flex_sdk_2.zip, I just unzipped the contents in to a work folder, c:\flex_sdk_2. The key resources I used from this package with were the compiler, bin\mxmlc.exe, and the debug Flash player (player\debug\SAFlashPlayer.exe).

2) I generated the following source in my favorite text editor, please note that I decided to go with the “source is the documentation” style of documentation for what and why I did:

The ActionScript source for the mp3 player class, SimpleSimpleMP3Player.as:

package { 
    import mx.containers.Panel; 
    import mx.controls.Button; 
    import flash.events.*; 
    import flash.media.Sound; 
    import flash.media.SoundChannel; 
    import flash.net.URLRequest; 
    import flash.utils.Timer;     

    public class SuperSimpleMP3Player extends Panel { 
    	// Song List 
    	private var songURLs:Array = 
    	    ["SongFromCottonField.MP3", 
	     "Bill_Cox--My_Rough_and_Rowdy_Ways.mp3", 
	     "Robert_Johnson-Love_In_Vain.mp3", 
	     "Andy_Iona-Naughty_Hula_Eyes.mp3", 
	     "AtlantaBound.MP3", 
	     "MamieSmithHerJazzHounds-CrazyBlues.mp3"];     

        // Current Song to Play 
        private var currentIndex:Number = 0;     

        // Sound Channel to monitor 
        private var song:SoundChannel;     

        // Request object for obtaining mp3 
        private var request:URLRequest     

        // Pause state management 
	private var paused:Boolean = true;     

	// Stopped state management 
	private var stopped:Boolean = false;     

	// Retains what position the song was in 
	// when it was paused, so we can go back to 
	// the same position when we hit play again. 
	private var position:Number;     

	// Sound... Factory for initializing our song. 
        private var soundFactory:Sound;     

	// The magic var that allows us to set the actual 
	// implementation of the play button from the Flex 
	// MXML.  This allows a custom component, see 
	// SimpleMP3.mxml, to set the actual button that 
	// playButton referres to, letting us change the 
	// label, or any other property of the button in 
	// our ActionScript. 
	public var playButton:Button;     

        public function SuperSimpleMP3Player() { 
            super(); 
	    playMP3(currentIndex);     

        }     

	// Play MP3 at specified index in songURLs array. 
	public function playMP3(mp3Index:Number):void { 
	    stopped = false; 
	    paused = false; 
	    position = 0; 
	    var request:URLRequest = 
	        new URLRequest(songURLs[mp3Index]); 
	    soundFactory = new Sound(); 
	    soundFactory.addEventListener(Event.ID3, id3Handler); 
	    soundFactory.load(request); 
	    song = soundFactory.play(); 
            song.addEventListener(Event.SOUND_COMPLETE, 
                soundCompleteHandler); 
	}     

        // Since the id3 information is not available until it 
        // is read off the string we need to make sure we have 
        // a way of updating the UI once it has been loaded. 
        // Having songName as a bindable allows us to do that, 
        // and the id3Handler will notify us when the information 
        // is ready to be displayed. 
        [Bindable("songNameChanged")] 
	public function get songName():String { 
		return soundFactory.id3.artist + 
			" - " + soundFactory.id3.songName; 
        }     

	// Alert songNameChanged bind when id3 information 
	// has been loaded. 
        private function id3Handler(event:Event):void { 
            dispatchEvent(new Event("songNameChanged")); 
        }     

	// Start the next song, once the current one has 
	// finished playing. 
	private function soundCompleteHandler(event:Event):void { 
	    position = 0; 
	    currentIndex++; 
	    if (currentIndex >= songURLs.length) { 
	        currentIndex = 0; 
	    } 
	    playMP3(currentIndex); 
        }     

	// Pause current song, or play song if already paused. 
	// Setting playButton label such that any GUI button 
	// that is attached will change with play or pause. 
	public function pause():void { 
	    if (!stopped) { 
	        if (!paused) { 
	    	    paused = true; 
		    position = song.position; 
		    song.stop(); 
		    playButton.label = ">"; 
	        } else { 
		    paused = false; 
		    song = soundFactory.play(position); 
		    song.addEventListener(Event.SOUND_COMPLETE, 
		    	soundCompleteHandler); 
		    playButton.label = "||"; 
	        } 
	    } else { 
	        playMP3(currentIndex); 
	        playButton.label = "||"; 
	    } 
        }     

	// Stop current song 
	public function stop():void { 
		stopped = true; 
		song.stop(); 
		position = 0; 
		playButton.label = ">"; 
	}     

	// Switch to Next Song 
	public function next():void { 
	    currentIndex++; 
	    if (currentIndex >= songURLs.length) { 
	        currentIndex = 0; 
	    }     

	    song.stop(); 
	    position = 0;     

	    // Track if player was already playing, 
	    // paused, or stopped. If stopped or 
	    // paused, still "play" so we can start 
	    // streaming and obtain the id3 info.     

	    var wasStopped:Boolean = stopped; 
	    var wasPaused:Boolean = paused;     

	    playMP3(currentIndex);     

	    if (wasStopped) { 
	        stop(); 
	        return; 
	    }     

	    if (wasPaused) 
            { 
		paused = true; 
		position = song.position; 
		song.stop(); 
            } 
	}     

	// Switch to Previous Song 
	public function prev():void { 
	    currentIndex--; 
	    if (currentIndex < 0) { 
	        currentIndex = songURLs.length - 1; 
	    }    

	    song.stop(); 
	    position = 0;    

	    // Track if player was already playing, 
	    // paused, or stopped. If stopped or 
	    // paused, still "play" so we can start 
	    // streaming and obtain the id3 info.    

	    var wasStopped:Boolean = stopped; 
	    var wasPaused:Boolean = paused;    

	    playMP3(currentIndex);    

	    if (wasStopped) { 
	    	stop(); 
	    	return; 
	    } 
	    if (wasPaused) { 
		paused = true; 
		position = song.position; 
		song.stop(); 
    	    } 
	} 
    } 
}

The MXML for the custom mp3 player component, SimpleMP3.mxml:

<?xml version="1.0"?> 
<!-- SimpleMP3.mxml --> 
<custom:SuperSimpleMP3Player 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:custom="*"> 
     <mx:Label text="{String(songName)}"/> 
     <mx:ControlBar horizontalAlign="center"> 
      <mx:Spacer width="100%"/> 
      <mx:Button id="prevButton" label="<<" click="prev()"/> 
      <mx:Button id="pauseButton" label="||" click="pause()"/> 
      <mx:Button id="stopButton" label="X" click="stop()"/> 
      <mx:Button id="nextButton" label=">>" click="next()"/> 
      <mx:Spacer width="100%"/> 
    </mx:ControlBar> 
</custom:SuperSimpleMP3Player>

The MXML for container application, SimpleMP3Player.mxml:

<xml version="1.0" encoding="utf-8"?> 
<mx:Application 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:custom="*" 
    layout="vertical" 
  <custom:SimpleMP3 id="myMP3" headerHeight="0"  width="400"/> 
</mx:Application>

4) From the command line I compiled the file:

c:/flex_sdk_2/learning>../bin/mxmlc.exe 
	-use-network=false 
	SimpleMP3Player.as

Note that I had to use the ‘-use-network=false’ directive. This told the compiler that I will not be using the network in my testing so don’t worry about sandbox issues when trying to load the flv from my local drives. Once I decide, if I decided, to deploy this to a website, I will need to recompile my code without this directive.

6) After compilation succeeded, I loaded the swf in the debug Flash Player:

c:/flex_sdk_2/learning>../player/debug/SAFlashPlayer.exe 
	SimpleMP3Player.swf

Success. However, please don’t think of this as the only way of doing or even close to the best way of doing. No best practices used here, like supplying some sort of packaging/namespacing for my custom code and components, just me documenting my learning experience. 😉 I do hope this helps a few other with their own learning experiements and if you know of cleaner solutions, please feel free to leave some feedback in my comments section.

For reference, the source can also be downloaded from http://www.kriggio.com/mp3player/SuperSimpleMP3Player.zip

The following link, which may or may not be available depending if I have to take it down due to bandwidth issues, demonstrates the above code: http://www.kriggio.com/mp3player/mp3.html. Streaming mp3s = lots of bandwidth. 😦

Advertisements

June 19, 2007 Posted by | ActionScript, flex, Programming, technology | 20 Comments

A Super Simple FLV Player using ActionScript 3.0

As part of my ongoing pursuit of learning a wide variety of technologies, I decided to see what ActionScript 3.0 was all about. As part of my learning, I decided I wanted to join the ever growing crowd of people that have “created” their own FLV Players. I knew people weren’t actually creating the video player and were really just setting up Video component in the UI and telling it what video to play, yet I still wanted to see how it was done. As such, my journey into ActionScript 3.0 began. Fair warning: I get real lazy about writing clean code, organizing my files, and setting up my development environment when I just start learning something. As such, the following embraces the lazy approach to getting things started.

Prerequisites:

Flex 2 SDK: http://www.adobe.com/products/flex/sdk/
Example FLV Files: http://www.mediacollege.com/flash/video/tutorial/example-flv.html

1) Install Flex 2 SDK

After downloading the flex_sdk_2.zip, I just unzipped the contents in to a work folder, c:\flex_sdk_2. The key resources I used from this package with were the compiler, bin\mxmlc.exe, and the debug Flash player (player\debug\SAFlashPlayer.exe).

2) As a ActionScript3 novice, I browsed a few tutorial sites. Then I went ahead and compiled and ran a few different tutorials. I found that the Beginners Guide to Getting Started with AS3 at http://www.senocular.com/flash/tutorials/as3withmxmlc/ to be very helpful, and you will find it goes into much greater detailon the use of the mxmlc.exe command line tool than I go into here. Next, I decided I want to be cool like everyone else and create an FLV Video Player. After doing a decent search, I noticed that most of the tutorials for creating FLV Video PLayers were using Flash Professional, which is outside of my “just learning” budget. However, I did find what I was looking for in the Adobe Flash Media Development Center. The tutorial taught me a lot more than I initially wanted, but it showed me exactly what I need to do to create my own.

3) Once I read the tutorial, I embarked on creating my own SuperSimpleFLVPlayer. In order to test whatever I ended up making, I needed an example FLV file and I found one at
http://www.mediacollege.com/flash/video/tutorial/example-flv.html. I downloaded ‘20051210-w50s_56K.flv’ and saved it as c:\flex_sdk_2\learning\20051210-w50s_56K.flv.

4) Next, I generated the following source in my favorite text editor:

package { 
    import flash.display.Sprite; 
    import flash.net.NetConnection; 
    import flash.net.NetStream;  

    import flash.media.Video; 
    public class SuperSimpleFLVPlayer extends Sprite {  

        private var nc:NetConnection; 
        private var ns:NetStream; 
        private var vid:Video; 
        private var client:Object; 
        public function SuperSimpleFLVPlayer () { 
            // Initialize net stream 
            nc = new NetConnection(); 
            nc.connect (null); // Not using a media server. 
            ns = new NetStream(nc); 
            // Add video to stage 
            vid = new Video(320,240); 
            addChild (vid); 
            //vid.x = ( stage.stageWidth / 2) - ( vid.width / 2 ); 
            //vid.y = ( stage.stageHeight / 2) - ( vid.height / 2 ); 
            // Changed since when deployed the 
           // above set the video player nearly off the screen 
           // Since I am lazy, I am just going to 0 them 
           // out for now. Apparently, I have a lot more 
           // to learn. 
          vid.x = 0; 
          vid.y = 0;  

          // Add callback method for listening on 
          // NetStream meta data 
          client = new Object(); 
          ns.client = client; 
          client.onMetaData = nsMetaDataCallback; 
          // Play video 
          vid.attachNetStream ( ns ); 
          ns.play ( '20051210-w50s_56K.flv' ); 
        } 
        //MetaData 
        private function nsMetaDataCallback (mdata:Object):void { 
            trace (mdata.duration); 
        } 
    } 
}

I saved the source as c:\flex_sdk_2\learning\SuperSimpleFLVPlayer.as.

5) From the command line I compiled the file:

c:/flex_sdk_2/learning>../bin/mxmlc.exe 
        -use-network=false 
        SuperSimpleFLVPlayer.as

Note that I had to use the ‘-use-network=false’ directive. This told the compiler that I will not be using the network in my testing so don’t worry about sandbox issues when trying to load the flv from my local drives. Once I decide, if I decided, to deploy this to a website, I will need to recompile my code without this directive.

6) After compilation succeeded, I loaded the swf in the debug Flash Player:

c:/flex_sdk_2/learning>../player/debug/SAFlashPlayer.exe
        SuperSimpleFLVPlayer.swf

Success. Flash and ActionScript really is multimedia made easy.

Quick Update: I found that once I actually deployed this to a website it started behaving differently than it did in the debug tool, which I am none too happy about. However, for this quick and dirty learning experience, I just changed the vid.x and vid.y to both equal 0 and now it at least put the video into a visible part of the stage. For reference, feel free to check out what I deployed at: http://www.kriggio.com/tromstick/flv/index.html. By the way, feel free to tell me what I am doing wrong if you see anything, I really am just learning ActionScript 3.0 so any “constructive” criticism helps.

June 6, 2007 Posted by | ActionScript, Programming, technology | 23 Comments