3 October 2011
Successful completion of Part 3 in this tutorial series is recommended. Previous experience deploying streaming video online is helpful.
Beginning
This article is the fourth in our series of beginning-level tutorials about Adobe Flash Media Server 4.5. This particular tutorial gets you started using FMS 4.5 to stream audio into a Strobe Media Player available to you through the Open Source Media Framework (OSMF).
Here are all of the articles in the series (links will become active as the articles are published):
So far in this series, we have dealt only with streaming video files. Still, there will be times when you want to stream audio through Flash Media Server. The first thing you need to know about audio and Flash Media Server 4.5 is that it is a completely different game from working with local audio using ActionScript 3. In ActionScript, a number of Sound classes are used to manage audio. When it comes to FMS 4.5, those classes play a minor role. The reason is simple: the file is being added to a stream and, as such, the attachAudio() method from ActionScript 3 is, for all intents and purposes, rendered useless due to a completely different delivery method.
Flash Media Server 4.5 can stream several different audio formats: SPEEX, G.711, Nellymoser, MP3, and AAC. There are a few "flavors" of the AAC format and Flash supports AAC+, HE-AAC, AAC v1, and AAC v2. That's the good news. The bad news is that AAC content can only be played through Adobe Flash Player 9.0.115.0 or later. This makes sense because this was the Flash Player update released in conjunction with the introduction of H.264 playback in late 2007. Still, the most common audio formats you will encounter are MP3 and AAC. For a great overview of the AAC format, check out this blog post by Fabio Sonnati: How AAC works.
Now that you know what you can use, we'll now show you how to actually use it.
In this example we are going to show you how to play an audio file through Flash Media Server 4.5. It's really not that much different from streaming video.
To get started:
Note: The authors would like the thank William Hanna, Dean of the School of Media Studies and Information Technology at the Humber Institute of Advanced Learning and Technology in Toronto, Canada, for permission to use the AndreHprofile.mp3 clip, which was produced by the students in the Radio Broadcast program at Humber.
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
var nc:NetConnection = new NetConnection();
var ns:NetStream;
As you did with on-demand video, before getting the audio to play, you need to create a NetConnection object and give the object a name: in this case, ns . With the housekeeping out of the way, you can turn your attention to connecting to the server and listening in on the messages between the server and Flash.
Note: For the past couple versions of Adobe Flash Professional, when you assigned a class to a variable, the import statement for that class was added to the top of the Script pane. This feature is nice because it is a common best practice to import the classes. The problem is, it is somewhat inconsistent in Flash. Sometimes the statements are added and sometimes they aren't. Recognizing this, it has become standard within the Flash community not to rely on this feature and to add the required import statements manually instead.
In this instance, you are going to use a common handler— netStatusHandler —to listen to both the connection and the stream for four specific messages: The connection is made, the connection is rejected, the stream has started to play, or the stream is not found. Here's how:
nc.connect("rtmp://localhost/AudioStreams");
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
function netStatusHandler(e:NetStatusEvent):void {
traceField.text = e.info.code + "\n" + traceField.text;
trace(e.info.code);
switch(e.info.code){
case "NetConnection.Connect.Success":
beginStream();
break;
case "NetConnection.Connect.Rejected":
break;
case "NetStream.Play.Start":
break;
case "NetStream.Play.StreamNotFound":
trace("Can't find the stream.");
break;
}
}
We'll briefly step through this function for you. Its purpose is to catch and react to four specific NetStatusEvent events: connection made, connection rejected, the stream has started to play, and the stream is not found. As these events occur, the actual message will appear in the text box in layer 2 when you test the project, detailing an activity log for the audio stream.
Obviously, if there is a connection— NetConnection.Connect.Success —the audio file should start to play (through invocation of the beginStream() function, in this example). If there isn't a connection— NetConnection.Connect.Rejected —check that your copy of FMS 4.5 is actually running and make sure the spelling of the application in the code matches the name of the application's folder.
The next check is to ensure the stream is playing. NetStream.Play.Start is the message that confirms this. The final message— NetStream.Play.StreamNotFound —is self-explanatory and is usually resolved by making sure you have the correct folder structure and path to the audio file. Now that the tests are in place, you can turn your attention to the audio file.
/* this function will handle creation of the NetStream object.
we invoke NetStream.play() to begin streaming. */
function beginStream():void {
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
ns.play("mp3:AndreHprofile");
}
As you can see, the "magic" happens with the netStatusHandler() function. The first step is to add the NetConnection to the stream and then listen for the stream-level messages between the server and the SWF application. If everything is good to go, the play() method of the NetStream class will look for an MP3 file named AndreHProfile and add it to the stream.
In the previous exercise, we showed you how to create an application that streams an audio file and how to get it playing. If we were to stop there, you would be well within your rights to start complaining. It is not exactly a best practice to play an audio file with no way of letting the user turn the darn thing off. In this exercise, we are not only going to enable the user to stop playback, but also show you how to display the time and how to pause a track.
To get started:
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.events.Event;
import flash.events.MouseEvent;
var isPlaying:Boolean = false;
var nc: NetConnection = new NetConnection();
var ns:NetStream;
addEventListener(Event.ENTER_FRAME, monitorTime);
nc.connect("rtmp://localhost/AudioStream");
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
function netStatusHandler(e:NetStatusEvent):void {
traceField.text = e.info.code + "\n" + traceField.text;
trace(e.info.code);
switch(e.info.code){
case "NetConnection.Connect.Success":
beginStream();
break;
case "NetConnection.Connect.Rejected":
break;
case "NetStream.Play.Start":
break;
case "NetStream.Play.StreamNotFound":
trace("Can't find the stream");
break;
}
}
There isn't much difference between this code and the code from the previous project. Still, there are some important additions. The first is the isPlaying variable. We are going to be tying a couple of functions to the condition of whether the audio is playing or not. We also want to show the user how much time has elapsed while the audio track is playing. To do this, we create a listener that will keep an eye on the time.
function beginStream():void {
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
ns.play("mp3:AndreHprofile");
ns.pause();
timeField.text = "ready";
}
At first glance it might strike you as a bit odd that as soon as we turn on the stream, we pause it. We have to, because a stream starts playing immediately and, in this case, the radio report will come blaring out of the user's speakers. This is not what we want. We want to give the user the opportunity to turn it on or off.
playBtn.addEventListener(MouseEvent.CLICK, playStream);
pauseBtn.addEventListener(MouseEvent.CLICK, pauseStream);
stopBtn.addEventListener(MouseEvent.CLICK, stopStream);
playStream() . Enter the following:function playStream(e:MouseEvent):void {
if(!isPlaying){
ns.resume();
isPlaying = true;
}
}
The logic for the Play button is really quite efficient. The first line checks to see if the stream is not playing— (!isPlaying) —when the button is clicked.There are only three possible states for the audio not to be playing: the beginNetStream() function has paused the stream, the user has clicked the Pause button, or the user has clicked the Stop button. In any case, the stream is resumed—the audio track starts playing—and the isPlaying variable's Boolean value is set to true .
function pauseStream(e:MouseEvent):void {
if(isPlaying){
isPlaying = false;
ns.pause();
}
}
function stopStream(e:MouseEvent):void {
isPlaying = false;
ns.close();
timeField.text = "stopped";
}
There's not much new here, other than the text in the timeField being changed to "stopped" when the Stop button is clicked. The key point, if you are new to working with streaming media, is that you are not really starting, stopping, or pausing the audio track itself, as you would through the use of the Sound object. You are informing the server either to no longer send audio data along the stream, or to resume the transmission of audio data along the stream.
function monitorTime(e:Event):void {
if(isPlaying){
timeField.text = Math.round(ns.time) + " seconds...";
}
}
There's not much new here, other than the text in the timeField being changed to "stopped" when the Stop button is clicked. The key point, if you are new to working with streaming media, is that you are not really starting, stopping, or pausing the audio track itself, as you would through the use of the Sound object. You are informing the server either to no longer send audio data along the stream, or to resume the transmission of audio data along the stream.
So far in this exercise you have been playing with a single file. Now that you know how to do that, we'll show you how let a user choose among multiple audio files.
Phil Darling, the son-in-law of one of the authors, is the bassist and founder of a rather hot "indie" band in Toronto named The TinBangs. The group has just released an EP that contains three songs, and the plan is to stream them out to let their fans hear the new work.
Note: The authors would like to thank Phil Darling and the other members of the band for letting us use these files for this example.
This means the user needs to be given the opportunity to pick from among three songs. For ths purpose, we have chosen to go with the List component that is packaged with Flash Professional CS 5.5.
Note: There are other ways to approach this project, ranging from using the ComboBox component to using an XML document as the DataProvider. We have chosen to go with the List component due to space constraints.
To get started:
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import fl.data.DataProvider;
import fl.controls.List
To use the List component, you need to use the DataProvider class to feed the data into the List component and the List class from the controls package to get the component working.
var playList:Array = new Array();
playList.push({label:"White Lies (Timekiller)",data:"WhiteLies(Timekiller)"});
playList.push({label:"Young Lions", data:"YoungLions"});
playList.push({label:"Your Sky Is Falling", data:"YourSkyIsFalling"});
audioList.dataProvider = new DataProvider(playList);
audioList.addEventListener(Event.CHANGE, switchStream);
We start by creating an array and giving it the name playList . Each item in the play list is going to appear in the List component. This component requires two pieces of information. The first is label , which is the text that will appear in the component when the application is running. The second is the data to use, which in this case is the name of the audio file. The List component is then told that playList will provide the data for the component. We are also going to listen for the user to make a selection in the List ( Event.CHANGE ) and, when this is detected, to execute the switchStream() function.
switchStream() function, click in line 44 of the Script pane and type:function switchStream(e:Event):void {
ns.play("mp3:" + e.target.selectedItem.data);
if(!isPlaying){
ns.pause();
}
}
The major change here is in the play() method. Instead of entering the name, you grab the data portion of the list item and use it instead.
The next part in this tutorial series walks you through the process of streaming HTTP Dynamic Streaming (HDS) content and also shows you how to use the multiple bitrate feature of Flash Media Server 4.5. We'll see you there.
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.
Tutorials & Samples |