Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0
# Conflicts:
# src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
# src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
# src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| | |
| | | ZLMä½¿ç¨ææ¡£ [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit) |
| | | > wvpææ¡£ç±giteeæä¾æå¡ï¼å¦æéå°æä¸å¼è¯·å¤å·æ°å 次ã |
| | | |
| | | # 社群å°å |
| | | # ä»è´¹ç¤¾ç¾¤ |
| | | [](https://t.zsxq.com/0d8VAD3Dm) |
| | | > æ¶è´¹æ¯ä¸ºäºæä¾æ´å¥½çæå¡ï¼ä¹æ¯å¯¹ä½è
æ´å¤§çæ¿å±ãå å
¥æççç¨æ·ä¸å¤©åå¯ä»¥ç§ä¿¡æçä¸å¾®ä¿¡å·ï¼æä¼æå¤§å®¶å
¥ç¾¤ãå å
¥ä¸å¤©å
䏿»¡æå¯ä»¥ç´æ¥é款ï¼å¤§å®¶ä¸éè¦æé¡¾èï¼æ¥ç½å«ä¸å¤©ä¹ä¸æ¯ä¸å¯ä»¥ã |
| | | |
| | |
| | | - [X] æ¯ææå
坿§è¡jaråwar |
| | | - [X] æ¯æè·¨å请æ±ï¼æ¯æåå端å离é¨ç½² |
| | | - [X] æ¯æMysqlï¼Postgresqlï¼éä»çæ°æ®åº |
| | | - [X] æ¯æOnvif(ç®åå¨onvif忝ï¼éè¦å®è£
onvifæå¡ï¼æå¡è¯·å¨ç¥è¯æçè·å) |
| | | |
| | | # ææåè®® |
| | | æ¬é¡¹ç®èªæä»£ç 使ç¨å®½æ¾çMITåè®®ï¼å¨ä¿ççæä¿¡æ¯çæ
åµä¸å¯ä»¥èªç±åºç¨äºåèªåç¨ãéåä¸ç项ç®ã 使¯æ¬é¡¹ç®ä¹é¶ç¢ç使ç¨äºä¸äºå
¶ä»ç弿ºä»£ç ï¼å¨åç¨çæ
åµä¸è¯·èªè¡æ¿ä»£æåé¤ï¼ ç±äºä½¿ç¨æ¬é¡¹ç®è产ççåä¸çº 纷æä¾µæè¡ä¸ºä¸æ¦ä¸æ¬é¡¹ç®åå¼åè
æ å
³ï¼è¯·èªè¡æ¿æ
æ³å¾é£é©ã å¨ä½¿ç¨æ¬é¡¹ç®ä»£ç æ¶ï¼ä¹åºè¯¥å¨ææåè®®ä¸åæ¶è¡¨ææ¬é¡¹ç®ä¾èµçç¬¬ä¸æ¹åºçåè®® |
| | |
| | | - å®å
¨å¼æºï¼ä¸ä½¿ç¨MIT许å¯åè®®ãä¿ççæçæ
åµä¸å¯ä»¥ç¨äºåä¸é¡¹ç®ã |
| | | - æ¯æå¤æµåªä½èç¹è´è½½åè¡¡ã |
| | | |
| | | # 社群 |
| | | # ä»è´¹ç¤¾ç¾¤ |
| | | [](https://t.zsxq.com/0d8VAD3Dm) |
| | | > æ¶è´¹æ¯ä¸ºäºæä¾æ´å¥½çæå¡ï¼ä¹æ¯å¯¹ä½è
æ´å¤§çæ¿å±ãå å
¥æççç¨æ·ä¸å¤©åå¯ä»¥ç§ä¿¡æçä¸å¾®ä¿¡å·ï¼æä¼æå¤§å®¶å
¥ç¾¤ãå å
¥ä¸å¤©å
䏿»¡æå¯ä»¥ç´æ¥é款ï¼å¤§å®¶ä¸éè¦æé¡¾èï¼æ¥ç½å«ä¸å¤©ä¹ä¸æ¯ä¸å¯ä»¥ã |
| | | |
| | |
| | | - [X] 注å |
| | | - [X] 注é |
| | | - [X] 宿¶è§é³é¢ç¹æ |
| | | - [ ] è®¾å¤æ§å¶ |
| | | - [ ] äºå°æ§å¶ |
| | | - [X] è®¾å¤æ§å¶ |
| | | - [X] äºå°æ§å¶ |
| | | - [ ] è¿ç¨å¯å¨ |
| | | - [ ] å½åæ§å¶ |
| | | - [ ] æ¥è¦å¸é²/æ¤é² |
| | | - [ ] æ¥è¦å¤ä½ |
| | | - [ ] 强å¶å
³é®å¸§ |
| | | - [ ] ææ¡æ¾å¤§ |
| | | - [ ] ææ¡ç¼©å° |
| | | - [ ] çå®ä½æ§å¶ |
| | | - [X] å½åæ§å¶ |
| | | - [X] æ¥è¦å¸é²/æ¤é² |
| | | - [X] æ¥è¦å¤ä½ |
| | | - [X] 强å¶å
³é®å¸§ |
| | | - [X] ææ¡æ¾å¤§ |
| | | - [X] ææ¡ç¼©å° |
| | | - [X] çå®ä½æ§å¶ |
| | | - [ ] 设å¤é
ç½® |
| | | - [ ] æ¥è¦äºä»¶éç¥ååå |
| | | - [X] 设å¤ç®å½è®¢é
|
| | |
| | | - [X] 设å¤ç®å½æ¥è¯¢ |
| | | - [X] 设å¤ç¶ææ¥è¯¢ |
| | | - [ ] 设å¤é
ç½®æ¥è¯¢ |
| | | - [ ] 设å¤é¢ç½®ä½æ¥è¯¢ |
| | | - [X] 设å¤é¢ç½®ä½æ¥è¯¢ |
| | | - [X] ç¶æä¿¡æ¯æ¥é |
| | | - [X] 设å¤è§é³é¢æä»¶æ£ç´¢ |
| | | - [X] åå²è§é³é¢çåæ¾ |
| | |
| | | - [x] æå |
| | | - [x] è¿/é |
| | | - [x] 忢 |
| | | - [ ] è§é³é¢æä»¶ä¸è½½ |
| | | - [X] è§é³é¢æä»¶ä¸è½½ |
| | | - [ ] ~~æ ¡æ¶~~ |
| | | - [X] 订é
åéç¥ |
| | | - [X] äºä»¶è®¢é
|
| | |
| | | |
| | | <groupId>com.genersoft</groupId> |
| | | <artifactId>wvp-pro</artifactId> |
| | | <version>2.6.8</version> |
| | | <version>2.6.9</version> |
| | | <name>web video platform</name> |
| | | <description>彿 28181è§é¢å¹³å°</description> |
| | | <packaging>${project.packaging}</packaging> |
| | |
| | | change createTime create_time varchar(50) null; |
| | | |
| | | alter table gb_stream |
| | | add constraint gb_stream_pk |
| | | primary key (gbStreamId); |
| | | |
| | | alter table gb_stream |
| | | change gbStreamId gb_stream_id int auto_increment; |
| | | |
| | | alter table gb_stream |
New file |
| | |
| | | package com.genersoft.iot.vmp.common; |
| | | |
| | | public interface GeneralCallback<T>{ |
| | | void run(int code, String msg, T data); |
| | | } |
| | |
| | | public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
|
| | |
|
| | | /**
|
| | | * redis éç¥å¹³å°å
³éæ¨æµ
|
| | | */
|
| | | public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
|
| | |
|
| | | /**
|
| | | * redis æ¶æ¯è¯·æ±ææçå¨çº¿éé
|
| | | */
|
| | | public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
|
| | |
| | | @Autowired |
| | | private RedisPushStreamResponseListener redisPushStreamResponseListener; |
| | | |
| | | @Autowired |
| | | private RedisCloseStreamMsgListener redisCloseStreamMsgListener; |
| | | |
| | | |
| | | /** |
| | | * redisæ¶æ¯çå¬å¨å®¹å¨ å¯ä»¥æ·»å å¤ä¸ªçå¬ä¸åè¯é¢çredisçå¬å¨ï¼åªéè¦ææ¶æ¯çå¬å¨åç¸åºçæ¶æ¯è®¢é
å¤çå¨ç»å®ï¼è¯¥æ¶æ¯çå¬å¨ |
| | |
| | | container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE)); |
| | | container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE)); |
| | | container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE)); |
| | | container.addMessageListener(redisCloseStreamMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE)); |
| | | return container; |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.bean; |
| | | |
| | | import javax.sdp.SessionDescription; |
| | | |
| | | /** |
| | | * 28181 çSDPè§£æå¨ |
| | | */ |
| | | public class Gb28181Sdp { |
| | | private SessionDescription baseSdb; |
| | | private String ssrc; |
| | | |
| | | private String mediaDescription; |
| | | |
| | | public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) { |
| | | Gb28181Sdp gb28181Sdp = new Gb28181Sdp(); |
| | | gb28181Sdp.setBaseSdb(baseSdb); |
| | | gb28181Sdp.setSsrc(ssrc); |
| | | gb28181Sdp.setMediaDescription(mediaDescription); |
| | | return gb28181Sdp; |
| | | } |
| | | |
| | | |
| | | public SessionDescription getBaseSdb() { |
| | | return baseSdb; |
| | | } |
| | | |
| | | public void setBaseSdb(SessionDescription baseSdb) { |
| | | this.baseSdb = baseSdb; |
| | | } |
| | | |
| | | public String getSsrc() { |
| | | return ssrc; |
| | | } |
| | | |
| | | public void setSsrc(String ssrc) { |
| | | this.ssrc = ssrc; |
| | | } |
| | | |
| | | public String getMediaDescription() { |
| | | return mediaDescription; |
| | | } |
| | | |
| | | public void setMediaDescription(String mediaDescription) { |
| | | this.mediaDescription = mediaDescription; |
| | | } |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.gb28181.session; |
| | | |
| | | import com.genersoft.iot.vmp.conf.SipConfig; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Component; |
| | |
| | | @Autowired |
| | | private SipConfig sipConfig; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | |
| | | public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) { |
| | | String ssrcPrefix = sipConfig.getDomain().substring(3, 8); |
| | | String redisKey = SSRC_INFO_KEY + mediaServerId; |
| | | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; |
| | | List<String> ssrcList = new ArrayList<>(); |
| | | for (int i = 1; i < MAX_STREAM_COUNT; i++) { |
| | | String ssrc = String.format("%s%04d", ssrcPrefix, i); |
| | |
| | | return; |
| | | } |
| | | String sn = ssrc.substring(1); |
| | | String redisKey = SSRC_INFO_KEY + mediaServerId; |
| | | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; |
| | | redisTemplate.opsForSet().add(redisKey, sn); |
| | | } |
| | | |
| | |
| | | */ |
| | | private String getSN(String mediaServerId) { |
| | | String sn = null; |
| | | String redisKey = SSRC_INFO_KEY + mediaServerId; |
| | | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; |
| | | Long size = redisTemplate.opsForSet().size(redisKey); |
| | | if (size == null || size == 0) { |
| | | throw new RuntimeException("ssrcå·²ç»ç¨å®"); |
| | |
| | | * @param mediaServerId æµåªä½æå¡ID |
| | | */ |
| | | public boolean hasMediaServerSSRC(String mediaServerId) { |
| | | String redisKey = SSRC_INFO_KEY + mediaServerId; |
| | | String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; |
| | | return redisTemplate.opsForSet().members(redisKey) != null; |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢ssrcæ¯å¦å¯ç¨ |
| | | * |
| | | * @param mediaServerId |
| | | * @param ssrc |
| | | * @return |
| | | */ |
| | | public boolean checkSsrc(String mediaServerId, String ssrc) { |
| | | String sn = ssrc.substring(1); |
| | | String redisKey = SSRC_INFO_KEY + mediaServerId; |
| | | return redisTemplate.opsForSet().isMember(redisKey, sn) != null; |
| | | } |
| | | } |
| | |
| | |
|
| | | public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
|
| | |
|
| | | public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
|
| | |
|
| | | public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
|
| | |
|
| | | public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
|
| | |
|
| | | public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
|
| | | public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
|
| | |
|
| | | public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
|
| | |
|
| | |
| | | parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); |
| | | //via |
| | | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| | | ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), |
| | | parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag()); |
| | | ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), |
| | | Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag()); |
| | | viaHeader.setRPort(); |
| | | viaHeaders.add(viaHeader); |
| | | //from |
| | |
| | | }
|
| | | subscribe.removeSubscribe(hookSubscribe);
|
| | | });
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
| | |
|
| | | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
| | | ResponseEvent responseEvent = (ResponseEvent) event.event;
|
| | |
| | | });
|
| | | });
|
| | |
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
|
| | |
|
| | | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
| | | ResponseEvent responseEvent = (ResponseEvent) event.event;
|
| | | SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
| | | String contentString =new String(response.getRawContent());
|
| | | int ssrcIndex = contentString.indexOf("y=");
|
| | | String ssrc=ssrcInfo.getSsrc();
|
| | | if (ssrcIndex >= 0) {
|
| | | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
|
| | | }
|
| | | String ssrc = SipUtils.getSsrcFromSdp(contentString);
|
| | | streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
|
| | | okEvent.response(event);
|
| | | });
|
| | |
| | | // è§£æsdpæ¶æ¯, 使ç¨jainsip èªå¸¦çsdpè§£ææ¹å¼ |
| | | String contentString = new String(request.getRawContent()); |
| | | |
| | | // jainSip䏿¯æy=åæ®µï¼ ç§»é¤ä»¥è§£æã |
| | | // æ£æ¥æ¯å¦æyåæ®µ |
| | | int ssrcIndex = contentString.indexOf("y="); |
| | | |
| | | SessionDescription sdp; |
| | | if (ssrcIndex >= 0) { |
| | | //ssrcè§å®é¿åº¦ä¸º10个åèï¼ä¸åä½ä¸é¿åº¦ä»¥é¿å
åç»è¿æâf=âåæ®µ |
| | | String substring = contentString.substring(0, ssrcIndex); |
| | | sdp = SdpFactory.getInstance().createSessionDescription(substring); |
| | | } else { |
| | | sdp = SdpFactory.getInstance().createSessionDescription(contentString); |
| | | } |
| | | Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); |
| | | SessionDescription sdp = gb28181Sdp.getBaseSdb(); |
| | | String sessionName = sdp.getSessionName().getValue(); |
| | | |
| | | Long startTime = null; |
| | |
| | | } |
| | | |
| | | String ssrc; |
| | | if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { |
| | | if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { |
| | | // ä¸çº§å¹³å°ç¹ææ¶ä¸ä½¿ç¨ä¸çº§å¹³å°æå®çssrcï¼ä½¿ç¨èªå®ä¹çssrcï¼åè彿 ææ¡£-ç¹æå¤å设å¤åªä½æµSSRCå¤çæ¹å¼ |
| | | ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); |
| | | }else { |
| | | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); |
| | | ssrc = gb28181Sdp.getSsrc(); |
| | | } |
| | | String streamTypeStr = null; |
| | | if (mediaTransmissionTCP) { |
| | |
| | | } else if (gbStream != null) { |
| | | |
| | | String ssrc; |
| | | if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { |
| | | if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { |
| | | // ä¸çº§å¹³å°ç¹ææ¶ä¸ä½¿ç¨ä¸çº§å¹³å°æå®çssrcï¼ä½¿ç¨èªå®ä¹çssrcï¼åè彿 ææ¡£-ç¹æå¤å设å¤åªä½æµSSRCå¤çæ¹å¼ |
| | | ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); |
| | | }else { |
| | | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); |
| | | ssrc = gb28181Sdp.getSsrc(); |
| | | } |
| | | |
| | | if("push".equals(gbStream.getStreamType())) { |
| | |
| | | } |
| | | String contentString = new String(request.getRawContent()); |
| | | // jainSip䏿¯æy=åæ®µï¼ ç§»é¤ç§»é¤ä»¥è§£æã |
| | | String substring = contentString; |
| | | String ssrc = "0000000404"; |
| | | int ssrcIndex = contentString.indexOf("y="); |
| | | if (ssrcIndex > 0) { |
| | | substring = contentString.substring(0, ssrcIndex); |
| | | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); |
| | | } |
| | | ssrcIndex = substring.indexOf("f="); |
| | | if (ssrcIndex > 0) { |
| | | substring = contentString.substring(0, ssrcIndex); |
| | | } |
| | | SessionDescription sdp = null; |
| | | |
| | | try { |
| | | sdp = SdpFactory.getInstance().createSessionDescription(substring); |
| | | Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); |
| | | SessionDescription sdp = gb28181Sdp.getBaseSdb(); |
| | | // è·åæ¯æçæ ¼å¼ |
| | | Vector mediaDescriptions = sdp.getMediaDescriptions(true); |
| | | // æ¥çæ¯å¦æ¯æPS è´è½½96 |
| | |
| | | } |
| | | }else { |
| | | addChannelMap.put(channel.getChannelId(), channel); |
| | | if (userSetting.getDeviceStatusNotify()) { |
| | | // åéredisæ¶æ¯ |
| | | redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); |
| | | } |
| | | |
| | | if (addChannelMap.keySet().size() > 300) { |
| | | executeSaveForAdd(); |
| | | } |
| | |
| | | // å é¤ |
| | | logger.info("[æ¶å°å é¤éééç¥] æ¥èªè®¾å¤: {}, éé {}", device.getDeviceId(), channel.getChannelId()); |
| | | deleteChannelList.add(channel); |
| | | if (userSetting.getDeviceStatusNotify()) { |
| | | // åéredisæ¶æ¯ |
| | | redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false); |
| | | } |
| | | if (deleteChannelList.size() > 300) { |
| | | executeSaveForDelete(); |
| | | } |
| | |
| | | if (addChannelMap.keySet().size() > 300) { |
| | | executeSaveForAdd(); |
| | | } |
| | | if (userSetting.getDeviceStatusNotify()) { |
| | | // åéredisæ¶æ¯ |
| | | redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | |
| | | mobilePosition.setDeviceId(device.getDeviceId()); |
| | | mobilePosition.setChannelId(channelId); |
| | | String time = XmlUtil.getText(rootElement, "Time"); |
| | | mobilePosition.setTime(time); |
| | | if (ObjectUtils.isEmpty(time)){ |
| | | mobilePosition.setTime(DateUtil.getNow()); |
| | | }else { |
| | | mobilePosition.setTime(SipUtils.parseTime(time)); |
| | | } |
| | | |
| | | mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); |
| | | mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); |
| | | if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) { |
| | |
| | | |
| | | // åéredisæ¶æ¯ã éç¥ä½ç½®ä¿¡æ¯çåå |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", time); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceId); |
| | | jsonObject.put("code", channelId); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | |
| | | storager.updateChannelPosition(deviceChannel); |
| | | // åéredisæ¶æ¯ã éç¥ä½ç½®ä¿¡æ¯çåå |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", mobilePosition.getTime()); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | |
| | | |
| | | // åéredisæ¶æ¯ã éç¥ä½ç½®ä¿¡æ¯çåå |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", mobilePosition.getTime()); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; |
| | | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| | | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| | | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | |
| | | } |
| | | mobilePosition.setDeviceId(sipMsgInfo.getDevice().getDeviceId()); |
| | | mobilePosition.setChannelId(getText(rootElementAfterCharset, "DeviceID")); |
| | | mobilePosition.setTime(getText(rootElementAfterCharset, "Time")); |
| | | String time = getText(rootElementAfterCharset, "Time"); |
| | | if (ObjectUtils.isEmpty(time)){ |
| | | mobilePosition.setTime(DateUtil.getNow()); |
| | | }else { |
| | | mobilePosition.setTime(SipUtils.parseTime(time)); |
| | | } |
| | | mobilePosition.setLongitude(Double.parseDouble(getText(rootElementAfterCharset, "Longitude"))); |
| | | mobilePosition.setLatitude(Double.parseDouble(getText(rootElementAfterCharset, "Latitude"))); |
| | | if (NumericUtil.isDouble(getText(rootElementAfterCharset, "Speed"))) { |
| | |
| | | |
| | | // åéredisæ¶æ¯ã éç¥ä½ç½®ä¿¡æ¯çåå |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", mobilePosition.getTime()); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| | | import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| | | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| | | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| | | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.utils.GpsUtil; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | | import org.dom4j.DocumentException; |
| | | import org.dom4j.Element; |
| | |
| | | @Autowired |
| | | private IDeviceChannelService deviceChannelService; |
| | | |
| | | @Autowired |
| | | private DeferredResultHolder resultHolder; |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | | responseMessageHandler.addHandler(cmdType, this); |
| | |
| | | } |
| | | mobilePosition.setDeviceId(device.getDeviceId()); |
| | | mobilePosition.setChannelId(getText(rootElement, "DeviceID")); |
| | | mobilePosition.setTime(getText(rootElement, "Time")); |
| | | //å
¼å®¹ISO 8601æ ¼å¼æ¶é´ |
| | | String time = getText(rootElement, "Time"); |
| | | if (ObjectUtils.isEmpty(time)){ |
| | | mobilePosition.setTime(DateUtil.getNow()); |
| | | }else { |
| | | mobilePosition.setTime(SipUtils.parseTime(time)); |
| | | } |
| | | mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); |
| | | mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); |
| | | if (NumericUtil.isDouble(getText(rootElement, "Speed"))) { |
| | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | |
| | | storager.updateChannelPosition(deviceChannel); |
| | | |
| | | String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId(); |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(key); |
| | | msg.setData(mobilePosition); |
| | | resultHolder.invokeAllResult(msg); |
| | | |
| | | // åéredisæ¶æ¯ã éç¥ä½ç½®ä¿¡æ¯çåå |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", mobilePosition.getTime()); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; |
| | | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| | | import gov.nist.javax.sip.ResponseEventExt; |
| | | import gov.nist.javax.sip.message.SIPResponse; |
| | | import org.slf4j.Logger; |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.sdp.SdpFactory; |
| | | import javax.sdp.SdpParseException; |
| | | import javax.sdp.SessionDescription; |
| | | import javax.sip.InvalidArgumentException; |
| | |
| | | ResponseEventExt event = (ResponseEventExt)evt; |
| | | |
| | | String contentString = new String(response.getRawContent()); |
| | | // jainSip䏿¯æy=åæ®µï¼ ç§»é¤ä»¥è§£æã |
| | | int ssrcIndex = contentString.indexOf("y="); |
| | | // æ£æ¥æ¯å¦æyåæ®µ |
| | | SessionDescription sdp; |
| | | if (ssrcIndex >= 0) { |
| | | //ssrcè§å®é¿åº¦ä¸º10åèï¼ä¸åä½ä¸é¿åº¦ä»¥é¿å
åç»è¿æâf=âåæ®µ |
| | | String substring = contentString.substring(0, contentString.indexOf("y=")); |
| | | sdp = SdpFactory.getInstance().createSessionDescription(substring); |
| | | } else { |
| | | sdp = SdpFactory.getInstance().createSessionDescription(contentString); |
| | | } |
| | | |
| | | Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); |
| | | SessionDescription sdp = gb28181Sdp.getBaseSdb(); |
| | | SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); |
| | | Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response); |
| | | |
| | |
| | | package com.genersoft.iot.vmp.gb28181.utils; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; |
| | | import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.utils.GitUtil; |
| | | import gov.nist.javax.sip.address.AddressImpl; |
| | | import gov.nist.javax.sip.address.SipUri; |
| | | import gov.nist.javax.sip.header.Subject; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | | import org.apache.commons.lang3.RandomStringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.util.ObjectUtils; |
| | | |
| | | import javax.sdp.SdpFactory; |
| | | import javax.sdp.SdpParseException; |
| | | import javax.sdp.SessionDescription; |
| | | import javax.sip.PeerUnavailableException; |
| | | import javax.sip.SipFactory; |
| | | import javax.sip.header.FromHeader; |
| | |
| | | import javax.sip.header.UserAgentHeader; |
| | | import javax.sip.message.Request; |
| | | import java.text.ParseException; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | |
| | | * @createTime 2021å¹´09æ27æ¥ 15:12:00 |
| | | */ |
| | | public class SipUtils { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(SipUtils.class); |
| | | |
| | | public static String getUserIdFromFromHeader(Request request) { |
| | | FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); |
| | |
| | | } |
| | | |
| | | public static String getNewViaTag() { |
| | | return "z9hG4bK" + System.currentTimeMillis(); |
| | | return "z9hG4bK" + RandomStringUtils.randomNumeric(10); |
| | | } |
| | | |
| | | public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException { |
| | |
| | | } |
| | | return deviceChannel; |
| | | } |
| | | |
| | | public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException { |
| | | |
| | | // jainSip䏿¯æy= f=åæ®µï¼ ç§»é¤ä»¥è§£æã |
| | | int ssrcIndex = sdpStr.indexOf("y="); |
| | | int mediaDescriptionIndex = sdpStr.indexOf("f="); |
| | | // æ£æ¥æ¯å¦æyåæ®µ |
| | | SessionDescription sdp; |
| | | String ssrc = null; |
| | | String mediaDescription = null; |
| | | if (mediaDescriptionIndex == 0 && ssrcIndex == 0) { |
| | | sdp = SdpFactory.getInstance().createSessionDescription(sdpStr); |
| | | }else { |
| | | String lines[] = sdpStr.split("\\r?\\n"); |
| | | StringBuilder sdpBuffer = new StringBuilder(); |
| | | for (String line : lines) { |
| | | if (line.trim().startsWith("y=")) { |
| | | ssrc = line.substring(2); |
| | | }else if (line.trim().startsWith("f=")) { |
| | | mediaDescription = line.substring(2); |
| | | }else { |
| | | sdpBuffer.append(line.trim()).append("\r\n"); |
| | | } |
| | | } |
| | | sdp = SdpFactory.getInstance().createSessionDescription(sdpBuffer.toString()); |
| | | } |
| | | return Gb28181Sdp.getInstance(sdp, ssrc, mediaDescription); |
| | | } |
| | | |
| | | public static String getSsrcFromSdp(String sdpStr) { |
| | | |
| | | // jainSip䏿¯æy= f=åæ®µï¼ ç§»é¤ä»¥è§£æã |
| | | int ssrcIndex = sdpStr.indexOf("y="); |
| | | if (ssrcIndex == 0) { |
| | | return null; |
| | | } |
| | | String lines[] = sdpStr.split("\\r?\\n"); |
| | | for (String line : lines) { |
| | | if (line.trim().startsWith("y=")) { |
| | | return line.substring(2); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String parseTime(String timeStr) { |
| | | if (ObjectUtils.isEmpty(timeStr)){ |
| | | return null; |
| | | } |
| | | System.out.println(timeStr); |
| | | LocalDateTime localDateTime; |
| | | try { |
| | | localDateTime = LocalDateTime.parse(timeStr); |
| | | }catch (DateTimeParseException e) { |
| | | try { |
| | | localDateTime = LocalDateTime.parse(timeStr, DateUtil.formatterISO8601); |
| | | }catch (DateTimeParseException e2) { |
| | | logger.error("[æ ¼å¼åæ¶é´] æ æ³æ ¼å¼åæ¶é´ï¼ {}", timeStr); |
| | | return null; |
| | | } |
| | | } |
| | | return localDateTime.format(DateUtil.formatterISO8601); |
| | | } |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.common.CommonCallback; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | @Schema(description = "ææµå°å") |
| | | private String url; |
| | | @Schema(description = "ææµå°å") |
| | | private String src_url; |
| | | private String srcUrl; |
| | | @Schema(description = "ç®æ å°å") |
| | | private String dst_url; |
| | | private String dstUrl; |
| | | @Schema(description = "è¶
æ¶æ¶é´") |
| | | private int timeout_ms; |
| | | private int timeoutMs; |
| | | @Schema(description = "ffmpeg模æ¿KEY") |
| | | private String ffmpeg_cmd_key; |
| | | private String ffmpegCmdKey; |
| | | @Schema(description = "rtspææµæ¶ï¼ææµæ¹å¼ï¼0ï¼tcpï¼1ï¼udpï¼2ï¼ç»æ") |
| | | private String rtp_type; |
| | | private String rtpType; |
| | | @Schema(description = "æ¯å¦å¯ç¨") |
| | | private boolean enable; |
| | | @Schema(description = "æ¯å¦å¯ç¨é³é¢") |
| | | private boolean enable_audio; |
| | | private boolean enableAudio; |
| | | @Schema(description = "æ¯å¦å¯ç¨MP4") |
| | | private boolean enable_mp4; |
| | | private boolean enableMp4; |
| | | @Schema(description = "æ¯å¦ æ 人è§çæ¶å é¤") |
| | | private boolean enable_remove_none_reader; |
| | | private boolean enableRemoveNoneReader; |
| | | |
| | | @Schema(description = "æ¯å¦ æ 人è§çæ¶èªå¨åç¨") |
| | | private boolean enable_disable_none_reader; |
| | | @Schema(description = "å建æ¶é´") |
| | | private String createTime; |
| | | private boolean enableDisableNoneReader; |
| | | |
| | | public String getType() { |
| | | return type; |
| | |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getSrc_url() { |
| | | return src_url; |
| | | public String getSrcUrl() { |
| | | return srcUrl; |
| | | } |
| | | |
| | | public void setSrc_url(String src_url) { |
| | | this.src_url = src_url; |
| | | public void setSrcUrl(String src_url) { |
| | | this.srcUrl = src_url; |
| | | } |
| | | |
| | | public String getDst_url() { |
| | | return dst_url; |
| | | public String getDstUrl() { |
| | | return dstUrl; |
| | | } |
| | | |
| | | public void setDst_url(String dst_url) { |
| | | this.dst_url = dst_url; |
| | | public void setDstUrl(String dst_url) { |
| | | this.dstUrl = dst_url; |
| | | } |
| | | |
| | | public int getTimeout_ms() { |
| | | return timeout_ms; |
| | | public int getTimeoutMs() { |
| | | return timeoutMs; |
| | | } |
| | | |
| | | public void setTimeout_ms(int timeout_ms) { |
| | | this.timeout_ms = timeout_ms; |
| | | public void setTimeoutMs(int timeout_ms) { |
| | | this.timeoutMs = timeout_ms; |
| | | } |
| | | |
| | | public String getFfmpeg_cmd_key() { |
| | | return ffmpeg_cmd_key; |
| | | public String getFfmpegCmdKey() { |
| | | return ffmpegCmdKey; |
| | | } |
| | | |
| | | public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) { |
| | | this.ffmpeg_cmd_key = ffmpeg_cmd_key; |
| | | public void setFfmpegCmdKey(String ffmpeg_cmd_key) { |
| | | this.ffmpegCmdKey = ffmpeg_cmd_key; |
| | | } |
| | | |
| | | public String getRtp_type() { |
| | | return rtp_type; |
| | | public String getRtpType() { |
| | | return rtpType; |
| | | } |
| | | |
| | | public void setRtp_type(String rtp_type) { |
| | | this.rtp_type = rtp_type; |
| | | public void setRtpType(String rtp_type) { |
| | | this.rtpType = rtp_type; |
| | | } |
| | | |
| | | public boolean isEnable() { |
| | |
| | | this.enable = enable; |
| | | } |
| | | |
| | | public boolean isEnable_mp4() { |
| | | return enable_mp4; |
| | | public boolean isEnableMp4() { |
| | | return enableMp4; |
| | | } |
| | | |
| | | public void setEnable_mp4(boolean enable_mp4) { |
| | | this.enable_mp4 = enable_mp4; |
| | | public void setEnableMp4(boolean enable_mp4) { |
| | | this.enableMp4 = enable_mp4; |
| | | } |
| | | |
| | | @Override |
| | | public String getCreateTime() { |
| | | return createTime; |
| | | public boolean isEnableRemoveNoneReader() { |
| | | return enableRemoveNoneReader; |
| | | } |
| | | |
| | | @Override |
| | | public void setCreateTime(String createTime) { |
| | | this.createTime = createTime; |
| | | public void setEnableRemoveNoneReader(boolean enable_remove_none_reader) { |
| | | this.enableRemoveNoneReader = enable_remove_none_reader; |
| | | } |
| | | |
| | | public boolean isEnable_remove_none_reader() { |
| | | return enable_remove_none_reader; |
| | | public boolean isEnableDisableNoneReader() { |
| | | return enableDisableNoneReader; |
| | | } |
| | | |
| | | public void setEnable_remove_none_reader(boolean enable_remove_none_reader) { |
| | | this.enable_remove_none_reader = enable_remove_none_reader; |
| | | public void setEnableDisableNoneReader(boolean enable_disable_none_reader) { |
| | | this.enableDisableNoneReader = enable_disable_none_reader; |
| | | } |
| | | |
| | | public boolean isEnable_disable_none_reader() { |
| | | return enable_disable_none_reader; |
| | | public boolean isEnableAudio() { |
| | | return enableAudio; |
| | | } |
| | | |
| | | public void setEnable_disable_none_reader(boolean enable_disable_none_reader) { |
| | | this.enable_disable_none_reader = enable_disable_none_reader; |
| | | public void setEnableAudio(boolean enable_audio) { |
| | | this.enableAudio = enable_audio; |
| | | } |
| | | |
| | | public boolean isEnable_audio() { |
| | | return enable_audio; |
| | | } |
| | | |
| | | public void setEnable_audio(boolean enable_audio) { |
| | | this.enable_audio = enable_audio; |
| | | } |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.service; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.common.GeneralCallback; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| | |
| | | * ä¿åè§é¢ä»£ç |
| | | * @param param |
| | | */ |
| | | StreamInfo save(StreamProxyItem param); |
| | | void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback); |
| | | |
| | | /** |
| | | * æ·»å è§é¢ä»£çå°zlm |
| | |
| | | |
| | | @Override |
| | | public void offline(String deviceId, String reason) { |
| | | logger.error("[设å¤ç¦»çº¿]ï¼{}, deviceï¼{}", reason, deviceId); |
| | | logger.warn("[设å¤ç¦»çº¿]ï¼{}, deviceï¼{}", reason, deviceId); |
| | | Device device = deviceMapper.getDeviceByDeviceId(deviceId); |
| | | if (device == null) { |
| | | return; |
| | |
| | | } |
| | | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); |
| | | dynamicTask.stop(zlmKeepaliveKey); |
| | | dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000); |
| | | dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (serverItem.getHookAliveInterval().intValue() + 5) * 1000); |
| | | publisher.zlmOnlineEventPublish(serverItem.getId()); |
| | | |
| | | logger.info("[ZLM] è¿æ¥æå {} - {}:{} ", |
| | |
| | | |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.common.GeneralCallback; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| | | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| | | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| | |
| | | private IMediaServerService mediaServerService; |
| | | |
| | | @Autowired |
| | | private ZlmHttpHookSubscribe hookSubscribe; |
| | | |
| | | @Autowired |
| | | DataSourceTransactionManager dataSourceTransactionManager; |
| | | |
| | | @Autowired |
| | |
| | | |
| | | |
| | | @Override |
| | | public StreamInfo save(StreamProxyItem param) { |
| | | public void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback) { |
| | | MediaServerItem mediaInfo; |
| | | if (ObjectUtils.isEmpty(param.getMediaServerId()) || "auto".equals(param.getMediaServerId())){ |
| | | mediaInfo = mediaServerService.getMediaServerForMinimumLoad(null); |
| | |
| | | logger.warn("ä¿åä»£çæªæ¾å°å¨çº¿çZLM..."); |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ä¿åä»£çæªæ¾å°å¨çº¿çZLM"); |
| | | } |
| | | String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), |
| | | param.getStream() ); |
| | | param.setDst_url(dstUrl); |
| | | StringBuffer resultMsg = new StringBuffer(); |
| | | String dstUrl; |
| | | if ("ffmpeg".equalsIgnoreCase(param.getType())) { |
| | | JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaInfo); |
| | | if (jsonObject.getInteger("code") != 0) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "è·åæµåªä½é
置失败"); |
| | | } |
| | | JSONArray dataArray = jsonObject.getJSONArray("data"); |
| | | JSONObject mediaServerConfig = dataArray.getJSONObject(0); |
| | | String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey()); |
| | | String schema = getSchemaFromFFmpegCmd(ffmpegCmd); |
| | | if (schema == null) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpegææµä»£çæ æ³ä»ffmpeg cmdä¸è·åå°è¾åºæ ¼å¼"); |
| | | } |
| | | int port; |
| | | String schemaForUri; |
| | | if (schema.equalsIgnoreCase("rtsp")) { |
| | | port = mediaInfo.getRtspPort(); |
| | | schemaForUri = schema; |
| | | }else if (schema.equalsIgnoreCase("flv")) { |
| | | port = mediaInfo.getHttpPort(); |
| | | schemaForUri = "http"; |
| | | }else if (schema.equalsIgnoreCase("rtmp")) { |
| | | port = mediaInfo.getRtmpPort(); |
| | | schemaForUri = schema; |
| | | }else { |
| | | port = mediaInfo.getRtmpPort(); |
| | | schemaForUri = schema; |
| | | } |
| | | |
| | | dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(), |
| | | param.getStream()); |
| | | }else { |
| | | dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), |
| | | param.getStream()); |
| | | } |
| | | param.setDstUrl(dstUrl); |
| | | logger.info("[ææµä»£ç] è¾åºå°å为ï¼{}", dstUrl); |
| | | param.setMediaServerId(mediaInfo.getId()); |
| | | boolean saveResult; |
| | | // æ´æ° |
| | |
| | | saveResult = addStreamProxy(param); |
| | | } |
| | | if (!saveResult) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(),"ä¿å失败"); |
| | | callback.run(ErrorCode.ERROR100.getCode(), "ä¿å失败", null); |
| | | return; |
| | | } |
| | | StreamInfo resultForStreamInfo = null; |
| | | resultMsg.append("ä¿åæå"); |
| | | |
| | | HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(param.getApp(), param.getStream(), true, "rtsp", mediaInfo.getId()); |
| | | hookSubscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItem, response) -> { |
| | | StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream( |
| | | mediaInfo, param.getApp(), param.getStream(), null, null); |
| | | callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); |
| | | }); |
| | | |
| | | if (param.isEnable()) { |
| | | JSONObject jsonObject = addStreamProxyToZlm(param); |
| | | if (jsonObject == null || jsonObject.getInteger("code") != 0) { |
| | | resultMsg.append(", 使¯å¯ç¨å¤±è´¥ï¼è¯·æ£æ¥æµå°åæ¯å¦å¯ç¨"); |
| | | if (jsonObject != null && jsonObject.getInteger("code") == 0) { |
| | | hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); |
| | | StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream( |
| | | mediaInfo, param.getApp(), param.getStream(), null, null); |
| | | callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); |
| | | }else { |
| | | param.setEnable(false); |
| | | // ç´æ¥ç§»é¤ |
| | | if (param.isEnable_remove_none_reader()) { |
| | | if (param.isEnableRemoveNoneReader()) { |
| | | del(param.getApp(), param.getStream()); |
| | | }else { |
| | | updateStreamProxy(param); |
| | | } |
| | | if (jsonObject == null){ |
| | | callback.run(ErrorCode.ERROR100.getCode(), "è®°å½å·²ä¿åï¼å¯ç¨å¤±è´¥", null); |
| | | return; |
| | | }else { |
| | | callback.run(ErrorCode.ERROR100.getCode(), jsonObject.getString("msg"), null); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | }else { |
| | | resultForStreamInfo = mediaService.getStreamInfoByAppAndStream( |
| | | mediaInfo, param.getApp(), param.getStream(), null, null); |
| | | private String getSchemaFromFFmpegCmd(String ffmpegCmd) { |
| | | ffmpegCmd = ffmpegCmd.replaceAll(" + ", " "); |
| | | String[] paramArray = ffmpegCmd.split(" "); |
| | | if (paramArray.length == 0) { |
| | | return null; |
| | | } |
| | | for (int i = 0; i < paramArray.length; i++) { |
| | | if (paramArray[i].equalsIgnoreCase("-f")) { |
| | | if (i + 1 < paramArray.length - 1) { |
| | | return paramArray[i+1]; |
| | | }else { |
| | | return null; |
| | | } |
| | | |
| | | } |
| | | } |
| | | return resultForStreamInfo; |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | if ("default".equals(param.getType())){ |
| | | result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(), |
| | | param.isEnable_audio(), param.isEnable_mp4(), param.getRtp_type()); |
| | | param.isEnableAudio(), param.isEnableMp4(), param.getRtpType()); |
| | | }else if ("ffmpeg".equals(param.getType())) { |
| | | result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(), |
| | | param.getTimeout_ms() + "", param.isEnable_audio(), param.isEnable_mp4(), |
| | | param.getFfmpeg_cmd_key()); |
| | | result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl(), param.getDstUrl(), |
| | | param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(), |
| | | param.getFfmpegCmdKey()); |
| | | } |
| | | return result; |
| | | } |
| | |
| | | updateStreamProxy(streamProxy); |
| | | }else { |
| | | logger.info("å¯ç¨ä»£çå¤±è´¥ï¼ {}/{}->{}({})", app, stream, jsonObject.getString("msg"), |
| | | streamProxy.getSrc_url() == null? streamProxy.getUrl():streamProxy.getSrc_url()); |
| | | streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl()); |
| | | } |
| | | } |
| | | return result; |
| | |
| | | |
| | | @Override |
| | | public boolean stop(String app, String streamId) { |
| | | logger.info("[æ¨æµ ] 忢æµï¼ {}/{}", app, streamId); |
| | | StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); |
| | | if (streamPushItem != null) { |
| | | gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); |
New file |
| | |
| | | package com.genersoft.iot.vmp.service.redisMsg; |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.service.IStreamPushService; |
| | | import org.jetbrains.annotations.NotNull; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.data.redis.connection.Message; |
| | | import org.springframework.data.redis.connection.MessageListener; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.concurrent.ConcurrentLinkedQueue; |
| | | |
| | | /** |
| | | * æ¥æ¶æ¥èªredisçå
³éæµæ´æ°éç¥ |
| | | * @author lin |
| | | */ |
| | | @Component |
| | | public class RedisCloseStreamMsgListener implements MessageListener { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(RedisCloseStreamMsgListener.class); |
| | | |
| | | |
| | | @Autowired |
| | | private IStreamPushService pushService; |
| | | |
| | | private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); |
| | | |
| | | @Qualifier("taskExecutor") |
| | | @Autowired |
| | | private ThreadPoolTaskExecutor taskExecutor; |
| | | |
| | | @Override |
| | | public void onMessage(@NotNull Message message, byte[] bytes) { |
| | | boolean isEmpty = taskQueue.isEmpty(); |
| | | taskQueue.offer(message); |
| | | if (isEmpty) { |
| | | taskExecutor.execute(() -> { |
| | | while (!taskQueue.isEmpty()) { |
| | | Message msg = taskQueue.poll(); |
| | | try { |
| | | JSONObject jsonObject = JSON.parseObject(msg.getBody()); |
| | | String app = jsonObject.getString("app"); |
| | | String stream = jsonObject.getString("stream"); |
| | | pushService.stop(app, stream); |
| | | |
| | | }catch (Exception e) { |
| | | logger.warn("[REDISçå
³éæ¨æµéç¥] åç°æªå¤ççå¼å¸¸, \r\n{}", JSON.toJSONString(message)); |
| | | logger.error("[REDISçå
³éæ¨æµéç¥] å¼å¸¸å
å®¹ï¼ ", e); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | } |
| | |
| | | void removeAllDevice(); |
| | | |
| | | void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online); |
| | | void sendChannelAddOrDelete(String deviceId, String channelId, boolean add); |
| | | } |
| | |
| | | |
| | | @Select("select 'channel' as name, count(pgc.platform_id) count from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id where pgc.platform_id=#{platform_id} and dc.channel_id =#{gbId} " + |
| | | "union " + |
| | | "select 'stream' as name, count(pgs.platform_id) count from wvp_platform_gb_stream pgs left join wvp_gb_stream gs on pgs.gb_stream_id = gs.gb_stream_id where pgs.platform_id=#{platform_id} and gs.gb_id #{gbId}") |
| | | "select 'stream' as name, count(pgs.platform_id) count from wvp_platform_gb_stream pgs left join wvp_gb_stream gs on pgs.gb_stream_id = gs.gb_stream_id where pgs.platform_id=#{platform_id} and gs.gb_id =#{gbId}") |
| | | List<ChannelSourceInfo> getChannelSource(String platform_id, String gbId); |
| | | } |
| | |
| | | @Repository |
| | | public interface PlatformCatalogMapper { |
| | | |
| | | @Insert("INSERT INTO platform_catalog (id, name, platform_id, parent_id, civil_code, business_group_id) VALUES" + |
| | | @Insert("INSERT INTO wvp_platform_catalog (id, name, platform_id, parent_id, civil_code, business_group_id) VALUES" + |
| | | "(#{id}, #{name}, #{platformId}, #{parentId}, #{civilCode}, #{businessGroupId})") |
| | | int add(PlatformCatalog platformCatalog); |
| | | |
| | |
| | | PlatformCatalog select(String id); |
| | | |
| | | @Update(value = {" <script>" + |
| | | "UPDATE platform_catalog " + |
| | | "UPDATE wvp_platform_catalog " + |
| | | "SET name=#{name}" + |
| | | "WHERE id=#{id}"+ |
| | | "</script>"}) |
| | |
| | | @Select("SELECT *, (SELECT COUNT(1) from wvp_platform_catalog where parent_id = pc.id) as children_count from wvp_platform_catalog pc WHERE pc.platform_id=#{platformId}") |
| | | List<PlatformCatalog> selectByPlatForm(String platformId); |
| | | |
| | | @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = (SELECT pp.catalog_id from wvp_platform pp WHERE pp.server_gb_id=#{platformId})") |
| | | @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = (SELECT pp.catalog_id from wvp_platform pp WHERE pp.server_gb_id=#{platformId})") |
| | | PlatformCatalog selectDefaultByPlatFormId(String platformId); |
| | | |
| | | |
| | | @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = #{id}") |
| | | @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = #{id}") |
| | | PlatformCatalog selectParentCatalog(String id); |
| | | |
| | | @Select("SELECT pc.id as channel_id, pc.name, pc.civil_code, pc.business_group_id,'1' as parental, pc.parent_id " + |
| | |
| | | |
| | | @Insert("INSERT INTO wvp_stream_proxy (type, name, app, stream,media_server_id, url, src_url, dst_url, " + |
| | | "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" + |
| | | "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{src_url}, #{dst_url}, " + |
| | | "#{timeout_ms}, #{ffmpeg_cmd_key}, #{rtp_type}, #{enable_audio}, #{enable_mp4}, #{enable}, #{status}, " + |
| | | "#{enable_remove_none_reader}, #{enable_disable_none_reader}, #{createTime} )") |
| | | "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{srcUrl}, #{dstUrl}, " + |
| | | "#{timeoutMs}, #{ffmpegCmdKey}, #{rtpType}, #{enableAudio}, #{enableMp4}, #{enable}, #{status}, " + |
| | | "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )") |
| | | int add(StreamProxyItem streamProxyDto); |
| | | |
| | | @Update("UPDATE wvp_stream_proxy " + |
| | |
| | | "stream=#{stream}," + |
| | | "url=#{url}, " + |
| | | "media_server_id=#{mediaServerId}, " + |
| | | "src_url=#{src_url}," + |
| | | "dst_url=#{dst_url}, " + |
| | | "timeout_ms=#{timeout_ms}, " + |
| | | "ffmpeg_cmd_key=#{ffmpeg_cmd_key}, " + |
| | | "rtp_type=#{rtp_type}, " + |
| | | "enable_audio=#{enable_audio}, " + |
| | | "src_url=#{srcUrl}," + |
| | | "dst_url=#{dstUrl}, " + |
| | | "timeout_ms=#{timeoutMs}, " + |
| | | "ffmpeg_cmd_key=#{ffmpegCmdKey}, " + |
| | | "rtp_type=#{rtpType}, " + |
| | | "enable_audio=#{enableAudio}, " + |
| | | "enable=#{enable}, " + |
| | | "status=#{status}, " + |
| | | "enable_remove_none_reader=#{enable_remove_none_reader}, " + |
| | | "enable_disable_none_reader=#{enable_disable_none_reader}, " + |
| | | "enable_mp4=#{enable_mp4} " + |
| | | "enable_remove_none_reader=#{enableRemoveNoneReader}, " + |
| | | "enable_disable_none_reader=#{enableDisableNoneReader}, " + |
| | | "enable_mp4=#{enableMp4} " + |
| | | "WHERE app=#{app} AND stream=#{stream}") |
| | | int update(StreamProxyItem streamProxyDto); |
| | | |
| | |
| | | @Override |
| | | public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) { |
| | | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS; |
| | | if (channelId == null) { |
| | | logger.info("[rediséç¥] æ¨é设å¤ç¶æï¼ {}-{}", deviceId, online); |
| | | }else { |
| | | logger.info("[rediséç¥] æ¨éééç¶æï¼ {}/{}-{}", deviceId, channelId, online); |
| | | } |
| | | |
| | | StringBuilder msg = new StringBuilder(); |
| | | msg.append(deviceId); |
| | | if (channelId != null) { |
| | | msg.append(":").append(channelId); |
| | | } |
| | | msg.append(" ").append(online? "ON":"OFF"); |
| | | logger.info("[rediséç¥] æ¨éç¶æ-> {} ", msg); |
| | | // ä½¿ç¨ RedisTemplate<Object, Object> åéåç¬¦ä¸²æ¶æ¯ä¼å¯¼è´åéçæ¶æ¯å¤å¸¦äºåå¼å· |
| | | stringRedisTemplate.convertAndSend(key, msg.toString()); |
| | | } |
| | | |
| | | @Override |
| | | public void sendChannelAddOrDelete(String deviceId, String channelId, boolean add) { |
| | | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS; |
| | | |
| | | |
| | | StringBuilder msg = new StringBuilder(); |
| | | msg.append(deviceId); |
| | | if (channelId != null) { |
| | | msg.append(":").append(channelId); |
| | | } |
| | | msg.append(" ").append(add? "ADD":"DELETE"); |
| | | logger.info("[rediséç¥] æ¨ééé-> {}", msg); |
| | | // ä½¿ç¨ RedisTemplate<Object, Object> åéåç¬¦ä¸²æ¶æ¯ä¼å¯¼è´åéçæ¶æ¯å¤å¸¦äºåå¼å· |
| | | stringRedisTemplate.convertAndSend(key, msg.toString()); |
| | | } |
| | |
| | | public enum ErrorCode { |
| | | SUCCESS(0, "æå"), |
| | | ERROR100(100, "失败"), |
| | | ERROR400(400, "åæ°ä¸å
¨æè
é误"), |
| | | ERROR400(400, "åæ°ææ¹æ³é误"), |
| | | ERROR404(404, "èµæºæªæ¾å°"), |
| | | ERROR403(403, "æ æéæä½"), |
| | | ERROR401(401, "请ç»å½åéæ°è¯·æ±"), |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.bean; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | |
| | | @Schema(description = "æªå¾å°åä¿¡æ¯") |
| | | public class SnapPath { |
| | | |
| | | @Schema(description = "ç¸å¯¹å°å") |
| | | private String path; |
| | | |
| | | @Schema(description = "ç»å¯¹å°å") |
| | | private String absoluteFilePath; |
| | | |
| | | @Schema(description = "请æ±å°å") |
| | | private String url; |
| | | |
| | | |
| | | public static SnapPath getInstance(String path, String absoluteFilePath, String url) { |
| | | SnapPath snapPath = new SnapPath(); |
| | | snapPath.setPath(path); |
| | | snapPath.setAbsoluteFilePath(absoluteFilePath); |
| | | snapPath.setUrl(url); |
| | | return snapPath; |
| | | } |
| | | |
| | | |
| | | public String getPath() { |
| | | return path; |
| | | } |
| | | |
| | | public void setPath(String path) { |
| | | this.path = path; |
| | | } |
| | | |
| | | public String getAbsoluteFilePath() { |
| | | return absoluteFilePath; |
| | | } |
| | | |
| | | public void setAbsoluteFilePath(String absoluteFilePath) { |
| | | this.absoluteFilePath = absoluteFilePath; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | } |
| | |
| | | public DeferredResult<MobilePosition> realTimePosition(@PathVariable String deviceId) { |
| | | Device device = storager.queryVideoDevice(deviceId); |
| | | String uuid = UUID.randomUUID().toString(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId; |
| | | String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + deviceId; |
| | | try { |
| | | cmder.mobilePostitionQuery(device, event -> { |
| | | RequestMessage msg = new RequestMessage(); |
| | |
| | | @Operation(summary = "è¯·æ±æªå¾") |
| | | @Parameter(name = "deviceId", description = "设å¤å½æ ç¼å·", required = true) |
| | | @Parameter(name = "channelId", description = "éé彿 ç¼å·", required = true) |
| | | public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) { |
| | | @Parameter(name = "mark", description = "æ è¯", required = false) |
| | | public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId, @RequestParam(required = false) String mark) { |
| | | |
| | | try { |
| | | final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath()); |
| | | |
| | | final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + (mark == null? ".jpg": ("_" + mark + ".jpg"))).toPath()); |
| | | resp.setContentType(MediaType.IMAGE_PNG_VALUE); |
| | | IOUtils.copy(in, resp.getOutputStream()); |
| | | } catch (IOException e) { |
| | |
| | | package com.genersoft.iot.vmp.vmanager.streamProxy; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| | | import com.genersoft.iot.vmp.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| | | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| | | import com.github.pagehelper.PageInfo; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.util.ObjectUtils; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.context.request.async.DeferredResult; |
| | | |
| | | import java.util.UUID; |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | /** |
| | |
| | | |
| | | @Autowired |
| | | private IStreamProxyService streamProxyService; |
| | | |
| | | @Autowired |
| | | private DeferredResultHolder resultHolder; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | |
| | | @Operation(summary = "å页æ¥è¯¢æµä»£ç") |
| | |
| | | }) |
| | | @PostMapping(value = "/save") |
| | | @ResponseBody |
| | | public StreamContent save(@RequestBody StreamProxyItem param){ |
| | | public DeferredResult<Object> save(@RequestBody StreamProxyItem param){ |
| | | logger.info("æ·»å 代çï¼ " + JSONObject.toJSONString(param)); |
| | | if (ObjectUtils.isEmpty(param.getMediaServerId())) { |
| | | param.setMediaServerId("auto"); |
| | |
| | | if (ObjectUtils.isEmpty(param.getGbId())) { |
| | | param.setGbId(null); |
| | | } |
| | | return new StreamContent(streamProxyService.save(param)); |
| | | |
| | | RequestMessage requestMessage = new RequestMessage(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream(); |
| | | requestMessage.setKey(key); |
| | | String uuid = UUID.randomUUID().toString(); |
| | | requestMessage.setId(uuid); |
| | | DeferredResult<Object> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); |
| | | // å½åæ¥è¯¢ä»¥channelIdä½ä¸ºdeviceIdæ¥è¯¢ |
| | | resultHolder.put(key, uuid, result); |
| | | result.onTimeout(()->{ |
| | | WVPResult<StreamInfo> wvpResult = new WVPResult<>(); |
| | | wvpResult.setCode(ErrorCode.ERROR100.getCode()); |
| | | wvpResult.setMsg("è¶
æ¶"); |
| | | requestMessage.setData(wvpResult); |
| | | resultHolder.invokeAllResult(requestMessage); |
| | | }); |
| | | |
| | | streamProxyService.save(param, (code, msg, streamInfo) -> { |
| | | logger.info("[ææµä»£ç] {}", code == ErrorCode.SUCCESS.getCode()? "æå":"å¤±è´¥ï¼ " + msg); |
| | | if (code == ErrorCode.SUCCESS.getCode()) { |
| | | requestMessage.setData(new StreamContent(streamInfo)); |
| | | }else { |
| | | requestMessage.setData(WVPResult.fail(code, msg)); |
| | | } |
| | | resultHolder.invokeAllResult(requestMessage); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | @GetMapping(value = "/ffmpeg_cmd/list") |
| | |
| | | idle-timeout: 300000 # å
è®¸è¿æ¥å¨è¿æ¥æ± ä¸ç©ºé²çæé¿æ¶é´ï¼ä»¥æ¯«ç§ä¸ºåä½ï¼ |
| | | max-lifetime: 1200000 # æ¯æ± ä¸è¿æ¥å
³éåçæé¿çå½å¨æï¼ä»¥æ¯«ç§ä¸ºåä½) |
| | | |
| | | # ä¿®æ¹ä¸ºæ°æ®åºå段ä¸å线åéç´æ¥å¯¹åºjava驼峰å½å |
| | | mybatis: |
| | | configuration: |
| | | map-underscore-to-camel-case: true |
| | | |
| | | # ä¿®æ¹å页æä»¶ä¸º postgresqlï¼ æ°æ®åºç±»å为mysqlä¸éè¦ |
| | | #pagehelper: |
| | |
| | | {{scope.row.url}} |
| | | </el-tag> |
| | | <el-tag size="medium" v-if="scope.row.type != 'default'"> |
| | | <i class="cpoy-btn el-icon-document-copy" title="ç¹å»æ·è´" v-clipboard="scope.row.src_url" @success="$message({type:'success', message:'æåæ·è´å°ç²è´´æ¿'})"></i> |
| | | {{scope.row.src_url}} |
| | | <i class="cpoy-btn el-icon-document-copy" title="ç¹å»æ·è´" v-clipboard="scope.row.srcUrl" @success="$message({type:'success', message:'æåæ·è´å°ç²è´´æ¿'})"></i> |
| | | {{scope.row.srcUrl}} |
| | | </el-tag> |
| | | </div> |
| | | </template> |
| | |
| | | <el-table-column label="é³é¢" min-width="120" > |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable_audio">å·²å¯ç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable_audio">æªå¯ç¨</el-tag> |
| | | <el-tag size="medium" v-if="scope.row.enableAudio">å·²å¯ç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enableAudio">æªå¯ç¨</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å½å¶" min-width="120" > |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable_mp4">å·²å¯ç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable_mp4">æªå¯ç¨</el-tag> |
| | | <el-tag size="medium" v-if="scope.row.enableMp4">å·²å¯ç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enableMp4">æªå¯ç¨</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ 人è§ç" min-width="160" > |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable_remove_none_reader">ç§»é¤</el-tag> |
| | | <el-tag size="medium" v-if="scope.row.enable_disable_none_reader">åç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable_remove_none_reader && !scope.row.enable_disable_none_reader">ä¸åå¤ç</el-tag> |
| | | <el-tag size="medium" v-if="scope.row.enableRemoveNoneReader">ç§»é¤</el-tag> |
| | | <el-tag size="medium" v-if="scope.row.enableDisableNoneReader">åç¨</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enableRemoveNoneReader && !scope.row.enableDisableNoneReader">ä¸åå¤ç</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{ |
| | | if (url != null) { |
| | | this.$refs.onvifEdit.close(); |
| | | this.$refs.streamProxyEdit.openDialog({type: "default", url: url, src_url: url}, this.initData()) |
| | | this.$refs.streamProxyEdit.openDialog({type: "default", url: url, srcUrl: url}, this.initData()) |
| | | } |
| | | }) |
| | | }else { |
| | |
| | | }, |
| | | deleteStreamProxy: function(row){ |
| | | let that = this; |
| | | that.$axios({ |
| | | method:"delete", |
| | | url:"/api/proxy/del", |
| | | params:{ |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }).then((res)=>{ |
| | | that.initData() |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | this.$confirm('ç¡®å®å 餿¤ä»£çåï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | that.$axios({ |
| | | method:"delete", |
| | | url:"/api/proxy/del", |
| | | params:{ |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }).then((res)=>{ |
| | | that.initData() |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | }).catch(() => { |
| | | }); |
| | | }, |
| | | start: function(row){ |
| | | this.stopUpdateList() |
| | |
| | | <el-form-item label="ææµå°å" prop="url" v-if="proxyParam.type=='default'"> |
| | | <el-input v-model="proxyParam.url" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ææµå°å" prop="src_url" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.src_url" clearable></el-input> |
| | | <el-form-item label="ææµå°å" prop="srcUrl" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.srcUrl" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="è¶
æ¶æ¶é´:毫ç§" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.timeout_ms" clearable></el-input> |
| | | <el-form-item label="è¶
æ¶æ¶é´:毫ç§" prop="timeoutMs" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.timeoutMs" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="èç¹éæ©" prop="rtp_type"> |
| | | <el-form-item label="èç¹éæ©" prop="rtpType"> |
| | | <el-select |
| | | v-model="proxyParam.mediaServerId" |
| | | @change="mediaServerIdChange" |
| | |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="FFmpegå½ä»¤æ¨¡æ¿" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'"> |
| | | <!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>--> |
| | | <el-form-item label="FFmpegå½ä»¤æ¨¡æ¿" prop="ffmpegCmdKey" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-select |
| | | v-model="proxyParam.ffmpeg_cmd_key" |
| | | v-model="proxyParam.ffmpegCmdKey" |
| | | style="width: 100%" |
| | | placeholder="è¯·éæ©FFmpegå½ä»¤æ¨¡æ¿" |
| | | > |
| | |
| | | <el-form-item label="彿 ç¼ç " prop="gbId"> |
| | | <el-input v-model="proxyParam.gbId" placeholder="è®¾ç½®å½æ ç¼ç 坿¨éå°å½æ " clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ææµæ¹å¼" prop="rtp_type" v-if="proxyParam.type=='default'"> |
| | | <el-form-item label="ææµæ¹å¼" prop="rtpType" v-if="proxyParam.type=='default'"> |
| | | <el-select |
| | | v-model="proxyParam.rtp_type" |
| | | v-model="proxyParam.rtpType" |
| | | style="width: 100%" |
| | | placeholder="è¯·éæ©ææµæ¹å¼" |
| | | > |
| | |
| | | <el-option label="ç»æ" value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ 人è§ç" prop="rtp_type" > |
| | | <el-form-item label="æ 人è§ç" prop="rtpType" > |
| | | <el-select |
| | | @change="noneReaderHandler" |
| | | v-model="proxyParam.none_reader" |
| | | v-model="proxyParam.noneReader" |
| | | style="width: 100%" |
| | | placeholder="è¯·éæ©æ 人è§ççå¤çæ¹å¼" |
| | | > |
| | |
| | | <el-form-item label="å
¶ä»é项"> |
| | | <div style="float: left;"> |
| | | <el-checkbox label="å¯ç¨" v-model="proxyParam.enable" ></el-checkbox> |
| | | <el-checkbox label="å¼å¯é³é¢" v-model="proxyParam.enable_audio" ></el-checkbox> |
| | | <el-checkbox label="å½å¶" v-model="proxyParam.enable_mp4" ></el-checkbox> |
| | | <el-checkbox label="å¼å¯é³é¢" v-model="proxyParam.enableAudio" ></el-checkbox> |
| | | <el-checkbox label="å½å¶" v-model="proxyParam.enableMp4" ></el-checkbox> |
| | | </div> |
| | | |
| | | </el-form-item> |
| | |
| | | app: null, |
| | | stream: null, |
| | | url: "", |
| | | src_url: null, |
| | | timeout_ms: null, |
| | | ffmpeg_cmd_key: null, |
| | | srcUrl: null, |
| | | timeoutMs: null, |
| | | ffmpegCmdKey: null, |
| | | gbId: null, |
| | | rtp_type: null, |
| | | rtpType: null, |
| | | enable: true, |
| | | enable_audio: true, |
| | | enable_mp4: false, |
| | | none_reader: null, |
| | | enable_remove_none_reader: false, |
| | | enable_disable_none_reader: false, |
| | | enableAudio: true, |
| | | enableMp4: false, |
| | | noneReader: null, |
| | | enableRemoveNoneReader: false, |
| | | enableDisableNoneReader: false, |
| | | platformGbId: null, |
| | | mediaServerId: null, |
| | | }, |
| | |
| | | app: [{ required: true, message: "请è¾å
¥åºç¨å", trigger: "blur" }], |
| | | stream: [{ required: true, message: "请è¾å
¥æµID", trigger: "blur" }], |
| | | url: [{ required: true, message: "请è¾å
¥è¦ä»£ççæµ", trigger: "blur" }], |
| | | src_url: [{ required: true, message: "请è¾å
¥è¦ä»£ççæµ", trigger: "blur" }], |
| | | timeout_ms: [{ required: true, message: "请è¾å
¥FFmpegæ¨æµæåè¶
æ¶æ¶é´", trigger: "blur" }], |
| | | ffmpeg_cmd_key: [{ required: false, message: "请è¾å
¥FFmpegå½ä»¤åæ°æ¨¡æ¿ï¼å¯éï¼", trigger: "blur" }], |
| | | srcUrl: [{ required: true, message: "请è¾å
¥è¦ä»£ççæµ", trigger: "blur" }], |
| | | timeoutMs: [{ required: true, message: "请è¾å
¥FFmpegæ¨æµæåè¶
æ¶æ¶é´", trigger: "blur" }], |
| | | ffmpegCmdKey: [{ required: false, message: "请è¾å
¥FFmpegå½ä»¤åæ°æ¨¡æ¿ï¼å¯éï¼", trigger: "blur" }], |
| | | }, |
| | | }; |
| | | }, |
| | |
| | | this.listChangeCallback = callback; |
| | | if (proxyParam != null) { |
| | | this.proxyParam = proxyParam; |
| | | this.proxyParam.none_reader = null; |
| | | this.proxyParam.noneReader = null; |
| | | } |
| | | |
| | | let that = this; |
| | |
| | | } |
| | | }).then(function (res) { |
| | | that.ffmpegCmdList = res.data.data; |
| | | that.proxyParam.ffmpeg_cmd_key = Object.keys(res.data.data)[0]; |
| | | that.proxyParam.ffmpegCmdKey = Object.keys(res.data.data)[0]; |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | |
| | | } |
| | | }, |
| | | noneReaderHandler: function() { |
| | | if (this.proxyParam.none_reader === null || this.proxyParam.none_reader === "0") { |
| | | this.proxyParam.enable_disable_none_reader = false; |
| | | this.proxyParam.enable_remove_none_reader = false; |
| | | }else if (this.proxyParam.none_reader === "1"){ |
| | | this.proxyParam.enable_disable_none_reader = true; |
| | | this.proxyParam.enable_remove_none_reader = false; |
| | | }else if (this.proxyParam.none_reader ==="2"){ |
| | | this.proxyParam.enable_disable_none_reader = false; |
| | | this.proxyParam.enable_remove_none_reader = true; |
| | | if (this.proxyParam.noneReader === null || this.proxyParam.noneReader === "0") { |
| | | this.proxyParam.enableDisableNoneReader = false; |
| | | this.proxyParam.enableRemoveNoneReader = false; |
| | | }else if (this.proxyParam.noneReader === "1"){ |
| | | this.proxyParam.enableDisableNoneReader = true; |
| | | this.proxyParam.enableRemoveNoneReader = false; |
| | | }else if (this.proxyParam.noneReader ==="2"){ |
| | | this.proxyParam.enableDisableNoneReader = false; |
| | | this.proxyParam.enableRemoveNoneReader = true; |
| | | } |
| | | }, |
| | | }, |
| | |
| | | <rtc-player v-if="activePlayer === 'webRTC'" ref="webRTC" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px" :hasAudio="hasAudio" fluent autoplay live ></rtc-player> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="h265web">h265webæ¬è¯·æå¾
</el-tab-pane> |
| | | <el-tab-pane label="wsPlayer">wsPlayer æ¬è¯·æå¾
</el-tab-pane> |
| | | </el-tabs> |
| | | <jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px" :hasAudio="hasAudio" fluent autoplay live ></jessibucaPlayer> |
| | | <rtc-player v-if="Object.keys(this.player).length == 1 && this.player.webRTC" ref="jessibuca" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px" :hasAudio="hasAudio" fluent autoplay live ></rtc-player> |
| | |
| | | playFromStreamInfo: function (realHasAudio, streamInfo) { |
| | | this.showVideoDialog = true; |
| | | this.hasaudio = realHasAudio && this.hasaudio; |
| | | this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) |
| | | if (this.$refs[this.activePlayer]) { |
| | | this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) |
| | | }else { |
| | | this.$nextTick(() => { |
| | | this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) |
| | | }); |
| | | } |
| | | |
| | | |
| | | }, |
| | | close: function () { |
| | | console.log('å
³éè§é¢'); |