关于录屏相关的消息格式需要封一层,放在on-message下,利用on-message传递

This commit is contained in:
2026-06-02 23:17:15 +08:00
parent 59fc4be5cc
commit 206a3ac91d
5 changed files with 242 additions and 65 deletions

View File

@@ -1,5 +1,41 @@
import * as Logger from "../utils/logger.js";
const RECORDING_SIGNAL_EVENTS = [
'recording-started',
'recording-peer-request',
'recording-stopped',
'recording-status',
'recording-answer',
'recording-candidate'
];
function parseOnMessageData(data) {
if (typeof data !== 'string') {
return data;
}
try {
return JSON.parse(data);
} catch(e) {
Logger.error(`Signaling: on-message, error: ${e}`);
return data;
}
}
function dispatchOnMessageEvent(target, data, participantId) {
const parsed = parseOnMessageData(data);
if (participantId && parsed && typeof parsed === 'object') {
parsed.participantId = participantId;
}
target.dispatchEvent(new CustomEvent('on-message', { detail: parsed }));
if (parsed && typeof parsed.type === 'string' && RECORDING_SIGNAL_EVENTS.indexOf(parsed.type) !== -1) {
const detail = parsed.data && typeof parsed.data === 'object'
? { type: parsed.type, ...parsed.data }
: parsed;
target.dispatchEvent(new CustomEvent(parsed.type, { detail }));
}
}
export class Signaling extends EventTarget {
constructor(interval = 1000, baseUrl = null) {
@@ -73,15 +109,7 @@ export class Signaling extends EventTarget {
this.dispatchEvent(new CustomEvent('candidate', { detail: msg }));
break;
case "on-message":
{
let parsed = msg.data;
if (typeof msg.data === 'string') {
try { parsed = JSON.parse(msg.data); } catch(e) {
Logger.error(`Signaling: on-message, error: ${e}`);
}
}
this.dispatchEvent(new CustomEvent('on-message', { detail: parsed }));
}
dispatchOnMessageEvent(this, msg.data, msg.participantId);
break;
default:
break;
@@ -201,18 +229,7 @@ export class WebSocketSignaling extends EventTarget {
this.dispatchEvent(new CustomEvent('candidate', { detail: { connectionId: msg.from, candidate: msg.data.candidate, sdpMLineIndex: msg.data.sdpMLineIndex, sdpMid: msg.data.sdpMid, participantId: msg.participantId } }));
break;
case "on-message":
{
let parsed = msg.data;
if (typeof msg.data === 'string') {
try { parsed = JSON.parse(msg.data); } catch(e) {
Logger.error(`Signaling: on-message, error: ${e}`);
}
}
if (msg.participantId) {
parsed.participantId = msg.participantId;
}
this.dispatchEvent(new CustomEvent('on-message', { detail: parsed }));
}
dispatchOnMessageEvent(this, msg.data, msg.participantId);
break;
case "participant-left":
this.dispatchEvent(new CustomEvent('participant-left', { detail: msg }));
@@ -346,20 +363,23 @@ export class WebSocketSignaling extends EventTarget {
}
sendRecordingOffer(payload) {
const sendJson = JSON.stringify({ type: 'recording-offer', data: payload });
Logger.log(sendJson);
this.websocket.send(sendJson);
this.sendMessage(payload.connectionId || '', {
type: 'recording-offer',
data: payload
});
}
sendRecordingCandidate(payload) {
const sendJson = JSON.stringify({ type: 'recording-candidate', data: payload });
Logger.log(sendJson);
this.websocket.send(sendJson);
this.sendMessage(payload.connectionId || '', {
type: 'recording-candidate',
data: payload
});
}
sendRecordingStatus(payload) {
const sendJson = JSON.stringify({ type: 'recording-status', data: payload });
Logger.log(sendJson);
this.websocket.send(sendJson);
this.sendMessage(payload.connectionId || '', {
type: 'recording-status',
data: payload
});
}
}

View File

@@ -43,6 +43,89 @@ function createWebSocketSignaling(port) {
return new WebSocketSignaling(1, `ws://localhost:${port}`);
}
describe('recording signaling message envelope', () => {
const OriginalWebSocket = window.WebSocket;
let sentMessages;
beforeEach(() => {
sentMessages = [];
window.WebSocket = class {
constructor() {
this.readyState = 1;
}
send(message) {
sentMessages.push(message);
}
close() {
if (this.onclose) {
this.onclose();
}
}
};
});
afterEach(() => {
window.WebSocket = OriginalWebSocket;
});
test('sends recording offer through on-message', () => {
const signaling = new WebSocketSignaling(1, 'ws://localhost:1234');
signaling.sendRecordingOffer({
recordingId: 'recording-1',
connectionId: 'room-1',
participantId: 'participant-1',
sdp: 'offer-sdp'
});
expect(sentMessages).toHaveLength(1);
const outer = JSON.parse(sentMessages[0]);
expect(outer.type).toBe('on-message');
expect(outer.data.connectionId).toBe('room-1');
expect(outer.data.message).toEqual({
type: 'recording-offer',
data: {
recordingId: 'recording-1',
connectionId: 'room-1',
participantId: 'participant-1',
sdp: 'offer-sdp'
}
});
});
test('dispatches wrapped recording messages as recording events', () => {
const signaling = new WebSocketSignaling(1, 'ws://localhost:1234');
let recordingAnswer;
signaling.addEventListener('recording-answer', (event) => {
recordingAnswer = event.detail;
});
signaling.websocket.onmessage({
data: JSON.stringify({
type: 'on-message',
from: 'room-1',
data: JSON.stringify({
type: 'recording-answer',
data: {
recordingId: 'recording-1',
connectionId: 'room-1',
sdp: 'answer-sdp'
}
})
})
});
expect(recordingAnswer).toEqual({
type: 'recording-answer',
recordingId: 'recording-1',
connectionId: 'room-1',
sdp: 'answer-sdp'
});
});
});
describe.each(signalingModes)('signaling test in public mode', ({ mode }) => {
let signaling1;
let signaling2;