Pocket TTS Browser Engine
July 4, 2026 ยท View on GitHub
Pocket TTS Browser Engine is a fully local text-to-speech extension stack for Chrome and Edge. It exposes Pocket TTS voices through the browser TTS API so extensions and websites that already use chrome.tts can speak through a local audio.cpp server without any cloud API, subscription, or token cost.
What We Built
This project has four main parts:
- A Manifest V3 browser extension in extension that registers Pocket voices with
chrome.ttsEngine. - A local
audio.cppinference server that serves Pocket TTS audio overhttp://127.0.0.1:8080. - A native messaging bridge installer in scripts that registers a per-user native host in Windows for Chrome and Edge.
- A browser UI for status, testing, bridge validation, side panel controls, and installer ID management.
Current Capabilities
- Registers 8 Pocket voices for Chrome and Edge.
- Verifies local server health from the extension UI.
- Verifies native messaging registration in
HKCUfor both Chrome and Edge. - Supports popup controls and a full side-panel UI based on
options.html. - Plays speech entirely locally using Pocket TTS through
audio.cpp. - Supports Microsoft Read Aloud style chunked
onSpeaktraffic with queued fallback playback. - Supports one-click native bridge self-update from the side panel after the first bridge install.
- Supports custom local reference voices cloned from a short WAV sample, with good results from about 10 seconds of clean audio.
Prerequisites
Before this extension can speak, you need a working local audio.cpp build on the same Windows machine.
Required pieces:
audiocpp_server.exeaudiocpp_cli.exe- Pocket TTS model files
- a valid
server.json
The current extension defaults expect these paths:
C:\Projects\audio.cpp\build\windows-cuda-release\bin\audiocpp_server.exe
C:\Projects\audio.cpp\build\windows-cuda-release\bin\audiocpp_cli.exe
C:\Projects\audio.cpp\server.json
C:\Projects\audio.cpp\models\pocket-tts
Default local server endpoint:
http://127.0.0.1:8080
Important:
audio.cppproduces both the server and the CLI from the same build tree.- Built-in Pocket voices use the HTTP server on
127.0.0.1:8080. - Custom reference voices use
audiocpp_cli.exethrough the native bridge. - This repo does not build
audio.cppfor you. It expects those binaries and models to already exist. - The local server URL can be changed in the extension UI if your
audio.cppserver runs on a different localhost port. - The server EXE path, CLI EXE path,
server.jsonpath, and Pocket model path can all be changed in the extension UI.
Runtime Model
There are two local synthesis paths:
- Built-in Pocket voices
- Browser TTS request -> extension -> local
audiocpp_server.exeover HTTP
- Custom reference voices
- Browser TTS request -> extension -> native messaging host -> local
audiocpp_cli.exe --voice-ref - You can add a custom local voice in the UI by uploading a short clean WAV sample; about 10 seconds is a practical reference length.
Both paths are local-only when you are using Pocket voices from this extension.
Architecture
Extension
The extension service worker in background.js handles:
- Voice registration and voice mapping.
- Native messaging calls for bridge status and server launch.
- Browser TTS requests through both:
chrome.ttsEngine.onSpeakWithAudioStreamchrome.ttsEngine.onSpeak
The stream path is present for browsers that route TTS through onSpeakWithAudioStream.
The production fallback path currently matters most: Chrome/Edge often routes requests through onSpeak, especially from consumers like Microsoft Read Aloud. In that case the extension fetches WAV audio from the local Pocket TTS server and plays it through an offscreen document.
Offscreen Playback
Because MV3 service workers do not have direct DOM audio playback, the extension uses:
This offscreen document receives WAV bytes from the service worker and plays them using Web Audio.
Native Messaging Bridge
The native bridge consists of:
The installer:
- Compiles the native host into
%LOCALAPPDATA%\PocketTTSEngine\native-host - Writes the manifest for
com.pockettts.engine - Registers it in:
HKCU\Software\Google\Chrome\NativeMessagingHosts\com.pockettts.engineHKCU\Software\Microsoft\Edge\NativeMessagingHosts\com.pockettts.engine
The host supports:
pingstartServerstopSerververifyRegistrationhealth
Why The Final Design Looks Like This
During integration we confirmed a few important browser behaviors:
- The extension is correctly registered when voices appear in
chrome.tts.getVoices. - Chrome/Edge can route speech through
onSpeak, not justonSpeakWithAudioStream. - Microsoft Read Aloud sends many small
onSpeakrequests rapidly, so fallback playback must be queued instead of handled in parallel. - Offscreen playback is the reliable MV3-compatible solution for local audio playback from extension code.
That is why the extension now includes:
- stream support
- queued fallback playback
- offscreen audio
- side panel support
- bridge registration verification
Installation
1. Build or obtain audio.cpp
Make sure your audio.cpp checkout already contains:
build\windows-cuda-release\bin\audiocpp_server.exebuild\windows-cuda-release\bin\audiocpp_cli.exemodels\pocket-tts\...server.json
If your current workflow is:
(venv) (base) PS C:\Projects\audio.cpp> .\build\windows-cuda-release\bin\audiocpp_server.exe --config server.json
that is fine for manual launch and validation.
2. Verify the server can run locally
Manual validation command:
cd C:\Projects\audio.cpp
.\build\windows-cuda-release\bin\audiocpp_server.exe --config server.json
Expected listening endpoint:
http://127.0.0.1:8080
If your server is running on a different local port, you can change it later in:
Server Info->Set Server URL
If your audio.cpp checkout lives somewhere else, you can also update:
Server Info->Runtime Paths->Save Runtime Paths
3. Load the extension unpacked
Load extension as an unpacked extension in Chrome or Edge.
4. Install the native bridge
First install note:
- the very first native bridge install is still a one-time manual bootstrap
- after a current bridge is installed, the side panel button can update it automatically
Run:
powershell -ExecutionPolicy Bypass -File "C:\Projects\pocket-tts-engine\scripts\install-native-bridge.ps1" -ExtensionId "<your-extension-id>"
You can also use the extension UI by entering either:
Install / Update Bridge- a raw extension ID
- a full
chrome-extension://.../URL
Behavior:
- if no compatible bridge is installed yet, the button copies the manual bootstrap command
- once a current bridge is installed, the same button performs a one-click self-update
5. Reload the extension
Reload the unpacked extension after installing or updating the native bridge.
6. Open the side panel and verify status
The options UI should confirm:
- server health
- bridge install status
- Chrome and Edge native host registration
- loaded Pocket voices
Using The UI
Popup
The popup provides:
- quick speech tests
- voice selection
- side panel opening
- a collapsible
Add Installer Extension IDsection - a compact
Runtime Setupsummary for the active local endpoint and executable paths
Side Panel / Options UI
The side panel uses options.html and provides:
- server health checks
- bridge readiness checks
- registry verification for Chrome and Edge
- voice listing
- speech testing
- native bridge install/update flow
- server start via native bridge
- configurable local server URL
- configurable server, CLI, config, and model paths
- runtime path reset back to defaults
Start Server Button
The extension includes a Start Server button in the options UI.
What it does:
- calls the native messaging host
- launches
audiocpp_server.exe --config <server.json> - does not require an activated Python
venv - does not require an activated Conda
baseenvironment
Why that works:
- the extension is starting the compiled
.exe, not a Python entry point - the native host uses
Process.Start(...)directly
The startup flow now validates the configured runtime paths before launch and writes the results into the UI log, so missing EXEs, config files, or model directories show up before a launch attempt is made.
Important caveat:
- the native host currently sets the process working directory to the server executable folder, not the
audio.cpprepo root
That means the button is reliable when:
server.jsonis valid at the configured absolute path, and- any paths inside
server.jsonare absolute, or otherwise resolve correctly from the server executable location
Manual launch from C:\Projects\audio.cpp may still be safer when:
server.jsonuses relative model paths that assume the repo root as the working directory- you are still iterating on your
audio.cpplayout
In other words:
- no, the server does not need
(venv) (base)specifically for runtime - yes, working-directory-sensitive configs can still matter
- the current UI button is useful, but path handling should be considered part of the prerequisite setup
Custom Local Port
By default the extension assumes:
http://127.0.0.1:8080
If your local audio.cpp server listens on a different localhost port, open the side panel and update:
Server Info->Local Server Endpoint->Set Server URL
Supported values are intentionally limited to local HTTP endpoints such as:
http://127.0.0.1:8080http://127.0.0.1:9000http://localhost:8080
This keeps the extension aligned with the local-only privacy model.
Configurable Runtime Paths
The extension no longer requires the default C:\Projects\audio.cpp layout.
Open the side panel and update:
Server Info->Runtime Paths
You can override:
audiocpp_server.exeaudiocpp_cli.exeserver.jsonmodels\pocket-tts
Use:
Save Runtime Pathsto store a custom local layoutReset Defaultsto return to the built-inC:\Projects\audio.cppassumptions
These saved paths are used by:
Start ServerStop Server- custom reference voice synthesis through
audiocpp_cli
Verification Checklist
When the stack is working, the UI should show logs like:
Loaded 8 Pocket voicesServer is healthyBridge ready: 1.x.xBridge registered in Chrome and Edge
And speech requests should produce playback instead of immediate Speech stopped.
Repo Layout
pocket-tts-engine/
|-- README.md
|-- docs/
| |-- bridge-setup.md
| `-- notes.md
|-- extension/
| |-- background.js
| |-- manifest.json
| |-- offscreen.html
| |-- offscreen.js
| |-- options.html
| |-- options.js
| |-- popup.html
| |-- popup.js
| `-- icons/
`-- scripts/
|-- install-native-bridge.ps1
`-- PocketTtsNativeHost.cs
Notes
- This repo contains the browser-side engine and native bridge pieces.
- The Pocket TTS model files and
audio.cppserver binary live outside this repo. - The current implementation is optimized for fully local use on Windows with Chrome/Edge.
- The extension can now be pointed at non-default local
audio.cpplayouts through the side panel runtime path settings.