Commit 2f165d595af3565bd17612ee0f5866ace8ab43f4
1 parent
418970ea
对级联点播信令进行处理
Showing
8 changed files
with
293 additions
and
169 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| @@ -30,6 +30,8 @@ public class VideoManagerConstants { | @@ -30,6 +30,8 @@ public class VideoManagerConstants { | ||
| 30 | 30 | ||
| 31 | public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_"; | 31 | public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_"; |
| 32 | 32 | ||
| 33 | + public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_"; | ||
| 34 | + | ||
| 33 | public static final String Pattern_Topic = "VMP_keeplive_platform_"; | 35 | public static final String Pattern_Topic = "VMP_keeplive_platform_"; |
| 34 | 36 | ||
| 35 | public static final String EVENT_ONLINE_REGISTER = "1"; | 37 | public static final String EVENT_ONLINE_REGISTER = "1"; |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | ||
| 2 | + | ||
| 3 | +public class SendRtpItem { | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * 推流ip | ||
| 7 | + */ | ||
| 8 | + private String ip; | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 推流端口 | ||
| 12 | + */ | ||
| 13 | + private int port; | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 推流标识 | ||
| 17 | + */ | ||
| 18 | + private String ssrc; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 平台id | ||
| 22 | + */ | ||
| 23 | + private String platformId; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 通道id | ||
| 27 | + */ | ||
| 28 | + private String channelId; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 推流状态 | ||
| 32 | + * 0 等待设备推流上来 | ||
| 33 | + * 1 等待上级平台回复ack | ||
| 34 | + * 2 推流中 | ||
| 35 | + */ | ||
| 36 | + private int status = 0; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 设备推流的app | ||
| 40 | + */ | ||
| 41 | + private String app = "rtp"; | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 设备推流的streamId | ||
| 45 | + */ | ||
| 46 | + private String streamId; | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 是否为tcp | ||
| 50 | + */ | ||
| 51 | + private boolean tcp; | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 是否为tcp主动模式 | ||
| 55 | + */ | ||
| 56 | + private boolean tcpActive; | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * 自己推流使用的端口 | ||
| 60 | + */ | ||
| 61 | + private int localPort; | ||
| 62 | + | ||
| 63 | + public String getIp() { | ||
| 64 | + return ip; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public void setIp(String ip) { | ||
| 68 | + this.ip = ip; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + public int getPort() { | ||
| 72 | + return port; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public void setPort(int port) { | ||
| 76 | + this.port = port; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public String getSsrc() { | ||
| 80 | + return ssrc; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public void setSsrc(String ssrc) { | ||
| 84 | + this.ssrc = ssrc; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + public String getPlatformId() { | ||
| 88 | + return platformId; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + public void setPlatformId(String platformId) { | ||
| 92 | + this.platformId = platformId; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public String getChannelId() { | ||
| 96 | + return channelId; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public void setChannelId(String channelId) { | ||
| 100 | + this.channelId = channelId; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public int getStatus() { | ||
| 104 | + return status; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public void setStatus(int status) { | ||
| 108 | + this.status = status; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + public String getApp() { | ||
| 112 | + return app; | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + public void setApp(String app) { | ||
| 116 | + this.app = app; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + public String getStreamId() { | ||
| 120 | + return streamId; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + public void setStreamId(String streamId) { | ||
| 124 | + this.streamId = streamId; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + public boolean isTcp() { | ||
| 128 | + return tcp; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + public void setTcp(boolean tcp) { | ||
| 132 | + this.tcp = tcp; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + public int getLocalPort() { | ||
| 136 | + return localPort; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + public void setLocalPort(int localPort) { | ||
| 140 | + this.localPort = localPort; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + public boolean isTcpActive() { | ||
| 144 | + return tcpActive; | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + public void setTcpActive(boolean tcpActive) { | ||
| 148 | + this.tcpActive = tcpActive; | ||
| 149 | + } | ||
| 150 | +} |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
| @@ -136,6 +136,7 @@ public class SIPProcessorFactory { | @@ -136,6 +136,7 @@ public class SIPProcessorFactory { | ||
| 136 | processor.setCmderFroPlatform(cmderFroPlatform); | 136 | processor.setCmderFroPlatform(cmderFroPlatform); |
| 137 | processor.setPlayService(playService); | 137 | processor.setPlayService(playService); |
| 138 | processor.setStorager(storager); | 138 | processor.setStorager(storager); |
| 139 | + processor.setRedisCatchStorage(redisCatchStorage); | ||
| 139 | processor.setZlmrtpServerFactory(zlmrtpServerFactory); | 140 | processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
| 140 | return processor; | 141 | return processor; |
| 141 | } else if (Request.REGISTER.equals(method)) { | 142 | } else if (Request.REGISTER.equals(method)) { |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
| 1 | package com.genersoft.iot.vmp.gb28181.transmit.request.impl; | 1 | package com.genersoft.iot.vmp.gb28181.transmit.request.impl; |
| 2 | 2 | ||
| 3 | -import javax.sip.Dialog; | ||
| 4 | -import javax.sip.InvalidArgumentException; | ||
| 5 | -import javax.sip.RequestEvent; | ||
| 6 | -import javax.sip.SipException; | 3 | +import javax.sip.*; |
| 7 | import javax.sip.message.Request; | 4 | import javax.sip.message.Request; |
| 8 | 5 | ||
| 9 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; | 6 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; |
| @@ -26,7 +23,11 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor { | @@ -26,7 +23,11 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 26 | public void process(RequestEvent evt) { | 23 | public void process(RequestEvent evt) { |
| 27 | Request request = evt.getRequest(); | 24 | Request request = evt.getRequest(); |
| 28 | Dialog dialog = evt.getDialog(); | 25 | Dialog dialog = evt.getDialog(); |
| 26 | + DialogState state = dialog.getState(); | ||
| 29 | if (dialog == null) return; | 27 | if (dialog == null) return; |
| 28 | + if (request.getMethod().equals(Request.INVITE) && dialog.getState()== DialogState.CONFIRMED) { | ||
| 29 | + // TODO 查询并开始推流 | ||
| 30 | + } | ||
| 30 | try { | 31 | try { |
| 31 | Request ackRequest = null; | 32 | Request ackRequest = null; |
| 32 | CSeq csReq = (CSeq) request.getHeader(CSeq.NAME); | 33 | CSeq csReq = (CSeq) request.getHeader(CSeq.NAME); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
| @@ -4,9 +4,12 @@ import javax.sdp.*; | @@ -4,9 +4,12 @@ import javax.sdp.*; | ||
| 4 | import javax.sip.InvalidArgumentException; | 4 | import javax.sip.InvalidArgumentException; |
| 5 | import javax.sip.RequestEvent; | 5 | import javax.sip.RequestEvent; |
| 6 | import javax.sip.SipException; | 6 | import javax.sip.SipException; |
| 7 | +import javax.sip.SipFactory; | ||
| 8 | +import javax.sip.address.Address; | ||
| 7 | import javax.sip.address.SipURI; | 9 | import javax.sip.address.SipURI; |
| 8 | import javax.sip.header.ContentTypeHeader; | 10 | import javax.sip.header.ContentTypeHeader; |
| 9 | import javax.sip.header.FromHeader; | 11 | import javax.sip.header.FromHeader; |
| 12 | +import javax.sip.header.HeaderFactory; | ||
| 10 | import javax.sip.header.SubjectHeader; | 13 | import javax.sip.header.SubjectHeader; |
| 11 | import javax.sip.message.Request; | 14 | import javax.sip.message.Request; |
| 12 | import javax.sip.message.Response; | 15 | import javax.sip.message.Response; |
| @@ -15,6 +18,7 @@ import com.alibaba.fastjson.JSONObject; | @@ -15,6 +18,7 @@ import com.alibaba.fastjson.JSONObject; | ||
| 15 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 18 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 16 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 19 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 17 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 20 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 21 | +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | ||
| 18 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 22 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 19 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | 23 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 20 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; | 24 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; |
| @@ -100,16 +104,18 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | @@ -100,16 +104,18 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 100 | platformId = uri.getUser(); | 104 | platformId = uri.getUser(); |
| 101 | 105 | ||
| 102 | if (platformId == null || channelId == null) { | 106 | if (platformId == null || channelId == null) { |
| 103 | - response400Ack(evt); // 参数不全, 发400,请求错误 | 107 | + logger.info("无法从FromHeader的Address中获取到平台id,返回404"); |
| 108 | + responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误 | ||
| 104 | return; | 109 | return; |
| 105 | } | 110 | } |
| 106 | // 查询平台下是否有该通道 | 111 | // 查询平台下是否有该通道 |
| 107 | DeviceChannel channel = storager.queryChannelInParentPlatform(platformId, channelId); | 112 | DeviceChannel channel = storager.queryChannelInParentPlatform(platformId, channelId); |
| 108 | if (channel == null) { | 113 | if (channel == null) { |
| 109 | - response404Ack(evt); // 通道不存在,发404,资源不存在 | 114 | + logger.info("通道不存在,返回404"); |
| 115 | + responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 | ||
| 110 | return; | 116 | return; |
| 111 | }else { | 117 | }else { |
| 112 | - response100Ack(evt); // 通道存在,发100,trying | 118 | + responseAck(evt, Response.TRYING); // 通道存在,发100,trying |
| 113 | } | 119 | } |
| 114 | // 解析sdp消息, 使用jainsip 自带的sdp解析方式 | 120 | // 解析sdp消息, 使用jainsip 自带的sdp解析方式 |
| 115 | String contentString = new String(request.getRawContent()); | 121 | String contentString = new String(request.getRawContent()); |
| @@ -152,107 +158,79 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | @@ -152,107 +158,79 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 152 | } | 158 | } |
| 153 | } | 159 | } |
| 154 | } | 160 | } |
| 155 | -// Vector attributes = mediaDescription.getAttributes(false); | ||
| 156 | -// for (Object attributeObj : attributes) { | ||
| 157 | -// Attribute attribute = (Attribute)attributeObj; | ||
| 158 | -// String name = attribute.getName(); | ||
| 159 | -// switch (name){ | ||
| 160 | -// case "recvonly": | ||
| 161 | -// recvonly = true; | ||
| 162 | -// break; | ||
| 163 | -// case "rtpmap": | ||
| 164 | -// case "connection": | ||
| 165 | -// break; | ||
| 166 | -// case "setup": | ||
| 167 | -// mediaTransmissionTCP = true; | ||
| 168 | -// if ("active".equals(attribute.getValue())) { // tcp主动模式 | ||
| 169 | -// tcpActive = true; | ||
| 170 | -// }else if ("passive".equals(attribute.getValue())){ // tcp被动模式 | ||
| 171 | -// tcpActive = false; | ||
| 172 | -// } | ||
| 173 | -// break; | ||
| 174 | -// | ||
| 175 | -// } | ||
| 176 | -// if ("recvonly".equals(name)) { | ||
| 177 | -// recvonly = true; | ||
| 178 | -// } | ||
| 179 | -// | ||
| 180 | -// String value = attribute.getValue(); | ||
| 181 | -// } | ||
| 182 | break; | 161 | break; |
| 183 | } | 162 | } |
| 184 | } | 163 | } |
| 185 | if (port == -1) { | 164 | if (port == -1) { |
| 165 | + logger.info("不支持的媒体格式,返回415"); | ||
| 186 | // 回复不支持的格式 | 166 | // 回复不支持的格式 |
| 187 | - response415Ack(evt); // 不支持的格式,发415 | 167 | + responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 |
| 188 | return; | 168 | return; |
| 189 | } | 169 | } |
| 190 | String username = sdp.getOrigin().getUsername(); | 170 | String username = sdp.getOrigin().getUsername(); |
| 191 | String addressStr = sdp.getOrigin().getAddress(); | 171 | String addressStr = sdp.getOrigin().getAddress(); |
| 192 | String sessionName = sdp.getSessionName().getValue(); | 172 | String sessionName = sdp.getSessionName().getValue(); |
| 193 | logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); | 173 | logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); |
| 194 | -// | ||
| 195 | -// Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | ||
| 196 | -// if (device == null) { | ||
| 197 | -// logger.warn("点播平台{}的通道{}时未找到设备信息", platformId, channel); | ||
| 198 | -// response500Ack(evt); | ||
| 199 | -// return; | ||
| 200 | -// } | ||
| 201 | -// | ||
| 202 | -// // 通知下级推流, | ||
| 203 | -// PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{ | ||
| 204 | -// // 收到推流, 回复200OK | ||
| 205 | -// UUID uuid = UUID.randomUUID(); | ||
| 206 | -// int rtpServer = zlmrtpServerFactory.createRTPServer(uuid.toString()); | ||
| 207 | -// if (rtpServer == -1) { | ||
| 208 | -// logger.error("为获取到可用端口"); | ||
| 209 | -// return; | ||
| 210 | -// }else { | ||
| 211 | -// zlmrtpServerFactory.closeRTPServer(uuid.toString()); | ||
| 212 | -// } | ||
| 213 | -// // TODO 添加对tcp的支持 | ||
| 214 | -// MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | ||
| 215 | -// StringBuffer content = new StringBuffer(200); | ||
| 216 | -// content.append("v=0\r\n"); | ||
| 217 | -// content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | ||
| 218 | -// content.append("s=Play\r\n"); | ||
| 219 | -// content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | ||
| 220 | -// content.append("t=0 0\r\n"); | ||
| 221 | -// content.append("m=video "+ rtpServer+" RTP/AVP 96\r\n"); | ||
| 222 | -// content.append("a=sendonly\r\n"); | ||
| 223 | -// content.append("a=rtpmap:96 PS/90000\r\n"); | ||
| 224 | -// content.append("y="+ ssrc + "\r\n"); | ||
| 225 | -// content.append("f=\r\n"); | ||
| 226 | -// | ||
| 227 | -// try { | ||
| 228 | -// responseAck(evt, content.toString()); | ||
| 229 | -// } catch (SipException e) { | ||
| 230 | -// e.printStackTrace(); | ||
| 231 | -// } catch (InvalidArgumentException e) { | ||
| 232 | -// e.printStackTrace(); | ||
| 233 | -// } catch (ParseException e) { | ||
| 234 | -// e.printStackTrace(); | ||
| 235 | -// } | ||
| 236 | -// | ||
| 237 | -// // 写入redis, 超时时回复 | ||
| 238 | -//// redisCatchStorage.waiteAck() | ||
| 239 | -// },(event -> { | ||
| 240 | -// // 未知错误。直接转发设备点播的错误 | ||
| 241 | -// Response response = null; | ||
| 242 | -// try { | ||
| 243 | -// response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); | ||
| 244 | -// getServerTransaction(evt).sendResponse(response); | ||
| 245 | -// | ||
| 246 | -// } catch (ParseException | SipException | InvalidArgumentException e) { | ||
| 247 | -// e.printStackTrace(); | ||
| 248 | -// } | ||
| 249 | -// })); | ||
| 250 | -// playResult.getResult(); | ||
| 251 | - // 查找合适的端口推流, | ||
| 252 | - // 收到ack后调用推流接口 | ||
| 253 | - | ||
| 254 | 174 | ||
| 175 | + Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | ||
| 176 | + if (device == null) { | ||
| 177 | + logger.warn("点播平台{}的通道{}时未找到设备信息", platformId, channel); | ||
| 178 | + responseAck(evt, Response.SERVER_INTERNAL_ERROR); | ||
| 179 | + return; | ||
| 180 | + } | ||
| 181 | + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(ip, port, platformId, ssrc, channelId, | ||
| 182 | + mediaTransmissionTCP); | ||
| 183 | + if (tcpActive != null) { | ||
| 184 | + sendRtpItem.setTcpActive(tcpActive); | ||
| 185 | + } | ||
| 186 | + if (sendRtpItem == null) { | ||
| 187 | + logger.warn("服务器端口资源不足"); | ||
| 188 | + responseAck(evt, Response.BUSY_HERE); | ||
| 189 | + return; | ||
| 190 | + } | ||
| 255 | 191 | ||
| 192 | + // 写入redis, 超时时回复 | ||
| 193 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | ||
| 194 | + // 通知下级推流, | ||
| 195 | + PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{ | ||
| 196 | + // 收到推流, 回复200OK, 等待ack | ||
| 197 | + sendRtpItem.setStatus(1); | ||
| 198 | + redisCatchStorage.updateSendRTPSever(sendRtpItem); | ||
| 199 | + // TODO 添加对tcp的支持 | ||
| 200 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | ||
| 201 | + StringBuffer content = new StringBuffer(200); | ||
| 202 | + content.append("v=0\r\n"); | ||
| 203 | + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | ||
| 204 | + content.append("s=Play\r\n"); | ||
| 205 | + content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | ||
| 206 | + content.append("t=0 0\r\n"); | ||
| 207 | + content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); | ||
| 208 | + content.append("a=sendonly\r\n"); | ||
| 209 | + content.append("a=rtpmap:96 PS/90000\r\n"); | ||
| 210 | + content.append("y="+ ssrc + "\r\n"); | ||
| 211 | + content.append("f=\r\n"); | ||
| 212 | + | ||
| 213 | + try { | ||
| 214 | + responseAck(evt, content.toString()); | ||
| 215 | + } catch (SipException e) { | ||
| 216 | + e.printStackTrace(); | ||
| 217 | + } catch (InvalidArgumentException e) { | ||
| 218 | + e.printStackTrace(); | ||
| 219 | + } catch (ParseException e) { | ||
| 220 | + e.printStackTrace(); | ||
| 221 | + } | ||
| 222 | + },(event -> { | ||
| 223 | + // 未知错误。直接转发设备点播的错误 | ||
| 224 | + Response response = null; | ||
| 225 | + try { | ||
| 226 | + response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); | ||
| 227 | + getServerTransaction(evt).sendResponse(response); | ||
| 228 | + | ||
| 229 | + } catch (ParseException | SipException | InvalidArgumentException e) { | ||
| 230 | + e.printStackTrace(); | ||
| 231 | + } | ||
| 232 | + })); | ||
| 233 | + playResult.getResult(); | ||
| 256 | 234 | ||
| 257 | } catch (SipException | InvalidArgumentException | ParseException e) { | 235 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 258 | e.printStackTrace(); | 236 | e.printStackTrace(); |
| @@ -263,101 +241,47 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | @@ -263,101 +241,47 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 263 | } catch (SdpException e) { | 241 | } catch (SdpException e) { |
| 264 | e.printStackTrace(); | 242 | e.printStackTrace(); |
| 265 | } | 243 | } |
| 266 | - | ||
| 267 | } | 244 | } |
| 268 | 245 | ||
| 269 | /*** | 246 | /*** |
| 270 | - * 回复100 trying | 247 | + * 回复状态码 |
| 248 | + * 100 trying | ||
| 249 | + * 200 OK | ||
| 250 | + * 400 | ||
| 251 | + * 404 | ||
| 271 | * @param evt | 252 | * @param evt |
| 272 | * @throws SipException | 253 | * @throws SipException |
| 273 | * @throws InvalidArgumentException | 254 | * @throws InvalidArgumentException |
| 274 | * @throws ParseException | 255 | * @throws ParseException |
| 275 | */ | 256 | */ |
| 276 | - private void response100Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | 257 | + private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException { |
| 277 | Response response = getMessageFactory().createResponse(Response.TRYING, evt.getRequest()); | 258 | Response response = getMessageFactory().createResponse(Response.TRYING, evt.getRequest()); |
| 278 | getServerTransaction(evt).sendResponse(response); | 259 | getServerTransaction(evt).sendResponse(response); |
| 279 | } | 260 | } |
| 280 | 261 | ||
| 281 | - /*** | ||
| 282 | - * 回复200 OK | 262 | + /** |
| 263 | + * 回复带sdp的200 | ||
| 283 | * @param evt | 264 | * @param evt |
| 265 | + * @param sdp | ||
| 284 | * @throws SipException | 266 | * @throws SipException |
| 285 | * @throws InvalidArgumentException | 267 | * @throws InvalidArgumentException |
| 286 | * @throws ParseException | 268 | * @throws ParseException |
| 287 | */ | 269 | */ |
| 288 | private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { | 270 | private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { |
| 289 | Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); | 271 | Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); |
| 290 | - ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | 272 | + SipFactory sipFactory = SipFactory.getInstance(); |
| 273 | + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | ||
| 291 | response.setContent(sdp, contentTypeHeader); | 274 | response.setContent(sdp, contentTypeHeader); |
| 292 | - getServerTransaction(evt).sendResponse(response); | ||
| 293 | - } | ||
| 294 | 275 | ||
| 295 | - /*** | ||
| 296 | - * 回复400 | ||
| 297 | - * @param evt | ||
| 298 | - * @throws SipException | ||
| 299 | - * @throws InvalidArgumentException | ||
| 300 | - * @throws ParseException | ||
| 301 | - */ | ||
| 302 | - private void response400Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | ||
| 303 | - Response response = getMessageFactory().createResponse(Response.BAD_REQUEST, evt.getRequest()); | ||
| 304 | - getServerTransaction(evt).sendResponse(response); | ||
| 305 | - } | 276 | + SipURI sipURI = (SipURI)evt.getRequest().getRequestURI(); |
| 306 | 277 | ||
| 307 | - /*** | ||
| 308 | - * 回复404 | ||
| 309 | - * @param evt | ||
| 310 | - * @throws SipException | ||
| 311 | - * @throws InvalidArgumentException | ||
| 312 | - * @throws ParseException | ||
| 313 | - */ | ||
| 314 | - private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | ||
| 315 | - Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); | 278 | + Address concatAddress = sipFactory.createAddressFactory().createAddress( |
| 279 | + sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort() | ||
| 280 | + )); | ||
| 281 | + response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | ||
| 316 | getServerTransaction(evt).sendResponse(response); | 282 | getServerTransaction(evt).sendResponse(response); |
| 317 | } | 283 | } |
| 318 | 284 | ||
| 319 | - /*** | ||
| 320 | - * 回复415 不支持的媒体类型 | ||
| 321 | - * @param evt | ||
| 322 | - * @throws SipException | ||
| 323 | - * @throws InvalidArgumentException | ||
| 324 | - * @throws ParseException | ||
| 325 | - */ | ||
| 326 | - private void response415Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | ||
| 327 | - Response response = getMessageFactory().createResponse(Response.UNSUPPORTED_MEDIA_TYPE, evt.getRequest()); | ||
| 328 | - getServerTransaction(evt).sendResponse(response); | ||
| 329 | - } | ||
| 330 | - | ||
| 331 | - /*** | ||
| 332 | - * 回复488 | ||
| 333 | - * @param evt | ||
| 334 | - * @throws SipException | ||
| 335 | - * @throws InvalidArgumentException | ||
| 336 | - * @throws ParseException | ||
| 337 | - */ | ||
| 338 | - private void response488Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | ||
| 339 | - Response response = getMessageFactory().createResponse(Response.NOT_ACCEPTABLE_HERE, evt.getRequest()); | ||
| 340 | - getServerTransaction(evt).sendResponse(response); | ||
| 341 | - } | ||
| 342 | - | ||
| 343 | - /*** | ||
| 344 | - * 回复500 | ||
| 345 | - * @param evt | ||
| 346 | - * @throws SipException | ||
| 347 | - * @throws InvalidArgumentException | ||
| 348 | - * @throws ParseException | ||
| 349 | - */ | ||
| 350 | - private void response500Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | ||
| 351 | - Response response = getMessageFactory().createResponse(Response.SERVER_INTERNAL_ERROR, evt.getRequest()); | ||
| 352 | - getServerTransaction(evt).sendResponse(response); | ||
| 353 | - } | ||
| 354 | - | ||
| 355 | - | ||
| 356 | - | ||
| 357 | - | ||
| 358 | - | ||
| 359 | - | ||
| 360 | - | ||
| 361 | 285 | ||
| 362 | 286 | ||
| 363 | 287 | ||
| @@ -394,4 +318,12 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | @@ -394,4 +318,12 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 394 | public void setPlayService(IPlayService playService) { | 318 | public void setPlayService(IPlayService playService) { |
| 395 | this.playService = playService; | 319 | this.playService = playService; |
| 396 | } | 320 | } |
| 321 | + | ||
| 322 | + public IRedisCatchStorage getRedisCatchStorage() { | ||
| 323 | + return redisCatchStorage; | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { | ||
| 327 | + this.redisCatchStorage = redisCatchStorage; | ||
| 328 | + } | ||
| 397 | } | 329 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
| 1 | package com.genersoft.iot.vmp.media.zlm; | 1 | package com.genersoft.iot.vmp.media.zlm; |
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson.JSONObject; | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | ||
| 5 | +import com.genersoft.iot.vmp.gb28181.session.SsrcUtil; | ||
| 4 | import org.slf4j.Logger; | 6 | import org.slf4j.Logger; |
| 5 | import org.slf4j.LoggerFactory; | 7 | import org.slf4j.LoggerFactory; |
| 6 | import org.springframework.beans.factory.annotation.Autowired; | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -92,4 +94,34 @@ public class ZLMRTPServerFactory { | @@ -92,4 +94,34 @@ public class ZLMRTPServerFactory { | ||
| 92 | return currentPort++; | 94 | return currentPort++; |
| 93 | } | 95 | } |
| 94 | } | 96 | } |
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * 创建一个推流 | ||
| 100 | + * @param ip 推流ip | ||
| 101 | + * @param port 推流端口 | ||
| 102 | + * @param ssrc 推流唯一标识 | ||
| 103 | + * @param platformId 平台id | ||
| 104 | + * @param channelId 通道id | ||
| 105 | + * @param tcp 是否为tcp | ||
| 106 | + * @return SendRtpItem | ||
| 107 | + */ | ||
| 108 | + public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String channelId, boolean tcp){ | ||
| 109 | + String playSsrc = SsrcUtil.getPlaySsrc(); | ||
| 110 | + int localPort = createRTPServer(SsrcUtil.getPlaySsrc()); | ||
| 111 | + if (localPort != -1) { | ||
| 112 | + closeRTPServer(playSsrc); | ||
| 113 | + }else { | ||
| 114 | + logger.error("没有可用的端口"); | ||
| 115 | + return null; | ||
| 116 | + } | ||
| 117 | + SendRtpItem sendRtpItem = new SendRtpItem(); | ||
| 118 | + sendRtpItem.setIp(ip); | ||
| 119 | + sendRtpItem.setPort(port); | ||
| 120 | + sendRtpItem.setSsrc(ssrc); | ||
| 121 | + sendRtpItem.setPlatformId(platformId); | ||
| 122 | + sendRtpItem.setChannelId(channelId); | ||
| 123 | + sendRtpItem.setTcp(tcp); | ||
| 124 | + sendRtpItem.setLocalPort(localPort); | ||
| 125 | + return sendRtpItem; | ||
| 126 | + } | ||
| 95 | } | 127 | } |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.MediaServerConfig; | @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.MediaServerConfig; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | 5 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 6 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; | 6 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister; | 7 | import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister; |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | ||
| 8 | 9 | ||
| 9 | import java.util.Map; | 10 | import java.util.Map; |
| 10 | 11 | ||
| @@ -78,4 +79,6 @@ public interface IRedisCatchStorage { | @@ -78,4 +79,6 @@ public interface IRedisCatchStorage { | ||
| 78 | String queryPlatformRegisterInfo(String callId); | 79 | String queryPlatformRegisterInfo(String callId); |
| 79 | 80 | ||
| 80 | void delPlatformRegisterInfo(String callId); | 81 | void delPlatformRegisterInfo(String callId); |
| 82 | + | ||
| 83 | + void updateSendRTPSever(SendRtpItem sendRtpItem); | ||
| 81 | } | 84 | } |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| @@ -3,10 +3,7 @@ package com.genersoft.iot.vmp.storager.impl; | @@ -3,10 +3,7 @@ package com.genersoft.iot.vmp.storager.impl; | ||
| 3 | import com.genersoft.iot.vmp.common.StreamInfo; | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 5 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 5 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 7 | -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | ||
| 8 | -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; | ||
| 9 | -import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister; | 6 | +import com.genersoft.iot.vmp.gb28181.bean.*; |
| 10 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 7 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 11 | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; | 8 | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; |
| 12 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; | 9 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| @@ -215,4 +212,10 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | @@ -215,4 +212,10 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | ||
| 215 | public void delPlatformRegisterInfo(String callId) { | 212 | public void delPlatformRegisterInfo(String callId) { |
| 216 | redis.del(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId); | 213 | redis.del(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId); |
| 217 | } | 214 | } |
| 215 | + | ||
| 216 | + @Override | ||
| 217 | + public void updateSendRTPSever(SendRtpItem sendRtpItem) { | ||
| 218 | + String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + sendRtpItem.getPlatformId() + "_" + sendRtpItem.getChannelId(); | ||
| 219 | + redis.set(key, sendRtpItem); | ||
| 220 | + } | ||
| 218 | } | 221 | } |