Commit 1b44ba33671e27c3d206d875306b226c770b7980

Authored by panlinlin
1 parent e09e541c

完成向上级联->点播--002

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
... ... @@ -15,6 +15,7 @@ import com.alibaba.fastjson.JSON;
15 15 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
16 16 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
17 17 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  18 +import com.genersoft.iot.vmp.vmanager.service.IPlayService;
18 19 import org.slf4j.Logger;
19 20 import org.slf4j.LoggerFactory;
20 21 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -103,6 +104,9 @@ public class SIPProcessorFactory {
103 104 @Autowired
104 105 private OtherResponseProcessor otherResponseProcessor;
105 106  
  107 + @Autowired
  108 + private IPlayService playService;
  109 +
106 110  
107 111 // 注:这里使用注解会导致循环依赖注入,暂用springBean
108 112 private SipProvider tcpSipProvider;
... ... @@ -120,7 +124,9 @@ public class SIPProcessorFactory {
120 124 processor.setTcpSipProvider(getTcpSipProvider());
121 125 processor.setUdpSipProvider(getUdpSipProvider());
122 126  
  127 + processor.setCmder(cmder);
123 128 processor.setCmderFroPlatform(cmderFroPlatform);
  129 + processor.setPlayService(playService);
124 130 processor.setStorager(storager);
125 131 return processor;
126 132 } else if (Request.REGISTER.equals(method)) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
... ... @@ -10,19 +10,26 @@ import javax.sip.header.SubjectHeader;
10 10 import javax.sip.message.Request;
11 11 import javax.sip.message.Response;
12 12  
  13 +import com.alibaba.fastjson.JSONObject;
  14 +import com.genersoft.iot.vmp.gb28181.bean.Device;
13 15 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
14 16 import com.genersoft.iot.vmp.gb28181.sdp.Codec;
15 17 import com.genersoft.iot.vmp.gb28181.sdp.MediaDescription;
16 18 import com.genersoft.iot.vmp.gb28181.sdp.SdpParser;
17 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;
18 22 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
19 23 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
20 24 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
21 25 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  26 +import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
  27 +import com.genersoft.iot.vmp.vmanager.service.IPlayService;
22 28 import gov.nist.javax.sip.address.AddressImpl;
23 29 import gov.nist.javax.sip.address.SipUri;
24 30 import org.slf4j.Logger;
25 31 import org.slf4j.LoggerFactory;
  32 +import org.springframework.beans.factory.annotation.Autowired;
26 33  
27 34 import java.io.IOException;
28 35 import java.text.ParseException;
... ... @@ -41,6 +48,10 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
41 48  
42 49 private IVideoManagerStorager storager;
43 50  
  51 + private SIPCommander cmder;
  52 +
  53 + private IPlayService playService;
  54 +
44 55 /**
45 56 * 处理invite请求
46 57 *
... ... @@ -119,7 +130,30 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
119 130  
120 131  
121 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 +
122 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();
123 157 // 查找合适的端口推流,
124 158 // 发送 200ok
125 159 // 收到ack后调用推流接口
... ... @@ -149,14 +183,16 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
149 183 }
150 184  
151 185 /***
152   - * 回复404
  186 + * 回复200 OK
153 187 * @param evt
154 188 * @throws SipException
155 189 * @throws InvalidArgumentException
156 190 * @throws ParseException
157 191 */
158   - private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
159   - Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest());
  192 + private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
  193 + Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
  194 + ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  195 + response.setContent(sdp, contentTypeHeader);
160 196 getServerTransaction(evt).sendResponse(response);
161 197 }
162 198  
... ... @@ -173,6 +209,18 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
173 209 }
174 210  
175 211 /***
  212 + * 回复404
  213 + * @param evt
  214 + * @throws SipException
  215 + * @throws InvalidArgumentException
  216 + * @throws ParseException
  217 + */
  218 + private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
  219 + Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest());
  220 + getServerTransaction(evt).sendResponse(response);
  221 + }
  222 +
  223 + /***
176 224 * 回复488
177 225 * @param evt
178 226 * @throws SipException
... ... @@ -185,16 +233,14 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
185 233 }
186 234  
187 235 /***
188   - * 回复200 OK
  236 + * 回复500
189 237 * @param evt
190 238 * @throws SipException
191 239 * @throws InvalidArgumentException
192 240 * @throws ParseException
193 241 */
194   - private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
195   - Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
196   - ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
197   - response.setContent(sdp, contentTypeHeader);
  242 + private void response500Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
  243 + Response response = getMessageFactory().createResponse(Response.SERVER_INTERNAL_ERROR, evt.getRequest());
