New stem recording system captures 5 time-aligned WAV files (host, caller,
music, sfx, ads) during live shows. Standalone postprod.py processes stems
into broadcast-ready MP3 with gap removal, voice compression, music ducking,
and EBU R128 loudness normalization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Music crossfade: smooth 3-second blend between tracks instead of hard stop/start
- Emotional detection: analyze host mood from recent messages so callers adapt tone
- AI caller summaries: generate call summaries with timestamps for show history
- Returning callers: persist regular callers across sessions with call history
- Session export: generate transcripts with speaker labels and chapter markers
- Caller screening: AI pre-screens phone callers to get name and topic while queued
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add dedicated ad playback system (no loop, own channel)
- Ad channel defaults to 11, saved/loaded with audio settings
- Separate play_ad/stop_ad methods and API endpoints
- Frontend stop button now calls /api/ads/stop instead of stopMusic
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log chunk count and peak audio level on recording stop
- Add null check on _recorded_audio in callback
- Small delay after stopping piggybacked recording for callback to finish
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mute host mic forwarding while TTS is streaming to prevent interleaving
both audio sources into the same playback buffer
- Replace nearest-neighbor downsampling with box-filter averaging on both
server (host mic) and browser (caller mic) for anti-aliased resampling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace per-callback async task spawning with persistent queue-based sender
- Buffer host mic to 60ms chunks (was 21ms) to reduce WebSocket frame rate
- Reduce server ring buffer prebuffer from 150ms to 80ms
- Reduce browser playback jitter buffer from 150ms to 100ms
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a live caller is on air, the host stream already has an InputStream
open. Opening a second one for push-to-talk recording causes a conflict.
Now recording piggybacks on the host stream callback instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reduce capture chunk from 4096 to 640 samples (256ms → 40ms)
- Replace BufferSource scheduling with AudioWorklet playback ring buffer
- Add 80ms jitter buffer with linear interpolation upsampling
- Reduce host mic and live caller stream blocksizes from 4096/2048 to 1024
- Replace librosa.resample with numpy interpolation in send_audio_to_caller
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use persistent callback-based output stream instead of opening/closing per chunk
- Replace librosa.resample with simple decimation in real-time audio callbacks
- Move host stream initialization to background thread to avoid blocking
- Change live caller channel default to 9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>