|
|
@@ -9,11 +9,10 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.hswebframework.web.exception.BusinessException;
|
|
|
import org.jetlinks.community.media.bean.SSRCInfo;
|
|
|
import org.jetlinks.community.media.bean.StreamInfo;
|
|
|
-import org.jetlinks.community.media.entity.MediaDeviceChannel;
|
|
|
import org.jetlinks.community.media.entity.MediaDevice;
|
|
|
import org.jetlinks.community.media.gb28181.result.WVPResult;
|
|
|
import org.jetlinks.community.media.session.VideoStreamSessionManager;
|
|
|
-import org.jetlinks.community.media.storage.impl.RedisCatchStorageImpl;
|
|
|
+import org.jetlinks.community.media.storage.impl.RedisCacheStorageImpl;
|
|
|
import org.jetlinks.community.media.transmit.callback.DeferredResultHolder;
|
|
|
import org.jetlinks.community.media.transmit.callback.RequestMessage;
|
|
|
import org.jetlinks.community.media.transmit.cmd.SipCommander;
|
|
|
@@ -28,7 +27,6 @@ import org.springframework.http.HttpStatus;
|
|
|
import org.springframework.http.ResponseEntity;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.ResourceUtils;
|
|
|
-import reactor.core.publisher.Flux;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
import java.io.FileNotFoundException;
|
|
|
import java.time.Duration;
|
|
|
@@ -47,7 +45,7 @@ public class LocalPlayService {
|
|
|
//
|
|
|
private final SipCommander cmder;
|
|
|
|
|
|
- private final RedisCatchStorageImpl redisCatchStorage;
|
|
|
+ private final RedisCacheStorageImpl redisCatchStorage;
|
|
|
|
|
|
private final LocalMediaServerItemService mediaServerItemService;
|
|
|
|
|
|
@@ -71,6 +69,9 @@ public class LocalPlayService {
|
|
|
|
|
|
public Mono<ResponseEntity> play(MediaServerItem mediaServerItem, String deviceId, String channelId,
|
|
|
ZLMHttpHookSubscribe.Event hookEvent, ZLMHttpHookSubscribe.Event errorEvent) {
|
|
|
+ //todo
|
|
|
+ mediaServerItem.setRtpEnable(false);
|
|
|
+ mediaServerItem.setRtpProxyPort(10000);
|
|
|
PlayResult playResult = new PlayResult();
|
|
|
|
|
|
String msgId=UUID.randomUUID().toString();
|
|
|
@@ -79,12 +80,86 @@ public class LocalPlayService {
|
|
|
|
|
|
final AtomicBoolean start=new AtomicBoolean(false);
|
|
|
|
|
|
- return eventBus.subscribe(
|
|
|
- Subscription
|
|
|
- .builder()
|
|
|
- .topics(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg))
|
|
|
- .features(Subscription.Feature.local)
|
|
|
- .build())
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return eventBus.subscribe(
|
|
|
+ Subscription.of("media_play",DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg), Subscription.Feature.local))
|
|
|
+ .mergeWith( Mono.justOrEmpty(redisCatchStorage.queryPlayByDevice(deviceId,channelId))
|
|
|
+ .flatMap(streamInfo -> {
|
|
|
+ if(StrUtil.isEmpty(streamInfo.getStreamId())){
|
|
|
+ return Mono.error(new BusinessException("点播失败, redis缓存streamId等于null"));
|
|
|
+ }
|
|
|
+ String mediaServerId = streamInfo.getMediaServerId();
|
|
|
+ MediaServerItem mediaInfo = mediaServerItemService.getOne(mediaServerId);
|
|
|
+
|
|
|
+ JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamInfo.getStreamId());
|
|
|
+ if (rtpInfo != null && rtpInfo.getBool("exist")) {
|
|
|
+ if (hookEvent != null) {
|
|
|
+ //todo
|
|
|
+// hookEvent.response(mediaServerItem, com.alibaba.fastjson.JSONObject.parseObject(JSON.toJSONString(streamInfo)));
|
|
|
+ }
|
|
|
+ clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
+ ResponseEntity.ok(streamInfo));
|
|
|
+ } else {
|
|
|
+ // TODO 点播前是否重置状态
|
|
|
+ redisCatchStorage.stopPlay(streamInfo);
|
|
|
+ return deviceChannelService.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId())
|
|
|
+ .flatMap(ignore->{
|
|
|
+ SSRCInfo ssrcInfo;
|
|
|
+ String streamId2 = null;
|
|
|
+ if (mediaServerItem.isRtpEnable()) {
|
|
|
+ streamId2 = String.format("%s_%s",deviceId, channelId);
|
|
|
+ }
|
|
|
+ ssrcInfo = mediaServerItemService.openRTPServer(mediaServerItem, streamId2);
|
|
|
+
|
|
|
+ return cmder.playStreamCmd(mediaServerItem, ssrcInfo, redisCatchStorage.getDevice(deviceId), channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
|
|
+ log.info("收到订阅消息: " + response.toString());
|
|
|
+ onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, msgId)
|
|
|
+ .subscribe();
|
|
|
+ }, (event) -> {
|
|
|
+ mediaServerItemService.closeRTPServer(playResult.getDevice(), channelId);
|
|
|
+ WVPResult wvpResult = WVPResult.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg),null);
|
|
|
+ clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
+ ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(wvpResult));
|
|
|
+ })
|
|
|
+ .then();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return Mono.empty();
|
|
|
+ })
|
|
|
+ .switchIfEmpty(Mono.just(mediaServerItem)
|
|
|
+ .flatMap(serverItem->{
|
|
|
+ SSRCInfo ssrcInfo;
|
|
|
+ String streamId = null;
|
|
|
+ if (serverItem.isRtpEnable()) {
|
|
|
+ streamId = String.format("%s_%s", deviceId, channelId);
|
|
|
+ }
|
|
|
+
|
|
|
+ ssrcInfo = mediaServerItemService.openRTPServer(serverItem, streamId);
|
|
|
+
|
|
|
+ // 发送点播消息
|
|
|
+ MediaDevice device = redisCatchStorage.getDevice(deviceId);
|
|
|
+ return cmder.playStreamCmd(serverItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
|
|
|
+ log.info("收到订阅消息: " + response.toString());
|
|
|
+ onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, msgId).subscribe();
|
|
|
+ if (hookEvent != null) {
|
|
|
+// hookEvent.response(mediaServerItem, response);
|
|
|
+ }
|
|
|
+ }, (event) -> {
|
|
|
+ WVPResult wvpResult = WVPResult.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
|
|
|
+ // 点播返回sip错误
|
|
|
+ mediaServerItemService.closeRTPServer(playResult.getDevice(), channelId);
|
|
|
+ clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
+ ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(wvpResult));
|
|
|
+ if (errorEvent != null) {
|
|
|
+ //todo
|
|
|
+// errorEvent.response(event);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then();
|
|
|
+ })).then(Mono.empty()))
|
|
|
+
|
|
|
//超时报错 todo
|
|
|
.timeout(Duration.ofSeconds(10), Mono.error(new BusinessException("点播/收流超时,请稍候重试")))
|
|
|
//报错时,发送bye指令
|
|
|
@@ -139,84 +214,6 @@ public class LocalPlayService {
|
|
|
//保证接下来的操作流仅被触发一次
|
|
|
.filter(ignore->!start.get())
|
|
|
.doOnNext(ignore->start.set(true))
|
|
|
-
|
|
|
- .concatWith(
|
|
|
- Mono.fromRunnable(()->
|
|
|
- Mono.just(redisCatchStorage.queryPlayByDevice(deviceId,channelId))
|
|
|
- .flatMap(streamInfo -> {
|
|
|
- if(StrUtil.isEmpty(streamInfo.getStreamId())){
|
|
|
- return Mono.error(new BusinessException("点播失败, redis缓存streamId等于null"));
|
|
|
- }
|
|
|
- String mediaServerId = streamInfo.getMediaServerId();
|
|
|
- MediaServerItem mediaInfo = mediaServerItemService.getOne(mediaServerId);
|
|
|
-
|
|
|
- JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamInfo.getStreamId());
|
|
|
- if (rtpInfo != null && rtpInfo.getBool("exist")) {
|
|
|
- if (hookEvent != null) {
|
|
|
- //todo
|
|
|
-// hookEvent.response(mediaServerItem, com.alibaba.fastjson.JSONObject.parseObject(JSON.toJSONString(streamInfo)));
|
|
|
- }
|
|
|
- clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
- ResponseEntity.ok(streamInfo));
|
|
|
- } else {
|
|
|
- // TODO 点播前是否重置状态
|
|
|
- redisCatchStorage.stopPlay(streamInfo);
|
|
|
- return deviceChannelService.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId())
|
|
|
- .flatMap(ignore->{
|
|
|
- SSRCInfo ssrcInfo;
|
|
|
- String streamId2 = null;
|
|
|
- if (mediaServerItem.isRtpEnable()) {
|
|
|
- streamId2 = String.format("%s_%s",deviceId, channelId);
|
|
|
- }
|
|
|
- ssrcInfo = mediaServerItemService.openRTPServer(mediaServerItem, streamId2);
|
|
|
-
|
|
|
- return cmder.playStreamCmd(mediaServerItem, ssrcInfo, redisCatchStorage.getDevice(deviceId), channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
|
|
- log.info("收到订阅消息: " + response.toString());
|
|
|
- onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, msgId)
|
|
|
- .subscribe();
|
|
|
- }, (event) -> {
|
|
|
- mediaServerItemService.closeRTPServer(playResult.getDevice(), channelId);
|
|
|
- WVPResult wvpResult = WVPResult.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg),null);
|
|
|
- clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
- ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(wvpResult));
|
|
|
- })
|
|
|
- .then();
|
|
|
- });
|
|
|
- }
|
|
|
- return Mono.empty();
|
|
|
- })
|
|
|
- .switchIfEmpty(Mono.just(mediaServerItem)
|
|
|
- .flatMap(serverItem->{
|
|
|
- SSRCInfo ssrcInfo;
|
|
|
- String streamId = null;
|
|
|
- if (serverItem.isRtpEnable()) {
|
|
|
- streamId = String.format("%s_%s", deviceId, channelId);
|
|
|
- }
|
|
|
-
|
|
|
- ssrcInfo = mediaServerItemService.openRTPServer(serverItem, streamId);
|
|
|
-
|
|
|
- // 发送点播消息
|
|
|
- return cmder.playStreamCmd(serverItem, ssrcInfo, redisCatchStorage.getDevice(deviceId), channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
|
|
|
- log.info("收到订阅消息: " + response.toString());
|
|
|
- onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, msgId).subscribe();
|
|
|
- if (hookEvent != null) {
|
|
|
-// hookEvent.response(mediaServerItem, response);
|
|
|
- }
|
|
|
- }, (event) -> {
|
|
|
- WVPResult wvpResult = WVPResult.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
|
|
|
- // 点播返回sip错误
|
|
|
- mediaServerItemService.closeRTPServer(playResult.getDevice(), channelId);
|
|
|
- clusterEventBus.publish(DeferredResultHolder.getTopicByDeviceIdAndChannelId(DeferredResultHolder.CALLBACK_CMD_PLAY, msg),
|
|
|
- ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(wvpResult));
|
|
|
- if (errorEvent != null) {
|
|
|
- //todo
|
|
|
-// errorEvent.response(event);
|
|
|
- }
|
|
|
- })
|
|
|
- .then();
|
|
|
- }))
|
|
|
- .subscribe()
|
|
|
- ))
|
|
|
.doOnError(BusinessException.class, e -> cmder.streamByeCmd(deviceId, channelId).subscribe())
|
|
|
.single();
|
|
|
}
|
|
|
@@ -252,7 +249,7 @@ public class LocalPlayService {
|
|
|
if (device == null) {
|
|
|
return Mono.empty();
|
|
|
}
|
|
|
- return Mono.just(device.getMediaServerId())
|
|
|
+ return Mono.justOrEmpty(device.getMediaServerId())
|
|
|
.flatMap(mediaServerItemService::findById)
|
|
|
//找不到设备相应的媒体流服务器则根据负载均衡获取相应的媒体流服务器
|
|
|
.switchIfEmpty(mediaServerItemService.getMediaServerForMinimumLoad())
|