Commit 42901d03746d534d701ea3b8663e1c6d2c938c6d
Committed by
GitHub
Merge branch 'wvp-28181-2.0' into wvp-28181-2.0
Showing
47 changed files
with
759 additions
and
548 deletions
DOCKERFILE
| ... | ... | @@ -85,7 +85,7 @@ RUN echo '#!/bin/bash' > run.sh && \ |
| 85 | 85 | echo 'nohup /opt/media/MediaServer -d -m 3 &' >> run.sh && \ |
| 86 | 86 | echo 'cd /opt/wvp' >> run.sh && \ |
| 87 | 87 | echo 'if [${WVP_CONFIG}]; then' >> run.sh && \ |
| 88 | - echo ' java -jar *.jar --spring.confi g.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 ${WVP_CONFIG}' >> run.sh && \ | |
| 88 | + echo ' java -jar *.jar --spring.config.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 ${WVP_CONFIG}' >> run.sh && \ | |
| 89 | 89 | echo 'else' >> run.sh && \ |
| 90 | 90 | echo ' java -jar *.jar --spring.config.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 --media.ip=127.0.0.1 --media.sdp-ip=${WVP_IP} --sip.ip=${WVP_IP} --media.stream-ip=${WVP_IP}' >> run.sh && \ |
| 91 | 91 | echo 'fi' >> run.sh | ... | ... |
pom.xml
| ... | ... | @@ -169,13 +169,6 @@ |
| 169 | 169 | <version>1.2.73</version> |
| 170 | 170 | </dependency> |
| 171 | 171 | |
| 172 | - <!--Guava是一种基于开源的Java库--> | |
| 173 | - <dependency> | |
| 174 | - <groupId>com.google.guava</groupId> | |
| 175 | - <artifactId>guava</artifactId> | |
| 176 | - <version>30.0-jre</version> | |
| 177 | - </dependency> | |
| 178 | - | |
| 179 | 172 | <!-- okhttp --> |
| 180 | 173 | <dependency> |
| 181 | 174 | <groupId>com.squareup.okhttp3</groupId> |
| ... | ... | @@ -279,6 +272,9 @@ |
| 279 | 272 | <plugin> |
| 280 | 273 | <groupId>pl.project13.maven</groupId> |
| 281 | 274 | <artifactId>git-commit-id-plugin</artifactId> |
| 275 | + <configuration> | |
| 276 | + <offline>true</offline> | |
| 277 | + </configuration> | |
| 282 | 278 | </plugin> |
| 283 | 279 | |
| 284 | 280 | <plugin> | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
| ... | ... | @@ -60,12 +60,9 @@ public class SipPlatformRunner implements CommandLineRunner { |
| 60 | 60 | |
| 61 | 61 | // 取消订阅 |
| 62 | 62 | sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{ |
| 63 | - ParentPlatform platform = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId()); | |
| 64 | - sipCommanderForPlatform.register(platform, null, null); | |
| 63 | + // 发送平台未注册消息 | |
| 64 | + publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId()); | |
| 65 | 65 | }); |
| 66 | - | |
| 67 | - // 发送平台未注册消息 | |
| 68 | - publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId()); | |
| 69 | 66 | } |
| 70 | 67 | } |
| 71 | 68 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 5 | + | |
| 6 | +public class InviteStreamInfo { | |
| 7 | + | |
| 8 | + public InviteStreamInfo(MediaServerItem mediaServerItem, JSONObject response, String callId, String app, String stream) { | |
| 9 | + this.mediaServerItem = mediaServerItem; | |
| 10 | + this.response = response; | |
| 11 | + this.callId = callId; | |
| 12 | + this.app = app; | |
| 13 | + this.stream = stream; | |
| 14 | + } | |
| 15 | + | |
| 16 | + private MediaServerItem mediaServerItem; | |
| 17 | + private JSONObject response; | |
| 18 | + private String callId; | |
| 19 | + private String app; | |
| 20 | + private String stream; | |
| 21 | + | |
| 22 | + public MediaServerItem getMediaServerItem() { | |
| 23 | + return mediaServerItem; | |
| 24 | + } | |
| 25 | + | |
| 26 | + public void setMediaServerItem(MediaServerItem mediaServerItem) { | |
| 27 | + this.mediaServerItem = mediaServerItem; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public JSONObject getResponse() { | |
| 31 | + return response; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public void setResponse(JSONObject response) { | |
| 35 | + this.response = response; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public String getCallId() { | |
| 39 | + return callId; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public void setCallId(String callId) { | |
| 43 | + this.callId = callId; | |
| 44 | + } | |
| 45 | + | |
| 46 | + public String getApp() { | |
| 47 | + return app; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public void setApp(String app) { | |
| 51 | + this.app = app; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public String getStream() { | |
| 55 | + return stream; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public void setStream(String stream) { | |
| 59 | + this.stream = stream; | |
| 60 | + } | |
| 61 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
| ... | ... | @@ -114,6 +114,21 @@ public class ParentPlatform { |
| 114 | 114 | */ |
| 115 | 115 | private String catalogId; |
| 116 | 116 | |
| 117 | + /** | |
| 118 | + * 已被订阅目录信息 | |
| 119 | + */ | |
| 120 | + private boolean catalogSubscribe; | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * 已被订阅报警信息 | |
| 124 | + */ | |
| 125 | + private boolean alarmSubscribe; | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * 已被订阅GPS信息 | |
| 129 | + */ | |
| 130 | + private boolean gpsSubscribe; | |
| 131 | + | |
| 117 | 132 | public Integer getId() { |
| 118 | 133 | return id; |
| 119 | 134 | } |
| ... | ... | @@ -290,4 +305,28 @@ public class ParentPlatform { |
| 290 | 305 | public void setCatalogId(String catalogId) { |
| 291 | 306 | this.catalogId = catalogId; |
| 292 | 307 | } |
| 308 | + | |
| 309 | + public boolean isCatalogSubscribe() { | |
| 310 | + return catalogSubscribe; | |
| 311 | + } | |
| 312 | + | |
| 313 | + public void setCatalogSubscribe(boolean catalogSubscribe) { | |
| 314 | + this.catalogSubscribe = catalogSubscribe; | |
| 315 | + } | |
| 316 | + | |
| 317 | + public boolean isAlarmSubscribe() { | |
| 318 | + return alarmSubscribe; | |
| 319 | + } | |
| 320 | + | |
| 321 | + public void setAlarmSubscribe(boolean alarmSubscribe) { | |
| 322 | + this.alarmSubscribe = alarmSubscribe; | |
| 323 | + } | |
| 324 | + | |
| 325 | + public boolean isGpsSubscribe() { | |
| 326 | + return gpsSubscribe; | |
| 327 | + } | |
| 328 | + | |
| 329 | + public void setGpsSubscribe(boolean gpsSubscribe) { | |
| 330 | + this.gpsSubscribe = gpsSubscribe; | |
| 331 | + } | |
| 293 | 332 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
| ... | ... | @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.bean; |
| 2 | 2 | |
| 3 | 3 | import org.springframework.stereotype.Component; |
| 4 | 4 | |
| 5 | +import java.util.ArrayList; | |
| 6 | +import java.util.List; | |
| 5 | 7 | import java.util.concurrent.ConcurrentHashMap; |
| 6 | 8 | |
| 7 | 9 | @Component |
| ... | ... | @@ -34,4 +36,14 @@ public class SubscribeHolder { |
| 34 | 36 | public void removeMobilePositionSubscribe(String platformId) { |
| 35 | 37 | mobilePositionMap.remove(platformId); |
| 36 | 38 | } |
| 39 | + | |
| 40 | + public List<String> getAllCatalogSubscribePlatform() { | |
| 41 | + List<String> platforms = new ArrayList<>(); | |
| 42 | + if(catalogMap.size() > 0) { | |
| 43 | + for (String key : catalogMap.keySet()) { | |
| 44 | + platforms.add(catalogMap.get(key).getId()); | |
| 45 | + } | |
| 46 | + } | |
| 47 | + return platforms; | |
| 48 | + } | |
| 37 | 49 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
| ... | ... | @@ -14,19 +14,15 @@ public class SubscribeInfo { |
| 14 | 14 | public SubscribeInfo(RequestEvent evt, String id) { |
| 15 | 15 | this.id = id; |
| 16 | 16 | Request request = evt.getRequest(); |
| 17 | - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); | |
| 18 | - this.callId = callIdHeader.getCallId(); | |
| 19 | - FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); | |
| 20 | - this.fromTag = fromHeader.getTag(); | |
| 21 | 17 | ExpiresHeader expiresHeader = (ExpiresHeader)request.getHeader(ExpiresHeader.NAME); |
| 22 | 18 | this.expires = expiresHeader.getExpires(); |
| 23 | 19 | EventHeader eventHeader = (EventHeader)request.getHeader(EventHeader.NAME); |
| 24 | 20 | this.eventId = eventHeader.getEventId(); |
| 25 | 21 | this.eventType = eventHeader.getEventType(); |
| 26 | - ViaHeader viaHeader = (ViaHeader)request.getHeader(ViaHeader.NAME); | |
| 27 | - this.branch = viaHeader.getBranch(); | |
| 28 | 22 | this.transaction = evt.getServerTransaction(); |
| 29 | 23 | this.dialog = evt.getDialog(); |
| 24 | + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); | |
| 25 | + this.callId = callIdHeader.getCallId(); | |
| 30 | 26 | } |
| 31 | 27 | |
| 32 | 28 | private String id; |
| ... | ... | @@ -34,9 +30,6 @@ public class SubscribeInfo { |
| 34 | 30 | private String callId; |
| 35 | 31 | private String eventId; |
| 36 | 32 | private String eventType; |
| 37 | - private String fromTag; | |
| 38 | - private String toTag; | |
| 39 | - private String branch; | |
| 40 | 33 | private ServerTransaction transaction; |
| 41 | 34 | private Dialog dialog; |
| 42 | 35 | |
| ... | ... | @@ -52,18 +45,6 @@ public class SubscribeInfo { |
| 52 | 45 | return callId; |
| 53 | 46 | } |
| 54 | 47 | |
| 55 | - public String getFromTag() { | |
| 56 | - return fromTag; | |
| 57 | - } | |
| 58 | - | |
| 59 | - public void setToTag(String toTag) { | |
| 60 | - this.toTag = toTag; | |
| 61 | - } | |
| 62 | - | |
| 63 | - public String getToTag() { | |
| 64 | - return toTag; | |
| 65 | - } | |
| 66 | - | |
| 67 | 48 | public void setId(String id) { |
| 68 | 49 | this.id = id; |
| 69 | 50 | } |
| ... | ... | @@ -76,10 +57,6 @@ public class SubscribeInfo { |
| 76 | 57 | this.callId = callId; |
| 77 | 58 | } |
| 78 | 59 | |
| 79 | - public void setFromTag(String fromTag) { | |
| 80 | - this.fromTag = fromTag; | |
| 81 | - } | |
| 82 | - | |
| 83 | 60 | public String getEventId() { |
| 84 | 61 | return eventId; |
| 85 | 62 | } |
| ... | ... | @@ -96,14 +73,6 @@ public class SubscribeInfo { |
| 96 | 73 | this.eventType = eventType; |
| 97 | 74 | } |
| 98 | 75 | |
| 99 | - public String getBranch() { | |
| 100 | - return branch; | |
| 101 | - } | |
| 102 | - | |
| 103 | - public void setBranch(String branch) { | |
| 104 | - this.branch = branch; | |
| 105 | - } | |
| 106 | - | |
| 107 | 76 | public ServerTransaction getTransaction() { |
| 108 | 77 | return transaction; |
| 109 | 78 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
| ... | ... | @@ -30,7 +30,7 @@ public class SipSubscribe { |
| 30 | 30 | // @Scheduled(fixedRate= 100 * 60 * 60 ) |
| 31 | 31 | @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次 |
| 32 | 32 | public void execute(){ |
| 33 | - logger.info("[定时任务] 清理过期的订阅信息"); | |
| 33 | + logger.info("[定时任务] 清理过期的SIP订阅信息"); | |
| 34 | 34 | Calendar calendar = Calendar.getInstance(); |
| 35 | 35 | calendar.setTime(new Date()); |
| 36 | 36 | calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - 5); |
| ... | ... | @@ -49,10 +49,10 @@ public class SipSubscribe { |
| 49 | 49 | errorTimeSubscribes.remove(key); |
| 50 | 50 | } |
| 51 | 51 | } |
| 52 | - logger.info("okTimeSubscribes.size:{}",okTimeSubscribes.size()); | |
| 53 | - logger.info("okSubscribes.size:{}",okSubscribes.size()); | |
| 54 | - logger.info("errorTimeSubscribes.size:{}",errorTimeSubscribes.size()); | |
| 55 | - logger.info("errorSubscribes.size:{}",errorSubscribes.size()); | |
| 52 | + logger.debug("okTimeSubscribes.size:{}",okTimeSubscribes.size()); | |
| 53 | + logger.debug("okSubscribes.size:{}",okSubscribes.size()); | |
| 54 | + logger.debug("errorTimeSubscribes.size:{}",errorTimeSubscribes.size()); | |
| 55 | + logger.debug("errorSubscribes.size:{}",errorSubscribes.size()); | |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | public interface Event { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
| ... | ... | @@ -68,8 +68,6 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 68 | 68 | String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId(); |
| 69 | 69 | Device deviceInStore = storager.queryVideoDevice(device.getDeviceId()); |
| 70 | 70 | device.setOnline(1); |
| 71 | - // 处理上线监听 | |
| 72 | - storager.updateDevice(device); | |
| 73 | 71 | switch (event.getFrom()) { |
| 74 | 72 | // 注册时触发的在线事件,先在redis中增加超时超时监听 |
| 75 | 73 | case VideoManagerConstants.EVENT_ONLINE_REGISTER: |
| ... | ... | @@ -98,7 +96,8 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 98 | 96 | |
| 99 | 97 | break; |
| 100 | 98 | } |
| 101 | - | |
| 99 | + // 处理上线监听 | |
| 100 | + storager.updateDevice(device); | |
| 102 | 101 | List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId()); |
| 103 | 102 | eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON); |
| 104 | 103 | // 上线添加订阅 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| ... | ... | @@ -74,7 +74,7 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 74 | 74 | } |
| 75 | 75 | }else { |
| 76 | 76 | // 获取所用订阅 |
| 77 | - List<String> platforms = redisCatchStorage.getAllSubscribePlatform(); | |
| 77 | + List<String> platforms = subscribeHolder.getAllCatalogSubscribePlatform(); | |
| 78 | 78 | if (event.getDeviceChannels() != null) { |
| 79 | 79 | if (platforms.size() > 0) { |
| 80 | 80 | for (DeviceChannel deviceChannel : event.getDeviceChannels()) { |
| ... | ... | @@ -117,8 +117,6 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 117 | 117 | List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); |
| 118 | 118 | if (parentPlatforms != null && parentPlatforms.size() > 0) { |
| 119 | 119 | for (ParentPlatform platform : parentPlatforms) { |
| 120 | - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId(); | |
| 121 | -// SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key); | |
| 122 | 120 | SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); |
| 123 | 121 | if (subscribeInfo == null) continue; |
| 124 | 122 | logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
| ... | ... | @@ -95,14 +95,14 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { |
| 95 | 95 | logger.debug("\n收到响应:\n{}", responseEvent.getResponse()); |
| 96 | 96 | int status = response.getStatusCode(); |
| 97 | 97 | |
| 98 | - if (((status >= 200) && (status < 300)) || status == 401) { // Success! | |
| 98 | + if (((status >= 200) && (status < 300)) || status == Response.UNAUTHORIZED) { // Success! | |
| 99 | 99 | CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); |
| 100 | 100 | String method = cseqHeader.getMethod(); |
| 101 | 101 | ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); |
| 102 | 102 | if (sipRequestProcessor != null) { |
| 103 | 103 | sipRequestProcessor.process(responseEvent); |
| 104 | 104 | } |
| 105 | - if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { | |
| 105 | + if (status != Response.UNAUTHORIZED && responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { | |
| 106 | 106 | CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME); |
| 107 | 107 | if (callIdHeader != null) { |
| 108 | 108 | SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; | |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 6 | 7 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 7 | 8 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| ... | ... | @@ -103,7 +104,7 @@ public interface ISIPCommander { |
| 103 | 104 | * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 104 | 105 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 105 | 106 | */ |
| 106 | - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); | |
| 107 | + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent); | |
| 107 | 108 | |
| 108 | 109 | /** |
| 109 | 110 | * 请求历史媒体下载 |
| ... | ... | @@ -114,13 +115,13 @@ public interface ISIPCommander { |
| 114 | 115 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 115 | 116 | * @param downloadSpeed 下载倍速参数 |
| 116 | 117 | */ |
| 117 | - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); | |
| 118 | + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event, SipSubscribe.Event errorEvent); | |
| 118 | 119 | |
| 119 | 120 | /** |
| 120 | 121 | * 视频流停止 |
| 121 | 122 | */ |
| 122 | - void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent); | |
| 123 | - void streamByeCmd(String deviceId, String channelId, String stream); | |
| 123 | + void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent); | |
| 124 | + void streamByeCmd(String deviceId, String channelId, String stream, String callId); | |
| 124 | 125 | |
| 125 | 126 | /** |
| 126 | 127 | * 回放暂停 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -6,6 +6,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.UserSetup; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; | |
| 9 | 11 | import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; |
| 10 | 12 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 11 | 13 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| ... | ... | @@ -445,27 +447,13 @@ public class SIPCommander implements ISIPCommander { |
| 445 | 447 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 446 | 448 | */ |
| 447 | 449 | @Override |
| 448 | - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event | |
| 449 | - , SipSubscribe.Event errorEvent) { | |
| 450 | + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 451 | + String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, | |
| 452 | + SipSubscribe.Event errorEvent) { | |
| 450 | 453 | try { |
| 451 | 454 | |
| 452 | 455 | logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); |
| 453 | 456 | |
| 454 | - // 添加订阅 | |
| 455 | - JSONObject subscribeKey = new JSONObject(); | |
| 456 | - subscribeKey.put("app", "rtp"); | |
| 457 | - subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 458 | - subscribeKey.put("regist", true); | |
| 459 | - subscribeKey.put("schema", "rtmp"); | |
| 460 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 461 | - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); | |
| 462 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 463 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 464 | - if (event != null) { | |
| 465 | - event.response(mediaServerItemInUse, json); | |
| 466 | - } | |
| 467 | - }); | |
| 468 | - | |
| 469 | 457 | StringBuffer content = new StringBuffer(200); |
| 470 | 458 | content.append("v=0\r\n"); |
| 471 | 459 | content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); |
| ... | ... | @@ -530,6 +518,21 @@ public class SIPCommander implements ISIPCommander { |
| 530 | 518 | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| 531 | 519 | : udpSipProvider.getNewCallId(); |
| 532 | 520 | |
| 521 | + // 添加订阅 | |
| 522 | + JSONObject subscribeKey = new JSONObject(); | |
| 523 | + subscribeKey.put("app", "rtp"); | |
| 524 | + subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 525 | + subscribeKey.put("regist", true); | |
| 526 | + subscribeKey.put("schema", "rtmp"); | |
| 527 | + subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 528 | + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey); | |
| 529 | + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 530 | + (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 531 | + if (hookEvent != null) { | |
| 532 | + InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()); | |
| 533 | + hookEvent.call(inviteStreamInfo); | |
| 534 | + } | |
| 535 | + }); | |
| 533 | 536 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); |
| 534 | 537 | |
| 535 | 538 | transmitRequest(device, request, errorEvent, okEvent -> { |
| ... | ... | @@ -537,6 +540,9 @@ public class SIPCommander implements ISIPCommander { |
| 537 | 540 | streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction()); |
| 538 | 541 | streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog); |
| 539 | 542 | }); |
| 543 | + if (inviteStreamCallback != null) { | |
| 544 | + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); | |
| 545 | + } | |
| 540 | 546 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 541 | 547 | e.printStackTrace(); |
| 542 | 548 | } |
| ... | ... | @@ -552,24 +558,11 @@ public class SIPCommander implements ISIPCommander { |
| 552 | 558 | * @param downloadSpeed 下载倍速参数 |
| 553 | 559 | */ |
| 554 | 560 | @Override |
| 555 | - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event | |
| 561 | + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event | |
| 556 | 562 | , SipSubscribe.Event errorEvent) { |
| 557 | 563 | try { |
| 558 | 564 | logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); |
| 559 | 565 | |
| 560 | - // 添加订阅 | |
| 561 | - JSONObject subscribeKey = new JSONObject(); | |
| 562 | - subscribeKey.put("app", "rtp"); | |
| 563 | - subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 564 | - subscribeKey.put("regist", true); | |
| 565 | - subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 566 | - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); | |
| 567 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 568 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 569 | - event.response(mediaServerItemInUse, json); | |
| 570 | - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); | |
| 571 | - }); | |
| 572 | - | |
| 573 | 566 | StringBuffer content = new StringBuffer(200); |
| 574 | 567 | content.append("v=0\r\n"); |
| 575 | 568 | content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); |
| ... | ... | @@ -637,6 +630,19 @@ public class SIPCommander implements ISIPCommander { |
| 637 | 630 | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| 638 | 631 | : udpSipProvider.getNewCallId(); |
| 639 | 632 | |
| 633 | + // 添加订阅 | |
| 634 | + JSONObject subscribeKey = new JSONObject(); | |
| 635 | + subscribeKey.put("app", "rtp"); | |
| 636 | + subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 637 | + subscribeKey.put("regist", true); | |
| 638 | + subscribeKey.put("mediaServerId", mediaServerItem.getId()); | |
| 639 | + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); | |
| 640 | + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 641 | + (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 642 | + event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); | |
| 643 | + subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); | |
| 644 | + }); | |
| 645 | + | |
| 640 | 646 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); |
| 641 | 647 | |
| 642 | 648 | ClientTransaction transaction = transmitRequest(device, request, errorEvent); |
| ... | ... | @@ -652,15 +658,15 @@ public class SIPCommander implements ISIPCommander { |
| 652 | 658 | * 视频流停止, 不使用回调 |
| 653 | 659 | */ |
| 654 | 660 | @Override |
| 655 | - public void streamByeCmd(String deviceId, String channelId, String stream) { | |
| 656 | - streamByeCmd(deviceId, channelId, stream, null); | |
| 661 | + public void streamByeCmd(String deviceId, String channelId, String stream, String callId) { | |
| 662 | + streamByeCmd(deviceId, channelId, stream, callId, null); | |
| 657 | 663 | } |
| 658 | 664 | |
| 659 | 665 | /** |
| 660 | 666 | * 视频流停止 |
| 661 | 667 | */ |
| 662 | 668 | @Override |
| 663 | - public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) { | |
| 669 | + public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) { | |
| 664 | 670 | try { |
| 665 | 671 | SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream); |
| 666 | 672 | ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream); |
| ... | ... | @@ -672,7 +678,15 @@ public class SIPCommander implements ISIPCommander { |
| 672 | 678 | } |
| 673 | 679 | return; |
| 674 | 680 | } |
| 675 | - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream); | |
| 681 | + SIPDialog dialog; | |
| 682 | + if (callId != null) { | |
| 683 | + dialog = streamSession.getDialogByCallId(deviceId, channelId, callId); | |
| 684 | + }else { | |
| 685 | + if (stream == null) return; | |
| 686 | + dialog = streamSession.getDialogByStream(deviceId, channelId, stream); | |
| 687 | + } | |
| 688 | + | |
| 689 | + | |
| 676 | 690 | if (dialog == null) { |
| 677 | 691 | logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId); |
| 678 | 692 | return; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 13 | 13 | import com.genersoft.iot.vmp.utils.SerializeUtils; |
| 14 | 14 | import gov.nist.javax.sip.SipProviderImpl; |
| 15 | 15 | import gov.nist.javax.sip.SipStackImpl; |
| 16 | +import gov.nist.javax.sip.message.MessageFactoryImpl; | |
| 16 | 17 | import gov.nist.javax.sip.message.SIPRequest; |
| 17 | 18 | import gov.nist.javax.sip.stack.SIPDialog; |
| 18 | 19 | import org.slf4j.Logger; |
| ... | ... | @@ -77,11 +78,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 77 | 78 | @Override |
| 78 | 79 | public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { |
| 79 | 80 | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); |
| 81 | + parentPlatform.setExpires("0"); | |
| 80 | 82 | if (parentPlatformCatch != null) { |
| 81 | 83 | parentPlatformCatch.setParentPlatform(parentPlatform); |
| 82 | 84 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| 83 | 85 | } |
| 84 | - parentPlatform.setExpires("0"); | |
| 85 | 86 | return register(parentPlatform, null, null, errorEvent, okEvent, false); |
| 86 | 87 | } |
| 87 | 88 | |
| ... | ... | @@ -101,7 +102,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 101 | 102 | callIdHeader = udpSipProvider.getNewCallId(); |
| 102 | 103 | } |
| 103 | 104 | |
| 104 | - request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, null, callIdHeader); | |
| 105 | + request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, | |
| 106 | + redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, | |
| 107 | + "z9hG4bK-" + UUID.randomUUID().toString().replace("-", ""), callIdHeader); | |
| 105 | 108 | // 将 callid 写入缓存, 等注册成功可以更新状态 |
| 106 | 109 | String callIdFromHeader = callIdHeader.getCallId(); |
| 107 | 110 | redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, parentPlatform.getServerGBId()); |
| ... | ... | @@ -414,11 +417,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 414 | 417 | private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent, |
| 415 | 418 | SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent ) |
| 416 | 419 | throws NoSuchFieldException, IllegalAccessException, SipException, ParseException { |
| 420 | + MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory(); | |
| 421 | + // 设置编码, 防止中文乱码 | |
| 422 | + messageFactory.setDefaultContentEncodingCharset("gb2312"); | |
| 417 | 423 | Dialog dialog = subscribeInfo.getDialog(); |
| 418 | - Request notifyRequest = dialog.createRequest(Request.NOTIFY); | |
| 419 | - | |
| 424 | + if (dialog == null) return; | |
| 425 | + SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY); | |
| 420 | 426 | ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); |
| 421 | - | |
| 422 | 427 | notifyRequest.setContent(catalogXmlContent, contentTypeHeader); |
| 423 | 428 | |
| 424 | 429 | SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory() |
| ... | ... | @@ -509,7 +514,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 509 | 514 | } |
| 510 | 515 | |
| 511 | 516 | @Override |
| 512 | - public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) { | |
| 517 | + public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, | |
| 518 | + SubscribeInfo subscribeInfo, Integer index) { | |
| 513 | 519 | if (parentPlatform == null |
| 514 | 520 | || deviceChannels == null |
| 515 | 521 | || deviceChannels.size() == 0 |
| ... | ... | @@ -577,24 +583,30 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 577 | 583 | recordXml.append("<SN>" +recordInfo.getSn() + "</SN>\r\n"); |
| 578 | 584 | recordXml.append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n"); |
| 579 | 585 | recordXml.append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); |
| 580 | - recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n"); | |
| 581 | - for (RecordItem recordItem : recordInfo.getRecordList()) { | |
| 582 | - recordXml.append("<Item>\r\n"); | |
| 583 | - if (deviceChannel != null) { | |
| 584 | - recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n"); | |
| 585 | - recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n"); | |
| 586 | - recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n"); | |
| 587 | - recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n"); | |
| 588 | - recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n"); | |
| 589 | - recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n"); | |
| 590 | - if (!StringUtils.isEmpty(recordItem.getFileSize())) { | |
| 591 | - recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); | |
| 592 | - } | |
| 593 | - if (!StringUtils.isEmpty(recordItem.getFilePath())) { | |
| 594 | - recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n"); | |
| 586 | + if (recordInfo.getRecordList() == null ) { | |
| 587 | + recordXml.append("<RecordList Num=\"0\">\r\n"); | |
| 588 | + }else { | |
| 589 | + recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n"); | |
| 590 | + if (recordInfo.getRecordList().size() > 0) { | |
| 591 | + for (RecordItem recordItem : recordInfo.getRecordList()) { | |
| 592 | + recordXml.append("<Item>\r\n"); | |
| 593 | + if (deviceChannel != null) { | |
| 594 | + recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n"); | |
| 595 | + recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n"); | |
| 596 | + recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n"); | |
| 597 | + recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n"); | |
| 598 | + recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n"); | |
| 599 | + recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n"); | |
| 600 | + if (!StringUtils.isEmpty(recordItem.getFileSize())) { | |
| 601 | + recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); | |
| 602 | + } | |
| 603 | + if (!StringUtils.isEmpty(recordItem.getFilePath())) { | |
| 604 | + recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n"); | |
| 605 | + } | |
| 606 | + } | |
| 607 | + recordXml.append("</Item>\r\n"); | |
| 595 | 608 | } |
| 596 | 609 | } |
| 597 | - recordXml.append("</Item>\r\n"); | |
| 598 | 610 | } |
| 599 | 611 | |
| 600 | 612 | recordXml.append("</RecordList>\r\n"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
| ... | ... | @@ -27,10 +27,7 @@ import javax.sip.header.CallIdHeader; |
| 27 | 27 | import javax.sip.header.FromHeader; |
| 28 | 28 | import javax.sip.header.HeaderAddress; |
| 29 | 29 | import javax.sip.header.ToHeader; |
| 30 | -import java.util.HashMap; | |
| 31 | -import java.util.Map; | |
| 32 | -import java.util.Timer; | |
| 33 | -import java.util.TimerTask; | |
| 30 | +import java.util.*; | |
| 34 | 31 | |
| 35 | 32 | /** |
| 36 | 33 | * SIP命令类型: ACK请求 |
| ... | ... | @@ -84,44 +81,72 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In |
| 84 | 81 | String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); |
| 85 | 82 | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); |
| 86 | 83 | String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; |
| 87 | - String deviceId = sendRtpItem.getDeviceId(); | |
| 88 | - StreamInfo streamInfo = null; | |
| 89 | - if (sendRtpItem.isPlay()) { | |
| 90 | - streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 91 | - }else { | |
| 92 | - streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); | |
| 93 | - } | |
| 94 | - if (streamInfo == null) { | |
| 95 | - streamInfo = new StreamInfo(); | |
| 96 | - streamInfo.setApp(sendRtpItem.getApp()); | |
| 97 | - streamInfo.setStream(sendRtpItem.getStreamId()); | |
| 98 | - } | |
| 99 | - redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 84 | + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); | |
| 85 | + logger.info("收到ACK,开始向上级推流 rtp/{}", sendRtpItem.getStreamId()); | |
| 100 | 86 | Map<String, Object> param = new HashMap<>(); |
| 101 | 87 | param.put("vhost","__defaultVhost__"); |
| 102 | - param.put("app",streamInfo.getApp()); | |
| 103 | - param.put("stream",streamInfo.getStream()); | |
| 88 | + param.put("app",sendRtpItem.getApp()); | |
| 89 | + param.put("stream",sendRtpItem.getStreamId()); | |
| 104 | 90 | param.put("ssrc", sendRtpItem.getSsrc()); |
| 105 | 91 | param.put("dst_url",sendRtpItem.getIp()); |
| 106 | 92 | param.put("dst_port", sendRtpItem.getPort()); |
| 107 | 93 | param.put("is_udp", is_Udp); |
| 108 | - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); | |
| 109 | - JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 110 | - if (jsonObject.getInteger("code") != 0) { | |
| 111 | - logger.info("监听流以等待流上线{}/{}", streamInfo.getApp(), streamInfo.getStream()); | |
| 112 | - // 监听流上线 | |
| 113 | - // 添加订阅 | |
| 114 | - JSONObject subscribeKey = new JSONObject(); | |
| 115 | - subscribeKey.put("app", "rtp"); | |
| 116 | - subscribeKey.put("stream", streamInfo.getStream()); | |
| 117 | - subscribeKey.put("regist", true); | |
| 118 | - subscribeKey.put("schema", "rtmp"); | |
| 119 | - subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); | |
| 120 | - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 121 | - (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 122 | - zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 123 | - }); | |
| 124 | - } | |
| 94 | + param.put("src_port", sendRtpItem.getLocalPort()); | |
| 95 | + zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | +// if (streamInfo == null) { // 流还没上来,对方就回复ack | |
| 100 | +// logger.info("监听流以等待流上线1 rtp/{}", sendRtpItem.getStreamId()); | |
| 101 | +// // 监听流上线 | |
| 102 | +// // 添加订阅 | |
| 103 | +// JSONObject subscribeKey = new JSONObject(); | |
| 104 | +// subscribeKey.put("app", "rtp"); | |
| 105 | +// subscribeKey.put("stream", sendRtpItem.getStreamId()); | |
| 106 | +// subscribeKey.put("regist", true); | |
| 107 | +// subscribeKey.put("schema", "rtmp"); | |
| 108 | +// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); | |
| 109 | +// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 110 | +// (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 111 | +// Map<String, Object> param = new HashMap<>(); | |
| 112 | +// param.put("vhost","__defaultVhost__"); | |
| 113 | +// param.put("app",json.getString("app")); | |
| 114 | +// param.put("stream",json.getString("stream")); | |
| 115 | +// param.put("ssrc", sendRtpItem.getSsrc()); | |
| 116 | +// param.put("dst_url",sendRtpItem.getIp()); | |
| 117 | +// param.put("dst_port", sendRtpItem.getPort()); | |
| 118 | +// param.put("is_udp", is_Udp); | |
| 119 | +// param.put("src_port", sendRtpItem.getLocalPort()); | |
| 120 | +// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 121 | +// }); | |
| 122 | +// }else { | |
| 123 | +// Map<String, Object> param = new HashMap<>(); | |
| 124 | +// param.put("vhost","__defaultVhost__"); | |
| 125 | +// param.put("app",streamInfo.getApp()); | |
| 126 | +// param.put("stream",streamInfo.getStream()); | |
| 127 | +// param.put("ssrc", sendRtpItem.getSsrc()); | |
| 128 | +// param.put("dst_url",sendRtpItem.getIp()); | |
| 129 | +// param.put("dst_port", sendRtpItem.getPort()); | |
| 130 | +// param.put("is_udp", is_Udp); | |
| 131 | +// param.put("src_port", sendRtpItem.getLocalPort()); | |
| 132 | +// | |
| 133 | +// JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 134 | +// if (jsonObject.getInteger("code") != 0) { | |
| 135 | +// logger.info("监听流以等待流上线2 {}/{}", streamInfo.getApp(), streamInfo.getStream()); | |
| 136 | +// // 监听流上线 | |
| 137 | +// // 添加订阅 | |
| 138 | +// JSONObject subscribeKey = new JSONObject(); | |
| 139 | +// subscribeKey.put("app", "rtp"); | |
| 140 | +// subscribeKey.put("stream", streamInfo.getStream()); | |
| 141 | +// subscribeKey.put("regist", true); | |
| 142 | +// subscribeKey.put("schema", "rtmp"); | |
| 143 | +// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); | |
| 144 | +// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, | |
| 145 | +// (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 146 | +// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); | |
| 147 | +// }); | |
| 148 | +// } | |
| 149 | +// } | |
| 125 | 150 | } |
| 126 | 151 | } |
| 127 | 152 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -93,14 +93,16 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 93 | 93 | param.put("app",sendRtpItem.getApp()); |
| 94 | 94 | param.put("stream",streamId); |
| 95 | 95 | param.put("ssrc",sendRtpItem.getSsrc()); |
| 96 | - logger.info("停止向上级推流:" + streamId); | |
| 96 | + logger.info("收到bye:停止向上级推流:" + streamId); | |
| 97 | 97 | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| 98 | 98 | zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); |
| 99 | 99 | redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null); |
| 100 | 100 | int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); |
| 101 | 101 | if (totalReaderCount <= 0) { |
| 102 | - logger.info(streamId + "无其它观看者,通知设备停止推流"); | |
| 103 | - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId); | |
| 102 | + logger.info("收到bye: {}无其它观看者,通知设备停止推流", streamId); | |
| 103 | + if (sendRtpItem.isPlay()) { | |
| 104 | + cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null); | |
| 105 | + } | |
| 104 | 106 | } |
| 105 | 107 | } |
| 106 | 108 | // 可能是设备主动停止 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 9 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 10 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| ... | ... | @@ -91,6 +92,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 91 | 92 | @Autowired |
| 92 | 93 | private SIPProcessorObserver sipProcessorObserver; |
| 93 | 94 | |
| 95 | + @Autowired | |
| 96 | + private VideoStreamSessionManager sessionManager; | |
| 97 | + | |
| 94 | 98 | |
| 95 | 99 | @Override |
| 96 | 100 | public void afterPropertiesSet() throws Exception { |
| ... | ... | @@ -233,6 +237,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 233 | 237 | } |
| 234 | 238 | String username = sdp.getOrigin().getUsername(); |
| 235 | 239 | String addressStr = sdp.getOrigin().getAddress(); |
| 240 | + | |
| 236 | 241 | logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); |
| 237 | 242 | Device device = null; |
| 238 | 243 | // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 |
| ... | ... | @@ -266,13 +271,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 266 | 271 | sendRtpItem.setDialog(dialogByteArray); |
| 267 | 272 | byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction()); |
| 268 | 273 | sendRtpItem.setTransaction(transactionByteArray); |
| 269 | - // 写入redis, 超时时回复 | |
| 270 | - redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 274 | + | |
| 271 | 275 | |
| 272 | 276 | Long finalStartTime = startTime; |
| 273 | 277 | Long finalStopTime = stopTime; |
| 274 | 278 | ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{ |
| 275 | - logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId()); | |
| 279 | + String app = responseJSON.getString("app"); | |
| 280 | + String stream = responseJSON.getString("stream"); | |
| 281 | + logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream); | |
| 276 | 282 | // * 0 等待设备推流上来 |
| 277 | 283 | // * 1 下级已经推流,等待上级平台回复ack |
| 278 | 284 | // * 2 推流中 |
| ... | ... | @@ -325,46 +331,66 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 325 | 331 | e.printStackTrace(); |
| 326 | 332 | } |
| 327 | 333 | }); |
| 334 | + sendRtpItem.setApp("rtp"); | |
| 328 | 335 | if ("Playback".equals(sessionName)) { |
| 329 | 336 | sendRtpItem.setPlay(false); |
| 330 | - sendRtpItem.setStreamId(ssrc); | |
| 337 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); | |
| 338 | + sendRtpItem.setStreamId(ssrcInfo.getStream()); | |
| 339 | + // 写入redis, 超时时回复 | |
| 340 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 331 | 341 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| 332 | - playService.playBack(device.getDeviceId(), channelId, format.format(start), format.format(end),result -> { | |
| 333 | - if (result.getCode() != 0){ | |
| 334 | - logger.warn("录像回放失败"); | |
| 335 | - if (result.getEvent() != null) { | |
| 336 | - errorEvent.response(result.getEvent()); | |
| 337 | - } | |
| 338 | - redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); | |
| 339 | - try { | |
| 340 | - responseAck(evt, Response.REQUEST_TIMEOUT); | |
| 341 | - } catch (SipException e) { | |
| 342 | - e.printStackTrace(); | |
| 343 | - } catch (InvalidArgumentException e) { | |
| 344 | - e.printStackTrace(); | |
| 345 | - } catch (ParseException e) { | |
| 346 | - e.printStackTrace(); | |
| 342 | + playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, format.format(start), | |
| 343 | + format.format(end), null, result -> { | |
| 344 | + if (result.getCode() != 0){ | |
| 345 | + logger.warn("录像回放失败"); | |
| 346 | + if (result.getEvent() != null) { | |
| 347 | + errorEvent.response(result.getEvent()); | |
| 348 | + } | |
| 349 | + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); | |
| 350 | + try { | |
| 351 | + responseAck(evt, Response.REQUEST_TIMEOUT); | |
| 352 | + } catch (SipException e) { | |
| 353 | + e.printStackTrace(); | |
| 354 | + } catch (InvalidArgumentException e) { | |
| 355 | + e.printStackTrace(); | |
| 356 | + } catch (ParseException e) { | |
| 357 | + e.printStackTrace(); | |
| 358 | + } | |
| 359 | + }else { | |
| 360 | + if (result.getMediaServerItem() != null) { | |
| 361 | + hookEvent.response(result.getMediaServerItem(), result.getResponse()); | |
| 362 | + } | |
| 347 | 363 | } |
| 348 | - }else { | |
| 349 | - if (result.getMediaServerItem() != null) { | |
| 350 | - hookEvent.response(result.getMediaServerItem(), result.getResponse()); | |
| 351 | - } | |
| 352 | - } | |
| 353 | - }); | |
| 364 | + }); | |
| 354 | 365 | }else { |
| 355 | 366 | sendRtpItem.setPlay(true); |
| 356 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); | |
| 357 | - if (streamInfo == null) { | |
| 367 | + SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); | |
| 368 | + if (playTransaction != null) { | |
| 369 | + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream()); | |
| 370 | + if (!streamReady) { | |
| 371 | + playTransaction = null; | |
| 372 | + } | |
| 373 | + } | |
| 374 | + if (playTransaction == null) { | |
| 375 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); | |
| 358 | 376 | if (mediaServerItem.isRtpEnable()) { |
| 359 | 377 | sendRtpItem.setStreamId(String.format("%s_%s", device.getDeviceId(), channelId)); |
| 378 | + }else { | |
| 379 | + sendRtpItem.setStreamId(ssrcInfo.getStream()); | |
| 360 | 380 | } |
| 361 | - sendRtpItem.setPlay(false); | |
| 362 | - playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent, errorEvent, ()->{ | |
| 381 | + // 写入redis, 超时时回复 | |
| 382 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 383 | + playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg)->{ | |
| 363 | 384 | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| 364 | - }); | |
| 385 | + }, null); | |
| 365 | 386 | }else { |
| 366 | - sendRtpItem.setStreamId(streamInfo.getStream()); | |
| 367 | - hookEvent.response(mediaServerItem, null); | |
| 387 | + sendRtpItem.setStreamId(playTransaction.getStream()); | |
| 388 | + // 写入redis, 超时时回复 | |
| 389 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | |
| 390 | + JSONObject jsonObject = new JSONObject(); | |
| 391 | + jsonObject.put("app", sendRtpItem.getApp()); | |
| 392 | + jsonObject.put("stream", sendRtpItem.getStreamId()); | |
| 393 | + hookEvent.response(mediaServerItem, jsonObject); | |
| 368 | 394 | } |
| 369 | 395 | } |
| 370 | 396 | }else if (gbStream != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
| ... | ... | @@ -233,7 +233,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 233 | 233 | */ |
| 234 | 234 | private void processNotifyCatalogList(RequestEvent evt) { |
| 235 | 235 | try { |
| 236 | - System.out.println(343434); | |
| 237 | 236 | FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); |
| 238 | 237 | String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader); |
| 239 | 238 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
| ... | ... | @@ -158,20 +158,14 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 158 | 158 | String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔 |
| 159 | 159 | dynamicTask.startCron(key, new GPSSubscribeTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval)); |
| 160 | 160 | subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo); |
| 161 | -// redisCatchStorage.updateSubscribe(key, subscribeInfo); | |
| 162 | 161 | }else if (subscribeInfo.getExpires() == 0) { |
| 163 | 162 | dynamicTask.stop(key); |
| 164 | -// redisCatchStorage.delSubscribe(key); | |
| 165 | 163 | subscribeHolder.removeMobilePositionSubscribe(platformId); |
| 166 | 164 | } |
| 167 | 165 | |
| 168 | 166 | try { |
| 169 | 167 | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); |
| 170 | - Response response = responseXmlAck(evt, resultXml.toString(), parentPlatform); | |
| 171 | - ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME); | |
| 172 | - subscribeInfo.setToTag(toHeader.getTag()); | |
| 173 | - redisCatchStorage.updateSubscribe(key, subscribeInfo); | |
| 174 | - | |
| 168 | + responseXmlAck(evt, resultXml.toString(), parentPlatform); | |
| 175 | 169 | } catch (SipException e) { |
| 176 | 170 | e.printStackTrace(); |
| 177 | 171 | } catch (InvalidArgumentException e) { |
| ... | ... | @@ -211,21 +205,14 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 211 | 205 | .append("</Response>\r\n"); |
| 212 | 206 | |
| 213 | 207 | if (subscribeInfo.getExpires() > 0) { |
| 214 | -// redisCatchStorage.updateSubscribe(key, subscribeInfo); | |
| 215 | 208 | subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo); |
| 216 | 209 | }else if (subscribeInfo.getExpires() == 0) { |
| 217 | -// redisCatchStorage.delSubscribe(key); | |
| 218 | 210 | subscribeHolder.removeCatalogSubscribe(platformId); |
| 219 | 211 | } |
| 220 | 212 | |
| 221 | 213 | try { |
| 222 | 214 | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId); |
| 223 | - Response response = responseXmlAck(evt, resultXml.toString(), parentPlatform); | |
| 224 | - ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME); | |
| 225 | - subscribeInfo.setToTag(toHeader.getTag()); | |
| 226 | -// redisCatchStorage.updateSubscribe(key, subscribeInfo); | |
| 227 | - subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo); | |
| 228 | - | |
| 215 | + responseXmlAck(evt, resultXml.toString(), parentPlatform); | |
| 229 | 216 | } catch (SipException e) { |
| 230 | 217 | e.printStackTrace(); |
| 231 | 218 | } catch (InvalidArgumentException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
| ... | ... | @@ -67,9 +67,6 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement |
| 67 | 67 | // 查询设备是否存在 |
| 68 | 68 | CSeqHeader cseqHeader = (CSeqHeader) evt.getRequest().getHeader(CSeqHeader.NAME); |
| 69 | 69 | String method = cseqHeader.getMethod(); |
| 70 | - if (method.equals("MESSAGE")) { | |
| 71 | - System.out.println(); | |
| 72 | - } | |
| 73 | 70 | Device device = redisCatchStorage.getDevice(deviceId); |
| 74 | 71 | // 查询上级平台是否存在 |
| 75 | 72 | ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
| ... | ... | @@ -18,6 +18,7 @@ import org.springframework.stereotype.Component; |
| 18 | 18 | import javax.sip.InvalidArgumentException; |
| 19 | 19 | import javax.sip.RequestEvent; |
| 20 | 20 | import javax.sip.SipException; |
| 21 | +import javax.sip.header.CallIdHeader; | |
| 21 | 22 | import javax.sip.message.Response; |
| 22 | 23 | import java.text.ParseException; |
| 23 | 24 | |
| ... | ... | @@ -56,14 +57,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i |
| 56 | 57 | } catch (ParseException e) { |
| 57 | 58 | e.printStackTrace(); |
| 58 | 59 | } |
| 60 | + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); | |
| 59 | 61 | String NotifyType =getText(rootElement, "NotifyType"); |
| 60 | 62 | if (NotifyType.equals("121")){ |
| 61 | 63 | logger.info("媒体播放完毕,通知关流"); |
| 62 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*"); | |
| 63 | - if (streamInfo != null) { | |
| 64 | - redisCatchStorage.stopPlayback(streamInfo); | |
| 65 | - cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); | |
| 66 | - } | |
| 64 | + String channelId =getText(rootElement, "DeviceID"); | |
| 65 | + redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); | |
| 66 | + cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); | |
| 67 | + // TODO 如果级联播放,需要给上级发送此通知 | |
| 68 | + | |
| 67 | 69 | } |
| 68 | 70 | } |
| 69 | 71 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
| ... | ... | @@ -88,7 +88,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp |
| 88 | 88 | Element secrecyElement = rootElement.element("Secrecy"); |
| 89 | 89 | int secrecy = 0; |
| 90 | 90 | if (secrecyElement != null) { |
| 91 | - secrecy = Integer.parseInt(secrecyElement.getText()); | |
| 91 | + secrecy = Integer.parseInt(secrecyElement.getText().trim()); | |
| 92 | 92 | } |
| 93 | 93 | String type = "all"; |
| 94 | 94 | Element typeElement = rootElement.element("Type"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; | |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; |
| ... | ... | @@ -40,6 +41,9 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 40 | 41 | @Autowired |
| 41 | 42 | private SIPProcessorObserver sipProcessorObserver; |
| 42 | 43 | |
| 44 | + @Autowired | |
| 45 | + private SubscribeHolder subscribeHolder; | |
| 46 | + | |
| 43 | 47 | @Override |
| 44 | 48 | public void afterPropertiesSet() throws Exception { |
| 45 | 49 | // 添加消息处理的订阅 |
| ... | ... | @@ -83,19 +87,19 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 83 | 87 | // 注册/注销成功 |
| 84 | 88 | logger.info(String.format("%s %s成功", platformGBId, action)); |
| 85 | 89 | redisCatchStorage.delPlatformRegisterInfo(callId); |
| 86 | - parentPlatform.setStatus("注册".equals(action)); | |
| 90 | + redisCatchStorage.delPlatformCatchInfo(platformGBId); | |
| 87 | 91 | // 取回Expires设置,避免注销过程中被置为0 |
| 88 | - if (!parentPlatformCatch.getParentPlatform().getExpires().equals("0")) { | |
| 89 | - ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId); | |
| 90 | - String expires = parentPlatformTmp.getExpires(); | |
| 91 | - parentPlatform.setExpires(expires); | |
| 92 | - parentPlatform.setId(parentPlatformTmp.getId()); | |
| 93 | - redisCatchStorage.updatePlatformRegister(parentPlatform); | |
| 94 | - redisCatchStorage.updatePlatformKeepalive(parentPlatform); | |
| 95 | - parentPlatformCatch.setParentPlatform(parentPlatform); | |
| 96 | - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); | |
| 97 | - } | |
| 92 | + ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId); | |
| 93 | + parentPlatformTmp.setStatus("注册".equals(action)); | |
| 94 | + redisCatchStorage.updatePlatformRegister(parentPlatformTmp); | |
| 95 | + redisCatchStorage.updatePlatformKeepalive(parentPlatformTmp); | |
| 96 | + parentPlatformCatch.setParentPlatform(parentPlatformTmp); | |
| 97 | + redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); | |
| 98 | 98 | storager.updateParentPlatformStatus(platformGBId, "注册".equals(action)); |
| 99 | + if ("注销".equals(action)) { | |
| 100 | + subscribeHolder.removeCatalogSubscribe(platformGBId); | |
| 101 | + subscribeHolder.removeMobilePositionSubscribe(platformGBId); | |
| 102 | + } | |
| 99 | 103 | |
| 100 | 104 | } |
| 101 | 105 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -9,9 +9,12 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 9 | 9 | import com.genersoft.iot.vmp.conf.MediaConfig; |
| 10 | 10 | import com.genersoft.iot.vmp.conf.UserSetup; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 12 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 14 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 13 | 15 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 14 | 16 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 17 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 15 | 18 | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| 16 | 19 | import com.genersoft.iot.vmp.service.*; |
| 17 | 20 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -81,7 +84,7 @@ public class ZLMHttpHookListener { |
| 81 | 84 | private UserSetup userSetup; |
| 82 | 85 | |
| 83 | 86 | @Autowired |
| 84 | - private MediaConfig mediaConfig; | |
| 87 | + private VideoStreamSessionManager sessionManager; | |
| 85 | 88 | |
| 86 | 89 | @Autowired |
| 87 | 90 | private ZLMRESTfulUtils zlmresTfulUtils; |
| ... | ... | @@ -207,15 +210,15 @@ public class ZLMHttpHookListener { |
| 207 | 210 | }else { |
| 208 | 211 | ret.put("enableMP4", userSetup.isRecordPushLive()); |
| 209 | 212 | } |
| 210 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(stream); | |
| 211 | - | |
| 212 | - // 录像回放时不进行录像下载 | |
| 213 | - if (streamInfo != null) { | |
| 214 | - ret.put("enableMP4", false); | |
| 215 | - }else { | |
| 216 | - ret.put("enableMP4", userSetup.isRecordPushLive()); | |
| 213 | + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, stream); | |
| 214 | + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | |
| 215 | + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | |
| 216 | + String channelId = ssrcTransactionForAll.get(0).getChannelId(); | |
| 217 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | |
| 218 | + if (deviceChannel != null) { | |
| 219 | + ret.put("enable_audio", deviceChannel.isHasAudio()); | |
| 220 | + } | |
| 217 | 221 | } |
| 218 | - | |
| 219 | 222 | return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); |
| 220 | 223 | } |
| 221 | 224 | |
| ... | ... | @@ -350,8 +353,12 @@ public class ZLMHttpHookListener { |
| 350 | 353 | redisCatchStorage.stopPlay(streamInfo); |
| 351 | 354 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 352 | 355 | }else{ |
| 353 | - streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 354 | - redisCatchStorage.stopPlayback(streamInfo); | |
| 356 | + streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 357 | + if (streamInfo != null) { | |
| 358 | + redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(), | |
| 359 | + streamInfo.getStream(), null); | |
| 360 | + } | |
| 361 | + | |
| 355 | 362 | } |
| 356 | 363 | }else { |
| 357 | 364 | if (!"rtp".equals(app)){ |
| ... | ... | @@ -443,18 +450,19 @@ public class ZLMHttpHookListener { |
| 443 | 450 | ret.put("close", false); |
| 444 | 451 | } else { |
| 445 | 452 | cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(), |
| 446 | - streamInfoForPlayCatch.getStream()); | |
| 453 | + streamInfoForPlayCatch.getStream(), null); | |
| 447 | 454 | redisCatchStorage.stopPlay(streamInfoForPlayCatch); |
| 448 | 455 | storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); |
| 449 | 456 | } |
| 450 | 457 | }else{ |
| 451 | - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 458 | + StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 452 | 459 | if (streamInfoForPlayBackCatch != null) { |
| 453 | 460 | cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), |
| 454 | - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream()); | |
| 455 | - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch); | |
| 461 | + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); | |
| 462 | + redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(), | |
| 463 | + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null); | |
| 456 | 464 | }else { |
| 457 | - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownloadByStreamId(streamId); | |
| 465 | + StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null); | |
| 458 | 466 | // 进行录像下载时无人观看不断流 |
| 459 | 467 | if (streamInfoForDownload != null) { |
| 460 | 468 | ret.put("close", false); |
| ... | ... | @@ -462,7 +470,7 @@ public class ZLMHttpHookListener { |
| 462 | 470 | } |
| 463 | 471 | } |
| 464 | 472 | MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); |
| 465 | - if (mediaServerItem != null && "-1".equals(mediaServerItem.getStreamNoneReaderDelayMS())) { | |
| 473 | + if (mediaServerItem != null && mediaServerItem.getStreamNoneReaderDelayMS() == -1) { | |
| 466 | 474 | ret.put("close", false); |
| 467 | 475 | } |
| 468 | 476 | return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
| ... | ... | @@ -45,12 +45,8 @@ public class ZLMRTPServerFactory { |
| 45 | 45 | |
| 46 | 46 | Map<String, Object> param = new HashMap<>(); |
| 47 | 47 | int result = -1; |
| 48 | - /** | |
| 49 | - * 不设置推流端口端则使用随机端口 | |
| 50 | - */ | |
| 51 | - if (StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){ | |
| 52 | - param.put("port", 0); | |
| 53 | - }else { | |
| 48 | + // 不设置推流端口端则使用随机端口 | |
| 49 | + if (!StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){ | |
| 54 | 50 | int newPort = getPortFromportRange(mediaServerItem); |
| 55 | 51 | param.put("port", newPort); |
| 56 | 52 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| ... | ... | @@ -2,10 +2,14 @@ package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; | |
| 5 | 7 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 6 | 8 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 7 | 9 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 10 | +import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; | |
| 8 | 11 | import com.genersoft.iot.vmp.service.bean.PlayBackCallback; |
| 12 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 9 | 13 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| 10 | 14 | import org.springframework.http.ResponseEntity; |
| 11 | 15 | import org.springframework.web.context.request.async.DeferredResult; |
| ... | ... | @@ -17,13 +21,17 @@ public interface IPlayService { |
| 17 | 21 | |
| 18 | 22 | void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid); |
| 19 | 23 | |
| 24 | + void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 25 | + ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, | |
| 26 | + InviteTimeOutCallback timeoutCallback, String uuid); | |
| 20 | 27 | PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback); |
| 21 | 28 | |
| 22 | 29 | MediaServerItem getNewMediaServerItem(Device device); |
| 23 | 30 | |
| 24 | - void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString); | |
| 31 | + void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString); | |
| 25 | 32 | |
| 26 | - DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback errorCallBack); | |
| 33 | + DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); | |
| 34 | + DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); | |
| 27 | 35 | |
| 28 | 36 | void zlmServerOffline(String mediaServerId); |
| 29 | 37 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
| ... | ... | @@ -7,9 +7,9 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 7 | 7 | import javax.sip.RequestEvent; |
| 8 | 8 | |
| 9 | 9 | public class PlayBackResult<T> { |
| 10 | - private int code; | |
| 11 | - private T data; | |
| 12 | - private MediaServerItem mediaServerItem; | |
| 10 | + private int code; | |
| 11 | + private T data; | |
| 12 | + private MediaServerItem mediaServerItem; | |
| 13 | 13 | private JSONObject response; |
| 14 | 14 | private SipSubscribe.EventResult event; |
| 15 | 15 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -512,7 +512,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 512 | 512 | param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)); |
| 513 | 513 | param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex)); |
| 514 | 514 | param.put("hook.timeoutSec","20"); |
| 515 | - param.put("general.streamNoneReaderDelayMS","-1".equals(mediaServerItem.getStreamNoneReaderDelayMS())?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() ); | |
| 515 | + param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS()==-1?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() ); | |
| 516 | 516 | // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 |
| 517 | 517 | // 置0关闭此特性(推流断开会导致立即断开播放器) |
| 518 | 518 | // 此参数不应大于播放器超时时间 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| ... | ... | @@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 16 | 16 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 17 | 17 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 18 | 18 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 19 | +import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; | |
| 19 | 20 | import com.genersoft.iot.vmp.service.bean.PlayBackCallback; |
| 20 | 21 | import com.genersoft.iot.vmp.service.bean.PlayBackResult; |
| 21 | 22 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -27,6 +28,7 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| 27 | 28 | import com.genersoft.iot.vmp.service.IMediaService; |
| 28 | 29 | import com.genersoft.iot.vmp.service.IPlayService; |
| 29 | 30 | import gov.nist.javax.sip.stack.SIPDialog; |
| 31 | +import jdk.nashorn.internal.ir.RuntimeNode; | |
| 30 | 32 | import org.slf4j.Logger; |
| 31 | 33 | import org.slf4j.LoggerFactory; |
| 32 | 34 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -36,6 +38,9 @@ import org.springframework.stereotype.Service; |
| 36 | 38 | import org.springframework.util.ResourceUtils; |
| 37 | 39 | import org.springframework.web.context.request.async.DeferredResult; |
| 38 | 40 | |
| 41 | +import javax.sip.header.CallIdHeader; | |
| 42 | +import javax.sip.header.Header; | |
| 43 | +import javax.sip.message.Request; | |
| 39 | 44 | import java.io.FileNotFoundException; |
| 40 | 45 | import java.util.*; |
| 41 | 46 | |
| ... | ... | @@ -79,6 +84,8 @@ public class PlayServiceImpl implements IPlayService { |
| 79 | 84 | private UserSetup userSetup; |
| 80 | 85 | |
| 81 | 86 | |
| 87 | + | |
| 88 | + | |
| 82 | 89 | @Override |
| 83 | 90 | public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, |
| 84 | 91 | ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| ... | ... | @@ -141,67 +148,7 @@ public class PlayServiceImpl implements IPlayService { |
| 141 | 148 | e.printStackTrace(); |
| 142 | 149 | } |
| 143 | 150 | }); |
| 144 | - if (streamInfo == null) { | |
| 145 | - String streamId = null; | |
| 146 | - if (mediaServerItem.isRtpEnable()) { | |
| 147 | - streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 148 | - } | |
| 149 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); | |
| 150 | - // 超时处理 | |
| 151 | - Timer timer = new Timer(); | |
| 152 | - timer.schedule(new TimerTask() { | |
| 153 | - @Override | |
| 154 | - public void run() { | |
| 155 | - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId)); | |
| 156 | - if (timeoutCallback != null) { | |
| 157 | - timeoutCallback.run(); | |
| 158 | - } | |
| 159 | - WVPResult wvpResult = new WVPResult(); | |
| 160 | - wvpResult.setCode(-1); | |
| 161 | - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); | |
| 162 | - if (dialog != null) { | |
| 163 | - wvpResult.setMsg("收流超时,请稍候重试"); | |
| 164 | - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 | |
| 165 | - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 166 | - }else { | |
| 167 | - wvpResult.setMsg("点播超时,请稍候重试"); | |
| 168 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 169 | - mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); | |
| 170 | - streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); | |
| 171 | - } | |
| 172 | - | |
| 173 | - msg.setData(wvpResult); | |
| 174 | - | |
| 175 | - // 回复之前所有的点播请求 | |
| 176 | - resultHolder.invokeAllResult(msg); | |
| 177 | - } | |
| 178 | - }, userSetup.getPlayTimeout()); | |
| 179 | - // 发送点播消息 | |
| 180 | - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { | |
| 181 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 182 | - timer.cancel(); | |
| 183 | - onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid); | |
| 184 | - if (hookEvent != null) { | |
| 185 | - hookEvent.response(mediaServerItem, response); | |
| 186 | - } | |
| 187 | - }, (event) -> { | |
| 188 | - timer.cancel(); | |
| 189 | - WVPResult wvpResult = new WVPResult(); | |
| 190 | - wvpResult.setCode(-1); | |
| 191 | - // 点播返回sip错误 | |
| 192 | - mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 193 | - // 释放ssrc | |
| 194 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 195 | - streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); | |
| 196 | - | |
| 197 | - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 198 | - msg.setData(wvpResult); | |
| 199 | - resultHolder.invokeAllResult(msg); | |
| 200 | - if (errorEvent != null) { | |
| 201 | - errorEvent.response(event); | |
| 202 | - } | |
| 203 | - }); | |
| 204 | - } else { | |
| 151 | + if (streamInfo != null) { | |
| 205 | 152 | String streamId = streamInfo.getStream(); |
| 206 | 153 | if (streamId == null) { |
| 207 | 154 | WVPResult wvpResult = new WVPResult(); |
| ... | ... | @@ -227,67 +174,109 @@ public class PlayServiceImpl implements IPlayService { |
| 227 | 174 | if (hookEvent != null) { |
| 228 | 175 | hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo))); |
| 229 | 176 | } |
| 230 | - } else { | |
| 231 | - // TODO 点播前是否重置状态 | |
| 177 | + }else { | |
| 232 | 178 | redisCatchStorage.stopPlay(streamInfo); |
| 233 | 179 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 234 | - String streamId2 = null; | |
| 235 | - if (mediaServerItem.isRtpEnable()) { | |
| 236 | - streamId2 = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 237 | - } | |
| 238 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2); | |
| 239 | - // 超时处理 | |
| 240 | - Timer timer = new Timer(); | |
| 241 | - timer.schedule(new TimerTask() { | |
| 242 | - @Override | |
| 243 | - public void run() { | |
| 244 | - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId)); | |
| 245 | - if (timeoutCallback != null) { | |
| 246 | - timeoutCallback.run(); | |
| 247 | - } | |
| 248 | - WVPResult wvpResult = new WVPResult(); | |
| 249 | - wvpResult.setCode(-1); | |
| 250 | - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); | |
| 251 | - if (dialog != null) { | |
| 252 | - wvpResult.setMsg("收流超时,请稍候重试"); | |
| 253 | - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 | |
| 254 | - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 255 | - }else { | |
| 256 | - wvpResult.setMsg("点播超时,请稍候重试"); | |
| 257 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 258 | - mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); | |
| 259 | - streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); | |
| 260 | - } | |
| 261 | - | |
| 262 | - msg.setData(wvpResult); | |
| 263 | - // 回复之前所有的点播请求 | |
| 264 | - resultHolder.invokeAllResult(msg); | |
| 265 | - } | |
| 266 | - }, userSetup.getPlayTimeout()); | |
| 267 | - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { | |
| 268 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 269 | - onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid); | |
| 270 | - }, (event) -> { | |
| 271 | - mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 272 | - // 释放ssrc | |
| 273 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 274 | - streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); | |
| 275 | - WVPResult wvpResult = new WVPResult(); | |
| 276 | - wvpResult.setCode(-1); | |
| 277 | - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 278 | - msg.setData(wvpResult); | |
| 279 | - resultHolder.invokeAllResult(msg); | |
| 280 | - }); | |
| 180 | + streamInfo = null; | |
| 281 | 181 | } |
| 282 | - } | |
| 283 | 182 | |
| 183 | + } | |
| 184 | + if (streamInfo == null) { | |
| 185 | + String streamId = null; | |
| 186 | + if (mediaServerItem.isRtpEnable()) { | |
| 187 | + streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 188 | + } | |
| 189 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); | |
| 190 | + play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{ | |
| 191 | + if (hookEvent != null) { | |
| 192 | + hookEvent.response(mediaServerItem, response); | |
| 193 | + } | |
| 194 | + }, event -> { | |
| 195 | + // sip error错误 | |
| 196 | + WVPResult wvpResult = new WVPResult(); | |
| 197 | + wvpResult.setCode(-1); | |
| 198 | + wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 199 | + msg.setData(wvpResult); | |
| 200 | + resultHolder.invokeAllResult(msg); | |
| 201 | + if (errorEvent != null) { | |
| 202 | + errorEvent.response(event); | |
| 203 | + } | |
| 204 | + }, (code, msgStr)->{ | |
| 205 | + // invite点播超时 | |
| 206 | + WVPResult wvpResult = new WVPResult(); | |
| 207 | + wvpResult.setCode(-1); | |
| 208 | + if (code == 0) { | |
| 209 | + wvpResult.setMsg("点播超时,请稍候重试"); | |
| 210 | + }else if (code == 1) { | |
| 211 | + wvpResult.setMsg("收流超时,请稍候重试"); | |
| 212 | + } | |
| 213 | + msg.setData(wvpResult); | |
| 214 | + // 回复之前所有的点播请求 | |
| 215 | + resultHolder.invokeAllResult(msg); | |
| 216 | + }, uuid); | |
| 217 | + } | |
| 284 | 218 | return playResult; |
| 285 | 219 | } |
| 286 | 220 | |
| 221 | + | |
| 222 | + | |
| 223 | + @Override | |
| 224 | + public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 225 | + ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, | |
| 226 | + InviteTimeOutCallback timeoutCallback, String uuid) { | |
| 227 | + | |
| 228 | + String streamId = null; | |
| 229 | + if (mediaServerItem.isRtpEnable()) { | |
| 230 | + streamId = String.format("%s_%s", device.getDeviceId(), channelId); | |
| 231 | + } | |
| 232 | + if (ssrcInfo == null) { | |
| 233 | + ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); | |
| 234 | + } | |
| 235 | + | |
| 236 | + // 超时处理 | |
| 237 | + Timer timer = new Timer(); | |
| 238 | + SSRCInfo finalSsrcInfo = ssrcInfo; | |
| 239 | + timer.schedule(new TimerTask() { | |
| 240 | + @Override | |
| 241 | + public void run() { | |
| 242 | + logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId)); | |
| 243 | + | |
| 244 | + SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); | |
| 245 | + if (dialog != null) { | |
| 246 | + timeoutCallback.run(1, "收流超时"); | |
| 247 | + // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 | |
| 248 | + cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null); | |
| 249 | + }else { | |
| 250 | + timeoutCallback.run(0, "点播超时"); | |
| 251 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); | |
| 252 | + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); | |
| 253 | + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); | |
| 254 | + } | |
| 255 | + } | |
| 256 | + }, userSetup.getPlayTimeout()); | |
| 257 | + | |
| 258 | + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { | |
| 259 | + logger.info("收到订阅消息: " + response.toJSONString()); | |
| 260 | + timer.cancel(); | |
| 261 | + // hook响应 | |
| 262 | + onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); | |
| 263 | + hookEvent.response(mediaServerItemInuse, response); | |
| 264 | + }, (event) -> { | |
| 265 | + timer.cancel(); | |
| 266 | + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); | |
| 267 | + // 释放ssrc | |
| 268 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); | |
| 269 | + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); | |
| 270 | + errorEvent.response(event); | |
| 271 | + }); | |
| 272 | + } | |
| 273 | + | |
| 287 | 274 | @Override |
| 288 | 275 | public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| 289 | 276 | RequestMessage msg = new RequestMessage(); |
| 290 | - msg.setId(uuid); | |
| 277 | + if (uuid != null) { | |
| 278 | + msg.setId(uuid); | |
| 279 | + } | |
| 291 | 280 | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| 292 | 281 | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| 293 | 282 | if (streamInfo != null) { |
| ... | ... | @@ -297,7 +286,6 @@ public class PlayServiceImpl implements IPlayService { |
| 297 | 286 | storager.startPlay(deviceId, channelId, streamInfo.getStream()); |
| 298 | 287 | } |
| 299 | 288 | redisCatchStorage.startPlay(streamInfo); |
| 300 | - msg.setData(JSON.toJSONString(streamInfo)); | |
| 301 | 289 | |
| 302 | 290 | WVPResult wvpResult = new WVPResult(); |
| 303 | 291 | wvpResult.setCode(0); |
| ... | ... | @@ -329,9 +317,24 @@ public class PlayServiceImpl implements IPlayService { |
| 329 | 317 | return mediaServerItem; |
| 330 | 318 | } |
| 331 | 319 | |
| 320 | + @Override | |
| 321 | + public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, | |
| 322 | + String endTime,InviteStreamCallback inviteStreamCallback, | |
| 323 | + PlayBackCallback callback) { | |
| 324 | + Device device = storager.queryVideoDevice(deviceId); | |
| 325 | + if (device == null) return null; | |
| 326 | + MediaServerItem newMediaServerItem = getNewMediaServerItem(device); | |
| 327 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); | |
| 328 | + | |
| 329 | + return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); | |
| 330 | + } | |
| 332 | 331 | |
| 333 | 332 | @Override |
| 334 | - public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback callback) { | |
| 333 | + public DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, | |
| 334 | + String deviceId, String channelId, String startTime, | |
| 335 | + String endTime, InviteStreamCallback infoCallBack, | |
| 336 | + PlayBackCallback playBackCallback) { | |
| 337 | + if (mediaServerItem == null || ssrcInfo == null) return null; | |
| 335 | 338 | String uuid = UUID.randomUUID().toString(); |
| 336 | 339 | String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; |
| 337 | 340 | DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L); |
| ... | ... | @@ -341,8 +344,6 @@ public class PlayServiceImpl implements IPlayService { |
| 341 | 344 | return result; |
| 342 | 345 | } |
| 343 | 346 | |
| 344 | - MediaServerItem newMediaServerItem = getNewMediaServerItem(device); | |
| 345 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); | |
| 346 | 347 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result); |
| 347 | 348 | RequestMessage msg = new RequestMessage(); |
| 348 | 349 | msg.setId(uuid); |
| ... | ... | @@ -356,63 +357,62 @@ public class PlayServiceImpl implements IPlayService { |
| 356 | 357 | logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| 357 | 358 | playBackResult.setCode(-1); |
| 358 | 359 | playBackResult.setData(msg); |
| 359 | - callback.call(playBackResult); | |
| 360 | + playBackCallback.call(playBackResult); | |
| 360 | 361 | SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); |
| 361 | 362 | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| 362 | 363 | if (dialog != null) { |
| 363 | 364 | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| 364 | - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 365 | + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); | |
| 365 | 366 | }else { |
| 366 | - mediaServerService.releaseSsrc(newMediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 367 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 367 | 368 | mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); |
| 368 | 369 | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| 369 | 370 | } |
| 370 | - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 371 | + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); | |
| 371 | 372 | // 回复之前所有的点播请求 |
| 372 | - callback.call(playBackResult); | |
| 373 | + playBackCallback.call(playBackResult); | |
| 373 | 374 | } |
| 374 | 375 | }, userSetup.getPlayTimeout()); |
| 375 | - cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> { | |
| 376 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 377 | - timer.cancel(); | |
| 378 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); | |
| 379 | - if (streamInfo == null) { | |
| 380 | - logger.warn("设备回放API调用失败!"); | |
| 381 | - msg.setData("设备回放API调用失败!"); | |
| 382 | - playBackResult.setCode(-1); | |
| 383 | - playBackResult.setData(msg); | |
| 384 | - callback.call(playBackResult); | |
| 385 | - return; | |
| 386 | - } | |
| 387 | - redisCatchStorage.startPlayback(streamInfo); | |
| 388 | - msg.setData(JSON.toJSONString(streamInfo)); | |
| 389 | - playBackResult.setCode(0); | |
| 390 | - playBackResult.setData(msg); | |
| 391 | - playBackResult.setMediaServerItem(mediaServerItem); | |
| 392 | - playBackResult.setResponse(response); | |
| 393 | - callback.call(playBackResult); | |
| 394 | - }, event -> { | |
| 395 | - timer.cancel(); | |
| 396 | - msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 397 | - playBackResult.setCode(-1); | |
| 398 | - playBackResult.setData(msg); | |
| 399 | - playBackResult.setEvent(event); | |
| 400 | - callback.call(playBackResult); | |
| 401 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 402 | - }); | |
| 376 | + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, | |
| 377 | + (InviteStreamInfo inviteStreamInfo) -> { | |
| 378 | + logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); | |
| 379 | + timer.cancel(); | |
| 380 | + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); | |
| 381 | + if (streamInfo == null) { | |
| 382 | + logger.warn("设备回放API调用失败!"); | |
| 383 | + msg.setData("设备回放API调用失败!"); | |
| 384 | + playBackResult.setCode(-1); | |
| 385 | + playBackResult.setData(msg); | |
| 386 | + playBackCallback.call(playBackResult); | |
| 387 | + return; | |
| 388 | + } | |
| 389 | + redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId()); | |
| 390 | + msg.setData(JSON.toJSONString(streamInfo)); | |
| 391 | + playBackResult.setCode(0); | |
| 392 | + playBackResult.setData(msg); | |
| 393 | + playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem()); | |
| 394 | + playBackResult.setResponse(inviteStreamInfo.getResponse()); | |
| 395 | + playBackCallback.call(playBackResult); | |
| 396 | + }, event -> { | |
| 397 | + timer.cancel(); | |
| 398 | + msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 399 | + playBackResult.setCode(-1); | |
| 400 | + playBackResult.setData(msg); | |
| 401 | + playBackResult.setEvent(event); | |
| 402 | + playBackCallback.call(playBackResult); | |
| 403 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 404 | + }); | |
| 403 | 405 | return result; |
| 404 | 406 | } |
| 405 | 407 | |
| 406 | - | |
| 407 | - | |
| 408 | 408 | @Override |
| 409 | - public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { | |
| 409 | + public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) { | |
| 410 | 410 | RequestMessage msg = new RequestMessage(); |
| 411 | 411 | msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId); |
| 412 | 412 | msg.setId(uuid); |
| 413 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); | |
| 413 | + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); | |
| 414 | 414 | if (streamInfo != null) { |
| 415 | - redisCatchStorage.startDownload(streamInfo); | |
| 415 | + redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId()); | |
| 416 | 416 | msg.setData(JSON.toJSONString(streamInfo)); |
| 417 | 417 | resultHolder.invokeResult(msg); |
| 418 | 418 | } else { |
| ... | ... | @@ -449,7 +449,8 @@ public class PlayServiceImpl implements IPlayService { |
| 449 | 449 | if (allSsrc.size() > 0) { |
| 450 | 450 | for (SsrcTransaction ssrcTransaction : allSsrc) { |
| 451 | 451 | if(ssrcTransaction.getMediaServerId().equals(mediaServerId)) { |
| 452 | - cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | |
| 452 | + cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), | |
| 453 | + ssrcTransaction.getStream(), null); | |
| 453 | 454 | } |
| 454 | 455 | } |
| 455 | 456 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| ... | ... | @@ -47,17 +47,15 @@ public interface IRedisCatchStorage { |
| 47 | 47 | |
| 48 | 48 | StreamInfo queryPlayByStreamId(String steamId); |
| 49 | 49 | |
| 50 | - StreamInfo queryPlaybackByStreamId(String steamId); | |
| 51 | - | |
| 52 | 50 | StreamInfo queryPlayByDevice(String deviceId, String channelId); |
| 53 | 51 | |
| 54 | 52 | Map<String, StreamInfo> queryPlayByDeviceId(String deviceId); |
| 55 | 53 | |
| 56 | - boolean startPlayback(StreamInfo stream); | |
| 54 | + boolean startPlayback(StreamInfo stream, String callId); | |
| 57 | 55 | |
| 58 | - boolean stopPlayback(StreamInfo streamInfo); | |
| 56 | + boolean stopPlayback(String deviceId, String channelId, String stream, String callId); | |
| 59 | 57 | |
| 60 | - StreamInfo queryPlaybackByDevice(String deviceId, String code); | |
| 58 | + StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId); | |
| 61 | 59 | |
| 62 | 60 | void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch); |
| 63 | 61 | |
| ... | ... | @@ -167,9 +165,9 @@ public interface IRedisCatchStorage { |
| 167 | 165 | * 开始下载录像时存入 |
| 168 | 166 | * @param streamInfo |
| 169 | 167 | */ |
| 170 | - boolean startDownload(StreamInfo streamInfo); | |
| 168 | + boolean startDownload(StreamInfo streamInfo, String callId); | |
| 171 | 169 | |
| 172 | - StreamInfo queryDownloadByStreamId(String streamId); | |
| 170 | + StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId); | |
| 173 | 171 | |
| 174 | 172 | /** |
| 175 | 173 | * 查找第三方系统留下的国标预设值 |
| ... | ... | @@ -204,18 +202,8 @@ public interface IRedisCatchStorage { |
| 204 | 202 | |
| 205 | 203 | void resetAllSN(); |
| 206 | 204 | |
| 207 | - void updateSubscribe(String key, SubscribeInfo subscribeInfo); | |
| 208 | - | |
| 209 | - SubscribeInfo getSubscribe(String key); | |
| 210 | - | |
| 211 | - void delSubscribe(String key); | |
| 212 | - | |
| 213 | 205 | MediaItem getStreamInfo(String app, String streamId, String mediaServerId); |
| 214 | 206 | |
| 215 | - List<SubscribeInfo> getAllSubscribe(); | |
| 216 | - | |
| 217 | - List<String> getAllSubscribePlatform(); | |
| 218 | - | |
| 219 | 207 | void addCpuInfo(double cpuInfo); |
| 220 | 208 | |
| 221 | 209 | void addMemInfo(double memInfo); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
| ... | ... | @@ -231,7 +231,6 @@ public interface DeviceChannelMapper { |
| 231 | 231 | " name as title,\n" + |
| 232 | 232 | " channelId as \"value\",\n" + |
| 233 | 233 | " channelId as \"key\",\n" + |
| 234 | - " channelId,\n" + | |
| 235 | 234 | " longitude,\n" + |
| 236 | 235 | " latitude\n" + |
| 237 | 236 | " from device_channel\n" + |
| ... | ... | @@ -248,4 +247,13 @@ public interface DeviceChannelMapper { |
| 248 | 247 | "<foreach collection='channels' item='item' open='(' separator=',' close=')' > #{item.channelId}</foreach>" + |
| 249 | 248 | " </script>"}) |
| 250 | 249 | int cleanChannelsNotInList(String deviceId, List<DeviceChannel> channels); |
| 250 | + | |
| 251 | + @Update(" update device_channel" + | |
| 252 | + " set subCount = (select *" + | |
| 253 | + " from (select count(0)" + | |
| 254 | + " from device_channel" + | |
| 255 | + " where deviceId = #{deviceId} and parentId = #{channelId}) as temp)" + | |
| 256 | + " where deviceId = #{deviceId} " + | |
| 257 | + " and channelId = #{channelId}") | |
| 258 | + int updateChannelSubCount(String deviceId, String channelId); | |
| 251 | 259 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
| ... | ... | @@ -55,7 +55,7 @@ public interface PlatformChannelMapper { |
| 55 | 55 | int cleanChannelForGB(String platformId); |
| 56 | 56 | |
| 57 | 57 | @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}' and pgc.platformId='${platformId}'") |
| 58 | - DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); | |
| 58 | + List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId); | |
| 59 | 59 | |
| 60 | 60 | @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " + |
| 61 | 61 | " from device_channel dc left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId " + |
| ... | ... | @@ -67,7 +67,7 @@ public interface PlatformChannelMapper { |
| 67 | 67 | " left join device_channel dc on dc.id = pgc.deviceChannelId\n" + |
| 68 | 68 | " left join device d on dc.deviceId = d.deviceId\n" + |
| 69 | 69 | "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}") |
| 70 | - Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); | |
| 70 | + List<Device> queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); | |
| 71 | 71 | |
| 72 | 72 | @Delete("<script> "+ |
| 73 | 73 | "DELETE FROM platform_gb_channel WHERE catalogId=#{id}" + | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -134,13 +134,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | 136 | @Override |
| 137 | - public StreamInfo queryPlaybackByStreamId(String streamId) { | |
| 138 | - List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, userSetup.getServerId(), streamId)); | |
| 139 | - if (playLeys == null || playLeys.size() == 0) return null; | |
| 140 | - return (StreamInfo)redis.get(playLeys.get(0).toString()); | |
| 141 | - } | |
| 142 | - | |
| 143 | - @Override | |
| 144 | 137 | public StreamInfo queryPlayByDevice(String deviceId, String channelId) { |
| 145 | 138 | List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, |
| 146 | 139 | userSetup.getServerId(), |
| ... | ... | @@ -166,49 +159,67 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 166 | 159 | |
| 167 | 160 | |
| 168 | 161 | @Override |
| 169 | - public boolean startPlayback(StreamInfo stream) { | |
| 170 | - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 171 | - userSetup.getServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()), stream); | |
| 162 | + public boolean startPlayback(StreamInfo stream, String callId) { | |
| 163 | + return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 164 | + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); | |
| 172 | 165 | } |
| 173 | 166 | |
| 174 | 167 | @Override |
| 175 | - public boolean startDownload(StreamInfo streamInfo) { | |
| 176 | - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(), | |
| 177 | - streamInfo.getStream(), streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo); | |
| 168 | + public boolean startDownload(StreamInfo stream, String callId) { | |
| 169 | + return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, | |
| 170 | + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); | |
| 178 | 171 | } |
| 179 | 172 | |
| 180 | 173 | @Override |
| 181 | - public boolean stopPlayback(StreamInfo streamInfo) { | |
| 182 | - if (streamInfo == null) return false; | |
| 183 | - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 174 | + public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) { | |
| 175 | + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); | |
| 184 | 176 | if (deviceChannel != null) { |
| 185 | 177 | deviceChannel.setStreamId(null); |
| 186 | - deviceChannel.setDeviceId(streamInfo.getDeviceID()); | |
| 178 | + deviceChannel.setDeviceId(deviceId); | |
| 187 | 179 | deviceChannelMapper.update(deviceChannel); |
| 188 | 180 | } |
| 189 | - return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 181 | + if (deviceId == null) deviceId = "*"; | |
| 182 | + if (channelId == null) channelId = "*"; | |
| 183 | + if (stream == null) stream = "*"; | |
| 184 | + if (callId == null) callId = "*"; | |
| 185 | + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 190 | 186 | userSetup.getServerId(), |
| 191 | - streamInfo.getStream(), | |
| 192 | - streamInfo.getDeviceID(), | |
| 193 | - streamInfo.getChannelId())); | |
| 187 | + deviceId, | |
| 188 | + channelId, | |
| 189 | + stream, | |
| 190 | + callId | |
| 191 | + ); | |
| 192 | + List<Object> scan = redis.scan(key); | |
| 193 | + if (scan.size() > 0) { | |
| 194 | + for (Object keyObj : scan) { | |
| 195 | + redis.del((String) keyObj); | |
| 196 | + } | |
| 197 | + } | |
| 198 | + return true; | |
| 194 | 199 | } |
| 195 | 200 | |
| 196 | 201 | @Override |
| 197 | - public StreamInfo queryPlaybackByDevice(String deviceId, String code) { | |
| 198 | - // String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 199 | - // deviceId, | |
| 200 | - // code); | |
| 201 | - List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 202 | + public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) { | |
| 203 | + if (stream == null && callId == null) { | |
| 204 | + return null; | |
| 205 | + } | |
| 206 | + if (deviceId == null) deviceId = "*"; | |
| 207 | + if (channelId == null) channelId = "*"; | |
| 208 | + if (stream == null) stream = "*"; | |
| 209 | + if (callId == null) callId = "*"; | |
| 210 | + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 202 | 211 | userSetup.getServerId(), |
| 203 | 212 | deviceId, |
| 204 | - code)); | |
| 205 | - if (playLeys == null || playLeys.size() == 0) { | |
| 206 | - playLeys = redis.scan(String.format("%S_%s_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 207 | - userSetup.getServerId(), | |
| 208 | - deviceId)); | |
| 213 | + channelId, | |
| 214 | + stream, | |
| 215 | + callId | |
| 216 | + ); | |
| 217 | + List<Object> streamInfoScan = redis.scan(key); | |
| 218 | + if (streamInfoScan.size() > 0) { | |
| 219 | + return (StreamInfo) redis.get((String) streamInfoScan.get(0)); | |
| 220 | + }else { | |
| 221 | + return null; | |
| 209 | 222 | } |
| 210 | - if (playLeys == null || playLeys.size() == 0) return null; | |
| 211 | - return (StreamInfo)redis.get(playLeys.get(0).toString()); | |
| 212 | 223 | } |
| 213 | 224 | |
| 214 | 225 | @Override |
| ... | ... | @@ -361,7 +372,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 361 | 372 | } |
| 362 | 373 | } |
| 363 | 374 | |
| 364 | - List<Object> playBackers = redis.scan(String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 375 | + List<Object> playBackers = redis.scan(String.format("%S_%s_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX, | |
| 365 | 376 | userSetup.getServerId(), |
| 366 | 377 | deviceId)); |
| 367 | 378 | if (playBackers.size() > 0) { |
| ... | ... | @@ -426,10 +437,27 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 426 | 437 | } |
| 427 | 438 | |
| 428 | 439 | @Override |
| 429 | - public StreamInfo queryDownloadByStreamId(String streamId) { | |
| 430 | - List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(), streamId)); | |
| 431 | - if (playLeys == null || playLeys.size() == 0) return null; | |
| 432 | - return (StreamInfo)redis.get(playLeys.get(0).toString()); | |
| 440 | + public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) { | |
| 441 | + if (stream == null && callId == null) { | |
| 442 | + return null; | |
| 443 | + } | |
| 444 | + if (deviceId == null) deviceId = "*"; | |
| 445 | + if (channelId == null) channelId = "*"; | |
| 446 | + if (stream == null) stream = "*"; | |
| 447 | + if (callId == null) callId = "*"; | |
| 448 | + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, | |
| 449 | + userSetup.getServerId(), | |
| 450 | + deviceId, | |
| 451 | + channelId, | |
| 452 | + stream, | |
| 453 | + callId | |
| 454 | + ); | |
| 455 | + List<Object> streamInfoScan = redis.scan(key); | |
| 456 | + if (streamInfoScan.size() > 0) { | |
| 457 | + return (StreamInfo) redis.get((String) streamInfoScan.get(0)); | |
| 458 | + }else { | |
| 459 | + return null; | |
| 460 | + } | |
| 433 | 461 | } |
| 434 | 462 | |
| 435 | 463 | @Override |
| ... | ... | @@ -491,21 +519,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 491 | 519 | } |
| 492 | 520 | |
| 493 | 521 | @Override |
| 494 | - public void updateSubscribe(String key, SubscribeInfo subscribeInfo) { | |
| 495 | - redis.set(key, subscribeInfo, subscribeInfo.getExpires()); | |
| 496 | - } | |
| 497 | - | |
| 498 | - @Override | |
| 499 | - public SubscribeInfo getSubscribe(String key) { | |
| 500 | - return (SubscribeInfo)redis.get(key); | |
| 501 | - } | |
| 502 | - | |
| 503 | - @Override | |
| 504 | - public void delSubscribe(String key) { | |
| 505 | - redis.del(key); | |
| 506 | - } | |
| 507 | - | |
| 508 | - @Override | |
| 509 | 522 | public List<GPSMsgInfo> getAllGpsMsgInfo() { |
| 510 | 523 | String scanKey = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_*"; |
| 511 | 524 | List<GPSMsgInfo> result = new ArrayList<>(); |
| ... | ... | @@ -536,32 +549,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 536 | 549 | } |
| 537 | 550 | |
| 538 | 551 | @Override |
| 539 | - public List<SubscribeInfo> getAllSubscribe() { | |
| 540 | - String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*"; | |
| 541 | - List<SubscribeInfo> result = new ArrayList<>(); | |
| 542 | - List<Object> keys = redis.scan(scanKey); | |
| 543 | - for (int i = 0; i < keys.size(); i++) { | |
| 544 | - String key = (String) keys.get(i); | |
| 545 | - SubscribeInfo subscribeInfo = (SubscribeInfo) redis.get(key); | |
| 546 | - result.add(subscribeInfo); | |
| 547 | - } | |
| 548 | - return result; | |
| 549 | - } | |
| 550 | - | |
| 551 | - @Override | |
| 552 | - public List<String> getAllSubscribePlatform() { | |
| 553 | - String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*"; | |
| 554 | - List<String> result = new ArrayList<>(); | |
| 555 | - List<Object> keys = redis.scan(scanKey); | |
| 556 | - for (int i = 0; i < keys.size(); i++) { | |
| 557 | - String key = (String) keys.get(i); | |
| 558 | - String platformId = key.substring(scanKey.length() - 1); | |
| 559 | - result.add(platformId); | |
| 560 | - } | |
| 561 | - return result; | |
| 562 | - } | |
| 563 | - | |
| 564 | - @Override | |
| 565 | 552 | public void addCpuInfo(double cpuInfo) { |
| 566 | 553 | String key = VideoManagerConstants.SYSTEM_INFO_CPU_PREFIX + userSetup.getServerId(); |
| 567 | 554 | SystemInfoDto<Double> systemInfoDto = new SystemInfoDto<>(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
| ... | ... | @@ -42,7 +42,7 @@ import java.util.*; |
| 42 | 42 | @Component |
| 43 | 43 | public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 44 | 44 | |
| 45 | - private Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class); | |
| 45 | + private final Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class); | |
| 46 | 46 | |
| 47 | 47 | @Autowired |
| 48 | 48 | EventPublisher eventPublisher; |
| ... | ... | @@ -171,6 +171,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 171 | 171 | }else { |
| 172 | 172 | deviceChannelMapper.update(channel); |
| 173 | 173 | } |
| 174 | + deviceChannelMapper.updateChannelSubCount(deviceId,channel.getParentId()); | |
| 174 | 175 | } |
| 175 | 176 | |
| 176 | 177 | @Override |
| ... | ... | @@ -542,7 +543,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 542 | 543 | if (parentPlatformCatch == null) { // serverGBId 已变化 |
| 543 | 544 | ParentPlatform parentPlatById = platformMapper.getParentPlatById(parentPlatform.getId()); |
| 544 | 545 | // 使用旧的查出缓存ID |
| 545 | - parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatById.getServerGBId()); | |
| 546 | + parentPlatformCatch = new ParentPlatformCatch(); | |
| 546 | 547 | parentPlatformCatch.setId(parentPlatform.getServerGBId()); |
| 547 | 548 | redisCatchStorage.delPlatformCatchInfo(parentPlatById.getServerGBId()); |
| 548 | 549 | } |
| ... | ... | @@ -662,8 +663,16 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 662 | 663 | |
| 663 | 664 | @Override |
| 664 | 665 | public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) { |
| 665 | - DeviceChannel channel = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId); | |
| 666 | - return channel; | |
| 666 | + List<DeviceChannel> channels = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId); | |
| 667 | + if (channels.size() > 1) { | |
| 668 | + // 出现长度大于0的时候肯定是国标通道的ID重复了 | |
| 669 | + logger.warn("国标ID存在重复:{}", channelId); | |
| 670 | + } | |
| 671 | + if (channels.size() == 0) { | |
| 672 | + return null; | |
| 673 | + }else { | |
| 674 | + return channels.get(0); | |
| 675 | + } | |
| 667 | 676 | } |
| 668 | 677 | |
| 669 | 678 | @Override |
| ... | ... | @@ -680,8 +689,18 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 680 | 689 | |
| 681 | 690 | @Override |
| 682 | 691 | public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) { |
| 683 | - Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | |
| 684 | - return device; | |
| 692 | + List<Device> devices = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | |
| 693 | + if (devices.size() > 1) { | |
| 694 | + // 出现长度大于0的时候肯定是国标通道的ID重复了 | |
| 695 | + logger.warn("国标ID存在重复:{}", channelId); | |
| 696 | + } | |
| 697 | + if (devices.size() == 0) { | |
| 698 | + return null; | |
| 699 | + }else { | |
| 700 | + return devices.get(0); | |
| 701 | + } | |
| 702 | + | |
| 703 | + | |
| 685 | 704 | } |
| 686 | 705 | |
| 687 | 706 | /** |
| ... | ... | @@ -1083,6 +1102,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 1083 | 1102 | |
| 1084 | 1103 | @Override |
| 1085 | 1104 | public List<ParentPlatform> queryPlatFormListForStreamWithGBId(String app, String stream, List<String> platforms) { |
| 1105 | + if (platforms == null || platforms.size() == 0) { | |
| 1106 | + return new ArrayList<>(); | |
| 1107 | + } | |
| 1086 | 1108 | return platformGbStreamMapper.queryPlatFormListForGBWithGBId(app, stream, platforms); |
| 1087 | 1109 | } |
| 1088 | 1110 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.UserSetup; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; | |
| 10 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 11 | 12 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 12 | 13 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| ... | ... | @@ -50,6 +51,9 @@ public class PlatformController { |
| 50 | 51 | private IRedisCatchStorage redisCatchStorage; |
| 51 | 52 | |
| 52 | 53 | @Autowired |
| 54 | + private SubscribeHolder subscribeHolder; | |
| 55 | + | |
| 56 | + @Autowired | |
| 53 | 57 | private ISIPCommanderForPlatform commanderForPlatform; |
| 54 | 58 | |
| 55 | 59 | @Autowired |
| ... | ... | @@ -110,10 +114,14 @@ public class PlatformController { |
| 110 | 114 | }) |
| 111 | 115 | public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count) { |
| 112 | 116 | |
| 113 | -// if (logger.isDebugEnabled()) { | |
| 114 | -// logger.debug("查询所有上级设备API调用"); | |
| 115 | -// } | |
| 116 | - return storager.queryParentPlatformList(page, count); | |
| 117 | + PageInfo<ParentPlatform> parentPlatformPageInfo = storager.queryParentPlatformList(page, count); | |
| 118 | + if (parentPlatformPageInfo.getList().size() > 0) { | |
| 119 | + for (ParentPlatform platform : parentPlatformPageInfo.getList()) { | |
| 120 | + platform.setGpsSubscribe(subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()) != null); | |
| 121 | + platform.setCatalogSubscribe(subscribeHolder.getCatalogSubscribe(platform.getServerGBId()) != null); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return parentPlatformPageInfo; | |
| 117 | 125 | } |
| 118 | 126 | |
| 119 | 127 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| ... | ... | @@ -120,7 +120,7 @@ public class PlayController { |
| 120 | 120 | storager.stopPlay(deviceId, channelId); |
| 121 | 121 | return result; |
| 122 | 122 | } |
| 123 | - cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), (event) -> { | |
| 123 | + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, (event) -> { | |
| 124 | 124 | redisCatchStorage.stopPlay(streamInfo); |
| 125 | 125 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 126 | 126 | RequestMessage msg = new RequestMessage(); |
| ... | ... | @@ -174,7 +174,7 @@ public class PlayController { |
| 174 | 174 | public ResponseEntity<String> playConvert(@PathVariable String streamId) { |
| 175 | 175 | StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
| 176 | 176 | if (streamInfo == null) { |
| 177 | - streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 177 | + streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 178 | 178 | } |
| 179 | 179 | if (streamInfo == null) { |
| 180 | 180 | logger.warn("视频转码API调用失败!, 视频流已经停止!"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.gb28181.playback; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 6 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| ... | ... | @@ -93,11 +94,6 @@ public class DownloadController { |
| 93 | 94 | } |
| 94 | 95 | resultHolder.put(key, uuid, result); |
| 95 | 96 | Device device = storager.queryVideoDevice(deviceId); |
| 96 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); | |
| 97 | - if (streamInfo != null) { | |
| 98 | - // 停止之前的下载 | |
| 99 | - cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream()); | |
| 100 | - } | |
| 101 | 97 | |
| 102 | 98 | MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); |
| 103 | 99 | if (newMediaServerItem == null) { |
| ... | ... | @@ -112,9 +108,9 @@ public class DownloadController { |
| 112 | 108 | |
| 113 | 109 | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); |
| 114 | 110 | |
| 115 | - cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> { | |
| 116 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 117 | - playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid); | |
| 111 | + cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> { | |
| 112 | + logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); | |
| 113 | + playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid); | |
| 118 | 114 | }, event -> { |
| 119 | 115 | RequestMessage msg = new RequestMessage(); |
| 120 | 116 | msg.setId(uuid); |
| ... | ... | @@ -135,7 +131,7 @@ public class DownloadController { |
| 135 | 131 | @GetMapping("/stop/{deviceId}/{channelId}/{stream}") |
| 136 | 132 | public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { |
| 137 | 133 | |
| 138 | - cmder.streamByeCmd(deviceId, channelId, stream); | |
| 134 | + cmder.streamByeCmd(deviceId, channelId, stream, null); | |
| 139 | 135 | |
| 140 | 136 | if (logger.isDebugEnabled()) { |
| 141 | 137 | logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId)); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
| ... | ... | @@ -77,7 +77,7 @@ public class PlaybackController { |
| 77 | 77 | logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | - DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, wvpResult->{ | |
| 80 | + DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{ | |
| 81 | 81 | resultHolder.invokeResult(wvpResult.getData()); |
| 82 | 82 | }); |
| 83 | 83 | |
| ... | ... | @@ -96,7 +96,7 @@ public class PlaybackController { |
| 96 | 96 | @PathVariable String channelId, |
| 97 | 97 | @PathVariable String stream) { |
| 98 | 98 | |
| 99 | - cmder.streamByeCmd(deviceId, channelId, stream); | |
| 99 | + cmder.streamByeCmd(deviceId, channelId, stream, null); | |
| 100 | 100 | |
| 101 | 101 | if (logger.isDebugEnabled()) { |
| 102 | 102 | logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId)); |
| ... | ... | @@ -124,7 +124,7 @@ public class PlaybackController { |
| 124 | 124 | public ResponseEntity<String> playPause(@PathVariable String streamId) { |
| 125 | 125 | logger.info("playPause: "+streamId); |
| 126 | 126 | JSONObject json = new JSONObject(); |
| 127 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 127 | + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 128 | 128 | if (null == streamInfo) { |
| 129 | 129 | json.put("msg", "streamId不存在"); |
| 130 | 130 | logger.warn("streamId不存在!"); |
| ... | ... | @@ -144,7 +144,7 @@ public class PlaybackController { |
| 144 | 144 | public ResponseEntity<String> playResume(@PathVariable String streamId) { |
| 145 | 145 | logger.info("playResume: "+streamId); |
| 146 | 146 | JSONObject json = new JSONObject(); |
| 147 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 147 | + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 148 | 148 | if (null == streamInfo) { |
| 149 | 149 | json.put("msg", "streamId不存在"); |
| 150 | 150 | logger.warn("streamId不存在!"); |
| ... | ... | @@ -165,7 +165,7 @@ public class PlaybackController { |
| 165 | 165 | public ResponseEntity<String> playSeek(@PathVariable String streamId, @PathVariable long seekTime) { |
| 166 | 166 | logger.info("playSeek: "+streamId+", "+seekTime); |
| 167 | 167 | JSONObject json = new JSONObject(); |
| 168 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 168 | + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 169 | 169 | if (null == streamInfo) { |
| 170 | 170 | json.put("msg", "streamId不存在"); |
| 171 | 171 | logger.warn("streamId不存在!"); |
| ... | ... | @@ -186,7 +186,7 @@ public class PlaybackController { |
| 186 | 186 | public ResponseEntity<String> playSpeed(@PathVariable String streamId, @PathVariable Double speed) { |
| 187 | 187 | logger.info("playSpeed: "+streamId+", "+speed); |
| 188 | 188 | JSONObject json = new JSONObject(); |
| 189 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); | |
| 189 | + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); | |
| 190 | 190 | if (null == streamInfo) { |
| 191 | 191 | json.put("msg", "streamId不存在"); |
| 192 | 192 | logger.warn("streamId不存在!"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
| ... | ... | @@ -177,7 +177,7 @@ public class ApiStreamController { |
| 177 | 177 | result.put("error","未找到流信息"); |
| 178 | 178 | return result; |
| 179 | 179 | } |
| 180 | - cmder.streamByeCmd(serial, code, streamInfo.getStream()); | |
| 180 | + cmder.streamByeCmd(serial, code, streamInfo.getStream(), null); | |
| 181 | 181 | redisCatchStorage.stopPlay(streamInfo); |
| 182 | 182 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 183 | 183 | return null; | ... | ... |
web_src/src/components/ParentPlatformList.vue
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | </div> |
| 14 | 14 | <!--设备列表--> |
| 15 | 15 | <el-table :data="platformList" border style="width: 100%" :height="winHeight"> |
| 16 | - <el-table-column prop="name" label="名称" width="240" align="center"></el-table-column> | |
| 16 | + <el-table-column prop="name" label="名称" align="center"></el-table-column> | |
| 17 | 17 | <el-table-column prop="serverGBId" label="平台编号" width="180" align="center"></el-table-column> |
| 18 | 18 | <el-table-column label="是否启用" width="120" align="center"> |
| 19 | 19 | <template slot-scope="scope"> |
| ... | ... | @@ -38,9 +38,19 @@ |
| 38 | 38 | </div> |
| 39 | 39 | </template> |
| 40 | 40 | </el-table-column> |
| 41 | - <el-table-column prop="deviceGBId" label="设备国标编号" width="240" align="center"></el-table-column> | |
| 41 | + <el-table-column prop="deviceGBId" label="设备国标编号" width="200" align="center"></el-table-column> | |
| 42 | 42 | <el-table-column prop="transport" label="信令传输模式" width="120" align="center"></el-table-column> |
| 43 | - <el-table-column prop="channelCount" label="通道数" align="center"></el-table-column> | |
| 43 | + <el-table-column prop="channelCount" label="通道数" width="120" align="center"></el-table-column> | |
| 44 | + <el-table-column label="订阅信息" width="240" align="center" fixed="right"> | |
| 45 | + <template slot-scope="scope"> | |
| 46 | + <i v-if="scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-on iconfont icon-gbaojings" ></i> | |
| 47 | + <i v-if="!scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-off iconfont icon-gbaojings" ></i> | |
| 48 | + <i v-if="scope.row.catalogSubscribe" title="目录订阅" class="subscribe-on iconfont icon-gjichus" ></i> | |
| 49 | + <i v-if="!scope.row.catalogSubscribe" title="目录订阅" class="subscribe-off iconfont icon-gjichus" ></i> | |
| 50 | + <i v-if="scope.row.gpsSubscribe" title="位置订阅" class="subscribe-on iconfont icon-gxunjians" ></i> | |
| 51 | + <i v-if="!scope.row.gpsSubscribe" title="位置订阅" class="subscribe-off iconfont icon-gxunjians" ></i> | |
| 52 | + </template> | |
| 53 | + </el-table-column> | |
| 44 | 54 | |
| 45 | 55 | <el-table-column label="操作" width="300" align="center" fixed="right"> |
| 46 | 56 | <template slot-scope="scope"> |
| ... | ... | @@ -169,3 +179,13 @@ export default { |
| 169 | 179 | } |
| 170 | 180 | }; |
| 171 | 181 | </script> |
| 182 | +<style> | |
| 183 | +.subscribe-on{ | |
| 184 | + color: #409EFF; | |
| 185 | + font-size: 1.3rem; | |
| 186 | +} | |
| 187 | +.subscribe-off{ | |
| 188 | + color: #afafb3; | |
| 189 | + font-size: 1.3rem; | |
| 190 | +} | |
| 191 | +</style> | ... | ... |
web_src/src/components/dialog/StreamProxyEdit.vue
| ... | ... | @@ -193,6 +193,7 @@ export default { |
| 193 | 193 | this.mediaServer.getOnlineMediaServerList((data)=>{ |
| 194 | 194 | this.mediaServerList = data.data; |
| 195 | 195 | this.proxyParam.mediaServerId = this.mediaServerList[0].id |
| 196 | + this.mediaServerIdChange() | |
| 196 | 197 | }) |
| 197 | 198 | }, |
| 198 | 199 | mediaServerIdChange:function (){ |
| ... | ... | @@ -206,6 +207,7 @@ export default { |
| 206 | 207 | } |
| 207 | 208 | }).then(function (res) { |
| 208 | 209 | that.ffmpegCmdList = res.data.data; |
| 210 | + that.proxyParam.ffmpeg_cmd_key = Object.keys(res.data.data)[0]; | |
| 209 | 211 | }).catch(function (error) { |
| 210 | 212 | console.log(error); |
| 211 | 213 | }); | ... | ... |
web_src/src/components/dialog/chooseChannelForGb.vue
| 1 | 1 | <template> |
| 2 | 2 | <div id="chooseChannelForGb" > |
| 3 | 3 | <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;"> |
| 4 | - <span v-if="catalogId == null">{{catalogName}}的直播流</span> | |
| 5 | - <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span> | |
| 4 | + <span v-if="catalogId == null">{{catalogName}}的国标通道</span> | |
| 5 | + <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的国标通道</span> | |
| 6 | 6 | </div> |
| 7 | 7 | <div style="background-color: #FFFFFF; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| 8 | 8 | 搜索: <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" prefix-icon="el-icon-search" v-model="searchSrt" clearable> </el-input> | ... | ... |
web_src/src/components/dialog/chooseChannelForStream.vue
| 1 | 1 | <template> |
| 2 | 2 | <div id="chooseChannelFoStream" > |
| 3 | 3 | <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;"> |
| 4 | - <span v-if="catalogId == null">{{catalogName}}的直播流</span> | |
| 5 | - <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span> | |
| 4 | + <span v-if="catalogId == null">{{catalogName}}的直播通道</span> | |
| 5 | + <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播通道</span> | |
| 6 | 6 | </div> |
| 7 | 7 | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| 8 | 8 | ... | ... |
web_src/static/css/iconfont.css
| 1 | 1 | @font-face { |
| 2 | 2 | font-family: "iconfont"; /* Project id 1291092 */ |
| 3 | - src: url('iconfont.woff2?t=1644809302709') format('woff2'), | |
| 4 | - url('iconfont.woff?t=1644809302709') format('woff'), | |
| 5 | - url('iconfont.ttf?t=1644809302709') format('truetype'); | |
| 3 | + src: url('iconfont.woff2?t=1647245982270') format('woff2'), | |
| 4 | + url('iconfont.woff?t=1647245982270') format('woff'), | |
| 5 | + url('iconfont.ttf?t=1647245982270') format('truetype'); | |
| 6 | 6 | } |
| 7 | 7 | |
| 8 | 8 | .iconfont { |
| ... | ... | @@ -13,6 +13,22 @@ |
| 13 | 13 | -moz-osx-font-smoothing: grayscale; |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | +.icon-xitongxinxi:before { | |
| 17 | + content: "\e7d6"; | |
| 18 | +} | |
| 19 | + | |
| 20 | +.icon-gbaojings:before { | |
| 21 | + content: "\e7d7"; | |
| 22 | +} | |
| 23 | + | |
| 24 | +.icon-gjichus:before { | |
| 25 | + content: "\e7d8"; | |
| 26 | +} | |
| 27 | + | |
| 28 | +.icon-gxunjians:before { | |
| 29 | + content: "\e7d9"; | |
| 30 | +} | |
| 31 | + | |
| 16 | 32 | .icon-ziyuan:before { |
| 17 | 33 | content: "\e7d5"; |
| 18 | 34 | } | ... | ... |
web_src/static/css/iconfont.woff2
No preview for this file type