diff --git a/client/public/onebyone/README.md b/client/public/README.md similarity index 100% rename from client/public/onebyone/README.md rename to client/public/README.md diff --git a/client/public/bidirectional/css/style.css b/client/public/bidirectional/css/style.css deleted file mode 100644 index b5617d6..0000000 --- a/client/public/bidirectional/css/style.css +++ /dev/null @@ -1,54 +0,0 @@ -div#select, div#resolution { - margin: 1em; -} - -button { - margin: 0 20px 5px 0; - vertical-align: top; - width: 155px; -} - -div#buttons { - border-top: 1px solid #eee; - border-bottom: 1px solid #eee; - margin: 1em 0 1em 0; - padding: 1em 0 1em 0; -} - -div#local { - margin: 0 20px 0 0; -} - -div#preview { - border-bottom: 1px solid #eee; - margin: 0 0 1em 0; - padding: 0 0 0.5em 0; -} - -div#preview>div { - display: inline-block; - vertical-align: top; - width: calc(50% - 20px); -} - -div#connectionId { - margin: 1em; -} - -h2 { - margin: 0 0 0.5em 0; -} - -textarea { - color: #444; - font-size: 0.9em; - font-weight: 300; - width: calc(20% - 10px); - height: 1.3em; - line-height: 1.3; - vertical-align: middle; -} - -video { - height: 225px; -} \ No newline at end of file diff --git a/client/public/bidirectional/index.html b/client/public/bidirectional/index.html deleted file mode 100644 index 84dad5e..0000000 --- a/client/public/bidirectional/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - Bidirectional Sample - - - -
-

Bidirectional Sample

- - - -
- - - - -
- -
- -
-
- - -
- -
- - - -
- -
-
-

Local

- -
-
-
-

Remote

- -
-
-
- -
- Connection ID: - -
-
- Codec preferences: - -
- -

For more information about Bidirectional sample, see Bidirectional - sample document page.

- -
- -
- View source on GitHub -
-
- - - - - - - - - - diff --git a/client/public/bidirectional/js/main.js b/client/public/bidirectional/js/main.js deleted file mode 100644 index 2e4df80..0000000 --- a/client/public/bidirectional/js/main.js +++ /dev/null @@ -1,382 +0,0 @@ -/** - * 双向视频通话应用主文件 - * 负责初始化视频设备、建立WebRTC连接、处理信令和显示视频流 - */ - -// 导入必要的模块 -import { SendVideo } from "./sendvideo.js"; // 视频发送和接收处理 -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; // 服务器配置和RTC配置 -import { createDisplayStringArray } from "../../js/stats.js"; // 统计信息处理 -import { RenderStreaming } from "../../module/renderstreaming.js"; // WebRTC连接管理 -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; // 信令管理 - -// 默认视频流尺寸 -const defaultStreamWidth = 1280; -const defaultStreamHeight = 720; - -// 预定义的视频分辨率列表 -const streamSizeList = - [ - { width: 640, height: 360 }, // 标清 - { width: 1280, height: 720 }, // 高清 - { width: 1920, height: 1080 }, // 全高清 - { width: 2560, height: 1440 }, // 2K - { width: 3840, height: 2160 }, // 4K - { width: 360, height: 640 }, // 竖屏标清 - { width: 720, height: 1280 }, // 竖屏高清 - { width: 1080, height: 1920 }, // 竖屏全高清 - { width: 1440, height: 2560 }, // 竖屏2K - { width: 2160, height: 3840 }, // 竖屏4K - ]; - -// DOM元素引用 -const localVideo = document.getElementById('localVideo'); // 本地视频元素 -const remoteVideo = document.getElementById('remoteVideo'); // 远程视频元素 -const localVideoStatsDiv = document.getElementById('localVideoStats'); // 本地视频统计信息 -const remoteVideoStatsDiv = document.getElementById('remoteVideoStats'); // 远程视频统计信息 -const textForConnectionId = document.getElementById('textForConnectionId'); // 连接ID输入框 -textForConnectionId.value = getRandom(); // 生成随机连接ID -const videoSelect = document.querySelector('select#videoSource'); // 视频设备选择 -const audioSelect = document.querySelector('select#audioSource'); // 音频设备选择 -const videoResolutionSelect = document.querySelector('select#videoResolution'); // 视频分辨率选择 -const cameraWidthInput = document.querySelector('input#cameraWidth'); // 自定义宽度输入 -const cameraHeightInput = document.querySelector('input#cameraHeight'); // 自定义高度输入 - -// 编解码器偏好设置 -const codecPreferences = document.getElementById('codecPreferences'); -// 检查浏览器是否支持设置编解码器偏好 -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); // 消息显示区域 -messageDiv.style.display = 'none'; // 初始隐藏消息区域 - -let useCustomResolution = false; // 是否使用自定义分辨率 - -// 初始化输入选择和编解码器选择 -setUpInputSelect(); -showCodecSelect(); - -/** @type {SendVideo} */ -let sendVideo = new SendVideo(localVideo, remoteVideo); // 视频处理实例 -/** @type {RenderStreaming} */ -let renderstreaming; // WebRTC连接管理实例 -let useWebSocket; // 是否使用WebSocket信令 -let connectionId; // 连接ID - -// 按钮事件绑定 -const startButton = document.getElementById('startVideoButton'); -startButton.addEventListener('click', startVideo); // 启动视频按钮 -const setupButton = document.getElementById('setUpButton'); -setupButton.addEventListener('click', setUp); // 设置连接按钮 -const hangUpButton = document.getElementById('hangUpButton'); -hangUpButton.addEventListener('click', hangUp); // 挂断按钮 - -// 页面卸载前清理 -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); // 停止WebRTC连接 -}, true); - -// 初始化配置 -setupConfig(); - -/** - * 初始化服务器配置 - * @async - * @returns {Promise} - */ -async function setupConfig() { - const res = await getServerConfig(); // 获取服务器配置 - useWebSocket = res.useWebSocket; // 设置是否使用WebSocket - showWarningIfNeeded(res.startupMode); // 显示启动模式警告 -} - -/** - * 根据启动模式显示警告信息 - * @param {string} startupMode - 启动模式,可能的值包括"public"和"private" - */ -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "public") { - warningDiv.innerHTML = "

Warning

