3 Commits

Author SHA1 Message Date
DatCaptainHorse
e0751b368a feat: runner and playsite updates, mouse input stutter fix
- Also fixed mangohud config
2025-12-01 00:27:13 +02:00
DatCaptainHorse
0f71b02271 exp(relay): Restore playout delay to 0 2025-12-01 00:16:15 +02:00
DatCaptainHorse
f9b4269ce3 exp(relay): Try setting high playout delay 2025-11-30 20:52:12 +02:00
7 changed files with 39 additions and 62 deletions

View File

@@ -130,7 +130,7 @@ RUN --mount=type=cache,target=${CARGO_HOME}/registry \
cargo install cargo-c cargo install cargo-c
# Clone repository # Clone repository
RUN git clone --depth 1 --rev "e4c70b64dad3cd8bbf5eec011f419386adf737ee" https://github.com/games-on-whales/gst-wayland-display.git RUN git clone --depth 1 --rev "67b1183997fd7aaf57398e4b01bd64c4d2433c45" https://github.com/games-on-whales/gst-wayland-display.git
#-------------------------------------------------------------------- #--------------------------------------------------------------------
FROM gst-wayland-deps AS gst-wayland-planner FROM gst-wayland-deps AS gst-wayland-planner

View File

@@ -15,7 +15,7 @@ RUN --mount=type=cache,target=/var/cache/pacman/pkg \
pacman -S --needed --noconfirm \ pacman -S --needed --noconfirm \
vulkan-intel lib32-vulkan-intel vpl-gpu-rt \ vulkan-intel lib32-vulkan-intel vpl-gpu-rt \
vulkan-radeon lib32-vulkan-radeon \ vulkan-radeon lib32-vulkan-radeon \
mesa lib32-mesa \ mesa lib32-mesa vulkan-mesa-layers lib32-vulkan-mesa-layers \
gtk3 lib32-gtk3 \ gtk3 lib32-gtk3 \
sudo xorg-xwayland seatd libinput gamescope mangohud wlr-randr \ sudo xorg-xwayland seatd libinput gamescope mangohud wlr-randr \
pipewire pipewire-pulse pipewire-alsa wireplumber \ pipewire pipewire-pulse pipewire-alsa wireplumber \
@@ -68,9 +68,7 @@ COPY packages/configs/wireplumber.conf.d/* /etc/wireplumber/wireplumber.conf.d/
COPY packages/configs/pipewire.conf.d/* /etc/pipewire/pipewire.conf.d/ COPY packages/configs/pipewire.conf.d/* /etc/pipewire/pipewire.conf.d/
## MangoHud Config ## ## MangoHud Config ##
RUN mkdir -p "${NESTRI_HOME}/.config/MangoHud" COPY packages/configs/MangoHud/MangoHud.conf /etc/nestri/configs/MangoHud/
COPY packages/configs/MangoHud/MangoHud.conf "${NESTRI_HOME}/.config/MangoHud/"
### Artifacts from Builder ### ### Artifacts from Builder ###
COPY --from=builder /artifacts/bin/nestri-server /usr/bin/ COPY --from=builder /artifacts/bin/nestri-server /usr/bin/

View File

@@ -36,10 +36,8 @@ export class Keyboard {
if (this.connected) this.stop(); if (this.connected) this.stop();
this.connected = true; this.connected = true;
document.addEventListener("keydown", this.keydownListener, { document.addEventListener("keydown", this.keydownListener);
passive: false, document.addEventListener("keyup", this.keyupListener);
});
document.addEventListener("keyup", this.keyupListener, { passive: false });
} }
private stop() { private stop() {
@@ -73,6 +71,6 @@ export class Keyboard {
private keyToVirtualKeyCode(code: string) { private keyToVirtualKeyCode(code: string) {
// Treat Home key as Escape - TODO: Make user-configurable // Treat Home key as Escape - TODO: Make user-configurable
if (code === "Home") return 1; if (code === "Home") return 1;
return keyCodeToLinuxEventCode[code] || undefined; return keyCodeToLinuxEventCode[code] || 0;
} }
} }

View File

@@ -35,8 +35,6 @@ export class Mouse {
this.wrtc = webrtc; this.wrtc = webrtc;
this.canvas = canvas; this.canvas = canvas;
this.sendInterval = 1000 / webrtc.currentFrameRate;
this.mousemoveListener = (e: MouseEvent) => { this.mousemoveListener = (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -77,18 +75,10 @@ export class Mouse {
if (document.pointerLockElement == this.canvas) { if (document.pointerLockElement == this.canvas) {
this.connected = true; this.connected = true;
this.canvas.addEventListener("mousemove", this.mousemoveListener, { this.canvas.addEventListener("mousemove", this.mousemoveListener);
passive: false, this.canvas.addEventListener("mousedown", this.mousedownListener);
}); this.canvas.addEventListener("mouseup", this.mouseupListener);
this.canvas.addEventListener("mousedown", this.mousedownListener, { this.canvas.addEventListener("wheel", this.mousewheelListener);
passive: false,
});
this.canvas.addEventListener("mouseup", this.mouseupListener, {
passive: false,
});
this.canvas.addEventListener("wheel", this.mousewheelListener, {
passive: false,
});
} else { } else {
if (this.connected) { if (this.connected) {
this.stop(); this.stop();
@@ -106,7 +96,7 @@ export class Mouse {
private startProcessing() { private startProcessing() {
setInterval(() => { setInterval(() => {
if (this.connected && (this.movementX !== 0 || this.movementY !== 0)) { if (this.connected) {
this.sendAggregatedMouseMove(); this.sendAggregatedMouseMove();
this.movementX = 0; this.movementX = 0;
this.movementY = 0; this.movementY = 0;

View File

@@ -13,9 +13,10 @@ import {
ProtoClientRequestRoomStream, ProtoClientRequestRoomStream,
ProtoClientRequestRoomStreamSchema, ProtoClientRequestRoomStreamSchema,
ProtoICE, ProtoICE,
ProtoICESchema, ProtoRaw, ProtoICESchema,
ProtoRaw,
ProtoSDP, ProtoSDP,
ProtoSDPSchema ProtoSDPSchema,
} from "./proto/types_pb"; } from "./proto/types_pb";
import { P2PMessageStream } from "./streamwrapper"; import { P2PMessageStream } from "./streamwrapper";
@@ -38,7 +39,6 @@ export class WebRTCStream {
private _roomName: string | undefined = undefined; private _roomName: string | undefined = undefined;
private _isConnected: boolean = false; private _isConnected: boolean = false;
private _dataChannelCallbacks: Array<(data: any) => void> = []; private _dataChannelCallbacks: Array<(data: any) => void> = [];
currentFrameRate: number = 100;
constructor( constructor(
serverURL: string, serverURL: string,
@@ -126,11 +126,19 @@ export class WebRTCStream {
} }
}); });
this._msgStream.on("session-assigned", (data: ProtoClientRequestRoomStream) => { this._msgStream.on(
this._sessionId = data.sessionId; "session-assigned",
localStorage.setItem("nestri-session-id", this._sessionId); (data: ProtoClientRequestRoomStream) => {
console.log("Session ID assigned:", this._sessionId, "for room:", data.roomName); this._sessionId = data.sessionId;
}); localStorage.setItem("nestri-session-id", this._sessionId);
console.log(
"Session ID assigned:",
this._sessionId,
"for room:",
data.roomName,
);
},
);
this._msgStream.on("offer", async (data: ProtoSDP) => { this._msgStream.on("offer", async (data: ProtoSDP) => {
if (!this._pc) { if (!this._pc) {
@@ -293,26 +301,8 @@ export class WebRTCStream {
this._onConnected( this._onConnected(
new MediaStream([this._audioTrack, this._videoTrack]), new MediaStream([this._audioTrack, this._videoTrack]),
); );
// Continuously set low-latency target
this._pc.getReceivers().forEach((receiver: RTCRtpReceiver) => {
let intervalLoop = setInterval(async () => {
if (
receiver.track.readyState !== "live" ||
(receiver.transport && receiver.transport.state !== "connected")
) {
clearInterval(intervalLoop);
return;
} else {
// @ts-ignore
receiver.jitterBufferTarget = receiver.jitterBufferDelayHint = receiver.playoutDelayHint = 0;
}
}, 50);
});
} }
} }
this._gatherFrameRate();
} else if ( } else if (
this._pc.connectionState === "failed" || this._pc.connectionState === "failed" ||
this._pc.connectionState === "closed" || this._pc.connectionState === "closed" ||
@@ -412,11 +402,16 @@ export class WebRTCStream {
}; };
} }
private _gatherFrameRate() { private async _gatherStats(): Promise<any> {
if (this._pc === undefined || this._videoTrack === undefined) return; if (
this._pc === undefined ||
this._videoTrack === undefined ||
!this._isConnected
)
return null;
const videoInfoPromise = new Promise<{ fps: number }>((resolve) => { return new Promise<any>((resolve) => {
// Keep trying to get fps until it's found // Keep trying to get stats until gotten
const interval = setInterval(async () => { const interval = setInterval(async () => {
if (this._pc === undefined) { if (this._pc === undefined) {
clearInterval(interval); clearInterval(interval);
@@ -428,15 +423,11 @@ export class WebRTCStream {
if (report.type === "inbound-rtp") { if (report.type === "inbound-rtp") {
clearInterval(interval); clearInterval(interval);
resolve({ fps: report.framesPerSecond }); resolve({ pli: report.pliCount, nack: report.nackCount });
} }
}); });
}, 250); }, 250);
}); });
videoInfoPromise.then((value) => {
this.currentFrameRate = value.fps;
});
} }
// Send binary message through the data channel // Send binary message through the data channel

View File

@@ -13,4 +13,4 @@ export GST_GL_API=gles2
export GST_GL_WINDOW=surfaceless export GST_GL_WINDOW=surfaceless
# Gamescope does not respect MangoHud default config location # Gamescope does not respect MangoHud default config location
export MANGOHUD_CONFIGFILE=${NESTRI_HOME}/.config/MangoHud/MangoHud.conf export MANGOHUD_CONFIGFILE=/etc/nestri/configs/MangoHud/MangoHud.conf

View File

@@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.90" channel = "1.91"