From 35852f691b1306924c32d56560bfcbe0a680f798 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Fri, 27 Feb 2026 11:51:38 +0100 Subject: [PATCH] Voice: ensure mic on in auth join, add track diagnostics Made-with: Cursor --- src/bot/audioProcedure.ts | 18 ++++++++++++++++++ src/bot/orchestrator.ts | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/bot/audioProcedure.ts b/src/bot/audioProcedure.ts index 038bd18..37a900c 100644 --- a/src/bot/audioProcedure.ts +++ b/src/bot/audioProcedure.ts @@ -286,6 +286,18 @@ export class AudioProcedure { const before = await collectWebRtcAudioStats(); + // Hypothesis B: verify TTS track matches PC sender track + const ttsTrack = streamDest.stream.getAudioTracks()[0]; + const ttsTrackId = ttsTrack?.id || null; + const senderTrackIds: string[] = []; + for (const pc of pcs) { + const senders = pc.getSenders?.() || []; + for (const s of senders) { + if (s?.track?.kind === 'audio') senderTrackIds.push(s.track.id); + } + } + const trackMatch = ttsTrackId && senderTrackIds.includes(ttsTrackId); + // Play through the MediaStreamDestination -> Teams mic input const source = ctx.createBufferSource(); source.buffer = audioBuffer; @@ -308,10 +320,16 @@ export class AudioProcedure { after, deltaBytes: after.bytesSentTotal - before.bytesSentTotal, deltaPackets: after.packetsSentTotal - before.packetsSentTotal, + ttsTrackId, + senderTrackIds, + trackMatch, }; }); }, { audioData, format }); + this._logger.info( + `[Voice] TTS track vs PC: ttsTrackId=${playbackDiag?.ttsTrackId ?? 'n/a'} senderTrackIds=[${(playbackDiag?.senderTrackIds ?? []).join(',')}] trackMatch=${playbackDiag?.trackMatch ?? false}`, + ); this._logger.info( `TTS WebRTC diagnostics: pcs=${playbackDiag?.after?.pcs ?? 0}, senders=${playbackDiag?.after?.senderCount ?? 0}, ` + `deltaBytes=${playbackDiag?.deltaBytes ?? 0}, deltaPackets=${playbackDiag?.deltaPackets ?? 0}`, diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts index 5f9726b..3b44f20 100644 --- a/src/bot/orchestrator.ts +++ b/src/bot/orchestrator.ts @@ -371,7 +371,10 @@ export class BotOrchestrator { await this._takeScreenshot('step4a-no-buttons-found', this._isDebugMode); } - // STEP 5: Poll for "Join now" on the pre-join screen (mic is NOT touched) + // Ensure microphone is ON before joining (required for voice playback) + await this._ensureMicOn(); + + // STEP 5: Poll for "Join now" on the pre-join screen await this._takeScreenshot('step5-before-join-now', this._isDebugMode); const joinNowBtn = await this._pollForElement(preJoinSelectors, 30000, 'Join now button');