# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview ISR is a Python audio recording application that captures from multiple simultaneous sources (Icecast/HTTP streams and ALSA soundcard devices) with time-based file splitting. All application code is in two files: `isr.py` (recorder) and `web.py` (archive browser UI). ## Commands ```bash # Run the recorder python isr.py # uses config.ini python isr.py myconfig.ini # custom config file python isr.py --list-devices # list available ALSA devices # Run the web UI python web.py # http://localhost:8080 python web.py --dir recordings # custom recordings directory # Stop: Ctrl+C (or docker compose down) # Install dependencies pip install requests # for stream recording pip install numpy soundfile # for FLAC output and web waveform analysis (optional) # Docker docker compose up -d docker compose logs -f docker compose down ``` ## Architecture ### Audio Backend System - **AudioDevice** — Dataclass: id, name, channels, sample_rate, backend type - **AudioBackend** (ABC) — Abstract base for audio capture backends - **ALSABackend** — Native ALSA support via `arecord` subprocess (the only backend) - **ALSAStream** — Context manager that wraps an `arecord` subprocess and reads PCM in a thread - **AudioSystem** — Discovers available backends, lists devices, resolves device specs ### Recorder Classes - **BaseRecorder** (ABC) — Common settings, `get_next_split_time()`, `generate_filename()`, `record()` interface - **StreamRecorder(BaseRecorder)** — Records HTTP/Icecast streams with format auto-detection and OGG/FLAC header injection - **SoundcardRecorder(BaseRecorder)** — Records from ALSA devices; outputs WAV or FLAC via `_AudioFileWriter` - **_AudioFileWriter** — Unified write/close interface for wave (WAV) and soundfile (FLAC) - **RecorderManager** — Loads config, creates recorders, manages threads, handles shutdown ### Key Implementation Details - ALSA backend spawns `arecord` as a subprocess; raw PCM is read in 100 ms chunks via a reader thread - Device selection: `default`, `monitor` (loopback), partial name match, or exact `hw:X,Y` ID - Thread-safe audio buffering with `threading.Lock()` - OGG/Opus/FLAC headers captured from first ~16 KB of stream and prepended to each split file - File splits aligned to time period boundaries (`get_next_split_time()`) - SIGTERM handled in `main()` so Docker `docker compose down` shuts down cleanly ## Configuration Copy `config.example.ini` to `config.ini`. Each section defines a recording source: - `type = stream` — HTTP/Icecast stream recording - `type = soundcard` — ALSA device recording In Docker, set `output_directory = /recordings` and `log_file = /recordings/recorder.log`. ## Docker Two services share a `./recordings` bind mount: - `recorder` — runs `isr.py`, maps `/dev/snd` for ALSA access - `web` — runs `web.py`, read-only access to recordings, exposes port 8080