• How to send Flash data using the IExternalizable interface

    This article describes how to send Flash data to and from a Wowza Streaming Engine™ media server by implementing the IExternalizable interface. This can be used for object serialization, a method for transferring and storing data, validating data, sending remote procedure calls, distributing objects, and detecting changes in time-varying data. The example in this article demonstrates an echo of the Example class from the client to the media server and back.

    To see a working example of this setup, you can download the flashdatainjectionexample.zip file containing a plug and play JAR file that you can include in the [install-dir]/lib directory of your Wowza Streaming Engine media server installation. You can test the example using the included SWF and HTML files.

    Notes:
    • Wowza Streaming Engine software is required.

    • Flash CS version 5.5 or later is required.

    • Install the Wowza IDE if you haven't done so already.

    Implementation


    On the Flash side, create an actionscript class that implements IExternalizable (create file com/wowza/Example.as):

    package com.wowza 
    {
            import flash.utils.*;
    
    	public class Example implements IExternalizable 
    	{
    		private var propertyStringOne:String = "";
    		private var propertyStringTwo:String = "";
    		
    		public function writeExternal(output:IDataOutput):void 
    		{
    			output.writeUTF(this.propertyStringOne);
    			output.writeUTF(this.propertyStringTwo);
    		}
    		
    		public function readExternal(input:IDataInput):void 
    		{
    			this.propertyStringOne = input.readUTF();
    			this.propertyStringTwo = input.readUTF();
    		}
    	}
    }
    Create an FLA file that connects to the Wowza Streaming Engine media server. Use that connection and create an instance of the Example object to send to your media server:
    import flash.net.NetConnection;
    import flash.utils.IExternalizable;
    import flash.external.ExternalInterface;
    import com.wowza.Example;
    
    var nc:NetConnection = null;
    
    function ncOnStatus(infoObject:NetStatusEvent)
    {
    	trace("nc: "+infoObject.info.code+" ("+infoObject.info.description+")");
    	if (infoObject.info.code == "NetConnection.Connect.Success")
    	{
    		doPlay.enabled=true;
    	}	
    }
    
    function sendData(event:MouseEvent)
    {
    	var secureResult:Object = new Object();
    	secureResult.onResult = function(testResult)
    	{ 
    		 ExternalInterface.call("console.log", ">> From Wowza :: "+testResult.propertyStringOne+":"+testResult.propertyStringTwo);
    	}
    
    	var testObj:Example = new Example();
    	testObj.propertyStringOne = "propertyStringOne";
    	testObj.propertyStringTwo = "propertyStringTwo";  
    	nc.call("testMethod", new Responder(secureResult.onResult), testObj);
    }
    
    function main(){ 
    	registerClassAlias("com.wowza.wms.plugin.test2.AMFExternalizableTest", Example);
    	
    	doPlay.addEventListener(MouseEvent.CLICK, sendData);
    
    	nc = new NetConnection();
    	nc.objectEncoding = ObjectEncoding.AMF3; //should be by default
    	nc.addEventListener(NetStatusEvent.NET_STATUS, ncOnStatus);
    	nc.connect("rtmp://localhost/vod");
    	
    	doPlay.enabled=false;
    }
    main();
    In the example above, a button is added that's enabled after successful connection. Click this new button to initiate the exchange between the client and the Wowza Streaming Engine media server.

    On the media server side, create a module (JAR file) that implements testMethod:
    package com.wowza.wms.plugin.test2;
    
    import com.wowza.wms.amf.*;
    import com.wowza.wms.application.*;
    import com.wowza.wms.client.*;
    import com.wowza.wms.module.*;
    import com.wowza.wms.request.*;
    
    public class ModuleExternalize extends ModuleBase
    {
    	public void onAppStart(IApplicationInstance appInstance)
    	{ 
    	}
    	
    	public void testMethod(IClient client, RequestFunction function, AMFDataList params)
    	{
    		try{
                            // This will print out the data as received by your flash client
    			getLogger().info("ModuleExternalize.testMethod: "+params.toString());
    		
    			// example of how to create an AMF object that has custom serialization
                            // AMFDataObj newResult = new AMFDataObj();
                            // AMFExternalizableTest newSerializer = new AMFExternalizableTest();
    			// newResult.put("str0", new AMFDataItem("teststring1"));
    			// newResult.put("str1", new AMFDataItem("teststring2"));
    			// newResult.setSerializer(newSerializer); 
    			// sendResult(client, params, newResult); 
    			
                            // simply relay the data so you can see the object pass between client/server.
    			sendResult(client, params, params.get(PARAM1)); 
    			
    		}
    		catch(Exception ex){
    			getLogger().info("ModuleExternalize.testMethod response error: "+ex.getMessage());
    		}
    	}
    }
    Create a class that will be used for serialization. The example AMFExternalizableTest class below defines two class variables: propertyStringOne and propertyStringTwo. This class uses a simple ArrayList of the given properties that we defined on both the client and server side (propertyStringOne and propertyStringTwo) to iterate through in both the serialize and deserialize methods.

    package com.wowza.wms.plugin.test2;
    
    import java.io.DataOutputStream;
    import java.nio.ByteBuffer;
    import java.util.ArrayList;
    
    import com.wowza.util.BufferUtils;
    import com.wowza.wms.amf.AMFDataContextDeserialize;
    import com.wowza.wms.amf.AMFDataContextSerialize;
    import com.wowza.wms.amf.AMFDataItem;
    import com.wowza.wms.amf.AMFDataObj;
    import com.wowza.wms.amf.IAMFExternalizable;
    
    public class AMFExternalizableTest implements IAMFExternalizable
    {
    	private String className = "com.wowza.wms.plugin.test2.AMFExternalizableTest";
    	private ArrayList<String> classProperties = new ArrayList<String>();
    	
    	public AMFExternalizableTest(){
    		classProperties.add("propertyStringOne");
    		classProperties.add("propertyStringTwo");
    	}
    	
    	public String getClassName()
    	{
    		return className;
    	}
    	
    	public void setClassName(String className)
    	{
    		this.className = className;
    	}
    	
    	public void deserialize(AMFDataObj amfObj, ByteBuffer data, AMFDataContextDeserialize context)
    	{ 
    		try
    		{	
    			for(int i=0;i<classProperties.size();i++)
    			{
    				int utflen = BufferUtils.getUnsignedShort(data);
    				byte[] strBytes = new byte[utflen];
    				data.get(strBytes);
    				
    				amfObj.put(classProperties.get(i), new AMFDataItem(new String(strBytes, "UTF-8")));
    			}
    		}
    		catch(Exception e)
    		{
    			System.out.println("ERROR: "+e.toString());
    		}
    	}
    	
    	public void serialize(AMFDataObj amfObj, DataOutputStream out, AMFDataContextSerialize context)
    	{ 
    		try
    		{
    			for(int i=0;i<classProperties.size();i++)
    			{
    				String str = amfObj.getString(classProperties.get(i));
    				if (str == null)
    					str = "";
    				
    				out.writeUTF(str);
    			}
    		}
    		catch(Exception e)
    		{
    			System.out.println("ERROR: "+e.toString());
    		}
    	}
    }

    Originally Published: For Wowza Streaming Engine on 12-24-2015.

    If you're having problems or want to discuss this article, post in our forum.