Skip to content

Architecture

The module uses a service-oriented architecture. Core services are registered in local_tts.services.yml; Drush commands in drush.services.yml.

PHP services

Service Class Responsibility
local_tts.tts_service TtsService Facade: voice management, health checks, generation coordination
local_tts.tts_generator TtsGenerator Binary execution, chunked processing, WAV to OGG transcoding via ffmpeg
local_tts.cache_manager TtsCacheManager Cache metadata table, file reference counting, metadata saves
local_tts.text_extractor TtsTextExtractor Render-based text extraction with anonymous account switching
local_tts.cron_service TtsCronService Stale metadata cleanup, LRU eviction, orphan file removal
local_tts.batch_service TtsBatchService Batch generation with retry logic and translation-aware queries
local_tts.player_builder TtsPlayerBuilder Player render array with voice controls and accessibility markup

Controllers

Controller Route Purpose
TtsController /local-tts/generate (POST) Validates entity, extracts text, checks cache, queues generation
TtsController /local-tts/status/{cache_key} Polling endpoint: reports "ready" or "processing"
VoicePreviewController /admin/config/media/local-tts/preview Generates voice preview audio samples
TtsCacheController /admin/config/media/local-tts/cache/delete/{cache_key} Deletes individual cache entries

Plugins

Plugin Type Purpose
LocalTtsBlock Block Site-wide TTS player via Block layout
LocalTtsPlayerItem Field type Per-content TTS player field
LocalTtsPlayerFormatter Field formatter Configurable voice/speed/volume settings
TtsGenerationWorker Queue worker Background generation with stale-content detection

Frontend

File Purpose
local-tts-player.js Player constructor: playback, queue polling, scrubber, progress persistence
local-tts-voice-preview.js Voice preview buttons on the Voices settings tab
local-tts-player.css Player layout, CSS custom properties for theming
local-tts-gin.css Gin admin theme integration
local-tts-dxpr-theme.css DXPR Theme integration

The block plugin (LocalTtsBlock) and field formatter (LocalTtsPlayerFormatter) both delegate to TtsPlayerBuilder for the player UI, so the rendering logic is shared.

Key design decisions

  • Server-side text extraction: the generate endpoint never accepts text from the client. It loads the entity server-side and renders it to extract text, preventing content injection.
  • Atomic file writes: generated audio is written to a .part temp file with a random suffix, then atomically renamed to the final path. This prevents concurrent workers from serving half-written files.
  • Reference-counted deletion: multiple metadata rows can reference the same audio file (e.g. same text with different entity sources). Files are only deleted when no metadata rows reference them.
  • Stale-content detection: the queue worker re-extracts text from the entity at processing time and compares it to the queued text, dropping jobs where the content has changed since queuing.