|
@@ -1,8 +1,14 @@
|
|
|
package org.jetlinks.pro.media.service;
|
|
|
|
|
|
+import java.time.Duration;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
+import javax.annotation.PostConstruct;
|
|
|
+import javax.annotation.PreDestroy;
|
|
|
import lombok.Setter;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
|
|
|
+import org.hswebframework.web.bean.FastBeanCopier;
|
|
|
import org.hswebframework.web.crud.events.EntityDeletedEvent;
|
|
|
import org.hswebframework.web.crud.service.GenericReactiveCrudService;
|
|
|
import org.jetlinks.core.event.EventBus;
|
|
@@ -16,25 +22,23 @@ import org.jetlinks.pro.media.entity.MediaGatewayEntity;
|
|
|
import org.jetlinks.pro.media.entity.MediaStreamEntity;
|
|
|
import org.jetlinks.pro.media.enums.ChannelSyncState;
|
|
|
import org.jetlinks.pro.media.enums.GatewayStatus;
|
|
|
-import org.jetlinks.pro.media.gb28181.cascade.CascadeStreamInfo;
|
|
|
+import org.jetlinks.pro.media.gb28181.RedisSsrcPool;
|
|
|
+import org.jetlinks.pro.media.gb28181.SsrcPool;
|
|
|
import org.jetlinks.pro.media.server.DeviceStreamInfo;
|
|
|
import org.jetlinks.pro.media.server.StreamInfo;
|
|
|
import org.jetlinks.pro.media.server.StreamManager;
|
|
|
+import org.jetlinks.pro.media.sip.SipProperties;
|
|
|
import org.reactivestreams.Publisher;
|
|
|
import org.springframework.beans.factory.ObjectProvider;
|
|
|
import org.springframework.boot.CommandLineRunner;
|
|
|
import org.springframework.context.event.EventListener;
|
|
|
+import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
import reactor.core.Disposable;
|
|
|
import reactor.core.publisher.Flux;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
-import javax.annotation.PreDestroy;
|
|
|
-import java.time.Duration;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
-
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class MediaGatewayService extends GenericReactiveCrudService<MediaGatewayEntity, String> implements CommandLineRunner {
|
|
@@ -52,14 +56,21 @@ public class MediaGatewayService extends GenericReactiveCrudService<MediaGateway
|
|
|
|
|
|
private MediaChannelService channelService;
|
|
|
|
|
|
- public MediaGatewayService(EventBus eventBus,
|
|
|
- StreamManager streamManager,
|
|
|
- ObjectProvider<MediaGatewayProvider> providers,
|
|
|
- ObjectProvider<MediaGateway> fixedGateway,
|
|
|
- MediaChannelService channelService) {
|
|
|
+ private final ReactiveRedisConnectionFactory connectionFactory;
|
|
|
+
|
|
|
+ private SsrcPool ssrcPool;
|
|
|
+
|
|
|
+ public MediaGatewayService(
|
|
|
+ EventBus eventBus,
|
|
|
+ StreamManager streamManager,
|
|
|
+ ObjectProvider<MediaGatewayProvider> providers,
|
|
|
+ ObjectProvider<MediaGateway> fixedGateway,
|
|
|
+ MediaChannelService channelService,
|
|
|
+ ReactiveRedisConnectionFactory connectionFactory) {
|
|
|
this.eventBus = eventBus;
|
|
|
this.streamManager = streamManager;
|
|
|
this.channelService = channelService;
|
|
|
+ this.connectionFactory = connectionFactory;
|
|
|
for (MediaGatewayProvider provider : providers) {
|
|
|
gatewayProviders.put(provider.getId(), provider);
|
|
|
}
|
|
@@ -68,6 +79,21 @@ public class MediaGatewayService extends GenericReactiveCrudService<MediaGateway
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @PostConstruct
|
|
|
+ public void initSsrcPool() {
|
|
|
+ // fixme
|
|
|
+ this.getGatewayByServerId("gb28181_MediaServer")
|
|
|
+ .flatMap(
|
|
|
+ config -> {
|
|
|
+ SipProperties sipProperties =
|
|
|
+ FastBeanCopier.copy(config.getConfiguration(), new SipProperties());
|
|
|
+ this.ssrcPool =
|
|
|
+ new RedisSsrcPool(connectionFactory, sipProperties.getSipId().substring(3, 8));
|
|
|
+ return Mono.empty();
|
|
|
+ })
|
|
|
+ .subscribe();
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public Mono<SaveResult> save(Publisher<MediaGatewayEntity> entityPublisher) {
|
|
|
return Flux.from(entityPublisher)
|
|
@@ -172,15 +198,18 @@ public class MediaGatewayService extends GenericReactiveCrudService<MediaGateway
|
|
|
return Mono.justOrEmpty(gateways.get(id));
|
|
|
}
|
|
|
|
|
|
- //监听来自其他集群的视频流关闭事件
|
|
|
- @Subscribe(topics = "/media/*/*/*/closed", features = Subscription.Feature.broker)
|
|
|
- public Mono<Void> closeStream(DeviceStreamInfo stream) {
|
|
|
- return this
|
|
|
- .getGateway(stream.getGatewayId())
|
|
|
- .flatMap(gateway -> gateway
|
|
|
- .closeStream(stream)
|
|
|
- .then()
|
|
|
-// .flatMap(success -> streamManager.removeStream(stream.getDeviceId(), stream.getStreamId()))
|
|
|
+ public Mono<MediaGatewayEntity> getGatewayByServerId(String serverId) {
|
|
|
+ return createQuery().where(MediaGatewayEntity::getMediaServerId, serverId).fetchOne(); // 返回单个结果
|
|
|
+ }
|
|
|
+
|
|
|
+ // 监听来自其他集群的视频流关闭事件
|
|
|
+ @Subscribe(topics = "/media/*/*/*/closed", features = Subscription.Feature.broker)
|
|
|
+ public Mono<Void> closeStream(DeviceStreamInfo stream) {
|
|
|
+ return this.getGateway(stream.getGatewayId())
|
|
|
+ .flatMap(
|
|
|
+ gateway -> gateway.closeStream(stream).then()
|
|
|
+ // .flatMap(success -> streamManager.removeStream(stream.getDeviceId(),
|
|
|
+ // stream.getStreamId()))
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -223,16 +252,36 @@ public class MediaGatewayService extends GenericReactiveCrudService<MediaGateway
|
|
|
@Override
|
|
|
public void run(String... args) {
|
|
|
|
|
|
- if (autoCloseNoWatching) {
|
|
|
- intervalJob = Flux
|
|
|
- .interval(Duration.ofMinutes(1))
|
|
|
- .flatMap(ignore -> streamManager
|
|
|
- //只定时删除直播,回放
|
|
|
- .removeNoWatchingStream(null, Duration.ofMinutes(5), StreamInfo.TYPE_LIVE, StreamInfo.TYPE_PLAYBACK)
|
|
|
- .onErrorResume(err -> Mono.empty())
|
|
|
- .then())
|
|
|
- .subscribe();
|
|
|
- }
|
|
|
+ if (autoCloseNoWatching) {
|
|
|
+ intervalJob =
|
|
|
+ Flux.interval(Duration.ofMinutes(1))
|
|
|
+ .flatMap(
|
|
|
+ ignore ->
|
|
|
+ streamManager
|
|
|
+ // 只定时删除直播,回放
|
|
|
+ .removeNoWatchingStream(
|
|
|
+ null,
|
|
|
+ Duration.ofMinutes(5),
|
|
|
+ StreamInfo.TYPE_LIVE,
|
|
|
+ StreamInfo.TYPE_PLAYBACK)
|
|
|
+ .flatMap(
|
|
|
+ ssrc -> {
|
|
|
+ if (ssrc == null || ssrc.isEmpty()) {
|
|
|
+ return Mono.empty();
|
|
|
+ }
|
|
|
+
|
|
|
+ return ssrcPool
|
|
|
+ .release(ssrc)
|
|
|
+ .onErrorResume(
|
|
|
+ err -> {
|
|
|
+ log.error("Error releasing ssrc: " + ssrc, err);
|
|
|
+ return Mono.empty();
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .onErrorResume(err -> Mono.empty())
|
|
|
+ .then())
|
|
|
+ .subscribe();
|
|
|
+ }
|
|
|
|
|
|
createQuery()
|
|
|
.where(MediaGatewayEntity::getStatus, GatewayStatus.enabled)
|