Commit 2eb1ca2d94a09c2d3ced69de28de72d2d6d77d8e
1 parent
6a4cdc36
国标录像支持多端同时播放
Showing
33 changed files
with
282 additions
and
230 deletions
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
| ... | ... | @@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSONArray; |
| 5 | 5 | public class StreamInfo { |
| 6 | 6 | |
| 7 | 7 | private String app; |
| 8 | - private String streamId; | |
| 8 | + private String stream; | |
| 9 | 9 | private String deviceID; |
| 10 | 10 | private String channelId; |
| 11 | 11 | private String flv; |
| ... | ... | @@ -153,12 +153,12 @@ public class StreamInfo { |
| 153 | 153 | this.ws_ts = ws_ts; |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | - public String getStreamId() { | |
| 157 | - return streamId; | |
| 156 | + public String getStream() { | |
| 157 | + return stream; | |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | - public void setStreamId(String streamId) { | |
| 161 | - this.streamId = streamId; | |
| 160 | + public void setStream(String stream) { | |
| 161 | + this.stream = stream; | |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | public String getRtc() { | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -29,6 +29,7 @@ public class VideoManagerConstants { |
| 29 | 29 | // 此处多了一个_,暂不修改 |
| 30 | 30 | public static final String PLAYER_PREFIX = "VMP_PLAYER_"; |
| 31 | 31 | public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_"; |
| 32 | + public static final String PLAY_INFO_PREFIX = "VMP_PLAY_INFO_"; | |
| 32 | 33 | |
| 33 | 34 | public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_"; |
| 34 | 35 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
| ... | ... | @@ -4,11 +4,12 @@ public class SsrcTransaction { |
| 4 | 4 | |
| 5 | 5 | private String deviceId; |
| 6 | 6 | private String channelId; |
| 7 | - private String ssrc; | |
| 8 | - private String streamId; | |
| 7 | + private String callId; | |
| 8 | + private String stream; | |
| 9 | 9 | private byte[] transaction; |
| 10 | 10 | private byte[] dialog; |
| 11 | 11 | private String mediaServerId; |
| 12 | + private String ssrc; | |
| 12 | 13 | |
| 13 | 14 | public String getDeviceId() { |
| 14 | 15 | return deviceId; |
| ... | ... | @@ -26,20 +27,20 @@ public class SsrcTransaction { |
| 26 | 27 | this.channelId = channelId; |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | - public String getSsrc() { | |
| 30 | - return ssrc; | |
| 30 | + public String getCallId() { | |
| 31 | + return callId; | |
| 31 | 32 | } |
| 32 | 33 | |
| 33 | - public void setSsrc(String ssrc) { | |
| 34 | - this.ssrc = ssrc; | |
| 34 | + public void setCallId(String callId) { | |
| 35 | + this.callId = callId; | |
| 35 | 36 | } |
| 36 | 37 | |
| 37 | - public String getStreamId() { | |
| 38 | - return streamId; | |
| 38 | + public String getStream() { | |
| 39 | + return stream; | |
| 39 | 40 | } |
| 40 | 41 | |
| 41 | - public void setStreamId(String streamId) { | |
| 42 | - this.streamId = streamId; | |
| 42 | + public void setStream(String stream) { | |
| 43 | + this.stream = stream; | |
| 43 | 44 | } |
| 44 | 45 | |
| 45 | 46 | public byte[] getTransaction() { |
| ... | ... | @@ -65,4 +66,12 @@ public class SsrcTransaction { |
| 65 | 66 | public void setMediaServerId(String mediaServerId) { |
| 66 | 67 | this.mediaServerId = mediaServerId; |
| 67 | 68 | } |
| 69 | + | |
| 70 | + public String getSsrc() { | |
| 71 | + return ssrc; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public void setSsrc(String ssrc) { | |
| 75 | + this.ssrc = ssrc; | |
| 76 | + } | |
| 68 | 77 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
| ... | ... | @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 14 | 14 | import gov.nist.javax.sip.stack.SIPDialog; |
| 15 | 15 | import org.springframework.beans.factory.annotation.Autowired; |
| 16 | 16 | import org.springframework.stereotype.Component; |
| 17 | +import org.springframework.util.StringUtils; | |
| 17 | 18 | |
| 18 | 19 | /** |
| 19 | 20 | * @description:视频流session管理器,管理视频预览、预览回放的通信句柄 |
| ... | ... | @@ -29,39 +30,55 @@ public class VideoStreamSessionManager { |
| 29 | 30 | @Autowired |
| 30 | 31 | private UserSetup userSetup; |
| 31 | 32 | |
| 32 | - public void put(String deviceId, String channelId ,String ssrc, String streamId, String mediaServerId, ClientTransaction transaction){ | |
| 33 | + /** | |
| 34 | + * 添加一个点播/回放的事务信息 | |
| 35 | + * 后续可以通过流Id/callID | |
| 36 | + * @param deviceId 设备ID | |
| 37 | + * @param channelId 通道ID | |
| 38 | + * @param callId 一次请求的CallID | |
| 39 | + * @param stream 流名称 | |
| 40 | + * @param mediaServerId 所使用的流媒体ID | |
| 41 | + * @param transaction 事务 | |
| 42 | + */ | |
| 43 | + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction){ | |
| 33 | 44 | SsrcTransaction ssrcTransaction = new SsrcTransaction(); |
| 34 | 45 | ssrcTransaction.setDeviceId(deviceId); |
| 35 | 46 | ssrcTransaction.setChannelId(channelId); |
| 36 | - ssrcTransaction.setStreamId(streamId); | |
| 47 | + ssrcTransaction.setStream(stream); | |
| 37 | 48 | byte[] transactionByteArray = SerializeUtils.serialize(transaction); |
| 38 | 49 | ssrcTransaction.setTransaction(transactionByteArray); |
| 50 | + ssrcTransaction.setCallId(callId); | |
| 39 | 51 | ssrcTransaction.setSsrc(ssrc); |
| 40 | 52 | ssrcTransaction.setMediaServerId(mediaServerId); |
| 41 | 53 | |
| 42 | - redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId, ssrcTransaction); | |
| 54 | + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() | |
| 55 | + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); | |
| 56 | + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() | |
| 57 | + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); | |
| 43 | 58 | } |
| 44 | 59 | |
| 45 | - public void put(String deviceId, String channelId , Dialog dialog){ | |
| 46 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 60 | + public void put(String deviceId, String channelId, String callId, Dialog dialog){ | |
| 61 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); | |
| 47 | 62 | if (ssrcTransaction != null) { |
| 48 | 63 | byte[] dialogByteArray = SerializeUtils.serialize(dialog); |
| 49 | 64 | ssrcTransaction.setDialog(dialogByteArray); |
| 50 | 65 | } |
| 51 | - redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId, ssrcTransaction); | |
| 66 | + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() | |
| 67 | + + "_" + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" | |
| 68 | + + ssrcTransaction.getStream(), ssrcTransaction); | |
| 52 | 69 | } |
| 53 | 70 | |
| 54 | 71 | |
| 55 | - public ClientTransaction getTransaction(String deviceId, String channelId){ | |
| 56 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 72 | + public ClientTransaction getTransactionByStream(String deviceId, String channelId, String stream){ | |
| 73 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 57 | 74 | if (ssrcTransaction == null) return null; |
| 58 | 75 | byte[] transactionByteArray = ssrcTransaction.getTransaction(); |
| 59 | 76 | ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray); |
| 60 | 77 | return clientTransaction; |
| 61 | 78 | } |
| 62 | 79 | |
| 63 | - public SIPDialog getDialog(String deviceId, String channelId){ | |
| 64 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 80 | + public SIPDialog getDialogByStream(String deviceId, String channelId, String stream){ | |
| 81 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 65 | 82 | if (ssrcTransaction == null) return null; |
| 66 | 83 | byte[] dialogByteArray = ssrcTransaction.getDialog(); |
| 67 | 84 | if (dialogByteArray == null) return null; |
| ... | ... | @@ -69,36 +86,37 @@ public class VideoStreamSessionManager { |
| 69 | 86 | return dialog; |
| 70 | 87 | } |
| 71 | 88 | |
| 72 | - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId){ | |
| 73 | - SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId); | |
| 74 | - return ssrcTransaction; | |
| 89 | + public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ | |
| 90 | + if (StringUtils.isEmpty(callId)) callId ="*"; | |
| 91 | + if (StringUtils.isEmpty(stream)) stream ="*"; | |
| 92 | + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; | |
| 93 | + List<Object> scanResult = redisUtil.scan(key); | |
| 94 | + if (scanResult.size() == 0) return null; | |
| 95 | + return (SsrcTransaction)redisUtil.get((String) scanResult.get(0)); | |
| 75 | 96 | } |
| 76 | 97 | |
| 77 | - public String getStreamId(String deviceId, String channelId){ | |
| 78 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 79 | - if (ssrcTransaction == null) return null; | |
| 80 | - return ssrcTransaction.getStreamId(); | |
| 81 | - } | |
| 82 | - public String getMediaServerId(String deviceId, String channelId){ | |
| 83 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 98 | + public String getMediaServerId(String deviceId, String channelId, String stream){ | |
| 99 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 84 | 100 | if (ssrcTransaction == null) return null; |
| 85 | 101 | return ssrcTransaction.getMediaServerId(); |
| 86 | 102 | } |
| 87 | 103 | |
| 88 | - public String getSSRC(String deviceId, String channelId){ | |
| 89 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 104 | + public String getSSRC(String deviceId, String channelId, String stream){ | |
| 105 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 90 | 106 | if (ssrcTransaction == null) return null; |
| 91 | 107 | return ssrcTransaction.getSsrc(); |
| 92 | 108 | } |
| 93 | 109 | |
| 94 | - public void remove(String deviceId, String channelId) { | |
| 95 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId); | |
| 110 | + public void remove(String deviceId, String channelId, String stream) { | |
| 111 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 96 | 112 | if (ssrcTransaction == null) return; |
| 97 | - redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId); | |
| 113 | + redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" | |
| 114 | + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); | |
| 98 | 115 | } |
| 99 | 116 | |
| 117 | + | |
| 100 | 118 | public List<SsrcTransaction> getAllSsrc() { |
| 101 | - List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetup.getServerId() + "_" )); | |
| 119 | + List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetup.getServerId() + "_" )); | |
| 102 | 120 | List<SsrcTransaction> result= new ArrayList<>(); |
| 103 | 121 | for (int i = 0; i < ssrcTransactionKeys.size(); i++) { |
| 104 | 122 | String key = (String)ssrcTransactionKeys.get(i); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| ... | ... | @@ -119,8 +119,8 @@ public interface ISIPCommander { |
| 119 | 119 | /** |
| 120 | 120 | * 视频流停止 |
| 121 | 121 | */ |
| 122 | - void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent); | |
| 123 | - void streamByeCmd(String deviceId, String channelId); | |
| 122 | + void streamByeCmd(String deviceId, String channelId, String ssrc, SipSubscribe.Event okEvent); | |
| 123 | + void streamByeCmd(String deviceId, String channelId, String ssrc); | |
| 124 | 124 | |
| 125 | 125 | /** |
| 126 | 126 | * 回放暂停 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
| ... | ... | @@ -17,7 +17,7 @@ public interface ISIPCommanderForPlatform { |
| 17 | 17 | * @return |
| 18 | 18 | */ |
| 19 | 19 | boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); |
| 20 | - boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); | |
| 20 | + boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain); | |
| 21 | 21 | |
| 22 | 22 | /** |
| 23 | 23 | * 向上级平台注销 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
| ... | ... | @@ -128,7 +128,15 @@ public class SIPRequestHeaderPlarformProvider { |
| 128 | 128 | |
| 129 | 129 | |
| 130 | 130 | Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), fromTag, viaTag, callIdHeader); |
| 131 | - | |
| 131 | + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); | |
| 132 | + if (www == null) { | |
| 133 | + AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader("Digest"); | |
| 134 | + authorizationHeader.setUsername(parentPlatform.getDeviceGBId()); | |
| 135 | + authorizationHeader.setURI(requestURI); | |
| 136 | + authorizationHeader.setAlgorithm("MD5"); | |
| 137 | + registerRequest.addHeader(authorizationHeader); | |
| 138 | + return registerRequest; | |
| 139 | + } | |
| 132 | 140 | String realm = www.getRealm(); |
| 133 | 141 | String nonce = www.getNonce(); |
| 134 | 142 | String scheme = www.getScheme(); |
| ... | ... | @@ -139,7 +147,6 @@ public class SIPRequestHeaderPlarformProvider { |
| 139 | 147 | |
| 140 | 148 | callIdHeader.setCallId(callId); |
| 141 | 149 | |
| 142 | - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); | |
| 143 | 150 | String cNonce = null; |
| 144 | 151 | String nc = "00000001"; |
| 145 | 152 | if (qop != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| ... | ... | @@ -226,7 +226,7 @@ public class SIPRequestHeaderProvider { |
| 226 | 226 | throws PeerUnavailableException, ParseException, InvalidArgumentException { |
| 227 | 227 | Request request = null; |
| 228 | 228 | if (streamInfo == null) return null; |
| 229 | - Dialog dialog = streamSession.getDialog(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 229 | + Dialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); | |
| 230 | 230 | |
| 231 | 231 | SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), |
| 232 | 232 | device.getHostAddress()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -331,7 +331,7 @@ public class SIPCommander implements ISIPCommander { |
| 331 | 331 | */ |
| 332 | 332 | @Override |
| 333 | 333 | public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) { |
| 334 | - String streamId = ssrcInfo.getStreamId(); | |
| 334 | + String streamId = ssrcInfo.getStream(); | |
| 335 | 335 | try { |
| 336 | 336 | if (device == null) return; |
| 337 | 337 | String streamMode = device.getStreamMode().toUpperCase(); |
| ... | ... | @@ -404,6 +404,8 @@ public class SIPCommander implements ISIPCommander { |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | 406 | content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc |
| 407 | + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 | |
| 408 | +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 | |
| 407 | 409 | |
| 408 | 410 | String tm = Long.toString(System.currentTimeMillis()); |
| 409 | 411 | |
| ... | ... | @@ -412,14 +414,14 @@ public class SIPCommander implements ISIPCommander { |
| 412 | 414 | |
| 413 | 415 | Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader); |
| 414 | 416 | |
| 415 | - String finalStreamId = streamId; | |
| 416 | 417 | transmitRequest(device, request, (e -> { |
| 417 | - streamSession.remove(device.getDeviceId(), channelId); | |
| 418 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 418 | 419 | mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc()); |
| 419 | 420 | errorEvent.response(e); |
| 420 | 421 | }), e ->{ |
| 421 | - streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction()); | |
| 422 | - streamSession.put(device.getDeviceId(), channelId , e.dialog); | |
| 422 | + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 | |
| 423 | + streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction()); | |
| 424 | + streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog); | |
| 423 | 425 | }); |
| 424 | 426 | |
| 425 | 427 | |
| ... | ... | @@ -441,12 +443,12 @@ public class SIPCommander implements ISIPCommander { |
| 441 | 443 | , SipSubscribe.Event errorEvent) { |
| 442 | 444 | try { |
| 443 | 445 | |
| 444 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 446 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 445 | 447 | |
| 446 | 448 | // 添加订阅 |
| 447 | 449 | JSONObject subscribeKey = new JSONObject(); |
| 448 | 450 | subscribeKey.put("app", "rtp"); |
| 449 | - subscribeKey.put("stream", ssrcInfo.getStreamId()); | |
| 451 | + subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 450 | 452 | subscribeKey.put("regist", true); |
| 451 | 453 | subscribeKey.put("mediaServerId", mediaServerItem.getId()); |
| 452 | 454 | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); |
| ... | ... | @@ -466,8 +468,6 @@ public class SIPCommander implements ISIPCommander { |
| 466 | 468 | content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" " |
| 467 | 469 | +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); |
| 468 | 470 | |
| 469 | - | |
| 470 | - | |
| 471 | 471 | String streamMode = device.getStreamMode().toUpperCase(); |
| 472 | 472 | |
| 473 | 473 | if (userSetup.isSeniorSdp()) { |
| ... | ... | @@ -527,8 +527,8 @@ public class SIPCommander implements ISIPCommander { |
| 527 | 527 | |
| 528 | 528 | transmitRequest(device, request, errorEvent, okEvent -> { |
| 529 | 529 | ResponseEvent responseEvent = (ResponseEvent) okEvent.event; |
| 530 | - streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), responseEvent.getClientTransaction()); | |
| 531 | - streamSession.put(device.getDeviceId(), channelId, okEvent.dialog); | |
| 530 | + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction()); | |
| 531 | + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog); | |
| 532 | 532 | }); |
| 533 | 533 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 534 | 534 | e.printStackTrace(); |
| ... | ... | @@ -548,12 +548,12 @@ public class SIPCommander implements ISIPCommander { |
| 548 | 548 | public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event |
| 549 | 549 | , SipSubscribe.Event errorEvent) { |
| 550 | 550 | try { |
| 551 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 551 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); | |
| 552 | 552 | |
| 553 | 553 | // 添加订阅 |
| 554 | 554 | JSONObject subscribeKey = new JSONObject(); |
| 555 | 555 | subscribeKey.put("app", "rtp"); |
| 556 | - subscribeKey.put("stream", ssrcInfo.getStreamId()); | |
| 556 | + subscribeKey.put("stream", ssrcInfo.getStream()); | |
| 557 | 557 | subscribeKey.put("regist", true); |
| 558 | 558 | subscribeKey.put("mediaServerId", mediaServerItem.getId()); |
| 559 | 559 | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); |
| ... | ... | @@ -634,7 +634,8 @@ public class SIPCommander implements ISIPCommander { |
| 634 | 634 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); |
| 635 | 635 | |
| 636 | 636 | ClientTransaction transaction = transmitRequest(device, request, errorEvent); |
| 637 | - streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction); | |
| 637 | + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction); | |
| 638 | + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction); | |
| 638 | 639 | |
| 639 | 640 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 640 | 641 | e.printStackTrace(); |
| ... | ... | @@ -645,17 +646,17 @@ public class SIPCommander implements ISIPCommander { |
| 645 | 646 | * 视频流停止, 不使用回调 |
| 646 | 647 | */ |
| 647 | 648 | @Override |
| 648 | - public void streamByeCmd(String deviceId, String channelId) { | |
| 649 | - streamByeCmd(deviceId, channelId, null); | |
| 649 | + public void streamByeCmd(String deviceId, String channelId, String stream) { | |
| 650 | + streamByeCmd(deviceId, channelId, stream, null); | |
| 650 | 651 | } |
| 651 | 652 | |
| 652 | 653 | /** |
| 653 | 654 | * 视频流停止 |
| 654 | 655 | */ |
| 655 | 656 | @Override |
| 656 | - public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) { | |
| 657 | + public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) { | |
| 657 | 658 | try { |
| 658 | - ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId); | |
| 659 | + ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream); | |
| 659 | 660 | if (transaction == null) { |
| 660 | 661 | logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); |
| 661 | 662 | SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>(); |
| ... | ... | @@ -664,7 +665,7 @@ public class SIPCommander implements ISIPCommander { |
| 664 | 665 | } |
| 665 | 666 | return; |
| 666 | 667 | } |
| 667 | - SIPDialog dialog = streamSession.getDialog(deviceId, channelId); | |
| 668 | + SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream); | |
| 668 | 669 | if (dialog == null) { |
| 669 | 670 | logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId); |
| 670 | 671 | return; |
| ... | ... | @@ -708,11 +709,11 @@ public class SIPCommander implements ISIPCommander { |
| 708 | 709 | |
| 709 | 710 | dialog.sendRequest(clientTransaction); |
| 710 | 711 | |
| 711 | - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId); | |
| 712 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callIdHeader.getCallId(), null); | |
| 712 | 713 | if (ssrcTransaction != null) { |
| 713 | 714 | MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); |
| 714 | 715 | mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc()); |
| 715 | - streamSession.remove(deviceId, channelId); | |
| 716 | + streamSession.remove(deviceId, channelId, ssrcTransaction.getStream()); | |
| 716 | 717 | } |
| 717 | 718 | } catch (SipException | ParseException e) { |
| 718 | 719 | e.printStackTrace(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -53,7 +53,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 53 | 53 | |
| 54 | 54 | @Override |
| 55 | 55 | public boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { |
| 56 | - return register(parentPlatform, null, null, errorEvent, okEvent); | |
| 56 | + return register(parentPlatform, null, null, errorEvent, okEvent, false); | |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | @Override |
| ... | ... | @@ -65,15 +65,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 65 | 65 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | - return register(parentPlatform, null, null, errorEvent, okEvent); | |
| 68 | + return register(parentPlatform, null, null, errorEvent, okEvent, false); | |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | @Override |
| 72 | - public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { | |
| 72 | + public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, | |
| 73 | + SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain) { | |
| 73 | 74 | try { |
| 74 | 75 | Request request = null; |
| 75 | 76 | String tm = Long.toString(System.currentTimeMillis()); |
| 76 | - if (www == null ) { | |
| 77 | + if (!registerAgain ) { | |
| 77 | 78 | // //callid |
| 78 | 79 | CallIdHeader callIdHeader = null; |
| 79 | 80 | if(parentPlatform.getTransport().equals("TCP")) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
| ... | ... | @@ -72,10 +72,10 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In |
| 72 | 72 | if (deviceId == null) { |
| 73 | 73 | streamInfo = new StreamInfo(); |
| 74 | 74 | streamInfo.setApp(sendRtpItem.getApp()); |
| 75 | - streamInfo.setStreamId(sendRtpItem.getStreamId()); | |
| 75 | + streamInfo.setStream(sendRtpItem.getStreamId()); | |
| 76 | 76 | }else { |
| 77 | 77 | streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
| 78 | - sendRtpItem.setStreamId(streamInfo.getStreamId()); | |
| 78 | + sendRtpItem.setStreamId(streamInfo.getStream()); | |
| 79 | 79 | streamInfo.setApp("rtp"); |
| 80 | 80 | } |
| 81 | 81 | |
| ... | ... | @@ -85,7 +85,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In |
| 85 | 85 | Map<String, Object> param = new HashMap<>(); |
| 86 | 86 | param.put("vhost","__defaultVhost__"); |
| 87 | 87 | param.put("app",streamInfo.getApp()); |
| 88 | - param.put("stream",streamInfo.getStreamId()); | |
| 88 | + param.put("stream",streamInfo.getStream()); | |
| 89 | 89 | param.put("ssrc", sendRtpItem.getSsrc()); |
| 90 | 90 | param.put("dst_url",sendRtpItem.getIp()); |
| 91 | 91 | param.put("dst_port", sendRtpItem.getPort()); |
| ... | ... | @@ -98,21 +98,21 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In |
| 98 | 98 | try { |
| 99 | 99 | if (System.currentTimeMillis() - startTime < 30 * 1000) { |
| 100 | 100 | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| 101 | - if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) { | |
| 101 | + if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStream())) { | |
| 102 | 102 | rtpPushed = true; |
| 103 | 103 | logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]", |
| 104 | - streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort()); | |
| 104 | + streamInfo.getApp() ,streamInfo.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); | |
| 105 | 105 | zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| 106 | 106 | } else { |
| 107 | 107 | logger.info("等待设备推流[{}/{}].......", |
| 108 | - streamInfo.getApp() ,streamInfo.getStreamId()); | |
| 108 | + streamInfo.getApp() ,streamInfo.getStream()); | |
| 109 | 109 | Thread.sleep(1000); |
| 110 | 110 | continue; |
| 111 | 111 | } |
| 112 | 112 | } else { |
| 113 | 113 | rtpPushed = true; |
| 114 | 114 | logger.info("设备推流[{}/{}]超时,终止向上级推流", |
| 115 | - streamInfo.getApp() ,streamInfo.getStreamId()); | |
| 115 | + streamInfo.getApp() ,streamInfo.getStream()); | |
| 116 | 116 | } |
| 117 | 117 | } catch (InterruptedException e) { |
| 118 | 118 | e.printStackTrace(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -89,18 +89,19 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 89 | 89 | redisCatchStorage.deleteSendRTPServer(platformGbId, channelId); |
| 90 | 90 | if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) { |
| 91 | 91 | logger.info(streamId + "无其它观看者,通知设备停止推流"); |
| 92 | - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); | |
| 92 | + cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId); | |
| 93 | 93 | } |
| 94 | 94 | } |
| 95 | 95 | // 可能是设备主动停止 |
| 96 | 96 | Device device = storager.queryVideoDeviceByChannelId(platformGbId); |
| 97 | 97 | if (device != null) { |
| 98 | 98 | StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); |
| 99 | + | |
| 99 | 100 | if (streamInfo != null) { |
| 100 | 101 | redisCatchStorage.stopPlay(streamInfo); |
| 101 | 102 | } |
| 102 | 103 | storager.stopPlay(device.getDeviceId(), channelId); |
| 103 | - mediaServerService.closeRTPServer(device, channelId); | |
| 104 | + mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream()); | |
| 104 | 105 | } |
| 105 | 106 | } |
| 106 | 107 | } catch (SipException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
| ... | ... | @@ -62,7 +62,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i |
| 62 | 62 | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*"); |
| 63 | 63 | if (streamInfo != null) { |
| 64 | 64 | redisCatchStorage.stopPlayback(streamInfo); |
| 65 | - cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 65 | + cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); | |
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
| ... | ... | @@ -78,7 +78,7 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 78 | 78 | |
| 79 | 79 | if (response.getStatusCode() == 401) { |
| 80 | 80 | WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); |
| 81 | - sipCommanderForPlatform.register(parentPlatform, callId, www, null, null); | |
| 81 | + sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true); | |
| 82 | 82 | }else if (response.getStatusCode() == 200){ |
| 83 | 83 | // 注册/注销成功 |
| 84 | 84 | logger.info(String.format("%s %s成功", platformGBId, action)); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -360,6 +360,7 @@ public class ZLMHttpHookListener { |
| 360 | 360 | StreamPushItem streamPushItem = null; |
| 361 | 361 | StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks); |
| 362 | 362 | item.setStreamInfo(streamInfoByAppAndStream); |
| 363 | + | |
| 363 | 364 | redisCatchStorage.addStream(mediaServerItem, type, app, streamId, item); |
| 364 | 365 | if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() |
| 365 | 366 | || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() |
| ... | ... | @@ -438,14 +439,16 @@ public class ZLMHttpHookListener { |
| 438 | 439 | if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { |
| 439 | 440 | ret.put("close", false); |
| 440 | 441 | } else { |
| 441 | - cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); | |
| 442 | + cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(), | |
| 443 | + streamInfoForPlayCatch.getStream()); | |
| 442 | 444 | redisCatchStorage.stopPlay(streamInfoForPlayCatch); |
| 443 | 445 | storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); |
| 444 | 446 | } |
| 445 | 447 | }else{ |
| 446 | 448 | StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| 447 | 449 | if (streamInfoForPlayBackCatch != null) { |
| 448 | - cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), streamInfoForPlayBackCatch.getChannelId()); | |
| 450 | + cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), | |
| 451 | + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream()); | |
| 449 | 452 | redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch); |
| 450 | 453 | }else { |
| 451 | 454 | StreamInfo streamInfoForDownload = redisCatchStorage.queryDownloadByStreamId(streamId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| ... | ... | @@ -46,7 +46,7 @@ public interface IMediaServerService { |
| 46 | 46 | |
| 47 | 47 | SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean isPlayback); |
| 48 | 48 | |
| 49 | - void closeRTPServer(Device device, String channelId); | |
| 49 | + void closeRTPServer(Device device, String channelId, String ssrc); | |
| 50 | 50 | |
| 51 | 51 | void clearRTPServer(MediaServerItem mediaServerItem); |
| 52 | 52 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| ... | ... | @@ -5,14 +5,16 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 7 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 8 | +import com.genersoft.iot.vmp.service.bean.PlayBackCallback; | |
| 8 | 9 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| 10 | +import org.springframework.http.ResponseEntity; | |
| 11 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 9 | 12 | |
| 10 | 13 | /** |
| 11 | 14 | * 点播处理 |
| 12 | 15 | */ |
| 13 | 16 | public interface IPlayService { |
| 14 | 17 | |
| 15 | - void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid); | |
| 16 | 18 | void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid); |
| 17 | 19 | |
| 18 | 20 | PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
| ... | ... | @@ -20,4 +22,6 @@ public interface IPlayService { |
| 20 | 22 | MediaServerItem getNewMediaServerItem(Device device); |
| 21 | 23 | |
| 22 | 24 | void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString); |
| 25 | + | |
| 26 | + DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback errorCallBack); | |
| 23 | 27 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java
| ... | ... | @@ -4,12 +4,12 @@ public class SSRCInfo { |
| 4 | 4 | |
| 5 | 5 | private int port; |
| 6 | 6 | private String ssrc; |
| 7 | - private String StreamId; | |
| 7 | + private String Stream; | |
| 8 | 8 | |
| 9 | - public SSRCInfo(int port, String ssrc, String streamId) { | |
| 9 | + public SSRCInfo(int port, String ssrc, String stream) { | |
| 10 | 10 | this.port = port; |
| 11 | 11 | this.ssrc = ssrc; |
| 12 | - StreamId = streamId; | |
| 12 | + Stream = stream; | |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | public int getPort() { |
| ... | ... | @@ -28,11 +28,11 @@ public class SSRCInfo { |
| 28 | 28 | this.ssrc = ssrc; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | - public String getStreamId() { | |
| 32 | - return StreamId; | |
| 31 | + public String getStream() { | |
| 32 | + return Stream; | |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | - public void setStreamId(String streamId) { | |
| 36 | - StreamId = streamId; | |
| 35 | + public void setStream(String stream) { | |
| 36 | + Stream = stream; | |
| 37 | 37 | } |
| 38 | 38 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -162,15 +162,16 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | @Override |
| 165 | - public void closeRTPServer(Device device, String channelId) { | |
| 166 | - String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId); | |
| 165 | + public void closeRTPServer(Device device, String channelId, String stream) { | |
| 166 | + String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId, stream); | |
| 167 | + String ssrc = streamSession.getSSRC(device.getDeviceId(), channelId, stream); | |
| 167 | 168 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); |
| 168 | 169 | if (mediaServerItem != null) { |
| 169 | 170 | String streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| 170 | 171 | zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId); |
| 171 | - releaseSsrc(mediaServerItem, streamSession.getSSRC(device.getDeviceId(), channelId)); | |
| 172 | + releaseSsrc(mediaServerItem, ssrc); | |
| 172 | 173 | } |
| 173 | - streamSession.remove(device.getDeviceId(), channelId); | |
| 174 | + streamSession.remove(device.getDeviceId(), channelId, stream); | |
| 174 | 175 | } |
| 175 | 176 | |
| 176 | 177 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
| ... | ... | @@ -74,7 +74,7 @@ public class MediaServiceImpl implements IMediaService { |
| 74 | 74 | @Override |
| 75 | 75 | public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr) { |
| 76 | 76 | StreamInfo streamInfoResult = new StreamInfo(); |
| 77 | - streamInfoResult.setStreamId(stream); | |
| 77 | + streamInfoResult.setStream(stream); | |
| 78 | 78 | streamInfoResult.setApp(app); |
| 79 | 79 | if (addr == null) { |
| 80 | 80 | addr = mediaInfo.getStreamIp(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| ... | ... | @@ -16,10 +16,10 @@ 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.PlayBackCallback; | |
| 19 | 20 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 20 | 21 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 21 | 22 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 22 | -import com.genersoft.iot.vmp.utils.redis.RedisUtil; | |
| 23 | 23 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 24 | 24 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| 25 | 25 | import com.genersoft.iot.vmp.service.IMediaService; |
| ... | ... | @@ -54,9 +54,6 @@ public class PlayServiceImpl implements IPlayService { |
| 54 | 54 | private IRedisCatchStorage redisCatchStorage; |
| 55 | 55 | |
| 56 | 56 | @Autowired |
| 57 | - private RedisUtil redis; | |
| 58 | - | |
| 59 | - @Autowired | |
| 60 | 57 | private DeferredResultHolder resultHolder; |
| 61 | 58 | |
| 62 | 59 | @Autowired |
| ... | ... | @@ -104,19 +101,21 @@ public class PlayServiceImpl implements IPlayService { |
| 104 | 101 | logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| 105 | 102 | WVPResult wvpResult = new WVPResult(); |
| 106 | 103 | wvpResult.setCode(-1); |
| 107 | - SIPDialog dialog = streamSession.getDialog(deviceId, channelId); | |
| 104 | + SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, streamInfo.getStream()); | |
| 108 | 105 | if (dialog != null) { |
| 109 | 106 | wvpResult.setMsg("收流超时,请稍候重试"); |
| 110 | 107 | }else { |
| 111 | 108 | wvpResult.setMsg("点播超时,请稍候重试"); |
| 112 | 109 | } |
| 110 | + | |
| 113 | 111 | msg.setData(wvpResult); |
| 114 | 112 | // 点播超时回复BYE |
| 115 | - cmder.streamByeCmd(device.getDeviceId(), channelId); | |
| 113 | + cmder.streamByeCmd(device.getDeviceId(), channelId, streamInfo.getStream()); | |
| 116 | 114 | // 释放rtpserver |
| 117 | - mediaServerService.closeRTPServer(playResult.getDevice(), channelId); | |
| 115 | + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, streamInfo.getStream()); | |
| 118 | 116 | // 回复之前所有的点播请求 |
| 119 | 117 | resultHolder.invokeAllResult(msg); |
| 118 | + // TODO 释放ssrc | |
| 120 | 119 | }); |
| 121 | 120 | result.onCompletion(()->{ |
| 122 | 121 | // 点播结束时调用截图接口 |
| ... | ... | @@ -154,14 +153,12 @@ public class PlayServiceImpl implements IPlayService { |
| 154 | 153 | } |
| 155 | 154 | }); |
| 156 | 155 | if (streamInfo == null) { |
| 157 | - SSRCInfo ssrcInfo; | |
| 158 | 156 | String streamId = null; |
| 159 | 157 | if (mediaServerItem.isRtpEnable()) { |
| 160 | 158 | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| 161 | 159 | } |
| 162 | 160 | |
| 163 | - ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); | |
| 164 | - | |
| 161 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); | |
| 165 | 162 | // 发送点播消息 |
| 166 | 163 | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { |
| 167 | 164 | logger.info("收到订阅消息: " + response.toJSONString()); |
| ... | ... | @@ -173,7 +170,7 @@ public class PlayServiceImpl implements IPlayService { |
| 173 | 170 | WVPResult wvpResult = new WVPResult(); |
| 174 | 171 | wvpResult.setCode(-1); |
| 175 | 172 | // 点播返回sip错误 |
| 176 | - mediaServerService.closeRTPServer(playResult.getDevice(), channelId); | |
| 173 | + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream()); | |
| 177 | 174 | wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| 178 | 175 | msg.setData(wvpResult); |
| 179 | 176 | resultHolder.invokeAllResult(msg); |
| ... | ... | @@ -184,7 +181,7 @@ public class PlayServiceImpl implements IPlayService { |
| 184 | 181 | |
| 185 | 182 | }); |
| 186 | 183 | } else { |
| 187 | - String streamId = streamInfo.getStreamId(); | |
| 184 | + String streamId = streamInfo.getStream(); | |
| 188 | 185 | if (streamId == null) { |
| 189 | 186 | WVPResult wvpResult = new WVPResult(); |
| 190 | 187 | wvpResult.setCode(-1); |
| ... | ... | @@ -213,18 +210,16 @@ public class PlayServiceImpl implements IPlayService { |
| 213 | 210 | // TODO 点播前是否重置状态 |
| 214 | 211 | redisCatchStorage.stopPlay(streamInfo); |
| 215 | 212 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 216 | - SSRCInfo ssrcInfo; | |
| 217 | 213 | String streamId2 = null; |
| 218 | 214 | if (mediaServerItem.isRtpEnable()) { |
| 219 | 215 | streamId2 = String.format("%s_%s", device.getDeviceId(), channelId); |
| 220 | 216 | } |
| 221 | - ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2); | |
| 222 | - | |
| 217 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2); | |
| 223 | 218 | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { |
| 224 | 219 | logger.info("收到订阅消息: " + response.toJSONString()); |
| 225 | 220 | onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid); |
| 226 | 221 | }, (event) -> { |
| 227 | - mediaServerService.closeRTPServer(playResult.getDevice(), channelId); | |
| 222 | + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream()); | |
| 228 | 223 | WVPResult wvpResult = new WVPResult(); |
| 229 | 224 | wvpResult.setCode(-1); |
| 230 | 225 | wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| ... | ... | @@ -242,12 +237,12 @@ public class PlayServiceImpl implements IPlayService { |
| 242 | 237 | RequestMessage msg = new RequestMessage(); |
| 243 | 238 | msg.setId(uuid); |
| 244 | 239 | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| 245 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid); | |
| 240 | + StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId); | |
| 246 | 241 | if (streamInfo != null) { |
| 247 | 242 | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| 248 | 243 | if (deviceChannel != null) { |
| 249 | - deviceChannel.setStreamId(streamInfo.getStreamId()); | |
| 250 | - storager.startPlay(deviceId, channelId, streamInfo.getStreamId()); | |
| 244 | + deviceChannel.setStreamId(streamInfo.getStream()); | |
| 245 | + storager.startPlay(deviceId, channelId, streamInfo.getStream()); | |
| 251 | 246 | } |
| 252 | 247 | redisCatchStorage.startPlay(streamInfo); |
| 253 | 248 | msg.setData(JSON.toJSONString(streamInfo)); |
| ... | ... | @@ -284,29 +279,53 @@ public class PlayServiceImpl implements IPlayService { |
| 284 | 279 | |
| 285 | 280 | |
| 286 | 281 | @Override |
| 287 | - public void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) { | |
| 282 | + public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback callback) { | |
| 283 | + String uuid = UUID.randomUUID().toString(); | |
| 284 | + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; | |
| 285 | + DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L); | |
| 286 | + Device device = storager.queryVideoDevice(deviceId); | |
| 287 | + if (device == null) { | |
| 288 | + result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); | |
| 289 | + return result; | |
| 290 | + } | |
| 291 | + | |
| 292 | + MediaServerItem newMediaServerItem = getNewMediaServerItem(device); | |
| 293 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); | |
| 294 | + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result); | |
| 288 | 295 | RequestMessage msg = new RequestMessage(); |
| 289 | - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId); | |
| 290 | 296 | msg.setId(uuid); |
| 291 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid); | |
| 292 | - if (streamInfo != null) { | |
| 297 | + msg.setKey(key); | |
| 298 | + result.onTimeout(()->{ | |
| 299 | + msg.setData("回放超时"); | |
| 300 | + callback.call(msg); | |
| 301 | + }); | |
| 302 | + cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> { | |
| 303 | + logger.info("收到订阅消息: " + response.toJSONString()); | |
| 304 | + StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); | |
| 305 | + if (streamInfo == null) { | |
| 306 | + logger.warn("设备回放API调用失败!"); | |
| 307 | + msg.setData("设备回放API调用失败!"); | |
| 308 | + callback.call(msg); | |
| 309 | + return; | |
| 310 | + } | |
| 293 | 311 | redisCatchStorage.startPlayback(streamInfo); |
| 294 | 312 | msg.setData(JSON.toJSONString(streamInfo)); |
| 295 | - resultHolder.invokeResult(msg); | |
| 296 | - } else { | |
| 297 | - logger.warn("设备回放API调用失败!"); | |
| 298 | - msg.setData("设备回放API调用失败!"); | |
| 299 | - resultHolder.invokeResult(msg); | |
| 300 | - } | |
| 313 | + callback.call(msg); | |
| 314 | + }, event -> { | |
| 315 | + msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 316 | + callback.call(msg); | |
| 317 | + }); | |
| 318 | + return result; | |
| 301 | 319 | } |
| 302 | 320 | |
| 303 | 321 | |
| 322 | + | |
| 304 | 323 | @Override |
| 305 | 324 | public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| 306 | 325 | RequestMessage msg = new RequestMessage(); |
| 307 | 326 | msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId); |
| 308 | 327 | msg.setId(uuid); |
| 309 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId, uuid); | |
| 328 | + StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); | |
| 310 | 329 | if (streamInfo != null) { |
| 311 | 330 | redisCatchStorage.startDownload(streamInfo); |
| 312 | 331 | msg.setData(JSON.toJSONString(streamInfo)); |
| ... | ... | @@ -319,7 +338,7 @@ public class PlayServiceImpl implements IPlayService { |
| 319 | 338 | } |
| 320 | 339 | |
| 321 | 340 | |
| 322 | - public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) { | |
| 341 | + public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) { | |
| 323 | 342 | String streamId = resonse.getString("stream"); |
| 324 | 343 | JSONArray tracks = resonse.getJSONArray("tracks"); |
| 325 | 344 | StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| ... | ... | @@ -132,7 +132,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 132 | 132 | }else { |
| 133 | 133 | streamLive = true; |
| 134 | 134 | StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream( |
| 135 | - mediaInfo, param.getApp(), param.getStream(), null); | |
| 135 | + mediaInfo, param.getApp(), param.getStream(), null, null); | |
| 136 | 136 | wvpResult.setData(streamInfo); |
| 137 | 137 | |
| 138 | 138 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; |
| 7 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 8 | 8 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 9 | 9 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 10 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 10 | 11 | import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; |
| 11 | 12 | |
| 12 | 13 | import java.util.List; |
| ... | ... | @@ -220,4 +221,5 @@ public interface IRedisCatchStorage { |
| 220 | 221 | void addMemInfo(double memInfo); |
| 221 | 222 | |
| 222 | 223 | void addNetInfo(Map<String, String> networkInterfaces); |
| 224 | + | |
| 223 | 225 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; |
| 10 | 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 11 | 11 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 12 | 12 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 13 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 13 | 14 | import com.genersoft.iot.vmp.service.bean.ThirdPartyGB; |
| 14 | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 15 | 16 | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; |
| ... | ... | @@ -91,7 +92,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 91 | 92 | */ |
| 92 | 93 | @Override |
| 93 | 94 | public boolean startPlay(StreamInfo stream) { |
| 94 | - return redis.set(String.format("%S_%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetup.getServerId(), stream.getStreamId(),stream.getDeviceID(), stream.getChannelId()), | |
| 95 | + return redis.set(String.format("%S_%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetup.getServerId(), | |
| 96 | + stream.getStream(), stream.getDeviceID(), stream.getChannelId()), | |
| 95 | 97 | stream); |
| 96 | 98 | } |
| 97 | 99 | |
| ... | ... | @@ -105,7 +107,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 105 | 107 | if (streamInfo == null) return false; |
| 106 | 108 | return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, |
| 107 | 109 | userSetup.getServerId(), |
| 108 | - streamInfo.getStreamId(), | |
| 110 | + streamInfo.getStream(), | |
| 109 | 111 | streamInfo.getDeviceID(), |
| 110 | 112 | streamInfo.getChannelId())); |
| 111 | 113 | } |
| ... | ... | @@ -119,7 +121,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 119 | 121 | return (StreamInfo)redis.get(String.format("%S_%s_%s_%s_%s", |
| 120 | 122 | VideoManagerConstants.PLAYER_PREFIX, |
| 121 | 123 | userSetup.getServerId(), |
| 122 | - streamInfo.getStreamId(), | |
| 124 | + streamInfo.getStream(), | |
| 123 | 125 | streamInfo.getDeviceID(), |
| 124 | 126 | streamInfo.getChannelId())); |
| 125 | 127 | } |
| ... | ... | @@ -165,14 +167,14 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 165 | 167 | |
| 166 | 168 | @Override |
| 167 | 169 | public boolean startPlayback(StreamInfo stream) { |
| 168 | - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, userSetup.getServerId(),stream.getStreamId(), | |
| 169 | - stream.getDeviceID(), stream.getChannelId()), 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); | |
| 170 | 172 | } |
| 171 | 173 | |
| 172 | 174 | @Override |
| 173 | 175 | public boolean startDownload(StreamInfo streamInfo) { |
| 174 | - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(),streamInfo.getStreamId(), | |
| 175 | - streamInfo.getDeviceID(), streamInfo.getChannelId()), 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); | |
| 176 | 178 | } |
| 177 | 179 | |
| 178 | 180 | @Override |
| ... | ... | @@ -186,7 +188,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 186 | 188 | } |
| 187 | 189 | return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| 188 | 190 | userSetup.getServerId(), |
| 189 | - streamInfo.getStreamId(), | |
| 191 | + streamInfo.getStream(), | |
| 190 | 192 | streamInfo.getDeviceID(), |
| 191 | 193 | streamInfo.getChannelId())); |
| 192 | 194 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.impl; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 3 | 4 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| ... | ... | @@ -156,7 +157,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 156 | 157 | public synchronized void updateChannel(String deviceId, DeviceChannel channel) { |
| 157 | 158 | String channelId = channel.getChannelId(); |
| 158 | 159 | channel.setDeviceId(deviceId); |
| 159 | - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId())); | |
| 160 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 161 | + if (streamInfo != null) { | |
| 162 | + channel.setStreamId(streamInfo.getStream()); | |
| 163 | + } | |
| 160 | 164 | String now = this.format.format(System.currentTimeMillis()); |
| 161 | 165 | channel.setUpdateTime(now); |
| 162 | 166 | DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); |
| ... | ... | @@ -178,7 +182,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 178 | 182 | if (channelList.size() == 0) { |
| 179 | 183 | for (DeviceChannel channel : channels) { |
| 180 | 184 | channel.setDeviceId(deviceId); |
| 181 | - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId())); | |
| 185 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 186 | + if (streamInfo != null) { | |
| 187 | + channel.setStreamId(streamInfo.getStream()); | |
| 188 | + } | |
| 182 | 189 | String now = this.format.format(System.currentTimeMillis()); |
| 183 | 190 | channel.setUpdateTime(now); |
| 184 | 191 | channel.setCreateTime(now); |
| ... | ... | @@ -189,9 +196,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 189 | 196 | channelsInStore.put(deviceChannel.getChannelId(), deviceChannel); |
| 190 | 197 | } |
| 191 | 198 | for (DeviceChannel channel : channels) { |
| 192 | - String channelId = channel.getChannelId(); | |
| 193 | 199 | channel.setDeviceId(deviceId); |
| 194 | - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId())); | |
| 200 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId()); | |
| 201 | + if (streamInfo != null) { | |
| 202 | + channel.setStreamId(streamInfo.getStream()); | |
| 203 | + } | |
| 195 | 204 | String now = this.format.format(System.currentTimeMillis()); |
| 196 | 205 | channel.setUpdateTime(now); |
| 197 | 206 | if (channelsInStore.get(channel.getChannelId()) != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| ... | ... | @@ -110,26 +110,26 @@ public class PlayController { |
| 110 | 110 | String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId; |
| 111 | 111 | resultHolder.put(key, uuid, result); |
| 112 | 112 | Device device = storager.queryVideoDevice(deviceId); |
| 113 | - cmder.streamByeCmd(deviceId, channelId, (event) -> { | |
| 114 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 115 | - if (streamInfo == null) { | |
| 116 | - RequestMessage msg = new RequestMessage(); | |
| 117 | - msg.setId(uuid); | |
| 118 | - msg.setKey(key); | |
| 119 | - msg.setData("点播未找到"); | |
| 120 | - resultHolder.invokeAllResult(msg); | |
| 121 | - storager.stopPlay(deviceId, channelId); | |
| 122 | - }else { | |
| 123 | - redisCatchStorage.stopPlay(streamInfo); | |
| 124 | - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 125 | - RequestMessage msg = new RequestMessage(); | |
| 126 | - msg.setId(uuid); | |
| 127 | - msg.setKey(key); | |
| 128 | - //Response response = event.getResponse(); | |
| 129 | - msg.setData(String.format("success")); | |
| 130 | - resultHolder.invokeAllResult(msg); | |
| 131 | - } | |
| 132 | - mediaServerService.closeRTPServer(device, channelId); | |
| 113 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); | |
| 114 | + if (streamInfo == null) { | |
| 115 | + RequestMessage msg = new RequestMessage(); | |
| 116 | + msg.setId(uuid); | |
| 117 | + msg.setKey(key); | |
| 118 | + msg.setData("点播未找到"); | |
| 119 | + resultHolder.invokeAllResult(msg); | |
| 120 | + storager.stopPlay(deviceId, channelId); | |
| 121 | + return result; | |
| 122 | + } | |
| 123 | + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), (event) -> { | |
| 124 | + redisCatchStorage.stopPlay(streamInfo); | |
| 125 | + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); | |
| 126 | + RequestMessage msg = new RequestMessage(); | |
| 127 | + msg.setId(uuid); | |
| 128 | + msg.setKey(key); | |
| 129 | + //Response response = event.getResponse(); | |
| 130 | + msg.setData(String.format("success")); | |
| 131 | + resultHolder.invokeAllResult(msg); | |
| 132 | + mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream()); | |
| 133 | 133 | }); |
| 134 | 134 | |
| 135 | 135 | if (deviceId != null || channelId != null) { |
| ... | ... | @@ -329,7 +329,7 @@ public class PlayController { |
| 329 | 329 | jsonObject.put("deviceId", transaction.getDeviceId()); |
| 330 | 330 | jsonObject.put("channelId", transaction.getChannelId()); |
| 331 | 331 | jsonObject.put("ssrc", transaction.getSsrc()); |
| 332 | - jsonObject.put("streamId", transaction.getStreamId()); | |
| 332 | + jsonObject.put("streamId", transaction.getStream()); | |
| 333 | 333 | objects.add(jsonObject); |
| 334 | 334 | } |
| 335 | 335 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java
| ... | ... | @@ -96,7 +96,7 @@ public class DownloadController { |
| 96 | 96 | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); |
| 97 | 97 | if (streamInfo != null) { |
| 98 | 98 | // 停止之前的下载 |
| 99 | - cmder.streamByeCmd(deviceId, channelId); | |
| 99 | + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream()); | |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | 102 | MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); |
| ... | ... | @@ -114,7 +114,7 @@ public class DownloadController { |
| 114 | 114 | |
| 115 | 115 | cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> { |
| 116 | 116 | logger.info("收到订阅消息: " + response.toJSONString()); |
| 117 | - playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid.toString()); | |
| 117 | + playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid); | |
| 118 | 118 | }, event -> { |
| 119 | 119 | RequestMessage msg = new RequestMessage(); |
| 120 | 120 | msg.setId(uuid); |
| ... | ... | @@ -130,11 +130,12 @@ public class DownloadController { |
| 130 | 130 | @ApiImplicitParams({ |
| 131 | 131 | @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class), |
| 132 | 132 | @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class), |
| 133 | + @ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class), | |
| 133 | 134 | }) |
| 134 | - @GetMapping("/stop/{deviceId}/{channelId}") | |
| 135 | - public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) { | |
| 135 | + @GetMapping("/stop/{deviceId}/{channelId}/{stream}") | |
| 136 | + public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { | |
| 136 | 137 | |
| 137 | - cmder.streamByeCmd(deviceId, channelId); | |
| 138 | + cmder.streamByeCmd(deviceId, channelId, stream); | |
| 138 | 139 | |
| 139 | 140 | if (logger.isDebugEnabled()) { |
| 140 | 141 | logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId)); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
| ... | ... | @@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory; |
| 18 | 18 | import org.springframework.beans.factory.annotation.Autowired; |
| 19 | 19 | import org.springframework.http.HttpStatus; |
| 20 | 20 | import org.springframework.http.ResponseEntity; |
| 21 | +import org.springframework.util.StringUtils; | |
| 21 | 22 | import org.springframework.web.bind.annotation.CrossOrigin; |
| 22 | 23 | import org.springframework.web.bind.annotation.GetMapping; |
| 23 | 24 | import org.springframework.web.bind.annotation.PathVariable; |
| ... | ... | @@ -75,52 +76,8 @@ public class PlaybackController { |
| 75 | 76 | if (logger.isDebugEnabled()) { |
| 76 | 77 | logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| 77 | 78 | } |
| 78 | - String uuid = UUID.randomUUID().toString(); | |
| 79 | - String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; | |
| 80 | - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L); | |
| 81 | - Device device = storager.queryVideoDevice(deviceId); | |
| 82 | - if (device == null) { | |
| 83 | - result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); | |
| 84 | - return result; | |
| 85 | - } | |
| 86 | - MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); | |
| 87 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); | |
| 88 | - | |
| 89 | - // 超时处理 | |
| 90 | - result.onTimeout(()->{ | |
| 91 | - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); | |
| 92 | - RequestMessage msg = new RequestMessage(); | |
| 93 | - msg.setId(uuid); | |
| 94 | - msg.setKey(key); | |
| 95 | - msg.setData("Timeout"); | |
| 96 | - resultHolder.invokeResult(msg); | |
| 97 | - }); | |
| 98 | - | |
| 99 | - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); | |
| 100 | - if (streamInfo != null) { | |
| 101 | - // 停止之前的回放 | |
| 102 | - cmder.streamByeCmd(deviceId, channelId); | |
| 103 | - } | |
| 104 | - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result); | |
| 105 | - | |
| 106 | - if (newMediaServerItem == null) { | |
| 107 | - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); | |
| 108 | - RequestMessage msg = new RequestMessage(); | |
| 109 | - msg.setId(uuid); | |
| 110 | - msg.setKey(key); | |
| 111 | - msg.setData("Timeout"); | |
| 112 | - resultHolder.invokeResult(msg); | |
| 113 | - return result; | |
| 114 | - } | |
| 115 | 79 | |
| 116 | - cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> { | |
| 117 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 118 | - playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString()); | |
| 119 | - }, event -> { | |
| 120 | - RequestMessage msg = new RequestMessage(); | |
| 121 | - msg.setId(uuid); | |
| 122 | - msg.setKey(key); | |
| 123 | - msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); | |
| 80 | + DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, msg->{ | |
| 124 | 81 | resultHolder.invokeResult(msg); |
| 125 | 82 | }); |
| 126 | 83 | |
| ... | ... | @@ -131,24 +88,31 @@ public class PlaybackController { |
| 131 | 88 | @ApiImplicitParams({ |
| 132 | 89 | @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class), |
| 133 | 90 | @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class), |
| 91 | + @ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class), | |
| 134 | 92 | }) |
| 135 | - @GetMapping("/stop/{deviceId}/{channelId}") | |
| 136 | - public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) { | |
| 93 | + @GetMapping("/stop/{deviceId}/{channelId}/{stream}") | |
| 94 | + public ResponseEntity<String> playStop( | |
| 95 | + @PathVariable String deviceId, | |
| 96 | + @PathVariable String channelId, | |
| 97 | + @PathVariable String stream) { | |
| 137 | 98 | |
| 138 | - cmder.streamByeCmd(deviceId, channelId); | |
| 99 | + cmder.streamByeCmd(deviceId, channelId, stream); | |
| 139 | 100 | |
| 140 | 101 | if (logger.isDebugEnabled()) { |
| 141 | 102 | logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId)); |
| 142 | 103 | } |
| 104 | + if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(channelId) || StringUtils.isEmpty(stream)) { | |
| 105 | + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); | |
| 106 | + } | |
| 143 | 107 | |
| 144 | 108 | if (deviceId != null && channelId != null) { |
| 145 | 109 | JSONObject json = new JSONObject(); |
| 146 | 110 | json.put("deviceId", deviceId); |
| 147 | 111 | json.put("channelId", channelId); |
| 148 | - return new ResponseEntity<String>(json.toString(), HttpStatus.OK); | |
| 112 | + return new ResponseEntity<>(json.toString(), HttpStatus.OK); | |
| 149 | 113 | } else { |
| 150 | 114 | logger.warn("设备录像回放停止API调用失败!"); |
| 151 | - return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); | |
| 115 | + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); | |
| 152 | 116 | } |
| 153 | 117 | } |
| 154 | 118 | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
| ... | ... | @@ -103,7 +103,7 @@ public class ApiStreamController { |
| 103 | 103 | PlayResult play = playService.play(newMediaServerItem, serial, code, (mediaServerItem, response)->{ |
| 104 | 104 | StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code); |
| 105 | 105 | JSONObject result = new JSONObject(); |
| 106 | - result.put("StreamID", streamInfo.getStreamId()); | |
| 106 | + result.put("StreamID", streamInfo.getStream()); | |
| 107 | 107 | result.put("DeviceID", device.getDeviceId()); |
| 108 | 108 | result.put("ChannelID", code); |
| 109 | 109 | result.put("ChannelName", deviceChannel.getName()); |
| ... | ... | @@ -177,7 +177,7 @@ public class ApiStreamController { |
| 177 | 177 | result.put("error","未找到流信息"); |
| 178 | 178 | return result; |
| 179 | 179 | } |
| 180 | - cmder.streamByeCmd(serial, code); | |
| 180 | + cmder.streamByeCmd(serial, code, streamInfo.getStream()); | |
| 181 | 181 | redisCatchStorage.stopPlay(streamInfo); |
| 182 | 182 | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| 183 | 183 | return null; | ... | ... |
src/main/resources/logback-spring-local.xml
| ... | ... | @@ -83,7 +83,7 @@ |
| 83 | 83 | <logger name="com.genersoft.iot.vmp.storager.dao" level="INFO"> |
| 84 | 84 | <appender-ref ref="STDOUT"/> |
| 85 | 85 | </logger> |
| 86 | - <logger name="com.genersoft.iot.vmp.gb28181" level="DEBUG"> | |
| 86 | + <logger name="com.genersoft.iot.vmp.gb28181" level="INFO"> | |
| 87 | 87 | <appender-ref ref="STDOUT"/> |
| 88 | 88 | </logger> |
| 89 | 89 | ... | ... |
web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -307,7 +307,7 @@ export default { |
| 307 | 307 | this.isLoging = false; |
| 308 | 308 | // this.videoUrl = streamInfo.rtc; |
| 309 | 309 | this.videoUrl = this.getUrlByStreamInfo(streamInfo); |
| 310 | - this.streamId = streamInfo.streamId; | |
| 310 | + this.streamId = streamInfo.stream; | |
| 311 | 311 | this.app = streamInfo.app; |
| 312 | 312 | this.mediaServerId = streamInfo.mediaServerId; |
| 313 | 313 | this.playFromStreamInfo(false, streamInfo) |
| ... | ... | @@ -485,8 +485,9 @@ export default { |
| 485 | 485 | }).then(function (res) { |
| 486 | 486 | var streamInfo = res.data; |
| 487 | 487 | that.app = streamInfo.app; |
| 488 | - that.streamId = streamInfo.streamId; | |
| 488 | + that.streamId = streamInfo.stream; | |
| 489 | 489 | that.mediaServerId = streamInfo.mediaServerId; |
| 490 | + that.ssrc = streamInfo.ssrc; | |
| 490 | 491 | that.videoUrl = that.getUrlByStreamInfo(streamInfo); |
| 491 | 492 | that.recordPlay = true; |
| 492 | 493 | }); |
| ... | ... | @@ -497,7 +498,7 @@ export default { |
| 497 | 498 | this.videoUrl = ''; |
| 498 | 499 | this.$axios({ |
| 499 | 500 | method: 'get', |
| 500 | - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId | |
| 501 | + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId | |
| 501 | 502 | }).then(function (res) { |
| 502 | 503 | if (callback) callback() |
| 503 | 504 | }); |
| ... | ... | @@ -517,7 +518,7 @@ export default { |
| 517 | 518 | }).then(function (res) { |
| 518 | 519 | var streamInfo = res.data; |
| 519 | 520 | that.app = streamInfo.app; |
| 520 | - that.streamId = streamInfo.streamId; | |
| 521 | + that.streamId = streamInfo.stream; | |
| 521 | 522 | that.mediaServerId = streamInfo.mediaServerId; |
| 522 | 523 | that.videoUrl = that.getUrlByStreamInfo(streamInfo); |
| 523 | 524 | that.recordPlay = true; |
| ... | ... | @@ -529,7 +530,7 @@ export default { |
| 529 | 530 | this.videoUrl = ''; |
| 530 | 531 | this.$axios({ |
| 531 | 532 | method: 'get', |
| 532 | - url: '/api/download/stop/' + this.deviceId + "/" + this.channelId | |
| 533 | + url: '/api/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId | |
| 533 | 534 | }).then(function (res) { |
| 534 | 535 | if (callback) callback() |
| 535 | 536 | }); |
| ... | ... | @@ -539,8 +540,6 @@ export default { |
| 539 | 540 | let that = this; |
| 540 | 541 | this.$axios({ |
| 541 | 542 | method: 'post', |
| 542 | - // url: '/api/ptz/' + this.deviceId + '/' + this.channelId + '?leftRight=' + leftRight + '&upDown=' + upDown + | |
| 543 | - // '&inOut=' + zoom + '&moveSpeed=50&zoomSpeed=50' | |
| 544 | 543 | url: '/api/ptz/control/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&horizonSpeed=' + this.controSpeed + '&verticalSpeed=' + this.controSpeed + '&zoomSpeed=' + this.controSpeed |
| 545 | 544 | }).then(function (res) {}); |
| 546 | 545 | }, | ... | ... |