Commit d679a9fcf8355e56f7be79a535e81f8300c70cb5

Authored by 648540858
1 parent f6fa1eed

添加对点播时设备自定义ssrc的支持

src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
... ... @@ -136,4 +136,7 @@ public class SsrcConfig {
136 136 this.notUsed = notUsed;
137 137 }
138 138  
  139 + public boolean checkSsrc(String ssrcInResponse) {
  140 + return !isUsed.contains(ssrcInResponse);
  141 + }
139 142 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -93,8 +93,8 @@ public interface ISIPCommander {
93 93 * @param device 视频设备
94 94 * @param channelId 预览通道
95 95 */
96   - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
97   -
  96 + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  97 +
98 98 /**
99 99 * 请求回放视频流
100 100 *
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -343,7 +343,7 @@ public class SIPCommander implements ISIPCommander {
343 343 */
344 344 @Override
345 345 public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
346   - ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
  346 + ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
347 347 String streamId = ssrcInfo.getStream();
348 348 try {
349 349 if (device == null) return;
... ... @@ -436,6 +436,7 @@ public class SIPCommander implements ISIPCommander {
436 436 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
437 437 streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
438 438 streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
  439 + okEvent.response(e);
439 440 });
440 441  
441 442  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
... ... @@ -202,6 +202,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
202 202 String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
203 203 String deviceID = XmlUtil.getText(rootElement, "DeviceID");
204 204 ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
  205 + if (platform == null)return;
205 206 SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
206 207 if (evt.getServerTransaction() == null) {
207 208 ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
... ... @@ -222,7 +222,24 @@ public class XmlUtil {
222 222 // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
223 223 deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")) == 1?1:0);
224 224 }
225   - deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
  225 + /**
  226 + * 行政区划展示设备树与业务分组展示设备树是两种不同的模式
  227 + * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下:
  228 + * 河北省
  229 + * --> 石家庄市
  230 + * --> 摄像头
  231 + * --> 正定县
  232 + * --> 摄像头
  233 + * --> 摄像头
  234 + *
  235 + * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织:
  236 + * 业务分组
  237 + * --> 虚拟组织
  238 + * --> 摄像头
  239 + * --> 虚拟组织
  240 + * --> 摄像头
  241 + * --> 摄像头
  242 + */
226 243 String parentId = XmlUtil.getText(itemDevice, "ParentID");
227 244 if (parentId != null) {
228 245 if (parentId.contains("/")) {
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
... ... @@ -46,7 +46,7 @@ public interface IMediaServerService {
46 46  
47 47 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck);
48 48  
49   - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);
  49 + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback);
50 50  
51 51 void closeRTPServer(String deviceId, String channelId, String ssrc);
52 52  
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
... ... @@ -118,11 +118,11 @@ public class MediaServerServiceImpl implements IMediaServerService {
118 118  
119 119 @Override
120 120 public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck) {
121   - return openRTPServer(mediaServerItem, streamId, ssrcCheck,false);
  121 + return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,false);
122 122 }
123 123  
124 124 @Override
125   - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {
  125 + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback) {
126 126 if (mediaServerItem == null || mediaServerItem.getId() == null) {
127 127 return null;
128 128 }
... ... @@ -135,10 +135,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
135 135 return null;
136 136 }else {
137 137 String ssrc = null;
138   - if (isPlayback) {
139   - ssrc = ssrcConfig.getPlayBackSsrc();
  138 + if (presetSsrc != null) {
  139 + ssrc = presetSsrc;
140 140 }else {
141   - ssrc = ssrcConfig.getPlaySsrc();
  141 + if (isPlayback) {
  142 + ssrc = ssrcConfig.getPlayBackSsrc();
  143 + }else {
  144 + ssrc = ssrcConfig.getPlaySsrc();
  145 + }
142 146 }
143 147  
144 148 if (streamId == null) {
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -39,6 +39,7 @@ import org.springframework.stereotype.Service;
39 39 import org.springframework.util.ResourceUtils;
40 40 import org.springframework.web.context.request.async.DeferredResult;
41 41  
  42 +import javax.sip.ResponseEvent;
42 43 import java.io.FileNotFoundException;
43 44 import java.math.BigDecimal;
44 45 import java.util.*;
... ... @@ -256,7 +257,7 @@ public class PlayServiceImpl implements IPlayService {
256 257 }
257 258 }
258 259 }, userSetting.getPlayTimeout());
259   -
  260 + final String ssrc = ssrcInfo.getSsrc();
260 261 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
261 262 logger.info("收到订阅消息: " + response.toJSONString());
262 263 timer.cancel();
... ... @@ -264,10 +265,38 @@ public class PlayServiceImpl implements IPlayService {
264 265 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid);
265 266 hookEvent.response(mediaServerItemInuse, response);
266 267 }, (event) -> {
  268 + ResponseEvent responseEvent = (ResponseEvent)event.event;
  269 + String contentString = new String(responseEvent.getResponse().getRawContent());
  270 + // 获取ssrc
  271 + int ssrcIndex = contentString.indexOf("y=");
  272 + // 检查是否有y字段
  273 + if (ssrcIndex >= 0) {
  274 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  275 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  276 + if (!ssrc.equals(ssrcInResponse) && device.isSsrcCheck()) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  277 + // 查询 ssrcInResponse 是否可用
  278 + if (mediaServerItem.isRtpEnable() && !mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
  279 + // ssrc 不可用
  280 + // 释放ssrc
  281 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  282 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  283 + event.msg = "下级自定义了ssrc,但是此ssrc不可用";
  284 + event.statusCode = 400;
  285 + errorEvent.response(event);
  286 + return;
  287 + }
  288 + // 关闭rtp server
  289 + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  290 + // 重新开启ssrc server
  291 + mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false);
  292 + }
  293 + }
  294 + }, (event) -> {
267 295 timer.cancel();
268 296 mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
269 297 // 释放ssrc
270 298 mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  299 +
271 300 streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
272 301 errorEvent.response(event);
273 302 });
... ...