Going Beyond Streaming with Flash Media Server

Flash Media Server Setup

ITP's Flash Media Server has now been setup for each of you to use.

In your home directory on itp.nyu.edu you will see a "flash" directory. In this directory there is an Application.xml file which you will have to edit in order for things to work right.

In that file, you need to change all of the instances of "netid" to your actual net-id.

<Application>
	<StreamManager>
		<!-- Specifies the physical location where
				recorded streams are stored. -->
			<StorageDir>/home/sve204/flash/vod/media/</StorageDir>

		<VirtualDirectory>
			<!-- Specifies application specific virtual directory
				mapping for recorded streams. -->
			<Streams>/home/sve204/flash/vod/media/</Streams>
		</VirtualDirectory>
	</StreamManager>

	<SharedObjManager>
		<!-- Specifies the physical location where shared
			objects are stored for this user. -->
			<StorageDir>/home/sve204/flash/sharedobjects/</StorageDir>
	</SharedObjManager>
</Application> 		
		

Broadcasting Messages/Sharing Data

We have already looked at using FMS to broadcast live media (video) but how about broadcasting simple messages back and forth.

Fortunately, it is relatively easy with FMS to do that with:

Shared Objects

Flash and FMS have a capability which is called a SharedObject. SharedObject allows us to have a Flash object which can be used to transmit data back and forth from client to server to all of the clients. In effect it is shared between all of the clients.

Flash Media Server Developer Documentation: About Shared Objects

Remote Shared Objects

Shared Objects can be local (like a browser cookie) or remote (on the server shared amongst different people), they can also be persistent (saved to disk) or non-persistent (deleted when the last client disconnects).

Here is a very very basic example of a non-persistent remote shared object:

package 
{ 
	// Class so we can display and/or be used in the Flash IDE
  	import flash.display.Sprite; 
  
  	// Class that allows a Shared Object to exist on FMS
  	import flash.net.SharedObject; 
  
  	// So we can get Status from the NetConnection (callback)
  	import flash.events.NetStatusEvent; 
  
  	// So we can get events from the SharedObject (callback)
  	import flash.events.SyncEvent; 
  
  	// So we can connect to FMS
  	import flash.net.NetConnection;

	// Import TextField to show what to send/recieve
	import flash.text.TextField;
	
	import flash.text.TextFieldType;


	// Import TextEvent so we know when something happens in TextField
	import flash.events.TextEvent;

  	public class SimpleSO extends Sprite 
  	{
  		// Declare a SharedObject object
  		private var sharedObject:SharedObject;
  		
  		// Declare a NetConnection Object
  		private var netConnection:NetConnection;

		// Declare a TextField
		private var textField:TextField;

		// Constructor  
	        public function SimpleSO()
       		 { 
        		trace("starting");
        	
        		// String with URL to app on FMS
        		var rtmpURL:String = "rtmp://itp.nyu.edu/sve204/SimpleSO";

			// Instantiate NetConnection
			netConnection = new NetConnection();

			// Event listener, calls netStatusCallBack when a NetStatusEvent is fired
			netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusCallBack);

			// Connect to the application on the server
			netConnection.connect(rtmpURL);

			// Create the textField
			textField = new TextField();

			// Add event listener
			textField.addEventListener(TextEvent.TEXT_INPUT, textEventCallBack);
			
			// Make the textField an input field
			textField.type = TextFieldType.INPUT;
			
			// Set it's position and dimensions
			textField.x = 10;
			textField.y = 10;
			textField.width = 100;
			textField.height = 40;
			
			// Set it's starting text
			textField.text = "hi";
			
			// Add it to the display
			addChild(textField);
		}

        	// NetStatusEvent Callback
        	private function netStatusCallBack(nsEvent:NetStatusEvent):void 
        	{ 
        		// If we connected successfully
        		if (nsEvent.info.code == "NetConnection.Connect.Success")
        		{
				// Set up the shared object
				// We'll call it SimpleSO, pass in the app url and not make it persistent
				sharedObject = SharedObject.getRemote("SimpleSO",netConnection.uri,false);
				
				// Add a listener for when shared object is changed
			   	sharedObject.addEventListener (SyncEvent.SYNC,syncEventCallBack); 

				// Connect the shared object to our netConnection
				sharedObject.connect(netConnection);
        		}
        		else
        		{
				// Didn't connect
				trace("Sorry connection failed");
        		}
        	}	 

		private function syncEventCallBack(syncEvent:SyncEvent):void
		{
			//  Array of changes: syncEvent.changeList[]		
			for (var i:int = 0; i < syncEvent.changeList.length; i++)
			{
				trace(syncEvent.changeList[i].code);
				
				switch(syncEvent.changeList[i].code)
				{
					case "clear":
						break;
					case "success":
						break;
					case "change":
						// get the new data
						var newData:String = sharedObject.data.theData;
						trace("recieved " + newData);

						// Update TextField
						textField.text = sharedObject.data.theData;
		
						break;
				}
			}
		}

		private function textEventCallBack(textEvent:TextEvent):void
		{
			trace(textEvent.text);
			
			// If the text == a space
			if (textEvent.text == " ")
			{
				// send it
				sendData(textField.text);
			}
		}
		
		// send the data
		private function sendData(dataToSend:String):void
		{
			sharedObject.setProperty("theData",dataToSend);
		}	
	} 
} 
		

