diff --git a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxy.java b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxy.java new file mode 100644 index 0000000..e3e25a7 --- /dev/null +++ b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxy.java @@ -0,0 +1,42 @@ +package cn.skcks.docking.gb28181.media.dto.proxy; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; + +@Data +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +public class AddStreamPusherProxy { + /** + * 添加的流的虚拟主机,例如__defaultVhost__ + */ + private String vhost = "__defaultVhost__"; + /** + * 协议,例如 rtsp或rtmp + */ + private String schema; + /** + * 添加的流的应用名,例如live + */ + private String app; + /** + * 需要转推的流id + */ + private String stream; + /** + * 目标转推url,带参数需要自行url转义 + */ + private String dstUrl; + /** + * 转推失败重试次数,默认无限重试 + */ + private Integer retryCount; + /** + * rtsp推流时,推流方式,0:tcp,1:udp + */ + private Integer rtpType; + /** + * 推流超时时间,单位秒,float类型 + */ + private Double timeoutSec; +} diff --git a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxyResp.java b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxyResp.java new file mode 100644 index 0000000..f689fb9 --- /dev/null +++ b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/AddStreamPusherProxyResp.java @@ -0,0 +1,8 @@ +package cn.skcks.docking.gb28181.media.dto.proxy; + +import lombok.Data; + +@Data +public class AddStreamPusherProxyResp { + private String key; +} diff --git a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/DelStreamPusherProxyResp.java b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/DelStreamPusherProxyResp.java new file mode 100644 index 0000000..0a24d52 --- /dev/null +++ b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/dto/proxy/DelStreamPusherProxyResp.java @@ -0,0 +1,8 @@ +package cn.skcks.docking.gb28181.media.dto.proxy; + +import lombok.Data; + +@Data +public class DelStreamPusherProxyResp { + private Boolean flag; +} diff --git a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaHttpClient.java b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaHttpClient.java index 616e749..bb1f050 100644 --- a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaHttpClient.java +++ b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaHttpClient.java @@ -1,6 +1,9 @@ package cn.skcks.docking.gb28181.media.proxy; import cn.skcks.docking.gb28181.media.dto.config.ServerConfig; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxy; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxyResp; +import cn.skcks.docking.gb28181.media.dto.proxy.DelStreamPusherProxyResp; import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse; import cn.skcks.docking.gb28181.media.dto.rtp.CloseRtpServer; import cn.skcks.docking.gb28181.media.dto.rtp.CloseRtpServerResp; @@ -40,4 +43,10 @@ public interface ZlmMediaHttpClient { @GetMapping("/index/api/version") ZlmResponse version(@RequestParam String secret); + + @PostMapping("/index/api/addStreamPusherProxy") + ZlmResponse addStreamPusherProxy(@RequestParam String secret, @RequestBody AddStreamPusherProxy params); + + @PostMapping("/index/api/delStreamPusherProxy") + ZlmResponse delStreamPusherProxy(@RequestParam String secret, @RequestParam String key); } diff --git a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaService.java b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaService.java index 05bdb4c..74e0af0 100644 --- a/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaService.java +++ b/zlmediakit-service/src/main/java/cn/skcks/docking/gb28181/media/proxy/ZlmMediaService.java @@ -1,31 +1,37 @@ package cn.skcks.docking.gb28181.media.proxy; -import cn.skcks.docking.gb28181.common.json.JsonUtils; import cn.skcks.docking.gb28181.media.dto.config.ServerConfig; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxy; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxyResp; +import cn.skcks.docking.gb28181.media.dto.proxy.DelStreamPusherProxyResp; import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse; import cn.skcks.docking.gb28181.media.dto.rtp.CloseRtpServer; import cn.skcks.docking.gb28181.media.dto.rtp.CloseRtpServerResp; import cn.skcks.docking.gb28181.media.dto.rtp.OpenRtpServer; import cn.skcks.docking.gb28181.media.dto.rtp.OpenRtpServerResp; import cn.skcks.docking.gb28181.media.dto.version.VersionResp; -import com.fasterxml.jackson.core.type.TypeReference; import lombok.Builder; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; -import java.util.Map; @Builder +@SuppressWarnings("unused") public class ZlmMediaService { private String secret; private ZlmMediaHttpClient exchange; + /** + * 功能:获取API列表 + */ public ZlmResponse> getApiList() { return exchange.getApiList(secret); } - + /** + * 功能:获取服务器配置 + */ public ZlmResponse> getServerConfig() { return exchange.getServerConfig(secret); } @@ -35,19 +41,49 @@ public class ZlmMediaService { return exchange.getServerConfigResponseEntity(secret); } + /** + * 功能:设置服务器配置 + */ public String setServerConfig(ServerConfig config){ return exchange.setServerConfig(secret, config); } + /** + * 功能:创建GB28181 RTP接收端口,如果该端口接收数据超时,则会自动被回收(不用调用closeRtpServer接口) + */ public OpenRtpServerResp openRtpServer(OpenRtpServer params){ return exchange.openRtpServer(secret, params); } + /** + * 关闭GB28181 RTP接收端口 + */ public CloseRtpServerResp closeRtpServer(CloseRtpServer params){ return exchange.closeRtpServer(secret, params); } + /** + * 功能:获取版本信息,如分支,commit id, 编译时间 + */ public ZlmResponse version(){ return exchange.version(secret); } + + /** + * 添加rtsp/rtmp主动推流(把本服务器的直播流推送到其他服务器去) + */ + public ZlmResponse addStreamPusherProxy(AddStreamPusherProxy params){ + return exchange.addStreamPusherProxy(secret, params); + } + + /** + * + * 功能:关闭推流 + *

(可以使用close_streams接口关闭源直播流也可以停止推流)

+ * @param key addStreamPusherProxy 接口返回的key + */ + public ZlmResponse delStreamPusherProxy(@RequestParam String key) { + return exchange.delStreamPusherProxy(secret, key); + } } + diff --git a/zlmediakit-service/src/test/java/cn/skcks/docking/gb28181/test/MediaServiceTest.java b/zlmediakit-service/src/test/java/cn/skcks/docking/gb28181/test/MediaServiceTest.java index 3b9ad12..6b5cef2 100644 --- a/zlmediakit-service/src/test/java/cn/skcks/docking/gb28181/test/MediaServiceTest.java +++ b/zlmediakit-service/src/test/java/cn/skcks/docking/gb28181/test/MediaServiceTest.java @@ -1,9 +1,12 @@ package cn.skcks.docking.gb28181.test; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.skcks.docking.gb28181.common.json.JsonResponse; +import cn.skcks.docking.gb28181.media.dto.config.HookConfig; import cn.skcks.docking.gb28181.media.dto.config.ServerConfig; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxy; +import cn.skcks.docking.gb28181.media.dto.proxy.AddStreamPusherProxyResp; +import cn.skcks.docking.gb28181.media.dto.proxy.DelStreamPusherProxyResp; import cn.skcks.docking.gb28181.media.dto.response.ZlmResponse; import cn.skcks.docking.gb28181.media.dto.response.ZlmResponseConvertor; import cn.skcks.docking.gb28181.media.dto.rtp.CloseRtpServer; @@ -32,7 +35,7 @@ import java.util.*; @ExtendWith(SpringExtension.class) public class MediaServiceTest { @Autowired - private ZlmMediaService zlMediaHttpService; + private ZlmMediaService zlmMediaService; @Test void test(){ @@ -50,10 +53,10 @@ public class MediaServiceTest { @Test void context(){ - ResponseEntity entity = zlMediaHttpService.getServerConfigResponseEntity(); + ResponseEntity entity = zlmMediaService.getServerConfigResponseEntity(); log.info("{}", entity.getBody()); - ZlmResponse> test = zlMediaHttpService.getServerConfig(); + ZlmResponse> test = zlmMediaService.getServerConfig(); JsonResponse> jsonResponse = test.getJsonResponse(); log.info("{}", jsonResponse); @@ -65,19 +68,19 @@ public class MediaServiceTest { @Test @SneakyThrows void testApi(){ - log.info("{}", zlMediaHttpService.getApiList()); + log.info("{}", zlmMediaService.getApiList()); int port = 60000; String streamId = "testStream"; OpenRtpServer openRtpServer = new OpenRtpServer(port,0,streamId); - log.info("{}", zlMediaHttpService.openRtpServer(openRtpServer)); + log.info("{}", zlmMediaService.openRtpServer(openRtpServer)); Thread.sleep(500); CloseRtpServer closeRtpServer = new CloseRtpServer(streamId); - log.info("{}", zlMediaHttpService.closeRtpServer(closeRtpServer)); + log.info("{}", zlmMediaService.closeRtpServer(closeRtpServer)); } @Test void version(){ - ZlmResponse versionResp = zlMediaHttpService.version(); + ZlmResponse versionResp = zlmMediaService.version(); log.info("{}", versionResp); Date date = versionResp.getData().getBuildTime(); log.info("{}", date); @@ -87,20 +90,51 @@ public class MediaServiceTest { @Test void configTest(){ - ZlmResponse> resp = zlMediaHttpService.getServerConfig(); + ZlmResponse> resp = zlmMediaService.getServerConfig(); log.info("{}", resp); ServerConfig config = resp.getData().get(0); config.getApi().setApiDebug(0); - log.info("{}", zlMediaHttpService.setServerConfig(config)); + log.info("{}", zlmMediaService.setServerConfig(config)); - resp = zlMediaHttpService.getServerConfig(); + resp = zlmMediaService.getServerConfig(); log.info("{}", resp); config.getApi().setApiDebug(1); - log.info("{}", zlMediaHttpService.setServerConfig(config)); + log.info("{}", zlmMediaService.setServerConfig(config)); - resp = zlMediaHttpService.getServerConfig(); + resp = zlmMediaService.getServerConfig(); log.info("{}", resp); - log.info("{}", zlMediaHttpService.setServerConfig(config)); + log.info("{}", zlmMediaService.setServerConfig(config)); + } + + @Test + void emptyHookConfigTest(){ + ZlmResponse> resp = zlmMediaService.getServerConfig(); + log.info("{}", resp); + ServerConfig config = resp.getData().get(0); + config.setHook(new HookConfig()); + log.info("{}", zlmMediaService.setServerConfig(config)); + log.info("{}", zlmMediaService.getServerConfig()); + } + + /** + *

先清空 hook 后

+ *

再使用 ffmpeg 或其他推流工具

+ *

推流到 zlm 服务的 /live/test 再执行此测试

+ */ + @Test + void streamPusherProxyTest(){ + AddStreamPusherProxy addStreamPusherProxy = new AddStreamPusherProxy(); + addStreamPusherProxy.setSchema("rtmp"); + addStreamPusherProxy.setApp("live"); + addStreamPusherProxy.setStream("test"); + addStreamPusherProxy.setDstUrl("rtmp://127.0.0.1/live/test2"); + + ZlmResponse addStreamPusherProxyRespZlmResponse = zlmMediaService.addStreamPusherProxy(addStreamPusherProxy); + log.info("{}", addStreamPusherProxyRespZlmResponse); + AddStreamPusherProxyResp data = addStreamPusherProxyRespZlmResponse.getData(); + String key = Optional.ofNullable(data).orElse(new AddStreamPusherProxyResp()).getKey(); + ZlmResponse delStreamPusherProxyRespZlmResponse = zlmMediaService.delStreamPusherProxy(key); + log.info("{}",delStreamPusherProxyRespZlmResponse); } }