From 06ff78d2f81873e517528aa717b726f68853aa45 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Tue, 17 Feb 2026 20:17:01 +0100
Subject: [PATCH] fix: improve camera toggle detection with better logging and
state verification
Co-authored-by: Cursor
---
src/bot/orchestrator.ts | 75 +++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 18 deletions(-)
diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts
index 75de834..b6e3711 100644
--- a/src/bot/orchestrator.ts
+++ b/src/bot/orchestrator.ts
@@ -318,28 +318,67 @@ export class BotOrchestrator {
*/
private async _ensureCameraOn(): Promise {
try {
- // Look for camera toggle button
- const cameraBtn = await this._page!.$('button[data-tid="toggle-video"], button[aria-label*="camera" i], button[aria-label*="Camera" i], button[aria-label*="Video" i]');
- if (cameraBtn) {
- // Check if camera is currently off (aria-pressed="false" or similar)
- const isOff = await cameraBtn.evaluate((el) => {
- return el.getAttribute('aria-pressed') === 'false' ||
- el.getAttribute('aria-checked') === 'false' ||
- el.classList.contains('is-off') ||
- el.querySelector('.fui-Icon-regular') !== null;
- });
- if (isOff) {
- await cameraBtn.click();
- this._logger.info('Camera toggled ON');
- await this._page!.waitForTimeout(1000);
- } else {
- this._logger.info('Camera already ON');
+ // Try multiple selectors for the camera toggle
+ const cameraSelectors = [
+ 'button[data-tid="toggle-video"]',
+ 'button[aria-label*="camera" i]',
+ 'button[aria-label*="Camera" i]',
+ 'button[aria-label*="Video" i]',
+ '#video-toggle-button',
+ '[data-tid="prejoin-camera-toggle"]',
+ ];
+
+ let cameraBtn = null;
+ let matchedSelector = '';
+ for (const sel of cameraSelectors) {
+ cameraBtn = await this._page!.$(sel);
+ if (cameraBtn) {
+ matchedSelector = sel;
+ break;
}
+ }
+
+ if (!cameraBtn) {
+ this._logger.warn('Camera toggle button not found with any selector');
+ return;
+ }
+
+ // Log button details for debugging
+ const btnInfo = await cameraBtn.evaluate((el) => {
+ return {
+ ariaLabel: el.getAttribute('aria-label') || '',
+ ariaPressed: el.getAttribute('aria-pressed'),
+ ariaChecked: el.getAttribute('aria-checked'),
+ dataTid: el.getAttribute('data-tid') || '',
+ className: el.className?.substring(0, 80) || '',
+ title: el.getAttribute('title') || '',
+ innerText: el.innerText?.trim()?.substring(0, 30) || '',
+ };
+ });
+ this._logger.info(`Camera button found: ${matchedSelector} | aria-label="${btnInfo.ariaLabel}" | aria-pressed=${btnInfo.ariaPressed} | title="${btnInfo.title}"`);
+
+ // Determine if camera is off — click to turn it ON
+ // In Teams pre-join: aria-pressed="false" means camera is OFF
+ const shouldClick = btnInfo.ariaPressed === 'false' || btnInfo.ariaChecked === 'false';
+
+ if (shouldClick) {
+ await cameraBtn.click();
+ this._logger.info('Camera toggled ON (was off)');
+ await this._page!.waitForTimeout(2000);
+
+ // Verify the toggle worked
+ const afterState = await cameraBtn.evaluate((el) => el.getAttribute('aria-pressed'));
+ this._logger.info(`Camera state after toggle: aria-pressed=${afterState}`);
+ } else if (btnInfo.ariaPressed === null && btnInfo.ariaChecked === null) {
+ // No aria state — click anyway to turn camera on (safe default)
+ await cameraBtn.click();
+ this._logger.info('Camera clicked (no aria state detected, assuming toggle)');
+ await this._page!.waitForTimeout(2000);
} else {
- this._logger.warn('Camera toggle button not found');
+ this._logger.info('Camera already ON (aria-pressed=true)');
}
} catch (err) {
- this._logger.warn('Could not toggle camera:', err);
+ this._logger.warn(`Could not toggle camera: ${err}`);
}
}