This sample is not working on Public Mode."; - warningDiv.hidden = false; - } -} - -/** - * 启动本地视频 - * @async - * @returns {Promise} - */ -async function startVideo() { - // 禁用相关输入控件 - videoSelect.disabled = true; - audioSelect.disabled = true; - videoResolutionSelect.disabled = true; - cameraWidthInput.disabled = true; - cameraHeightInput.disabled = true; - startButton.disabled = true; - - let width = 0; - let height = 0; - - // 根据选择的分辨率设置视频尺寸 - if (useCustomResolution) { - width = cameraWidthInput.value ? cameraWidthInput.value : defaultStreamWidth; - height = cameraHeightInput.value ? cameraHeightInput.value : defaultStreamHeight; - } else { - const size = streamSizeList[videoResolutionSelect.value]; - width = size.width; - height = size.height; - } - - // 启动本地视频 - await sendVideo.startLocalVideo(videoSelect.value, audioSelect.value, width, height); - - // 启用设置按钮 - setupButton.disabled = false; -} - -/** - * 设置WebRTC连接 - * @async - * @returns {Promise} - */ -async function setUp() { - setupButton.disabled = true; // 禁用设置按钮 - hangUpButton.disabled = false; // 启用挂断按钮 - connectionId = textForConnectionId.value; // 获取连接ID - codecPreferences.disabled = true; // 禁用编解码器选择 - - // 创建信令实例 - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); // 获取RTC配置 - renderstreaming = new RenderStreaming(signaling, config); // 创建WebRTC连接管理实例 - - // 连接建立回调 - renderstreaming.onConnect = () => { - const tracks = sendVideo.getLocalTracks(); // 获取本地媒体轨道 - for (const track of tracks) { - renderstreaming.addTransceiver(track, { direction: 'sendonly' }); // 添加发送轨道 - } - setCodecPreferences(); // 设置编解码器偏好 - showStatsMessage(); // 显示统计信息 - }; - - // 连接断开回调 - renderstreaming.onDisconnect = () => { - hangUp(); // 挂断连接 - }; - - // 轨道事件回调 - renderstreaming.onTrackEvent = (data) => { - const direction = data.transceiver.direction; - if (direction == "sendrecv" || direction == "recvonly") { - sendVideo.addRemoteTrack(data.track); // 添加远程轨道 - } - }; - - // 启动WebRTC连接 - await renderstreaming.start(); - await renderstreaming.createConnection(connectionId); - -} - -/** - * 设置编解码器偏好 - */ -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - - // 获取视频收发器并设置编解码器偏好 - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -/** - * 挂断WebRTC连接 - * @async - * @returns {Promise} - */ -async function hangUp() { - clearStatsMessage(); // 清除统计信息 - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - hangUpButton.disabled = true; // 禁用挂断按钮 - setupButton.disabled = false; // 启用设置按钮 - - // 删除连接并停止WebRTC - await renderstreaming.deleteConnection(); - await renderstreaming.stop(); - renderstreaming = null; - remoteVideo.srcObject = null; // 清除远程视频源 - - textForConnectionId.value = getRandom(); // 生成新的随机连接ID - connectionId = null; - - // 启用编解码器选择 - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } -} - -/** - * 生成随机连接ID - * @returns {string} 5位随机数字字符串 - */ -function getRandom() { - const max = 99999; - const length = String(max).length; - const number = Math.floor(Math.random() * max); - return (Array(length).join('0') + number).slice(-length); // 补零确保5位 -} - -/** - * 设置输入选择控件 - * @async - * @returns {Promise} - */ -async function setUpInputSelect() { - // 获取媒体设备列表 - const deviceInfos = await navigator.mediaDevices.enumerateDevices(); - - // 填充视频设备选择 - for (let i = 0; i !== deviceInfos.length; ++i) { - const deviceInfo = deviceInfos[i]; - if (deviceInfo.kind === 'videoinput') { - const option = document.createElement('option'); - option.value = deviceInfo.deviceId; - option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`; - videoSelect.appendChild(option); - } else if (deviceInfo.kind === 'audioinput') { - // 填充音频设备选择 - const option = document.createElement('option'); - option.value = deviceInfo.deviceId; - option.text = deviceInfo.label || `mic ${audioSelect.length + 1}`; - audioSelect.appendChild(option); - } - } - - // 填充视频分辨率选择 - for (let i = 0; i < streamSizeList.length; i++) { - const streamSize = streamSizeList[i]; - const option = document.createElement('option'); - option.value = i; - option.text = `${streamSize.width} x ${streamSize.height}`; - videoResolutionSelect.appendChild(option); - } - - // 添加自定义分辨率选项 - const option = document.createElement('option'); - option.value = streamSizeList.length; - option.text = 'Custom'; - videoResolutionSelect.appendChild(option); - videoResolutionSelect.value = 1; // 默认选择1280 x 720 - - // 分辨率选择变化事件 - videoResolutionSelect.addEventListener('change', (event) => { - const isCustom = event.target.value >= streamSizeList.length; - cameraWidthInput.disabled = !isCustom; - cameraHeightInput.disabled = !isCustom; - useCustomResolution = isCustom; - }); -} - -/** - * 显示编解码器选择 - */ -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - // 获取视频编解码器能力 - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - // 跳过冗余和FEC编解码器 - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -// 统计信息相关变量 -let lastStats; // 上次统计信息 -let intervalId; // 统计信息更新间隔ID - -/** - * 显示统计信息 - */ -function showStatsMessage() { - // 每秒更新一次统计信息 - intervalId = setInterval(async () => { - // 显示本地视频分辨率 - if (localVideo.videoWidth) { - localVideoStatsDiv.innerHTML = `Sending resolution: ${localVideo.videoWidth} x ${localVideo.videoHeight} px`; - } - // 显示远程视频分辨率 - if (remoteVideo.videoWidth) { - remoteVideoStatsDiv.innerHTML = `Receiving resolution: ${remoteVideo.videoWidth} x ${remoteVideo.videoHeight} px`; - } - - if (renderstreaming == null || connectionId == null) { - return; - } - - // 获取WebRTC统计信息 - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - // 创建统计信息显示数组 - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
'); - } - lastStats = stats; - }, 1000); -} - -/** - * 清除统计信息 - */ -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); // 清除定时器 - } - lastStats = null; - intervalId = null; - localVideoStatsDiv.innerHTML = ''; - remoteVideoStatsDiv.innerHTML = ''; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} diff --git a/client/public/bidirectional/js/sendvideo.js b/client/public/bidirectional/js/sendvideo.js deleted file mode 100644 index 8cea080..0000000 --- a/client/public/bidirectional/js/sendvideo.js +++ /dev/null @@ -1,53 +0,0 @@ -import * as Logger from "../../module/logger.js"; - -export class SendVideo { - constructor(localVideoElement, remoteVideoElement) { - this.localVideo = localVideoElement; - this.remoteVideo = remoteVideoElement; - } - - /** - * @param {MediaTrackConstraints} videoSource - * @param {MediaTrackConstraints} audioSource - * @param {number} videoWidth - * @param {number} videoHeight - */ - async startLocalVideo(videoSource, audioSource, videoWidth, videoHeight) { - try { - const constraints = { - video: { deviceId: videoSource ? { exact: videoSource } : undefined }, - audio: { deviceId: audioSource ? { exact: audioSource } : undefined } - }; - - if (videoWidth != null || videoWidth != 0) { - constraints.video.width = videoWidth; - } - if (videoHeight != null || videoHeight != 0) { - constraints.video.height = videoHeight; - } - - const localStream = await navigator.mediaDevices.getUserMedia(constraints); - this.localVideo.srcObject = localStream; - await this.localVideo.play(); - } catch (err) { - Logger.error(`mediaDevice.getUserMedia() error:${err}`); - } - } - - /** - * @returns {MediaStreamTrack[]} - */ - getLocalTracks() { - return this.localVideo.srcObject.getTracks(); - } - - /** - * @param {MediaStreamTrack} track - */ - addRemoteTrack(track) { - if (this.remoteVideo.srcObject == null) { - this.remoteVideo.srcObject = new MediaStream(); - } - this.remoteVideo.srcObject.addTrack(track); - } -} diff --git a/client/public/onebyone/chatmessage.js b/client/public/chatmessage.js similarity index 100% rename from client/public/onebyone/chatmessage.js rename to client/public/chatmessage.js diff --git a/client/public/onebyone/code-structure.md b/client/public/code-structure.md similarity index 100% rename from client/public/onebyone/code-structure.md rename to client/public/code-structure.md diff --git a/client/public/onebyone/connect/connect.html b/client/public/connect/connect.html similarity index 100% rename from client/public/onebyone/connect/connect.html rename to client/public/connect/connect.html diff --git a/client/public/onebyone/connect/connect.js b/client/public/connect/connect.js similarity index 100% rename from client/public/onebyone/connect/connect.js rename to client/public/connect/connect.js diff --git a/client/public/onebyone/connectview.js b/client/public/connectview.js similarity index 100% rename from client/public/onebyone/connectview.js rename to client/public/connectview.js diff --git a/client/public/css/main.css b/client/public/css/main.css deleted file mode 100644 index 28f66a2..0000000 --- a/client/public/css/main.css +++ /dev/null @@ -1,147 +0,0 @@ -h1 { - border-bottom: 1px solid #ccc; - font-weight: 500; - margin: 0 0 0.8em 0; - padding: 0 0 0.2em 0; -} - -h4 { - margin: 0; - padding: 0 0 0.2em 0; -} - -body { - font-family: 'Roboto', sans-serif; - font-weight: 300; - margin: 0; - padding: 1em; - word-break: break-word; -} - -button { - margin: 20px 10px 0 0; - width: 130px; -} - -button#gather { - display: block; -} - -section { - border-bottom: 1px solid #eee; - margin: 0 0 1.5em 0; - padding: 0 0 1.5em 0; -} - -section#iceServers label { - display: inline-block; - width: 150px; -} - -section#iceServers input { - margin: 0 0 10px; - width: 260px; -} - -select { - margin: 0 1em 1em 0; - position: relative; - top: -1px; -} - -select#servers { - font-size: 1em; - padding: 5px; - width: 420px; -} - -section:last-child { - border-bottom: none; - margin: 0; - padding: 0; -} - -div#container { - margin: 0 auto 0 auto; - max-width: 60em; - padding: 1em 1.5em 1.3em 1.5em; -} - -code { - padding: 0.1em 0.25em; - color: #444; - background-color: #e7edf3; - border-radius: 3px; - border: solid 1px #d6dde4; - font-weight: 400; -} - -p { - color: #444; - font-weight: 300; -} - -p#data { - border-top: 1px dotted #666; - line-height: 1.3em; - max-height: 1000px; - overflow-y: auto; - padding: 1em 0 0 0; -} - -p.borderBelow { - border-bottom: 1px solid #aaa; - padding: 0 0 20px 0; -} - -video { - background: #222; - margin: 0 0 20px 0; - --width: 100%; - width: var(--width); - height: calc(var(--width) * 0.75); -} - -div#warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; - padding: 1em; - border: 1px solid transparent; -} - -div.box { - margin: 1em; -} - -div#message { - border-top: 1px solid #666; - margin: 1em; - padding: 1em; -} - -@media screen and (max-width: 650px) { - .highlight { - font-size: 1em; - margin: 0 0 20px 0; - padding: 0.2em 1em; - } - h1 { - font-size: 24px; - } -} - -@media screen and (max-width: 550px) { - button:active { - background-color: darkRed; - } - h1 { - font-size: 22px; - } -} - -@media screen and (max-width: 450px) { - h1 { - font-size: 20px; - } -} \ No newline at end of file diff --git a/client/public/onebyone/css/style.css b/client/public/css/style.css similarity index 100% rename from client/public/onebyone/css/style.css rename to client/public/css/style.css diff --git a/client/public/onebyone/endcall/endcall.html b/client/public/endcall/endcall.html similarity index 100% rename from client/public/onebyone/endcall/endcall.html rename to client/public/endcall/endcall.html diff --git a/client/public/onebyone/endcall/endcall.js b/client/public/endcall/endcall.js similarity index 100% rename from client/public/onebyone/endcall/endcall.js rename to client/public/endcall/endcall.js diff --git a/client/public/images/head/三花猫.png b/client/public/images/head/三花猫.png new file mode 100644 index 0000000..4377794 Binary files /dev/null and b/client/public/images/head/三花猫.png differ diff --git a/client/public/images/head/仓鼠.png b/client/public/images/head/仓鼠.png new file mode 100644 index 0000000..6c13702 Binary files /dev/null and b/client/public/images/head/仓鼠.png differ diff --git a/client/public/images/head/可达鸭.png b/client/public/images/head/可达鸭.png new file mode 100644 index 0000000..e4f593d Binary files /dev/null and b/client/public/images/head/可达鸭.png differ diff --git a/client/public/images/head/哈士奇.png b/client/public/images/head/哈士奇.png new file mode 100644 index 0000000..33bb347 Binary files /dev/null and b/client/public/images/head/哈士奇.png differ diff --git a/client/public/images/head/奶牛猫.png b/client/public/images/head/奶牛猫.png new file mode 100644 index 0000000..a44d8b1 Binary files /dev/null and b/client/public/images/head/奶牛猫.png differ diff --git a/client/public/images/head/布偶猫.png b/client/public/images/head/布偶猫.png new file mode 100644 index 0000000..84f0646 Binary files /dev/null and b/client/public/images/head/布偶猫.png differ diff --git a/client/public/images/head/无毛猫.png b/client/public/images/head/无毛猫.png new file mode 100644 index 0000000..d7e88ac Binary files /dev/null and b/client/public/images/head/无毛猫.png differ diff --git a/client/public/images/head/暹罗猫.png b/client/public/images/head/暹罗猫.png new file mode 100644 index 0000000..4e74ec0 Binary files /dev/null and b/client/public/images/head/暹罗猫.png differ diff --git a/client/public/images/head/柯基.png b/client/public/images/head/柯基.png new file mode 100644 index 0000000..6941df9 Binary files /dev/null and b/client/public/images/head/柯基.png differ diff --git a/client/public/images/head/柴犬.png b/client/public/images/head/柴犬.png new file mode 100644 index 0000000..107604f Binary files /dev/null and b/client/public/images/head/柴犬.png differ diff --git a/client/public/images/head/橘猫.png b/client/public/images/head/橘猫.png new file mode 100644 index 0000000..b3253f5 Binary files /dev/null and b/client/public/images/head/橘猫.png differ diff --git a/client/public/images/head/法斗.png b/client/public/images/head/法斗.png new file mode 100644 index 0000000..e82e181 Binary files /dev/null and b/client/public/images/head/法斗.png differ diff --git a/client/public/images/head/田园犬.png b/client/public/images/head/田园犬.png new file mode 100644 index 0000000..2de3a0a Binary files /dev/null and b/client/public/images/head/田园犬.png differ diff --git a/client/public/images/head/白猫.png b/client/public/images/head/白猫.png new file mode 100644 index 0000000..27b6667 Binary files /dev/null and b/client/public/images/head/白猫.png differ diff --git a/client/public/images/head/羊.png b/client/public/images/head/羊.png new file mode 100644 index 0000000..b990a75 Binary files /dev/null and b/client/public/images/head/羊.png differ diff --git a/client/public/images/head/腊肠犬.png b/client/public/images/head/腊肠犬.png new file mode 100644 index 0000000..9477354 Binary files /dev/null and b/client/public/images/head/腊肠犬.png differ diff --git a/client/public/images/head/荷兰猪.png b/client/public/images/head/荷兰猪.png new file mode 100644 index 0000000..f1b676e Binary files /dev/null and b/client/public/images/head/荷兰猪.png differ diff --git a/client/public/images/head/蓝猫.png b/client/public/images/head/蓝猫.png new file mode 100644 index 0000000..6c498e4 Binary files /dev/null and b/client/public/images/head/蓝猫.png differ diff --git a/client/public/images/head/藏獒.png b/client/public/images/head/藏獒.png new file mode 100644 index 0000000..3a04b3a Binary files /dev/null and b/client/public/images/head/藏獒.png differ diff --git a/client/public/images/head/边牧.png b/client/public/images/head/边牧.png new file mode 100644 index 0000000..6ac9a02 Binary files /dev/null and b/client/public/images/head/边牧.png differ diff --git a/client/public/images/head/金毛.png b/client/public/images/head/金毛.png new file mode 100644 index 0000000..ef983f0 Binary files /dev/null and b/client/public/images/head/金毛.png differ diff --git a/client/public/images/head/黑猫.png b/client/public/images/head/黑猫.png new file mode 100644 index 0000000..613eea9 Binary files /dev/null and b/client/public/images/head/黑猫.png differ diff --git a/client/public/index.html b/client/public/index.html index b71b437..f6c9da4 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -1,77 +1,731 @@ + + + - - - - Unity Render Streaming Samples + + + VideoCall - 一对一视频通话 + + + - -
-