198 244 getServerTransaction(evt).sendResponse(response);
199 245 }
200 246  
... ... @@ -207,6 +253,8 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
207 253  
208 254  
209 255  
  256 +
  257 +
210 258 public SIPCommanderFroPlatform getCmderFroPlatform() {
211 259 return cmderFroPlatform;
212 260 }
... ... @@ -222,4 +270,20 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
222 270 public void setStorager(IVideoManagerStorager storager) {
223 271 this.storager = storager;
224 272 }
  273 +
  274 + public SIPCommander getCmder() {
  275 + return cmder;
  276 + }
  277 +
  278 + public void setCmder(SIPCommander cmder) {
  279 + this.cmder = cmder;
  280 + }
  281 +
  282 + public IPlayService getPlayService() {
  283 + return playService;
  284 + }
  285 +
  286 + public void setPlayService(IPlayService playService) {
  287 + this.playService = playService;
  288 + }
225 289 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
... ... @@ -234,4 +234,6 @@ public interface IVideoManagerStorager {
234 234  
235 235  
236 236 DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
  237 +
  238 + Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
237 239 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
... ... @@ -335,4 +335,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
335 335 DeviceChannel channel = patformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
336 336 return channel;
337 337 }
  338 +
  339 + @Override
  340 + public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
  341 + return null;
  342 + }
338 343 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
... ... @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 10 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
11 11 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
12 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  13 +import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
13 14 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
14 15 import org.slf4j.Logger;
15 16 import org.slf4j.LoggerFactory;
... ... @@ -64,62 +65,19 @@ public class PlayController {
64 65 @PathVariable String channelId) {
65 66  
66 67  
67   - Device device = storager.queryVideoDevice(deviceId);
68   - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
69   -
70   - UUID uuid = UUID.randomUUID();
71   - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
72   -
73   - // 录像查询以channelId作为deviceId查询
74   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
75   -
76   - if (streamInfo == null) {
77   - // 发送点播消息
78   - cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
79   - logger.info("收到订阅消息: " + response.toJSONString());
80   - playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
81   - }, event -> {
82   - RequestMessage msg = new RequestMessage();
83   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
84   - Response response = event.getResponse();
85   - msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
86   - resultHolder.invokeResult(msg);
87   - });
88   - } else {
89   - String streamId = streamInfo.getStreamId();
90   - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
91   - if (rtpInfo.getBoolean("exist")) {
92   - RequestMessage msg = new RequestMessage();
93   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
94   - msg.setData(JSON.toJSONString(streamInfo));
95   - resultHolder.invokeResult(msg);
96   - } else {
97   - redisCatchStorage.stopPlay(streamInfo);
98   - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
99   - cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
100   - logger.info("收到订阅消息: " + response.toJSONString());
101   - playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
102   - }, event -> {
103   - RequestMessage msg = new RequestMessage();
104   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
105   - Response response = event.getResponse();
106   - msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
107   - resultHolder.invokeResult(msg);
108   - });
109   - }
110   - }
  68 + PlayResult playResult = playService.play(deviceId, channelId, null, null);
