diff --git a/opennow-stable/package-lock.json b/opennow-stable/package-lock.json index 3234c1c1..1afd9256 100644 --- a/opennow-stable/package-lock.json +++ b/opennow-stable/package-lock.json @@ -1,12 +1,12 @@ { "name": "opennow-stable", - "version": "0.3.1", + "version": "0.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opennow-stable", - "version": "0.3.1", + "version": "0.2.4", "dependencies": { "lucide-react": "^0.563.0", "react": "^19.2.4", @@ -58,6 +58,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1830,6 +1831,7 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1971,6 +1973,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2137,7 +2140,6 @@ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", @@ -2157,7 +2159,6 @@ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -2180,7 +2181,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2196,8 +2196,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/archiver-utils/node_modules/string_decoder": { "version": "1.1.1", @@ -2205,7 +2204,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -2403,6 +2401,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2912,7 +2911,6 @@ "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -3163,7 +3161,6 @@ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -3177,7 +3174,6 @@ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -3418,6 +3414,7 @@ "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", @@ -3613,7 +3610,6 @@ "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "25.1.8", "archiver": "^5.3.1", @@ -3627,7 +3623,6 @@ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -3643,7 +3638,6 @@ "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -3657,7 +3651,6 @@ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 10.0.0" } @@ -4128,8 +4121,7 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fs-extra": { "version": "8.1.0", @@ -4768,8 +4760,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/isbinaryfile": { "version": "5.0.7", @@ -4926,7 +4917,6 @@ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readable-stream": "^2.0.5" }, @@ -4940,7 +4930,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4956,8 +4945,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lazystream/node_modules/string_decoder": { "version": "1.1.1", @@ -4965,7 +4953,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -4982,40 +4969,35 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -5544,7 +5526,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5821,8 +5802,7 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/progress": { "version": "2.0.3", @@ -5894,6 +5874,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5954,7 +5935,6 @@ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "minimatch": "^5.1.0" } @@ -5964,8 +5944,7 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/readdir-glob/node_modules/brace-expansion": { "version": "2.0.2", @@ -5973,7 +5952,6 @@ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -5984,7 +5962,6 @@ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6548,7 +6525,6 @@ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -6804,6 +6780,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -7045,7 +7022,6 @@ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", @@ -7061,7 +7037,6 @@ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", diff --git a/opennow-stable/src/main/index.ts b/opennow-stable/src/main/index.ts index 3ff0edf0..b3c3e407 100644 --- a/opennow-stable/src/main/index.ts +++ b/opennow-stable/src/main/index.ts @@ -1091,58 +1091,45 @@ function registerIpcHandlers(): void { }); } - // Ping regions IPC handler — TCP connect timing (like ExitLag-style route probes: latency + stability) + // Ping regions IPC handler - uses TCP connection timing for accurate latency measurement + // Runs 3 tests and averages the results ipcMain.handle(IPC_CHANNELS.PING_REGIONS, async (_event, regions: StreamRegion[]): Promise => { const pingPromises = regions.map(async (region) => { try { const url = new URL(region.url); const hostname = url.hostname; - const port = url.protocol === "https:" ? 443 : 80; - + const port = url.protocol === 'https:' ? 443 : 80; + const validPings: number[] = []; - const sampleCount = 5; - for (let i = 0; i < sampleCount; i++) { + + // Run 3 ping tests + for (let i = 0; i < 3; i++) { const pingMs = await tcpPing(hostname, port, 3000); if (pingMs !== null) { validPings.push(pingMs); } } - + + // Calculate average of successful pings if (validPings.length > 0) { - const sum = validPings.reduce((a, b) => a + b, 0); - const avgPing = Math.round(sum / validPings.length); - const minMs = Math.min(...validPings); - const maxMs = Math.max(...validPings); - let jitterMs: number | undefined; - if (validPings.length >= 2) { - const mean = sum / validPings.length; - const variance = - validPings.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / validPings.length; - jitterMs = Math.round(Math.sqrt(variance)); - } - return { - url: region.url, - pingMs: avgPing, - minMs, - maxMs, - jitterMs, - samples: validPings.length, + const avgPing = Math.round(validPings.reduce((a, b) => a + b, 0) / validPings.length); + return { url: region.url, pingMs: avgPing }; + } else { + return { + url: region.url, + pingMs: null, + error: 'All ping tests failed' }; } - return { - url: region.url, - pingMs: null, - error: "All ping tests failed", - }; } catch { - return { - url: region.url, - pingMs: null, - error: "Invalid URL", + return { + url: region.url, + pingMs: null, + error: 'Invalid URL' }; } }); - + return Promise.all(pingPromises); }); diff --git a/opennow-stable/src/main/settings.ts b/opennow-stable/src/main/settings.ts index fd6d3f6b..c45aff82 100644 --- a/opennow-stable/src/main/settings.ts +++ b/opennow-stable/src/main/settings.ts @@ -1,15 +1,7 @@ import { app } from "electron"; import { join } from "node:path"; import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; -import type { - VideoCodec, - ColorQuality, - VideoAccelerationPreference, - MicrophoneMode, - GameLanguage, - AspectRatio, - IceTransportPolicy, -} from "@shared/gfn"; +import type { VideoCodec, ColorQuality, VideoAccelerationPreference, MicrophoneMode, GameLanguage, AspectRatio } from "@shared/gfn"; export interface Settings { /** Video resolution (e.g., "1920x1080") */ @@ -75,8 +67,6 @@ export interface Settings { gameLanguage: GameLanguage; /** Experimental request for Low Latency, Low Loss, Scalable throughput on new sessions */ enableL4S: boolean; - /** WebRTC ICE policy: "all" (default) or "relay" (TURN-only) */ - iceTransportPolicy: IceTransportPolicy; } const defaultStopShortcut = "Ctrl+Shift+Q"; @@ -118,7 +108,6 @@ const DEFAULT_SETTINGS: Settings = { windowHeight: 900, gameLanguage: "en_US", enableL4S: false, - iceTransportPolicy: "all", }; export class SettingsManager { diff --git a/opennow-stable/src/renderer/src/App.tsx b/opennow-stable/src/renderer/src/App.tsx index a0c4078f..2032ab1c 100644 --- a/opennow-stable/src/renderer/src/App.tsx +++ b/opennow-stable/src/renderer/src/App.tsx @@ -426,7 +426,6 @@ export function App(): JSX.Element { windowHeight: 900, gameLanguage: "en_US", enableL4S: false, - iceTransportPolicy: "all", }); const [settingsLoaded, setSettingsLoaded] = useState(false); const [regions, setRegions] = useState([]); @@ -794,13 +793,8 @@ export function App(): JSX.Element { }, [providers, providerIdpId, authSession]); const effectiveStreamingBaseUrl = useMemo(() => { - const base = selectedProvider?.streamingServiceUrl?.trim() ?? ""; - const preferred = settings.region?.trim() ?? ""; - if (preferred && preferred.startsWith("https://")) { - return preferred.endsWith("/") ? preferred : `${preferred}/`; - } - return base; - }, [selectedProvider, settings.region]); + return selectedProvider?.streamingServiceUrl ?? ""; + }, [selectedProvider]); const loadSubscriptionInfo = useCallback( async (session: AuthSession): Promise => { @@ -1245,7 +1239,6 @@ export function App(): JSX.Element { microphoneDeviceId: settings.microphoneDeviceId || undefined, mouseSensitivity: settings.mouseSensitivity, mouseAcceleration: settings.mouseAcceleration, - iceTransportPolicy: settings.iceTransportPolicy, onLog: (line: string) => console.log(`[WebRTC] ${line}`), onStats: (stats) => diagnosticsStore.set(stats), onEscHoldProgress: (visible, progress) => { @@ -1305,20 +1298,7 @@ export function App(): JSX.Element { }); return () => unsubscribe(); - }, [ - resetLaunchRuntime, - settings.microphoneMode, - settings.microphoneDeviceId, - settings.mouseSensitivity, - settings.mouseAcceleration, - settings.codec, - settings.colorQuality, - settings.resolution, - settings.fps, - settings.maxBitrateMbps, - settings.iceTransportPolicy, - (settings as { autoFullScreen?: boolean }).autoFullScreen, - ]); + }, [resetLaunchRuntime, settings]); // Save settings when changed const updateSetting = useCallback(async (key: K, value: Settings[K]) => { @@ -1348,13 +1328,6 @@ export function App(): JSX.Element { // ignore } } - if (key === "iceTransportPolicy") { - try { - (clientRef.current as any)?.setIceTransportPolicy?.(value); - } catch { - // ignore - } - } }, [settingsLoaded]); const handleMouseSensitivityChange = useCallback((value: number) => { diff --git a/opennow-stable/src/renderer/src/components/SettingsPage.tsx b/opennow-stable/src/renderer/src/components/SettingsPage.tsx index 228e8989..cc8df624 100644 --- a/opennow-stable/src/renderer/src/components/SettingsPage.tsx +++ b/opennow-stable/src/renderer/src/components/SettingsPage.tsx @@ -307,30 +307,17 @@ function loadStoredCodecResults(): CodecTestResult[] | null { interface PingCacheEntry { url: string; pingMs: number | null; - minMs?: number; - maxMs?: number; - jitterMs?: number; - samples?: number; - error?: string; } -function loadStoredPingResults(): Map | null { +function loadStoredPingResults(): Map | null { try { const raw = window.sessionStorage.getItem(PING_RESULTS_STORAGE_KEY); if (!raw) return null; const parsed = JSON.parse(raw) as unknown; if (!Array.isArray(parsed)) return null; - const results = new Map(); + const results = new Map(); for (const entry of parsed as PingCacheEntry[]) { - results.set(entry.url, { - url: entry.url, - pingMs: entry.pingMs, - minMs: entry.minMs, - maxMs: entry.maxMs, - jitterMs: entry.jitterMs, - samples: entry.samples, - error: entry.error, - }); + results.set(entry.url, entry.pingMs); } return results; } catch { @@ -338,19 +325,11 @@ function loadStoredPingResults(): Map | null { } } -function saveStoredPingResults(results: Map): void { +function saveStoredPingResults(results: Map): void { try { const entries: PingCacheEntry[] = []; - results.forEach((r, url) => { - entries.push({ - url, - pingMs: r.pingMs, - minMs: r.minMs, - maxMs: r.maxMs, - jitterMs: r.jitterMs, - samples: r.samples, - error: r.error, - }); + results.forEach((pingMs, url) => { + entries.push({ url, pingMs }); }); window.sessionStorage.setItem(PING_RESULTS_STORAGE_KEY, JSON.stringify(entries)); } catch { @@ -533,10 +512,6 @@ async function testCodecSupport(): Promise { return results; } -function getRegionPingMs(map: Map, url: string): number | null | undefined { - return map.get(url)?.pingMs; -} - /* ── Component ────────────────────────────────────────────────────── */ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPageProps): JSX.Element { @@ -552,14 +527,13 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag // Region ping state const initialPingResults = useMemo(() => loadStoredPingResults(), []); - const [pingResults, setPingResults] = useState>(initialPingResults ?? new Map()); + const [pingResults, setPingResults] = useState>(initialPingResults ?? new Map()); const [isPinging, setIsPinging] = useState(false); const [bestRegionUrl, setBestRegionUrl] = useState(() => { if (!initialPingResults) return null; let bestUrl: string | null = null; let bestPing = Infinity; - initialPingResults.forEach((entry, url) => { - const pingMs = entry.pingMs; + initialPingResults.forEach((pingMs, url) => { if (pingMs !== null && pingMs < bestPing) { bestPing = pingMs; bestUrl = url; @@ -573,12 +547,12 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag setIsPinging(true); try { const results = await window.openNow.pingRegions(regions); - const pingMap = new Map(); + const pingMap = new Map(); let bestUrl: string | null = null; let bestPing = Infinity; for (const result of results) { - pingMap.set(result.url, result); + pingMap.set(result.url, result.pingMs); if (result.pingMs !== null && result.pingMs < bestPing) { bestPing = result.pingMs; bestUrl = result.url; @@ -821,8 +795,8 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag // Sort by ping (best first), then by name filtered.sort((a, b) => { - const pingA = getRegionPingMs(pingResults, a.url); - const pingB = getRegionPingMs(pingResults, b.url); + const pingA = pingResults.get(a.url); + const pingB = pingResults.get(b.url); // If both have ping results, sort by ping if (pingA !== undefined && pingB !== undefined && pingA !== null && pingB !== null) { @@ -984,7 +958,7 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag {!settings.region && bestRegionUrl && ( (() => { const bestRegion = regions.find(r => r.url === bestRegionUrl); - const pingValue = getRegionPingMs(pingResults, bestRegionUrl); + const pingValue = pingResults.get(bestRegionUrl); if (bestRegion && pingValue !== undefined && pingValue !== null) { return ( @@ -997,7 +971,7 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag )} {settings.region && ( (() => { - const pingValue = getRegionPingMs(pingResults, settings.region); + const pingValue = pingResults.get(settings.region); if (pingValue !== undefined && pingValue !== null) { return ( @@ -1066,7 +1040,7 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag Auto (Best) {bestRegionUrl && (() => { const bestRegion = regions.find(r => r.url === bestRegionUrl); - const bestPing = getRegionPingMs(pingResults, bestRegionUrl); + const bestPing = pingResults.get(bestRegionUrl); if (bestRegion && bestPing !== undefined && bestPing !== null) { return ( @@ -1103,31 +1077,15 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag ... ) : ( (() => { - const pr = pingResults.get(region.url); - const pingValue = pr?.pingMs; - const jitterHint = - pr?.jitterMs != null || pr?.minMs != null || pr?.maxMs != null - ? [ - pr.jitterMs != null ? `Jitter ~${pr.jitterMs}ms` : null, - pr.minMs != null && pr.maxMs != null ? `${pr.minMs}–${pr.maxMs}ms` : null, - ] - .filter(Boolean) - .join(" · ") - : undefined; + const pingValue = pingResults.get(region.url); if (pingValue === undefined) { return -; } else if (pingValue === null) { return Failed; } else { return ( - + {pingValue}ms - {pr?.jitterMs != null && pr.jitterMs > 0 ? ( - ±{pr.jitterMs} - ) : null} ); } @@ -1145,9 +1103,6 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag )} - - Choosing a region (or Auto) sets which GeForce NOW data center CloudMatch uses. This is the main in-app way to optimize latency; it is not a VPN or custom routing product like ExitLag. - @@ -1365,33 +1320,6 @@ export function SettingsPage({ settings, regions, onSettingChange }: SettingsPag -
- -
- {( - [ - { value: "all" as const, label: "Default", title: "Try direct and relay candidates (typical home networks)" }, - { value: "relay" as const, label: "Relay only", title: "Force TURN — can help with VPNs or strict NAT (may add latency)" }, - ] as const - ).map((opt) => ( - - ))} -
- - Controls WebRTC candidate gathering. This is not a full “game booster” VPN; it only affects how OpenNOW connects to GeForce NOW. - -
- diff --git a/opennow-stable/src/renderer/src/gfn/webrtcClient.ts b/opennow-stable/src/renderer/src/gfn/webrtcClient.ts index e1d8ef2c..5c037f31 100644 --- a/opennow-stable/src/renderer/src/gfn/webrtcClient.ts +++ b/opennow-stable/src/renderer/src/gfn/webrtcClient.ts @@ -5,7 +5,6 @@ import type { SessionInfo, VideoCodec, MicrophoneMode, - IceTransportPolicy, } from "@shared/gfn"; import { @@ -209,8 +208,6 @@ interface ClientOptions { onEscHoldProgress?: (visible: boolean, progress: number) => void; onTimeWarning?: (warning: StreamTimeWarning) => void; onMicStateChange?: (state: MicStateChange) => void; - /** ICE gathering policy — "relay" forces TURN-only (VPN / strict NAT). Default "all". */ - iceTransportPolicy?: IceTransportPolicy; } function timestampUs(sourceTimestampMs?: number): bigint { @@ -568,7 +565,6 @@ export class GfnWebRtcClient { private videoDecodeStallWarningSent = false; private serverRegion = ""; private gpuType = ""; - private iceTransportPolicy: IceTransportPolicy = "all"; private diagnostics: StreamDiagnostics = { connectionState: "closed", @@ -612,7 +608,6 @@ export class GfnWebRtcClient { options.audioElement.muted = true; this.mouseSensitivity = options.mouseSensitivity ?? 1; this.mouseAccelerationPercent = Math.max(1, Math.min(150, Math.round(options.mouseAcceleration ?? 1))); - this.iceTransportPolicy = options.iceTransportPolicy === "relay" ? "relay" : "all"; // Configure video element for lowest latency playback this.configureVideoElementForLowLatency(options.videoElement); @@ -662,15 +657,6 @@ export class GfnWebRtcClient { } /** Update mouse sensitivity multiplier at runtime. */ - public setIceTransportPolicy(policy: IceTransportPolicy): void { - const next = policy === "relay" ? "relay" : "all"; - if (this.iceTransportPolicy === next) { - return; - } - this.iceTransportPolicy = next; - this.log(`ICE transport policy updated to ${next} (applies on next stream)`); - } - public setMouseSensitivity(value: number): void { const v = Number.isFinite(value) ? value : 1; this.mouseSensitivity = Math.max(0.01, v); @@ -3305,7 +3291,6 @@ export class GfnWebRtcClient { iceServers: toRtcIceServers(session.iceServers), bundlePolicy: "max-bundle", rtcpMuxPolicy: "require", - iceTransportPolicy: this.iceTransportPolicy, }; const pc = new RTCPeerConnection(rtcConfig); diff --git a/opennow-stable/src/renderer/src/styles.css b/opennow-stable/src/renderer/src/styles.css index 3927bacc..05501695 100644 --- a/opennow-stable/src/renderer/src/styles.css +++ b/opennow-stable/src/renderer/src/styles.css @@ -2805,12 +2805,6 @@ button.game-card-store-chip.active:hover { background: rgba(239, 68, 68, 0.15); } -.region-ping-jitter { - font-size: 0.72em; - opacity: 0.85; - font-weight: 500; -} - .region-ping-loading { color: var(--ink-muted); font-style: italic; diff --git a/opennow-stable/src/shared/gfn.ts b/opennow-stable/src/shared/gfn.ts index 38be44db..66465e9a 100644 --- a/opennow-stable/src/shared/gfn.ts +++ b/opennow-stable/src/shared/gfn.ts @@ -35,9 +35,6 @@ export function colorQualityIs10Bit(cq: ColorQuality): boolean { export type MicrophoneMode = "disabled" | "push-to-talk" | "voice-activity"; export type AspectRatio = "16:9" | "16:10" | "21:9" | "32:9"; -/** WebRTC ICE candidate gathering policy — "relay" can help when only TURN works reliably (e.g. VPN / strict NAT). */ -export type IceTransportPolicy = "all" | "relay"; - export interface Settings { resolution: string; aspectRatio: AspectRatio; @@ -75,10 +72,6 @@ export interface Settings { gameLanguage: GameLanguage; /** Experimental request for Low Latency, Low Loss, Scalable throughput on new sessions */ enableL4S: boolean; - /** - * WebRTC ICE transport policy for streaming. "relay" uses TURN only (often needed with VPNs or strict NAT). - */ - iceTransportPolicy: IceTransportPolicy; } export interface LoginProvider { @@ -187,14 +180,6 @@ export interface PingResult { url: string; pingMs: number | null; error?: string; - /** Lowest TCP connect time in the sample (ms), when measured */ - minMs?: number; - /** Highest TCP connect time in the sample (ms), when measured */ - maxMs?: number; - /** Approximate jitter: standard deviation of samples (ms), when measured */ - jitterMs?: number; - /** Number of successful connect samples (e.g. 5) */ - samples?: number; } export interface GamesFetchRequest {