Unity Render Streaming Samples

+ + +
+ +
+ -
-

These are WebClient samples for use with Unity Render - Streaming.

-
+ + +
-
-

Server Configuration

-
-
+ +
+
+
+ +
+

VideoCall

+

一对一视频通话

-
-

ICE servers

- -
- - -
-
- - -
-
- - -
-
- - - -
-
+
+
+ + +
+

+ 连接ID是用于建立点对点通话的唯一标识,由发起方生成并分享给接收方。 +

+
-
-

Receiver Sample

-

This is a sample for receiving video / audio from Unity.

-

It can be used in combination with the Broadcast scene of Unity Render Streaming.

-
+
+ + +
-
-

Bidirectional Sample

-

This is a sample for sending and receiving video in both directions.

-

It can be used in combination with the Bidirectional scene of Unity Render Streaming.

-

The WebApp must be running in Private mode.

-
+ + -
-

Multiplay Sample

-

This sample connects as a Guest in the Multiplay scene of Unity Render Streaming.

-
+ + -
-

VideoPlayer Sample

-

This is a sample to receive the camera image rendered on Unity. You can operate the camera in Unity from the - browser.

-

It can be used in combination with the WebBrowserInput scene of Unity Render Streaming.

-

The WebApp must be running in Public mode.

-
+ + + +
+ + 未连接 +
+
+
+
+ + + + + +
+ + 通知内容 +
+ + + + + + + + + + -
- View source on GitHub -
-
- + + diff --git a/client/public/onebyone/knowledge-graph.md b/client/public/knowledge-graph.md similarity index 100% rename from client/public/onebyone/knowledge-graph.md rename to client/public/knowledge-graph.md diff --git a/client/public/onebyone/main.js b/client/public/main.js similarity index 100% rename from client/public/onebyone/main.js rename to client/public/main.js diff --git a/client/public/onebyone/models.js b/client/public/models.js similarity index 100% rename from client/public/onebyone/models.js rename to client/public/models.js diff --git a/client/public/multiplay/css/style.css b/client/public/multiplay/css/style.css deleted file mode 100644 index 73ce19f..0000000 --- a/client/public/multiplay/css/style.css +++ /dev/null @@ -1,99 +0,0 @@ -body { - margin: 0px; -} - -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#VideoThumbnail { - position: absolute; - top: 0; - left: 0; - width: 30%; - height: 30%; -} - -#greenButton { - position: absolute; - bottom: 10px; - left: 10px; - width: 160px; - background-color: #4CAF50; - /* Green */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#blueButton { - position: absolute; - bottom: 10px; - left: 180px; - width: 160px; - background-color: #447FAF; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#orangeButton { - position: absolute; - bottom: 10px; - left: 350px; - width: 160px; - background-color: #FF7700; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} \ No newline at end of file diff --git a/client/public/multiplay/index.html b/client/public/multiplay/index.html deleted file mode 100644 index 7cbf3d5..0000000 --- a/client/public/multiplay/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - Multiplay Sample - - - - -
-

