Compare commits

..

2 Commits

Author SHA1 Message Date
Glenn Thompson ef3e1eab47 Rewrite README.org for current Radiance/Harmony/CL-Streamer architecture
- Document CL-Streamer as our own in-process streaming server
- Remove Icecast/Liquidsoap sections (no longer used)
- Add architecture diagram showing single-process audio pipeline
- Document playlist scheduling, playback state persistence, resume
- Add FDK-AAC shim build instructions
- Update dependencies (Harmony, cl-mixed, CFFI, LAME, FDK-AAC, etc.)
- Add resource usage stats
- Update troubleshooting for common SBCL pathname issues
- Docker now only used for PostgreSQL
2026-03-05 20:22:52 +03:00
Glenn Thompson 770e565027 Fix broken file paths in all 5 scheduler playlists
- underworld-and-friends.m3u: Fix Drexciya (Bubble Chamber mp3, Aqua Worm Hole mp3),
  Model 500 (correct filename 08-model_500-digital_solutions.flac)
- afternoon-orbit.m3u: Fix BoC (dash + mp3), The Orb (mp3 + track numbers),
  Drexciya, Model 500, Vector Lovers (track 11 mp3), Underworld STITI (subdir)
- midnight-ambient.m3u: Fix Bark Psychosis (mp3), Tape Loop Orchestra (NBSP in filename)
- morning-drift.m3u: Fix BoC Kid for Today (dash + mp3)
- evening-descent.m3u: Fix Johann Johannsson (capitalization),
  Tape Loop Orchestra (disc subdir), Brian Eno (curly quote in filename)
2026-03-05 20:13:35 +03:00
6 changed files with 284 additions and 238 deletions

View File

