Change predefined datachannels to callbacks

This commit is contained in:
sergystepanov 2026-06-01 21:10:45 +03:00
parent de24654ca8
commit edb92b8993
2 changed files with 25 additions and 40 deletions

View file

@ -154,11 +154,6 @@ const startGame = () => {
return;
}
if (!webrtc.isInputReady()) {
message.show('Game is not ready yet. Please wait');
return;
}
log.info('[control] game start');
setState(app.state.game);
@ -493,15 +488,22 @@ sub(GAME_PLAYER_IDX_SET, idx => {
sub(GAME_ERROR_NO_FREE_SLOTS, () => message.show("No free slots :(", 2500));
sub(WEBRTC_NEW_CONNECTION, (data) => {
workerManager.whoami(data.wid);
webrtc.onData = (x) => onMessage(api.decode(x.data))
webrtc.start(data.ice);
webrtc.modDataChannel = (ch) => {
ch.binaryType = "arraybuffer";
if (ch.label === "data") {
ch.onmessage = (x) => onMessage(api.decode(x.data));
pub(WEBRTC_CONNECTION_READY);
}
return ch
}
api.server.initWebrtc()
gameList.set(data.games);
});
sub(WEBRTC_ICE_CANDIDATE_FOUND, (data) => api.server.sendIceCandidate(data.candidate));
sub(WEBRTC_SDP_ANSWER, (data) => api.server.sendSdp(data.sdp));
sub(WEBRTC_SDP_OFFER, (data) => webrtc.setRemoteDescription(api.decodeB64(data.sdp), stream.video.el));
sub(WEBRTC_ICE_CANDIDATE_RECEIVED, (data) => {
sub(WEBRTC_ICE_CANDIDATE_RECEIVED, (data) => {
const candidate = data.candidate ? api.decodeB64(data.candidate) : ''
webrtc.addCandidate(candidate)
});
@ -528,7 +530,7 @@ sub(KEY_RELEASED, onKeyRelease);
sub(SETTINGS_CHANGED, () => message.show('Settings have been updated'));
sub(AXIS_CHANGED, onAxisChanged);
sub(CONTROLLER_UPDATED, data => webrtc.input(data));
sub(CONTROLLER_UPDATED, data => webrtc.send("data", data));
sub(RECORDING_TOGGLED, handleRecording);
sub(RECORDING_STATUS_CHANGED, handleRecordingStatus);
@ -552,8 +554,8 @@ const wid = new URLSearchParams(document.location.search).get('wid');
socket.init(roomId, wid, zone);
api.transport = {
send: socket.send,
keyboard: webrtc.keyboard,
mouse: webrtc.mouse,
keyboard: (data) => webrtc.send("keyboard", data),
mouse: (data) => webrtc.send("mouse", data),
}
// stats

View file

@ -15,9 +15,8 @@ let /** @type {RTCLocalIceCandidateInit[]} */ candidates = [];
let isAnswered = false;
let isFlushing = false;
let connected = false;
let inputReady = false;
let /** @type {(MessageEvent) => void} */ onData;
let /** @type {(channel: RTCDataChannel) => RTCDataChannel} */ modDataChannel;
const ice = ((timeout = 3000) => {
let timeoutId;
@ -93,6 +92,12 @@ const ice = ((timeout = 3000) => {
};
})();
// readyChan - wraps an RTCDataChannel to ensure it is ready before sending
const readyChan = (/** @type {RTCDataChannel} */ dc) => ({
send: (/** @type {string} */ data) =>
dc.readyState === "open" && dc.send(data),
});
const flushCandidates = () => {
if (isFlushing || !isAnswered) return;
isFlushing = true;
@ -120,26 +125,9 @@ export const webrtc = {
mediaStream = new MediaStream();
pc.ondatachannel = (ev) => {
const chan = ev.channel;
chan.binaryType = "arraybuffer";
let chan = modDataChannel ? modDataChannel(ev.channel) : ev.channel;
channels.set(chan.label, readyChan(chan));
log.debug(`[rtc] [data-ch] push: ${chan.label}`);
channels.set(chan.label, chan);
if (chan.label === "data") {
chan.onopen = () => {
log.debug("[rtc] [data-ch] input channel has been opened");
inputReady = true;
pub(WEBRTC_CONNECTION_READY);
};
if (onData) {
chan.onmessage = onData;
}
chan.onclose = () => {
inputReady = false;
log.debug("[rtc] [data-ch] input channel has been closed");
};
}
};
pc.oniceconnectionstatechange = ice.onIceConnectionStateChange;
pc.onicegatheringstatechange = ice.onIceGatheringStateChange;
@ -165,9 +153,7 @@ export const webrtc = {
log.error(`[rtc] [sdp] remote offer error: ${e}`);
}
log.debug(
`[rtc] [sdp] remote Trickle ICE support: ${pc.canTrickleIceCandidates}`,
);
log.debug(`[rtc] [sdp] Trickle ICE: ${pc.canTrickleIceCandidates}`);
try {
const answer = await pc.createAnswer();
@ -193,11 +179,8 @@ export const webrtc = {
}
candidates.push(candidate);
},
keyboard: (data) => channels.get("keyboard")?.send(data),
mouse: (data) => channels.get("mouse")?.send(data),
input: (data) => inputReady && channels.get("data")?.send(data),
send: (chan, data) => channels.get(chan)?.send(data),
isConnected: () => connected,
isInputReady: () => inputReady,
stats: async () => {
if (!connected) return Promise.resolve();
return await pc.getStats();
@ -223,7 +206,7 @@ export const webrtc = {
candidates = [];
log.info("[rtc] WebRTC has been closed");
},
set onData(/** @type {(MessageEvent) => void} */ fn) {
onData = fn;
set modDataChannel(fn) {
modDataChannel = fn;
},
};