How to track users using a SharedObject

The following is example code to track connected users in a shared object:
 

package com.wowza.wms.plugin.test.module;

import com.wowza.wms.module.*; 
import com.wowza.wms.client.*;
import com.wowza.wms.application.*;
import com.wowza.wms.sharedobject.*;

public class ModuleConnectedUserSO extends ModuleBase
{
	static public final String CONNECTEDUSERS_SONAME = "connectedUsersSO";

	public void onAppStart(IApplicationInstance appInstance)
	{
		getLogger().info("onAppStart: ");

		// Create a shared object to keep track of the connected users
		ISharedObjects sharedObjects = appInstance.getSharedObjects(false);
		ISharedObject connectedUsersSO = new SharedObject(CONNECTEDUSERS_SONAME);
		sharedObjects.put(CONNECTEDUSERS_SONAME, connectedUsersSO);

		connectedUsersSO.lock();
		try
		{
			connectedUsersSO.acquire();
		}
		catch (Exception e)
		{

		}
		finally
		{
			connectedUsersSO.unlock();
		}
		getLogger().info("onAppStart: create shared object: "+CONNECTEDUSERS_SONAME);
	}

	public void onAppStop(IApplicationInstance appInstance)
	{
		getLogger().info("onAppStop: ");

		// release the shared object when the application stops
		ISharedObjects sharedObjects = appInstance.getSharedObjects(false);
		ISharedObject connectedUsersSO = sharedObjects.get(CONNECTEDUSERS_SONAME);
		if (connectedUsersSO != null)
		{
			getLogger().info("onAppStart: release shared object: "+CONNECTEDUSERS_SONAME);
			connectedUsersSO.lock();
			try
			{
				connectedUsersSO.release();
			}
			catch (Exception e)
			{

			}
			finally
			{
				connectedUsersSO.unlock();
			}
		}
	}

	public void onConnect(IClient client, RequestFunction function, AMFDataList params) 
	{

		String userName = getParamString(params, PARAM1);
		client.getProperties().setProperty("userName", userName);

	}
	public void onConnectAccept(IClient client)
	{
		// when a client connection is accepted add a property to the shared object
		// that notifies all connections of new client
		getLogger().info("onConnectAccept: "+client.getClientId());
		ISharedObjects sharedObjects = getAppInstance(client).getSharedObjects(false);
		ISharedObject connectedUsersSO = sharedObjects.get(CONNECTEDUSERS_SONAME);
		if (connectedUsersSO != null)
		{
			connectedUsersSO.lock();
			try
			{
				getLogger().info("onConnectAccept: add property: "+client.getClientId());
				String userName = client.getProperties().getPropertyStr("userName");
				String propName = userName+ ": " + client.getClientId();
				connectedUsersSO.setProperty(propName, "connected");
			}
			catch (Exception e)
			{

			}
			finally
			{
				connectedUsersSO.unlock();
			}
		}
	}

	public void onDisconnect(IClient client)
	{
		// When the client is disconnected remove the property from the shared object
		getLogger().info("onDisconnect: "+client.getClientId());
		ISharedObjects sharedObjects = getAppInstance(client).getSharedObjects(false);
		ISharedObject connectedUsersSO = sharedObjects.get(CONNECTEDUSERS_SONAME);
		if (connectedUsersSO != null)
		{
			synchronized(connectedUsersSO)
			{
				connectedUsersSO.lock();
				try
				{
					getLogger().info("onDisconnect: remove property: "+client.getClientId());
					String propName = "c"+client.getClientId();
					connectedUsersSO.deleteSlot(propName);
					connectedUsersSO.purge(connectedUsersSO.getVersion()-200);
				}
				catch (Exception e)
				{

				}
				finally
				{
					connectedUsersSO.unlock();
				}
			}
		}
	}
}
Note: On May 23, 2008 I removed the pinging code since it is no longer needed based on new features.

This is the essential client-side Actionscript. This includes an binadable ArrayCollection that would only be useful in a Flex application:
 
import flash.events.NetStatusEvent;
import flash.net.NetConnection;
import flash.net.SharedObject;
// for Flex
import mx.collections.ArrayCollection;


public function doConnect(event:Event = null):void 
{
	nc = new NetConnection();
	nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
	nc.connect("rtmp://[wowza-address]/[appName],"Charlie");
}


function netStatusHandler(infoObject:NetStatusEvent):void 
{
	connectedUsersSO = SharedObject.getRemote("connectedUsersSO", nc.uri, false);
	connectedUsersSO.addEventListener(SyncEvent.SYNC, streamSynch);
	connectedUsersSO.connect(nc);

}

// for Flex
[Bindable]
public var streamList:ArrayCollection;

private function streamSynch(event:SyncEvent):void
{
	var results:Object = event.target.data;
        var array:Array = new Array();
        for( var item:String in results )
	{
		var obj:Object = new Object();
		obj.label = results[ item ];
		obj.value = item;
		array.push( obj );
	}
	// for Flex
	streamList = new ArrayCollection(array);
}

Originally Published: 10-03-2010.

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