Multiplay Sample

- - - -
- -
- Codec preferences: - -
- -
- Lock Cursor to Player: - -
- -

- For more information about sample, see Multiplay sample document page. -

- -
- -
- View source on GitHub -
-
- - - - - - - - - diff --git a/client/public/multiplay/js/main.js b/client/public/multiplay/js/main.js deleted file mode 100644 index b9f147c..0000000 --- a/client/public/multiplay/js/main.js +++ /dev/null @@ -1,203 +0,0 @@ -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; -import { createDisplayStringArray } from "../../js/stats.js"; -import { VideoPlayer } from "../../js/videoplayer.js"; -import { RenderStreaming } from "../../module/renderstreaming.js"; -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; - -/** @enum {number} */ -const ActionType = { - ChangeLabel: 0 -}; - -/** @type {Element} */ -let playButton; -/** @type {RenderStreaming} */ -let renderstreaming; -/** @type {boolean} */ -let useWebSocket; -/** @type {RTCDataChannel} */ -let multiplayChannel; - -const codecPreferences = document.getElementById('codecPreferences'); -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); -messageDiv.style.display = 'none'; - -const playerDiv = document.getElementById('player'); -const lockMouseCheck = document.getElementById('lockMouseCheck'); -const videoPlayer = new VideoPlayer(); - -setup(); - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showCodecSelect(); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

Warning

This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - const elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = '../../images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - playButton.style.display = 'none'; - - // add video player - videoPlayer.createPlayer(playerDiv, lockMouseCheck); - setupRenderStreaming(); -} - -async function setupRenderStreaming() { - codecPreferences.disabled = true; - - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); - renderstreaming = new RenderStreaming(signaling, config); - renderstreaming.onConnect = onConnect; - renderstreaming.onDisconnect = onDisconnect; - renderstreaming.onTrackEvent = (data) => videoPlayer.addTrack(data.track); - renderstreaming.onGotOffer = setCodecPreferences; - - await renderstreaming.start(); - await renderstreaming.createConnection(); -} - -function onConnect() { - const channel = renderstreaming.createDataChannel("input"); - videoPlayer.setupInput(channel); - multiplayChannel = renderstreaming.createDataChannel("multiplay"); - multiplayChannel.onopen = onOpenMultiplayChannel; - showStatsMessage(); -} - -async function onOpenMultiplayChannel() { - await new Promise(resolve => setTimeout(resolve, 100)); - const num = Math.floor(Math.random() * 100000); - const json = JSON.stringify({ type: ActionType.ChangeLabel, argument: String(num) }); - multiplayChannel.send(json); -} - -async function onDisconnect(connectionId) { - clearStatsMessage(); - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - await renderstreaming.stop(); - renderstreaming = null; - multiplayChannel = null; - videoPlayer.deletePlayer(); - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } - showPlayButton(); -} - -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -/** @type {RTCStatsReport} */ -let lastStats; -/** @type {number} */ -let intervalId; - -function showStatsMessage() { - intervalId = setInterval(async () => { - if (renderstreaming == null) { - return; - } - - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
'); - } - lastStats = stats; - }, 1000); -} - -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); - } - lastStats = null; - intervalId = null; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} diff --git a/client/public/onebyone/index.html b/client/public/onebyone/index.html deleted file mode 100644 index f6c9da4..0000000 --- a/client/public/onebyone/index.html +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - - VideoCall - 一对一视频通话 - - - - - - - -
- -
- - - - -
- - -
-
-
- -
-

VideoCall

-

一对一视频通话

- -
-
- - -
-

- 连接ID是用于建立点对点通话的唯一标识,由发起方生成并分享给接收方。 -

-
- -
- - -
- - - - - - - - - - -
- - 未连接 -
-
-
-
- - - - - -
- - 通知内容 -
- - - - - - - - - - - - - - - diff --git a/client/public/receiver/css/style.css b/client/public/receiver/css/style.css deleted file mode 100644 index 4248609..0000000 --- a/client/public/receiver/css/style.css +++ /dev/null @@ -1,43 +0,0 @@ -body { - margin: 0px; -} - -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} \ No newline at end of file diff --git a/client/public/receiver/index.html b/client/public/receiver/index.html deleted file mode 100644 index 56b281b..0000000 --- a/client/public/receiver/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - Receiver Sample - - - - -
-

Receiver Sample

- - - -
- -
- Codec preferences: - -
- -
- Lock Cursor to Player: - -
- -

- For more information about sample, see - Broadcast sample document page. -

- -
- -
- View source on GitHub -
-
- - - - - - - - - diff --git a/client/public/receiver/js/main.js b/client/public/receiver/js/main.js deleted file mode 100644 index ba41f78..0000000 --- a/client/public/receiver/js/main.js +++ /dev/null @@ -1,186 +0,0 @@ -import { getServerConfig, getRTCConfiguration } from "../../js/config.js"; -import { createDisplayStringArray } from "../../js/stats.js"; -import { VideoPlayer } from "../../js/videoplayer.js"; -import { RenderStreaming } from "../../module/renderstreaming.js"; -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; - -/** @type {Element} */ -let playButton; -/** @type {RenderStreaming} */ -let renderstreaming; -/** @type {boolean} */ -let useWebSocket; - -const codecPreferences = document.getElementById('codecPreferences'); -const supportsSetCodecPreferences = window.RTCRtpTransceiver && - 'setCodecPreferences' in window.RTCRtpTransceiver.prototype; -const messageDiv = document.getElementById('message'); -messageDiv.style.display = 'none'; - -const playerDiv = document.getElementById('player'); -const lockMouseCheck = document.getElementById('lockMouseCheck'); -const videoPlayer = new VideoPlayer(); - -setup(); - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - if(!renderstreaming) - return; - await renderstreaming.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showCodecSelect(); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

Warning

