Notable changes to Voxis. Version bumps are tagged in commit messages
(vX.Y.Z: ...); this file tracks contributions and fixes as they land.
- A client-side marker now detects a session that never reached a clean shutdown (app crash, force-kill, BSOD, power loss) and reports it retroactively on the next launch, closing a gap where such sessions left no trace in the activation-funnel telemetry at all.
- Video/Game and a meeting's incoming leg can now speak the translation in a voice close to the original speaker's own ("Dubbing Voice" in Settings › Translation), on the ~29 languages Qwen can voice. Off by default; the clone is established once from the first utterance and held for the session. A per-response re-clone mode was also built and live-tested but turned out not to track a speaker change mid-session (it just locks onto whoever spoke first, same as the "once" mode) — pulled from the UI rather than ship a mode that silently doesn't do what it claims.
- History rows can now be starred to pin them; starred sessions are exempt from the 90-day/500-file cleanup pass, with a "starred only" filter next to the search box.
- A saved session's text can now be corrected directly in History; exports (TXT/SRT/VTT) automatically reflect the fix.
- History can generate a short AI summary of any saved session on request (paid plans; unrestricted on the OSS/BYOK build) — never automatic, so it never spends a model call without an explicit ask.
- A new control lets you drop the currently playing translated sentence on the incoming leg without stopping the session. Meeting's outgoing leg is deliberately excluded — skipping it would drop the other party into silence mid-sentence on a live call.
- Meeting's outgoing leg now paces a long translated turn the same way the incoming leg already does (WSOLA catch-up time-compression when a response outruns realtime), instead of letting the untrimmed backlog build up directly in the playback ring. The optional "listen to my translation" confidence monitor stays on the raw, unpaced feed on purpose — it exists to mirror exactly what the other party hears, which is the paced mic-side output, not a second independently-timed copy.
- Settings › Membership now shows an inline referral code/link with a copy button and live stats (friends joined, minutes earned), instead of only a link out to the website.
- The Terms list (Settings › Translation) can now be imported from a text file instead of typed by hand, merging into whatever is already there.
- Language pickers now show a flag emoji next to each language name for a
quicker scan. Native
<select>dropdowns can't render actual flag images, and Windows' own emoji font renders some flags as a two-letter country code instead of a picture — a real image-based picker would need replacing the native control, tracked separately. - A free/taste-tier session whose fast translation engine hits a real, server-confirmed problem mid-session now gets a backup voice instead of the session simply ending — a short notice explains what's happening. The backup voice never costs the session's trial minutes; it draws from the same daily free-voice allowance every account already has, so it can't run indefinitely. The server only grants it while it has real evidence of trouble, so a session can't trigger this on its own.
- A translator that had recent input but produced no output long enough to trip its own no-output watchdog (an engine-side stall, not the user going quiet) could still be billed for that stretch — the accrual now pauses for it, same as it already does for a dead capture device. Traced to a real field report of minutes disappearing during a run of repeated reconnect-and-recover cycles.
- Reporting a problem now auto-attaches the signed-in account's email instead of relying on a manual field almost everyone left blank, so a follow-up doesn't depend on the reporter typing it in.
- Meeting's outgoing-leg catch-up pacing (added in this same batch, see "Added" above) is disabled again pending a real-device repro: a paid customer's Meeting session on 1.0.60 produced correct translated text and audible translated speech locally, but the other party heard nothing — reproduced identically on both Microsoft Teams and Zoom, ruling out a call-app-specific setting. The stager was the only functional change 1.0.60 made to that delivery path, so the leg now feeds the virtual-cable Player directly again, exactly as it did before 1.0.60. The incoming leg's stager (unrelated code path, proven since PR #39) is untouched.
- A translator session whose self-heal reconnect attempts ran out while translation output stayed empty used to sit "connected" with a one-time warning and never recover until the user noticed and restarted it by hand. It now gives up and recovers the same way a terminal engine error does — a paid session fails over to the backup engine, and an in-progress free/taste session gets a shot at the cascade rescue instead of hanging silently.
- A device fingerprint used to enforce the one-free-trial-per-computer rule could fall back to a value that is identical across every unit of a common hardware model (manufacturer + product name, not a real per-machine ID) when a lower-level Windows API was unavailable. This could incorrectly flag a brand-new account's free trial as already used on a shared hardware model. The weak fallback is now recognized as such and never used for that check.
- Several client-side security hardening fixes: the internal JS-to-native bridge now enforces an explicit allowlist instead of exposing every method to page script; connection parameters supplied by the server are now validated before use; a login fallback path no longer leaves a session token in browser history; a settings key could be written without going through its own validation; and a few crash-on-malformed-input edge cases (settings, transcripts, connection data) now degrade gracefully instead of crashing the app. A dependency was also updated to patch a known vulnerability.
- A translation-engine failure with no substitute engine available could surface the raw upstream error text to the user (e.g. a provider's literal technical error payload) instead of a clear message. Now shows a plain status in all 23 languages; the technical detail still reaches the log.
- A long-running Qwen session carrying a lot of speech could be dropped and
reconnected even though the connection was healthy: the WebSocket ping/pong
keepalive (
ping_timeout=10s) could fire before the app's own stall watchdogs did, if DashScope's server was still busy processing a large in-flight exchange. Raised to 600s per DashScope's own support-ticket guidance — the app's stall/no-output watchdogs already catch a genuinely dead connection within ~20s during active streaming (they key off actual traffic, not ping/pong), so this only removes the false-positive disconnect on healthy, busy sessions. - A Qwen capacity error ("thread pool exhausted") that used to be retried up to 8 times with fast backoff is now recognized as terminal instead of generic-transient — it was hammering an already-saturated shared rate limit and prolonging the very outage it was reacting to. A terminal error now gets one immediate retry on a server-provided sibling connection pool before falling back to the alternate engine.
- On VB-CABLE setups, the volume mirror assumed the physical playback device sat at 0 dB. If it didn't — the common case — that device's own level silently capped the output under whatever the mirror computed: the display showed full volume with nothing left to raise while the actual level was quieter. Voxis now raises the physical device to full for the session and restores it on stop.
- The language picker now locks out any language a free-tier session cannot use, with a link to upgrade, instead of letting you pick it and finding out later — mid-session — that it does not work. Paired with a cost-control change: a free or taste-tier session no longer falls back to the paid engine under any circumstance (an outage included), it only ever uses the primary engine or ends the session cleanly. Paid sessions are unaffected — they still fail over to the backup engine when needed.
- The top bar now shows which version you're running, and flags it when a
newer one is available — checked in the background against a small public
manifest (
voxislive.com/app.json) that also carries language coverage for the website. The check is unauthenticated and sends no user data, so it runs on the OSS/BYOK build too, not just the official release. - Voxis says something when it cannot hear anything. If no sound reaches it in the first seconds of a Video session, it now tells you — and names the two things that actually cause it: nothing is playing, or you are speaking into your microphone, which Video mode does not translate. Until now the app stayed completely silent in that state; measurement across every recorded session showed 40% of them ended inside 30 seconds, with another attempt following a median 14 seconds later, i.e. people were retrying, not losing interest.
- The gap between pressing Start and the first translated word is no longer a blank screen: the stream shows that it is connecting, escalates if the handshake drags past ten seconds, and sets the expectation that the first translation lands a few seconds after someone speaks. The line explaining that delay used to appear only with the first caption — after the wait it was meant to explain, and never at all for anyone who gave up first.
- Release notes now cover every version you skipped, not just the running one. Store updates land in the background and can jump several versions at once, which is how 1.0.50's notes reached nobody who went from 1.0.49 to 1.0.51 in a single update. The card also links to the full changelog on the website.
- Translated-voice gender, chosen per direction: "Translation voice" (what you hear) and "My voice" (what the other person hears you as, in Meeting mode). Both live in Settings › Translation — it is set once for a meeting, not adjusted per session, so it does not belong on the main screen. Available on the 31 targets served by the Qwen engine — measurement showed the Gemini translate model ignores voice selection entirely, so on the remaining targets the picker says so instead of silently doing nothing. Until now every session used one server-default voice, which is female.
- Release notes in the app: after an update you see what changed once, in your own UI language, instead of having to find the Microsoft Store listing. A fresh install is not shown a changelog — it gets the onboarding tour.
- A ready-made list of ~31 proper nouns ships with the term box, so brand and product names are spelled right before anyone types anything. It can be switched off, and your own terms always win over a shipped one.
- The term box moved out of General into its own Settings › Translation tab and is no longer called "Meeting terms": it has always applied to Video mode too.
- A translator session that connected but never produced any output no longer looped retrying the same dead connection forever: the retry counter was reset by time-alive alone, so a connection that stayed open past 5 seconds before dying with zero output kept "proving the path works" and never reached the threshold that hands the session to a backup engine. It now also requires that the session actually produced output before resetting. Paid plans additionally fail over to the backup engine on the very first dropped connection instead of riding out several retries.
- A session no longer goes permanently silent when the translation service starts rejecting the audio it is sent. Those rejections still count as "the engine is hearing us", so both self-heal watchdogs stayed disarmed: the session kept its connection, showed as active, produced nothing, and never reconnected. One field meeting lost its last 13 minutes that way. Voxis now treats a rejected utterance as input and reconnects itself.
- The close button of the translation-history window sits at the top right, like every other window, instead of next to the title.
- Meeting mode no longer translates its own outgoing voice back at you. On a PC with VB-Cable installed, both directions shared the one cable, so the translation Voxis had just sent into the call came back in as if the other party had said it — a third, phantom voice in your own language.
- Captions no longer run words together at a sentence boundary ("bekleyelim.Bu arada," instead of "bekleyelim. Bu arada,") — it affected a quarter of all caption lines on the Qwen engine.
- Repeated caption text is removed: both a whole line re-spoken as the next turn, and a clause the engine emits twice inside one line. The translated speech only ever said it once.
- A caption line no longer swallows 20+ seconds of speech; past a length or time budget it splits at the next sentence end.
- Subtitle exports (SRT/VTT) are wrapped to a readable line width — cues used to run off the frame, the longest being a single 548-character line.
- Subtitle timings now start from the session, not from the first translated word, so an export lines up with its own audio recording. A session that began before anyone spoke shifted every cue.
- Meeting mode keeps its two directions apart. Both translators fed one caption line and one transcript, so the other party's words and your own interleaved with no way to tell them apart. Each side is now labelled, on screen and in the saved transcript.
- The "Original audio (while speaking)" control on VB-CABLE setups now ducks the original speaker, not the background music — a same-day regression had it scaling the whole ambient mix uniformly instead.
- The "Translation volume" slider no longer plays quieter than its displayed percentage (it was being applied twice, effectively squaring the setting).
- Translated audio playback could be briefly delayed by a slow UI frame; UI updates now run off the audio-delivery thread.
- Closing the app while the floating overlay window was open could leave the process running in the background instead of exiting.
- History now loads noticeably faster (cached session summaries instead of re-parsing every transcript on every open).
- Both language pickers now show a permanent explanatory line — it's no longer ambiguous that the outgoing-language field only applies in Meeting mode.
- Word drops at translated-caption turn boundaries; captions now stream smoothly and stay in sync with the translated speech (superseded an earlier client-side word-pacing engine that caused the drops).
- Source-language captions are now paired to the correct translation turn using the model's actual simultaneous-interpretation lag, instead of drifting onto an earlier or later turn during continuous narration.
- A
TypeErrorinIncomingPipeline's text-sync callback signature that could interrupt a Meeting session.
- Settings > General: a Meeting terms box. Names your meetings use — companies, products, people — can be listed one per line so the translator spells them correctly instead of guessing.
- Settings > Saving tab: transcript folder, audio recording, and automatic TXT/SRT/VTT export formats (generated alongside the JSON on every save) are now grouped in one place; quick TXT/SRT/VTT export buttons also appear right after saving a transcript, without opening History.
- Automatic background pruning of old transcript folders (keeps the newest 500 sessions / 90 days).
- The OpenAI translation engine has been fully removed from the client (it was already disabled server-side; this removes the remaining client-side code path).
- Audio device diagnostics now reflect the device and signal actually being tested: output test tone, system-audio meter, and microphone meter are independent instead of conflated into one indicator. Raw audio activity is also distinguished from detected speech, so music/system sounds are no longer shown as speech.
- Translated-speech playback catch-up (WSOLA time-compression) is now shared between the Gemini and Qwen engines instead of being Qwen-only, so a long translated turn on either engine stays closer to the live captions.
- Meeting mode: an opt-in "Listen to my translation" monitor plays the outgoing translated speech through the user's own headphones in addition to the virtual microphone, so a speaker can verify what the other side hears.
- A language-swap control to exchange the two translation targets in one step.
Thanks to Vladimir Vorobyov (@uladzemer) for this contribution — audio diagnostics fix.
- A crash partway through starting a Video/Game or Meeting session could leak the capture device, player, or translator instead of releasing them.
- Engine failover from OpenAI to Gemini now retargets the capture's sample rate (16 kHz vs 24 kHz), instead of playing the source 1.5x slow after the swap.
- A translated turn with no text yet (only the source line captured) was silently dropped from the transcript instead of being kept as source-only.
- Session key/secret storage (
BYOKkeys, the per-install secret, saved transcripts) now writes through unique temp files under a lock, closing a race where two concurrent writes could clobber each other's staging file. SECURITY.mdnow discloses the hash-verified model downloads (speaker labeling, local TTS voices) the open-source build performs on first use, instead of claiming it makes no outbound calls of its own.LICENSEwas missing several sections of the PolyForm Noncommercial 1.0.0 text it references (Distribution License, Notices, Changes and New Works License, Patent License); restored to the complete, official text.
- An advanced, opt-in "allow multiple app instances" setting (Windows only, off by default) for users who explicitly want more than one Voxis process running at once.
- A
QualityGitHub Actions workflow: the pytest suite and ruff run on every push and pull request againstmain(Python 3.11 and 3.13, Windows).
Thanks to Vladimir Vorobyov (@uladzemer) for this contribution too — runtime/storage hardening.