Red5二次开发实现用户自定义逻辑

Red5二次开发实现用户自定义逻辑

上一篇文章介绍了Red5服务器的搭建是使用,这一篇文章将介绍如何在Red5中实现自己的逻辑。本文章是以第一篇为基础,默认已搭建好Red5服务器,不再介绍Red5服务器的搭建与使用。

准备工作

开发工具:Eclipse

Red5 Server:Red5 Server 1.0.9 https://github.com/Red5/red5-server

red5-eclipse-plugin:https://github.com/Red5/red5-eclipse-plugin

开发工具使用的Eclipse,因为需要使用Red5插件,而Red5插件仅支持Eclipse所以只能选择Eclipse

安装Eclipse插件

根据上面提供的链接下载Red5-eclipse-plugin插件,压缩包解压之后将发现目录中存在一个screenshots文件夹,里面为插件安装步骤的截图,Github中的Readme中也有插件安装的讲解,这里就不再演示插件的具体安装步骤。

在这里插入图片描述

注意:在使用之前需要对插件进行简单的修改,否则在配置Red5-server的时候会出现无法进行下一步的问题,以Windows为例,打开org.leagueplanet.server.glassfish目录,找到red5.serverdef并编辑,将文件中的所有.sh结尾的配置全部替换为.bat结尾。Linux系统同理,将.bat修改为.sh

在这里插入图片描述

安装完成后重启eclipse,window->show view->servers->new server.出现Red5 Server Runtime选项,说明安装成功。

创建Web项目

新建项目选择Dynamic Web project,第一次配置需要配置一下三处

在这里插入图片描述

首先Target runtime可能是空的,这时我们就需要选择New Runtime进行配置运行时环境,如下图所示,选择Infrared5中的Red5 Server RunTime,点击下一步

在这里插入图片描述

接下来还需要配置JRE和Red5 Server的路径,Runtime Directory就是选择我们解压的Red5 Server的目录

在这里插入图片描述

配置完成后可能下图所示的错误,这是因为我们下载的Red5 Server中相关jar包的命名包含版本信息,例如red5-io-1.8.0-Realease.jar,这时候就要将其修改为red5-io.jar

在这里插入图片描述

继续下一步,配置Red5的启动关闭文件以及相关端口号

在这里插入图片描述

现在我们回到了创建项目的页面,这是还需要对Configuration进行修改,点击Modify,按照下图进行勾选在这里插入图片描述

现在项目就创建完成了,生成服务端同时还生成了客户端

在这里插入图片描述

测试运行

Run Server选择Red5 Server Runtime

在这里插入图片描述

使用浏览器打开http://127.0.0.1:5080/demos/publisher.html,发布直播收看直播正常

在这里插入图片描述

实现自己的逻辑

在实现这些功能之前我们需要先了解一下Red5响应请求的具体流程

  1. Red5在启动时会调用RTMPMinaTransport的start()方法,该方法会开启rmtp的socket监听端口(默认是1935),然后使用Mina 的api 将RTMPMinaIoHandler 绑定到该端口。
  2. RTMPMinaIoHandler 上定义了messageReceived()、messageSent()、sessionOpened()和sessionClosed()等方法,当有socket请求时,相应的方法会被调用。这时RTMPMinaIoHandler 会使用当前的socket连接来创建一个(或者使用之前创建好的)RTMPMinaConnection,并将其作为参数传递给定义于RTMPHandler类上的相应的messageReceived()、messageSent()、connectionOpened()和connectionClosed()方法
  3. RTMPHandler会调用Server类的lookupGlobal()方法获得当前的GlobalScope,然后再利用GlobalScope找到当前socket请求应该使用的WebScope(这个WebScope 由开发者在WEB-INF\red5-web.xml中定义)。最后,RTMPHandler会调用RTMPMinaConnection 的connect ()方法连接到相应的WebScope。
  4. 通常来说,WebScope又会将请求转移给ApplicationAdapter,由它来最终响应请求,而项目中通过重载ApplicationAdapter的方法来实现自己的逻辑。至此,控制流进入了开发者的项目中。一般在具体使用中多会使用ApplicationAdapter的父类MultiThreadedApplicationAdapter,因为它是Red5应用程序的基础类,并且支持多线程,性能上要优于Application(未验证)。它提供了操作SharedObjects 和 streams的方法,还有连接和服务列表,是一个应用程序基本的Iscope。它实现了IstreamAwareScopeHandler接口,提供了在应用程序种控制流的方法。它还提供了一个很有用的事件控制器,可以拦截流、授权用户访问等。可以在其子类中添加各种方法,还可在客户端上通过NetConnection.call()方法调用服务器端的方法。
