[*] 日常优化
This commit is contained in:
@@ -629,13 +629,17 @@ openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12
|
||||
|
||||
```
|
||||
# 安装路径
|
||||
--prefix=/data/dev/ffmpeg/build
|
||||
--prefix=/usr/local
|
||||
--prefix=/usr/local/ffmpeg
|
||||
# 执行文件路径
|
||||
--bindir=/data/dev/ffmpeg/bin
|
||||
--bindir=/usr/local/bin
|
||||
--bindir=/usr/local/ffmpeg/bin
|
||||
# 库文件路径
|
||||
--libdir=/usr/local/lib
|
||||
--libdir=/usr/local/ffmpeg/lib
|
||||
# 头文件路径
|
||||
--includedir=/usr/local/include
|
||||
--includedir=/usr/local/ffmpeg/include
|
||||
```
|
||||
|
||||
## 清理源码
|
||||
|
||||
@@ -277,6 +277,7 @@ public class SessionClient extends Client {
|
||||
if(sdp == null || sdpMid == null || sdpMLineIndex == null) {
|
||||
Log.w(SessionClient.class.getSimpleName(), "无效媒体协商:" + body);
|
||||
} else {
|
||||
// TODO:验证是否可能为空PC
|
||||
this.peerConnection.addIceCandidate(new IceCandidate(sdpMid, sdpMLineIndex, sdp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ const os = require("os");
|
||||
* 一半配置本机IP地址,用于Mediasoup媒体协商时SDP地址信息。
|
||||
* 如果存在多网卡或者多子网时,需要配置信令地址重写和防火墙端口转发。
|
||||
*/
|
||||
defaultTaoyaoHost = "192.168.1.110";
|
||||
const defaultTaoyaoHost = "192.168.1.110";
|
||||
|
||||
/**
|
||||
* 配置
|
||||
@@ -13,25 +13,27 @@ defaultTaoyaoHost = "192.168.1.110";
|
||||
module.exports = {
|
||||
// 服务名称
|
||||
name: "taoyao-client-media",
|
||||
// 服务配置
|
||||
// 信令配置
|
||||
signal: {
|
||||
// 服务版本
|
||||
version: "1.0.0",
|
||||
// 信令版本
|
||||
version : "1.0.0",
|
||||
// 终端标识
|
||||
clientId: "taoyao-client-media",
|
||||
clientId : "taoyao-client-media",
|
||||
// 终端类型
|
||||
clientType: "MEDIA",
|
||||
// 终端名称
|
||||
name: "桃夭媒体服务",
|
||||
name : "桃夭媒体服务",
|
||||
// 信令地址
|
||||
host: "127.0.0.1",
|
||||
// host: "192.168.1.100",
|
||||
host : "127.0.0.1",
|
||||
// host : "192.168.1.100",
|
||||
// 信令端口
|
||||
port: 8888,
|
||||
port : 8888,
|
||||
// 信令协议
|
||||
scheme: "wss",
|
||||
scheme : "wss",
|
||||
// 信令帐号
|
||||
username: "taoyao",
|
||||
username : "taoyao",
|
||||
// 信令密码
|
||||
password: "taoyao",
|
||||
password : "taoyao",
|
||||
},
|
||||
// 录像配置
|
||||
record: {
|
||||
|
||||
@@ -92,7 +92,7 @@ const signalChannel = {
|
||||
if (me.heartbeatTimer) {
|
||||
clearTimeout(me.heartbeatTimer);
|
||||
}
|
||||
me.heartbeatTimer = setTimeout(async function () {
|
||||
me.heartbeatTimer = setTimeout(async () => {
|
||||
if (me.connected()) {
|
||||
me.push(
|
||||
protocol.buildMessage("client::heartbeat", {
|
||||
@@ -120,7 +120,7 @@ const signalChannel = {
|
||||
* @param {*} address 信令地址
|
||||
* @param {*} reconnection 是否重连
|
||||
*
|
||||
* @returns Promise
|
||||
* @returns Promise<WebSocket>
|
||||
*/
|
||||
async connect(address, reconnection = true) {
|
||||
const me = this;
|
||||
@@ -134,13 +134,13 @@ const signalChannel = {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.debug("连接信令通道", me.address);
|
||||
me.channel = new WebSocket(me.address, { rejectUnauthorized: false, handshakeTimeout: 5000 });
|
||||
me.channel.on("open", async function () {
|
||||
me.channel.on("open", async () => {
|
||||
console.info("打开信令通道", me.address);
|
||||
me.push(
|
||||
protocol.buildMessage("client::register", {
|
||||
name : config.signal.name,
|
||||
clientId : config.signal.clientId,
|
||||
clientType: "MEDIA",
|
||||
clientType: config.signal.clientType,
|
||||
username : config.signal.username,
|
||||
password : config.signal.password,
|
||||
// TODO:电池信息
|
||||
@@ -153,7 +153,7 @@ const signalChannel = {
|
||||
me.heartbeat();
|
||||
resolve(me.channel);
|
||||
});
|
||||
me.channel.on("close", async function () {
|
||||
me.channel.on("close", async () => {
|
||||
console.warn("信令通道关闭", me.address);
|
||||
me.taoyao.connect = false;
|
||||
if(!me.connected()) {
|
||||
@@ -164,11 +164,11 @@ const signalChannel = {
|
||||
}
|
||||
// 不要失败回调
|
||||
});
|
||||
me.channel.on("error", async function (e) {
|
||||
me.channel.on("error", async (e) => {
|
||||
console.error("信令通道异常", me.address, e);
|
||||
// 不要失败回调
|
||||
});
|
||||
me.channel.on("message", async function (data) {
|
||||
me.channel.on("message", async (data) => {
|
||||
const content = data.toString();
|
||||
try {
|
||||
console.debug("信令通道消息", content);
|
||||
@@ -196,7 +196,7 @@ const signalChannel = {
|
||||
clearTimeout(me.reconnectTimer);
|
||||
}
|
||||
// 定时重连
|
||||
me.reconnectTimer = setTimeout(function () {
|
||||
me.reconnectTimer = setTimeout(() => {
|
||||
console.info("重连信令通道", me.address);
|
||||
me.connect(me.address, me.reconnection);
|
||||
me.lockReconnect = false;
|
||||
@@ -227,9 +227,9 @@ const signalChannel = {
|
||||
console.info("关闭信令通道", me.address);
|
||||
clearTimeout(me.heartbeatTimer);
|
||||
clearTimeout(me.reconnectTimer);
|
||||
me.reconnection = false;
|
||||
me.channel.close();
|
||||
me.reconnection = false;
|
||||
me.taoyao.connect = false;
|
||||
me.channel.close();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -150,12 +150,6 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
console.info(`
|
||||
中庭地白树栖鸦,冷露无声湿桂花。
|
||||
今夜月明人尽望,不知秋思落谁家。
|
||||
|
||||
:: https://gitee.com/acgist/taoyao
|
||||
`);
|
||||
},
|
||||
methods: {
|
||||
async connectSignal() {
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
/**
|
||||
* 配置:{ min: 8000, exact: 32000, ideal: 32000, max: 48000 }
|
||||
* 配置
|
||||
*/
|
||||
const config = {
|
||||
// 信令配置
|
||||
signal: {
|
||||
// 信令版本
|
||||
version : "1.0.0",
|
||||
// 终端类型
|
||||
clientType: "WEB",
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 音频默认配置
|
||||
* 配置:{ min: 8000, exact: 32000, ideal: 32000, max: 48000 }
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings
|
||||
*/
|
||||
@@ -31,6 +41,7 @@ const defaultAudioConfig = {
|
||||
|
||||
/**
|
||||
* 视频默认配置
|
||||
* 配置:{ min: 8000, exact: 32000, ideal: 32000, max: 48000 }
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings
|
||||
*/
|
||||
@@ -147,6 +158,7 @@ const defaultRTCPeerConnectionConfig = {
|
||||
};
|
||||
|
||||
export {
|
||||
config,
|
||||
defaultAudioConfig,
|
||||
defaultVideoConfig,
|
||||
defaultShareScreenConfig,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as mediasoupClient from "mediasoup-client";
|
||||
import {
|
||||
config,
|
||||
defaultAudioConfig,
|
||||
defaultVideoConfig,
|
||||
defaultShareScreenConfig,
|
||||
@@ -9,7 +10,7 @@ import {
|
||||
} from "./Config.js";
|
||||
|
||||
/**
|
||||
* 信令
|
||||
* 信令协议
|
||||
*/
|
||||
const protocol = {
|
||||
// 当前索引
|
||||
@@ -48,7 +49,7 @@ const protocol = {
|
||||
const me = this;
|
||||
const message = {
|
||||
header: {
|
||||
v : v || "1.0.0",
|
||||
v : v || config.signal.version,
|
||||
id : id || me.buildId(),
|
||||
signal: signal,
|
||||
},
|
||||
@@ -97,7 +98,7 @@ const signalChannel = {
|
||||
if (me.heartbeatTimer) {
|
||||
clearTimeout(me.heartbeatTimer);
|
||||
}
|
||||
me.heartbeatTimer = setTimeout(async function () {
|
||||
me.heartbeatTimer = setTimeout(async () => {
|
||||
if (me.connected()) {
|
||||
const battery = await navigator.getBattery();
|
||||
me.push(
|
||||
@@ -125,7 +126,7 @@ const signalChannel = {
|
||||
* @param {*} address 信令地址
|
||||
* @param {*} reconnection 是否重连
|
||||
*
|
||||
* @returns Promise
|
||||
* @returns Promise<WebSocket>
|
||||
*/
|
||||
async connect(address, reconnection = true) {
|
||||
const me = this;
|
||||
@@ -139,14 +140,14 @@ const signalChannel = {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.debug("连接信令通道", me.address);
|
||||
me.channel = new WebSocket(me.address);
|
||||
me.channel.onopen = async function () {
|
||||
me.channel.onopen = async () => {
|
||||
console.info("打开信令通道", me.address);
|
||||
const battery = await navigator.getBattery();
|
||||
me.push(
|
||||
protocol.buildMessage("client::register", {
|
||||
name : me.taoyao.name,
|
||||
clientId : me.taoyao.clientId,
|
||||
clientType: "WEB",
|
||||
clientType: config.signal.clientType,
|
||||
username : me.taoyao.username,
|
||||
password : me.taoyao.password,
|
||||
battery : battery.level * 100,
|
||||
@@ -158,7 +159,7 @@ const signalChannel = {
|
||||
me.heartbeat();
|
||||
resolve(me.channel);
|
||||
};
|
||||
me.channel.onclose = async function () {
|
||||
me.channel.onclose = async () => {
|
||||
console.warn("信令通道关闭", me.channel);
|
||||
me.taoyao.connect = false;
|
||||
if(!me.connected()) {
|
||||
@@ -170,11 +171,11 @@ const signalChannel = {
|
||||
}
|
||||
// 不要失败回调
|
||||
};
|
||||
me.channel.onerror = async function (e) {
|
||||
me.channel.onerror = async (e) => {
|
||||
console.error("信令通道异常", me.channel, e);
|
||||
// 不要失败回调
|
||||
};
|
||||
me.channel.onmessage = async function (e) {
|
||||
me.channel.onmessage = async (e) => {
|
||||
const content = e.data;
|
||||
try {
|
||||
console.debug("信令通道消息", content);
|
||||
@@ -202,7 +203,7 @@ const signalChannel = {
|
||||
clearTimeout(me.reconnectTimer);
|
||||
}
|
||||
// 定时重连
|
||||
me.reconnectTimer = setTimeout(function () {
|
||||
me.reconnectTimer = setTimeout(() => {
|
||||
console.info("重连信令通道", me.address);
|
||||
me.connect(me.address, me.reconnection);
|
||||
me.lockReconnect = false;
|
||||
@@ -230,27 +231,27 @@ const signalChannel = {
|
||||
*/
|
||||
close() {
|
||||
const me = this;
|
||||
console.info("关闭信令通道", me.address);
|
||||
clearTimeout(me.heartbeatTimer);
|
||||
clearTimeout(me.reconnectTimer);
|
||||
me.reconnection = false;
|
||||
me.channel.close();
|
||||
me.reconnection = false;
|
||||
me.taoyao.connect = false;
|
||||
me.channel.close();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 会话
|
||||
* 视频会话
|
||||
*/
|
||||
class Session {
|
||||
|
||||
// 会话ID
|
||||
id;
|
||||
// 远程终端名称
|
||||
name;
|
||||
// 音量
|
||||
volume = "100%";
|
||||
// 是否关闭
|
||||
closed;
|
||||
// 音量
|
||||
volume;
|
||||
// 远程终端名称
|
||||
name;
|
||||
// 远程终端ID
|
||||
clientId;
|
||||
// 会话ID
|
||||
@@ -263,17 +264,21 @@ class Session {
|
||||
videoEnabled;
|
||||
// 本地音频
|
||||
localAudioTrack;
|
||||
// 本地音频是否可用(暂停关闭)
|
||||
localAudioEnabled;
|
||||
// 本地视频
|
||||
localVideoTrack;
|
||||
// 本地视频是否可用(暂停关闭)
|
||||
localVideoEnabled;
|
||||
// 远程音频
|
||||
remoteAudioTrack;
|
||||
// 远程音频是否可用(暂停关闭)
|
||||
remoteAudioEnabled;
|
||||
// 远程视频
|
||||
remoteVideoTrack;
|
||||
// 远程视频是否可用(暂停关闭)
|
||||
remoteVideoEnabled;
|
||||
// PeerConnection
|
||||
// WebRTC PeerConnection
|
||||
peerConnection;
|
||||
|
||||
constructor({
|
||||
@@ -283,67 +288,91 @@ class Session {
|
||||
audioEnabled,
|
||||
videoEnabled
|
||||
}) {
|
||||
this.id = sessionId;
|
||||
this.name = name;
|
||||
this.closed = false;
|
||||
this.clientId = clientId;
|
||||
this.sessionId = sessionId;
|
||||
this.id = sessionId;
|
||||
this.closed = false;
|
||||
this.volume = "100%";
|
||||
this.name = name;
|
||||
this.clientId = clientId;
|
||||
this.sessionId = sessionId;
|
||||
this.audioEnabled = audioEnabled;
|
||||
this.videoEnabled = videoEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停本地媒体
|
||||
*
|
||||
* @param {*} type 媒体类型
|
||||
*/
|
||||
async pause(type) {
|
||||
if(type === 'audio' && this.localAudioTrack) {
|
||||
this.localAudioEnabled = false;
|
||||
this.localAudioEnabled = false;
|
||||
this.localAudioTrack.enabled = false;
|
||||
}
|
||||
if(type === 'video' && this.localVideoTrack) {
|
||||
this.localVideoEnabled = false;
|
||||
this.localVideoEnabled = false;
|
||||
this.localVideoTrack.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复本地媒体
|
||||
*
|
||||
* @param {*} type 媒体类型
|
||||
*/
|
||||
async resume(type) {
|
||||
if(type === 'audio' && this.localAudioTrack) {
|
||||
this.localAudioEnabled = true;
|
||||
this.localAudioEnabled = true;
|
||||
this.localAudioTrack.enabled = true;
|
||||
}
|
||||
if(type === 'video' && this.localVideoTrack) {
|
||||
this.localVideoEnabled = true;
|
||||
this.localVideoEnabled = true;
|
||||
this.localVideoTrack.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停远程媒体
|
||||
*
|
||||
* @param {*} type 媒体类型
|
||||
*/
|
||||
async pauseRemote(type) {
|
||||
if(type === 'audio') {
|
||||
this.remoteAudioEnabled = false;
|
||||
if(type === 'audio' && this.remoteAudioTrack) {
|
||||
this.remoteAudioEnabled = false;
|
||||
this.remoteAudioTrack.enabled = false;
|
||||
}
|
||||
if(type === 'video') {
|
||||
this.remoteVideoEnabled = false;
|
||||
if(type === 'video' && this.remoteVideoTrack) {
|
||||
this.remoteVideoEnabled = false;
|
||||
this.remoteVideoTrack.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复远程媒体
|
||||
*
|
||||
* @param {*} type 媒体类型
|
||||
*/
|
||||
async resumeRemote(type) {
|
||||
if(type === 'audio') {
|
||||
this.remoteAudioEnabled = true;
|
||||
if(type === 'audio' && this.remoteAudioTrack) {
|
||||
this.remoteAudioEnabled = true;
|
||||
this.remoteAudioTrack.enabled = true;
|
||||
}
|
||||
if(type === 'video') {
|
||||
this.remoteVideoEnabled = true;
|
||||
if(type === 'video' && this.remoteVideoTrack) {
|
||||
this.remoteVideoEnabled = true;
|
||||
this.remoteVideoTrack.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭视频会话
|
||||
*/
|
||||
async close() {
|
||||
if(this.closed) {
|
||||
return;
|
||||
}
|
||||
console.debug("会话关闭", this.sessionId);
|
||||
this.closed = true;
|
||||
this.localAudioEnabled = false;
|
||||
this.localVideoEnabled = false;
|
||||
this.localAudioEnabled = false;
|
||||
this.localVideoEnabled = false;
|
||||
this.remoteAudioEnabled = false;
|
||||
this.remoteVideoEnabled = false;
|
||||
if(this.localAudioTrack) {
|
||||
@@ -368,21 +397,39 @@ class Session {
|
||||
}
|
||||
}
|
||||
|
||||
async addIceCandidate(candidate) {
|
||||
/**
|
||||
* 添加媒体协商
|
||||
*
|
||||
* @param {*} candidate 媒体协商
|
||||
* @param {*} index 重试次数
|
||||
*/
|
||||
async addIceCandidate(candidate, index = 0) {
|
||||
if(this.closed) {
|
||||
return;
|
||||
}
|
||||
if(!candidate || candidate.sdpMid === undefined || candidate.sdpMLineIndex === undefined && candidate.candidate === undefined) {
|
||||
if(index >= 8) {
|
||||
console.debug("添加媒体协商次数超限", candidate, index);
|
||||
return;
|
||||
}
|
||||
if(
|
||||
!candidate ||
|
||||
candidate.sdpMid === undefined ||
|
||||
candidate.candidate === undefined ||
|
||||
candidate.sdpMLineIndex === undefined
|
||||
) {
|
||||
console.debug("无效媒体协商", candidate);
|
||||
return;
|
||||
}
|
||||
if(this.peerConnection) {
|
||||
await this.peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
|
||||
} else {
|
||||
setTimeout(() => this.addIceCandidate(candidate), 50);
|
||||
console.debug("延迟添加媒体协商", candidate, index);
|
||||
setTimeout(() => this.addIceCandidate(candidate, ++index), 100);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
// TODO:continue
|
||||
|
||||
/**
|
||||
* 远程终端
|
||||
@@ -2694,6 +2741,18 @@ class Taoyao extends RemoteClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭媒体轨道
|
||||
*
|
||||
* @param {*} mediaTrack 媒体轨道
|
||||
*/
|
||||
closeMediaTrack(mediaTrack) {
|
||||
if(!mediaTrack) {
|
||||
return;
|
||||
}
|
||||
mediaTrack.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭视频房间媒体
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import App from "./App.vue";
|
||||
import App from "./App.vue";
|
||||
import ElementPlus from "element-plus";
|
||||
import { createApp } from "vue";
|
||||
import ElementPlus from "element-plus";
|
||||
import "./assets/main.css";
|
||||
import "element-plus/dist/index.css";
|
||||
|
||||
console.info(`
|
||||
中庭地白树栖鸦,冷露无声湿桂花。
|
||||
今夜月明人尽望,不知秋思落谁家。
|
||||
|
||||
:: https://gitee.com/acgist/taoyao
|
||||
`);
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(ElementPlus);
|
||||
app.mount("#app");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { defineConfig } from "vite";
|
||||
import fs from "node:fs";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { defineConfig } from "vite";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
export default defineConfig({
|
||||
@@ -9,8 +9,8 @@ export default defineConfig({
|
||||
port: 8443,
|
||||
host: "0.0.0.0",
|
||||
https: {
|
||||
key : fs.readFileSync("src/certs/server.key"),
|
||||
cert: fs.readFileSync("src/certs/server.crt"),
|
||||
key: fs.readFileSync("src/certs/server.key"),
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
|
||||
Reference in New Issue
Block a user