一.GB28181信令交互过程
其中,信令1、8、9、10、11、12为SIP服务器接收到客户端的呼叫请求后通过 B2BUA 代理方式建立 媒体流接收者与媒体服务器之间的媒体流信令过程,信令2~7为SIP服务器通过三方呼叫控制建立媒 体服务器与媒体流发送者之间的媒体流信令过程,信令13~16为媒体流接收者断开与媒体服务器之间 的媒体流信令过程,信令17~20为 SIP 服务器断开媒体服务器与媒体流发送者之间的媒体流信令过程。
命令流程描述如下:
1:媒体流接收者向SIP服务器发送Invite消息,消息头域中携带 Subject字段,表明点播的视频源ID、发送方媒体流序列号、媒体流接收者ID、接收端媒体流序列号等参数,SDP消息体中s字段为“Play”代表实时点播。
2:SIP服务器收到Invite请求后,通过三方呼叫控制建立媒体服务器和媒体流发送者之间的媒体连接。向媒体服务器发送Invite消息,此消息不携带SDP消息体。
3:媒体服务器收到SIP服务器的Invite请求后,回复200OK 响应,携带SDP消息体,消息体中描述了媒体服务器接收媒体流的IP、端口、媒体格式等内容。
4:SIP服务器收到媒体服务器返回的200OK 响应后,向媒体流发送者发送Invite请求,请求 中携带消息3中媒体服务器回复的200OK 响应消息体,s字段为“Play”代表实时点播,增加y字段描述SSRC值,f字段描述媒体参数。
5:媒体流发送者收到SIP服务器的Invite请求后,回复200OK 响应,携带SDP消息体,消息体中描述了媒体流发送者发送媒体流的IP、端口、媒体格式、SSRC字段等内容。
6:SIP服务器收到媒体流发送者返回的200OK 响应后,向媒体服务器发送 ACK 请求,请求中携带消息5中媒体流发送者回复的200OK 响应消息体,完成与媒体服务器的Invite会话建立过程。
7:SIP服务器收到媒体流发送者返回的200OK 响应后,向媒体流发送者发送 ACK 请求,请求中不携带消息体,完成与媒体流发送者的Invite会话建立过程。
8:完成三方呼叫控制后,SIP服务器通过B2BUA 代理方式建立媒体流接收者和媒体服务器之间的媒体连接。在消息1中增加SSRC值,转发给媒体服务器。
9:媒体服务器收到Invite请求,回复200OK 响应,携带SDP消息体,消息体中描述了媒体服务器发送媒体流的IP、端口、媒体格式、SSRC值等内容。
10:SIP服务器将消息9转发给媒体流接收者。
11:媒体流接收者收到200OK 响应后,回复 ACK 消息,完成与SIP服务器的Invite会话建立过程。
12:SIP服务器将消息11转发给媒体服务器,完成与媒体服务器的Invite会话建立过程。
13:媒体流接收者向SIP服务器发送 BYE消息,断开消息1、10、11建立的同媒体流接收者的Invite会话。
14:SIP服务器收到 BYE消息后回复200OK 响应,会话断开。
15:SIP服务器收到 BYE消息后向媒体服务器发送 BYE消息,断开消息8、9、12建立的同媒体服务器的Invite会话。
16:媒体服务器收到 BYE消息后回复200OK 响应,会话断开。
17:SIP服务器向媒体服务器发送 BYE 消息,断开消息2、3、6建立的同媒体服务器的Invite会话。
18:媒体服务器收到 BYE消息后回复200OK 响应,会话断开。
19:SIP 服务器向媒体流发送者发送 BYE 消息,断开消息4、5、7建立的同媒体流发送者的Invite会话。
20:媒体流发送者收到 BYE消息后回复200OK 响应,会话断开。
======================================
二.GB28181代码实现:
#include "SipClient.h"
#include "SipServerConfig.h"
#include "Utils/Log.h"
using namespace GB28181;
int main(int argc, char *argv[]) {
LOGI("GB28181 start!");
const char *serverIp = "192.168.1.224";
int serverPort = 15060;
const char *serverSipId = "34020000002000000001";
const char *serverSipRealm = "3402000000";
const char *serverSipPass = "123456789";
int serverSipTimeout = 0;
int serverSipExpiry = 3600;
const char *clientUa = "GB28181Client";
const char *clientIp = "192.168.1.224";
int clientPort = 5060;
const char *clientId = "34020000001310000001";
int localRtpPort = 10001;// 本地RTP的推流端口
SipServerConfig serverConfig(serverIp,serverPort,serverSipId,serverSipRealm,
serverSipPass,serverSipTimeout,serverSipExpiry);
SipClientConfig clientConfig(clientUa,clientIp,clientPort,clientId,localRtpPort);
SipClient client(&serverConfig,&clientConfig);
client.loop();
return 0;
}
进入main函数后,配置服务器和客户端的数据,然后进入client.loop(),初始化sip服务器,sip服务器eXosip_event_wait开始等待接收客户端的请求等。sip服务器初始化流程如下:
1)eXosip_init (初始化)
2)eXosip_listen_addr (监听sip端口)
3)eXosip_register_build_initial_register (构建一个register)
4)eXosip_register_send_register (发送register)
5)eXosip_event_wait (等待对端事件)
6)eXosip_execute (处理事件,调整内部状态)
7)eXosip_automatic_action (根据当前状况,发出响应消息)
client.loop()循环接受客户端sip请求事件
根据时间类型执行不同请求:
例如客户端发起Invite推流请求
进入response_invite,对客户端的invite请求做出回应,以及发送解析的sdp消息结构体等
接收到信令服务器的ask后,后开始推流
RtpSendPs实例化一个对象,进行创建udp端连接,非阻塞监听mSockFd套接字,为推流做准备。
建立udp连接后,start创建推流线程SendDataThread,开始音视频流推送服务,gb28181_streampackageForH264主要进行码流分包封装任务和包头结构封装任务,最后进行打包发送。