A production-ready FastAPI application for real-time call monitoring, audio streaming, and recording integration with Asterisk/VICIdial systems. Features WebSocket-based live audio streaming, automatic recording via snoop channels, and cloud storage integration with Supabase.
- Real-Time Call Monitoring - Monitor active calls via Asterisk ARI (Asterisk REST Interface)
- Live Audio Streaming - WebSocket-based real-time audio streaming to web dashboard
- Intelligent Recording - Automatic recording using snoop channels (works with Dial() bridges)
- VICIdial Integration - Seamless integration with VICIdial without dialplan modifications
- MeetMe Conference Support - Automatic carrier channel movement to MeetMe conferences
- Cloud Storage - Audio chunks stored in Supabase Storage for scalability
- REST API - Complete REST API for call management and metadata
- Web Dashboard - Real-time monitoring dashboard with live audio visualization
- Architecture
- How It Works
- Prerequisites
- Installation
- Configuration
- Usage
- API Documentation
- Code Structure
- Deployment
- Troubleshooting
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Asterisk ββββββββ Audio Bridge ββββββββ Supabase β
β (ARI/Stasis) β β (FastAPI) β β (DB + Storage) β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β
β WebSocket
βΌ
ββββββββββββββββββββ
β Web Dashboard β
β (index.html) β
ββββββββββββββββββββ
- Asterisk Monitor Service - Monitors call events and manages recordings
- ARI Client - Interfaces with Asterisk REST API
- Logger Service - Handles database and storage operations
- WebSocket Manager - Manages real-time audio streaming connections
- Audio Processor - Processes and formats audio chunks
-
Channel Detection
- Asterisk channel enters Stasis application (
audio-bridge) - Monitor service receives
StasisStartevent via WebSocket - System identifies channel type (agent/carrier) and context
- Asterisk channel enters Stasis application (
-
Recording Strategy
- For Dial() Bridges (VICIdial default):
- Creates a "snoop channel" to monitor the original channel
- Starts recording on snoop channel (in Stasis, recordable)
- Original channel continues in Dial() bridge unaffected
- For Stasis Channels:
- Direct recording on the channel
- For MeetMe Conferences:
- Detects MeetMe room from channel variables
- Moves carrier channel to MeetMe conference
- VICIdial handles MeetMe recording
- For Dial() Bridges (VICIdial default):
-
Audio Processing
- Audio chunks retrieved from Asterisk recordings
- Processed through AudioProcessor for format conversion
- Uploaded to Supabase Storage bucket
- Metadata stored in Supabase database
-
Real-Time Streaming
- Chunks broadcast via WebSocket to connected clients
- Dashboard receives and plays audio in real-time
- Supports multiple concurrent connections
The Challenge: VICIdial uses Dial() which creates bridges that aren't Stasis-managed. Redirecting channels to Stasis would disrupt active calls.
The Solution: ARI snoop channels can monitor and record channels even when they're in Dial() bridges. The snoop channel:
- Is in Stasis (can be recorded)
- Doesn't affect the original channel
- Receives audio from both directions (spy: "both")
Implementation: See app/services/asterisk_monitor.py:
- Lines 1054-1090: Snoop channel creation for Dial() bridges
- Lines 1333-1366: Polling mechanism for missed channels
The system automatically detects MeetMe conferences and ensures proper integration:
-
Room Detection - Extracts MeetMe room number from:
- Channel variables (
MEETME_ROOMNUM,CONFBRIDGE, etc.) - Channel name patterns (e.g.,
Local/8600051@default) - Dialplan context/exten
- Channel variables (
-
Channel Movement - Uses ARI to move carrier channel to MeetMe:
await ari_client.add_channel_to_meetme(carrier_channel_id, meetme_room)
-
VICIdial Compatibility - Sets
DIALSTATUS=ANSWERso VICIdial shows call as LIVE
Implementation: See app/services/asterisk_monitor.py lines 276-286, 333-344, 371-384
- Python 3.9+
- Asterisk 13+ with ARI enabled
- PostgreSQL database (Supabase recommended)
- Supabase account (for Storage)
- Node.js (optional, for development)
git clone <repository-url>
cd phase1-audio-bridgepython3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activatepip install --upgrade pip
pip install -r requirements.txtCopy .env.example to .env and configure:
cp .env.example .env
nano .env # Or use your preferred editor# Database (Supabase PostgreSQL)
DATABASE_URL=postgresql://postgres.user:password@host:5432/postgres
# Supabase Storage
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-service-role-key
SUPABASE_STORAGE_BUCKET=audio-bucket
# Asterisk ARI
ASTERISK_HOST=your-asterisk-server.com
ASTERISK_PORT=8088
ASTERISK_USERNAME=asterisk
ASTERISK_PASSWORD=your-ari-password
ASTERISK_WS_URL=ws://your-asterisk-server.com:8088/ari/events?app=audio-bridge&subscribeAll=true
ASTERISK_APP_NAME=audio-bridge
ENABLE_WEBSOCKET_MONITOR=true# Audio Processing
AUDIO_CHUNK_SIZE=4096
AUDIO_SAMPLE_RATE=8000
AUDIO_CHANNELS=1
AUDIO_FORMAT=PCM
# Logging
LOG_LEVEL=INFO
LOG_AUDIO_STREAMS=true
# Server
HOST=0.0.0.0
PORT=8000-
Create Storage Bucket:
- Go to Supabase Dashboard β Storage
- Create bucket named
audio-bucket(or your preferred name) - Set as public if needed, or configure policies
-
Get Service Role Key:
- Dashboard β Settings β API
- Copy
service_rolekey (notanonkey) - Add to
.envasSUPABASE_KEY
Enable ARI on your Asterisk server:
-
Create
/etc/asterisk/ari.conf:[general] enabled = yes pretty = yes allowed_origins = * [asterisk] type = user read_only = no password = your_secure_password
-
Configure
/etc/asterisk/http.conf:[general] enabled=yes bindaddr=0.0.0.0 bindport=8088
-
Restart Asterisk:
sudo systemctl restart asterisk
See docs/ASTERISK_CONNECTION_SETUP.md for detailed instructions.
python run.py
# Or
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000- Web Dashboard:
http://localhost:8000/static/index.html - API Docs:
http://localhost:8000/docs - Health Check:
http://localhost:8000/api/health
See docs/DEPLOYMENT_INSTRUCTIONS.md for production deployment guide.
GET /api/healthReturns service health status.
GET /api/calls?limit=50Returns list of calls with metadata.
GET /api/calls/{call_id}Returns detailed information about a specific call.
POST /api/stream/audio/{call_id}
Content-Type: application/octet-stream
X-Ingest-Token: your-token (optional)Alternative endpoint for ingesting audio streams.
ws://localhost:8000/ws/audio/{call_id}
Real-time audio streaming WebSocket connection for a specific call.
Message Format:
- Server β Client: JSON with base64-encoded audio chunks
- Client β Server: Connection management messages
phase1-audio-bridge/
βββ app/
β βββ api/ # API endpoints
β β βββ websocket.py # WebSocket streaming
β β βββ calls.py # REST API for calls
β β βββ health.py # Health check
β β
β βββ services/ # Core business logic
β β βββ asterisk_monitor.py # Main monitoring service
β β βββ asterisk_client.py # ARI client wrapper
β β βββ logger.py # Database & storage
β β βββ audio_processor.py # Audio processing
β β
β βββ database/ # Database layer
β β βββ connection.py # DB connection setup
β β βββ models.py # SQLAlchemy models
β β
β βββ utils/ # Utilities
β β βββ supabase_storage.py # Supabase Storage client
β β βββ audio_utils.py # Audio utilities
β β
β βββ models/ # Pydantic models
β β βββ call.py
β β βββ audio.py
β β
β βββ config.py # Configuration management
β βββ main.py # FastAPI application
β
βββ static/
β βββ index.html # Web dashboard
β
βββ scripts/ # Deployment & utility scripts
β βββ deploy.sh
β βββ setup_asterisk_ari.sh
β βββ ...
β
βββ docs/ # Documentation
βββ requirements.txt # Python dependencies
βββ README.md # This file
app/services/asterisk_monitor.py (Main Monitoring Service)
- Monitors Asterisk events via WebSocket
- Handles call lifecycle (start, recording, end)
- Creates snoop channels for Dial() bridge recording
- Integrates with MeetMe conferences
- Polling mechanism for missed channels
app/services/asterisk_client.py (ARI Client)
- Wraps Asterisk REST API calls
- Channel, bridge, and recording management
- Snoop channel creation
- MeetMe conference operations
app/services/logger.py (Data Logging)
- Stores call metadata in database
- Uploads audio chunks to Supabase Storage
- Manages chunk metadata and relationships
app/utils/supabase_storage.py (Storage Client)
- Supabase Storage client initialization
- Async upload operations
- Public URL generation
app/api/websocket.py (WebSocket Manager)
- Manages WebSocket connections
- Broadcasts audio chunks to clients
- Connection lifecycle management
static/index.html (Web Dashboard)
- Real-time call monitoring interface
- WebSocket client for audio streaming
- Audio visualization and playback
calls - Call metadata
call_id(primary key)channel_id,caller_number,callee_numberstatus,start_time,end_time,duration
audio_streams - Audio stream metadata
stream_id(primary key)call_id(foreign key)format,sample_rate,channels
audio_chunks - Audio chunk metadata
id(primary key)call_id,stream_id(foreign keys)chunk_index,data_path(Supabase Storage URL)size,timestamp
-
Server Requirements:
- Ubuntu 20.04+ or similar
- Python 3.9+
- PostgreSQL client libraries
-
Deploy Code:
rsync -avz --exclude='venv' --exclude='.env' ./ user@server:/opt/audio-bridge/
-
Setup Systemd Service:
sudo cp scripts/audio-bridge.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable audio-bridge sudo systemctl start audio-bridge -
Configure Nginx:
sudo cp scripts/nginx.conf /etc/nginx/sites-available/audio-bridge sudo ln -s /etc/nginx/sites-available/audio-bridge /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx
See docs/DEPLOYMENT_INSTRUCTIONS.md for complete deployment guide.
No audio chunks being uploaded
# Check Supabase credentials
grep SUPABASE .env
# Check logs for upload errors
journalctl -u audio-bridge | grep -i "upload\|supabase"Calls not appearing in dashboard
# Verify WebSocket connection
journalctl -u audio-bridge | grep -i "websocket\|stasis"
# Check ARI connection
curl -u asterisk:password http://asterisk-server:8088/ari/asterisk/infoRecordings not starting
# Check snoop channel creation
journalctl -u audio-bridge | grep -i "snoop"
# Verify channel events
journalctl -u audio-bridge | grep -i "channel.*created\|channel.*entered"Enable debug logging in .env:
LOG_LEVEL=DEBUG
DEBUG=truesystemctl status audio-bridge
journalctl -u audio-bridge -f # Follow logs- Supabase Service Role Key: Keep secure, never commit to git
- ARI Password: Strong password, restricted access
- Environment Variables: Use
.envfile (not committed) - WebSocket: Consider adding authentication tokens
- Storage Bucket: Configure appropriate access policies
- Migrated from filesystem storage to Supabase Storage
- Audio chunks now stored in cloud bucket
- Database
data_pathfield stores Storage URLs - Improved scalability and reliability
Migration Notes:
- Backward compatible (existing file paths still work)
- Requires Supabase Storage bucket setup
- See Configuration section for setup instructions
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with FastAPI
- Uses Asterisk ARI
- Storage powered by Supabase
For issues and questions:
- Check Troubleshooting section
- Review documentation in
docs/directory - Check service logs:
journalctl -u audio-bridge -f
Version: 1.0.0
Last Updated: January 2025