đź“– Read this document in Persian: README_fa.md
Stream live audio from any Asterisk channel to a WebSocket server in just a few lines:
exten => 100,1,Answer()
exten => 100,n,AudioFork(ws://your-server:8080/in,c(SLIN)L(8000)M)
That's it! Your audio stream is now available for real‑time processing (speech‑to‑text, analytics, recording, etc.).
AudioFork is a high‑performance Asterisk module that captures raw audio from a live channel and forwards it in real‑time to a WebSocket server. This unlocks unlimited possibilities for live voice processing, including:
- 🎤 Speech‑to‑Text (STT) transcription
- 📞 Call recording and archiving
- 📊 Sentiment & voice analytics
- 🔊 Acoustic event detection
- 🤖 AI‑powered voice assistants
Built on Asterisk’s powerful ast_audiohook API, it intercepts audio without disrupting the ongoing call. The original app_audiofork (by Nadir Hamid) provided basic SLIN 8 kHz streaming. This enhanced version adds production‑ready features: configurable codecs (SLIN/G722/PCMU/PCMA), sample rates up to 48 kHz, Bearer token authentication, custom HTTP headers, WebSocket subprotocol negotiation, JSON metadata, exponential‑backoff reconnection, header sanitisation, and sub‑100ms interruption – all based on real‑world deployment needs.
| Challenge | How AudioFork Solves It |
|---|---|
| Complex transcoding | Automatically transcodes channel audio to your desired codec/rate. |
| Authentication | Supports Bearer tokens and custom headers (with runtime fallback). |
| Network instability | Intelligent reconnection with exponential backoff keeps the stream alive. |
| Real‑time metadata | Sends JSON metadata before the audio stream for context‑aware processing. |
| Security | Built‑in header sanitisation prevents injection attacks. |
| Performance | Low‑latency, efficient audio streaming with minimal CPU overhead. |
| Feature | Option | Description |
|---|---|---|
| Multiple audio formats | c, L |
SLIN at 8/16/32/48 kHz, G722, PCMU, PCMA. Auto‑transcoded. |
| Custom headers & Bearer auth | H, A |
Sent during WebSocket handshake. Uses ast_websocket_client_create_with_headers when available. |
| WebSocket subprotocol | s |
E.g. audio/raw; defaults to echo. |
| JSON metadata | M |
TEXT frame with channel, caller ID, dialed number, start time, codec, sample rate. |
| Exponential backoff | – | Delay doubles each attempt, capped at 30 s, up to r attempts. |
| Fast interruption | – | StopAudioFork honoured within ~100 ms (nanosleep‑based). |
| Header sanitisation | – | Strips control chars; skips malformed pairs to prevent injection. |
| Metadata retry | – | Up to 3 attempts with 200 ms delay; audio continues on failure. |
- Real‑time Transcription – Feed audio directly to STT engines (e.g., Google Cloud, Azure, Whisper).
- Call Analytics – Analyse customer sentiment or detect keywords during live calls.
- Voice Biometrics – Identify speakers or detect anomalies in real time.
- Recording & Archiving – Store audio streams in cloud storage or local servers.
- AI Assistants – Enable voice‑enabled bots that respond during calls.
- Asterisk 13+ (tested on 18.x / 20.x)
- Loaded modules:
func_periodic_hook(optional),codec_g722,codec_ulaw,codec_alaw,res_websocket - Development headers from your Asterisk source tree
make ASTTOPDIR=/usr/src/asterisk
sudo make install ASTTOPDIR=/usr/src/asterisk# From Asterisk CLI:
module load app_audiofork.so
# Auto‑load at startup – add to /etc/asterisk/modules.conf:
[modules]
load => app_audiofork.soexten => 100,1,Answer()
exten => 100,n,AudioFork(ws://127.0.0.1:8080/in,c(SLIN)L(8000)s(audio/raw)M,A(my-jwt)H(X-Api-Key:abc123))
| Option | Meaning |
|---|---|
c(codec) |
Codec: SLIN, G722, PCMU, PCMA |
L(rate) |
SLIN sample rate: 8000, 16000, 32000, 48000 (ignored for other codecs) |
s(proto) |
WebSocket subprotocol (e.g., audio/raw) |
M |
Enable JSON metadata frame before audio |
A(token) |
Bearer token – adds Authorization: Bearer <token> header |
H(k:v,k:v) |
Custom headers as comma‑separated Key:Value pairs |
R(sec) |
Initial reconnection delay in seconds (backoff base) |
r(n) |
Max reconnection attempts |
T(cert) |
TLS certificate path for secure (wss://) connections |
D(dir) |
Direction: in, out, or both (default) |
Action: AudioFork
Channel: PJSIP/1001-00000001
WsServer: ws://127.0.0.1:8080/in
Options: c(SLIN)L(8000)s(audio/raw)M
ActionID: af1
Action: StopAudioFork
Channel: PJSIP/1001-00000001
ActionID: af2
Action: AudioForkMute
Channel: PJSIP/1001-00000001
Direction: both
State: 1
asterisk -rx "audiofork start PJSIP/1001-00000001 ws://127.0.0.1:8080/in,c(SLIN)L(8000)M"
asterisk -rx "audiofork stop PJSIP/1001-00000001"
asterisk -rx "audiofork list PJSIP/1001-00000001"Asterisk channel
│ ast_audiohook (spy) intercepts audio
â–Ľ
audiofork_thread
│ ast_audiohook_read_frame(format) → transcoded to requested codec/rate
│
├─(once, if M)─▶ JSON metadata as TEXT frame
│
└─(loop)──────▶ audio frames as BINARY frames ──▶ WebSocket server
struct audiofork– per‑session state owned by the fork thread: the audiohook, resolvedast_format, codec/rate/subprotocol/headers, metadata flag, and flags.struct audiofork_ds– datastore attached to the channel holding the WebSocket URL, format, and synchronisation locks. Single‑owner lifetime: the fork thread frees it afterast_cond_wait()and NULLsaudiofork->audiofork_ds;audiofork_free()only frees it when non‑NULL. This prevents double‑free / use‑after‑free.
- Fixed critical double‑free of
audiofork_ds– ownership moved to the fork thread. - Actually transmit custom headers and Bearer token – runtime
dlsym()ofast_websocket_client_create_with_headerswith clear fallback warning. - Input validation for headers –
audiofork_normalize_headers()strips control chars and skips malformed pairs. - Precise interruption – replaced
sleep(1)withnanosleep()(100 ms granularity). - Metadata retry logic – up to 3 attempts with 200 ms delay; audio continues on failure.
| Issue | Solution |
|---|---|
| Headers not sent | On stock Asterisk, ast_websocket_client_create_with_headers is unavailable. Use subprotocol or URL query string (?token=...). A LOG_WARNING is printed. |
| Reconnection fails | Check R and r values, network reachability, and firewall to the WebSocket server. |
| Memory leaks | Always stop the fork cleanly with StopAudioFork (dialplan/AMI/CLI) or let the channel hang up. |
| Module not loading | Ensure prerequisites are loaded: res_websocket, codec_g722, codec_ulaw, codec_alaw (and func_periodic_hook for beep). Confirm build against correct Asterisk version. |
- Report bugs or request features via GitHub Issues.
- Submit improvements via Pull Requests.
- Questions? Open a discussion or reach out to the maintainer.
Maintainer: Hossein Mohhmadian (Hosseinhunta)
| Version | Author | Notes |
|---|---|---|
| Original | Nadir Hamid | Basic WebSocket audio forking (SLIN 8 kHz). |
| Enhanced (this fork) | Hossein Mohhmadian (Hosseinhunta) | Configurable codec/rate (c,L); subprotocol (s); custom headers & Bearer auth (H,A) via runtime dlsym; JSON metadata (M) with retry; exponential‑backoff reconnection (R,r); nanosleep‑based 100 ms interruption; header sanitisation; critical double‑free fix. GPLv2. |
License: GNU General Public License v2.0 – see the LICENSE file.