ApplicationAdapter核心方法
  1. public boolean appStart(IScope app);Red5应用程序启动时自动执行此方法,可以再这里执行一些初始化操作。
  2. public void appStop(IScope arg0);Red5应用程序停止时自动执行此方法。
  3. public boolean appConnect(IConnection arg0, Object[] arg1);当客户端连接本应用程序时自执行此方法。
  4. public boolean appDisconnect(Iconnection conn);当客户端断开连接时自动执行此方法。(如关闭浏览器、关闭FLASH PLAYER等特殊情况,均会触发该方法)。
  5. public boolean join(IClient arg0, IScope arg1);当有新的连接加入进来时自动调用。
  6. public void leave(IClient arg0, IScope arg1);连接断开
  7. public void streamPublishStart(IBroadcastStream stream);开始发布直播
  8. public void streamSubscriberStart(ISubscriberStream stream);开始播放流
  9. public void streamBroadcastClose(IBroadcastStream arg0);流结束
  10. public void streamSubscriberStart(ISubscriberStream stream);用户播放流
  11. public void streamSubscriberClose(ISubscriberStream arg0) ;用户断开播放
主要API简介
  1. IConnection:连接对象。每个连接都有一个关联的客户端和域。连接可能是持续型、轮询型、或短暂型。建立此接口的目的,是为了给不同的子类,如 RTMPConnection,RemotingConnection,AJAXConnection, HttpConnection 等,提供基础通用的方法。它提供getClient()方法来获取客服端对象。
  2. IScope :每个Red5应用程序至少有一个域,用来搭建处理器、环景、服务器之间的连接。域可以构成树形结构,所有客户端都可以作为其节点共享域内的对象(比如流和数据)。所有的客服端(client)通过连接(connection)连接到域中。对于单一域,每个连接对应一个客服端,每个客服端对应一个id,简单的应用,操作就针对一个id和一个连接进行。
  3. IServiceCapableConnection :获取有效连接。代码中先获取到连接实例,然后判断是否是有效连接并强制类型转换,之后调取客户端相应函数。
  4. IClient :客户端对象代表某单一客户端。一个客户端可以和同一主机下不同的域分别建立连接。客户端对象和HTTP session 很相像。可以使用IClientRegistry.newClient(Object[])方法来创建IClient对象。
  5. ApplicationAdapter:ApplicationAdapter是应用层级的IScope。若要处理流进程,需实现 IStreamAwareScopeHandler接口中的相应处理方法。ApplicationAdapter还提供了有效的事件处理机制,来进行截取流、确认用户等操作。同时,其子类中引入的方法均可在客户端通过 NetConnection 调取。在Aodbe 的FMS 中必须在服务器端维护客户端对象,与之相较,Red5 为您的远程请求提供了更加方便快捷的操作方法。

了解了实现流程和主要方法API后下面就开始

检查修改red5-web.xml文件,检查路径是否正确

<bean id="web.handler" class="org.red5.core.Application" />

检查修改red5-web.properties文件,这个文件是配置contextPath和Host,根据自己的需要设置,我的设置如下

webapp.contextPath=/red5-live
webapp.virtualHosts=*

然后就是创建Application类集成ApplicationAdapter类,重写相关方法,是先自定义逻辑

package org.red5.examples.springmvc;

import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.adapter.MultiThreadedApplicationAdapter;
import org.red5.server.api.IClient;
import org.red5.server.api.IConnection;
import org.red5.server.api.scope.IScope;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IServerStream;
//import org.slf4j.Logger;
import org.red5.server.api.stream.ISubscriberStream;
import org.springframework.stereotype.Component;

/**
 * Sample application that uses the client manager.
 * 
 * @author The Red5 Project (red5@osflash.org)
 */
@Component
public class Application extends MultiThreadedApplicationAdapter {
	
	//private static Logger log = Red5LoggerFactory.getLogger(Application.class);

	/** {@inheritDoc} */
    @Override
	public boolean connect(IConnection conn, IScope scope, Object[] params) {
    	//log.info("appConnect");
    	System.out.println("***********************************red5 connection...");
		return true;
	}

