使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用 -- 监控直播频道
2013-09-25 20:40
411 查看
跟 Red5 类似,Wowza 支持服务扩展,用户可以进行自定义应用程序开发,然后将其作为一个模块部署在 Wowza 服务器。Red5 提供了一个 Eclipse 插件进行应用扩展开发(参见《eclipse 的 Red5 插件安装简介》),Wowza 则提供了一个 IDE。本文简要介绍如何使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用。《安装并使用 Wowza 发布你的 RTMP 直播流》一文介绍了如何安装 Wowza 服务器并提供直播服务,本文将继续以此为例,介绍如何使用 Wowza IDE 开发应用对每个流频道进行监控。
I. 下载 Wowza IDE
官方下载地址 http://wowza.cn/mediaserver/developers(笔者 2014-03-18 10:28 注:Wowza4 发布之后,官方这个链接不再提供 IDE 下载。笔者推荐安装 Wowza IDE 插件到 Eclipse 进行开发,参考《Eclipse 安装/更新 Wowza IDE 插件的步骤》),选择适合你自己的平台的版本进行下载 (英文官网下载地址:http://www.wowza.com/pricing/installer)。
作者上传了一个 Windows 版本的到 CSDN 资源以做备份,如果看官嫌从官网下载速度太慢,可以点击下载:
WowzaIDE-2.0.0.exe
II. 安装
Windows 下直接运行步骤 I 下载的 WowzaIDE-2.0.0.exe。
安装好以后,开始 -> 程序 -> Wowza IDE 2 -> Wowza IDE 2 启动 IDE,选择一个目录作为你的工作台,进入后的界面跟 Eclipse 一般无二:
III. 新建项目
File -> New -> Wowza Media Server Project,打开新建项目向导,输入项目名 defonds-live-module:
其中,新项目名 defonds-live-module 也会作为 .jar 的文件名,之后作为一个模块被 Wowza IDE 自动部署在 Wowza 服务器 wowza/lib 目录下;Wowza Media Server /Location 应该指向你的 Wowza 服务器的安装目录。
点击 Next > 按钮,进入新建 WMS 模块类对话框:
包名栏输入:com.defonds.wms.module;
类名栏输入:DefondsLiveModule;
自定义方法名输入:doSomething,这个方法可以被客户端直接调用(NetConnection.call(“doSomething”, null);)。类 DefondsLiveModule 创建以后,你可以使用 doSomething 同样的标签来创建更多自定义方法;
Event Methods 部分是留给你捕捉一系列事件的接口,在这些事件发生时,这些方法将被调用。本文例子里保持默认选择,点击 Finish 按钮。
IDE 会创建 WMS 模块项目,创建模块类,创建一个运行命令并编译和绑定模块类到一个 jar 文件里,这个 jar 文件会被自动部署到 WMS 安装目录下:
最后编辑 DefondsLiveModule 类内容如下:
IV. 导入例子模块的类
Package Explorer 视图下,右击 defonds-live-module 项目中 src 下的 com.defonds.wms.module -> 选择 Import… -> 在导入对话框里,展开 General 文件夹 -> 选中 File System 后点击 Next > 按钮 -> 点击 Browse… 按钮 -> 浏览至 %Wowza%/examples/ServerSideModules/server 文件夹(这个是 Wowza 服务器安装的一部分) 后确定 -> 勾选 ModuleServerSide.java 后点 Finish 按钮,如下图所示。
这样子我们就把 ModuleServerSide.java 给导入进来了,Package Explorer 视图中双击导入的类名,发现有编译错误:
将 package com.mycompany.wms.module; 换成我们自定义的包名 package com.defonds.wms.module; 即可。
V. 配置 Application.xml
现在我们已经使用 Wowza IDE 构建好了我们自己定义的 defonds-live-module.jar,我们还需要指示 Wowza 服务器加载这个新模块。
编辑 %Wowza%/conf/live/Application.xml 文件,将以下模块定义添加进 <Modules> 部分的结尾:
这时我们的新模块才正式生效了。如果这一步不明白可以去看《安装并使用 Wowza 发布你的 RTMP 直播流》。
VI. 启动服务
这时我们可以在 Wowza IDE 内部启动 Wowza 服务器了。如果你已经启动了一个 service 模式或者 standalone 模式的 Wowza 服务器,那么你要先将其关闭。点击 Wowza IDE 的工具栏里的 Run 菜单里的 WowzaMediaServer_defonds-live-module 启动 Wowza 服务器。当然你也可以点击 Debug 菜单里的 WowzaMediaServer_defonds-live-module 以 debug 模式启动 Wowza。
这时 Wowza 服务器启动起来了,在 Wowza IDE 的下部的控制台标签里可以看到所有的控制台 log 输出。如同 Eclipse 中的 Tomcat,你可以在控制台窗口中点击关闭图标来停止服务器运行。
VII. 模块调试
现在我们来测试一下新模块的运行情况。使用你的 RTMP Client 发送 RTMP 流到 Wowza,比如 Server URL 为 rtmp://172.21.30.104/live,流名为 xxxxS_2059a0734ccfqvga,成功连接 Wowza 服务器。
Wowza IDE 控制台有 onPublish[live/_definst_/xxxxS_2059a0734ccfqvga]: streamName:xxxxS_2059a0734ccfqvga isRecord:false isAppend:false 输出,这个正是我们 DefondsLiveModule 类里的 StreamListener.onPublish 里定义的,测试成功。
参考资料
Wowza IDE User’s Guide
http://www.wowza.com/forums/content.php?472-How-to-start-and-stop-live-stream-recordings-programmatically-(IMediaStreamActionNotify3)
I. 下载 Wowza IDE
官方下载地址 http://wowza.cn/mediaserver/developers(笔者 2014-03-18 10:28 注:Wowza4 发布之后,官方这个链接不再提供 IDE 下载。笔者推荐安装 Wowza IDE 插件到 Eclipse 进行开发,参考《Eclipse 安装/更新 Wowza IDE 插件的步骤》),选择适合你自己的平台的版本进行下载 (英文官网下载地址:http://www.wowza.com/pricing/installer)。
作者上传了一个 Windows 版本的到 CSDN 资源以做备份,如果看官嫌从官网下载速度太慢,可以点击下载:
WowzaIDE-2.0.0.exe
II. 安装
Windows 下直接运行步骤 I 下载的 WowzaIDE-2.0.0.exe。
安装好以后,开始 -> 程序 -> Wowza IDE 2 -> Wowza IDE 2 启动 IDE,选择一个目录作为你的工作台,进入后的界面跟 Eclipse 一般无二:
III. 新建项目
File -> New -> Wowza Media Server Project,打开新建项目向导,输入项目名 defonds-live-module:
其中,新项目名 defonds-live-module 也会作为 .jar 的文件名,之后作为一个模块被 Wowza IDE 自动部署在 Wowza 服务器 wowza/lib 目录下;Wowza Media Server /Location 应该指向你的 Wowza 服务器的安装目录。
点击 Next > 按钮,进入新建 WMS 模块类对话框:
包名栏输入:com.defonds.wms.module;
类名栏输入:DefondsLiveModule;
自定义方法名输入:doSomething,这个方法可以被客户端直接调用(NetConnection.call(“doSomething”, null);)。类 DefondsLiveModule 创建以后,你可以使用 doSomething 同样的标签来创建更多自定义方法;
Event Methods 部分是留给你捕捉一系列事件的接口,在这些事件发生时,这些方法将被调用。本文例子里保持默认选择,点击 Finish 按钮。
IDE 会创建 WMS 模块项目,创建模块类,创建一个运行命令并编译和绑定模块类到一个 jar 文件里,这个 jar 文件会被自动部署到 WMS 安装目录下:
最后编辑 DefondsLiveModule 类内容如下:
package com.defonds.wms.module; import java.util.HashMap; import java.util.Map; import com.wowza.wms.livestreamrecord.model.ILiveStreamRecord; import com.wowza.wms.livestreamrecord.model.LiveStreamRecorderMP4; import com.wowza.wms.media.model.MediaCodecInfoAudio; import com.wowza.wms.media.model.MediaCodecInfoVideo; import com.wowza.wms.module.*; import com.wowza.wms.stream.*; import com.wowza.wms.amf.AMFPacket; import com.wowza.wms.application.IApplicationInstance; import com.wowza.wms.application.WMSProperties; public class DefondsLiveModule extends ModuleBase implements IModuleOnStream { private Map<String, ILiveStreamRecord> recorders = new HashMap<String, ILiveStreamRecord>(); private IApplicationInstance appInstance; public void onAppStart(IApplicationInstance appInstance) { this.appInstance = appInstance; } class StreamListener implements IMediaStreamActionNotify3 { public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket) { System.out.println("onMetaData[" + stream.getContextStr() + "]: " + metaDataPacket.toString()); } public void onPauseRaw(IMediaStream stream, boolean isPause, double location) { System.out.println("onPauseRaw[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location); } public void onPause(IMediaStream stream, boolean isPause, double location) { System.out.println("onPause[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location); } public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset) { System.out.println("onPlay[" + stream.getContextStr() + "]: playStart:" + playStart + " playLen:" + playLen + " playReset:" + playReset); } public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend) { System.out.println("onPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend); //create a livestreamrecorder instance to create .mp4 files ILiveStreamRecord recorder = new LiveStreamRecorderMP4(); recorder.init(appInstance); recorder.setRecordData(true); recorder.setStartOnKeyFrame(true); recorder.setVersionFile(true); // add it to the recorders list synchronized (recorders) { ILiveStreamRecord prevRecorder = recorders.get(streamName); if (prevRecorder != null) prevRecorder.stopRecording(); recorders.put(streamName, recorder); } // start recording, create 1 minute segments using default content path System.out.println("--- startRecordingSegmentByDuration for 60 minutes"); recorder.startRecordingSegmentByDuration(stream, null, null, 60*60*1000); // start recording, create 1MB segments using default content path //System.out.println("--- startRecordingSegmentBySize for 1MB"); //recorder.startRecordingSegmentBySize(stream, null, null, 1024*1024); // start recording, create new segment at 1:00am each day. //System.out.println("--- startRecordingSegmentBySchedule every "0 1 * * * *"); //recorder.startRecordingSegmentBySchedule(stream, null, null, "0 1 * * * *"); // start recording, using the default content path, do not append (i.e. overwrite if file exists) //System.out.println("--- startRecording"); //recorder.startRecording(stream, false); // log where the recording is being written System.out.println("onPublish[" + stream.getContextStr() + "]: new Recording started:" + recorder.getFilePath()); } public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend) { System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend); ILiveStreamRecord recorder = null; synchronized (recorders) { recorder = recorders.remove(streamName); } if (recorder != null) { // grab the current path to the recorded file String filepath = recorder.getFilePath(); // stop recording recorder.stopRecording(); System.out.println("onUnPublish[" + stream.getContextStr() + "]: File Closed:" + filepath); } else { System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " stream recorder not found"); } } public void onSeek(IMediaStream stream, double location) { System.out.println("onSeek[" + stream.getContextStr() + "]: location:" + location); } public void onStop(IMediaStream stream) { System.out.println("onStop[" + stream.getContextStr() + "]: "); } public void onCodecInfoAudio(IMediaStream stream,MediaCodecInfoAudio codecInfoAudio) { System.out.println("onCodecInfoAudio[" + stream.getContextStr() + " Audio Codec" + codecInfoAudio.toCodecsStr() + "]: "); } public void onCodecInfoVideo(IMediaStream stream,MediaCodecInfoVideo codecInfoVideo) { System.out.println("onCodecInfoVideo[" + stream.getContextStr() + " Video Codec" + codecInfoVideo.toCodecsStr() + "]: "); } } public void onStreamCreate(IMediaStream stream) { getLogger().info("onStreamCreate["+stream+"]: clientId:" + stream.getClientId()); IMediaStreamActionNotify3 actionNotify = new StreamListener(); WMSProperties props = stream.getProperties(); synchronized (props) { props.put("streamActionNotifier", actionNotify); } stream.addClientListener(actionNotify); } public void onStreamDestroy(IMediaStream stream) { getLogger().info("onStreamDestroy["+stream+"]: clientId:" + stream.getClientId()); IMediaStreamActionNotify3 actionNotify = null; WMSProperties props = stream.getProperties(); synchronized (props) { actionNotify = (IMediaStreamActionNotify3) stream.getProperties().get("streamActionNotifier"); } if (actionNotify != null) { stream.removeClientListener(actionNotify); getLogger().info("removeClientListener: " + stream.getSrc()); } } }
IV. 导入例子模块的类
Package Explorer 视图下,右击 defonds-live-module 项目中 src 下的 com.defonds.wms.module -> 选择 Import… -> 在导入对话框里,展开 General 文件夹 -> 选中 File System 后点击 Next > 按钮 -> 点击 Browse… 按钮 -> 浏览至 %Wowza%/examples/ServerSideModules/server 文件夹(这个是 Wowza 服务器安装的一部分) 后确定 -> 勾选 ModuleServerSide.java 后点 Finish 按钮,如下图所示。
这样子我们就把 ModuleServerSide.java 给导入进来了,Package Explorer 视图中双击导入的类名,发现有编译错误:
将 package com.mycompany.wms.module; 换成我们自定义的包名 package com.defonds.wms.module; 即可。
V. 配置 Application.xml
现在我们已经使用 Wowza IDE 构建好了我们自己定义的 defonds-live-module.jar,我们还需要指示 Wowza 服务器加载这个新模块。
编辑 %Wowza%/conf/live/Application.xml 文件,将以下模块定义添加进 <Modules> 部分的结尾:
<Module> <Name>DefondsLiveModule</Name> <Description>DefondsLiveModule</Description> <Class>com.defonds.wms.module.DefondsLiveModule</Class> </Module> <Module> <Name>ModuleServerSide</Name> <Description>Defonds ModuleServerSide</Description> <Class>com.defonds.wms.module.ModuleServerSide</Class> </Module>
这时我们的新模块才正式生效了。如果这一步不明白可以去看《安装并使用 Wowza 发布你的 RTMP 直播流》。
VI. 启动服务
这时我们可以在 Wowza IDE 内部启动 Wowza 服务器了。如果你已经启动了一个 service 模式或者 standalone 模式的 Wowza 服务器,那么你要先将其关闭。点击 Wowza IDE 的工具栏里的 Run 菜单里的 WowzaMediaServer_defonds-live-module 启动 Wowza 服务器。当然你也可以点击 Debug 菜单里的 WowzaMediaServer_defonds-live-module 以 debug 模式启动 Wowza。
这时 Wowza 服务器启动起来了,在 Wowza IDE 的下部的控制台标签里可以看到所有的控制台 log 输出。如同 Eclipse 中的 Tomcat,你可以在控制台窗口中点击关闭图标来停止服务器运行。
VII. 模块调试
现在我们来测试一下新模块的运行情况。使用你的 RTMP Client 发送 RTMP 流到 Wowza,比如 Server URL 为 rtmp://172.21.30.104/live,流名为 xxxxS_2059a0734ccfqvga,成功连接 Wowza 服务器。
Wowza IDE 控制台有 onPublish[live/_definst_/xxxxS_2059a0734ccfqvga]: streamName:xxxxS_2059a0734ccfqvga isRecord:false isAppend:false 输出,这个正是我们 DefondsLiveModule 类里的 StreamListener.onPublish 里定义的,测试成功。
参考资料
Wowza IDE User’s Guide
http://www.wowza.com/forums/content.php?472-How-to-start-and-stop-live-stream-recordings-programmatically-(IMediaStreamActionNotify3)
相关文章推荐
- 使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用 -- 监控直播频道
- 使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用 -- 监控直播频道
- 实时监控、直播流、流媒体、视频网站开发方案流媒体服务器搭建及配置详解:使用nginx搭建rtmp直播、rtmp点播、,hls直播服务配置详解
- 使用Kotlin开发Android应用(III):扩展函数和默认值
- 使用jQuery图表插件Sparklines来开发一个实用的网站PV(page view)实时监控应用
- 使用Kotlin开发Android应用(IV):自定义视图和Android扩展
- 使用Kotlin开发Android应用(IV):自定义视图和Android扩展
- 使用epoll 在 linux 上开发高性能应用服务器
- 使用 kqueue 在 FreeBSD 上开发高性能应用服务器
- 使用 kqueue 在 FreeBSD 上开发高性能应用服务器
- C#开发微信门户及应用(13)-使用地理位置扩展相关应用
- 使用JMX监控Tomcat(监控应用服务器系列文章)
- 使用JMX访问WebLogic Server MBean(监控应用服务器系列文章)
- 使用 kqueue 在 FreeBSD 上开发高性能应用服务器
- 监控应用服务器使用JMX监控Tomcat (推荐)
- 使用Kotlin开发第一个Android应用
- 使用 kqueue 在 FreeBSD 上开发高性能应用服务器
- Cordova - 使用Cordova开发iOS应用实战1(配置、开发第一个应用)
- 使用 Apache OpenJPA 开发 EJB 3.0 应用,第 2 部分: 开发第一个 Open JPA 应用
- 通过Stratus 服务器在Flash Player中使用RTMFP 开发P2P应用