You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Users report "can't hear" during video calls. Auto-diagnostics correctly identify the cause as speakerNotSet, attempt to re-align the speaker device, and report success — but post-fix validation shows the speaker is still null. The setSpeaker() call completes without error but the device never actually activates.
Diagnostics read from callObject.getInputDevices() / callObject.getOutputDevices() (synchronous call object methods)
These are two different APIs to the same underlying state. If the call object is in a bad state (e.g., after the #1226 crash/remount), getInputDevices()/getOutputDevices() may return nulls even though useDevices() shows valid devices.
Hypothesis: many PE events are caused by the #1226 crash
The same TypeError: Cannot read properties of undefined (reading 'then') from #1226 appears in the PE breadcrumbs. The sequence is:
Even if #1226 accounts for many events, there are likely real speaker issues too:
setSpeaker() can silently fail: The Promise resolves without error even when the underlying HTMLAudioElement.setSinkId() doesn't actually change the output device (e.g., stale device ID from a disconnected Bluetooth device).
No post-set verification: After setSpeaker() succeeds, neither the alignment code nor the FixAV recovery verifies that currentSpeaker actually reflects the change.
Safari gesture requirement: Safari requires a user gesture for setSinkId(). When alignment runs from a React effect (no gesture context), setSinkId throws NotAllowedError. The gesture prompt system handles this, but QD shows 7 consecutive failures in one session.
Bluetooth device churn: Bluetooth devices (AirPods, "sairpods", WH-1000XM4) can disconnect between alignment and use, leaving the speaker unset with no recovery.
Add post-set verification to alignSpeaker() — re-query devices.currentSpeaker after setSpeaker() and retry with fallback if unchanged
Align the diagnostics API to use devices.currentSpeaker (the hook) instead of callObject.getOutputDevices() (the snapshot), or verify they return the same data
Add Bluetooth disconnect detection and proactive fallback
User Impact
High — 22 distinct users unable to hear audio during calls. The FixAV panel diagnoses the problem but can't fix it, leaving users stuck.
Summary
Users report "can't hear" during video calls. Auto-diagnostics correctly identify the cause as
speakerNotSet, attempt to re-align the speaker device, and report success — but post-fix validation shows the speaker is still null. ThesetSpeaker()call completes without error but the device never actually activates.Sentry issues:
reportedAVError: 36 events, 22 users (ongoing)avDiagnosticResponse: 33 events, 18 users (correlated roommate diagnostics)Investigation Findings
What the Sentry data shows
Diagnostic data from PE events consistently shows all three device types with
currentId: null— not just the speaker:{ "deviceAlignment": { "camera": { "currentId": null, "currentLabel": null }, "microphone": { "currentId": null, "currentLabel": null }, "speaker": { "currentId": null, "currentLabel": null } } }Breadcrumb sequence from PE event 3348c86c:
14:14:04— "Speaker aligned via id match" — alignment logs success14:14:04—TypeError: Cannot read properties of undefined (reading 'then')— bug: startRecording() returns undefined during stage transitions, crashing VideoCall #1226 crash14:14:21— Diagnosed causes:speakerNotSet— speaker is null despite "successful" alignment14:14:21— Re-aligned speaker device — fix attempt14:14:22— Validation:stillPresent: speakerNotSet— fix failedKey observation: diagnostics vs alignment use different APIs
There is a disconnect between how devices are set and how they are read back:
devices.setSpeaker()and readsdevices.currentSpeaker(from Daily'suseDevices()React hook)callObject.getInputDevices()/callObject.getOutputDevices()(synchronous call object methods)These are two different APIs to the same underlying state. If the call object is in a bad state (e.g., after the #1226 crash/remount),
getInputDevices()/getOutputDevices()may return nulls even thoughuseDevices()shows valid devices.Hypothesis: many PE events are caused by the #1226 crash
The same
TypeError: Cannot read properties of undefined (reading 'then')from #1226 appears in the PE breadcrumbs. The sequence is:getInputDevices()/getOutputDevices()return nulls for all device typesspeakerNotSet→ fix failsIf this hypothesis is correct, deploying the #1226 fix should significantly reduce PE/PG events.
Remaining concerns (independent of #1226)
Even if #1226 accounts for many events, there are likely real speaker issues too:
setSpeaker()can silently fail: The Promise resolves without error even when the underlyingHTMLAudioElement.setSinkId()doesn't actually change the output device (e.g., stale device ID from a disconnected Bluetooth device).No post-set verification: After
setSpeaker()succeeds, neither the alignment code nor the FixAV recovery verifies thatcurrentSpeakeractually reflects the change.Safari gesture requirement: Safari requires a user gesture for
setSinkId(). When alignment runs from a React effect (no gesture context),setSinkIdthrowsNotAllowedError. The gesture prompt system handles this, but QD shows 7 consecutive failures in one session.Bluetooth device churn: Bluetooth devices (AirPods, "sairpods", WH-1000XM4) can disconnect between alignment and use, leaving the speaker unset with no recovery.
Plan
alignSpeaker()— re-querydevices.currentSpeakeraftersetSpeaker()and retry with fallback if unchangeddevices.currentSpeaker(the hook) instead ofcallObject.getOutputDevices()(the snapshot), or verify they return the same dataUser Impact
High — 22 distinct users unable to hear audio during calls. The FixAV panel diagnoses the problem but can't fix it, leaving users stuck.
Affected Code
client/src/call/hooks/useDeviceAlignment.js—alignSpeaker()lacks post-set verificationclient/src/call/FixAV.jsx—collectAVDiagnostics()reads fromcallObject.getOutputDevices()which may differ fromdevices.currentSpeakerclient/src/call/utils/avRecovery.js— soft fix forspeakerNotSetreports false success