mirror of
https://github.com/Flexpair/mumbling-mole.git
synced 2026-04-19 05:40:56 +00:00
An HTML5 Mumble client for Chrome, Firefox, Edge and now also Safari
- JavaScript 74%
- Vue 14.1%
- Shell 3.5%
- SCSS 3.4%
- Python 3.2%
- Other 1.8%
Bumps [dotenv](https://github.com/motdotla/dotenv) from 17.4.1 to 17.4.2. - [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/motdotla/dotenv/compare/v17.4.1...v17.4.2) --- updated-dependencies: - dependency-name: dotenv dependency-version: 17.4.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|---|---|---|
| .codacy | ||
| .devcontainer | ||
| .github | ||
| .semgrep | ||
| __mocks__ | ||
| __tests__ | ||
| app | ||
| auth-server | ||
| backups | ||
| localize | ||
| scripts | ||
| tests | ||
| themes/MetroMumbleLight | ||
| upstream | ||
| .codacy.yml | ||
| .depcheckrc | ||
| .dockerignore | ||
| .env.test.example | ||
| .gitattributes | ||
| .gitconfig | ||
| .gitignore | ||
| .nvmrc | ||
| .sonarignore | ||
| audit-baseline.json | ||
| build-esbuild.mjs | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| jest.config.js | ||
| jest.setup.js | ||
| jest.text-transformer.cjs | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.js | ||
| README.md | ||
| rebuild-and-restart.sh | ||
| sonar-project.properties | ||
| start-dev-server.sh | ||
| stop-dev-server.sh | ||
🎤 Mumbling Mole
Browser-first Mumble voice chat client – no native dependencies required
Mumbling Mole brings Mumble voice communication to modern browsers via Vue.js 3, Web Audio API with AudioWorklet, and WebSocket tunneling (NOT WebRTC). Built on mumble-web.
v4.0.3 · Vue.js 3.5.25 · esbuild 0.27.0 · 1,477 unit tests
✨ Features
- 🎙️ Browser-native audio – AudioWorklet + Opus via WASM
- 🔌 WebSocket tunneling – TCP over WebSocket (no WebRTC)
- ⚡ Vue.js 3 + Pinia – Modern reactive UI with 7 state stores
- 📦 Fast builds – esbuild compiles in ~0.3s
- 🐳 Docker-ready – Containerized dev and production
- 🔊 Audio loopback – Built-in 440Hz test for validation
🚀 Quick Start
git clone https://github.com/Flexpair/mumbling-mole.git
cd mumbling-mole && npm install
# Development
./start-dev-server.sh # Build + serve at http://local.flexpair.app
npm run build:local # Rebuild + restart server
# Testing
npm test # Full suite: unit + E2E + audit
npm run test:unit # Jest (1,477 tests)
npm run test:loopback:headed # Playwright with visible browser
# Production
npm run build # Clean build (~0.3s)
Test audio: Connect → Click Test → Speak into mic → Hear echo
🏗️ Architecture
┌─────────────────────────────────────────────────────────────┐
│ Main Thread │ Web Worker │
│ • Vue.js 3 + Pinia stores │ • Mumble protocol │
│ • AppState coordinator │ • Opus encoding (WASM) │
│ • AudioContext singleton │ • Channel/user trees │
└────────────────────────────────┴─────────────────────────────┘
│ │
AudioWorklet WebSocket
(48kHz capture) │
└────────────websockify───────┘
↓
Mumble Server (TCP:64738)
Key Files
| Concern | Files |
|---|---|
| Entry/UI | app/index.js → app/components/App.vue |
| State | app/stores/*.js (7 Pinia stores) |
| Audio | voice.js → recorder-worker.js → encode-worker.js |
| Network | worker-client.js ↔ worker.js → mumble-websocket.js |
Audio Pipeline
- Send:
recorder-worker.js(960 samples @ 48kHz) → Opus WASM → WebSocket - Receive: WebSocket → decoder pool → jitter buffer → speakers
- ⚠️ Critical: Sender MUST output 960-sample frames (20ms @ 48kHz)
🐳 Docker
# Production
docker build --target prod -t mumbling-mole:prod \
--build-arg GIT_COMMIT=$(git rev-parse HEAD) .
# Development
docker build --target dev -t mumbling-mole:dev .
| Variable | Description | Default |
|---|---|---|
MUMBLE_SERVER |
Target host:port |
Required |
PORT |
HTTP server port | 80 |
SKIP_TUNNEL |
Disable websockify | false |
🔧 Configuration
Runtime config: app/config.js (defaults) + app/config.local.js (overrides)
window.mumbleWebConfig = {
defaults: { address: 'voice.example.com', port: '443' }
}
Theming: ?theme=MetroMumbleLight or MetroMumbleDark
🐛 Troubleshooting
# Tunnel logs
tail -f /tmp/entrypoint.log
# Audio state (browser console)
audioContextManager.getStats()
- No audio? Check mic permissions (HTTPS required)
- Worker errors? Update BOTH
_dispatchEventANDregisterEventProxy - AudioWorklet? Must be ES5 – no imports/requires
📁 Project Structure
app/
├── index.js # Entry (Pinia + Vue mount)
├── components/ # Vue.js components
├── stores/ # Pinia stores (7 modules)
├── audio/ # AudioWorklet + codec workers
├── worker.js # Web Worker (Mumble protocol)
├── worker-client.js # Main↔Worker bridge
└── mumble-client/ # Vendored protocol client
📚 Documentation
| Document | Purpose |
|---|---|
| .github/copilot-instructions.md | AI coding agent guide |
| tests/README.md | Testing strategy |
| app/audio/README.md | Audio debugging |
| app/stores/README.md | Pinia architecture |
| app/auth/README.md | Auth abstraction |
⚠️ Known Issues
- #201: Unbounded playback queue (memory leak risk)
- #202: No configurable jitter buffer
- #203: Missing Opus PLC (packet loss → clicks)
🤝 Contributing
- Fork →
git checkout -b feature/name - Follow conventions: Pinia stores, Vue 3 Composition API,
useXStore()pattern - Test:
npm test - PR with conventional commits (
feat:,fix:,refactor:)
Critical rules:
- Always
ensureAudioContext(), nevernew AudioContext() - Worker events: update BOTH
_dispatchEventANDregisterEventProxy - Never commit
dist/– it's generated
📄 License
The upstream mumble-web project is licensed under the ISC License - see upstream/LICENSE.
Licensing for modifications in this fork is pending.
🙏 Acknowledgments
- mumble-web – Original project by Jonas Herzig
- MetroMumble – Theme inspiration
Made with ❤️ for the Flexpair community