Browse Source

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

pull/486/head
648540858 2 years ago
parent
commit
d679a9fcf8
  1. 3
      src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
  2. 4
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  3. 3
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  4. 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
  5. 19
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  6. 2
      src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
  7. 14
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
  8. 31
      src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java

3
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java

@ -136,4 +136,7 @@ public class SsrcConfig {
this.notUsed = notUsed;
}
public boolean checkSsrc(String ssrcInResponse) {
return !isUsed.contains(ssrcInResponse);
}
}

4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java

@ -93,8 +93,8 @@ public interface ISIPCommander {
* @param device 视频设备
* @param channelId 预览通道
*/
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
/**
* 请求回放视频流
*

3
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@ -343,7 +343,7 @@ public class SIPCommander implements ISIPCommander {
*/
@Override
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
String streamId = ssrcInfo.getStream();
try {
if (device == null) return;
@ -436,6 +436,7 @@ public class SIPCommander implements ISIPCommander {
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
okEvent.response(e);
});

1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java

@ -202,6 +202,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
String deviceID = XmlUtil.getText(rootElement, "DeviceID");
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
if (platform == null)return;
SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
if (evt.getServerTransaction() == null) {
ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest())

19
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java

@ -222,7 +222,24 @@ public class XmlUtil {
// 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")) == 1?1:0);
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
/**
* 行政区划展示设备树与业务分组展示设备树是两种不同的模式
* 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下:
* 河北省
* --> 石家庄市
* --> 摄像头
* --> 正定县
* --> 摄像头
* --> 摄像头
*
* 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织:
* 业务分组
* --> 虚拟组织
* --> 摄像头
* --> 虚拟组织
* --> 摄像头
* --> 摄像头
*/
String parentId = XmlUtil.getText(itemDevice, "ParentID");
if (parentId != null) {
if (parentId.contains("/")) {

2
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java

@ -46,7 +46,7 @@ public interface IMediaServerService {
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck);
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback);
void closeRTPServer(String deviceId, String channelId, String ssrc);

14
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

@ -118,11 +118,11 @@ public class MediaServerServiceImpl implements IMediaServerService {
@Override
public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck) {
return openRTPServer(mediaServerItem, streamId, ssrcCheck,false);
return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,false);
}
@Override
public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {
public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback) {
if (mediaServerItem == null || mediaServerItem.getId() == null) {
return null;
}
@ -135,10 +135,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
return null;
}else {
String ssrc = null;
if (isPlayback) {
ssrc = ssrcConfig.getPlayBackSsrc();
if (presetSsrc != null) {
ssrc = presetSsrc;
}else {
ssrc = ssrcConfig.getPlaySsrc();
if (isPlayback) {
ssrc = ssrcConfig.getPlayBackSsrc();
}else {
ssrc = ssrcConfig.getPlaySsrc();
}
}
if (streamId == null) {

31
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java

@ -39,6 +39,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.ResponseEvent;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.util.*;
@ -256,18 +257,46 @@ public class PlayServiceImpl implements IPlayService {
}
}
}, userSetting.getPlayTimeout());
final String ssrc = ssrcInfo.getSsrc();
cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
logger.info("收到订阅消息: " + response.toJSONString());
timer.cancel();
// hook响应
onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid);
hookEvent.response(mediaServerItemInuse, response);
}, (event) -> {
ResponseEvent responseEvent = (ResponseEvent)event.event;
String contentString = new String(responseEvent.getResponse().getRawContent());
// 获取ssrc
int ssrcIndex = contentString.indexOf("y=");
// 检查是否有y字段
if (ssrcIndex >= 0) {
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
if (!ssrc.equals(ssrcInResponse) && device.isSsrcCheck()) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
// 查询 ssrcInResponse 是否可用
if (mediaServerItem.isRtpEnable() && !mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
// ssrc 不可用
// 释放ssrc
mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
event.msg = "下级自定义了ssrc,但是此ssrc不可用";
event.statusCode = 400;
errorEvent.response(event);
return;
}
// 关闭rtp server
mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
// 重新开启ssrc server
mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false);
}
}
}, (event) -> {
timer.cancel();
mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
// 释放ssrc
mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
errorEvent.response(event);
});

Loading…
Cancel
Save