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');