Skip to content

Fallback when glasses mic stops streaming#3189

Open
isaiahb wants to merge 1 commit into
cloud-v2-authfrom
codex/glasses-mic-fallback
Open

Fallback when glasses mic stops streaming#3189
isaiahb wants to merge 1 commit into
cloud-v2-authfrom
codex/glasses-mic-fallback

Conversation

@isaiahb

@isaiahb isaiahb commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • skip glasses mic selection when the glasses are disconnected
  • temporarily degrade the glasses mic after LC3 inactivity so phone/system mic can recover audio
  • clear the degraded state as soon as LC3 frames resume

Test

  • Not run in this split step; native Android/iOS Bluetooth path should be verified on device.

Note

Medium Risk
Changes runtime mic routing and STT/audio capture on the native Bluetooth path; behavior is gated by connection state and mic preference but should be verified on physical devices.

Overview
When the glasses LC3 stream goes quiet for more than five seconds while the app is on the glasses mic, Android and iOS DeviceManager now temporarily degrades that source (15s) and calls updateMicState() so the next mic in micRanking can take over—instead of only re-enabling the glasses mic. Users who force preferredMic to glasses or have no alternate in the ranking still get the reinit path.

Mic selection skips GLASSES_CUSTOM when glasses.connected is false, and while the degraded window is active (same preference/ranking exceptions). Incoming LC3 clears the degraded flag so the glasses mic can be chosen again as soon as frames return.

On iOS, the inactivity watchdog treats never-seen LC3 as infinite idle (not ~0s vs Date()), aligning with Android’s “no frame yet” behavior.

Reviewed by Cursor Bugbot for commit d292e51. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds an automatic fallback when the glasses mic stops streaming so audio continues via phone/system mic.

  • Bug Fixes
    • Skip selecting the glasses mic when the glasses are disconnected.
    • After 5s of no LC3 frames, temporarily degrade MicTypes.GLASSES_CUSTOM for 15s and switch to a higher-ranked mic when preferredMic isn’t "glasses"; clear the degraded state as soon as LC3 resumes.
    • Implemented on both Android and iOS DeviceManager.

Written for commit d292e51. Summary will update on new commits.

Review in cubic

@isaiahb isaiahb requested a review from a team as a code owner June 17, 2026 22:53
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

📋 PR Review Helper

📱 Mobile App Build

Ready to test! (commit d292e51)

📥 Download APK

🕶️ ASG Client Build

Waiting for build...


🔀 Test Locally

gh pr checkout 3189

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d292e51. Configure here.

*/
fun handleGlassesMicData(rawLC3Data: ByteArray, frameSize: Int = 40) {
lastLc3Event = System.currentTimeMillis()
glassesMicDegradedUntilMs = 0L

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Degrade cleared before decode

Medium Severity

glassesMicDegradedUntil is cleared at the very start of handleGlassesMicData, before LC3 decode or validation succeeds. Failed, invalid, or undecodable frames still reset the degraded state and refresh lastLc3Event, so the app can treat a broken stream as recovered and select the glasses mic again without usable audio.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d292e51. Configure here.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d292e51600

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +362 to +366
glassesMicDegradedUntilMs = System.currentTimeMillis() + 15_000
Bridge.log(
"MAN: No audio activity in the last 5 seconds from glasses, temporarily falling back from glasses mic"
)
updateMicState()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-arm the glasses mic after fallback expires

When this auto-mode fallback path runs, updateMicState() skips glasses, selects the phone mic, and the cleanup loop disables the non-selected glasses mic with setMicEnabled(false). The watchdog then returns early on future ticks because glasses.micEnabled is false, and nothing calls updateMicState() when glassesMicDegradedUntilMs expires, so the intended 15-second fallback can persist indefinitely until an unrelated route or setting change occurs and the preferred auto glasses mic may never recover.

Useful? React with 👍 / 👎.

Comment on lines +800 to +804
glassesMicDegradedUntil = Date().addingTimeInterval(15)
Bridge.log(
"MAN: No audio activity in the last 5 seconds from glasses, temporarily falling back from glasses mic"
)
updateMicState()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-arm the glasses mic after fallback expires

When this auto-mode fallback path runs, updateMicState() skips glasses, selects the phone mic, and the cleanup loop disables the non-selected glasses mic with setMicEnabled(false). The watchdog then returns early on future ticks because glasses.micEnabled is false, and nothing calls updateMicState() when glassesMicDegradedUntil expires, so the intended 15-second fallback can persist indefinitely until an unrelated route or setting change occurs and the preferred auto glasses mic may never recover.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant