Show the microphone level meter in the audio menu

The meter sits at the foot of the microphone group and follows the selected
microphone. Its capture starts when the menu opens and stops when it closes,
muted or not, so the microphone is only held while the user is looking at the
level. A denied permission shows a hint in place of the meter.

Keyboard navigation marks the current menu item with a focus border; pointer
use gets the hover background only, since the menu moves DOM focus to
whatever the pointer is over.

Spec: FEATURES_SPEC/2026-09_Audio_Quick_Menu.md, slice 3 — AC9, AC10, AC12,
AC14, AC23, AC24 (manual), AC26.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
fkwp
2026-09-10 23:53:36 +02:00
co-authored by Claude Fable 5.1
parent 29a7a50d57
commit 2bda5eb18c
7 changed files with 309 additions and 63 deletions
+27
View File
@@ -63,6 +63,33 @@ test("audio menu leaves participants visible while switching output", async ({
await SpaHelpers.expectVideoTilesCount(page, 2);
});
test("level indicator moves with microphone input", async ({
browser,
browserName,
}) => {
test.skip(
browserName === "firefox",
"Firefox has no audio backend on the CI runner, so the level stays at zero there. It passes against Firefox elsewhere, including CI's own Docker image over plain HTTP.",
);
const context = await browser.newContext({ reducedMotion: "reduce" });
const page = await context.newPage();
await page.goto("/");
await SpaHelpers.createCall(page, "Speaker", "Level meter", true);
await expect(page.getByTestId("videoTile")).toHaveCount(1);
await page.getByRole("button", { name: "Microphone" }).click();
const meter = page.getByRole("menu").getByRole("meter");
await expect(meter).toBeVisible();
// The browser's fake microphone plays a tone, so the meter has to leave its
// resting level while the menu is open.
await expect
.poll(async () => Number(await meter.getAttribute("aria-valuenow")), {
timeout: 15_000,
})
.toBeGreaterThan(0);
});
async function firstUncheckedIndex(
rows: Locator,
count: number,