EasyDarwin源码分析(三)——rtsp-client

rtsp-client.go

这个模块主要实现了客户端的拉流功能。也就是在网页上点击“拉流分发”按钮后,easydarwin会向用户填写的源地址拉流,然后再转发出去,在向源地址拉流的时候,easydarwin相当于是一个rtsp客户端。所以这里使用rtsp-client.go。

EasyDarwin中有两个模块分别是rtsp-server和rtsp-client,rtsp-server分析见:rtsp-server源码分析
乍一看这两个模块,一个server一个cilent,好像正好是一对服务器和客户端,其实两者关系不大,各自完成不同的功能。
rtsp-server是EasyDarwin提供rtsp服务,监听554端口(默认)。而rtsp-client的作用是主动向某个音视频源地址进行拉流,在拉流的过程中充当客户端的角色,所以叫client。

这个功能的开始是从网页上点击“拉流分发”开始的,这么说其实并不是完全正确,因为前端点击“拉流分发”后是向后端发送了一个http请求,你从别的地方发这个请求也是可以的。所以我们从接收http请求开始讲起。

routers/routers.go

routers.go主要就是用来接收前端发来的请求,这里使用的是第三方包gin,其实主要看以下代码就行。第一行Group,对请求做了一个分组,也就是api接收的请求都是/api/v1/xxx形式的。

下面就是具体的请求,第一个参数:请求路径,第二个参数:处理这个请求的函数。

“拉流分发”处理的请求是/stream/start
EasyDarwin源码分析(三)——rtsp-client_第1张图片

EasyDarwin源码分析(三)——rtsp-client_第2张图片

首先定义一个结构体,用来接收前端发来的数据。

EasyDarwin源码分析(三)——rtsp-client_第3张图片

给这个client创建一个pusher,当easydarwin作为一个客户端向第三方源拉流后,得把这个媒体流再次转发出去,供用户拉取,所以这里的pusher(推流者),就是将client拉取到的流转发、再次推送出去。

EasyDarwin源码分析(三)——rtsp-client_第4张图片

client.Start(),启动这个向第三方源拉流的rtsp客户端。
将上面new的pusher添加到rtsp-server的pusher队列中。
在client成功从第三方源拉到媒体流后,会将这些媒体流数据添加到pusher中,等待用户来拉取。

下面分析刚才提到的那些函数(在rtsp/rtsp-client.go中)

NewRTSPClient()

EasyDarwin源码分析(三)——rtsp-client_第5张图片

函数的主体部分就是对RTSPClient的实例化。RTSPClient结构体如下(部分)

EasyDarwin源码分析(三)——rtsp-client_第6张图片

client.Start()

EasyDarwin源码分析(三)——rtsp-client_第7张图片

可以看到Start()函数里面主要就调用了另外两个方法。requestStream()主要负责RTSP命令交互,startStream()负责媒体流的收发(rtp)

requestStream()

EasyDarwin源码分析(三)——rtsp-client_第8张图片

首先解析客户端的URL,我在这里打了个断点,当我在页面上点击拉流分发、输入好摄像头源地址等信息,最后点击确定时,到达此断点。
这里的client.URL是摄像头的源地址。url.Parse对这个地址进行了解析,这是一个工具包,返回的 l 不是一个字符串而是一个结构体。如下

EasyDarwin源码分析(三)——rtsp-client_第9张图片
EasyDarwin源码分析(三)——rtsp-client_第10张图片
EasyDarwin源码分析(三)——rtsp-client_第11张图片

建立Tcp连接,准备进行命令交互。为客户端client创建Reader和Writer,用来读写连接conn中的数据。

EasyDarwin源码分析(三)——rtsp-client_第12张图片

发送OPTIONS请求,这里的Request()是一个封装好的,用于RTSP命令交互的接口,该接口发送报文,并且接受响应。两个返回值,分别是RTSP响应和错误,在代码里,每一个请求都判断了错误。

EasyDarwin源码分析(三)——rtsp-client_第13张图片

发送DESCRIBE请求,并接受响应。使用第三方包解析响应中的SDP信息。

EasyDarwin源码分析(三)——rtsp-client_第14张图片

在一般情况下,视频和音频各有一个媒体流。上面的代码根据客户端使用TCP/UDP来给首部字段的"Transport"字段赋值。

请添加图片描述

然后发送SETUP请求:

请添加图片描述

最后发送发送PLAY命令

startStream()

EasyDarwin源码分析(三)——rtsp-client_第15张图片

初始化,这里的OptionIntervalMillis是心跳间隔,如果设置了这个值,则以这个值为周期,定时发送OPTIONS请求。

EasyDarwin源码分析(三)——rtsp-client_第16张图片

connRW是之前已经初始化的读写器

ReadByte()函数:读取一个字节。如果是 0×24 ,则是rtp数据,不然就是rtsp命令。
如果看了之前的rtsp-server源码分析会发现很眼熟,没错,他把处理rtsp命令和rtp包的代码,在这里又写了一遍,也就是说通过ffmpeg推来的流,和easydarwin通过rtsp-client主动去拉的流,虽然这些都是音视频流,但是在代码里却在不同的模块里分别处理了(但是代码内容基本相似),并没有使用同一份代码。

EasyDarwin源码分析(三)——rtsp-client_第17张图片

EasyDarwin源码分析(三)——rtsp-client_第18张图片

这里是RTP包的解析过程,可以看到,首先收取一个包的长度,然后根据这个长度,接收完成所有的一整包。再去解析包的内容,最后将包回调出去。RTP包有四种类型,VIDEO、AUDIO、VIDEOCONTROL、AUDIOCONTROL,这些类型通过channel来区分开来。

最后处理这些pack的是RTPHandles,详解:EasyDarwin源码分析(四)—— RTPHandles

非RTP数据包的接收,就比较简单了。由于RTSP是文本协议,逐行读取文本,直到读出一个长度为0的行。同时判断是否包括Content-Length, 如果有的话,再读取Content-Length长度的数据包。否则接收完成。

总结:

在用EasyDarwin之前就知道他就是一个流媒体服务器,在分析完rtsp-client和rtsp-server之后,我们可以总结他的功能为“拉转推”和“收转推”,也就是一个是主动拉流(使用rtsp-client),一个是被动接收流再转推出去(使用rtsp-server和rtsp-session)。

当初学习这一部分时一篇很重要的文章:EasyDarwinGo拉转推功能之拉流

你可能感兴趣的:(EasyDarwin,easydarwin,go)