注意:在这个例子中,只是这个应用程序的作用域有sample处理程序,而不是子作用域,如果想这个处理程序同样在房间中起作用,必须在房间的作用域内的roomStart方法中注册它。
Calls to client methods
调用客户端的方法
从red5的应用程序中调用客户端方法函数,你首先需要一个当前连接对象作为参考
代码如下:
import org.red5.server.api.IConnection;
import org.red5.server.api.Red5;
import org.red5.server.api.service.IServiceCapableConnection;
...
IConnection conn = Red5.getConnectionLocal();
如果这个连接对象执行了IServiceCapableConnection,那么它就支持调用在另一个目标的方法
代码如下:
if (conn instanceof IServiceCapableConnection) {
IServiceCapableConnection sc = (IServiceCapableConnection) conn;
sc.invoke("the_method", new Object[]{"One", 1});
}
如果你需要方法调用的结果,你必须提供一个类作为第三个参数,这个类执行IPendingServiceCallback
代码如下:
import org.red5.server.api.service.IPendingService;
import org.red5.server.api.service.IPendingServiceCallback;
class MyCallback implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
// Do something with "call.getResult()"
}
}
The method call looks now like this:
这个方法的调用例子如下:
if (conn instanceof IServiceCapableConnection) {
IServiceCapableConnection sc = (IServiceCapableConnection) conn;
sc.invoke("the_method", new Object[]{"One", 1}, new MyCallback());
}
当然你能够在你的应用程序中执行这些,而且能传递该应用程序的实例
SharedObjects
共享对象
访问和处理共享对象的接口函数已经被指定在ISharedObjectService类中
当我们在服务器端执行脚本处理共享对象的时候,需要特别指出的是这些被操作的共享对象一定要是在同一个作用域中被创建的。
当一个房间被被创建的同时创建一个新的共享对象,你可以在应用程序中重写你的roomStart函数:
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IScope;
import org.red5.server.api.so.ISharedObject;
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;
}
}
现在每次第一个用户连接到该应用程序的房间时,一个共享对象 sampleSO就会被服务器端创建.
一个共享对象应该被创建作为主程序的连接点,例如:rtmp://server/application 那么这个创建动作就应该在函数appStart中进行.
关于进一步的共享对象的函数信息,请大家参考ISharedObject的api参考文档
Serverside change listeners
服务器端执行改变监听事件
要像在FCS/FMS一样,得到共享对象的改变信息,一个监听器,就必须实现ISharedObjectListener类,示例代码如下:
import org.red5.server.api.so.ISharedObject;
import org.red5.server.api.so.ISharedObjectListener;
public class SampleSharedObjectListener
implements ISharedObjectListener {
public void onSharedObjectUpdate(ISharedObject so,
String key, Object value) {
// The attribute <key> of the shared object <so>
// was changed to <value>.
}
public void onSharedObjectDelete(ISharedObject so, String key) {
// The attribute <key> of the shared object <so> was deleted.
}
public void onSharedObjectSend(ISharedObject so,
String method, List params) {
// The handler <method> of the shared object <so> was called
// with the parameters <params>.
}
// Other methods as described in the interface...
}
此外,这个监听器还必须被注册在共享对象上,代码如下:
ISharedObject so = getSharedObject(scope, "sampleSO");
so.addSharedObjectListener(new SampleSharedObjectListener())
Changing from application code
从应用程序代码去改变共享对象的值
在服务器端改变共享对象示例代码如下:
ISharedObject so = getSharedObject(scope, "sampleSO");
so.setAttribute("fullname", "Sample user");
所有的作用域范围内注册了事件处理器的客户端也都会收到共享对象属性更改的通知
如果想要把多个操作共享对象的操作合并成一条更新事件发给作用域内的所有客户端,那么可以使用函数beginUpdate 和endUpdate,代码如下:
ISharedObject so = getSharedObject(scope, "sampleSO");
so.beginUpdate();
so.setAttribute("One", "1");
so.setAttribute("Two", "2");
so.removeAttribute("Three");
so.endUpdate();
服务器端执行的监听器将会通过各自的回调函数收到他们的更新通知
SharedObject event handlers
共享对象事件处理
从一个flash客户端或者相应的服务器端,通过remote_so.send(<handler>, <args>)调用共享对象,这个调用会被映射为red5的函数,因此一个事件处理程序必须通过ISharedObjectHandlerProvider的函数被注册。示例代码如下:
package com.fancycode.red5;
class MySharedObjectHandler {
public void myMethod(String arg1) {
// Now do something
}
}
...
ISharedObject so = getSharedObject(scope, "sampleSO");
so.registerServiceHandler(new MySharedObjectHandler());
可以给处理程序命名,代码如下:
ISharedObject so = getSharedObject(scope, "sampleSO");
so.registerServiceHandler("one.two", new MySharedObjectHandler());
这里处理程序被命名为one.two.myMethod
另一个为共享对象定义事件处理程序的方法是在red5-web.xml文件中增加他们
具体实例如下:
<bean id="sampleSO.one.two.soservice"
class="com.fancycode.red5.MySharedObjectHandler"
singleton="true" />
Persistence
持续性(持久性)
持续性被用于如在服务器重启后,对象的属性仍然有效能被使用。在FCS/FMS中通常有些服务器端的局部共享对象被用于这方面
Red5能使任意的对象具有持续性(持久性),实现他们需要使用IPersistable 类,基本上这些对象都会有 类型,路径,字符串名称 并且他们知道怎样去序列化和反序列化他们本身
下面是个序列化和反序列化的例子:
import java.io.IOException;
import org.red5.io.object.Input;
import org.red5.io.object.Output;
import org.red5.server.api.persistence.IPersistable;
class MyPersistentObject implements IPersistable {
// Attribute that will be made persistent
private String data = "My persistent value";
void serialize(Output output) throws IOException {
// Save the objects's data.
output.writeString(data);
}
void deserialize(Input input) throws IOException {
// Load the object's data.
data = input.readString();
}
// Other methods as described in the interface...
}
保存或者载入这个对象可以使用如下示例代码:
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IScope;
import org.red5.server.api.Red5;
import org.red5.server.api.persistence.IPersistenceStore;
class MyApplication extends ApplicationAdapter {
private void saveObject(MyPersistentObject object) {
// Get current scope.
IScope scope = Red5.getConnectionLocal().getScope();
// Save object in current scope.
scope.getStore().save(object);
}
private void loadObject(MyPersistentObject object) {
// Get current scope.
IScope scope = Red5.getConnectionLocal().getScope();
// Load object from current scope.
scope.getStore().load(object);
}
}
对于一个应用程序如果被要求没有自定义的对象,而且是数据后来还要被重复使用,那么可以用类IAttributeStore ,将他们存储在作用域内,作用域内的所有属性都不是用IPersistable方式开启的,
后端存储这些对象的方式是可以配置的,默认的状态下存储在内存和文件系统中是有效滴
使用文件系统的存储方式时,会为每一个对象创建一个文件,这个文件会被创建在"webapps/<app>/persistence/<type>/<path>/<name>.red5",例如:对于一个共享对象“theSO”存在于"rtmp://server/myApp/room1"的连接中,同时一个文件会创建在"webapps/myApp/persistence/SharedObject/room1/theSO.red5"
Periodic events
循环事件
应用程序中都需要按规律执行某个任务,在FCS/FMS中使用setInterval函数去执行循环事件
Red5提供了一个时序安排服务在ISchedulingService类中,该类也和其他服务一样是继承自ApplicationAdapter类。这个服务能够注册一个对象(这个对象需要实现IScheduledJob类)执行以固定时间间隔去执行函数
去注册这个对象的类似示例代码如下:
import org.red5.server.api.IScope;
import org.red5.server.api.IScheduledJob;
import org.red5.server.api.ISchedulingService;
import org.red5.server.adapter.ApplicationAdapter;
class MyJob implements IScheduledJob {
public void execute(ISchedulingService service) {
// Do something
}
}
public class SampleApplication extends ApplicationAdapter {
public boolean roomStart(IScope room) {
if (!super.roomStart(room))
return false;
// Schedule invokation of job every 10 seconds.
String id = addScheduledJob(10000, new MyJob());
room.setAttribute("MyJobId", id);
return true;
}
}
addScheduledJob函数返回的id能够用于后来去停止执行已经被注册的事件
示例代码如下:
public void roomStop(IScope room) {
String id = (String) room.getAttribute("MyJobId");
removeScheduledJob(id);
super.roomStop(room);
}