mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:40:44 +00:00
fix: wait for meet microphone readiness
This commit is contained in:
@@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Google Meet: stop advertising legacy `mode: "realtime"` to agents and config UIs, while keeping it as a hidden compatibility alias for `mode: "agent"`, so new joins use the STT -> OpenClaw agent -> TTS path instead of selecting the direct realtime voice fallback.
|
||||
- Google Meet: add `chrome.audioBufferBytes` for generated command-pair SoX audio commands and lower the default buffer from SoX's 8192 bytes to 4096 bytes to reduce Chrome talk-back latency.
|
||||
- Google Meet: split realtime provider config into agent-mode transcription and bidi-mode voice providers, and migrate legacy Gemini Live bidi configs with `doctor --fix`, so Gemini Live can back direct bidi fallback without breaking the default OpenClaw agent talk-back path.
|
||||
- Google Meet: keep waiting for the Meet microphone to unmute during join intro readiness instead of permanently skipping talk-back when Meet briefly reports the local mic as muted.
|
||||
- Google Meet: expose `voiceCall.postDtmfSpeechDelayMs` in the plugin manifest schema and setup hints, so manifest-based config editing accepts the runtime-supported Twilio delay key. Thanks @vincentkoc.
|
||||
- Google Meet: keep explicit non-Google `realtime.provider` values as the transcription provider compatibility fallback when `realtime.transcriptionProvider` is unset. Thanks @vincentkoc.
|
||||
- Google Meet: make Twilio setup status require an enabled `voice-call` plugin entry instead of treating a missing entry as ready. Thanks @vincentkoc.
|
||||
|
||||
@@ -118,7 +118,7 @@ function requestUrl(input: RequestInfo | URL): URL {
|
||||
}
|
||||
|
||||
function mockLocalMeetBrowserRequest(
|
||||
browserActResult: Record<string, unknown> = {
|
||||
browserActResult: Record<string, unknown> | (() => Record<string, unknown>) = {
|
||||
inCall: true,
|
||||
micMuted: false,
|
||||
title: "Meet call",
|
||||
@@ -158,7 +158,11 @@ function mockLocalMeetBrowserRequest(
|
||||
};
|
||||
}
|
||||
if (request.path === "/act") {
|
||||
return { result: JSON.stringify(browserActResult) };
|
||||
return {
|
||||
result: JSON.stringify(
|
||||
typeof browserActResult === "function" ? browserActResult() : browserActResult,
|
||||
),
|
||||
};
|
||||
}
|
||||
throw new Error(`unexpected browser request path ${request.path}`);
|
||||
},
|
||||
@@ -2766,6 +2770,57 @@ describe("google-meet plugin", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps waiting while the Meet microphone is muted during intro readiness", async () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", { value: "darwin" });
|
||||
try {
|
||||
let inspectCount = 0;
|
||||
mockLocalMeetBrowserRequest(() => {
|
||||
inspectCount += 1;
|
||||
return {
|
||||
inCall: true,
|
||||
micMuted: true,
|
||||
title: "Meet call",
|
||||
url: "https://meet.google.com/abc-defg-hij",
|
||||
};
|
||||
});
|
||||
const { methods } = setup({
|
||||
chrome: {
|
||||
audioBridgeCommand: ["bridge", "start"],
|
||||
waitForInCallMs: 1000,
|
||||
},
|
||||
});
|
||||
const handler = methods.get("googlemeet.join") as
|
||||
| ((ctx: {
|
||||
params: Record<string, unknown>;
|
||||
respond: ReturnType<typeof vi.fn>;
|
||||
}) => Promise<void>)
|
||||
| undefined;
|
||||
const respond = vi.fn();
|
||||
|
||||
await handler?.({
|
||||
params: { url: "https://meet.google.com/abc-defg-hij" },
|
||||
respond,
|
||||
});
|
||||
|
||||
expect(respond.mock.calls[0]?.[1]).toMatchObject({
|
||||
spoken: false,
|
||||
session: {
|
||||
chrome: {
|
||||
health: {
|
||||
micMuted: true,
|
||||
speechReady: false,
|
||||
speechBlockedReason: "meet-microphone-muted",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(inspectCount).toBeGreaterThanOrEqual(2);
|
||||
} finally {
|
||||
Object.defineProperty(process, "platform", { value: originalPlatform });
|
||||
}
|
||||
});
|
||||
|
||||
it("joins Chrome on a paired node without local Chrome or BlackHole", async () => {
|
||||
const { methods, nodesList, nodesInvoke } = setup(
|
||||
{
|
||||
|
||||
@@ -604,7 +604,12 @@ export class GoogleMeetRuntime {
|
||||
return false;
|
||||
}
|
||||
const blocked = health?.speechBlockedReason;
|
||||
if (blocked && blocked !== "not-in-call" && blocked !== "browser-unverified") {
|
||||
if (
|
||||
blocked &&
|
||||
blocked !== "not-in-call" &&
|
||||
blocked !== "browser-unverified" &&
|
||||
blocked !== "meet-microphone-muted"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user