51 lines
3.2 KiB
Python
51 lines
3.2 KiB
Python
import asyncio
|
|
import json
|
|
import pathlib
|
|
|
|
from playwright.async_api import async_playwright
|
|
|
|
OUT = pathlib.Path(__file__).resolve().parents[1] / "evidence"
|
|
OUT.mkdir(exist_ok=True)
|
|
|
|
|
|
async def main():
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch(
|
|
args=["--no-sandbox", "--autoplay-policy=no-user-gesture-required"]
|
|
)
|
|
page = await browser.new_page()
|
|
await page.goto("http://192.168.200.12:8010")
|
|
await page.evaluate("""async () => {
|
|
document.body.innerHTML='<video id="v" autoplay playsinline></video><canvas id="c" width="768" height="768"></canvas>';
|
|
const v=document.querySelector('video'), c=document.querySelector('canvas'), ctx=c.getContext('2d');
|
|
const ac=new AudioContext(), dest=ac.createMediaStreamDestination();
|
|
const pc=window.pc=new RTCPeerConnection({iceServers:[]});
|
|
const stream=new MediaStream(); v.srcObject=stream;
|
|
pc.ontrack=e=>stream.addTrack(e.track);
|
|
pc.addTransceiver('audio',{direction:'recvonly'}); pc.addTransceiver('video',{direction:'recvonly'});
|
|
await pc.setLocalDescription(await pc.createOffer());
|
|
await new Promise(r=>{if(pc.iceGatheringState==='complete')r();else pc.onicegatheringstatechange=()=>{if(pc.iceGatheringState==='complete')r()}});
|
|
const a=await (await fetch('/offer',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(pc.localDescription)})).json();
|
|
window.sid=a.sessionid; await pc.setRemoteDescription(a);
|
|
await new Promise(r=>v.onloadeddata=r); await v.play();
|
|
v.muted=true; const source=ac.createMediaStreamSource(stream); source.connect(ac.destination); source.connect(dest);
|
|
await ac.resume(); const recorded=c.captureStream(25); dest.stream.getAudioTracks().forEach(t=>recorded.addTrack(t));
|
|
window.metrics=[]; const analyser=ac.createAnalyser();source.connect(analyser);let buffer=new Float32Array(analyser.fftSize);
|
|
function draw(){ctx.drawImage(v,0,0,768,768);ctx.fillStyle='white';ctx.font='20px sans-serif';ctx.fillText((performance.now()/1000).toFixed(3),20,750);analyser.getFloatTimeDomainData(buffer);metrics.push([performance.now(),Math.sqrt(buffer.reduce((s,x)=>s+x*x,0)/buffer.length)]);window.raf=requestAnimationFrame(draw)}draw();
|
|
window.chunks=[];window.rec=new MediaRecorder(recorded,{mimeType:'video/webm;codecs=vp8,opus'});rec.ondataavailable=e=>chunks.push(e.data);rec.start(1000);
|
|
}""")
|
|
await page.wait_for_timeout(1500)
|
|
await page.evaluate(
|
|
"""async()=>{window.sent=performance.now();await fetch('/human',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sessionid:sid,type:'echo',text:'你好。八百标兵奔北坡,炮兵并排北边跑。现在我停下来听你说话。'})})}"""
|
|
)
|
|
await page.wait_for_timeout(18000)
|
|
data = await page.evaluate(
|
|
"""async()=>{await new Promise(r=>{rec.onstop=r;rec.stop()});const b=new Blob(chunks);return Array.from(new Uint8Array(await b.arrayBuffer()))}"""
|
|
)
|
|
(OUT / "baseline-browser-av.webm").write_bytes(bytes(data))
|
|
(OUT / "baseline.json").write_text(json.dumps(await page.evaluate("({sent,metrics})")))
|
|
await browser.close()
|
|
|
|
|
|
asyncio.run(main())
|