The following post is a copy of a post i originally contributed to the red5 mailing list.
Hello Red5 Community,
i am kind of new to red5 and spend the last days tyring to figure out how to use shared objects with red5.
In the following lines i like to summarise my experiences. This should serve as a hint for others who come accross the same questions and problems that i did.
Please feel free to correct or supplement the following lines where neccessary.
When discussing SharedObjects in the following, i refer to Remote Shared Objects and not Local Shared Objects of course. I also focus on non-persistent ones.
SharedObjects (SOs) are helpful to synchronize data between multiple clients in real-time and to invoke methods on multiple clients at once. A Remote SharedObject is an Object which is shared between multiple clients, namely all clients of the same scope.
So what is a Scope?
You can think of a scope as a chat room which is defined by the uri that is used to connect the server:
rtmp://localhost/red5test/lobby
red5test is the application scope
lobby is a room scope, a child scope of red5test
for more information on scopes see: http://jira.red5.org/confluence/display/docs/Scopes+and+Contexts
A Client can connect to a SO using the following Actionscript lines:
// at first you need to establish a connection to the server of course nc = new NetConnection(); nc.connect( "rtmp://localhost/red5test/", true ); // when the NetConnection is successfully established // (you have to listen to NetStatusEvent.NET_STATUS event) // you can connect to a remote SharedObject e.g. named "chat" so = SharedObject.getRemote("chat", nc.uri, false); // when the connection to the SO is successfully established, // you can begin to specify its contents so.setProperty("message","hello to all");
If a client connects to a SO, red5 looks into the specified scope if a SO named e.g. “chat” already exists.
If it does, red5 uses it, if not, red5 creates a new SO for the Scope and uses that.
When the last client connected to a SO disconnects from it, the SO will be destroyed (at least for non-persistent ones).
a) Access SOs on the serverside
SOs can also be accessed from the serverside, i.e. the server also can make changes to the SO and broadcast them to all connected clients.
To check wether a certain SO exists you can use the following lines in your Java Application:
//get scope of the current connection first IScope scope = Red5.getConnectionLocal().getScope(); // get SO ISharedObject so = getSharedObject(scope, "chat");
b) Create SOs on the serverside
You can also create SOs on the serverside with the following lines:
extracted from Joachim Bauchs tutorial:
To create a new shared object when a room is created, you can override the method roomStart in your application:
public class SampleApplication extends ApplicationAdapter { public boolean roomStart(IScope room) { if (!super.roomStart(room)) return false; createSharedObject(room, "sampleSO", true); ISharedObject so = getSharedObject(room, "sampleSO"); // Now you could do something with the shared object... return true; } }
If a shared object should be created for connections to the main application, e.g. rtmp://server/application, the same must be done in the method appStart.
One advantage is, that you can attach a Listener to the SO which is notified when a new client connects to the SO, updates data, disconnects etc. (See ISharedObjectListener)
Problem: clientside initiated vs. serverside initiated SOs
Creating SOs in your java application code can leed to some unexpected problems (It was at least for me).
The problem is related to something i refer to as clientside vs. serverside initiated SOs.
Of course all SOs wil be created on the red5 server. But there is a difference who initiated the creation.
The problem arises when you want to create a custom serverside SO for the main application:
e.g. I want to create an SO named “chat” in the main application scope and add a listener to it. So i put the following lines in my appStart method:
createSharedObject(scope, "chat", false); ISharedObject so = getSharedObject(scope, "chat"); ISharedObjectListener listener = new MyCustomListener(); so.addSharedObjectListener(listener);
Now when i start the server, appStart is called once the Application starts. My custom SO named “chat ” will be created (a serverside-initiated SO). Now when a client connects to the SO named “chat” in the main application scope, my custom SO will be used by red5. Everything works fine untill now.
But when all clients disconnect form this SO, my custom, serverside initiated SO will be destroyed by red5. After that, when a client connects to the SO named “chat”, red5 won’t find it anymore and will automatically create a new “genric” one. This new one now is clientside initiated, as i did not create it in the serverside code with createSharedObject. The difference now is, that no listener is attached to the new generic SO, and so no events will be fired anymore.
This problem is not that severe for SOs in a room scope. In this case you put your creation code inside the roomStart method. As the room is also destroyed when the last connected client disconnects, the roomStart method will be called multiple times during the application lifecycle, i.e. everytime the first client connects to a room. In this case the problem only arises when the last client disconnects from the SO but not the room.
It would be good to have something like a SharedObjectCreationHandler or a SharedObjectFactory, but unfortunately there is nothing like that. But there is a Handler which handles sort of SO creation events: the ISharedObjectSecurity.
This handler can be registered in the Application by registerSharedObjectSecurity. Its use is to controll access to shared objects. It contains an event method named isCreationAllowed: Prior to automatically creating a SO red5 checks if creation is allowed by calling this method.
Now if you want a custom serverside initiated SO to be created everytime red5 automatically tries to create a SO, you can put your SO creation code inside this method and return true. Red5 then knows creation is allowed and tries to create a SO. To do this red5f first checks if the SO already exists and !big surprise! it does, so red5 uses it and does not create one on its own.
import static org.red5.server.api.ScopeUtils.getScopeService; ... public class MySecurityHandler implements ISharedObjectSecurity { ... public boolean isCreationAllowed(IScope scope, String name, boolean persistent) { if ( "chat".equals(name) ) { // get the SO creation service. Basically the following lines are exactly // what MultiThreadedApplicationAdapter does. You can also pass a reference // to your Application to this SecurityHandler and use it instead ISharedObjectService service = (ISharedObjectService) getScopeService( scope, ISharedObjectService.class, SharedObjectService.class, false ); if( service.createSharedObject(scope, name, persistent) == true ) { ISharedObject so = service.getSharedObject(scope, name); ISharedObjectListener listener = new MyCustomListener(); so.addSharedObjectListener(listener); } } return true; } ... }
The method described here, was also discussed in: [Red5] creation handler to ShareObject
Here is good mail discussing that topic: http://osflash.org/pipermail/red5_osflash.org/2007-August/014406.html
That’s all,
hopefully it helps somebody.
Cheers,
Nik
—————–
Further tutorials on SOs: