|  |  | @ -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(); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  | 
 |