Problem
The PBX currently has no mechanism to record call metadata for billing, auditing, or operational analysis. Without CDRs, operators cannot answer questions like "who called whom, when, and for how long", "which trunk carried the most traffic", or "what is the call completion rate". This is a fundamental requirement for any production telephony deployment.
Proposed Solution
1. CDR Data Model
Each completed call produces a CDR record containing:
| Field |
Type |
Description |
call_id |
string |
SIP Call-ID of the Alice leg |
start_time |
RFC3339 |
Time of initial INVITE |
answer_time |
RFC3339 |
Time of 200 OK (answer) |
end_time |
RFC3339 |
Time of BYE or session timeout |
duration |
float64 |
Answer-to-end duration in seconds |
caller |
string |
From URI (Alice) |
callee |
string |
To URI (Bob/trunk target) |
disposition |
string |
answered, busy, rejected, canceled, failed, timeout |
trunk |
string |
Trunk name if routed through one, empty if internal |
alice_ip |
string |
Source IP of Alice |
bob_ip |
string |
Destination IP of Bob/trunk peer |
alice_rtp_packets |
int |
RTP packets sent by Alice leg |
bob_rtp_packets |
int |
RTP packets sent by Bob leg |
alice_rtp_bytes |
int |
RTP bytes sent by Alice leg |
bob_rtp_bytes |
int |
RTP bytes sent by Bob leg |
2. Output Format
Write CDRs to a configurable file path as newline-delimited JSON (one JSON object per line):
{"call_id":"abc123","start_time":"2026-07-06T10:00:00Z","answer_time":"...","duration":42.5,"caller":"sip:alice@pbx","callee":"sip:+14155551234@trunk","disposition":"answered","trunk":"twilio","alice_rtp_packets":2100,"bob_rtp_packets":2098}
3. Implementation
- New package:
internal/cdr/ — CDR record type, JSON serialization, writer with rotation
- CLI flag:
--cdr-file path/to/cdrs.jsonl
- Wire into B2BUA handler:
- Record
start_time on INVITE arrival
- Record
answer_time on 200 OK
- Record
end_time on BYE, CANCEL, or error
- Count RTP packets in the bridge (
media/bridge.go → increment counters per direction)
- On call cleanup (BYE handler or bridge exit), write the CDR record
- Thread-safe writer with optional buffering and fsync interval
4. Future Extensions (out of scope)
- CDR export to external billing systems (REST, SFTP)
- Real-time CDR streaming via WebSocket
- CDR database storage (PostgreSQL, etc.)
- Per-leg RTP quality metrics (jitter, packet loss)
Testing
- Unit test — CDR JSON format and field population
- Integration test — Make a call, verify a CDR is written to the CDR file with correct start/answer/end times and disposition=
answered
- Integration test — Rejected call (Bob sends 486) → CDR with disposition=
busy
- Integration test — Canceled call (Alice sends CANCEL before answer) → CDR with disposition=
canceled
References
- RFC 3261 §20.30: Call-ID header
- Standard CDR format from Asterisk CDR (csv) and FreeSWITCH CDR (JSON)
Problem
The PBX currently has no mechanism to record call metadata for billing, auditing, or operational analysis. Without CDRs, operators cannot answer questions like "who called whom, when, and for how long", "which trunk carried the most traffic", or "what is the call completion rate". This is a fundamental requirement for any production telephony deployment.
Proposed Solution
1. CDR Data Model
Each completed call produces a CDR record containing:
call_idstart_timeanswer_timeend_timedurationcallercalleedispositionanswered,busy,rejected,canceled,failed,timeouttrunkalice_ipbob_ipalice_rtp_packetsbob_rtp_packetsalice_rtp_bytesbob_rtp_bytes2. Output Format
Write CDRs to a configurable file path as newline-delimited JSON (one JSON object per line):
{"call_id":"abc123","start_time":"2026-07-06T10:00:00Z","answer_time":"...","duration":42.5,"caller":"sip:alice@pbx","callee":"sip:+14155551234@trunk","disposition":"answered","trunk":"twilio","alice_rtp_packets":2100,"bob_rtp_packets":2098}3. Implementation
internal/cdr/— CDR record type, JSON serialization, writer with rotation--cdr-file path/to/cdrs.jsonlstart_timeon INVITE arrivalanswer_timeon 200 OKend_timeon BYE, CANCEL, or errormedia/bridge.go→ increment counters per direction)4. Future Extensions (out of scope)
Testing
answeredbusycanceledReferences