	/** {@inheritDoc} */
    @Override
	public void disconnect(IConnection conn, IScope scope) {
    	//log.info("disconnect");
    	System.out.println("red5 disconnect...");
		super.disconnect(conn, scope);
	}
    
    // 连接时触发的函数,定义本过程中的username

    
    /**
	 * 开始发布直播
	 */
	@Override
	public void streamPublishStart(IBroadcastStream stream) {
		System.out.println("[streamPublishStart]********** ");
		System.out.println("发布Key: " + stream.getPublishedName());
	}

	/**
	 * 流结束
	 */
	@Override
	public void streamBroadcastClose(IBroadcastStream arg0) {
		System.out.println("streamBroadcastClose...");
		super.streamBroadcastClose(arg0);
	}
 
	/**
	 * 用户断开播放
	 */
	@Override
	public void streamSubscriberClose(ISubscriberStream arg0) {
		System.out.println("streamBroadcastClose..."+arg0.getConnection().getSessionId()+" "+arg0.getBroadcastStreamPublishName());
		super.streamSubscriberClose(arg0);
	}
 
	/**
	 * 链接rtmp服务器
	 */
	@Override
	public boolean appConnect(IConnection arg0, Object[] arg1) {
		// TODO Auto-generated method stub
		System.out.println("[appConnect]********** ");
		System.out.println("请求域:" + arg0.getScope().getContextPath());
		System.out.println("id:" + arg0.getClient().getId());
		System.out.println("name:" + arg0.getClient().getId());
		System.out.println("**************** ");
		
		Map<String, Object> hm = arg0.getConnectParams(); 
	      String host =   (String) hm.get("pageUrl"); 
	      System.out.println("**************host:"+host);
	      String allowHost = "http://localhost:18082/red5/"; 
	      boolean ret = false; 
	      if(allowHost == null || (allowHost!=null&&allowHost!="")){ 
	          ret = true; 
	      }else { 
	             String[] args = allowHost.split(","); 
	             ret = false; 
	             if(host != null && (host!=null&&host!="") ){ 
	                 for(int i=0;i<args.length;++i){ 
	                     if(host.indexOf( args[i])>=0){ 
	                         ret = true; 
	                         break; 
	                     } 
	                 } 
	             } 
	     } 
	     if(ret){ 
	    	 return super.appConnect(arg0, arg1);
	     }else { 
	         return false; 
	     } 
		
	}
 
	/**
	 * 加入了rtmp服务器
	 */
	@Override
	public boolean join(IClient arg0, IScope arg1) {
		// TODO Auto-generated method stub
		System.out.println("**************** 加入了RTMP服务器");
		return super.join(arg0, arg1);
	}
 
	/**
	 * 开始播放流
	 */
	@Override
	public void streamSubscriberStart(ISubscriberStream stream) {
		System.out.println("[streamSubscriberStart]********** ");
		System.out.println("播放域:" + stream.getScope().getContextPath());
		System.out.println("播放Key:" + stream.getBroadcastStreamPublishName());
		System.out.println("********************************* ");
		String sessionId = stream.getConnection().getSessionId();
		stream.getConnection().setAttribute(null, null);  
		System.out.println("sessionId"+sessionId);
		String path = stream.getConnection().getPath();
		String address = stream.getConnection().getRemoteAddress();
		System.out.println("address"+address);
		System.out.println("path"+path);
		String param = (String) stream.getConnection().getConnectParams().get("queryString");
		System.out.println("param"+param);
		System.out.println("********************************* "+stream.getConnection().getHost());
		super.streamSubscriberStart(stream);
	}
 
	/**
	 * 离开了rtmp服务器
	 */
	@Override
	public void leave(IClient arg0, IScope arg1) {
		System.out.println("*****************"+arg0.getCreationTime());
		System.out.println("leave");
		super.leave(arg0, arg1);
	}
	
	@Override
	public boolean appStart(IScope app) {
		System.out.println("*****************app启动");
		return super.appStart(app);
	}
}

下面就是启动服务器进行测试

在这里插入图片描述

相关信息都打印到了控制台,说明自定义的逻辑已经成功执行!

以上就是Red5服务器实现自定义逻辑的方法,下一篇介绍使用Eclipse将普通Java项目转为Maven项目,并集成Spring MVC

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值