心跳文本
MESSAGE sip:34020000002000000001@192.168.1.201:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.8:5060;rport;branch=z9hG4bK700933079
From: <sip:34020000001110000003@192.168.1.8:5060>;tag=1896094222
To: <sip:34020000002000000001@192.168.1.201:5060>
Call-ID: 78119256@192.168.1.8
CSeq: 20 MESSAGE
Max-Forwards: 70
User-Agent: Dahua SIP UAS V1.0
Content-Type: Application/MANSCDP+xml
Content-Length: 178
<?xml version="1.0" encoding="GB2312" ?>
<Notify>
<CmdType>Keepalive</CmdType>
<SN>0</SN>
<DeviceID>34020000001110000003</DeviceID>
<Status>OK</Status>
</Notify>
SIP/2.0 200 OK
CSeq: 20 MESSAGE
Call-ID: 78119256@192.168.1.8
From: <sip:34020000001110000003@192.168.1.8:5060>;tag=1896094222
To: <sip:34020000002000000001@192.168.1.201:5060>
Via: SIP/2.0/UDP 192.168.1.8:5060;rport;branch=z9hG4bK700933079
Content-Length: 0
心跳保活回复模板
private static final String str_Keepalive_ok=
"SIP/2.0 200 OK"+n+
"CSeq: {CSeq}"+n+
"Call-ID: {Call-ID}"+n+
"From: {From}"+n+
"To: {To}"+n+
"Via: {Via}"+n+
"Content-Length: 0"+n
+n;
心跳回复代码实现
if("MESSAGE".equals(map.get("method"))){
if("Keepalive".equals(map.get("CmdType"))){
sendStr=str_Keepalive_ok;
sendStr=sendStr.replace("{CSeq}",map.get("CSeq"));
sendStr=sendStr.replace("{Call-ID}",map.get("Call-ID"));
sendStr=sendStr.replace("{From}",map.get("From"));
sendStr=sendStr.replace("{To}",map.get("To"));
sendStr=sendStr.replace("{Via}",map.get("Via"));
if(deviceInfo.getSsrc()==null){
String deviceId=map.get("deviceId");
deviceInfo.setSsrc(Utils.getSsrc("010000"+deviceId.substring(deviceId.length()-4)));
}
}
}
推流文本
INVITE sip:34020000001110000003@192.168.1.8:5060;transport=udp SIP/2.0
Call-ID: 34020000001110000003
CSeq: 1 INVITE
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchlive
Max-Forwards: 70
Content-Type: Application/sdp
Contact: <sip:34020000002000000001@0.0.0.0:5060>
Supported: 100re1
Subject: 34020000001110000003:0100000003,34020000002000000001:0
User-Agent: fyl
Content-Length: 232
v=0
o=34020000001110000003 0 0 IN IP4 192.168.1.201
s=Play
c=IN IP4 192.168.1.201
t=0 0
m=video 10002 TCP/RTP/AVP 96 98 97
a=recvonly
a=rtpmap:96 PS/90000
a=rtpmap:98 H264/90000
a=rtpmap:97 MPEG4/90000
y=0100000003
f=
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchlive;received=192.168.1.201
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>
Call-ID: 34020000001110000003
CSeq: 1 INVITE
User-Agent: Dahua SIP UAS V1.0
Content-Length: 0
SIP/2.0 101 Dialog Establishement
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchlive;received=192.168.1.201
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>;tag=29937641
Call-ID: 34020000001110000003
CSeq: 1 INVITE
Contact: <sip:34020000001110000003@192.168.1.8:5060>
User-Agent: Dahua SIP UAS V1.0
Content-Length: 0
SIP/2.0 200 OK
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchlive;received=192.168.1.201
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>;tag=29937641
Call-ID: 34020000001110000003
CSeq: 1 INVITE
Contact: <sip:34020000001110000003@192.168.1.8:5060>
User-Agent: Dahua SIP UAS V1.0
Content-Type: application/sdp
Content-Length: 260
v=0
o=34020000001110000003 0 0 IN IP4 192.168.1.8
s=Play
i=VCam Live Video
c=IN IP4 192.168.1.8
t=0 0
m=video 9702 TCP/RTP/AVP 96
a=sendonly
a=rtpmap:96 PS/90000
a=streamprofile:0
a=setup:active
a=connection:new
y=0100000003
f=v/0/0/0/0/0a/0/0/0
ACK sip:34020000001110000003@192.168.1.8:5060 SIP/2.0
Call-ID: 34020000001110000003
CSeq: 1 ACK
Via: SIP/2.0/UDP 34020000002000000001:5060;branch=z9hG4bK-353633-cc1d42f582e2ec40dfedb6812f9ab1b8
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>;tag=29937641
Max-Forwards: 70
Content-Length: 0
BYE sip:34020000001110000003@192.168.1.8:5060;transport=udp SIP/2.0
Call-ID: 34020000001110000003
CSeq: 6 BYE
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>;tag=29937641
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchbye
Contact: <sip:34020000002000000001@0.0.0.0:5060>
Max-Forwards: 70
Content-Length: 0
SIP/2.0 200 OK
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=branchbye;received=192.168.1.201
From: <sip:34020000002000000001@0.0.0.0:5060>;tag=live
To: "34020000001110000003" <sip:34020000001110000003@192.168.1.8:5060>;tag=29937641
Call-ID: 34020000001110000003
CSeq: 6 BYE
User-Agent: Dahua SIP UAS V1.0
Content-Length: 0
由于摄像头是公司的画面,就不放流画面效果图了
上面涉及到的信息模板
private static final String str_invite=
"INVITE sip:{deviceId}@{deviceLocalIp}:{deviceLocalPort};transport=udp SIP/2.0"+n+
"Call-ID: {Call-ID}"+n+
"CSeq: 1 INVITE"+n+
"From: ;tag=live"+n+
"To: \"{deviceId}\" "+n+
"Via: SIP/2.0/UDP {serverIp}:{serverPort};branch=branchlive"+n+
"Max-Forwards: 70"+n+
"Content-Type: Application/sdp"+n+
"Contact: "+n+
"Supported: 100re1"+n+
"Subject: {deviceId}:010000{ssrc},{serverId}:0"+n+
"User-Agent: fyl"+n+
"Content-Length: {Content-Length}"+n+
n;
private static final String str_invite_sdp=
"v=0"+n+
"o={deviceId} 0 0 IN IP4 {mediaServerIp}"+n+
"s=Play"+n+
"c=IN IP4 {mediaServerIp}"+n+
"t=0 0"+n+
"m=video {mediaServerPort} TCP/RTP/AVP 96 98 97"+n+
"a=recvonly"+n+
"a=rtpmap:96 PS/90000"+n+
"a=rtpmap:98 H264/90000"+n+
"a=rtpmap:97 MPEG4/90000"+n+
"y=010000{ssrc}"+n+
"f="+n+
n;
private static final String str_invite_sdp_udp=
"v=0"+n+
"o={deviceId} 0 0 IN IP4 {mediaServerIp}"+n+
"s=Play"+n+
"c=IN IP4 {mediaServerIp}"+n+
"t=0 0"+n+
"m=video {mediaServerPort} RTP/AVP 96 98 97"+n+
"a=recvonly"+n+
"a=rtpmap:96 PS/90000"+n+
"a=rtpmap:98 H264/90000"+n+
"a=rtpmap:97 MPEG4/90000"+n+
"y=010000{ssrc}"+n+
"f="+n+
n;
private static final String str_ack=
"ACK sip:{deviceId}@{deviceLocalIp}:{deviceLocalPort} SIP/2.0"+n+
"Call-ID: {Call-ID}"+n+
"CSeq: 1 ACK"+n+
"Via: SIP/2.0/UDP {serverIp}:{serverPort};branch={branchId}"+n+
"From: {From}"+n+
"To: {To}"+n+
"Max-Forwards: 70"+n+
"Content-Length: 0"+n+
n;
private static final String str_bye=
"BYE sip:{deviceId}@{deviceLocalIp}:{deviceLocalPort};transport=udp SIP/2.0"+n+
"Call-ID: {Call-ID}"+n+
"CSeq: 6 BYE"+n+
"From: {From}"+n+
"To: {To}"+n+
"Via: SIP/2.0/UDP {serverIp}:{serverPort};branch=branchbye"+n+
"Contact: "+n+
"Max-Forwards: 70"+n+
"Content-Length: 0"+n+
n;
推流代码实现
public void play(String deviceId){
if(channel==null){
return;
}
logger.info("play start");
try {
DeviceInfo deviceInfo=getDeviceInfo(deviceId);
if(deviceInfo==null){
return;
}
InetSocketAddress inetSocketAddress=new InetSocketAddress(deviceInfo.getIp(),deviceInfo.getPort());
String sendStr=null;
sendStr=str_invite;
String callID=deviceId;
String ssrc=deviceId.substring(deviceId.length()-4);
sendStr=replaceAll("{Call-ID}", callID,sendStr);
sendStr=replaceAll("{deviceId}", deviceId,sendStr);
sendStr=replaceAll("{ssrc}", ssrc,sendStr);
sendStr=replaceAll("{deviceLocalIp}", deviceInfo.getLocalIp(),sendStr);
sendStr=replaceAll("{deviceLocalPort}", deviceInfo.getLocalPort(),sendStr);
sendStr=replaceAll("{serverId}", serverId,sendStr);
sendStr=replaceAll("{serverIp}", serverIp,sendStr);
sendStr=replaceAll("{serverPort}", serverPort,sendStr);
String sendStr2=str_invite_sdp;
sendStr2=replaceAll("{deviceId}", deviceId,sendStr2);
sendStr2=replaceAll("{ssrc}", ssrc,sendStr2);
sendStr2=replaceAll("{mediaServerIp}", mediaServerIp,sendStr2);
sendStr2=replaceAll("{mediaServerPort}", mediaServerPort,sendStr2);
sendStr=sendStr+sendStr2;
sendStr=replaceAll("{Content-Length}", String.valueOf(sendStr2.getBytes().length),sendStr);
if(sendStr!=null){
send(sendStr,inetSocketAddress);
Data.putScheduled(new SendTipsTask(deviceId + "下达推流指令。。。"));
}
}catch (Exception e){
logger.error("play error",e);
}
}
private static String replaceAll(String target,String replacement,String source){
if(target.contains("{")){
target=target.replace("{","\\{");
}
if(target.contains("}")){
target=target.replace("}","\\}");
}
Pattern p = Pattern.compile(target);
Matcher m = p.matcher(source);
return m.replaceAll(replacement);
}
回复ack
if("RESPONSE".equals(map.get("messageType"))){
if("200".equals(map.get("stateCode"))){
if(map.get("CSeq").contains("INVITE")){
sendStr=str_ack;
sendStr=replaceAll("{deviceId}",map.get("deviceId"),sendStr);
sendStr=replaceAll("{deviceLocalIp}",map.get("deviceLocalIp"),sendStr);
sendStr=replaceAll("{deviceLocalPort}",map.get("deviceLocalPort"),sendStr);
sendStr=replaceAll("{Call-ID}",map.get("Call-ID"),sendStr);
sendStr=replaceAll("{serverIp}",serverId,sendStr);
sendStr=replaceAll("{serverPort}",serverPort,sendStr);
sendStr=replaceAll("{branchId}", Utils.getBranchId(),sendStr);
sendStr=replaceAll("{From}",map.get("From"),sendStr);
sendStr=replaceAll("{To}",map.get("To"),sendStr);
String deviceId=map.get("deviceId");
deviceInfo.setLiveCallID(map.get("Call-ID"));
deviceInfo.setLiveFromInfo(map.get("From"));
deviceInfo.setLiveToInfo(map.get("To"));
deviceInfo.setSsrc(Utils.getSsrc("010000"+deviceId.substring(deviceId.length()-4)));
deviceInfo.setLive(true);
Data.putScheduled(new SendTipsTask(deviceId + "回复推流ack指令。。。"));
Data.putScheduled(new SendDataTask(commonService));
}
if(map.get("CSeq").contains("BYE")){
if(deviceInfo.getLiveCallID()!=null&&map.get("Call-ID").equals(deviceInfo.getLiveCallID())){
deviceInfo.setLive(false);
Data.putScheduled(new SendTipsTask(map.get("deviceId") + "推流已关闭。。。"));
Data.putScheduled(new SendDataTask(commonService));
}
}
}
}
断流
public void bye(String deviceId){
if(channel==null){
return;
}
logger.info("bye start");
try {
DeviceInfo deviceInfo=getDeviceInfo(deviceId);
if(deviceInfo==null){
return;
}
InetSocketAddress inetSocketAddress=new InetSocketAddress(deviceInfo.getIp(),deviceInfo.getPort());
String sendStr=null;
sendStr=str_bye;
String callID=deviceInfo.getLiveCallID();
if(callID==null){
callID=deviceId;
}
sendStr=replaceAll("{Call-ID}", callID,sendStr);
sendStr=replaceAll("{deviceId}", deviceId,sendStr);
sendStr=replaceAll("{deviceLocalIp}", deviceInfo.getLocalIp(),sendStr);
sendStr=replaceAll("{deviceLocalPort}", deviceInfo.getLocalPort(),sendStr);
sendStr=replaceAll("{serverId}", serverId,sendStr);
sendStr=replaceAll("{serverIp}", serverIp,sendStr);
sendStr=replaceAll("{serverPort}", serverPort,sendStr);
sendStr=replaceAll("{From}", deviceInfo.getLiveFromInfo(),sendStr);
sendStr=replaceAll("{To}", deviceInfo.getLiveToInfo(),sendStr);
if(sendStr!=null){
send(sendStr,inetSocketAddress);
}
}catch (Exception e){
logger.error("bye error",e);
}
}
gb28181的sip服务器简单实现就这么点了,当然还有获取什么设备信息的指令,ptz的指令,方法都是差不多,只要自己通过抓包就可以知道通讯的流程。
下节简单讲解java解包gb28181摄像头传输过来的rtp over tcp/udp流,并通过javacv退出rtmp