speaker-verification
audio
nemotron
tyger
experimental
tyger-speaker-predictor / code /browser_lifecycle_checks.py
ChristophSchuhmann's picture
Publish audited Robby source and completed Nemotron speaker-prediction experiments
0efd0f1 verified
Raw History Blame Contribute Delete
6.62 kB
"""Real Chromium, fake media/network: startup, cancellation and mic privacy.
Run with Playwright installed, e.g.:
uv run --no-project --with playwright python browser_lifecycle_checks.py
No GPU, hosted API, physical microphone, camera or real WebSocket is used.
"""
from functools import partial
import http.server
import json
import os
from pathlib import Path
import threading
from playwright.sync_api import sync_playwright
class QuietHandler(http.server.SimpleHTTPRequestHandler):
def log_message(self, *_args):
pass
CHECKS = r"""async () => {
const {RoboClient} = await import('/client.js');
const realWS = window.WebSocket;
const realGUM = navigator.mediaDevices.getUserMedia;
const sockets = [];
const results = [];
const tick = () => new Promise(r => setTimeout(r, 0));
const assert = (yes, text) => { if (!yes) throw Error(text); };
function context(addModule = async () => {}) {
return {audioWorklet: {addModule}, close: async () => {},
createMediaStreamSource: () => ({connect() {}, disconnect() {}})};
}
function client(addModule) {
const c = new RoboClient();
c.ctx = context(addModule);
c.clock = {stop() {}, inputLatency: null};
return c;
}
function media() {
let stopped = 0;
const track = {stop() { stopped++; }, getSettings() { return {}; }};
return {stream: {getTracks: () => [track], getAudioTracks: () => [track]},
get stopped() { return stopped; }};
}
class FakeWS {
constructor() {
this.readyState = 0; sockets.push(this);
setTimeout(() => { if (this.readyState === 0) {
this.readyState = 1; this.onopen?.();
}}, 15);
}
close() { this.readyState = 3; this.onclose?.(); }
send() {}
}
try {
window.WebSocket = FakeWS;
const c = client();
const before = sockets.length;
await Promise.all([c.start(false), c.start(false), c.start(false)]);
assert(sockets.length-before === 1, 'Concurrent start opened multiple sockets');
c.stop(); results.push('concurrent_start_uses_one_websocket');
const failedMedia = media();
navigator.mediaDevices.getUserMedia = async () => failedMedia.stream;
const f = client(async () => { throw Error('Injected worklet loading failure'); });
let failed = false;
try { await f.start(true); } catch { failed = true; }
assert(failed, 'Injected worklet failure did not reject');
assert(failedMedia.stopped >= 1 && f.stream === null && f.ctx === null,
'Microphone leaked after worklet failure');
results.push('worklet_failure_stops_microphone');
let resolveLate;
const late = media();
navigator.mediaDevices.getUserMedia = () => new Promise(r => { resolveLate = r; });
const l = client();
const pending = l.start(true).then(() => false, () => true);
await tick(); l.stop(); resolveLate(late.stream);
assert(await pending, 'Stopped startup unexpectedly succeeded');
assert(late.stopped >= 1 && l.stream === null && l.ctx === null,
'Late media permission left microphone running');
results.push('late_get_user_media_after_stop_is_released');
let resolveOld;
const oldMedia = media();
navigator.mediaDevices.getUserMedia = () => new Promise(r => { resolveOld = r; });
const r = client();
const oldStart = r.start(true).then(() => false, () => true);
await tick(); r.stop();
const newContext = context(); r.ctx = newContext; r.clock = {stop() {}};
await r.start(false); const newSocket = r.ws;
resolveOld(oldMedia.stream); await oldStart;
assert(oldMedia.stopped >= 1 && r.ws === newSocket && r.ctx === newContext,
'Cancelled old media startup damaged the new conversation');
r.stop(); results.push('old_media_result_cannot_close_new_session');
const s = client(); await s.start(false); const oldSocket = s.ws;
s.stop(); s.ctx = context(); s.clock = {stop() {}};
await s.start(false); const currentSocket = s.ws;
oldSocket.onclose();
assert(s.ws === currentSocket && currentSocket.readyState === 1,
'Stale close callback stopped a new WebSocket');
s.stop(); results.push('stale_websocket_close_is_ignored');
const resumed = client();let resumes=0;
resumed.ctx.state='suspended';resumed.ctx.resume=async()=>{resumes++;resumed.ctx.state='running';};
await resumed.start(false);
assert(resumes===1 && resumed.ctx.state==='running','Existing suspended context did not resume');
resumed.stop();results.push('existing_suspended_audio_context_resumes');
let resolveModule;
const workletMedia = media();
navigator.mediaDevices.getUserMedia = async () => workletMedia.stream;
const w = client(() => new Promise(r => { resolveModule = r; }));
const workletStart = w.start(true).then(() => false, () => true);
await tick(); w.stop(); resolveModule(); await workletStart;
assert(workletMedia.stopped >= 1 && w.stream === null && w.ctx === null,
'Stopped pending worklet reattached a microphone');
results.push('late_worklet_cannot_reattach_microphone');
return {passed: results.length, checks: results,
physical_microphone_used: false, hosted_api_calls: 0, real_websockets: 0};
} finally {
window.WebSocket = realWS;
navigator.mediaDevices.getUserMedia = realGUM;
}
}"""
def main():
static = Path(__file__).resolve().parent / 'static'
server = http.server.ThreadingHTTPServer(('127.0.0.1', 0),
partial(QuietHandler, directory=str(static)))
threading.Thread(target=server.serve_forever, daemon=True).start()
try:
with sync_playwright() as p:
browser = p.chromium.launch(executable_path=os.environ.get(
'ROBO_CHROME', '/usr/bin/google-chrome'), headless=True,
args=['--no-sandbox'])
try:
page = browser.new_page()
# A directory index is unnecessary: only establish a secure-local origin.
page.goto(f'http://127.0.0.1:{server.server_port}/clock.js')
errors = []
page.on('pageerror', lambda e: errors.append(str(e)))
report = page.evaluate(CHECKS)
assert not errors, errors
target=Path(__file__).resolve().parent/'logs/browser-lifecycle-checks.json'
target.parent.mkdir(exist_ok=True)
target.write_text(json.dumps(report,indent=2))
print(json.dumps(report, indent=2))
finally:
browser.close()
finally:
server.shutdown()
server.server_close()
if __name__ == '__main__':
main()