All notable changes to OpenStudio will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
setup-ai.shone-shot bootstrap script for the AI pipeline. It clones and buildswhisper.cpp, downloads the default Whisper model intomodels/, and prompts for LLM provider settings in.env. Thanks to @avezou (#12).- Regression tests for the AI bootstrap in
tests/test-setup-ai.sh, covering interrupted model downloads and.envfiles holding shell-hostile secrets, alongside the original happy path.
- Interrupted model downloads are no longer cached as success.
setup-ai.shwrote the 1.5 GB model straight to its final path, so a dropped transfer left a truncated file that every later run accepted as valid — and becausecapabilities.jsdetects the model with a bareexistsSync, the UI would un-gate Transcribe over a corrupt model. Downloads now land inmodels/ggml-medium.bin.part, are size-checked, and only then renamed into place. setup-ai.shno longer sources.envas shell. Sourcing executed the file, so aJWT_SECRETcontaining$aborted the script underset -uand a value with spaces ran as a command. Only the threeLLM_*keys are read now, and unrelated secrets are left untouched.setup-ai.shno longer aborts when ffmpeg is missing. Neither ffmpeg nor ffprobe is needed to clone whisper.cpp, build it, or fetch the model, so their absence now warns instead of blocking the entire bootstrap.- The 1.5 GB model download shows progress instead of running silent, which read as a hung script.
whisper.cppis no longer a tracked gitlink. It was pinned as a160000entry with no.gitmodulesbacking, so.gitignorecould never apply to it and every checkout that ransetup-ai.shshowed a permanently dirtymodified: whisper.cpp (new commits). It is now untracked and ignored, which is what the setup script already assumed.
0.3.2 - 2026-05-25
GET /api/capabilitiesendpoint reports availability offfmpeg,ffprobe, thewhisper.cppbinary, the Whisper model file, and the configured LLM endpoint. Results are cached for 60 s so the endpoint is cheap to hit on every page load. The frontend uses this snapshot to gate AI features at render time instead of letting users click into errors.- Capability-gating UI in the studio. Transcribe, Show Notes, and the MP3 format option appear as disabled with an info icon when their prereqs are missing. Clicking opens a modal (
web/js/capability-modal.js) that names the missing dependency and shows the exact install command (ffmpeg via brew/apt, whisper.cpp clone+make, Whisper model wget, LLM env var setup). New files:server/lib/capabilities.js,web/js/capability-modal.js. Modal DOM inweb/index.html, styles inweb/css/studio.css. LLM_API_KEYenv var for cloud OpenAI-compatible providers. When set, the show-notes generator sendsAuthorization: Bearer <key>with every chat completions call — works with OpenAI, Together, Groq, and any OpenAI-compatible shim (including litellm or anthropic-openai-compat for Anthropic). Local providers (LM Studio, Ollama, llama.cpp server) leave it blank and continue to work unchanged.
- README "Optional AI Tooling" section documents the capability-gating UX and ships a copy-pastable
.envsnippet for each common LLM provider (LM Studio, Ollama, OpenAI, Together AI, Groq, plus a note on running an OpenAI-compatible shim in front of Anthropic). Replaces the previous single-block LLM setup paragraph.
0.3.1 - 2026-05-25
- MP3 export now actually produces an MP3. Two bugs were stacked: the
run()helper used by the MP3 transcode inhandleExportCleanwas not imported intoserver.js, and the multipart parser swallowed the trailing boundary marker into the last form field's content — sooutputFormat=mp3silently fell back to WAV even when the import was fixed. Both addressed. POST /api/export/zipendpoint is defined. The route was wired in v0.3.0 but the handler did not exist; calling it returned a 500 with aReferenceError. Now streams a single archive of all uploaded tracks viaarchiver, 500 MB upload cap, preserves filenames fromContent-Disposition.
- Show-notes LLM endpoint is operator-configurable via
LLM_BASE_URLandLLM_MODELenvironment variables. Defaults tohttp://localhost:1234/v1(matches LM Studio's standard port) and modelqwen3.5-35b. Any OpenAI-compatible chat completions API works (LM Studio, Ollama with OpenAI shim, vLLM, llama.cpp server). Previous hardcoded URL is removed. - "Download All" in the studio UI now requests a single zip bundle from the new endpoint. On any failure, falls back to the existing per-track download behavior so users always get their files.
- README rewritten to reflect the actual shipped feature set. Features grouped into Broadcast core, Recording & post-production, Optional AI tooling, and Security & ops. New "Optional AI Tooling" section honestly documents ffmpeg requirement, whisper.cpp setup, model download (~1.5 GB), and LLM configuration. New "Known Gaps" section lists invite-link UI deficit and AI-setup manual steps.
bundleAndDownload()method onrecording-manager.js— POSTs all tracks to/api/export/zip, downloads the returned archive, falls back to per-track on failure.run()helper exported fromserver/lib/audio-cleaner.jsso other server modules can share the spawn wrapper.
- Smoke-tested on a host node process (no Docker): /health, /api/export/zip with 1/2/0 tracks, /api/export/clean WAV default, /api/export/clean with
outputFormat=mp3producing a real MP3 (verified ID3 v2.4, MPEG ADTS layer III, 64 kbps).
0.1.0 - 2026-03-12
Core Infrastructure
- WebRTC signaling server with room management (UUID-based rooms)
- WebSocket communication protocol with ping/pong health checks
- Peer registration and anti-spoofing validation
- Station manifest loading and validation
- Docker Compose deployment configuration (Icecast, coturn, signaling)
- Multi-platform Docker support (macOS ARM64/x86_64, Linux ARM64/x86_64)
Web Studio Client
- Browser-based studio interface with dark theme and responsive design
- Event-driven architecture (SignalingClient, RTCManager, ConnectionManager)
- Perfect Negotiation pattern for WebRTC connections
- Connection retry logic with exponential backoff
- ES modules architecture (no bundler required for MVP)
Audio System
- Web Audio graph with per-participant routing
- AudioContext lifecycle management with browser autoplay compliance
- Per-participant gain controls (0-200% range, smooth ramping)
- Producer-authoritative mute controls (host can mute anyone)
- Program bus mixing with stereo summing
- Real-time volume meter with RMS calculation and color-coded thresholds
Mix-Minus System (Professional broadcast-quality audio)
- O(N) phase-inversion algorithm for efficient mix-minus calculation
- Automatic per-caller mix-minus bus creation/destruction
- WebRTC renegotiation for return feed routing
- Bidirectional return feeds (each peer hears personalized mix)
- HTMLAudioElement playback for return feeds (prevents feedback loops)
- No self-echo (mix-minus excludes own audio)
Icecast Streaming
- MediaRecorder integration with Opus encoding (audio/webm;codecs=opus)
- HTTP PUT streaming via modern Fetch API with TransformStream
- Configurable bitrate options (48/96/128/192 kbps)
- Exponential backoff reconnection (5s → 60s max, 10 max attempts)
- Host-only streaming authorization
Developer Experience
- Dual-mode development workflow (Docker/Local via .env configuration)
- Universal development script (./dev.sh)
- Interactive mode switcher (./dev-switch.sh)
- Automated test suite (6 Playwright tests, 100% passing)
- Comprehensive Memory Bank documentation system
- 20-task YAML-based workflow with X-marker progress tracking
Documentation
- Complete architectural documentation (ARCHITECTURE.md, SIGNAL_FLOW.md, PRD.md)
- Memory Bank system with 8 core files + 25 task documentation files
- Stability testing infrastructure (4 comprehensive test templates)
- Developer workflow guides (CLAUDE.md, quick-start.md)
- Session Stability: 60+ minute sessions validated (automated testing infrastructure)
- Mute Latency: <150ms from button press to audio change (AudioParam linearRampToValueAtTime 50ms)
- Join Latency: <3s for peer connections (automated test validation)
- Supported Participants: 10-15 practical limit (mesh network topology)
- CPU Usage: <30% target on modern laptops (to be validated in manual testing)
- Memory Usage: <500MB for 10-participant sessions (to be validated in manual testing)
Signaling Server (1,742 lines)
- server/server.js - HTTP + WebSocket server with graceful shutdown
- server/lib/logger.js - ISO 8601 timestamped logging
- server/lib/websocket-server.js - WebSocket wrapper with ping/pong protocol
- server/lib/config-loader.js - Configuration management with validation
- server/lib/validate-manifest.js - Station manifest schema validation
- server/lib/message-validator.js - Signaling message validation with anti-spoofing
- server/lib/signaling-protocol.js - Peer registry and message relay
- server/lib/room.js - Room class with participant tracking and broadcast
- server/lib/room-manager.js - Room lifecycle with UUID generation and auto-cleanup
Web Studio Client (4,834 lines: 585 HTML/CSS + 4,249 JS)
- web/index.html - Semantic HTML5 structure with responsive layout
- web/css/reset.css - Modern CSS reset for cross-browser consistency
- web/css/studio.css - Dark theme with CSS Grid and custom properties
- web/js/signaling-client.js - WebSocket client with auto-reconnection (289 lines)
- web/js/rtc-manager.js - RTCPeerConnection manager with getUserMedia (358 lines)
- web/js/connection-manager.js - Perfect Negotiation and retry logic (438 lines)
- web/js/audio-context-manager.js - AudioContext singleton (162 lines)
- web/js/audio-graph.js - Participant node management and routing (309 lines)
- web/js/mix-minus.js - Phase-inversion algorithm (225 lines)
- web/js/return-feed.js - Return feed playback manager (198 lines)
- web/js/program-bus.js - Program bus mixing and MediaStreamDestination (233 lines)
- web/js/volume-meter.js - Canvas-based real-time visualization (227 lines)
- web/js/mute-manager.js - Authority-based mute control (205 lines)
- web/js/stream-encoder.js - MediaRecorder wrapper for Opus encoding (143 lines)
- web/js/icecast-streamer.js - HTTP PUT streaming with reconnection (298 lines)
- web/js/main.js - Application orchestration and event coordination (936 lines)
Testing (2,886 lines: 1,004 server + 1,882 Playwright)
- server/test-signaling.js - 9 signaling protocol tests
- server/test-rooms.js - 9 room management tests
- tests/test-webrtc.mjs - 2-peer WebRTC connection validation
- tests/test-audio-graph.mjs - AudioContext lifecycle and routing
- tests/test-gain-controls.mjs - Per-participant volume controls
- tests/test-program-bus.mjs - Program bus and volume meter
- tests/test-mix-minus.mjs - 3-peer mix-minus validation
- tests/test-return-feed.mjs - Bidirectional return feed routing
- run-pre-validation.sh - Automated test suite runner
Documentation (4,515 lines: 1,515 existing + 3,000 Task 019)
- docs/testing/stability-test-report.md - Comprehensive results template (600 lines)
- docs/testing/performance-benchmarks.md - Detailed metrics template (800 lines)
- docs/testing/stability-test-execution-guide.md - Step-by-step procedures (700 lines)
- docs/testing/monitoring-setup-guide.md - Platform-specific monitoring (900 lines)
- Port conflicts with common development tools (moved from 3000/8000 to 6736/6737)
- Docker multi-platform support for Apple Silicon (custom Alpine-based Icecast image)
- Return feed routing connection state checks (query RTCPeerConnection.connectionState directly)
- Gain controls test element timing (null-safe remote participant checks)
- WebRTC renegotiation race conditions (onnegotiationneeded event handler)
- Perfect Negotiation collision handling (staggered delays: polite 500ms, impolite 2500ms)
- Anti-spoofing validation (all messages validate "from" field matches registered peer ID)
- Non-root container execution (all Docker containers run as dedicated users)
- CORS headers for development APIs (/api/station)
- DTLS-SRTP encryption for all WebRTC media (browser-enforced)
- Development credentials clearly marked (admin/hackme for local testing only)
- Mesh network topology limits practical participant count to 10-15
- Self-mute has architectural limitation (requires microphone track muting, not yet implemented)
- Icecast credentials hard-coded (acceptable for localhost, needs server-side auth for production)
- Safari WebAudio quirks: Requires AudioContext.resume() after permission dialog, zero-gain causes suspension (workaround implemented)
- Manual testing pending for Tasks 016/017/018/019 (automated infrastructure complete)
- No DHT station directory yet (planned for Release 0.2)
- No waiting room/call screening (planned for Release 0.3)
Server (16 packages, 0 vulnerabilities):
- ws ^8.18.0 (WebSocket server)
- jsonwebtoken ^9.0.2 (JWT authentication)
Web (2 packages):
- playwright (automated testing only)
Infrastructure:
- Node.js 18 Alpine (signaling server base image)
- coturn/coturn (STUN/TURN server, multi-platform)
- Custom Alpine Icecast (multi-platform: ARM64 + x86_64)
None (initial release)
None (initial release)
- WebTorrent DHT or libp2p integration
- Ed25519 keypair generation for station identities
- Signed station manifests
- Decentralized station discovery
- Waiting room UI
- Call screening (admit/reject before live)
- Text chat integration
