






















@@ -1,3 +1,4 @@
1+import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
12import {
23GatewayClient,
34startGatewayClientWhenEventLoopReady,
@@ -18,11 +19,6 @@ type VoiceCallSpeakResult = {
1819error?: string;
1920};
202121-type VoiceCallDtmfResult = {
22-success?: boolean;
23-error?: string;
24-};
25-2622type VoiceCallMeetJoinResult = {
2723callId: string;
2824dtmfSent: boolean;
@@ -87,19 +83,24 @@ export async function joinMeetViaVoiceCallGateway(params: {
8783dtmfSequence?: string;
8884logger?: RuntimeLogger;
8985message?: string;
86+requesterSessionKey?: string;
87+sessionKey?: string;
9088}): Promise<VoiceCallMeetJoinResult> {
9189let client: VoiceCallGatewayClient | undefined;
92909391try {
9492client = await createConnectedGatewayClient(params.config);
9593params.logger?.info(
96-`[google-meet] Delegating Twilio join to Voice Call (dtmf=${params.dtmfSequence ? "post-connect" : "none"}, intro=${params.message ? "delayed" : "none"})`,
94+`[google-meet] Delegating Twilio join to Voice Call (dtmf=${params.dtmfSequence ? "pre-connect" : "none"}, intro=${params.message ? "delayed" : "none"})`,
9795);
9896const start = (await client.request(
9997"voicecall.start",
10098{
10199to: params.dialInNumber,
102100mode: "conversation",
101+ ...(params.dtmfSequence ? { dtmfSequence: params.dtmfSequence } : {}),
102+ ...(params.requesterSessionKey ? { requesterSessionKey: params.requesterSessionKey } : {}),
103+ ...(params.sessionKey ? { sessionKey: params.sessionKey } : {}),
103104},
104105{ timeoutMs: params.config.voiceCall.requestTimeoutMs },
105106)) as VoiceCallStartResult;
@@ -109,27 +110,10 @@ export async function joinMeetViaVoiceCallGateway(params: {
109110params.logger?.info(
110111`[google-meet] Voice Call Twilio phone leg started: callId=${start.callId}`,
111112);
112-let dtmfSent = false;
113-if (params.dtmfSequence) {
114-const delayMs = params.config.voiceCall.dtmfDelayMs;
115-params.logger?.info(
116-`[google-meet] Waiting ${delayMs}ms before sending Meet DTMF for callId=${start.callId}`,
117-);
118-await sleep(delayMs);
119-const dtmf = (await client.request(
120-"voicecall.dtmf",
121-{
122-callId: start.callId,
123-digits: params.dtmfSequence,
124-},
125-{ timeoutMs: params.config.voiceCall.requestTimeoutMs },
126-)) as VoiceCallDtmfResult;
127-if (dtmf.success === false) {
128-throw new Error(dtmf.error || "voicecall.dtmf failed");
129-}
130-dtmfSent = true;
113+const dtmfSent = Boolean(params.dtmfSequence);
114+if (dtmfSent) {
131115params.logger?.info(
132-`[google-meet] Meet DTMF sent after phone leg connected: callId=${start.callId} digits=${params.dtmfSequence.length}`,
116+`[google-meet] Meet DTMF queued before realtime connect: callId=${start.callId} digits=${params.dtmfSequence?.length ?? 0}`,
133117);
134118}
135119let introSent = false;
@@ -141,15 +125,23 @@ export async function joinMeetViaVoiceCallGateway(params: {
141125);
142126await sleep(delayMs);
143127}
144-const spoken = (await client.request(
145-"voicecall.speak",
146-{
147-callId: start.callId,
148-allowTwimlFallback: false,
149-message: params.message,
150-},
151-{ timeoutMs: params.config.voiceCall.requestTimeoutMs },
152-)) as VoiceCallSpeakResult;
128+let spoken: VoiceCallSpeakResult;
129+try {
130+spoken = (await client.request(
131+"voicecall.speak",
132+{
133+callId: start.callId,
134+allowTwimlFallback: false,
135+message: params.message,
136+},
137+{ timeoutMs: params.config.voiceCall.requestTimeoutMs },
138+)) as VoiceCallSpeakResult;
139+} catch (err) {
140+params.logger?.warn?.(
141+`[google-meet] Skipped intro speech because realtime bridge was not ready: ${formatErrorMessage(err)}`,
142+);
143+spoken = { success: false };
144+}
153145if (spoken.success === false) {
154146params.logger?.warn?.(
155147`[google-meet] Skipped intro speech because realtime bridge was not ready: ${
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。