This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - const elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = '../../images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - playButton.style.display = 'none'; - - // add video player - videoPlayer.createPlayer(playerDiv, lockMouseCheck); - setupRenderStreaming(); -} - -async function setupRenderStreaming() { - codecPreferences.disabled = true; - - const signaling = useWebSocket ? new WebSocketSignaling() : new Signaling(); - const config = getRTCConfiguration(); - renderstreaming = new RenderStreaming(signaling, config); - renderstreaming.onConnect = onConnect; - renderstreaming.onDisconnect = onDisconnect; - renderstreaming.onTrackEvent = (data) => videoPlayer.addTrack(data.track); - renderstreaming.onGotOffer = setCodecPreferences; - - await renderstreaming.start(); - await renderstreaming.createConnection(); -} - -function onConnect() { - const channel = renderstreaming.createDataChannel("input"); - videoPlayer.setupInput(channel); - showStatsMessage(); -} - -async function onDisconnect(connectionId) { - clearStatsMessage(); - messageDiv.style.display = 'block'; - messageDiv.innerText = `Disconnect peer on ${connectionId}.`; - - await renderstreaming.stop(); - renderstreaming = null; - videoPlayer.deletePlayer(); - if (supportsSetCodecPreferences) { - codecPreferences.disabled = false; - } - showPlayButton(); -} - -function setCodecPreferences() { - /** @type {RTCRtpCodecCapability[] | null} */ - let selectedCodecs = null; - if (supportsSetCodecPreferences) { - const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex]; - if (preferredCodec.value !== '') { - const [mimeType, sdpFmtpLine] = preferredCodec.value.split(' '); - const { codecs } = RTCRtpSender.getCapabilities('video'); - const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine); - const selectCodec = codecs[selectedCodecIndex]; - selectedCodecs = [selectCodec]; - } - } - - if (selectedCodecs == null) { - return; - } - const transceivers = renderstreaming.getTransceivers().filter(t => t.receiver.track.kind == "video"); - if (transceivers && transceivers.length > 0) { - transceivers.forEach(t => t.setCodecPreferences(selectedCodecs)); - } -} - -function showCodecSelect() { - if (!supportsSetCodecPreferences) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = `Current Browser does not support RTCRtpTransceiver.setCodecPreferences.`; - return; - } - - const codecs = RTCRtpSender.getCapabilities('video').codecs; - codecs.forEach(codec => { - if (['video/red', 'video/ulpfec', 'video/rtx'].includes(codec.mimeType)) { - return; - } - const option = document.createElement('option'); - option.value = (codec.mimeType + ' ' + (codec.sdpFmtpLine || '')).trim(); - option.innerText = option.value; - codecPreferences.appendChild(option); - }); - codecPreferences.disabled = false; -} - -/** @type {RTCStatsReport} */ -let lastStats; -/** @type {number} */ -let intervalId; - -function showStatsMessage() { - intervalId = setInterval(async () => { - if (renderstreaming == null) { - return; - } - - const stats = await renderstreaming.getStats(); - if (stats == null) { - return; - } - - const array = createDisplayStringArray(stats, lastStats); - if (array.length) { - messageDiv.style.display = 'block'; - messageDiv.innerHTML = array.join('
'); - } - lastStats = stats; - }, 1000); -} - -function clearStatsMessage() { - if (intervalId) { - clearInterval(intervalId); - } - lastStats = null; - intervalId = null; - messageDiv.style.display = 'none'; - messageDiv.innerHTML = ''; -} \ No newline at end of file diff --git a/client/public/onebyone/renderer.js b/client/public/renderer.js similarity index 100% rename from client/public/onebyone/renderer.js rename to client/public/renderer.js diff --git a/client/public/onebyone/store.js b/client/public/store.js similarity index 100% rename from client/public/onebyone/store.js rename to client/public/store.js diff --git a/client/public/uploads/avatars/user_XPMwGa7W.png b/client/public/uploads/avatars/user_XPMwGa7W.png new file mode 100644 index 0000000..d7e88ac Binary files /dev/null and b/client/public/uploads/avatars/user_XPMwGa7W.png differ diff --git a/client/public/onebyone/utils.js b/client/public/utils.js similarity index 100% rename from client/public/onebyone/utils.js rename to client/public/utils.js diff --git a/client/public/videoplayer/css/style.css b/client/public/videoplayer/css/style.css deleted file mode 100644 index 0efec66..0000000 --- a/client/public/videoplayer/css/style.css +++ /dev/null @@ -1,103 +0,0 @@ - -body { - margin: 0px; -} -button#muteButton { - margin: 5px 0; - width: auto; -} -#player { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - align-items: center; - justify-content: center; - display: flex; - background-color: #323232; -} - -#player:before { - content: ""; - display: block; - padding-top: 66%; -} - -#playButton { - width: 15%; - max-width: 200px; - cursor: pointer; -} - -#Video { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -#VideoThumbnail { - position: absolute; - top: 0; - left: 0; - width: 30%; - height: 30%; -} - -#greenButton { - position: absolute; - bottom: 10px; - left: 10px; - width: 160px; - background-color: #4CAF50; - /* Green */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#blueButton { - position: absolute; - bottom: 10px; - left: 180px; - width: 160px; - background-color: #447FAF; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#orangeButton { - position: absolute; - bottom: 10px; - left: 350px; - width: 160px; - background-color: #FF7700; - /* Blue */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} - -#fullscreenButton { - position: absolute; - top: 25px; - right: 25px; - width: 32px; - height: 32px; -} diff --git a/client/public/videoplayer/images/FullScreen.png b/client/public/videoplayer/images/FullScreen.png deleted file mode 100644 index ba386e6..0000000 Binary files a/client/public/videoplayer/images/FullScreen.png and /dev/null differ diff --git a/client/public/videoplayer/images/Play.png b/client/public/videoplayer/images/Play.png deleted file mode 100644 index 9d8dbd1..0000000 Binary files a/client/public/videoplayer/images/Play.png and /dev/null differ diff --git a/client/public/videoplayer/index.html b/client/public/videoplayer/index.html deleted file mode 100644 index 58dfc6b..0000000 --- a/client/public/videoplayer/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - VideoPlayer Sample - - - - -
-

VideoPlayer Sample

- - - -
- -

For more information about WebBrowserInput sample, see WebBrowserInput - sample document page.

- -
- View source on GitHub -
-
- - - - - - - - - diff --git a/client/public/videoplayer/js/gamepadEvents.js b/client/public/videoplayer/js/gamepadEvents.js deleted file mode 100644 index 7b164ff..0000000 --- a/client/public/videoplayer/js/gamepadEvents.js +++ /dev/null @@ -1,146 +0,0 @@ -import * as Logger from "../../module/logger.js"; - -const _e = 0.09; -const _gameloopInterval = 16.67; //in milliseconds, 60 times a second -var gameloop = null; -var gamepadsPreviousButtonsStates = {}; -var gamepadsPreviousAxesStates = {}; -var gamepadsConnectedTimeStamp = {}; -const _axisOffset = 100; -const _axisMultiplier = 1; -const _axisYInverted = -1; - -class GamepadButtonEvent extends Event { - constructor() { - super(...arguments); - this.index = arguments[1].index; - this.id = arguments[1].id; - this.value = arguments[1].value; - } -} - -class GamepadAxisEvent extends Event { - constructor() { - super(...arguments); - this.index = arguments[1].index; - this.x = arguments[1].x; - this.y = arguments[1].y; - this.id = arguments[1].id; - } -} - -function storePreviousState(gamepad) { - gamepadsPreviousButtonsStates[gamepad.index] = {}; - gamepad.buttons.forEach(function (button, index) { - gamepadsPreviousButtonsStates[gamepad.index][index] = { value: button.value, pressed: button.pressed }; - }); - - gamepadsPreviousAxesStates[gamepad.index] = [gamepad.axes.length]; - for (var index = 0; index < gamepad.axes.length; index++) - gamepadsPreviousAxesStates[gamepad.index][index] = gamepad.axes[index]; -} - -function checkAxes(gamepad, previousGamePad) { - for (var i = 0; i < gamepad.axes.length; i += 2) { - var absX = Math.abs(gamepad.axes[i]); - var absY = Math.abs(gamepad.axes[i + 1]); - var event = null; - if ((absX > _e) || - (absY > _e)) { - - event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: gamepad.axes[i] * _axisMultiplier, y: gamepad.axes[i + 1] * _axisMultiplier * _axisYInverted }); - document.dispatchEvent(event); - } - else { - var previousAbsX = Math.abs(previousGamePad[i]); - var previousAbsY = Math.abs(previousGamePad[i + 1]); - - //have to send if previously was moved - if ((previousAbsX > _e) || - (previousAbsY > _e)) { - event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: 0.0, y: 0.0 }); - document.dispatchEvent(event); - } - } - } -} - -function gameLoop() { - Object.keys(gamepadsPreviousAxesStates).forEach(function (gamepadIndex) { - var gamepad = navigator.webkitGetGamepads ? navigator.webkitGetGamepads()[gamepadIndex] : navigator.getGamepads()[gamepadIndex]; - var previousButtons = gamepadsPreviousButtonsStates[gamepadIndex]; - gamepad.buttons.forEach(function (button, index) { - var buttonStatus = navigator.webkitGetGamepads ? button == 1 : (button.value > 0 || button.pressed == true); - var previousButtonStatus = navigator.webkitGetGamepads ? previousButtons[index].value == 1 : (previousButtons[index].value > 0 || previousButtons[index].pressed == true); - var event; - if (buttonStatus != previousButtonStatus) { - if (buttonStatus) { - event = new GamepadButtonEvent('gamepadButtonDown', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value }); - } - else { - event = new GamepadButtonEvent('gamepadButtonUp', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: 0 }); - } - document.dispatchEvent(event); - } - else if (buttonStatus) { - event = new GamepadButtonEvent('gamepadButtonPressed', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value }); - document.dispatchEvent(event); - } - - }); - checkAxes(gamepad, gamepadsPreviousAxesStates[gamepadIndex]); - storePreviousState(gamepad); - }); -} - -function getCookie(cname) { - var name = cname + "="; - var decodedCookie = decodeURIComponent(document.cookie); - var ca = decodedCookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') { - c = c.substring(1); - } - if (c.indexOf(name) == 0) { - return c.substring(name.length, c.length); - } - } - return ""; -} - -export function gamepadHandler(event, connecting) { - var gamepad = event.gamepad; - - var key = gamepad.id.replace(/\s/g, ''); - var cookieTimeStamp = getCookie(key); - - if (connecting) { - storePreviousState(gamepad); - if (Object.keys(gamepadsPreviousAxesStates).length == 1) { - gameloop = setInterval(gameLoop, _gameloopInterval); - } - - //try to find the timestamp - //need to strip the : from the id - - if (cookieTimeStamp == "") { - document.cookie = key + "=" + gamepad.timestamp; - gamepadsConnectedTimeStamp[gamepad.index] = gamepad.timestamp; - } - else { - gamepadsConnectedTimeStamp[gamepad.index] = cookieTimeStamp; - } - - Logger.log("connected: " + gamepadsConnectedTimeStamp[gamepad.index]); - - } else { - delete gamepadsPreviousAxesStates[gamepad.index]; - delete gamepadsPreviousButtonsStates[gamepad.index]; - if (Object.keys(gamepadsPreviousAxesStates).length == 0) { - clearInterval(gameloop); - gameloop = null; - } - Logger.log("disconnected: " + gamepad.id); - } -} diff --git a/client/public/videoplayer/js/main.js b/client/public/videoplayer/js/main.js deleted file mode 100644 index 4eb8987..0000000 --- a/client/public/videoplayer/js/main.js +++ /dev/null @@ -1,156 +0,0 @@ -import { VideoPlayer } from "./video-player.js"; -import { registerGamepadEvents, registerKeyboardEvents, registerMouseEvents, sendClickEvent } from "./register-events.js"; -import { getServerConfig } from "../../js/config.js"; - -setup(); - -let playButton; -let videoPlayer; -let useWebSocket; - -window.document.oncontextmenu = function () { - return false; // cancel default menu -}; - -window.addEventListener('resize', function () { - videoPlayer.resizeVideo(); -}, true); - -window.addEventListener('beforeunload', async () => { - await videoPlayer.stop(); -}, true); - -async function setup() { - const res = await getServerConfig(); - useWebSocket = res.useWebSocket; - showWarningIfNeeded(res.startupMode); - showPlayButton(); -} - -function showWarningIfNeeded(startupMode) { - const warningDiv = document.getElementById("warning"); - if (startupMode == "private") { - warningDiv.innerHTML = "

