What's Changed
Bug Fixes
- Pipeline race condition in hold mode — Added
pipeline_lockmutex to serializestart()/stop(), preventingstop()from reading partially-initialized state when the user does a quick press-release. - STT errors no longer leave pipeline stuck in Recording —
TranscriptEvent::Errornow breaks out of the STT receive loop. This is the root cause of the macOS bug where the capsule would stay in "recording" state indefinitely after a transcription error. - Audio capture failure now handled gracefully — If
AudioCaptureHandle::start()fails, the pipeline cleans up preloaded state, emits an error event, and returns to idle. - Abort during start() no longer orphans audio thread — After audio capture setup, the abort flag is checked; if set, the handle is dropped immediately rather than stored for a stop() that will never come.
- Error messages no longer swallowed by idle transition — Stopped clearing
pipelineErroron idle state transition. Errors from failedstart()calls that rapidly cycle Recording → Idle now remain visible for 2.5 seconds. - Error timer no longer overwrites active recording — The 2.5s auto-dismiss timer in CapsuleError now checks if a new recording started during the error window before resetting state.
Details
- Added
pipeline_lock: tokio::sync::Mutex<()>toPipelineHandlefor start/stop serialization start()holds the lock through entire setup (config load, STT connect, audio capture start)stop()acquires the lock, reads all shared state, then drops the lock before the long STT waitAudioCaptureHandle::start()errors now emitpipeline:errorand clean up preloaded stateTranscriptEvent::Errorvariant now triggersbreakin the STT recv loop- Added abort flag check after audio capture to drop orphaned handles
useTauriEvents.ts: movedsetPipelineError(null)from idle handler to recording handlerCapsuleError.tsx: timer callback checkspipelineStatebefore callingresetRecording()
Full Changelog: v0.1.22...v0.1.23