[+] 优化房间创建、关闭、广播、终端列表逻辑
现在已经能够拉出视频
This commit is contained in:
@@ -22,6 +22,8 @@ module.exports = {
|
||||
name: "桃夭媒体服务",
|
||||
// 地址
|
||||
host: "127.0.0.1",
|
||||
// host: "192.168.1.100",
|
||||
// host: "192.168.8.100",
|
||||
// 端口
|
||||
port: 8888,
|
||||
// 协议
|
||||
|
||||
@@ -18,7 +18,7 @@ const taoyao = new Taoyao(mediasoupWorkers);
|
||||
* 创建Mediasoup Worker列表
|
||||
*/
|
||||
async function buildMediasoupWorkers() {
|
||||
// 可配置的事件
|
||||
// 监听事件
|
||||
// mediasoup.observer.on("newworker", fn(worker));
|
||||
const { workerSize } = config.mediasoup;
|
||||
console.info("创建Mediasoup Worker数量:", workerSize);
|
||||
@@ -29,16 +29,6 @@ async function buildMediasoupWorkers() {
|
||||
rtcMinPort: Number(config.mediasoup.workerSettings.rtcMinPort),
|
||||
rtcMaxPort: Number(config.mediasoup.workerSettings.rtcMaxPort),
|
||||
});
|
||||
worker.on("died", (error) => {
|
||||
console.warn("Mediasoup Worker停止服务:", worker.pid, error);
|
||||
setTimeout(() => process.exit(1), 2000);
|
||||
});
|
||||
worker.observer.on("close", () => {
|
||||
console.warn("Mediasoup Worker关闭服务:", worker.pid);
|
||||
});
|
||||
// 可配置的事件
|
||||
// worker.observer.on("newrouter", fn(router));
|
||||
// worker.observer.on("newwebrtcserver", fn(router));
|
||||
// 配置WebRTC服务
|
||||
const webRtcServerOptions = JSON.parse(
|
||||
JSON.stringify(config.mediasoup.webRtcServerOptions)
|
||||
@@ -49,6 +39,16 @@ async function buildMediasoupWorkers() {
|
||||
const webRtcServer = await worker.createWebRtcServer(webRtcServerOptions);
|
||||
worker.appData.webRtcServer = webRtcServer;
|
||||
mediasoupWorkers.push(worker);
|
||||
// 监听事件
|
||||
worker.on("died", (error) => {
|
||||
console.warn("Mediasoup Worker停止服务:", worker.pid, error);
|
||||
setTimeout(() => process.exit(1), 2000);
|
||||
});
|
||||
worker.observer.on("close", () => {
|
||||
console.warn("Mediasoup Worker关闭服务:", worker.pid);
|
||||
});
|
||||
// worker.observer.on("newrouter", fn(router));
|
||||
// worker.observer.on("newwebrtcserver", fn(router));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ const signalChannel = {
|
||||
console.debug("信令通道消息:", content);
|
||||
me.taoyao.on(JSON.parse(content));
|
||||
} catch (error) {
|
||||
console.error("处理信令消息异常:", data, error);
|
||||
console.error("处理信令消息异常:", data.toString(), error);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -322,15 +322,18 @@ class Room {
|
||||
/**
|
||||
* 关闭资源
|
||||
*/
|
||||
close() {
|
||||
const self = this;
|
||||
if (self.close) {
|
||||
closeAll() {
|
||||
const me = this;
|
||||
if (me.close) {
|
||||
return;
|
||||
}
|
||||
self.close = true;
|
||||
if (self.mediasoupRouter) {
|
||||
self.mediasoupRouter.close();
|
||||
}
|
||||
me.close = true;
|
||||
// me.producers.forEach(v => v.close());
|
||||
// me.consumers.forEach(v => v.close());
|
||||
// me.dataProducers.forEach(v => v.close());
|
||||
// me.dataConsumers.forEach(v => v.close());
|
||||
me.transports.forEach(v => v.close());
|
||||
me.mediasoupRouter.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,6 +407,9 @@ class Taoyao {
|
||||
case "room::create":
|
||||
this.roomCreate(message, body);
|
||||
break;
|
||||
case "room::close":
|
||||
this.roomClose(message, body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,8 +818,9 @@ class Taoyao {
|
||||
);
|
||||
});
|
||||
await transport.enableTraceEvent(["bwe"]);
|
||||
// await transport.enableTraceEvent([ 'probation', 'bwe' ]);
|
||||
transport.on("trace", (trace) => {
|
||||
console.debug("transport trace event:", trace, trace.type, transport.id);
|
||||
console.debug("transport trace event:", transport.id, trace.type, trace);
|
||||
});
|
||||
// 可配置的事件
|
||||
// transport.on("routerclose", fn());
|
||||
@@ -842,30 +849,42 @@ class Taoyao {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭房间信令
|
||||
*
|
||||
* @param {*} message 消息
|
||||
* @param {*} body 消息主体
|
||||
*/
|
||||
async roomClose(message, body) {
|
||||
const roomId = body.roomId;
|
||||
const room = this.rooms.get(roomId);
|
||||
if(!room) {
|
||||
console.warn("房间无效:", roomId);
|
||||
return;
|
||||
}
|
||||
console.info("关闭房间:", roomId);
|
||||
room.closeAll();
|
||||
this.rooms.delete(roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建房间信令
|
||||
*
|
||||
* @param {*} message 消息
|
||||
* @param {*} body 消息主体
|
||||
*
|
||||
* @returns 房间
|
||||
*/
|
||||
async roomCreate(message, body) {
|
||||
const me = this;
|
||||
const roomId = body.roomId;
|
||||
let room = this.rooms.get(roomId);
|
||||
let room = me.rooms.get(roomId);
|
||||
if (room) {
|
||||
this.push(message);
|
||||
return room;
|
||||
console.debug("创建房间已经存在:", room);
|
||||
me.push(message);
|
||||
return;
|
||||
}
|
||||
const mediasoupWorker = this.nextMediasoupWorker();
|
||||
const mediasoupWorker = me.nextMediasoupWorker();
|
||||
const { mediaCodecs } = config.mediasoup.routerOptions;
|
||||
const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs });
|
||||
mediasoupRouter.observer.on("close", () => {
|
||||
// TODO:通知房间关闭
|
||||
});
|
||||
// 可配置的事件
|
||||
// mediasoupRouter.on("workerclose", () => {});
|
||||
// mediasoupRouter.observer.on("newtransport", fn(transport));
|
||||
// TODO:下面两个监控改为配置启用
|
||||
const audioLevelObserver = await mediasoupRouter.createAudioLevelObserver({
|
||||
maxEntries: 1,
|
||||
@@ -883,10 +902,22 @@ class Taoyao {
|
||||
audioLevelObserver,
|
||||
activeSpeakerObserver,
|
||||
});
|
||||
this.rooms.set(roomId, room);
|
||||
me.rooms.set(roomId, room);
|
||||
console.info("创建房间", roomId);
|
||||
this.push(message);
|
||||
return room;
|
||||
me.push(message);
|
||||
// 监听事件
|
||||
mediasoupRouter.observer.on("close", () => {
|
||||
console.info("房间路由关闭:", roomId, mediasoupRouter);
|
||||
room.closeAll();
|
||||
me.rooms.delete(roomId);
|
||||
me.push(
|
||||
protocol.buildMessage("room::close", {
|
||||
roomId: roomId
|
||||
})
|
||||
);
|
||||
});
|
||||
// mediasoupRouter.on("workerclose", () => {});
|
||||
// mediasoupRouter.observer.on("newtransport", fn(transport));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="创建房间" name="create">
|
||||
<el-form-item label="媒体服务">
|
||||
<el-select v-model="room.mediaId" placeholder="媒体服务标识">
|
||||
<el-select v-model="room.mediaClientId" placeholder="媒体服务标识">
|
||||
<el-option
|
||||
v-for="value in medias"
|
||||
:key="value.clientId"
|
||||
@@ -79,7 +79,7 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="enterRoom" v-if="roomActive === 'enter'">进入</el-button>
|
||||
<el-button type="primary" @click="createRoom" v-if="roomActive === 'create'">创建</el-button>
|
||||
<el-button type="primary" @click="roomCreate" v-if="roomActive === 'create'">创建</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
<el-button type="primary" @click="roomActive = 'create';roomVisible = true;">创建房间</el-button>
|
||||
<el-button>邀请终端</el-button>
|
||||
<el-button>退出房间</el-button>
|
||||
<el-button type="danger">关闭房间</el-button>
|
||||
<el-button @click="closeRoom()" type="danger">关闭房间</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 终端 -->
|
||||
@@ -149,14 +149,17 @@ export default {
|
||||
this.medias = await this.taoyao.mediaList();
|
||||
},
|
||||
async enterRoom() {
|
||||
await this.taoyao.enterRoom(this.room.roomId);
|
||||
await this.taoyao.enterRoom(this.room.roomId, this.room.password);
|
||||
await this.taoyao.produceMedia();
|
||||
this.roomVisible = false;
|
||||
},
|
||||
async createRoom() {
|
||||
const room = await this.taoyao.createRoom(this.room);
|
||||
this.room = room;
|
||||
await this.enterRoom(room.roomId);
|
||||
async roomCreate() {
|
||||
const room = await this.taoyao.roomCreate(this.room);
|
||||
this.room.roomId = room.roomId;
|
||||
await this.enterRoom();
|
||||
},
|
||||
async closeRoom() {
|
||||
this.taoyao.closeRoom();
|
||||
},
|
||||
/**
|
||||
* 信令回调
|
||||
|
||||
@@ -394,6 +394,7 @@ class Taoyao {
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
/************************ 回调 ************************/
|
||||
/**
|
||||
* 回调策略:
|
||||
* 1. 如果注册请求回调,同时执行结果返回true不再执行后面所有回调。
|
||||
@@ -450,25 +451,32 @@ class Taoyao {
|
||||
* @param {*} message 消息
|
||||
*/
|
||||
async postCallback(message) {
|
||||
const self = this;
|
||||
const me = this;
|
||||
switch (message.header.signal) {
|
||||
case "room::client::list":
|
||||
me.defaultRoomClientList(message);
|
||||
break;
|
||||
case "client::reboot":
|
||||
self.defaultClientReboot(message);
|
||||
me.defaultClientReboot(message);
|
||||
break;
|
||||
case "client::shutdown":
|
||||
self.defaultClientShutdown(message);
|
||||
me.defaultClientShutdown(message);
|
||||
break;
|
||||
case "room::close":
|
||||
me.defaultRoomClose(message);
|
||||
break;
|
||||
case "room::enter":
|
||||
self.defaultRoomEnter(message);
|
||||
break;
|
||||
case "room::client::list":
|
||||
self.defaultRoomClientList(message);
|
||||
me.defaultRoomEnter(message);
|
||||
break;
|
||||
case "platform::error":
|
||||
self.callbackError(message);
|
||||
me.callbackError(message);
|
||||
break;
|
||||
default:
|
||||
console.warn("不支持的信令:", message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/************************ 信令 ************************/
|
||||
/**
|
||||
* 配置默认回调
|
||||
*
|
||||
@@ -505,6 +513,53 @@ class Taoyao {
|
||||
console.info("关闭终端");
|
||||
window.close();
|
||||
}
|
||||
/**
|
||||
* 房间终端列表信令
|
||||
*
|
||||
* @param {*} message 消息
|
||||
*/
|
||||
defaultRoomClientList(message) {
|
||||
const me = this;
|
||||
message.body.forEach(v => {
|
||||
if (v.clientId === me.clientId) {
|
||||
// 忽略自己
|
||||
} else {
|
||||
me.remoteClients.set(v.clientId, me.roomId);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 关闭房间信令
|
||||
*
|
||||
* @param {*} message 消息
|
||||
*/
|
||||
defaultRoomClose(message) {
|
||||
const me = this;
|
||||
const { roomId } = message.body;
|
||||
if(me.roomId !== roomId) {
|
||||
return;
|
||||
}
|
||||
console.info("关闭房间:", roomId);
|
||||
me.close();
|
||||
}
|
||||
/**
|
||||
* 创建房间信令
|
||||
*
|
||||
* @param {*} room 房间
|
||||
*
|
||||
* @returns 房间
|
||||
*/
|
||||
async roomCreate(room) {
|
||||
const me = this;
|
||||
if (!room) {
|
||||
me.callbackError("无效房间");
|
||||
return;
|
||||
}
|
||||
const response = await me.request(
|
||||
protocol.buildMessage("room::create", room)
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
defaultRoomEnter(message) {
|
||||
const { roomId, clientId } = message.body;
|
||||
if (clientId === this.clientId) {
|
||||
@@ -513,16 +568,6 @@ class Taoyao {
|
||||
this.remoteClients.set(clientId, roomId);
|
||||
}
|
||||
}
|
||||
defaultRoomClientList(message) {
|
||||
const self = this;
|
||||
message.body.forEach((v) => {
|
||||
if (v.clientId === self.clientId) {
|
||||
// 忽略自己
|
||||
} else {
|
||||
self.remoteClients.set(v.clientId, self.roomId);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 错误回调
|
||||
*/
|
||||
@@ -562,21 +607,7 @@ class Taoyao {
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
/**
|
||||
* 创建房间
|
||||
*/
|
||||
async createRoom(room) {
|
||||
const self = this;
|
||||
if (!room) {
|
||||
this.callbackError("无效房间");
|
||||
return;
|
||||
}
|
||||
const response = await self.request(
|
||||
protocol.buildMessage("room::create", room)
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
async enterRoom(roomId) {
|
||||
async enterRoom(roomId, password) {
|
||||
const self = this;
|
||||
if (!roomId) {
|
||||
this.callbackError("无效房间");
|
||||
@@ -586,7 +617,7 @@ class Taoyao {
|
||||
self.mediasoupDevice = new mediasoupClient.Device();
|
||||
const response = await self.request(
|
||||
protocol.buildMessage("media::router::rtp::capabilities", {
|
||||
roomId: self.roomId,
|
||||
roomId: self.roomId
|
||||
})
|
||||
);
|
||||
const routerRtpCapabilities = response.body.rtpCapabilities;
|
||||
@@ -594,6 +625,7 @@ class Taoyao {
|
||||
await self.request(
|
||||
protocol.buildMessage("room::enter", {
|
||||
roomId: roomId,
|
||||
password: password,
|
||||
rtpCapabilities: self.consume
|
||||
? self.mediasoupDevice.rtpCapabilities
|
||||
: undefined,
|
||||
@@ -604,6 +636,17 @@ class Taoyao {
|
||||
})
|
||||
);
|
||||
}
|
||||
async closeRoom() {
|
||||
const me = this;
|
||||
if(!me.roomId) {
|
||||
console.warn("房间无效:", me.roomId);
|
||||
return;
|
||||
}
|
||||
me.push(protocol.buildMessage("room::close", {
|
||||
roomId: me.roomId
|
||||
}));
|
||||
}
|
||||
/************************ 媒体 ************************/
|
||||
/**
|
||||
* 生产媒体
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import fs from "node:fs";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
|
||||
@@ -143,10 +143,6 @@ public interface Constant {
|
||||
* 房间ID
|
||||
*/
|
||||
String ROOM_ID = "roomId";
|
||||
/**
|
||||
* 媒体服务ID
|
||||
*/
|
||||
String MEDIA_ID = "mediaId";
|
||||
/**
|
||||
* 媒体流ID
|
||||
*/
|
||||
@@ -179,6 +175,10 @@ public interface Constant {
|
||||
* 数据消费者ID
|
||||
*/
|
||||
String DATA_CONSUMER_ID = "dataConsumerId";
|
||||
/**
|
||||
* 媒体服务ID
|
||||
*/
|
||||
String MEDIA_CLIENT_ID = "mediaClientId";
|
||||
/**
|
||||
* ICE服务
|
||||
*/
|
||||
|
||||
@@ -162,11 +162,11 @@ public class BootAutoConfiguration {
|
||||
public void init() {
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
|
||||
final String maxMemory = FileUtils.formatSize(runtime.maxMemory());
|
||||
final String freeMemory = FileUtils.formatSize(runtime.freeMemory());
|
||||
final String totalMemory = FileUtils.formatSize(runtime.totalMemory());
|
||||
final String maxMemory = FileUtils.formatSize(runtime.maxMemory());
|
||||
log.info("操作系统名称:{}", System.getProperty("os.name"));
|
||||
log.info("操作系统架构:{}", System.getProperty("os.arch"));
|
||||
log.info("操作系统名称:{}", System.getProperty("os.name"));
|
||||
log.info("操作系统版本:{}", System.getProperty("os.version"));
|
||||
log.info("可用的处理器数量:{}", runtime.availableProcessors());
|
||||
log.info("Java版本:{}", System.getProperty("java.version"));
|
||||
@@ -175,9 +175,9 @@ public class BootAutoConfiguration {
|
||||
log.info("ClassPath:{}", System.getProperty("java.class.path"));
|
||||
log.info("虚拟机名称:{}", System.getProperty("java.vm.name"));
|
||||
log.info("虚拟机参数:{}", runtimeMXBean.getInputArguments().stream().collect(Collectors.joining(" ")));
|
||||
log.info("虚拟机最大内存:{}", maxMemory);
|
||||
log.info("虚拟机空闲内存:{}", freeMemory);
|
||||
log.info("虚拟机已用内存:{}", totalMemory);
|
||||
log.info("虚拟机最大内存:{}", maxMemory);
|
||||
log.info("工作目录:{}", System.getProperty("user.dir"));
|
||||
log.info("用户目录:{}", System.getProperty("user.home"));
|
||||
log.info("临时目录:{}", System.getProperty("java.io.tmpdir"));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.acgist.taoyao.boot.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -61,8 +62,35 @@ public final class MapUtils {
|
||||
return null;
|
||||
} else if(object instanceof Long value) {
|
||||
return value;
|
||||
} else if(object instanceof Integer value) {
|
||||
return value.longValue();
|
||||
} else if(object instanceof Double value) {
|
||||
return value.longValue();
|
||||
}
|
||||
return Long.valueOf(object.toString());
|
||||
return new BigDecimal(object.toString()).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param body 消息主体
|
||||
* @param key 参数名称
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public static final Double getDouble(Map<?, ?> body, String key) {
|
||||
if(body == null) {
|
||||
return null;
|
||||
}
|
||||
final Object object = body.get(key);
|
||||
if(object == null) {
|
||||
return null;
|
||||
} else if(object instanceof Long value) {
|
||||
return value.doubleValue();
|
||||
} else if(object instanceof Integer value) {
|
||||
return value.doubleValue();
|
||||
} else if(object instanceof Double value) {
|
||||
return value;
|
||||
}
|
||||
return new BigDecimal(object.toString()).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,10 +106,14 @@ public final class MapUtils {
|
||||
final Object object = body.get(key);
|
||||
if(object == null) {
|
||||
return null;
|
||||
} else if(object instanceof Long value) {
|
||||
return value.intValue();
|
||||
} else if(object instanceof Integer value) {
|
||||
return value;
|
||||
} else if(object instanceof Double value) {
|
||||
return value.intValue();
|
||||
}
|
||||
return Integer.valueOf(object.toString());
|
||||
return new BigDecimal(object.toString()).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,12 +60,12 @@ public class ClientStatus {
|
||||
* @param body 消息主体
|
||||
*/
|
||||
public void copy(Map<String, Object> body) {
|
||||
this.setLatitude(MapUtils.get(body, Constant.LATITUDE));
|
||||
this.setLongitude(MapUtils.get(body, Constant.LONGITUDE));
|
||||
this.setHumidity(MapUtils.get(body, Constant.HUMIDITY));
|
||||
this.setTemperature(MapUtils.get(body, Constant.TEMPERATURE));
|
||||
this.setSignal(MapUtils.get(body, Constant.SIGNAL));
|
||||
this.setBattery(MapUtils.get(body, Constant.BATTERY));
|
||||
this.setLatitude(MapUtils.getDouble(body, Constant.LATITUDE));
|
||||
this.setLongitude(MapUtils.getDouble(body, Constant.LONGITUDE));
|
||||
this.setHumidity(MapUtils.getDouble(body, Constant.HUMIDITY));
|
||||
this.setTemperature(MapUtils.getDouble(body, Constant.TEMPERATURE));
|
||||
this.setSignal(MapUtils.getInteger(body, Constant.SIGNAL));
|
||||
this.setBattery(MapUtils.getInteger(body, Constant.BATTERY));
|
||||
this.setAlarming(MapUtils.getBoolean(body, Constant.ALARMING));
|
||||
this.setCharging(MapUtils.getBoolean(body, Constant.CHARGING));
|
||||
this.setRecording(MapUtils.getBoolean(body, Constant.RECORDING));
|
||||
|
||||
@@ -196,7 +196,7 @@ public class Room implements Closeable {
|
||||
@Override
|
||||
public void close() {
|
||||
log.info("关闭房间:{}", this.roomId);
|
||||
// TODO
|
||||
// TODO:关闭房间
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class MediaConsumeProtocol extends ProtocolRoomAdapter implements Applica
|
||||
|
||||
public static final String SIGNAL = "media::consume";
|
||||
|
||||
protected MediaConsumeProtocol() {
|
||||
public MediaConsumeProtocol() {
|
||||
super("消费媒体信令", SIGNAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class MediaTransportWebRtcCreateProtocol extends ProtocolRoomAdapter {
|
||||
|
||||
public static final String SIGNAL = "media::transport::webrtc::create";
|
||||
|
||||
protected MediaTransportWebRtcCreateProtocol() {
|
||||
public MediaTransportWebRtcCreateProtocol() {
|
||||
super("创建WebRTC通道信令", SIGNAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
}
|
||||
"""
|
||||
},
|
||||
flow = "终端->服务端->终端"
|
||||
flow = "终端->信令服务->终端"
|
||||
)
|
||||
public class PlatformScriptProtocol extends ProtocolClientAdapter {
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class PlatformShutdownProtocol extends ProtocolClientAdapter implements C
|
||||
if(this.applicationContext instanceof ConfigurableApplicationContext context) {
|
||||
// API关闭
|
||||
if(context.isActive()) {
|
||||
// 如果需要完整广播可以设置延时
|
||||
// 如果需要广播完成可以设置延时
|
||||
context.close();
|
||||
} else {
|
||||
// 其他情况
|
||||
|
||||
@@ -19,16 +19,17 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
||||
@Description(
|
||||
body = """
|
||||
{
|
||||
"roomId": "房间ID",
|
||||
...
|
||||
}
|
||||
""",
|
||||
flow = "终端->信令服务->终端"
|
||||
flow = "终端->信令服务-)终端"
|
||||
)
|
||||
public class RoomBroadcastProtocol extends ProtocolRoomAdapter {
|
||||
|
||||
public static final String SIGNAL = "room::broadcast";
|
||||
|
||||
protected RoomBroadcastProtocol() {
|
||||
public RoomBroadcastProtocol() {
|
||||
super("房间广播信令", SIGNAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,36 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
||||
*/
|
||||
@Protocol
|
||||
@Description(
|
||||
body = {
|
||||
"""
|
||||
{
|
||||
"roomId": "房间ID"
|
||||
}
|
||||
""",
|
||||
"""
|
||||
[
|
||||
{
|
||||
"ip": "终端IP",
|
||||
"name": "终端名称",
|
||||
"clientId": "终端ID",
|
||||
"clientType": "终端类型",
|
||||
"latitude": 纬度,
|
||||
"longitude": 经度,
|
||||
"humidity": 湿度,
|
||||
"temperature": 温度,
|
||||
"signal": 信号强度(0~100),
|
||||
"battery": 电池电量(0~100),
|
||||
"alarming": 是否发生告警(true|false),
|
||||
"charging": 是否正在充电(true|false),
|
||||
"recording": 是否正在录像(true|false),
|
||||
"lastHeartbeat": "最后心跳时间",
|
||||
"status": {更多状态},
|
||||
"config": {更多配置}
|
||||
},
|
||||
...
|
||||
]
|
||||
"""
|
||||
},
|
||||
flow = "终端=>信令服务->终端"
|
||||
)
|
||||
public class RoomClientListProtocol extends ProtocolRoomAdapter {
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.Map;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Description;
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.config.Constant;
|
||||
import com.acgist.taoyao.boot.model.Message;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.client.ClientType;
|
||||
@@ -17,6 +18,11 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
||||
*/
|
||||
@Protocol
|
||||
@Description(
|
||||
body = """
|
||||
{
|
||||
"roomId": "房间ID"
|
||||
}
|
||||
""",
|
||||
flow = "终端->信令服务->媒体服务->信令服务+)终端"
|
||||
)
|
||||
public class RoomCloseProtocol extends ProtocolRoomAdapter {
|
||||
@@ -29,9 +35,15 @@ public class RoomCloseProtocol extends ProtocolRoomAdapter {
|
||||
|
||||
@Override
|
||||
public void execute(String clientId, ClientType clientType, Room room, Client client, Client mediaClient, Message message, Map<String, Object> body) {
|
||||
if(clientType == ClientType.WEB) {
|
||||
mediaClient.push(this.build(Map.of(Constant.ROOM_ID, room.getRoomId())));
|
||||
} else if(clientType == ClientType.MEDIA) {
|
||||
room.close();
|
||||
this.clientManager.broadcast(message);
|
||||
// TODO:释放房间
|
||||
room.broadcast(message);
|
||||
// TODO:移除
|
||||
} else {
|
||||
this.logNoAdapter(clientType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,25 +16,30 @@ import com.acgist.taoyao.signal.event.MediaClientRegisterEvent;
|
||||
import com.acgist.taoyao.signal.party.media.Room;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolClientAdapter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 创建房间信令
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Slf4j
|
||||
@Protocol
|
||||
@Description(
|
||||
body = """
|
||||
body = {
|
||||
"""
|
||||
{
|
||||
"name": "房间名称",
|
||||
"passowrd": "房间密码",
|
||||
"mediaId": "媒体服务标识",
|
||||
"clientSize": "终端数量"
|
||||
"passowrd": "房间密码(选填)",
|
||||
"mediaClientId": "媒体服务ID"
|
||||
}
|
||||
""",
|
||||
flow = "终端->服务端+)终端"
|
||||
"""
|
||||
{
|
||||
"name": "房间名称",
|
||||
"clientSize": "终端数量",
|
||||
"mediaClientId": "媒体服务ID"
|
||||
}
|
||||
"""
|
||||
},
|
||||
flow = "终端->信令服务->媒体服务->信令服务+)终端"
|
||||
)
|
||||
public class RoomCreateProtocol extends ProtocolClientAdapter implements ApplicationListener<MediaClientRegisterEvent> {
|
||||
|
||||
@@ -53,19 +58,13 @@ public class RoomCreateProtocol extends ProtocolClientAdapter implements Applica
|
||||
@Override
|
||||
public void execute(String clientId, ClientType clientType, Client client, Message message, Map<String, Object> body) {
|
||||
if(clientType == ClientType.WEB) {
|
||||
final String roomId = MapUtils.get(body, Constant.ROOM_ID);
|
||||
if (roomId != null && this.roomManager.room(roomId) != null) {
|
||||
log.info("房间已经存在:{}", roomId);
|
||||
return;
|
||||
}
|
||||
// 创建房间
|
||||
// WEB同步创建房间
|
||||
final Room room = this.roomManager.create(
|
||||
MapUtils.get(body, Constant.NAME),
|
||||
MapUtils.get(body, Constant.PASSWORD),
|
||||
MapUtils.get(body, Constant.MEDIA_ID),
|
||||
MapUtils.get(body, Constant.MEDIA_CLIENT_ID),
|
||||
message.cloneWithoutBody()
|
||||
);
|
||||
// 广播消息
|
||||
message.setBody(room.getRoomStatus());
|
||||
this.clientManager.broadcast(message);
|
||||
} else {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.acgist.taoyao.signal.protocol.room;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.acgist.taoyao.boot.annotation.Description;
|
||||
import com.acgist.taoyao.boot.annotation.Protocol;
|
||||
import com.acgist.taoyao.boot.config.Constant;
|
||||
@@ -12,8 +14,8 @@ import com.acgist.taoyao.boot.utils.MapUtils;
|
||||
import com.acgist.taoyao.signal.client.Client;
|
||||
import com.acgist.taoyao.signal.client.ClientType;
|
||||
import com.acgist.taoyao.signal.party.media.ClientWrapper;
|
||||
import com.acgist.taoyao.signal.party.media.Room;
|
||||
import com.acgist.taoyao.signal.party.media.ClientWrapper.SubscribeType;
|
||||
import com.acgist.taoyao.signal.party.media.Room;
|
||||
import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -39,7 +41,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
}
|
||||
"""
|
||||
},
|
||||
flow = "终端->服务端-)终端"
|
||||
flow = "终端->信令服务-)终端"
|
||||
)
|
||||
public class RoomEnterProtocol extends ProtocolRoomAdapter {
|
||||
|
||||
@@ -59,7 +61,7 @@ public class RoomEnterProtocol extends ProtocolRoomAdapter {
|
||||
final Object rtpCapabilities = MapUtils.get(body, Constant.RTP_CAPABILITIES);
|
||||
final Object sctpCapabilities = MapUtils.get(body, Constant.SCTP_CAPABILITIES);
|
||||
final String roomPassowrd = room.getPassword();
|
||||
if(roomPassowrd != null && !roomPassowrd.equals(password)) {
|
||||
if(StringUtils.isNotEmpty(roomPassowrd) && !roomPassowrd.equals(password)) {
|
||||
throw MessageCodeException.of(MessageCode.CODE_3401, "密码错误");
|
||||
}
|
||||
// 进入房间
|
||||
@@ -74,7 +76,7 @@ public class RoomEnterProtocol extends ProtocolRoomAdapter {
|
||||
));
|
||||
room.broadcast(message);
|
||||
log.info("进入房间:{} - {}", clientId, room.getRoomId());
|
||||
// 推送房间用户信息
|
||||
// 推送房间用户信息:TODO event
|
||||
final Message roomClientListMessage = this.roomClientListProtocol.build();
|
||||
roomClientListMessage.setBody(room.clientStatus());
|
||||
client.push(roomClientListMessage);
|
||||
|
||||
@@ -24,7 +24,29 @@ import lombok.Setter;
|
||||
* @author acgist
|
||||
*/
|
||||
@Protocol
|
||||
@Description
|
||||
@Description(
|
||||
body = """
|
||||
{
|
||||
"diskspace": [
|
||||
{
|
||||
"path": "存储路径",
|
||||
"free": 存储空闲,
|
||||
"total": 存储总量
|
||||
},
|
||||
...
|
||||
],
|
||||
"maxMemory": 最大能用内存,
|
||||
"freeMemory": 空闲内存,
|
||||
"totalMemory": 已用内存,
|
||||
"osArch": "系统架构",
|
||||
"osName": "系统名称",
|
||||
"osVersion": "系统版本",
|
||||
"javaVmName": "虚拟机名称",
|
||||
"javaVersion": "虚拟机版本",
|
||||
"cpuProcessors": CPU核心数量
|
||||
}
|
||||
"""
|
||||
)
|
||||
public class SystemInfoProtocol extends ProtocolClientAdapter {
|
||||
|
||||
public static final String SIGNAL = "system::info";
|
||||
@@ -38,10 +60,10 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
|
||||
final Map<String, Object> info = new HashMap<>();
|
||||
// 硬盘
|
||||
final List<Diskspace> diskspace = new ArrayList<>();
|
||||
// File.listRoots(); -> 不全
|
||||
// FileSystems.getDefault().getFileStores(); -> 重复
|
||||
// File.listRoots();
|
||||
// FileSystems.getDefault().getFileStores();
|
||||
Stream.of(File.listRoots()).forEach(v -> {
|
||||
diskspace.add(new Diskspace(v.getPath(), v.getTotalSpace(), v.getFreeSpace()));
|
||||
diskspace.add(new Diskspace(v.getPath(), v.getFreeSpace(), v.getTotalSpace()));
|
||||
});
|
||||
info.put("diskspace", diskspace);
|
||||
// 内存
|
||||
@@ -53,8 +75,8 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
|
||||
info.put("freeMemoryGracefully", FileUtils.formatSize(runtime.freeMemory()));
|
||||
info.put("totalMemoryGracefully", FileUtils.formatSize(runtime.totalMemory()));
|
||||
// 其他
|
||||
info.put("osName", System.getProperty("os.name"));
|
||||
info.put("osArch", System.getProperty("os.arch"));
|
||||
info.put("osName", System.getProperty("os.name"));
|
||||
info.put("osVersion", System.getProperty("os.version"));
|
||||
info.put("javaVmName", System.getProperty("java.vm.name"));
|
||||
info.put("javaVersion", System.getProperty("java.version"));
|
||||
@@ -71,10 +93,6 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
|
||||
* 路径
|
||||
*/
|
||||
private final String path;
|
||||
/**
|
||||
* 总量
|
||||
*/
|
||||
private final Long total;
|
||||
/**
|
||||
* 空闲
|
||||
*/
|
||||
@@ -82,18 +100,22 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
|
||||
/**
|
||||
* 总量
|
||||
*/
|
||||
private final String totalGracefully;
|
||||
private final Long total;
|
||||
/**
|
||||
* 空闲
|
||||
*/
|
||||
private final String freeGracefully;
|
||||
/**
|
||||
* 总量
|
||||
*/
|
||||
private final String totalGracefully;
|
||||
|
||||
public Diskspace(String path, Long total, Long free) {
|
||||
public Diskspace(String path, Long free, Long total) {
|
||||
this.path = path;
|
||||
this.total = total;
|
||||
this.free = free;
|
||||
this.totalGracefully = FileUtils.formatSize(total);
|
||||
this.total = total;
|
||||
this.freeGracefully = FileUtils.formatSize(free);
|
||||
this.totalGracefully = FileUtils.formatSize(total);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user