Warning

This sample is not working on Private Mode."; - warningDiv.hidden = false; - } -} - -function showPlayButton() { - if (!document.getElementById('playButton')) { - let elementPlayButton = document.createElement('img'); - elementPlayButton.id = 'playButton'; - elementPlayButton.src = 'images/Play.png'; - elementPlayButton.alt = 'Start Streaming'; - playButton = document.getElementById('player').appendChild(elementPlayButton); - playButton.addEventListener('click', onClickPlayButton); - } -} - -function onClickPlayButton() { - - playButton.style.display = 'none'; - - const playerDiv = document.getElementById('player'); - - // add video player - const elementVideo = document.createElement('video'); - elementVideo.id = 'Video'; - elementVideo.style.touchAction = 'none'; - playerDiv.appendChild(elementVideo); - - // add video thumbnail - const elementVideoThumb = document.createElement('video'); - elementVideoThumb.id = 'VideoThumbnail'; - elementVideoThumb.style.touchAction = 'none'; - playerDiv.appendChild(elementVideoThumb); - - setupVideoPlayer([elementVideo, elementVideoThumb]).then(value => videoPlayer = value); - - // add blue button - const elementBlueButton = document.createElement('button'); - elementBlueButton.id = "blueButton"; - elementBlueButton.innerHTML = "Light on"; - playerDiv.appendChild(elementBlueButton); - elementBlueButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 1); - }); - - // add green button - const elementGreenButton = document.createElement('button'); - elementGreenButton.id = "greenButton"; - elementGreenButton.innerHTML = "Light off"; - playerDiv.appendChild(elementGreenButton); - elementGreenButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 2); - }); - - // add orange button - const elementOrangeButton = document.createElement('button'); - elementOrangeButton.id = "orangeButton"; - elementOrangeButton.innerHTML = "Play audio"; - playerDiv.appendChild(elementOrangeButton); - elementOrangeButton.addEventListener("click", function () { - sendClickEvent(videoPlayer, 3); - }); - - // add fullscreen button - const elementFullscreenButton = document.createElement('img'); - elementFullscreenButton.id = 'fullscreenButton'; - elementFullscreenButton.src = 'images/FullScreen.png'; - playerDiv.appendChild(elementFullscreenButton); - elementFullscreenButton.addEventListener("click", function () { - if (!document.fullscreenElement || !document.webkitFullscreenElement) { - if (document.documentElement.requestFullscreen) { - document.documentElement.requestFullscreen(); - } - else if (document.documentElement.webkitRequestFullscreen) { - document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - if (playerDiv.style.position == "absolute") { - playerDiv.style.position = "relative"; - } else { - playerDiv.style.position = "absolute"; - } - } - } - }); - document.addEventListener('webkitfullscreenchange', onFullscreenChange); - document.addEventListener('fullscreenchange', onFullscreenChange); - - function onFullscreenChange() { - if (document.webkitFullscreenElement || document.fullscreenElement) { - playerDiv.style.position = "absolute"; - elementFullscreenButton.style.display = 'none'; - } - else { - playerDiv.style.position = "relative"; - elementFullscreenButton.style.display = 'block'; - } - } -} - -async function setupVideoPlayer(elements) { - const videoPlayer = new VideoPlayer(elements); - await videoPlayer.setupConnection(useWebSocket); - - videoPlayer.ondisconnect = onDisconnect; - registerGamepadEvents(videoPlayer); - registerKeyboardEvents(videoPlayer); - registerMouseEvents(videoPlayer, elements[0]); - - return videoPlayer; -} - -function onDisconnect() { - const playerDiv = document.getElementById('player'); - clearChildren(playerDiv); - videoPlayer.stop(); - videoPlayer = null; - showPlayButton(); -} - -function clearChildren(element) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } -} diff --git a/client/public/videoplayer/js/register-events.js b/client/public/videoplayer/js/register-events.js deleted file mode 100644 index 4ef129e..0000000 --- a/client/public/videoplayer/js/register-events.js +++ /dev/null @@ -1,307 +0,0 @@ -import { gamepadHandler } from "./gamepadEvents.js"; -import * as Logger from "../../module/logger.js"; -import { Keymap } from "../../module/keymap.js"; - -const InputEvent = { - Keyboard: 0, - Mouse: 1, - MouseWheel: 2, - Touch: 3, - ButtonClick: 4, - Gamepad: 5 -}; - -const KeyboardEventType = { - Up: 0, - Down: 1 -}; - -const GamepadEventType = { - ButtonUp: 0, - ButtonDown: 1, - ButtonPressed: 2, - Axis: 3 -}; - -const PointerPhase = { - None: 0, - Began: 1, - Moved: 2, - Ended: 3, - Canceled: 4, - Stationary: 5 -}; - -let sendGamepadButtonDown = undefined; -let sendGamepadButtonUp = undefined; -let sendGamepadButtonPressed; -let gamepadAxisChange = undefined; -let gamepadConnected = undefined; -let gamepadDisconnected = undefined; - -export function registerGamepadEvents(videoPlayer) { - - const _videoPlayer = videoPlayer; - - sendGamepadButtonDown = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " down"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonDown); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - sendGamepadButtonUp = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " up"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonUp); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - sendGamepadButtonPressed = (e) => { - Logger.log("gamepad id: " + e.id + " button index: " + e.index + " value " + e.value + " pressed"); - let data = new DataView(new ArrayBuffer(19)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.ButtonPressed); - data.setUint8(2, e.index); - data.setFloat64(3, e.value, true); - - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - gamepadAxisChange = (e) => { - Logger.log("gamepad id: " + e.id + " axis: " + e.index + " value " + e.value + " x:" + e.x + " y:" + e.y); - let data = new DataView(new ArrayBuffer(27)); - data.setUint8(0, InputEvent.Gamepad); - data.setUint8(1, GamepadEventType.Axis); - data.setUint8(2, e.index); - data.setFloat64(3, e.x, true); - data.setFloat64(11, e.y, true); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - gamepadConnected = (e) => { gamepadHandler(e, true); }; - gamepadDisconnected = (e) => { gamepadHandler(e, false); }; - - - document.addEventListener("gamepadButtonDown", sendGamepadButtonDown, false); - document.addEventListener("gamepadButtonUp", sendGamepadButtonUp, false); - document.addEventListener("gamepadButtonPressed", sendGamepadButtonPressed, false); - document.addEventListener("gamepadAxis", gamepadAxisChange, false); - - window.addEventListener("gamepadconnected", gamepadConnected, false); - window.addEventListener("gamepaddisconnected", gamepadDisconnected, false); -} - -export function unregisterGamepadEvents() { - - document.removeEventListener("gamepadButtonDown", sendGamepadButtonDown, false); - document.removeEventListener("gamepadButtonUp", sendGamepadButtonUp, false); - document.removeEventListener("gamepadButtonPressed", sendGamepadButtonPressed, false); - document.removeEventListener("gamepadAxis", gamepadAxisChange, false); - - window.removeEventListener("gamepadconnected", gamepadConnected, false); - window.removeEventListener("gamepaddisconnected", gamepadDisconnected, false); - -} - - -let sendKeyUp = undefined; -let sendKeyDown = undefined; - - -export function registerKeyboardEvents(videoPlayer) { - - const _videoPlayer = videoPlayer; - - function sendKey(e, type) { - const key = Keymap[e.code]; - const character = e.key.length === 1 ? e.key.charCodeAt(0) : 0; - Logger.log("key down " + key + ", repeat = " + e.repeat + ", character = " + character); - _videoPlayer && _videoPlayer.sendMsg(new Uint8Array([InputEvent.Keyboard, type, e.repeat, key, character]).buffer); - } - - - sendKeyUp = (e) => { - sendKey(e, KeyboardEventType.Up); - }; - - sendKeyDown = (e) => { - sendKey(e, KeyboardEventType.Down); - }; - - document.addEventListener('keyup', sendKeyUp, false); - document.addEventListener('keydown', sendKeyDown, false); -} - - -export function unregisterKeyboardEvents() { - - //Stop listening to keyboard events - document.removeEventListener('keyup', sendKeyUp, false); - document.removeEventListener('keydown', sendKeyDown, false); -} - - -let sendMouse = undefined; -let sendMouseWheel = undefined; -let sendTouchEnd = undefined; -let sendTouchStart = undefined; -let sendTouchCancel = undefined; -let sendTouchMove = undefined; - - -export function registerMouseEvents(videoPlayer, playerElement) { - - const _videoPlayer = videoPlayer; - - function sendTouch(e, phase) { - const changedTouches = Array.from(e.changedTouches); - const touches = Array.from(e.touches); - const phrases = []; - - for (let i = 0; i < changedTouches.length; i++) { - if (touches.find(function (t) { - return t.identifier === changedTouches[i].identifier; - }) === undefined) { - touches.push(changedTouches[i]); - } - } - - for (let i = 0; i < touches.length; i++) { - touches[i].identifier; - phrases[i] = changedTouches.find( - function (e) { - return e.identifier === touches[i].identifier; - }) === undefined ? PointerPhase.Stationary : phase; - } - - Logger.log("touch phase:" + phase + " length:" + changedTouches.length + " pageX" + changedTouches[0].pageX + ", pageX: " + changedTouches[0].pageY + ", force:" + changedTouches[0].force); - - let data = new DataView(new ArrayBuffer(2 + 13 * touches.length)); - data.setUint8(0, InputEvent.Touch); - data.setUint8(1, touches.length); - let byteOffset = 2; - for (let i = 0; i < touches.length; i++) { - - const scale = _videoPlayer.videoScale; - const originX = _videoPlayer.videoOriginX; - const originY = _videoPlayer.videoOriginY; - - const x = (touches[i].pageX - originX) / scale; - // According to Unity Coordinate system - // const y = (touches[i].pageX - originY) / scale; - const y = _videoPlayer.videoHeight - (touches[i].pageY - originY) / scale; - - data.setInt32(byteOffset, touches[i].identifier, true); - byteOffset += 4; - data.setUint8(byteOffset, phrases[i]); - byteOffset += 1; - data.setInt16(byteOffset, x, true); - byteOffset += 2; - data.setInt16(byteOffset, y, true); - byteOffset += 2; - data.setFloat32(byteOffset, touches[i].force, true); - byteOffset += 4; - } - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - } - - sendTouchMove = (e) => { - sendTouch(e, PointerPhase.Moved); - e.preventDefault(); - }; - - sendTouchStart = (e) => { - sendTouch(e, PointerPhase.Began); - e.preventDefault(); - }; - - sendTouchEnd = (e) => { - sendTouch(e, PointerPhase.Ended); - e.preventDefault(); - }; - - sendTouchCancel = (e) => { - sendTouch(e, PointerPhase.Canceled); - e.preventDefault(); - }; - - sendMouse = (e) => { - const scale = _videoPlayer.videoScale; - const originX = _videoPlayer.videoOriginX; - const originY = _videoPlayer.videoOriginY; - - const x = (e.clientX - originX) / scale; - // According to Unity Coordinate system - // const y = (e.clientY - originY) / scale; - const y = _videoPlayer.videoHeight - (e.clientY - originY) / scale; - - Logger.log("x: " + x + ", y: " + y + ", scale: " + scale + ", originX: " + originX + ", originY: " + originY + " mouse button:" + e.buttons); - let data = new DataView(new ArrayBuffer(6)); - data.setUint8(0, InputEvent.Mouse); - data.setInt16(1, x, true); - data.setInt16(3, y, true); - data.setUint8(5, e.buttons); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - }; - - function sendMouseWheel(e) { - Logger.log("mouse wheel with delta " + e.wheelDelta); - let data = new DataView(new ArrayBuffer(9)); - data.setUint8(0, InputEvent.MouseWheel); - data.setFloat32(1, e.deltaX, true); - data.setFloat32(5, e.deltaY, true); - _videoPlayer && _videoPlayer.sendMsg(data.buffer); - } - - // Listen to mouse events - playerElement.addEventListener('click', sendMouse, false); - playerElement.addEventListener('mousedown', sendMouse, false); - playerElement.addEventListener('mouseup', sendMouse, false); - playerElement.addEventListener('mousemove', sendMouse, false); - playerElement.addEventListener('wheel', sendMouseWheel, false); - - // Listen to touch events based on "Touch Events Level1" TR. - // - // Touch event Level1 https://www.w3.org/TR/touch-events/ - // Touch event Level2 https://w3c.github.io/touch-events/ - // - playerElement.addEventListener('touchend', sendTouchEnd, false); - playerElement.addEventListener('touchstart', sendTouchStart, false); - playerElement.addEventListener('touchcancel', sendTouchCancel, false); - playerElement.addEventListener('touchmove', sendTouchMove, false); -} - - -export function unregisterMouseEvents(playerElement) { - - // Stop listening to mouse events - playerElement.removeEventListener('click', sendMouse, false); - playerElement.removeEventListener('mousedown', sendMouse, false); - playerElement.removeEventListener('mouseup', sendMouse, false); - playerElement.removeEventListener('mousemove', sendMouse, false); - playerElement.removeEventListener('wheel', sendMouseWheel, false); - - // Stop listening to touch events based on "Touch Events Level1" TR. - playerElement.removeEventListener('touchend', sendTouchEnd, false); - playerElement.removeEventListener('touchstart', sendTouchStart, false); - playerElement.removeEventListener('touchcancel', sendTouchCancel, false); - playerElement.removeEventListener('touchmove', sendTouchMove, false); - -} - - -export function sendClickEvent(videoPlayer, elementId) { - let data = new DataView(new ArrayBuffer(3)); - data.setUint8(0, InputEvent.ButtonClick); - data.setInt16(1, elementId, true); - videoPlayer && videoPlayer.sendMsg(data.buffer); -} diff --git a/client/public/videoplayer/js/video-player.js b/client/public/videoplayer/js/video-player.js deleted file mode 100644 index 19bfaca..0000000 --- a/client/public/videoplayer/js/video-player.js +++ /dev/null @@ -1,246 +0,0 @@ -import { Signaling, WebSocketSignaling } from "../../module/signaling.js"; -import Peer from "../../module/peer.js"; -import * as Logger from "../../module/logger.js"; - - -// enum type of event sending from Unity -var UnityEventType = { - SWITCH_VIDEO: 0 -}; - -function uuid4() { - var temp_url = URL.createObjectURL(new Blob()); - var uuid = temp_url.toString(); - URL.revokeObjectURL(temp_url); - return uuid.split(/[:/]/g).pop().toLowerCase(); // remove prefixes -} - -export class VideoPlayer { - constructor(elements) { - const _this = this; - this.pc = null; - this.channel = null; - this.connectionId = null; - - // main video - this.localStream = new MediaStream(); - this.video = elements[0]; - this.video.playsInline = true; - this.video.addEventListener('loadedmetadata', function () { - _this.video.play(); - _this.resizeVideo(); - }, true); - - // secondly video - this.localStream2 = new MediaStream(); - this.videoThumb = elements[1]; - this.videoThumb.playsInline = true; - this.videoThumb.addEventListener('loadedmetadata', function () { - _this.videoThumb.play(); - }, true); - - this.videoTrackList = []; - this.videoTrackIndex = 0; - this.maxVideoTrackLength = 2; - - this.ondisconnect = function () { }; - } - - async setupConnection(useWebSocket) { - const _this = this; - // close current RTCPeerConnection - if (this.pc) { - Logger.log('Close current PeerConnection'); - this.pc.close(); - this.pc = null; - } - - if (useWebSocket) { - this.signaling = new WebSocketSignaling(); - } else { - this.signaling = new Signaling(); - } - - this.connectionId = uuid4(); - - // Create peerConnection with proxy server and set up handlers - this.pc = new Peer(this.connectionId, true); - this.pc.addEventListener('disconnect', () => { - _this.ondisconnect(); - }); - this.pc.addEventListener('trackevent', (e) => { - const data = e.detail; - if (data.track.kind == 'video') { - _this.videoTrackList.push(data.track); - } - if (data.track.kind == 'audio') { - _this.localStream.addTrack(data.track); - } - if (_this.videoTrackList.length == _this.maxVideoTrackLength) { - _this.switchVideo(_this.videoTrackIndex); - } - }); - this.pc.addEventListener('sendoffer', (e) => { - const offer = e.detail; - _this.signaling.sendOffer(offer.connectionId, offer.sdp); - }); - this.pc.addEventListener('sendanswer', (e) => { - const answer = e.detail; - _this.signaling.sendAnswer(answer.connectionId, answer.sdp); - }); - this.pc.addEventListener('sendcandidate', (e) => { - const candidate = e.detail; - _this.signaling.sendCandidate(candidate.connectionId, candidate.candidate, candidate.sdpMid, candidate.sdpMLineIndex); - }); - - this.signaling.addEventListener('disconnect', async (e) => { - const data = e.detail; - if (_this.pc != null && _this.pc.connectionId == data.connectionId) { - _this.ondisconnect(); - } - }); - this.signaling.addEventListener('offer', async (e) => { - const offer = e.detail; - const desc = new RTCSessionDescription({ sdp: offer.sdp, type: "offer" }); - if (_this.pc != null) { - await _this.pc.onGotDescription(offer.connectionId, desc); - } - }); - this.signaling.addEventListener('answer', async (e) => { - const answer = e.detail; - const desc = new RTCSessionDescription({ sdp: answer.sdp, type: "answer" }); - if (_this.pc != null) { - await _this.pc.onGotDescription(answer.connectionId, desc); - } - }); - this.signaling.addEventListener('candidate', async (e) => { - const candidate = e.detail; - const iceCandidate = new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid, sdpMLineIndex: candidate.sdpMLineIndex }); - if (_this.pc != null) { - await _this.pc.onGotCandidate(candidate.connectionId, iceCandidate); - } - }); - - // setup signaling - await this.signaling.start(); - - // Create data channel with proxy server and set up handlers - this.channel = this.pc.createDataChannel(this.connectionId, 'data'); - this.channel.onopen = function () { - Logger.log('Datachannel connected.'); - }; - this.channel.onerror = function (e) { - Logger.log("The error " + e.error.message + " occurred\n while handling data with proxy server."); - }; - this.channel.onclose = function () { - Logger.log('Datachannel disconnected.'); - }; - this.channel.onmessage = async (msg) => { - // receive message from unity and operate message - let data; - // receive message data type is blob only on Firefox - if (navigator.userAgent.indexOf('Firefox') != -1) { - data = await msg.data.arrayBuffer(); - } else { - data = msg.data; - } - const bytes = new Uint8Array(data); - _this.videoTrackIndex = bytes[1]; - switch (bytes[0]) { - case UnityEventType.SWITCH_VIDEO: - _this.switchVideo(_this.videoTrackIndex); - break; - } - }; - } - - resizeVideo() { - const clientRect = this.video.getBoundingClientRect(); - const videoRatio = this.videoWidth / this.videoHeight; - const clientRatio = clientRect.width / clientRect.height; - - this._videoScale = videoRatio > clientRatio ? clientRect.width / this.videoWidth : clientRect.height / this.videoHeight; - const videoOffsetX = videoRatio > clientRatio ? 0 : (clientRect.width - this.videoWidth * this._videoScale) * 0.5; - const videoOffsetY = videoRatio > clientRatio ? (clientRect.height - this.videoHeight * this._videoScale) * 0.5 : 0; - this._videoOriginX = clientRect.left + videoOffsetX; - this._videoOriginY = clientRect.top + videoOffsetY; - } - - // switch streaming destination main video and secondly video - switchVideo(indexVideoTrack) { - this.video.srcObject = this.localStream; - this.videoThumb.srcObject = this.localStream2; - - if (indexVideoTrack == 0) { - this.replaceTrack(this.localStream, this.videoTrackList[0]); - this.replaceTrack(this.localStream2, this.videoTrackList[1]); - } - else { - this.replaceTrack(this.localStream, this.videoTrackList[1]); - this.replaceTrack(this.localStream2, this.videoTrackList[0]); - } - } - - // replace video track related the MediaStream - replaceTrack(stream, newTrack) { - const tracks = stream.getVideoTracks(); - for (const track of tracks) { - if (track.kind == 'video') { - stream.removeTrack(track); - } - } - stream.addTrack(newTrack); - } - - get videoWidth() { - return this.video.videoWidth; - } - - get videoHeight() { - return this.video.videoHeight; - } - - get videoOriginX() { - return this._videoOriginX; - } - - get videoOriginY() { - return this._videoOriginY; - } - - get videoScale() { - return this._videoScale; - } - - sendMsg(msg) { - if (this.channel == null) { - return; - } - switch (this.channel.readyState) { - case 'connecting': - Logger.log('Connection not ready'); - break; - case 'open': - this.channel.send(msg); - break; - case 'closing': - Logger.log('Attempt to sendMsg message while closing'); - break; - case 'closed': - Logger.log('Attempt to sendMsg message while connection closed.'); - break; - } - } - - async stop() { - if (this.signaling) { - await this.signaling.stop(); - this.signaling = null; - } - - if (this.pc) { - this.pc.close(); - this.pc = null; - } - } -} diff --git a/src/class/websockethandler.ts b/src/class/websockethandler.ts index b1e442a..e9ebd2a 100644 --- a/src/class/websockethandler.ts +++ b/src/class/websockethandler.ts @@ -91,7 +91,7 @@ function add(ws: WebSocket): void { clients.set(ws, id); (ws as any).socketId = (ws as any).socketId || `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; // 记录添加WebSocket连接的日志 - log(LogLevel.log, `Add WebSocket: ${ws.url}`); + log(LogLevel.log, `Add WebSocket: ${(ws as any).socketId.toString() }`); } /**