@ -1,10 +1,12 @@
#+TITLE: Asteroid Radio - Internet Radio Streaming Platform
#+AUTHOR: Asteroid Radio Development Team
#+DATE: 2026-01-26
#+DATE: 2026-03-05
* Overview
Asteroid Radio is a complete internet radio streaming platform built with Common Lisp, featuring a hacker-themed terminal aesthetic. The project combines the Radiance web framework with Icecast/Liquidsoap streaming infrastructure to create a full-featured music streaming platform with live broadcasting capabilities.
Asteroid Radio is a complete internet radio streaming platform built entirely in Common Lisp. It combines the [[https://shirakumo.github.io/radiance/][Radiance]] web framework with an in-process audio streaming pipeline powered by [[https://shirakumo.github.io/harmony/][Harmony]], [[https://shirakumo.github.io/cl-mixed/][cl-mixed]], and a custom streaming server called *CL-Streamer*. Everything runs in a single SBCL process — audio decoding, mixing, encoding, HTTP streaming, metadata, playlist scheduling, and the web frontend.
No external streaming services are required. The only external dependency is PostgreSQL for persistent data.
** Project Links
- *Repository*: https://github.com/fade/asteroid
@ -14,188 +16,229 @@ Asteroid Radio is a complete internet radio streaming platform built with Common
* Key Features
** Live Internet Radio Streaming
- Multiple quality streams: 128kbps MP3, 96kbps AAC, 64kbps MP3
- Professional audio processing with crossfading and ReplayGain normalization
- Icecast2 streaming server integration
- Liquidsoap audio pipeline for reliable broadcasting
- Stream queue control for curated programming
- Dual-format simultaneous output: 128kbps MP3 + 128kbps AAC
- Real-time audio decoding via Harmony (FLAC, MP3 via cl-mixed backends)
- Crossfade between tracks (3s overlap, configurable fade-in/fade-out)
- ICY metadata protocol for now-playing information in media players
- Burst-on-connect for instant playback start (~4s of buffered audio)
** CL-Streamer — The Audio Pipeline
CL-Streamer is Asteroid Radio's own native Common Lisp audio streaming server, written from scratch as part of this project. It provides HTTP audio streaming with ICY metadata, dual-format encoding (MP3 + AAC), and real-time audio processing — replacing what previously required separate Icecast and Liquidsoap Docker containers. It lives in the =cl-streamer/= directory and is loaded as an ASDF system within the Asteroid Radio process. See =cl-streamer/README.org= for full technical details.
Key components:
- *streaming-drain* — custom Harmony drain that intercepts mixed audio and feeds it to encoders instead of a sound card
- *MP3 encoder* — LAME via CFFI (=lame-ffi.lisp=)
- *AAC encoder* — FDK-AAC via a C shim that avoids SBCL signal handler conflicts (=fdkaac-shim.c=, =fdkaac-ffi.lisp=)
- *Broadcast buffer* — single-producer multi-consumer ring buffer per mount point; never blocks the encoder
- *ICY metadata* — SHOUTcast-compatible metadata interleaved in the stream
- *HTTP server* — usocket-based, serves =/asteroid.mp3= and =/asteroid.aac= directly
** Playlist Scheduling
- Cron-based playlist scheduler with configurable time slots (=playlist-scheduler.lisp=)
- M3U playlist files with =#EXTINF= metadata (=playlists/= directory)
- Playback state persistence — saves current track/playlist position to disk (=.playback-state.lisp=)
- Automatic resume from saved state on restart
- Sequential playback with crossfade transitions
** Music Library Management
- Database-backed track storage with metadata extraction
- Support for MP3, FLAC, OGG, and WAV formats
- Automatic metadata extraction using taglib
- Support for MP3 and FLAC formats (decoded by cl-mixed backends)
- Automatic metadata extraction using [[https://github.com/psilord/taglib][taglib]] (artist, title, album)
- Track search, filtering, sorting, and pagination
- Recursive directory scanning
** Web Interface
- RADIANCE framework with CLIP templating
- Admin dashboard for library and user management
- Radiance framework with CLIP templating
- Admin dashboard with stream status, listener stats, and library management
- Multiple player modes: inline, pop-out, and persistent frameset
- Live stream integration with embedded player
- Live stream integration with embedded HTML5 audio player
- Responsive design for desktop and mobile
- Role-based access control (Admin/DJ/Listener)
- ParenScript-generated JavaScript (=parenscript/= directory)
- LASS-generated CSS (=static/asteroid.lass=)
** Network Broadcasting
- Dynamic stream URL detection for multi-environment support
- Professional streaming URLs for media players
- Multi-listener support via Icecast2
- Docker-based deployment for easy setup
** Listener Statistics
- In-process listener tracking (no external polling needed)
- Geo IP lookup with caching (=listener-stats.lisp=)
- Per-mount and aggregate listener counts
- GDPR-compliant IP hashing and data retention
* Architecture Changes
* Architecture
** Framework Migration
- Migrated from Hunchentoot to RADIANCE web framework
- Implemented proper domain routing (=/asteroid/=)
- CLIP templating system for dynamic content
- Database abstraction layer for track storage
#+BEGIN_EXAMPLE
┌──────────────────────────────────────────────────────────────┐
│ SBCL Process │
│ │
│ ┌───────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Harmony │──▶│ streaming- │──▶│ MP3 Encoder │ │
│ │ (decode, │ │ drain │ │ (LAME FFI) │──▶│ /asteroid.mp3
│ │ crossfade,│ │ (float→s16 │ └───────────────────┘ │
│ │ mix) │ │ conversion) │ ┌───────────────────┐ │
│ └───────────┘ └──────────────┘──▶│ AAC Encoder │ │
│ ▲ │ (FDK-AAC C shim) │──▶│ /asteroid.aac
│ │ └───────────────────┘ │
│ ┌───────────┐ ┌───────────────────┐ │
│ │ Playlist │ ICY metadata ────▶│ CL-Streamer │ │
│ │ Scheduler │ Listener stats ◀──│ HTTP Server │ │
│ │ (cl-cron) │ │ (usocket) │ │
│ └───────────┘ └───────────────────┘ │
│ │ │
│ ┌───────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Radiance │──▶│ Admin │ │ PostgreSQL │ │
│ │ Web Server │ │ Dashboard │ │ (external) │ │
│ │ (port 8080)│ │ + Player UI │ │ │ │
│ └───────────┘ └──────────────┘ └───────────────────┘ │
└──────────────────────────────────────────────────────────────┘
#+END_EXAMPLE
** Streaming Stack
- *Icecast2*: Streaming server (port 8000) - Docker containerized
- *Liquidsoap*: Audio processing and streaming pipeline - Docker containerized
- *RADIANCE*: Web server and API (port 8080)
- *PostgreSQL*: Database backend (configured, ready for migration)
- *Docker Compose*: Container orchestration
** How Audio Flows
1. *Decode* — Harmony loads a FLAC or MP3 file via cl-mixed-flac or cl-mixed-mpg123
2. *Mix* — during crossfade, two voices play simultaneously through Harmony's mixer
3. *Drain* — the custom =streaming-drain= reads interleaved float samples from the pack buffer
4. *Convert* — floats are converted to signed 16-bit PCM via CFFI
5. *Encode* — PCM is fed to LAME (MP3) and FDK-AAC (AAC) encoders in parallel
6. *Buffer* — encoded bytes are written to per-mount broadcast ring buffers
7. *Serve* — HTTP clients read from their position in the ring buffer with ICY metadata interleaving
** File Structure
#+BEGIN_SRC
asteroid/
├── asteroid.lisp # Main server with RADIANCE routes
├── asteroid.asd # System definition with dependencies
├── asteroid.lisp # Main server, Radiance routes, API endpoints
├── asteroid.asd # ASDF system definition
├── stream-harmony.lisp # Harmony/CL-Streamer integration, playback state
├── playlist-scheduler.lisp # Cron-based playlist scheduling
├── stream-control.lisp # Stream queue management
├── listener-stats.lisp # Listener statistics and geo IP
├── user-management.lisp # User administration
├── playlist-management.lisp # Playlist operations
├── test-server.sh # Automated test suite
├── docker/ # Docker infrastructure
│ ├── docker-compose.yml # Container orchestration
│ ├── asteroid-radio-docker.liq # Liquidsoap config
│ ├── icecast.xml # Icecast configuration
│ └── music/ # Music library mount
├── user-playlists.lisp # User playlist features
├── user-profile.lisp # User profile management
├── track-requests.lisp # Track request system
├── auth-routes.lisp # Authentication routes
├── database.lisp # Database schema and helpers
├── Makefile # Build: compiles SBCL image
├── cl-streamer/ # Audio streaming subsystem
│ ├── cl-streamer.asd # ASDF system definition
│ ├── harmony-backend.lisp # Harmony integration, crossfade, play-list/play-file
│ ├── stream-server.lisp # HTTP streaming server (usocket)
│ ├── buffer.lisp # Broadcast ring buffer
│ ├── encoder.lisp # MP3 encoder (LAME FFI)
│ ├── aac-encoder.lisp # AAC encoder with frame accumulation
│ ├── lame-ffi.lisp # CFFI bindings for libmp3lame
│ ├── fdkaac-ffi.lisp # CFFI bindings for FDK-AAC (via shim)
│ ├── fdkaac-shim.c # C shim for FDK-AAC (avoids SBCL signal conflicts)
│ ├── libfdkaac-shim.so # Compiled shim shared library
│ ├── icy-protocol.lisp # ICY metadata encoding
│ └── README.org # Full CL-Streamer documentation
├── playlists/ # M3U playlist files for the scheduler
├── template/ # CLIP HTML templates
│ ├── front-page.ctml # Main page with live stream
│ ├── admin.ctml # Admin dashboard
│ ├── player.ctml # Web player interface
│ └── users.ctml # User management
├── static/ # CSS and assets
│ └── asteroid.lass # LASS stylesheet
├── parenscript/ # ParenScript JavaScript sources
├── static/ # CSS (LASS) and assets
├── migrations/ # PostgreSQL schema migrations
├── docker/ # Docker config (PostgreSQL only)
├── docs/ # Comprehensive documentation
│ ├── README.org # Documentation index
│ ├── PROJECT-OVERVIEW.org # Architecture overview
│ ├── PROJECT-HISTORY.org # Development timeline
│ ├── INSTALLATION.org # Setup guide
│ └── ... # Additional guides
└── music/ # Music library (local dev)
└── music/ # Music library symlink
#+END_SRC
* Quick Start
** Docker Installation (Recommended)
** Prerequisites
- *SBCL* — Steel Bank Common Lisp
- *Quicklisp* — with Ultralisp distribution (for Harmony, cl-mixed)
- *PostgreSQL* — running instance (Docker or native)
- *System libraries*: =libmp3lame=, =libfdk-aac=, =libflac=, =libmpg123=, =libtagc=
** Building the FDK-AAC Shim
CL-Streamer uses a thin C shim to call FDK-AAC, avoiding SBCL signal handler conflicts that cause recursive SIGSEGV when calling FDK-AAC directly via CFFI. The compiled =libfdkaac-shim.so= is included in the repository, but if you need to rebuild it (e.g. after updating =libfdk-aac=):
#+BEGIN_SRC bash
cd cl-streamer
gcc -shared -fPIC -o libfdkaac-shim.so fdkaac-shim.c -lfdk-aac
#+END_SRC
The shim is loaded automatically at ASDF system load time from the =cl-streamer/= directory — no installation or =LD_LIBRARY_PATH= configuration needed.
** Build and Run
#+BEGIN_SRC bash
# Clone repository
git clone https://github.com/fade/asteroid
cd asteroid/docker
cd asteroid
# Start all services
docker compose up -d
# Start PostgreSQL (if using Docker)
cd docker && docker compose up -d postgres && cd ..
# Verify streams are working
curl -I http://localhost:8000/asteroid.mp3
curl -I http://localhost:8000/asteroid.aac
curl -I http://localhost:8000/asteroid-low.mp3
# Build the SBCL image
make
# Run (set ASTEROID_STREAM_URL to the stream server address)
ASTEROID_STREAM_URL=http://localhost:8000 ./asteroid
#+END_SRC
On startup, Asteroid will:
1. Start the Radiance web server on port 8080
2. Start the CL-Streamer HTTP server on port 8000
3. Initialise the Harmony audio pipeline with MP3 + AAC encoders
4. Connect to PostgreSQL and load the playlist schedule
5. Resume playback from saved state (if =.playback-state.lisp= exists)
6. Begin streaming audio on =/asteroid.mp3= and =/asteroid.aac=
** Access Points
- *Web Interface*: http://localhost:8080/
- *Admin Panel*: http://localhost:8080/admin
- *High Quality MP3*: http://localhost:8000/asteroid.mp3 (128kbps)
- *High Quality AAC*: http://localhost:8000/asteroid.aac (96kbps)
- *Low Quality MP3*: http://localhost:8000/asteroid-low.mp3 (64kbps)
- *Icecast Admin*: http://localhost:8000/admin/ (admin/asteroid_admin_2024)
- *MP3 Stream*: http://localhost:8000/asteroid.mp3 (128kbps)
- *AAC Stream*: http://localhost:8000/asteroid.aac (128kbps)
* Playlist Scheduling
Playlists are M3U files in the =playlists/= directory. The scheduler (=playlist-scheduler.lisp=) uses =cl-cron= to switch playlists at configured times.
** Schedule Configuration
The schedule is stored in the database and loaded on startup. Example schedule:
| Time (UTC) | Playlist | Description |
|------------+------------------------+--------------------------------|
| 00:00 | midnight-ambient.m3u | Deep, dark ambient |
| 06:00 | morning-drift.m3u | Lighter, awakening ambient |
| 12:00 | afternoon-orbit.m3u | Mid-energy floating ambient |
| 13:00 | underworld-and-friends | Techno, electro, progressive |
| 18:00 | evening-descent.m3u | Winding down transitional |
** M3U Format
Playlists use =#EXTINF= metadata and =/app/music/= prefixed paths (rewritten to local library path at load time):
#+BEGIN_SRC
#EXTM3U
#PLAYLIST:Underworld & Friends
#EXTINF:-1,Underworld - Born Slippy (Nuxx)
/app/music/Underworld - Second Toughest In The Infants (flac)/Second Toughest In The Infants (CD2)/01 Born Slippy (Nuxx).flac
#EXTINF:-1,Orbital - Halcyon + On + On
/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Halcyon + On + On.mp3
#+END_SRC
** Playback State Persistence
The current track and playlist position are saved to =.playback-state.lisp= periodically. On restart, playback resumes from the saved position rather than restarting the playlist from the beginning.
* Music Library Management
** Adding Music
1. *Copy files*: Place MP3/FLAC files in =docker/music/= directory
2. *Access admin panel*: Navigate to =http://localhost:8080/admin=
3. *Scan library*: Click "Scan Library" to index new tracks
4. *Metadata extraction*: Track information automatically extracted
5. *Stream queue*: Optionally add tracks to broadcast queue
** Library Scanning
1. Recursive directory scanning of music folder
2. Metadata extracted using taglib (title, artist, album, duration)
3. Database records created with file paths and metadata
4. Tracks immediately available for playback and streaming
5. Supports nested folder structures
1. Place MP3/FLAC files in the music library directory (symlinked from =music/library/=)
2. Navigate to the admin panel at =http://localhost:8080/admin=
3. Click "Scan Library" to index new tracks
4. Metadata (artist, title, album) is automatically extracted via taglib
** Supported Formats
- *MP3*: Primary format, best compatibility
- *FLAC*: Lossless audio, high quality
- *OGG*: Open source format
- *WAV*: Uncompressed audio
- *FLAC* — decoded by cl-mixed-flac (via libflac)
- *MP3* — decoded by cl-mixed-mpg123 (via libmpg123)
* Icecast2 Integration
** Configuration
- *Server*: localhost:8000 (Docker container)
- *Mount points*: =/asteroid.mp3=, =/asteroid.aac=, =/asteroid-low.mp3=
- *Password*: =H1tn31EhsyLrfRmo= (configured in Docker setup)
- *Formats*: MP3 128kbps, AAC 96kbps, MP3 64kbps
** Docker Setup
Icecast2 runs in a Docker container - no manual installation needed.
#+BEGIN_SRC bash
# Managed via docker-compose
cd docker
docker compose up -d icecast
#+END_SRC
** Stream Access
- *High Quality MP3*: =http://localhost:8000/asteroid.mp3= (128kbps)
- *High Quality AAC*: =http://localhost:8000/asteroid.aac= (96kbps)
- *Low Quality MP3*: =http://localhost:8000/asteroid-low.mp3= (64kbps)
- *Admin interface*: =http://localhost:8000/admin/= (admin/asteroid_admin_2024)
- *Statistics*: =http://localhost:8000/status.xsl=
* Liquidsoap Integration
** Docker Configuration
Liquidsoap runs in a Docker container with configuration in =docker/asteroid-radio-docker.liq=
** Key Features
- *Multiple outputs*: Generates 3 simultaneous streams (MP3 128k, AAC 96k, MP3 64k)
- *Audio processing*: Crossfading, normalization, ReplayGain
- *Stream queue*: Reads from M3U playlist for curated programming
- *Telnet control*: Remote control interface on port 1234
- *Metadata*: Broadcasts track information to listeners
** Management
#+BEGIN_SRC bash
# Start Liquidsoap container
cd docker
docker compose up -d liquidsoap
# View logs
docker compose logs -f liquidsoap
# Restart streaming
docker compose restart liquidsoap
#+END_SRC
** Telnet Control
#+BEGIN_SRC bash
# Connect to Liquidsoap
telnet localhost 1234
# Or use netcat for scripting
echo "request.queue" | nc localhost 1234
echo "request.skip" | nc localhost 1234
#+END_SRC
** Path Mapping
In Docker deployments, music paths use =/app/music/= prefix. In local development, =music/library/= is a symlink to the actual music directory. The M3U playlist loader rewrites paths accordingly.
* User Management
** Roles
- *Admin*: Full system access, user management, stream control
- *Admin*: Full system access, user management, stream control, skip tracks
- *DJ*: Content management, playlist creation, library access
- *Listener*: Basic playback and personal playlists
@ -204,23 +247,15 @@ echo "request.skip" | nc localhost 1234
- Password: =asteroid123=
- ⚠️ Change default password after first login
** User Administration
- Create/manage users via admin panel
- Role-based access control
- User profiles and preferences
- Session management
* Player Modes
** Inline Player
- Embedded in web pages
- Standard HTML5 audio controls
- Queue management
- HTML5 audio with stream auto-reconnect
** Pop-Out Player
- Standalone player window
- Independent from main browser window
- Persistent across page navigation
** Frameset Player
- Bottom-frame persistent player
@ -229,25 +264,16 @@ echo "request.skip" | nc localhost 1234
* API Endpoints
Asteroid Radio provides a comprehensive REST API with 90+ endpoints.
** Status & Authentication
** Status & Streaming
- =GET /api/asteroid/status= - Server status
- =GET /api/asteroid/auth-status= - Authentication status
- =GET /api/asteroid/icecast-status= - Streaming status
- =GET /api/asteroid/icecast-status= - Stream status (now-playing, listeners; name kept for frontend compatibility)
- =POST /api/asteroid/stream/skip= - Skip current track (admin)
** Track Management
- =GET /api/asteroid/tracks= - List all tracks
- =GET /api/asteroid/admin/tracks= - Admin track listing
- =POST /api/asteroid/admin/scan-library= - Scan music library
** Player Control
- =GET /api/asteroid/player/status= - Player status
- =POST /api/asteroid/player/play= - Play track
- =POST /api/asteroid/player/pause= - Pause playback
- =POST /api/asteroid/player/stop= - Stop playback
- =POST /api/asteroid/player/resume= - Resume playback
** Playlist Management
- =GET /api/asteroid/playlists= - List user playlists
- =POST /api/asteroid/playlists/create= - Create playlist
@ -264,49 +290,52 @@ See =docs/API-ENDPOINTS.org= for complete API documentation.
* Database
** Current: Radiance DB
- File-based database abstraction
- Tracks, users, playlists, sessions
- Suitable for development and small deployments
** PostgreSQL (Configured)
- Docker container ready
- Full schema defined
- Migration pending
- See =docs/POSTGRESQL-SETUP.org= for details
* Documentation
Comprehensive documentation available in the =docs/= directory:
- *README.org* - Documentation index
- *PROJECT-OVERVIEW.org* - Architecture and features
- *PROJECT-HISTORY.org* - Development timeline and milestones
- *INSTALLATION.org* - Complete installation guide
- *DEVELOPMENT.org* - Developer setup and guidelines
- *DOCKER-STREAMING.org* - Docker streaming infrastructure
- *API-ENDPOINTS.org* - REST API reference
- *STREAM-CONTROL.org* - Stream queue management
- *USER-MANAGEMENT-SYSTEM.org* - User administration
- *PLAYLIST-SYSTEM.org* - Playlist functionality
- *TESTING.org* - Automated testing guide
- *POSTGRESQL-SETUP.org* - Database setup
** PostgreSQL
- Primary database for tracks, users, playlists, sessions, schedule, listener stats
- Docker container or native installation
- Schema managed via migrations in =migrations/= directory
- Connection configured in =config/radiance-postgres.lisp=
- See =docs/POSTGRESQL-SETUP.org= for setup details
* Dependencies
** Lisp Dependencies
- =radiance= - Web framework
- =harmony= - Audio framework (decode, mix, effects)
- =cl-mixed= / =cl-mixed-flac= / =cl-mixed-mpg123= - Low-level audio mixing and decoding
- =r-clip= - CLIP templating
- =lass= - CSS preprocessing
- =parenscript= - Lisp-to-JavaScript compiler
- =cl-json= - JSON handling
- =alexandria= - Common Lisp utilities
- =bordeaux-threads= - Portable threading
- =local-time= - Time handling
- =taglib= - Audio metadata extraction
- =cl-cron= - Cron-style job scheduling
- =cffi= - C foreign function interface
- =usocket= - Socket networking
- =i-postmodern= - PostgreSQL interface (Radiance)
- =ironclad= - Cryptographic hashing (passwords, IP hashing)
- =log4cl= - Logging
- =slynk= - Sly/SLIME interactive development
** System Dependencies (Docker)
- Docker Engine 20.10+
- Docker Compose 2.0+
- All streaming components containerized
** System Libraries
- =libmp3lame= - MP3 encoding (LAME)
- =libfdk-aac= - AAC encoding (FDK-AAC, accessed via C shim)
- =libflac= - FLAC decoding
- =libmpg123= - MP3 decoding
- =libtagc= - Audio metadata reading (taglib C bindings)
** Infrastructure
- *PostgreSQL* - only external service required
- *Docker* - optional, for running PostgreSQL
* Resource Usage
Running on a single SBCL process:
- *RAM*: ~320MB RSS (real-time audio decode + dual MP3/AAC encode)
- *CPU*: ~8% total (Harmony thread is ~5%)
- *Threads*: ~18
* Testing
@ -336,6 +365,9 @@ Comprehensive documentation available in the =docs/= directory:
4. Run test suite
5. Submit pull request
** Interactive Development
Asteroid starts a Slynk server on port 4009. Connect from Emacs/Sly for live REPL access to the running system — inspect streams, modify playlists, debug audio issues without restarting.
** Community
- *IRC*: #asteroid.music on irc.libera.chat
- *Issues*: GitHub issue tracker
@ -348,32 +380,45 @@ Comprehensive documentation available in the =docs/= directory:
* Troubleshooting
** Docker Issues
#+BEGIN_SRC bash
# Check container status
docker compose ps
# View logs
docker compose logs icecast
docker compose logs liquidsoap
# Restart services
docker compose restart
#+END_SRC
** Stream Not Playing
- Verify containers are running
- Check music files exist in =docker/music/=
- Test stream URLs with curl
- Review Liquidsoap logs
- Check that the process is running and CL-Streamer started (look for "CL-Streamer started on port 8000" in logs)
- Test stream URLs: =curl -I http://localhost:8000/asteroid.mp3=
- Check for audio file errors in the log (missing files, unsupported formats)
- Verify music library symlink: =ls -la music/library/=
** SBCL Pathname Issues
File paths containing square brackets (e.g. =[WEB FLAC]=) can cause =SIMPLE-ARRAY CHARACTER= errors because SBCL's =pathname= function interprets brackets as wildcard patterns. CL-Streamer uses =sb-ext:parse-native-namestring= to avoid this.
** Database Issues
- Check Radiance DB file permissions
- Verify database collections exist
- Review application logs
- Check PostgreSQL is running: =docker compose ps= (if using Docker)
- Verify connection in =config/radiance-postgres.lisp=
- Review application logs for connection errors
** Playback State
- Saved to =.playback-state.lisp= in the project root
- Delete this file to force a fresh start from the scheduled playlist
- Check logs for "Resuming after track..." on startup
For detailed troubleshooting, see documentation in =docs/= directory.
* Documentation
Comprehensive documentation available in the =docs/= directory:
- *README.org* - Documentation index
- *PROJECT-OVERVIEW.org* - Architecture and features
- *PROJECT-HISTORY.org* - Development timeline and milestones
- *INSTALLATION.org* - Complete installation guide
- *DEVELOPMENT.org* - Developer setup and guidelines
- *API-ENDPOINTS.org* - REST API reference
- *STREAM-CONTROL.org* - Stream queue management
- *USER-MANAGEMENT-SYSTEM.org* - User administration
- *PLAYLIST-SYSTEM.org* - Playlist functionality
- *TESTING.org* - Automated testing guide
- *POSTGRESQL-SETUP.org* - Database setup
See also =cl-streamer/README.org= for CL-Streamer technical documentation.
* License
See LICENSE file for details.
@ -381,13 +426,14 @@ See LICENSE file for details.
* Acknowledgments
Built with:
- Common Lisp (SBCL)
- Radiance web framework
- Icecast2 streaming server
- Liquidsoap audio processing
- Docker containerization
- [[https://www.sbcl.org/][SBCL]] (Steel Bank Common Lisp)
- [[https://shirakumo.github.io/radiance/][Radiance]] web framework (Shinmera)
- [[https://shirakumo.github.io/harmony/][Harmony]] audio framework (Shinmera)
- [[https://shirakumo.github.io/cl-mixed/][cl-mixed]] audio mixing library (Shinmera)
- [[https://lame.sourceforge.io/][LAME]] MP3 encoder
- [[https://github.com/mstorsjo/fdk-aac][FDK-AAC]] AAC encoder
Special thanks to all contributors and the Common Lisp community.
Special thanks to Yukari Hafner (Shinmera) for Harmony, cl-mixed, and Radiance, and to the Common Lisp community.
* Credits
@ -396,4 +442,4 @@ Special thanks to all contributors and the Common Lisp community.
---
*Last Updated: 2026-01-26*
*Last Updated: 2026-03-05*

View File

@ -6,7 +6,7 @@
#DESCRIPTION:Mid-energy floating ambient for the afternoon hours (12:00-18:00)
#EXTINF:-1,Boards of Canada - Kid for Today
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/01 Kid for Today.flac
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/01 - Kid for Today.mp3
#EXTINF:-1,Orbital - Halcyon + On + On
/app/music/Orbital/1993 - Orbital - Orbital 2 (Brown Album - TRUCD2, 828 386.2)/00. Halcyon + On + On.mp3
#EXTINF:-1,Four Tet - Parallel 1
@ -18,23 +18,23 @@
#EXTINF:-1,Plaid - Sun Electric - Tee (Plaid Mix)
/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/17-Sun_Electric-Tee_(Plaid_Mix).flac
#EXTINF:-1,The Orb - Little Fluffy Clouds
/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/05 Little Fluffy Clouds.flac
/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/01 Little Fluffy Clouds.mp3
#EXTINF:-1,Labradford - S
/app/music/Labradford/1997 - Mi Media Naranja/1 S.flac
#EXTINF:-1,Drexciya - Bubble Metropolis
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/01 Bubble Metropolis.flac
#EXTINF:-1,Drexciya - Bubble Chamber
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/12. Drexciya - Bubble Chamber.mp3
#EXTINF:-1,Clark - Spring But Dark
/app/music/Clark - Death Peak (2017) [FLAC]/01 - Spring But Dark.flac
#EXTINF:-1,Tycho - Rings
/app/music/Tycho - Epoch (Deluxe Version) (2019) [WEB FLAC16-44.1]/09 - Rings.flac
#EXTINF:-1,Boards of Canada - Amo Bishop Roden
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/02 Amo Bishop Roden.flac
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/02 - Amo Bishop Roden.mp3
#EXTINF:-1,FSOL - Sol 7
/app/music/The Future Sound of London - Environment Six (2016 - WEB - FLAC)/07 - Sol 7.flac
#EXTINF:-1,Aphex Twin - CHEETAHT7b
/app/music/Aphex Twin (2016) Cheetah EP [WEB] [FLAC]/Cheetah EP-002-Aphex Twin-CHEETAHT7b.flac
#EXTINF:-1,Model 500 - Digital Solutions
/app/music/Model 500/2015 - Digital Solutions/01 Digital Solutions.flac
/app/music/Model 500/2015 - Digital Solutions/08-model_500-digital_solutions.flac
#EXTINF:-1,Proem - Winter Wolves
/app/music/Proem - 2018 Modern Rope (WEB)/01. Winter Wolves.flac
#EXTINF:-1,Four Tet - Parallel 8
@ -46,7 +46,7 @@
#EXTINF:-1,Kiasmos - Thrown
/app/music/Kiasmos/2014 - Kiasmos/05 - Thrown.flac
#EXTINF:-1,The Orb - Supernova at the End of the Universe
/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/08 Supernova at the End of the Universe.flac
/app/music/The Orb/1991 - The Orb's Adventures Beyond the Ultraworld (Double Album)/03 Supernova at the End of the Universe.mp3
#EXTINF:-1,arovane - komposition no. 1
/app/music/arovane - Wirkung (2020) [WEB FLAC16]/17. arovane - komposition no. 1.flac
#EXTINF:-1,Orbital - Lush 3-1
@ -56,11 +56,11 @@
#EXTINF:-1,Clark - Absence (Bibio Remix)
/app/music/Clark - Feast Beast (2013) [24 Bit WEB FLAC] [16-44]/1.12. Clark - Absence (Bibio Remix).flac
#EXTINF:-1,Drexciya - Aqua Worm Hole
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/03 Aqua Worm Hole.flac
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/11. Drexciya - Aqua Worm Hole.mp3
#EXTINF:-1,FSOL - Electric Pastrol
/app/music/The Future Sound of London - Environment Six (2016 - WEB - FLAC)/16 - Electric Pastrol.flac
#EXTINF:-1,Vector Lovers - Capsule For One
/app/music/Vector Lovers/2005 - Capsule For One/01 - Capsule For One.flac
/app/music/Vector Lovers/2005 - Capsule For One/11 - Capsule For One.mp3
#EXTINF:-1,Plaid - Ricardo Tobar - After The Movie (Plaid Remix)
/app/music/Plaid - Stem Sell (Plaid Remixes) [2021] (WEB - FLAC - Lossless)/21-Ricardo_Tobar-After_The_Movie_(Plaid_Remix).flac
#EXTINF:-1,Aphex Twin - CHEETA2 ms800
@ -74,6 +74,6 @@
#EXTINF:-1,FSOL - Beyond the Field of Vision
/app/music/The Future Sound of London - Environment Six (2016 - WEB - FLAC)/19 - Beyond the Field of Vision.flac
#EXTINF:-1,Underworld - Cowgirl
/app/music/Underworld - Second Toughest In The Infants (flac)/01 - Juanita - Kiteless - To Dream Of Love.flac
/app/music/Underworld - Second Toughest In The Infants (flac)/Second Toughest In The Infants (CD1)/01 Juanita , Kiteless , To Dream Of Love.flac
#EXTINF:-1,Underworld - Everything, Everything
/app/music/Underworld - Everything, Everything (2000 - CD - FLAC)/01 - Juanita-Kiteless.flac

View File

@ -50,7 +50,7 @@
#EXTINF:-1,Kiasmos - Burnt
/app/music/Kiasmos/2014 - Kiasmos/08 - Burnt.flac
#EXTINF:-1,Johann Johannsson - The Theory of Everything
/app/music/Johann Johannsson - The Theory of Everything (2014) [FLAC]/24 - The Theory of Everything.flac
/app/music/Johann Johannsson - The Theory of Everything (2014) [FLAC]/24 - The Theory Of Everything.flac
#EXTINF:-1,Tangerine Dream - Pantha Rhei
/app/music/Tangerine Dream - Ambient Monkeys (flac)/11 Tangerine Dream - Pantha Rhei.flac
#EXTINF:-1,Biosphere - Stordjupta
@ -62,7 +62,7 @@
#EXTINF:-1,Proem - Kids That Hate Live Things
/app/music/Proem - Until Here for Years (n5md, 2019) flac/11 - Kids That Hate Live Things.flac
#EXTINF:-1,Brian Eno - I'm Hardly Me
/app/music/Brian Eno/2022 - ForeverAndEverNoMore/08 I'm Hardly Me.flac
/app/music/Brian Eno/2022 - ForeverAndEverNoMore/08 Im Hardly Me.flac
#EXTINF:-1,Labradford - P
/app/music/Labradford/1997 - Mi Media Naranja/7 P.flac
#EXTINF:-1,Tim Hecker - Starting Over Again
@ -78,4 +78,4 @@
#EXTINF:-1,Biosphere - Tomorrow Then We Will Attend
/app/music/Biosphere - Departed Glories (2016) - FLAC WEB/15 - Tomorrow Then We Will Attend.flac
#EXTINF:-1,Tape Loop Orchestra - The Word On My Lips Is Your Name
/app/music/Tape Loop Orchestra/2012 - The Word On My Lips Is Your Name/01 - The Word On My Lips Is Your Name.flac
/app/music/Tape Loop Orchestra/2012 - The Word On My Lips Is Your Name/Disc 1 - The Word On My Lips Is Your Name/01 - The Word On My Lips Is Your Name.flac

View File

@ -51,8 +51,8 @@
/app/music/Pye Corner Audio/2019 - Hollow Earth (WEB, #GBX032 DL)/09 - Subterranean Lakes.mp3
#EXTINF:-1,Labradford - WR
/app/music/Labradford/1997 - Mi Media Naranja/3 WR.flac
#EXTINF:-1,Bark Psychosis - Hex
/app/music/Bark Psychosis/1994 - Hex/01 The Loom.flac
#EXTINF:-1,Bark Psychosis - The Loom
/app/music/Bark Psychosis/1994 - Hex/01 - bark psychosis - the loom.mp3
#EXTINF:-1,Biosphere - Turned To Stone
/app/music/Biosphere - The Petrified Forest (2017) - CD FLAC/03. Biosphere - Turned To Stone.flac
#EXTINF:-1,Tim Hecker - Winter's Coming
@ -79,7 +79,7 @@
/app/music/Tim Hecker - The North Water Original Score (2021 - WEB - FLAC)/Tim Hecker - The North Water (Original Score) - 14 Twinkle In The Wasteland.flac
#EXTINF:-1,Locrian - Heavy Water
/app/music/Locrian - Infinite Dissolution (2015) - WEB FLAC/08 - Heavy Water.flac
#EXTINF:-1,Tape Loop Orchestra - 1953 Culture Festival
/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/01 - 1953 Culture Festival.flac
#EXTINF:-1,Tape Loop Orchestra - Reel One
/app/music/Tape Loop Orchestra/2009 - 1953 Culture Festival/01 Tape Loop Orchestra - Chapter 1   Reel One.mp3
#EXTINF:-1,Underworld - Everything, Everything
/app/music/Underworld - Everything, Everything (2000 - CD - FLAC)/01 - Juanita-Kiteless.flac

View File

@ -71,8 +71,8 @@
/app/music/The Future Sound of London - Environment Six (2016 - WEB - FLAC)/15 - Imagined Friends.flac
#EXTINF:-1,Biosphere - Lysbotn
/app/music/Biosphere - The Senja Recordings (2019) [FLAC]/11 - Lysbotn.flac
#EXTINF:-1,Boards of Canada - In a Beautiful Place Out in the Country
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/01 Kid for Today.flac
#EXTINF:-1,Boards of Canada - Kid for Today
/app/music/Boards of Canada/In a Beautiful Place Out in the Country/01 - Kid for Today.mp3
#EXTINF:-1,Brian Eno - Making Gardens Out of Silence
/app/music/Brian Eno/2022 - ForeverAndEverNoMore/10 Making Gardens Out of Silence.flac
#EXTINF:-1,Tangerine Dream - Virtue Is Its Own Reward

View File

@ -23,8 +23,8 @@
/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/A1 - Eye Contact.flac
#EXTINF:-1,Boxcutter - Arecibo Message
/app/music/Boxcutter - Arecibo Message (2009) [FLAC]/03 - Boxcutter - Arecibo Message.flac
#EXTINF:-1,Drexciya - Bubble Metropolis
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/01 Bubble Metropolis.flac
#EXTINF:-1,Drexciya - Bubble Chamber
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/12. Drexciya - Bubble Chamber.mp3
#EXTINF:-1,Orbital - Monsters Exist
/app/music/Orbital - Monsters Exist (PledgeMusic Deluxe) (2018) (WEB) [FLAC]/01 - Monsters Exist.flac
#EXTINF:-1,Underworld - Push Upstairs
@ -44,7 +44,7 @@
#EXTINF:-1,The Other People Place - Moonlight Rendezvous
/app/music/The Other People Place/2017 - Lifestyles Of The Laptop Café/B1 - Moonlight Rendezvous.flac
#EXTINF:-1,Model 500 - Digital Solutions
/app/music/Model 500/2015 - Digital Solutions/01 Digital Solutions.flac
/app/music/Model 500/2015 - Digital Solutions/08-model_500-digital_solutions.flac
#EXTINF:-1,Orbital - P.H.U.K
/app/music/Orbital - Monsters Exist (PledgeMusic Deluxe) (2018) (WEB) [FLAC]/04 - P.H.U.K.flac
#EXTINF:-1,Underworld - Pearls Girl
@ -56,7 +56,7 @@
#EXTINF:-1,Boxcutter - SpaceBass
/app/music/Boxcutter - Arecibo Message (2009) [FLAC]/04 - Boxcutter - SpaceBass.flac
#EXTINF:-1,Drexciya - Aqua Worm Hole
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/03 Aqua Worm Hole.flac
/app/music/Drexciya/2013 - Journey Of The Deep Sea Dweller III/11. Drexciya - Aqua Worm Hole.mp3
#EXTINF:-1,Dopplereffekt - Mandelbrot Set
/app/music/Dopplereffekt/2017 - Cellular Automata/07. Mandelbrot Set.flac
#EXTINF:-1,Underworld - Cups