|
|
@ -1,6 +1,8 @@ |
|
|
|
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; |
|
|
|
|
|
|
|
import java.lang.reflect.Field; |
|
|
|
import java.text.ParseException; |
|
|
|
import java.util.HashSet; |
|
|
|
|
|
|
|
import javax.sip.*; |
|
|
|
import javax.sip.address.SipURI; |
|
|
@ -8,18 +10,21 @@ import javax.sip.header.CallIdHeader; |
|
|
|
import javax.sip.header.ViaHeader; |
|
|
|
import javax.sip.message.Request; |
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
import com.genersoft.iot.vmp.common.StreamInfo; |
|
|
|
import com.genersoft.iot.vmp.conf.MediaConfig; |
|
|
|
import com.genersoft.iot.vmp.conf.UserSetup; |
|
|
|
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; |
|
|
|
import com.genersoft.iot.vmp.media.zlm.*; |
|
|
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
|
|
|
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem; |
|
|
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
|
|
|
import com.genersoft.iot.vmp.service.IMediaServerService; |
|
|
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
|
|
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
|
|
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|
|
|
import gov.nist.javax.sip.SipProviderImpl; |
|
|
|
import gov.nist.javax.sip.SipStackImpl; |
|
|
|
import gov.nist.javax.sip.message.SIPRequest; |
|
|
|
import gov.nist.javax.sip.stack.SIPDialog; |
|
|
|
import gov.nist.javax.sip.stack.SIPTransaction; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
@ -35,7 +40,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
|
|
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
|
|
|
import com.genersoft.iot.vmp.gb28181.utils.DateUtil; |
|
|
|
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
|
|
|
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
/** |
|
|
@ -55,12 +59,12 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
@Lazy |
|
|
|
@Autowired |
|
|
|
@Qualifier(value="tcpSipProvider") |
|
|
|
private SipProvider tcpSipProvider; |
|
|
|
private SipProviderImpl tcpSipProvider; |
|
|
|
|
|
|
|
@Lazy |
|
|
|
@Autowired |
|
|
|
@Qualifier(value="udpSipProvider") |
|
|
|
private SipProvider udpSipProvider; |
|
|
|
private SipProviderImpl udpSipProvider; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private SIPRequestHeaderProvider headerProvider; |
|
|
@ -74,9 +78,6 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
@Autowired |
|
|
|
private IRedisCatchStorage redisCatchStorage; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ZLMRTPServerFactory zlmrtpServerFactory; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private UserSetup userSetup; |
|
|
|
|
|
|
@ -86,6 +87,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
@Autowired |
|
|
|
private SipSubscribe sipSubscribe; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private IMediaServerService mediaServerService; |
|
|
|
|
|
|
|
private SIPDialog dialog; |
|
|
|
|
|
|
|
public SipConfig getSipConfig() { |
|
|
|
return sipConfig; |
|
|
|
} |
|
|
@ -334,26 +340,13 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
* @param errorEvent sip错误订阅 |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) { |
|
|
|
String streamId = null; |
|
|
|
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) { |
|
|
|
String streamId = ssrcInfo.getStreamId(); |
|
|
|
try { |
|
|
|
if (device == null) return; |
|
|
|
String streamMode = device.getStreamMode().toUpperCase(); |
|
|
|
|
|
|
|
String ssrc = streamSession.createPlaySsrc(); |
|
|
|
if (mediaServerItem.isRtpEnable()) { |
|
|
|
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId); |
|
|
|
}else { |
|
|
|
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
|
|
|
} |
|
|
|
Integer mediaPort = null; |
|
|
|
// 使用动态udp端口
|
|
|
|
if (mediaServerItem.isRtpEnable()) { |
|
|
|
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId); |
|
|
|
}else { |
|
|
|
mediaPort = mediaServerItem.getRtpProxyPort(); |
|
|
|
} |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort); |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); |
|
|
|
// 添加订阅
|
|
|
|
JSONObject subscribeKey = new JSONObject(); |
|
|
|
subscribeKey.put("app", "rtp"); |
|
|
@ -361,7 +354,7 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
subscribeKey.put("regist", true); |
|
|
|
subscribeKey.put("mediaServerId", mediaServerItem.getId()); |
|
|
|
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
|
|
|
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
(MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return; |
|
|
|
event.response(mediaServerItemInUse, json); |
|
|
|
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); |
|
|
@ -369,7 +362,6 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
//
|
|
|
|
StringBuffer content = new StringBuffer(200); |
|
|
|
content.append("v=0\r\n"); |
|
|
|
// content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
|
|
|
|
content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); |
|
|
|
content.append("s=Play\r\n"); |
|
|
|
content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); |
|
|
@ -377,11 +369,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
|
|
|
|
if (userSetup.isSeniorSdp()) { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -402,11 +394,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
}else { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -421,20 +413,25 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
content.append("y="+ssrc+"\r\n");//ssrc
|
|
|
|
content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
|
|
|
|
|
|
|
|
String tm = Long.toString(System.currentTimeMillis()); |
|
|
|
|
|
|
|
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
|
|
|
: udpSipProvider.getNewCallId(); |
|
|
|
|
|
|
|
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrc, callIdHeader); |
|
|
|
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader); |
|
|
|
|
|
|
|
ClientTransaction transaction = transmitRequest(device, request, (e -> { |
|
|
|
String finalStreamId = streamId; |
|
|
|
transmitRequest(device, request, (e -> { |
|
|
|
streamSession.remove(device.getDeviceId(), channelId); |
|
|
|
mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc()); |
|
|
|
errorEvent.response(e); |
|
|
|
})); |
|
|
|
streamSession.put(device.getDeviceId(), channelId ,ssrc,streamId, transaction); |
|
|
|
}), e ->{ |
|
|
|
streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(),e.getClientTransaction()); |
|
|
|
streamSession.put(device.getDeviceId(), channelId , e.getDialog()); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
} catch ( SipException | ParseException | InvalidArgumentException e) { |
|
|
|
e.printStackTrace(); |
|
|
@ -450,30 +447,21 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event |
|
|
|
public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event |
|
|
|
, SipSubscribe.Event errorEvent) { |
|
|
|
try { |
|
|
|
String ssrc = streamSession.createPlayBackSsrc(); |
|
|
|
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
|
|
|
|
|
|
|
Integer mediaPort = null; |
|
|
|
// 使用动态udp端口
|
|
|
|
if (mediaServerItem.isRtpEnable()) { |
|
|
|
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId); |
|
|
|
}else { |
|
|
|
mediaPort = mediaServerItem.getRtpProxyPort(); |
|
|
|
} |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort); |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); |
|
|
|
|
|
|
|
// 添加订阅
|
|
|
|
JSONObject subscribeKey = new JSONObject(); |
|
|
|
subscribeKey.put("app", "rtp"); |
|
|
|
subscribeKey.put("stream", streamId); |
|
|
|
subscribeKey.put("stream", ssrcInfo.getStreamId()); |
|
|
|
subscribeKey.put("regist", true); |
|
|
|
subscribeKey.put("mediaServerId", mediaServerItem.getId()); |
|
|
|
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); |
|
|
|
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
|
|
|
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
(MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return; |
|
|
|
event.response(mediaServerItemInUse, json); |
|
|
|
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); |
|
|
@ -494,11 +482,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
|
|
|
|
if (userSetup.isSeniorSdp()) { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -519,11 +507,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
}else { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -538,7 +526,7 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
content.append("y="+ssrc+"\r\n");//ssrc
|
|
|
|
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
|
|
|
|
|
|
|
String tm = Long.toString(System.currentTimeMillis()); |
|
|
|
|
|
|
@ -547,9 +535,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
|
|
|
|
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader); |
|
|
|
|
|
|
|
ClientTransaction transaction = transmitRequest(device, request, errorEvent); |
|
|
|
streamSession.put(device.getDeviceId(), channelId, ssrc, streamId, transaction); |
|
|
|
|
|
|
|
transmitRequest(device, request, errorEvent, okEvent -> { |
|
|
|
Dialog dialog = okEvent.getClientTransaction().getDialog(); |
|
|
|
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), okEvent.getClientTransaction()); |
|
|
|
streamSession.put(device.getDeviceId(), channelId, dialog); |
|
|
|
}); |
|
|
|
} catch ( SipException | ParseException | InvalidArgumentException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
@ -565,30 +555,20 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
* @param downloadSpeed 下载倍速参数 |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public void downloadStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event |
|
|
|
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event |
|
|
|
, SipSubscribe.Event errorEvent) { |
|
|
|
try { |
|
|
|
String ssrc = streamSession.createPlayBackSsrc(); |
|
|
|
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
|
|
|
|
|
|
|
Integer mediaPort = null; |
|
|
|
// 使用动态udp端口
|
|
|
|
if (mediaServerItem.isRtpEnable()) { |
|
|
|
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId); |
|
|
|
}else { |
|
|
|
mediaPort = mediaServerItem.getRtpProxyPort(); |
|
|
|
} |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort); |
|
|
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); |
|
|
|
|
|
|
|
// 添加订阅
|
|
|
|
JSONObject subscribeKey = new JSONObject(); |
|
|
|
subscribeKey.put("app", "rtp"); |
|
|
|
subscribeKey.put("stream", streamId); |
|
|
|
subscribeKey.put("stream", ssrcInfo.getStreamId()); |
|
|
|
subscribeKey.put("regist", true); |
|
|
|
subscribeKey.put("mediaServerId", mediaServerItem.getId()); |
|
|
|
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); |
|
|
|
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
|
|
|
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
(MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
|
|
|
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return; |
|
|
|
event.response(mediaServerItemInUse, json); |
|
|
|
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); |
|
|
@ -609,11 +589,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
|
|
|
|
if (userSetup.isSeniorSdp()) { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -634,11 +614,11 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
}else { |
|
|
|
if("TCP-PASSIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if ("TCP-ACTIVE".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); |
|
|
|
}else if("UDP".equals(streamMode)) { |
|
|
|
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); |
|
|
|
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); |
|
|
|
} |
|
|
|
content.append("a=recvonly\r\n"); |
|
|
|
content.append("a=rtpmap:96 PS/90000\r\n"); |
|
|
@ -654,7 +634,7 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
} |
|
|
|
content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); |
|
|
|
|
|
|
|
content.append("y="+ssrc+"\r\n");//ssrc
|
|
|
|
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
|
|
|
|
|
|
|
String tm = Long.toString(System.currentTimeMillis()); |
|
|
|
|
|
|
@ -664,7 +644,7 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader); |
|
|
|
|
|
|
|
ClientTransaction transaction = transmitRequest(device, request, errorEvent); |
|
|
|
streamSession.put(device.getDeviceId(), channelId, ssrc, streamId, transaction); |
|
|
|
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction); |
|
|
|
|
|
|
|
} catch ( SipException | ParseException | InvalidArgumentException e) { |
|
|
|
e.printStackTrace(); |
|
|
@ -684,53 +664,35 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) { |
|
|
|
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
|
|
|
try { |
|
|
|
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId); |
|
|
|
// 服务重启后, 无法直接发送bye, 通过手动构建发送
|
|
|
|
// if (transaction == null) {
|
|
|
|
//
|
|
|
|
// if (streamInfo != null) {
|
|
|
|
// MediaServerItem mediaServerItem = redisCatchStorage.getMediaInfo(streamInfo.getMediaServerId());
|
|
|
|
// JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServerItem,streamInfo.getApp(), streamInfo.getStreamId());
|
|
|
|
// if (mediaList != null) { // 仍在推流才发送
|
|
|
|
// if (mediaList.getInteger("code") == 0) {
|
|
|
|
// JSONArray data = mediaList.getJSONArray("data");
|
|
|
|
// if (data != null && data.size() > 0) {
|
|
|
|
// Device device = storager.queryVideoDevice(deviceId);
|
|
|
|
// if (device != null) {
|
|
|
|
// StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
|
|
|
|
// try {
|
|
|
|
// Request byteRequest = headerProvider.createByteRequest(device, channelId,
|
|
|
|
// transactionInfo.branch,
|
|
|
|
// transactionInfo.localTag,
|
|
|
|
// transactionInfo.remoteTag,
|
|
|
|
// transactionInfo.callId);
|
|
|
|
// transmitRequest(device, byteRequest);
|
|
|
|
// } catch (InvalidArgumentException e) {
|
|
|
|
// e.printStackTrace();
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// redisCatchStorage.stopPlay(streamInfo);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (okEvent != null) {
|
|
|
|
// okEvent.response(null);
|
|
|
|
// }
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
if (transaction == null) { |
|
|
|
logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); |
|
|
|
return; |
|
|
|
} |
|
|
|
Dialog dialog = transaction.getDialog(); |
|
|
|
SIPDialog dialog = streamSession.getDialog(deviceId, channelId); |
|
|
|
if (dialog == null) { |
|
|
|
logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId); |
|
|
|
return; |
|
|
|
} |
|
|
|
SipStack sipStack = udpSipProvider.getSipStack(); |
|
|
|
SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); |
|
|
|
if (dialog != sipDialog) { |
|
|
|
dialog = sipDialog; |
|
|
|
}else { |
|
|
|
dialog.setSipProvider(udpSipProvider); |
|
|
|
try { |
|
|
|
Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); |
|
|
|
sipStackField.setAccessible(true); |
|
|
|
sipStackField.set(dialog, sipStack); |
|
|
|
Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners"); |
|
|
|
eventListenersField.setAccessible(true); |
|
|
|
eventListenersField.set(dialog, new HashSet<>()); |
|
|
|
} catch (NoSuchFieldException | IllegalAccessException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Request byeRequest = dialog.createRequest(Request.BYE); |
|
|
|
SipURI byeURI = (SipURI) byeRequest.getRequestURI(); |
|
|
|
SIPRequest request = (SIPRequest)transaction.getRequest(); |
|
|
@ -752,7 +714,12 @@ public class SIPCommander implements ISIPCommander { |
|
|
|
|
|
|
|
dialog.sendRequest(clientTransaction); |
|
|
|
|
|
|
|
streamSession.remove(deviceId, channelId); |
|
|
|
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId); |
|
|
|
if (ssrcTransaction != null) { |
|
|
|
MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); |
|
|
|
mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc()); |
|
|
|
streamSession.remove(deviceId, channelId); |
|
|
|
} |
|
|
|
} catch (SipException | ParseException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
|