[+] 房间穿肩
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package com.acgist.taoyao.signal.client;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClient;
|
||||
import com.acgist.taoyao.signal.media.MediaClient;
|
||||
|
||||
/**
|
||||
* 终端会话
|
||||
@@ -34,14 +34,6 @@ public interface Client extends AutoCloseable {
|
||||
*/
|
||||
void push(Message message);
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
*
|
||||
* @param sn 终端标识
|
||||
* @param message 消息
|
||||
*/
|
||||
void push(String sn, Message message);
|
||||
|
||||
/**
|
||||
* @param timeout 超时时间
|
||||
*
|
||||
@@ -67,13 +59,13 @@ public interface Client extends AutoCloseable {
|
||||
boolean authorized();
|
||||
|
||||
/**
|
||||
* @return Mediasoup终端
|
||||
* @return 媒体服务终端
|
||||
*/
|
||||
MediasoupClient mediasoupClient();
|
||||
MediaClient mediaClient();
|
||||
|
||||
/**
|
||||
* @param mediasoupClient Mediasoup终端
|
||||
* @param mediaClient 媒体服务终端
|
||||
*/
|
||||
void mediasoupClient(MediasoupClient mediasoupClient);
|
||||
void mediaClient(MediaClient mediaClient);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.acgist.taoyao.signal.client;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Header;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClient;
|
||||
import com.acgist.taoyao.signal.media.MediaClient;
|
||||
|
||||
/**
|
||||
* 会话适配器
|
||||
@@ -38,7 +36,7 @@ public abstract class ClientAdapter<T extends AutoCloseable> implements Client {
|
||||
/**
|
||||
* 媒体服务终端
|
||||
*/
|
||||
protected MediasoupClient mediasoupClient;
|
||||
protected MediaClient mediaClient;
|
||||
|
||||
protected ClientAdapter(T instance) {
|
||||
this.time = System.currentTimeMillis();
|
||||
@@ -62,15 +60,6 @@ public abstract class ClientAdapter<T extends AutoCloseable> implements Client {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(String sn, Message message) {
|
||||
final Header header = message.getHeader();
|
||||
if(header != null) {
|
||||
header.setSn(sn);
|
||||
}
|
||||
this.push(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean timeout(long timeout) {
|
||||
return System.currentTimeMillis() - this.time > timeout;
|
||||
@@ -93,14 +82,14 @@ public abstract class ClientAdapter<T extends AutoCloseable> implements Client {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediasoupClient mediasoupClient() {
|
||||
return this.mediasoupClient;
|
||||
public MediaClient mediaClient() {
|
||||
return this.mediaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mediasoupClient(MediasoupClient mediasoupClient) {
|
||||
this.mediasoupClient = mediasoupClient;
|
||||
this.status.setMediasoup(mediasoupClient.name());
|
||||
public void mediaClient(MediaClient mediaClient) {
|
||||
this.mediaClient = mediaClient;
|
||||
this.status.setMediaName(mediaClient.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.acgist.taoyao.signal.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -54,8 +54,20 @@ public class ClientManager {
|
||||
*/
|
||||
public void unicast(String to, Message message) {
|
||||
this.clients().stream()
|
||||
.filter(v -> StringUtils.equals(to, v.sn()))
|
||||
.forEach(v -> v.push(v.sn(), message));
|
||||
.filter(v -> Objects.equals(to, v.sn()))
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单播消息
|
||||
*
|
||||
* @param to 接收终端
|
||||
* @param message 消息
|
||||
*/
|
||||
public void unicast(Client to, Message message) {
|
||||
this.clients().stream()
|
||||
.filter(v -> v.instance() == to)
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +76,7 @@ public class ClientManager {
|
||||
* @param message 消息
|
||||
*/
|
||||
public void broadcast(Message message) {
|
||||
this.clients().forEach(v -> v.push(v.sn(), message));
|
||||
this.clients().forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,8 +87,20 @@ public class ClientManager {
|
||||
*/
|
||||
public void broadcast(String from, Message message) {
|
||||
this.clients().stream()
|
||||
.filter(v -> !StringUtils.equals(from, v.sn()))
|
||||
.forEach(v -> v.push(v.sn(), message));
|
||||
.filter(v -> !Objects.equals(from, v.sn()))
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播消息
|
||||
*
|
||||
* @param from 发送终端
|
||||
* @param message 消息
|
||||
*/
|
||||
public void broadcast(Client from, Message message) {
|
||||
this.clients().stream()
|
||||
.filter(v -> v.instance() != from)
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +110,7 @@ public class ClientManager {
|
||||
*/
|
||||
public Client client(String sn) {
|
||||
return this.clients().stream()
|
||||
.filter(v -> StringUtils.equals(sn, v.sn()))
|
||||
.filter(v -> Objects.equals(sn, v.sn()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
@@ -102,16 +126,6 @@ public class ClientManager {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sn 终端标识
|
||||
*
|
||||
* @return 终端状态
|
||||
*/
|
||||
public ClientStatus status(String sn) {
|
||||
final Client client = this.client(sn);
|
||||
return client == null ? null : client.status();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有终端会话
|
||||
@@ -121,6 +135,16 @@ public class ClientManager {
|
||||
.filter(Client::authorized)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sn 终端标识
|
||||
*
|
||||
* @return 终端状态
|
||||
*/
|
||||
public ClientStatus status(String sn) {
|
||||
final Client client = this.client(sn);
|
||||
return client == null ? null : client.status();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有终端状态
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ClientStatus {
|
||||
* 媒体服务名称
|
||||
*/
|
||||
@Schema(title = "媒体服务名称", description = "媒体服务名称")
|
||||
private String mediasoup;
|
||||
private String mediaName;
|
||||
/**
|
||||
* 最后心跳时间
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
import com.acgist.taoyao.signal.client.websocket.WebSocketSignal;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClientManager;
|
||||
import com.acgist.taoyao.signal.media.MediaClientManager;
|
||||
import com.acgist.taoyao.signal.protocol.media.MediaRebootProtocol;
|
||||
import com.acgist.taoyao.signal.protocol.media.MediaShutdownProtocol;
|
||||
import com.acgist.taoyao.signal.protocol.platform.PlatformRebootProtocol;
|
||||
@@ -31,7 +31,7 @@ import com.acgist.taoyao.signal.service.impl.SecurityServiceImpl;
|
||||
public class SignalAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private MediasoupClientManager mediasoupClientManager;
|
||||
private MediaClientManager mediaClientManager;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@@ -52,11 +52,11 @@ public class SignalAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandLineRunner mediasoupCommandLineRunner() {
|
||||
public CommandLineRunner mediaCommandLineRunner() {
|
||||
return new CommandLineRunner() {
|
||||
@Override
|
||||
public void run(String ... args) throws Exception {
|
||||
SignalAutoConfiguration.this.mediasoupClientManager.init();
|
||||
SignalAutoConfiguration.this.mediaClientManager.init();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,9 +8,13 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.ClientManager;
|
||||
import com.acgist.taoyao.signal.client.ClientStatus;
|
||||
import com.acgist.taoyao.signal.protocol.client.ClientRebootProtocol;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
@@ -30,12 +34,14 @@ public class ClientController {
|
||||
|
||||
@Operation(summary = "终端列表", description = "终端列表")
|
||||
@GetMapping("/list")
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
|
||||
public Message list() {
|
||||
return Message.success(this.clientManager.status());
|
||||
}
|
||||
|
||||
@Operation(summary = "终端状态", description = "终端状态")
|
||||
@GetMapping("/status/{sn}")
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
|
||||
public Message status(@PathVariable String sn) {
|
||||
return Message.success(this.clientManager.status(sn));
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.ClientStatus;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
import com.acgist.taoyao.signal.room.RoomManager;
|
||||
import com.acgist.taoyao.signal.room.RoomStatus;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
@@ -33,19 +35,21 @@ public class RoomController {
|
||||
|
||||
@Operation(summary = "房间列表", description = "房间列表")
|
||||
@GetMapping("/list")
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = Room.class)))
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class)))
|
||||
public Message list() {
|
||||
return Message.success(this.roomManager.status());
|
||||
}
|
||||
|
||||
@Operation(summary = "房间状态", description = "房间状态")
|
||||
@GetMapping("/status/{id}")
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class)))
|
||||
public Message status(@PathVariable Long id) {
|
||||
return Message.success(this.roomManager.status(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "房间终端列表", description = "房间终端列表")
|
||||
@GetMapping("/list/client/{id}")
|
||||
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
|
||||
public Message listClient(@PathVariable Long id) {
|
||||
final Room room = this.roomManager.room(id);
|
||||
return Message.success(room == null ? List.of() : room.clientStatus());
|
||||
|
||||
@@ -47,10 +47,10 @@ public class RoomCreateEvent extends ApplicationEventAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Constant#MEDIASOUP}
|
||||
* @return {@link Constant#MEDIA_NAME}
|
||||
*/
|
||||
public String getMediasoup() {
|
||||
return this.get(Constant.MEDIASOUP);
|
||||
public String getMediaName() {
|
||||
return this.get(Constant.MEDIA_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.springframework.context.ApplicationListener;
|
||||
|
||||
import com.acgist.taoyao.signal.client.ClientManager;
|
||||
import com.acgist.taoyao.signal.event.ApplicationEventAdapter;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClientManager;
|
||||
import com.acgist.taoyao.signal.media.MediaClientManager;
|
||||
import com.acgist.taoyao.signal.room.RoomManager;
|
||||
|
||||
/**
|
||||
@@ -25,6 +25,6 @@ public abstract class ApplicationListenerAdapter<E extends ApplicationEventAdapt
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
@Autowired
|
||||
protected MediasoupClientManager mediasoupClientManager;
|
||||
protected MediaClientManager mediaClientManager;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.acgist.taoyao.signal.listener.room;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.EventListener;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.model.MessageCodeException;
|
||||
import com.acgist.taoyao.signal.event.room.RoomCreateEvent;
|
||||
import com.acgist.taoyao.signal.listener.ApplicationListenerAdapter;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
@@ -18,18 +19,20 @@ public class RoomCreateListener extends ApplicationListenerAdapter<RoomCreateEve
|
||||
public void onApplicationEvent(RoomCreateEvent event) {
|
||||
final Long id = event.getId();
|
||||
if(id != null && this.roomManager.room(id) != null) {
|
||||
// 房间已经存在
|
||||
return;
|
||||
throw MessageCodeException.of("房间已经存在");
|
||||
}
|
||||
// 广播消息
|
||||
final Message message = event.getMessage();
|
||||
// 创建房间
|
||||
final Room room = this.roomManager.create(
|
||||
event.getSn(),
|
||||
event.getName(),
|
||||
event.getPassword(),
|
||||
event.getMediasoup()
|
||||
event.getMediaName(),
|
||||
message.cloneWidthoutBody()
|
||||
);
|
||||
// 进入房间
|
||||
room.enter(event.getClient());
|
||||
final Message message = event.getMessage();
|
||||
message.setBody(room.getStatus());
|
||||
this.clientManager.broadcast(message);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.acgist.taoyao.boot.model.MessageCodeException;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.event.room.RoomEnterEvent;
|
||||
import com.acgist.taoyao.signal.listener.ApplicationListenerAdapter;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClient;
|
||||
import com.acgist.taoyao.signal.media.MediaClient;
|
||||
import com.acgist.taoyao.signal.protocol.Constant;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
|
||||
@@ -35,12 +35,12 @@ public class RoomEnterListener extends ApplicationListenerAdapter<RoomEnterEvent
|
||||
throw MessageCodeException.of(MessageCode.CODE_3401, "密码错误");
|
||||
}
|
||||
final Client client = event.getClient();
|
||||
final MediasoupClient mediasoupClient = room.getMediasoupClient();
|
||||
if(client.mediasoupClient() == null) {
|
||||
client.mediasoupClient(mediasoupClient);
|
||||
} else if(client.mediasoupClient() == mediasoupClient) {
|
||||
final MediaClient mediaClient = room.getMediaClient();
|
||||
if(client.mediaClient() == null) {
|
||||
client.mediaClient(mediaClient);
|
||||
} else if(client.mediaClient() == mediaClient) {
|
||||
} else {
|
||||
throw MessageCodeException.of("不在相同媒体服务:" + mediasoupClient.name());
|
||||
throw MessageCodeException.of("不在相同媒体服务:" + mediaClient.name());
|
||||
}
|
||||
// 进入房间
|
||||
room.enter(client);
|
||||
@@ -50,8 +50,7 @@ public class RoomEnterListener extends ApplicationListenerAdapter<RoomEnterEvent
|
||||
Constant.ID, room.getId(),
|
||||
Constant.SN, sn
|
||||
));
|
||||
room.broadcast(client, message);
|
||||
// TODO:推送流媒体列表
|
||||
room.broadcast(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
package com.acgist.taoyao.signal.media;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
@@ -30,7 +30,8 @@ import com.acgist.taoyao.boot.annotation.Client;
|
||||
import com.acgist.taoyao.boot.model.Header;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.model.MessageCode;
|
||||
import com.acgist.taoyao.boot.property.MediasoupProperties;
|
||||
import com.acgist.taoyao.boot.model.MessageCodeException;
|
||||
import com.acgist.taoyao.boot.property.MediaServerProperties;
|
||||
import com.acgist.taoyao.boot.property.TaoyaoProperties;
|
||||
import com.acgist.taoyao.boot.utils.JSONUtils;
|
||||
import com.acgist.taoyao.signal.protocol.Protocol;
|
||||
@@ -49,7 +50,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
@Client
|
||||
public class MediasoupClient {
|
||||
public class MediaClient {
|
||||
|
||||
@Autowired
|
||||
private TaskScheduler taskScheduler;
|
||||
@@ -77,7 +78,7 @@ public class MediasoupClient {
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
private MediasoupProperties mediasoupProperties;
|
||||
private MediaServerProperties mediaServerProperties;
|
||||
/**
|
||||
* 同步消息
|
||||
*/
|
||||
@@ -86,11 +87,11 @@ public class MediasoupClient {
|
||||
/**
|
||||
* 加载终端
|
||||
*
|
||||
* @param mediasoupProperties 媒体终端配置
|
||||
* @param mediaServerProperties 媒体服务配置
|
||||
*/
|
||||
public void init(MediasoupProperties mediasoupProperties) {
|
||||
this.mediasoupProperties = mediasoupProperties;
|
||||
this.name = mediasoupProperties.getName();
|
||||
public void init(MediaServerProperties mediaServerProperties) {
|
||||
this.mediaServerProperties = mediaServerProperties;
|
||||
this.name = mediaServerProperties.getName();
|
||||
this.duration = this.taoyaoProperties.getTimeout();
|
||||
this.buildClient();
|
||||
}
|
||||
@@ -106,7 +107,7 @@ public class MediasoupClient {
|
||||
* 连接WebSocket通道
|
||||
*/
|
||||
public void buildClient() {
|
||||
final URI uri = URI.create(this.mediasoupProperties.getAddress());
|
||||
final URI uri = URI.create(this.mediaServerProperties.getAddress());
|
||||
log.info("连接媒体服务:{}", uri);
|
||||
try {
|
||||
HttpClient
|
||||
@@ -159,7 +160,7 @@ public class MediasoupClient {
|
||||
final Message response = this.syncMessage.remove(id);
|
||||
if(response == null || message.equals(response)) {
|
||||
log.warn("媒体服务没有响应:{}", message);
|
||||
return this.platformErrorProtocol.build(id, MessageCode.CODE_2001, "媒体服务没有响应", response);
|
||||
throw MessageCodeException.of(MessageCode.CODE_2001, "媒体服务没有响应");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -179,7 +180,7 @@ public class MediasoupClient {
|
||||
// 设置新的通道
|
||||
this.webSocket = webSocket;
|
||||
// 发送授权消息
|
||||
this.send(this.mediaRegisterProtocol.build(this.mediasoupProperties));
|
||||
this.send(this.mediaRegisterProtocol.build(this.mediaServerProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,25 +205,25 @@ public class MediasoupClient {
|
||||
}
|
||||
final String v = header.getV();
|
||||
final String id = header.getId();
|
||||
final String sn = header.getSn();
|
||||
final String signal = header.getSignal();
|
||||
if(v == null || id == null || sn == null || signal == null) {
|
||||
if(v == null || id == null || signal == null) {
|
||||
log.warn("消息格式错误(缺失头部关键参数):{}", message);
|
||||
return;
|
||||
}
|
||||
final Message request = this.syncMessage.get(id);
|
||||
// 存在同步响应
|
||||
if(request != null) {
|
||||
// 同步处理
|
||||
// 重新设置消息
|
||||
this.syncMessage.put(id, message);
|
||||
// 唤醒等待现场
|
||||
synchronized (request) {
|
||||
request.notifyAll();
|
||||
}
|
||||
// 同步处理不要执行回调
|
||||
} else {
|
||||
final Protocol protocol = this.protocolManager.protocol(signal);
|
||||
if(protocol instanceof ProtocolMediaAdapter mediasoupProtocol) {
|
||||
mediasoupProtocol.execute(message, this.webSocket);
|
||||
if(protocol instanceof ProtocolMediaAdapter protocolMediaAdapter) {
|
||||
protocolMediaAdapter.execute(message, this.webSocket);
|
||||
} else {
|
||||
log.warn("未知媒体服务信令:{}", data);
|
||||
}
|
||||
@@ -241,7 +242,7 @@ public class MediasoupClient {
|
||||
public void onOpen(WebSocket webSocket) {
|
||||
log.info("媒体服务通道打开:{}", webSocket);
|
||||
Listener.super.onOpen(webSocket);
|
||||
MediasoupClient.this.open(webSocket);
|
||||
MediaClient.this.open(webSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,7 +255,7 @@ public class MediasoupClient {
|
||||
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
|
||||
log.debug("媒体服务收到消息(text):{}-{}", webSocket, data);
|
||||
try {
|
||||
MediasoupClient.this.execute(data.toString());
|
||||
MediaClient.this.execute(data.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("媒体服务处理异常:{}", data, e);
|
||||
}
|
||||
@@ -267,9 +268,9 @@ public class MediasoupClient {
|
||||
try {
|
||||
return Listener.super.onClose(webSocket, statusCode, reason);
|
||||
} finally {
|
||||
MediasoupClient.this.taskScheduler.schedule(
|
||||
MediasoupClient.this::buildClient,
|
||||
Instant.now().plusMillis(MediasoupClient.this.retryDuration())
|
||||
MediaClient.this.taskScheduler.schedule(
|
||||
MediaClient.this::buildClient,
|
||||
Instant.now().plusMillis(MediaClient.this.retryDuration())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -280,9 +281,9 @@ public class MediasoupClient {
|
||||
try {
|
||||
Listener.super.onError(webSocket, error);
|
||||
} finally {
|
||||
MediasoupClient.this.taskScheduler.schedule(
|
||||
MediasoupClient.this::buildClient,
|
||||
Instant.now().plusMillis(MediasoupClient.this.retryDuration())
|
||||
MediaClient.this.taskScheduler.schedule(
|
||||
MediaClient.this::buildClient,
|
||||
Instant.now().plusMillis(MediaClient.this.retryDuration())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
package com.acgist.taoyao.signal.media;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -7,7 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Manager;
|
||||
import com.acgist.taoyao.boot.property.WebrtcProperties;
|
||||
import com.acgist.taoyao.boot.property.MediaProperties;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -18,26 +18,26 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*/
|
||||
@Slf4j
|
||||
@Manager
|
||||
public class MediasoupClientManager {
|
||||
public class MediaClientManager {
|
||||
|
||||
@Autowired
|
||||
private WebrtcProperties webrtcProperties;
|
||||
private MediaProperties mediaProperties;
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 媒体服务终端列表
|
||||
*/
|
||||
private Map<String, MediasoupClient> clientMap = new ConcurrentHashMap<>();
|
||||
private Map<String, MediaClient> clientMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 加载媒体服务终端
|
||||
*/
|
||||
public void init() {
|
||||
this.webrtcProperties.getMediasoupList().stream()
|
||||
this.mediaProperties.getMediaServerList().stream()
|
||||
.filter(v -> Boolean.TRUE.equals(v.getEnabled()))
|
||||
.forEach(v -> {
|
||||
final MediasoupClient client = this.applicationContext.getBean(MediasoupClient.class);
|
||||
final MediaClient client = this.applicationContext.getBean(MediaClient.class);
|
||||
client.init(v);
|
||||
this.clientMap.put(client.name(), client);
|
||||
log.info("注册媒体服务终端:{}-{}", v.getAddress(), client);
|
||||
@@ -49,7 +49,7 @@ public class MediasoupClientManager {
|
||||
*
|
||||
* @return 媒体服务终端
|
||||
*/
|
||||
public MediasoupClient mediasoupClient(String name) {
|
||||
public MediaClient mediaClient(String name) {
|
||||
return this.clientMap.get(name);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
package com.acgist.taoyao.signal.media;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
package com.acgist.taoyao.signal.media;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
@@ -60,8 +60,8 @@ public class Stream implements Closeable {
|
||||
* 媒体流ID
|
||||
*
|
||||
* 媒体类型.发送终端标识.发送.房间ID:
|
||||
* 音频:audio.sn.sn.1000
|
||||
* 视频:video.sn.sn.1000
|
||||
* 音频:audio.sn.send.1000
|
||||
* 视频:video.sn.send.1000
|
||||
*
|
||||
* 媒体类型.接收终端标识.接收.发送终端标识.房间ID:
|
||||
* 音频:audio.sn.recv.sn.1000
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
package com.acgist.taoyao.signal.media;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.acgist.taoyao.signal.mediasoup;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 路由
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Slf4j
|
||||
public class Router implements Closeable {
|
||||
|
||||
/**
|
||||
* 房间
|
||||
*/
|
||||
private Room room;
|
||||
/**
|
||||
* 传输通道列表
|
||||
*/
|
||||
private List<Transport> transports;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
log.info("关闭路由:{}", this.room.getId());
|
||||
this.transports.forEach(Transport::close);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public interface Constant {
|
||||
/**
|
||||
* 媒体服务名称
|
||||
*/
|
||||
String MEDIASOUP = "mediasoup";
|
||||
String MEDIA_NAME = "mediaName";
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
@@ -75,5 +75,21 @@ public interface Constant {
|
||||
* WebRTC
|
||||
*/
|
||||
String WEBRTC = "webrtc";
|
||||
/**
|
||||
* 房间ID
|
||||
*/
|
||||
String ROOM_ID = "roomId";
|
||||
/**
|
||||
* 终端ID
|
||||
*/
|
||||
String CLIENT_ID = "clientId";
|
||||
/**
|
||||
* 路由ID
|
||||
*/
|
||||
String ROUTER_ID = "routerId";
|
||||
/**
|
||||
* 终端ID
|
||||
*/
|
||||
String STREAM_ID = "streamId";
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.acgist.taoyao.boot.property.TaoyaoProperties;
|
||||
import com.acgist.taoyao.boot.service.IdService;
|
||||
import com.acgist.taoyao.signal.client.ClientManager;
|
||||
import com.acgist.taoyao.signal.event.ApplicationEventAdapter;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClientManager;
|
||||
import com.acgist.taoyao.signal.media.MediaClientManager;
|
||||
import com.acgist.taoyao.signal.room.RoomManager;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ public abstract class ProtocolAdapter implements Protocol {
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
@Autowired
|
||||
protected MediasoupClientManager mediasoupClientManager;
|
||||
protected MediaClientManager mediaClientManager;
|
||||
|
||||
/**
|
||||
* 信令名称
|
||||
|
||||
@@ -95,11 +95,10 @@ public class ProtocolManager {
|
||||
}
|
||||
final String v = header.getV();
|
||||
final String id = header.getId();
|
||||
final String sn = header.getSn();
|
||||
final String signal = header.getSignal();
|
||||
// 设置缓存ID
|
||||
this.platformErrorProtocol.set(id);
|
||||
if(v == null || id == null || sn == null || signal == null) {
|
||||
if(v == null || id == null || signal == null) {
|
||||
log.warn("消息格式错误(缺失头部关键参数):{}", content);
|
||||
client.push(this.platformErrorProtocol.build("消息格式错误(缺失头部关键参数)"));
|
||||
return;
|
||||
@@ -112,9 +111,9 @@ public class ProtocolManager {
|
||||
return;
|
||||
}
|
||||
if(protocol instanceof ClientRegisterProtocol) {
|
||||
protocol.execute(sn, client, message);
|
||||
protocol.execute(null, client, message);
|
||||
} else if(this.securityService.authenticate(message, client, protocol)) {
|
||||
protocol.execute(sn, client, message);
|
||||
protocol.execute(client.sn(), client, message);
|
||||
} else {
|
||||
log.warn("终端会话没有授权:{}", content);
|
||||
client.push(this.platformErrorProtocol.build(MessageCode.CODE_3401, "终端会话没有授权"));
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.acgist.taoyao.signal.protocol;
|
||||
|
||||
import java.net.http.WebSocket;
|
||||
import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.model.MessageCodeException;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
|
||||
/**
|
||||
* 房间媒体服务信令适配器
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
public abstract class ProtocolMediaRoomAdapter extends ProtocolMediaAdapter {
|
||||
|
||||
protected ProtocolMediaRoomAdapter(String name, String signal) {
|
||||
super(name, signal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Message message, WebSocket webSocket) {
|
||||
final Object body = message.getBody();
|
||||
if(body instanceof Map<?, ?> map) {
|
||||
this.execute(this.room(map), map, message, webSocket);
|
||||
} else {
|
||||
throw MessageCodeException.of("信令主体类型错误:" + message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Client client, Message message) {
|
||||
final Object body = message.getBody();
|
||||
if(body instanceof Map<?, ?> map) {
|
||||
this.execute(sn, this.room(map), map, client, message);
|
||||
} else {
|
||||
throw MessageCodeException.of("信令主体类型错误:" + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param map 参数
|
||||
*
|
||||
* @return 房间
|
||||
*/
|
||||
protected Room room(Map<?, ?> map) {
|
||||
final Long roomId = this.roomId(map);
|
||||
final Room room = this.roomManager.room(roomId);
|
||||
if(room == null) {
|
||||
throw MessageCodeException.of("房间无效:" + roomId);
|
||||
}
|
||||
return room;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param map 参数
|
||||
*
|
||||
* @return 房间ID
|
||||
*/
|
||||
protected Long roomId(Map<?, ?> map) {
|
||||
final Object object = map.get(Constant.ROOM_ID);
|
||||
if(object == null) {
|
||||
return null;
|
||||
} else if(object instanceof Long value) {
|
||||
return value;
|
||||
}
|
||||
return Long.valueOf(object.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理房间信令
|
||||
*
|
||||
* @param room 房间
|
||||
* @param body 消息
|
||||
* @param message 信令消息
|
||||
* @param webSocket WebSocket
|
||||
*/
|
||||
public abstract void execute(Room room, Map<?, ?> body, Message message, WebSocket webSocket);
|
||||
|
||||
/**
|
||||
* 处理终端信令
|
||||
*
|
||||
* @param sn 终端标识
|
||||
* @param room 房间
|
||||
* @param body 消息
|
||||
* @param client 终端
|
||||
* @param message 信令消息
|
||||
*/
|
||||
public abstract void execute(String sn, Room room, Map<?, ?> body, Client client, Message message);
|
||||
|
||||
}
|
||||
@@ -16,12 +16,12 @@ public class ClientBroadcastProtocol extends ProtocolAdapter {
|
||||
public static final String SIGNAL = "client::broadcast";
|
||||
|
||||
public ClientBroadcastProtocol() {
|
||||
super("广播信令", SIGNAL);
|
||||
super("终端广播信令", SIGNAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Client client, Message message) {
|
||||
this.clientManager.broadcast(sn, message);
|
||||
this.clientManager.broadcast(client, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,12 +35,13 @@ public class ClientRegisterProtocol extends ProtocolMapAdapter {
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Map<?, ?> body, Client client, Message message) {
|
||||
final String clientSn = (String) body.get(Constant.SN);
|
||||
final String username = (String) body.get(Constant.USERNAME);
|
||||
final String password = (String) body.get(Constant.PASSWORD);
|
||||
// 如果需要终端鉴权在此实现
|
||||
if(this.securityService.authenticate(username, password)) {
|
||||
log.info("终端注册:{}", sn);
|
||||
client.authorize(sn);
|
||||
log.info("终端注册:{}", clientSn);
|
||||
client.authorize(clientSn);
|
||||
message.setCode(MessageCode.CODE_0000);
|
||||
} else {
|
||||
message.setCode(MessageCode.CODE_3401);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.acgist.taoyao.signal.protocol.client;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.acgist.taoyao.signal.protocol.media;
|
||||
|
||||
import java.net.http.WebSocket;
|
||||
import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolMediaRoomAdapter;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
|
||||
/**
|
||||
* 当前讲话终端信令
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Protocol
|
||||
public class AudioActiveSpeakerProtocol extends ProtocolMediaRoomAdapter {
|
||||
|
||||
public static final String SIGNAL = "audio::active::speaker";
|
||||
|
||||
public AudioActiveSpeakerProtocol() {
|
||||
super("当前讲话终端信令", SIGNAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Room room, Map<?, ?> body, Message message, WebSocket webSocket) {
|
||||
room.broadcast(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Room room, Map<?, ?> body, Client client, Message message) {
|
||||
// 忽略
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.acgist.taoyao.signal.protocol.media;
|
||||
|
||||
public class DisplayNameChangeProtocol {
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.property.WebrtcProperties;
|
||||
import com.acgist.taoyao.boot.property.MediaProperties;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter;
|
||||
|
||||
@@ -21,7 +21,7 @@ public class MediaListProtocol extends ProtocolMapAdapter {
|
||||
public static final String SIGNAL = "media::list";
|
||||
|
||||
@Autowired
|
||||
private WebrtcProperties webrtcProperties;
|
||||
private MediaProperties mediaProperties;
|
||||
|
||||
public MediaListProtocol() {
|
||||
super("媒体服务列表信令", SIGNAL);
|
||||
@@ -29,7 +29,7 @@ public class MediaListProtocol extends ProtocolMapAdapter {
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Map<?, ?> body, Client client, Message message) {
|
||||
message.setBody(this.webrtcProperties.getMediasoupList());
|
||||
message.setBody(this.mediaProperties.getMediaServerList());
|
||||
client.push(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.acgist.taoyao.signal.protocol.ProtocolAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 重启媒体服务信令
|
||||
* 媒体服务重启信令
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.property.MediasoupProperties;
|
||||
import com.acgist.taoyao.boot.property.MediaServerProperties;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.protocol.Constant;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolMediaAdapter;
|
||||
@@ -30,14 +30,14 @@ public class MediaRegisterProtocol extends ProtocolMediaAdapter {
|
||||
/**
|
||||
* 创建信令消息
|
||||
*
|
||||
* @param mediasoup 媒体配置
|
||||
* @param mediaServerProperties 媒体服务配置
|
||||
*
|
||||
* @return 信令消息
|
||||
*/
|
||||
public Message build(MediasoupProperties mediasoup) {
|
||||
public Message build(MediaServerProperties mediaServerProperties) {
|
||||
return super.build(Map.of(
|
||||
Constant.USERNAME, mediasoup.getUsername(),
|
||||
Constant.PASSWORD, mediasoup.getPassword()
|
||||
Constant.USERNAME, mediaServerProperties.getUsername(),
|
||||
Constant.PASSWORD, mediaServerProperties.getPassword()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.acgist.taoyao.signal.protocol.media;
|
||||
|
||||
import java.net.http.WebSocket;
|
||||
import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolMediaRoomAdapter;
|
||||
import com.acgist.taoyao.signal.room.Room;
|
||||
|
||||
/**
|
||||
* 路由RTP能力信令
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Protocol
|
||||
public class RouterRtpCapabilitiesProtocol extends ProtocolMediaRoomAdapter {
|
||||
|
||||
public static final String SIGNAL = "router::rtp::capabilities";
|
||||
|
||||
public RouterRtpCapabilitiesProtocol() {
|
||||
super("路由RTP能力信令", SIGNAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Room room, Map<?, ?> body, Message message, WebSocket webSocket) {
|
||||
// 忽略
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String sn, Room room, Map<?, ?> body, Client client, Message message) {
|
||||
client.push(room.sendSync(message));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package com.acgist.taoyao.signal.protocol.media;
|
||||
|
||||
/**
|
||||
* // TODO:推送流媒体列表
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
public class WebRtcTransportConnectProtocol {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
package com.acgist.taoyao.signal.room;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.client.ClientStatus;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClient;
|
||||
import com.acgist.taoyao.signal.media.MediaClient;
|
||||
import com.acgist.taoyao.signal.media.Transport;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 房间
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema(title = "房间", description = "房间")
|
||||
public class Room {
|
||||
public class Room implements Closeable {
|
||||
|
||||
/**
|
||||
* ID
|
||||
@@ -36,11 +39,15 @@ public class Room {
|
||||
/**
|
||||
* 媒体服务
|
||||
*/
|
||||
private MediasoupClient mediasoupClient;
|
||||
private MediaClient mediaClient;
|
||||
/**
|
||||
* 终端列表
|
||||
*/
|
||||
private List<Client> clients;
|
||||
/**
|
||||
* 传输通道列表
|
||||
*/
|
||||
private List<Transport> transports;
|
||||
|
||||
/**
|
||||
* @return 终端状态列表
|
||||
@@ -70,7 +77,7 @@ public class Room {
|
||||
/**
|
||||
* 终端离开
|
||||
*
|
||||
* @param sn 终端
|
||||
* @param client 终端
|
||||
*/
|
||||
public void leave(Client client) {
|
||||
synchronized (this.clients) {
|
||||
@@ -86,7 +93,19 @@ public class Room {
|
||||
* @param message 消息
|
||||
*/
|
||||
public void broadcast(Message message) {
|
||||
this.clients.forEach(v -> v.push(v.sn(), message));
|
||||
this.clients.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播消息
|
||||
*
|
||||
* @param from 发送终端
|
||||
* @param message 消息
|
||||
*/
|
||||
public void broadcast(String from, Message message) {
|
||||
this.clients.stream()
|
||||
.filter(v -> !Objects.equals(from, v.sn()))
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +117,27 @@ public class Room {
|
||||
public void broadcast(Client from, Message message) {
|
||||
this.clients.stream()
|
||||
.filter(v -> v != from)
|
||||
.forEach(v -> v.push(v.sn(), message));
|
||||
.forEach(v -> v.push(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MediaClient#send(Message)
|
||||
*/
|
||||
public void send(Message message) {
|
||||
this.mediaClient.send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MediaClient#sendSync(Message)
|
||||
*/
|
||||
public Message sendSync(Message message) {
|
||||
return this.mediaClient.sendSync(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
log.info("关闭房间:{}", this.id);
|
||||
this.transports.forEach(Transport::close);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package com.acgist.taoyao.signal.room;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Manager;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.boot.model.MessageCodeException;
|
||||
import com.acgist.taoyao.boot.service.IdService;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClient;
|
||||
import com.acgist.taoyao.signal.mediasoup.MediasoupClientManager;
|
||||
import com.acgist.taoyao.signal.media.MediaClient;
|
||||
import com.acgist.taoyao.signal.media.MediaClientManager;
|
||||
import com.acgist.taoyao.signal.protocol.Constant;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -26,7 +30,7 @@ public class RoomManager {
|
||||
@Autowired
|
||||
private IdService idService;
|
||||
@Autowired
|
||||
private MediasoupClientManager mediasoupClientManager;
|
||||
private MediaClientManager mediaClientManager;
|
||||
|
||||
/**
|
||||
* 房间列表
|
||||
@@ -40,11 +44,18 @@ public class RoomManager {
|
||||
*/
|
||||
public Room room(Long id) {
|
||||
return this.rooms.stream()
|
||||
.filter(v -> v.getId().equals(id))
|
||||
.filter(v -> Objects.equals(id, v.getId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有房间列表
|
||||
*/
|
||||
public List<Room> rooms() {
|
||||
return this.rooms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id ID
|
||||
*
|
||||
@@ -55,13 +66,6 @@ public class RoomManager {
|
||||
return room == null ? null : room.getStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有房间列表
|
||||
*/
|
||||
public List<Room> rooms() {
|
||||
return this.rooms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 所有房间状态
|
||||
*/
|
||||
@@ -77,14 +81,15 @@ public class RoomManager {
|
||||
* @param sn 创建终端标识
|
||||
* @param name 名称
|
||||
* @param password 密码
|
||||
* @param mediasoup 媒体服务名称
|
||||
* @param mediaName 媒体服务名称
|
||||
* @param message 创建消息
|
||||
*
|
||||
* @return 房间信息
|
||||
*/
|
||||
public Room create(String sn, String name, String password, String mediasoup) {
|
||||
final MediasoupClient mediasoupClient = this.mediasoupClientManager.mediasoupClient(mediasoup);
|
||||
if(mediasoupClient == null) {
|
||||
throw MessageCodeException.of("无效媒体服务:" + mediasoup);
|
||||
public Room create(String sn, String name, String password, String mediaName, Message message) {
|
||||
final MediaClient mediaClient = this.mediaClientManager.mediaClient(mediaName);
|
||||
if(mediaClient == null) {
|
||||
throw MessageCodeException.of("无效媒体服务:" + mediaName);
|
||||
}
|
||||
final Long id = this.idService.buildId();
|
||||
// 状态
|
||||
@@ -92,18 +97,19 @@ public class RoomManager {
|
||||
roomStatus.setId(id);
|
||||
roomStatus.setName(name);
|
||||
roomStatus.setSnSize(0L);
|
||||
roomStatus.setMediasoup(mediasoup);
|
||||
roomStatus.setMediaName(mediaName);
|
||||
// 房间
|
||||
final Room room = new Room();
|
||||
room.setId(id);
|
||||
room.setPassword(password);
|
||||
room.setStatus(roomStatus);
|
||||
room.setMediasoupClient(mediasoupClient);
|
||||
room.setMediaClient(mediaClient);
|
||||
room.setClients(new CopyOnWriteArrayList<>());
|
||||
// 加入
|
||||
this.rooms.add(room);
|
||||
// TODO:媒体服务
|
||||
// 创建媒体服务房间
|
||||
message.setBody(Map.of(Constant.ROOM_ID, id));
|
||||
mediaClient.sendSync(message);
|
||||
log.info("创建房间:{}-{}", id, name);
|
||||
this.rooms.add(room);
|
||||
return room;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,6 @@ public class RoomStatus {
|
||||
* 媒体服务名称
|
||||
*/
|
||||
@Schema(title = "媒体服务名称", description = "媒体服务名称")
|
||||
private String mediasoup;
|
||||
private String mediaName;
|
||||
|
||||
}
|
||||
|
||||
@@ -31,10 +31,6 @@ public class SecurityServiceImpl implements SecurityService {
|
||||
if(!session.authorized()) {
|
||||
return false;
|
||||
}
|
||||
// 信令终端鉴定
|
||||
if(!session.sn().equals(message.getHeader().getSn())) {
|
||||
return false;
|
||||
}
|
||||
// 信令权限鉴定
|
||||
if(!protocol.authenticate(message)) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user