feat(streamer): chromium cdp screencast driver

This commit is contained in:
devilreef 2026-04-30 15:28:31 +06:00
parent e0d93b03ae
commit baef915561
Signed by: devilreef
SSH key fingerprint: SHA256:UZisRr4iuXx+IhkbZnR655L2RWAT6o2rgbGv5F/6m3Y

60
streamer/src/chrome.ts Normal file
View file

@ -0,0 +1,60 @@
import { EventEmitter } from "node:events";
import puppeteer, { Browser, CDPSession, Page } from "puppeteer-core";
export interface ChromeOpts {
pageUrl: string;
width: number;
height: number;
framerate: number;
jpegQuality?: number; // 0..100, default 85
executablePath?: string; // default /usr/bin/chromium
}
export class ChromeRenderer extends EventEmitter {
private browser: Browser | null = null;
private page: Page | null = null;
private cdp: CDPSession | null = null;
constructor(private opts: ChromeOpts) { super(); }
async start(): Promise<void> {
this.browser = await puppeteer.launch({
executablePath: this.opts.executablePath ?? "/usr/bin/chromium",
headless: true,
args: [
"--no-sandbox",
"--disable-dev-shm-usage",
"--disable-gpu",
"--hide-scrollbars",
`--window-size=${this.opts.width},${this.opts.height}`,
"--autoplay-policy=no-user-gesture-required",
],
defaultViewport: { width: this.opts.width, height: this.opts.height },
});
this.page = await this.browser.newPage();
await this.page.goto(this.opts.pageUrl, { waitUntil: "networkidle2" });
this.cdp = await this.page.target().createCDPSession();
await this.cdp.send("Page.startScreencast", {
format: "jpeg",
quality: this.opts.jpegQuality ?? 85,
everyNthFrame: 1,
});
this.cdp.on("Page.screencastFrame", async (frame) => {
const buf = Buffer.from(frame.data, "base64");
this.emit("frame", buf);
await this.cdp!.send("Page.screencastFrameAck", { sessionId: frame.sessionId });
});
this.browser.on("disconnected", () => this.emit("disconnected"));
}
async stop(): Promise<void> {
try { await this.cdp?.send("Page.stopScreencast"); } catch { /* ignore */ }
await this.browser?.close().catch(() => {});
this.browser = null;
this.page = null;
this.cdp = null;
}
}