欢迎访问我的GitHub
https://github.com/zq2599/blog_demos内容:所有原创文章分类汇总,并支持源代码,涉及Java、Docker、Kubernetes、DevOPS等。
本篇概览
本文是《Kurento实战》的第四篇。在前一篇文章中,我们首先部署了KMS,然后开始了正式的演示。我们还研究了Kurento的重要概念,然后开始应用开发;本文的主要内容是分析官方的Kurento-hello-world项目,了解Kurento应用开发的基本流程和知识点。本文使用的代码是正式版本6.15.0。地址:https://github。com/Kurento/Kurento-tutorial-Java/archive/6 . 15 . 0 . zip阅读代码时,如果能把功能模块清晰地划分为一个整体,再把细节一个一个地打破,那么学习和理解源代码会更有效率。接下来,我们将按照kurento的官方标准套路进行拆分,逐个击破;如何划分功能模块
根据职责不同,整个代码分为三个部分:
WebSocket相关:WebSocket相关的一般处理,如连接建立、关闭、异常回调、业务逻辑分发等。WebRTC信令相关:ICE和SDP相关处理;业务逻辑:如果1和2代表WebRTC的一般处理,那么剩下的就是如何使用Kurento实现业务需求。这部分的主要内容是业务应用使用Kurento官方客户端与KMS交互,控制KMS为端侧提供服务。互动方式如下:
按照上面的方法,对代码进行拆分和划界,无论是阅读官方演示还是开发自己的应用程序,都可以处理得很清楚。接下来,学习官方hello-world源代码,看看如何开发一个完整的Kurento应用程序。
WebSocket相关
最简单的逻辑应该是一般的WebSocket处理。让我们先看这一部分,稍后再谈复杂性。处理程序类中与网络套接字相关的逻辑如下:继承自TextWebSocketHandler(只处理文本类型的数据,对于二进制数据直接关闭会话);override after connection established:WebSocket连接建立的回调,只键入一行日志;Override handletransport错误:WebSocket异常时回调,只关闭WebSocketSession;override afterConnectionClosed:web socket是否正常关闭
还是发生异常,此方法都会执行,逻辑也很简单,就是调用stop方法,这个方法是用来释放KMS资源的,有好几处都会调用,我们留到稍后和其他处理KMS的地方一起讲;
- 并不是所有的应用都需要重写上诉全部代码,还是以实际需求出发决定是否要重写,以kurento-one2one-call项目为例,只重写了handleTextMessage和afterConnectionClosed,其他的使用父类的即可,如下图:

- 还有一个发送消息到浏览器侧的sendMessage方法,以及发送错误信息的sendError方法;
信令相关
- kurento-hello-world应用的功能是和KMS实现实时音视频通信,因此WebRTC标准的信令处理是必不可少的,可惜Kurento官方并没有对信令处理做太多封装(也可能是信令和不同的业务处理逻辑都不一样,导致不好抽象),结果就是一堆信令处理的代码散落在业务代码中;
- 就算业务和信令的处理代码同时出现在Handler类中,只要熟悉WebRTC的信令处理流程,也很容易读懂代码,下图结合了WebRTC标准的信令处理流程,对前端和服务端的代码串联在一起就行分析,左边是浏览器上执行的js代码,右边是服务端,这些代码都用红色箭头标识了处于WebRTC信令处理流程的具体位置,至此,整个流程都清晰的展现出来:

- 如果您在电脑或手机上看上图觉得模糊,请下载原始文件,用draw.io打开,文件所在目录是:https://github.com/zq2599/blog_demos/tree/master/files ,文件名为helloworld-flow.drawio
- 上图列出了信令相关的所有代码,等到看完这些,剩下的就是业务代码了,也就是图中紫色部分的handleProcessSdpOffer方法;
业务相关
- kurento-hello-world应用是把本地摄像头和麦克风数据传到KMS,再从KMS取得这些数据在页面展示,先看看官方是如何描述KMS pipeline的:

- 从上图可见pipeline逻辑非常简单:只有一个WebRtcEndpoint,把自己的Src和Sink接上就完成了,咱们来看看对应的代码,在方法handleProcessSdpOffer中:
// 创建pipeline final MediaPipeline pipeline = kurento.createMediaPipeline(); user.setMediaPipeline(pipeline); // 创建webRtcEndpoint final WebRtcEndpoint webRtcEp = new WebRtcEndpoint.Builder(pipeline).build(); user.setWebRtcEndpoint(webRtcEp); // 自己的sink连接上自己的src webRtcEp.connect(webRtcEp); // ---- Endpoint configuration String sdpOffer = jsonMessage.get("sdpOffer").getAsString(); // 注册各类监听,例如媒体资源状态变化、ICE变化等 // 通过websocket回复SDP Offer initWebRtcEndpoint(session, webRtcEp, sdpOffer); log.info("[Handler::handleStart] New WebRtcEndpoint: {}", webRtcEp.getName()); // ---- Endpoint startup // 取得ICE信息 startWebRtcEndpoint(webRtcEp);
- 再来看看停止WebRtc的stop方法,其实就是向KMS发送了release指令:
private void stop(final WebSocketSession session) { // Remove the user session and release all resources final UserSession user = users.remove(session.getId()); if (user != null) { MediaPipeline mediaPipeline = user.getMediaPipeline(); if (mediaPipeline != null) { log.info("[Handler::stop] Release the Media Pipeline"); mediaPipeline.release(); } } }
小结
以上就是整个kurento-hello-world的源码分析,整个工程的代码在拆分后再分析时,变得异常清晰和简单:
- WebSocket和常规的java开发无异,向标准靠拢即可;
- WebRTC相关代码占了较大比重,但是严格遵循了标准的信令流程,只要熟悉WebRTC就很容易阅读和理解;
- 业务逻辑其实是和业务需求相关联的,这里需要熟悉KMS提供的能力,才能充分发挥KMS的实例,而pipeline编排和各个element的使用,也会是咱们后面文章的重点,用好这些element,打磨出更强大灵活的服务;
欢迎关注我的公众号:程序员欣宸