111 69  
112 70 // 超时处理
113   - result.onTimeout(()->{
  71 + playResult.getResult().onTimeout(()->{
114 72 logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
115 73 // 释放rtpserver
116   - cmder.closeRTPServer(device, channelId);
  74 + cmder.closeRTPServer(playResult.getDevice(), channelId);
117 75 RequestMessage msg = new RequestMessage();
118   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  76 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
119 77 msg.setData("Timeout");
120 78 resultHolder.invokeResult(msg);
121 79 });
122   - return result;
  80 + return playResult.getResult();
123 81 }
124 82  
125 83 @PostMapping("/play/{streamId}/stop")
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/play/bean/PlayResult.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.play.bean;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  4 +import org.springframework.http.ResponseEntity;
  5 +import org.springframework.web.context.request.async.DeferredResult;
  6 +
  7 +public class PlayResult {
  8 +
  9 + private DeferredResult<ResponseEntity<String>> result;
  10 + private String uuid;
  11 +
  12 + private Device device;
  13 +
  14 + public DeferredResult<ResponseEntity<String>> getResult() {
  15 + return result;
  16 + }
  17 +
  18 + public void setResult(DeferredResult<ResponseEntity<String>> result) {
  19 + this.result = result;
  20 + }
  21 +
  22 + public String getUuid() {
  23 + return uuid;
  24 + }
  25 +
  26 + public void setUuid(String uuid) {
  27 + this.uuid = uuid;
  28 + }
  29 +
  30 + public Device getDevice() {
  31 + return device;
  32 + }
  33 +
  34 + public void setDevice(Device device) {
  35 + this.device = device;
  36 + }
  37 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java
... ... @@ -2,6 +2,11 @@ package com.genersoft.iot.vmp.vmanager.service;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  6 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  7 +import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
  8 +import org.springframework.http.ResponseEntity;
  9 +import org.springframework.web.context.request.async.DeferredResult;
5 10  
6 11 /**
7 12 * 点播处理
... ... @@ -10,4 +15,6 @@ public interface IPlayService {
10 15  
11 16 void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid);
12 17 void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid);
  18 +
  19 + PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
13 20 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
... ... @@ -4,19 +4,29 @@ import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.genersoft.iot.vmp.common.StreamInfo;
6 6 import com.genersoft.iot.vmp.conf.MediaServerConfig;
  7 +import com.genersoft.iot.vmp.gb28181.bean.Device;
7 8 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  9 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
8 10 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  12 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  13 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  14 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
10 15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 16 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
12 17 import com.genersoft.iot.vmp.vmanager.play.PlayController;
  18 +import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
13 19 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
14 20 import org.slf4j.Logger;
15 21 import org.slf4j.LoggerFactory;
16 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.http.ResponseEntity;
17 24 import org.springframework.stereotype.Service;
  25 +import org.springframework.web.context.request.async.DeferredResult;
18 26  
  27 +import javax.sip.message.Response;
19 28 import java.text.DecimalFormat;
  29 +import java.util.UUID;
20 30  
21 31 @Service
22 32 public class PlayServiceImpl implements IPlayService {
... ... @@ -27,11 +37,76 @@ public class PlayServiceImpl implements IPlayService {
27 37 private IVideoManagerStorager storager;
28 38  
29 39 @Autowired
  40 + private SIPCommander cmder;
  41 +
  42 + @Autowired
30 43 private IRedisCatchStorage redisCatchStorage;
31 44  
32 45 @Autowired
33 46 private DeferredResultHolder resultHolder;
34 47  
  48 + @Autowired
  49 + private ZLMRESTfulUtils zlmresTfulUtils;
  50 +
  51 +
  52 + @Override
  53 + public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
  54 + PlayResult playResult = new PlayResult();
  55 + Device device = storager.queryVideoDevice(deviceId);
  56 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  57 + playResult.setDevice(device);
  58 + UUID uuid = UUID.randomUUID();
  59 + playResult.setUuid(uuid.toString());
  60 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
  61 + playResult.setResult(result);
  62 + // 录像查询以channelId作为deviceId查询
  63 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
  64 +
  65 + if (streamInfo == null) {
  66 + // 发送点播消息
  67 + cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  68 + logger.info("收到订阅消息: " + response.toJSONString());
  69 + onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  70 + if (hookEvent != null) {
  71 + hookEvent.response(response);
  72 + }
  73 + }, event -> {
  74 + RequestMessage msg = new RequestMessage();
  75 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  76 + Response response = event.getResponse();
  77 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  78 + resultHolder.invokeResult(msg);
  79 + if (errorEvent != null) {
  80 + errorEvent.response(event);
  81 + }
  82 + });
  83 + } else {
  84 + String streamId = streamInfo.getStreamId();
  85 + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  86 + if (rtpInfo.getBoolean("exist")) {
  87 + RequestMessage msg = new RequestMessage();
  88 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  89 + msg.setData(JSON.toJSONString(streamInfo));
  90 + resultHolder.invokeResult(msg);
  91 + } else {
  92 + redisCatchStorage.stopPlay(streamInfo);
  93 + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
  94 + cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  95 + logger.info("收到订阅消息: " + response.toJSONString());
  96 + onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  97 + }, event -> {
  98 + RequestMessage msg = new RequestMessage();
  99 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  100 + Response response = event.getResponse();
  101 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  102 + resultHolder.invokeResult(msg);
  103 + });
  104 + }
  105 + }
  106 +
  107 + return playResult;
  108 + }
  109 +
35 110 @Override
36 111 public void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid) {
37 112 RequestMessage msg = new RequestMessage();
... ...