Commit c1b3f2beb4b76e89d4938d2f7d5b31ff0f10220d
1 parent
9d19f6b9
国标级联--点播-未完成
Showing
5 changed files
with
128 additions
and
61 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
| ... | ... | @@ -10,6 +10,7 @@ import javax.sip.message.Request; |
| 10 | 10 | import javax.sip.message.Response; |
| 11 | 11 | |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 13 | +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | |
| 13 | 14 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 14 | 15 | import com.alibaba.fastjson.JSON; |
| 15 | 16 | import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; |
| ... | ... | @@ -107,6 +108,9 @@ public class SIPProcessorFactory { |
| 107 | 108 | @Autowired |
| 108 | 109 | private IPlayService playService; |
| 109 | 110 | |
| 111 | + @Autowired | |
| 112 | + private ZLMRTPServerFactory zlmrtpServerFactory; | |
| 113 | + | |
| 110 | 114 | |
| 111 | 115 | // 注:这里使用注解会导致循环依赖注入,暂用springBean |
| 112 | 116 | private SipProvider tcpSipProvider; |
| ... | ... | @@ -128,6 +132,7 @@ public class SIPProcessorFactory { |
| 128 | 132 | processor.setCmderFroPlatform(cmderFroPlatform); |
| 129 | 133 | processor.setPlayService(playService); |
| 130 | 134 | processor.setStorager(storager); |
| 135 | + processor.setZlmrtpServerFactory(zlmrtpServerFactory); | |
| 131 | 136 | return processor; |
| 132 | 137 | } else if (Request.REGISTER.equals(method)) { |
| 133 | 138 | RegisterRequestProcessor processor = new RegisterRequestProcessor(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.request.impl; |
| 2 | 2 | |
| 3 | +import javax.sdp.*; | |
| 3 | 4 | import javax.sip.InvalidArgumentException; |
| 4 | 5 | import javax.sip.RequestEvent; |
| 5 | 6 | import javax.sip.SipException; |
| ... | ... | @@ -11,20 +12,18 @@ import javax.sip.message.Request; |
| 11 | 12 | import javax.sip.message.Response; |
| 12 | 13 | |
| 13 | 14 | import com.alibaba.fastjson.JSONObject; |
| 15 | +import com.genersoft.iot.vmp.conf.MediaServerConfig; | |
| 14 | 16 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 15 | 17 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 16 | -import com.genersoft.iot.vmp.gb28181.sdp.Codec; | |
| 17 | -import com.genersoft.iot.vmp.gb28181.sdp.MediaDescription; | |
| 18 | -import com.genersoft.iot.vmp.gb28181.sdp.SdpParser; | |
| 19 | -import com.genersoft.iot.vmp.gb28181.sdp.SessionDescription; | |
| 20 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 21 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 22 | 18 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 23 | 19 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 24 | 20 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; |
| 21 | +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | |
| 22 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 25 | 23 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 26 | 24 | import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; |
| 27 | 25 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| 26 | +import gov.nist.javax.sdp.fields.SDPFormat; | |
| 28 | 27 | import gov.nist.javax.sip.address.AddressImpl; |
| 29 | 28 | import gov.nist.javax.sip.address.SipUri; |
| 30 | 29 | import org.slf4j.Logger; |
| ... | ... | @@ -34,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired; |
| 34 | 33 | import java.io.IOException; |
| 35 | 34 | import java.text.ParseException; |
| 36 | 35 | import java.util.List; |
| 36 | +import java.util.UUID; | |
| 37 | +import java.util.Vector; | |
| 37 | 38 | |
| 38 | 39 | /** |
| 39 | 40 | * @Description:处理INVITE请求 |
| ... | ... | @@ -48,10 +49,22 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { |
| 48 | 49 | |
| 49 | 50 | private IVideoManagerStorager storager; |
| 50 | 51 | |
| 52 | + private IRedisCatchStorage redisCatchStorage; | |
| 53 | + | |
| 51 | 54 | private SIPCommander cmder; |
| 52 | 55 | |
| 53 | 56 | private IPlayService playService; |
| 54 | 57 | |
| 58 | + private ZLMRTPServerFactory zlmrtpServerFactory; | |
| 59 | + | |
| 60 | + public ZLMRTPServerFactory getZlmrtpServerFactory() { | |
| 61 | + return zlmrtpServerFactory; | |
| 62 | + } | |
| 63 | + | |
| 64 | + public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { | |
| 65 | + this.zlmrtpServerFactory = zlmrtpServerFactory; | |
| 66 | + } | |
| 67 | + | |
| 55 | 68 | /** |
| 56 | 69 | * 处理invite请求 |
| 57 | 70 | * |
| ... | ... | @@ -98,64 +111,105 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { |
| 98 | 111 | }else { |
| 99 | 112 | response100Ack(evt); // 通道存在,发100,trying |
| 100 | 113 | } |
| 101 | - // 解析sdp消息 | |
| 102 | - SessionDescription sdp = new SdpParser().parse(request.getRawContent()); | |
| 114 | + // 解析sdp消息, 使用jainsip 自带的sdp解析方式 | |
| 115 | + String contentString = new String(request.getRawContent()); | |
| 116 | + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(contentString); | |
| 117 | + | |
| 118 | + // TODO 区分TCP发流还是udp, 当前默认udp | |
| 103 | 119 | // 获取支持的格式 |
| 104 | - List<MediaDescription> mediaDescriptions = sdp.getMediaDescriptions(); | |
| 120 | + Vector mediaDescriptions = sdp.getMediaDescriptions(true); | |
| 105 | 121 | // 查看是否支持PS 负载96 |
| 106 | 122 | String ip = null; |
| 107 | 123 | int port = -1; |
| 108 | - for (MediaDescription mediaDescription : mediaDescriptions) { | |
| 109 | - | |
| 110 | - List<Codec> codecs = mediaDescription.getCodecs(); | |
| 111 | - for (Codec codec : codecs) { | |
| 112 | - if("96".equals(codec.getPayloadType()) || "PS".equals(codec.getName()) || "ps".equals(codec.getName())) { | |
| 113 | - ip = mediaDescription.getIpAddress().getHostName(); | |
| 114 | - port = mediaDescription.getPort(); | |
| 115 | - break; | |
| 116 | - } | |
| 117 | - } | |
| 118 | - } | |
| 119 | - if (ip == null || port == -1) { // TODO 没有合适的视频流格式, 可配置是否使用第一个media信息 | |
| 120 | - if (mediaDescriptions.size() > 0) { | |
| 121 | - ip = mediaDescriptions.get(0).getIpAddress().getHostName(); | |
| 122 | - port = mediaDescriptions.get(0).getPort(); | |
| 123 | - } | |
| 124 | + for (int i = 0; i < mediaDescriptions.size(); i++) { | |
| 125 | + MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i); | |
| 126 | + Media media = mediaDescription.getMedia(); | |
| 127 | + port = media.getMediaPort(); | |
| 124 | 128 | } |
| 125 | - | |
| 126 | - if (ip == null || port == -1) { | |
| 127 | - response488Ack(evt); | |
| 128 | - return; | |
| 129 | - } | |
| 130 | - | |
| 131 | - | |
| 132 | - String ssrc = sdp.getSsrc(); | |
| 133 | - | |
| 134 | - Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | |
| 135 | - if (device == null) { | |
| 136 | - logger.warn("点播平台{}的通道{}时未找到设备信息", platformId, channel); | |
| 137 | - response500Ack(evt); | |
| 138 | - return; | |
| 139 | - } | |
| 140 | - | |
| 141 | - // 通知下级推流, | |
| 142 | - PlayResult playResult = playService.play(device.getDeviceId(), channelId, (response)->{ | |
| 143 | - // 收到推流, 回复200OK | |
| 144 | - | |
| 145 | - },(event -> { | |
| 146 | - // 未知错误。直接转发设备点播的错误 | |
| 147 | - Response response = null; | |
| 148 | - try { | |
| 149 | - response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); | |
| 150 | - getServerTransaction(evt).sendResponse(response); | |
| 151 | - | |
| 152 | - } catch (ParseException | SipException | InvalidArgumentException e) { | |
| 153 | - e.printStackTrace(); | |
| 154 | - } | |
| 155 | - })); | |
| 156 | - playResult.getResult(); | |
| 129 | +// for (MediaDescription mediaDescription : mediaDescriptions) { | |
| 130 | +// | |
| 131 | +// List<Codec> codecs = mediaDescription.getCodecs(); | |
| 132 | +// for (Codec codec : codecs) { | |
| 133 | +// if("96".equals(codec.getPayloadType()) || "PS".equals(codec.getName()) || "ps".equals(codec.getName())) { | |
| 134 | +// // TODO 这里很慢 | |
| 135 | +// ip = mediaDescription.getIpAddress().getHostName(); | |
| 136 | +// port = mediaDescription.getPort(); | |
| 137 | +// break; | |
| 138 | +// } | |
| 139 | +// } | |
| 140 | +// } | |
| 141 | +// if (ip == null || port == -1) { // TODO 没有合适的视频流格式, 可配置是否使用第一个media信息 | |
| 142 | +// if (mediaDescriptions.size() > 0) { | |
| 143 | +// ip = mediaDescriptions.get(0).getIpAddress().getHostName(); | |
| 144 | +// port = mediaDescriptions.get(0).getPort(); | |
| 145 | +// } | |
| 146 | +// } | |
| 147 | +// | |
| 148 | +// if (ip == null || port == -1) { | |
| 149 | +// response488Ack(evt); | |
| 150 | +// return; | |
| 151 | +// } | |
| 152 | +// | |
| 153 | +// | |
| 154 | +// String ssrc = sdp.getSsrc(); | |
| 155 | +// | |
| 156 | +// Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | |
| 157 | +// if (device == null) { | |
| 158 | +// logger.warn("点播平台{}的通道{}时未找到设备信息", platformId, channel); | |
| 159 | +// response500Ack(evt); | |
| 160 | +// return; | |
| 161 | +// } | |
| 162 | +// | |
| 163 | +// // 通知下级推流, | |
| 164 | +// PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{ | |
| 165 | +// // 收到推流, 回复200OK | |
| 166 | +// UUID uuid = UUID.randomUUID(); | |
| 167 | +// int rtpServer = zlmrtpServerFactory.createRTPServer(uuid.toString()); | |
| 168 | +// if (rtpServer == -1) { | |
| 169 | +// logger.error("为获取到可用端口"); | |
| 170 | +// return; | |
| 171 | +// }else { | |
| 172 | +// zlmrtpServerFactory.closeRTPServer(uuid.toString()); | |
| 173 | +// } | |
| 174 | +// // TODO 添加对tcp的支持 | |
| 175 | +// MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); | |
| 176 | +// StringBuffer content = new StringBuffer(200); | |
| 177 | +// content.append("v=0\r\n"); | |
| 178 | +// content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | |
| 179 | +// content.append("s=Play\r\n"); | |
| 180 | +// content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | |
| 181 | +// content.append("t=0 0\r\n"); | |
| 182 | +// content.append("m=video "+ rtpServer+" RTP/AVP 96\r\n"); | |
| 183 | +// content.append("a=sendonly\r\n"); | |
| 184 | +// content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 185 | +// content.append("y="+ ssrc + "\r\n"); | |
| 186 | +// content.append("f=\r\n"); | |
| 187 | +// | |
| 188 | +// try { | |
| 189 | +// responseAck(evt, content.toString()); | |
| 190 | +// } catch (SipException e) { | |
| 191 | +// e.printStackTrace(); | |
| 192 | +// } catch (InvalidArgumentException e) { | |
| 193 | +// e.printStackTrace(); | |
| 194 | +// } catch (ParseException e) { | |
| 195 | +// e.printStackTrace(); | |
| 196 | +// } | |
| 197 | +// | |
| 198 | +// // 写入redis, 超时时回复 | |
| 199 | +//// redisCatchStorage.waiteAck() | |
| 200 | +// },(event -> { | |
| 201 | +// // 未知错误。直接转发设备点播的错误 | |
| 202 | +// Response response = null; | |
| 203 | +// try { | |
| 204 | +// response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); | |
| 205 | +// getServerTransaction(evt).sendResponse(response); | |
| 206 | +// | |
| 207 | +// } catch (ParseException | SipException | InvalidArgumentException e) { | |
| 208 | +// e.printStackTrace(); | |
| 209 | +// } | |
| 210 | +// })); | |
| 211 | +// playResult.getResult(); | |
| 157 | 212 | // 查找合适的端口推流, |
| 158 | - // 发送 200ok | |
| 159 | 213 | // 收到ack后调用推流接口 |
| 160 | 214 | |
| 161 | 215 | |
| ... | ... | @@ -163,9 +217,12 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { |
| 163 | 217 | |
| 164 | 218 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 165 | 219 | e.printStackTrace(); |
| 166 | - } catch (IOException e) { | |
| 167 | 220 | logger.warn("sdp解析错误"); |
| 168 | 221 | e.printStackTrace(); |
| 222 | + } catch (SdpParseException e) { | |
| 223 | + e.printStackTrace(); | |
| 224 | + } catch (SdpException e) { | |
| 225 | + e.printStackTrace(); | |
| 169 | 226 | } |
| 170 | 227 | |
| 171 | 228 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PatformChannelMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 3 | 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 4 | 5 | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| 5 | 6 | import org.apache.ibatis.annotations.Delete; |
| ... | ... | @@ -45,4 +46,7 @@ public interface PatformChannelMapper { |
| 45 | 46 | @Select("SELECT * FROM device_channel WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE " + |
| 46 | 47 | "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'") |
| 47 | 48 | DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); |
| 49 | + | |
| 50 | + @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')") | |
| 51 | + Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); | |
| 48 | 52 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
| ... | ... | @@ -338,6 +338,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 338 | 338 | |
| 339 | 339 | @Override |
| 340 | 340 | public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) { |
| 341 | - return null; | |
| 341 | + Device device = patformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); | |
| 342 | + return device; | |
| 342 | 343 | } |
| 343 | 344 | } | ... | ... |
web_src/.postcssrc.js