You can download the code: SimpleSO.as or Try it: SimpleSO.swf

Here is a simple white board example:
package 
{ 

	// Class so we can display and/or be used in the Flash IDE
  	import flash.display.Sprite; 
  
  	// Class that allows a Shared Object to exist on FMS
  	import flash.net.SharedObject; 
  
  	// So we can get Status from the NetConnection (callback)
  	import flash.events.NetStatusEvent; 
  
  	// So we can get events from the SharedObject (callback)
  	import flash.events.SyncEvent; 
  
  	// So we can connect to FMS
  	import flash.net.NetConnection;
  	
	// For our mouse events (drawing)
	import flash.events.MouseEvent;
	  
  	public class WhiteBoardSO extends Sprite 
  	{
  		// Declare a SharedObject object
  		private var sharedObject:SharedObject;
  		
  		// Declare a NetConnection Object
  		private var netConnection:NetConnection;
  		
  		// Mouse Coordinates
  		private var startX:int;
  		private var startY:int;
  		private var endX:int;
  		private var endY:int;

		// Remote mouse coordinates
  		private var rstartX:int;
  		private var rstartY:int;
  		private var rendX:int;
  		private var rendY:int;


		// Constructor  
        public function WhiteBoardSO () 
        { 
        	trace("starting");
        	
        	// String with URL to app on FMS
        	var rtmpURL:String = "rtmp://itp.nyu.edu/sve204/WhiteBoard";

			// Instantiate NetConnection
			netConnection = new NetConnection();

			// Event listener, calls netStatusCallBack when a NetStatusEvent is fired
			netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusCallBack);

			// Connect to the application on the server
			netConnection.connect(rtmpURL);

			// Add the mouse event listeners
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEvent);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEvent);
			
			graphics.lineStyle(3, 0xFF0000, 1);

		}

		private function mouseDownEvent(mouseEvent:MouseEvent):void
		{
			trace("startx: " + mouseX);
			startX = mouseX;
			startY = mouseY;

            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMovedEvent);
		}
		
		private function mouseUpEvent(mouseEvent:MouseEvent):void
		{
			trace("endx: " + mouseX);
			
			endX = mouseX;
			endY = mouseY;
		
			graphics.moveTo(startX,startY);
			graphics.lineTo(endX,endY);
						
			sharedObject.setProperty("points",startX + "," + startY + "," + endX + "," + endY);

			stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMovedEvent);
		}
		
		private function mouseMovedEvent(mouseEvent:MouseEvent):void
		{
			endX = mouseX;
			endY = mouseY;
			
			graphics.moveTo(startX,startY)
			graphics.lineTo(endX,endY);
			
			sharedObject.setProperty("points",startX + "," + startY + "," + endX + "," + endY);
			
			startX = mouseX;
			startY = mouseY;
		}
        
        // NetStatusEvent Callback
        private function netStatusCallBack(nsEvent:NetStatusEvent):void 
        { 
        	// If we connected successfully
        	if (nsEvent.info.code == "NetConnection.Connect.Success")
        	{
				// Set up the shared object
				// We'll call it WhiteBoard, pass in the app url and not make it persistent
				sharedObject = SharedObject.getRemote("WhiteBoard",netConnection.uri,false);
				
				// Add a listener for when shared object is changed
			   	sharedObject.addEventListener (SyncEvent.SYNC,syncEventCallBack); 

				// Connect the shared object to our netConnection
				sharedObject.connect(netConnection);
        	}
        	else
        	{
				// Didn't connect
				trace("Sorry connection failed");
        	}
        } 


		private function syncEventCallBack(syncEvent:SyncEvent):void
		{
			//  Array of changes: syncEvent.changeList[]		
			for (var i:int = 0; i < syncEvent.changeList.length; i++)
			{
				trace(syncEvent.changeList[i].code);
				
				switch(syncEvent.changeList[i].code)
				{
					case "clear":
						break;
					case "success":
						break;
					case "change":
						var points:String = sharedObject.data.points;
						
						
						var pointsArray:Array = points.split(/,/);
						var rstartX:int = int(pointsArray[0]);
						var rstartY:int = int(pointsArray[1]);
						var rendX:int = int(pointsArray[2]);
						var rendY:int = int(pointsArray[3]);
						
						graphics.moveTo(rstartX,rstartY);
						graphics.lineTo(rendX,rendY);
			
						break;
				}
			}
		
		}
  } 
} 		
		

You can download the code: WhiteBoardSO.as or try it: WhiteBoardSO.swf