Merging or correlating multiple call legs

From VoIPmonitor.org


This guide explains how VoIPmonitor identifies and links multiple call legs belonging to the same end-to-end call.

Overview

Scenario Description VoIPmonitor Behavior
Same Call-ID Multiple legs share identical SIP Call-ID Automatically treated as one CDR (no configuration needed)
Different Call-IDs SBC/B2BUA generates new Call-ID for each leg Creates separate CDRs (requires correlation configuration)

Same Call-ID Behavior

When multiple legs share the same SIP Call-ID, VoIPmonitor automatically treats them as a single call:

  • Result: One CDR in the GUI, all packets in one PCAP file
  • BYE handling: When a BYE is received, VoIPmonitor finalizes the CDR for that Call-ID
  • No configuration needed: This is automatic and cannot be disabled

ℹ️ Note: If you want separate CDRs per leg, configure your PBX/SBC to generate unique Call-IDs, then use the correlation methods below.

Correlation Methods for Different Call-IDs

When calls pass through an SBC/B2BUA that generates new Call-IDs, choose one of these methods:

Method Result Use Case
Linking Separate CDRs, visually linked in GUI View each leg independently with navigation
Merging Single CDR and PCAP file Treat entire call as one record

Method 1: Linking Separate CDRs

Keeps legs as distinct database entries but associates them visually.

Automatic Linking (Legs by CID)

Built-in, no configuration required:

  • Matches CDRs where last 6 digits of caller/called numbers match within ±10 seconds
  • Found in CDR detail view → Legs by CID tab
  • Use Merge button to combine linked legs into unified SIP history view

Custom Header Linking

Link legs using a shared SIP header. Results appear in Legs by header tab.

GUI Configuration (no restart required):

  1. Navigate to Settings → Custom Headers → CDR
  2. Add the header name (e.g., X-Correlation-ID)
  3. Enable "match in SIP by header" checkbox

voipmonitor.conf (requires restart):

# Store header in cdr_next.match_header for leg matching
matchheader = X-Correlation-ID

# Alternative Call-ID for correlation when standard Call-ID changes
call_id_alternative = X-Correlation-ID

Method 2: Merging into Single CDR

Combines multiple legs into one CDR and one PCAP file. Requires the second leg's INVITE to contain a header with the first leg's Call-ID.

Configuration (voipmonitor.conf):

# Header containing parent Call-ID in outbound INVITEs
callidmerge_header = X-PARENT-CALLID

# Optional: Encrypt header value
#callidmerge_secret = yourSecretString

PBX Configuration Example (Asterisk):

[macro-add-parent-callid]
exten => s,1,NoOp(Adding Parent-Call-ID header)
exten => s,n,Set(ORIG_CALLID=${SIPHEADER(Call-ID)})
exten => s,n,SipAddHeader(X-PARENT-CALLID: ${ORIG_CALLID})
exten => s,n,MacroExit()

Comparison: Linking vs Merging

Feature Linking (matchheader) Merging (callidmerge_header)
Database entries Separate CDRs Single CDR
PCAP files Separate files Single merged file
GUI navigation "Legs by header" tab Single call view
PBX requirement Add correlation header Add header with parent Call-ID
Restart required GUI: No / Config: Yes Yes

MOS Analysis in Multi-Leg Calls

Default Behavior

When multiple legs are merged (same Call-ID), the GUI displays MOS from the longest RTP stream only. This can hide quality issues on shorter legs.

Solution 1: call_branches (Experimental)

Evaluate each leg separately:

call_branches = yes

⚠️ Warning: The call_branches option is experimental. Test before deploying to production.

Solution 2: Separate CDRs per Leg

Generate unique Call-IDs for each leg to create separate CDRs:

  • Each CDR shows exact packet loss/MOS for that specific leg
  • Link related CDRs using matchheader for navigation
  • Best for detailed per-stream quality analysis
Approach MOS Visibility Complexity
Default merged CDR Only longest stream Low
call_branches = yes Per-branch evaluation Low (experimental)
Separate CDRs + linking Individual MOS per leg High (requires PBX changes)

Transferred Calls: Preserving Audio

When calls are transferred (REFER/re-INVITE), BYE may terminate the original leg while transfer continues. To preserve audio:

# Continue recording RTP after BYE
ignore_rtp_after_bye_confirmed = no

# Continue duration counting after BYE
ignore_duration_after_bye_confirmed = no

💡 Tip: If audio for transferred portion is missing after configuring correlation, add these options and restart the sniffer.

IP-Based Access Control

When using filter_ip user restrictions, unique Call-IDs per leg are required for proper security.

Problem
If legs share the same Call-ID, users can download PCAPs containing traffic from IPs outside their permission (all leg traffic is combined).
Solution
Configure PBX/SBC to generate unique Call-IDs per network leg segment. Each CDR then contains only traffic from specific IPs.

⚠️ Warning: Do NOT use callidmerge_header when IP-based access control is required. Merging defeats the security purpose.

See User_Management for configuring IP-based restrictions.

Troubleshooting

Problem Cause Solution
One CDR instead of two Legs share same Call-ID Expected behavior; configure unique Call-IDs if separate CDRs needed
Audio missing after transfer BYE terminates recording Set ignore_rtp_after_bye_confirmed = no
Correlation not working Header mismatch or not present Verify header in PCAP; check exact spelling; restart sniffer for config changes
Capture stops on BYE Same Call-ID = same session For independent tracking, use unique Call-IDs per leg

See Also

AI Summary for RAG

Summary: VoIPmonitor call correlation handles multi-leg calls in two scenarios: (1) Same Call-ID legs are automatically treated as one CDR; (2) Different Call-IDs (from SBC/B2BUA) require configuration. Two methods exist: Linking (matchheader) keeps separate CDRs visually associated via "Legs by header" tab; Merging (callidmerge_header) combines legs into single CDR where second INVITE contains parent Call-ID header. For MOS visibility in merged calls, default shows only longest stream; use call_branches=yes (experimental) or separate CDRs for per-leg analysis. Transferred calls may lose audio if BYE terminates recording; fix with ignore_rtp_after_bye_confirmed=no. For IP-based access control (filter_ip), unique Call-IDs per leg are required to prevent unauthorized PCAP access.

Keywords: call correlation, leg matching, Call-ID, matchheader, call_id_alternative, callidmerge_header, ignore_rtp_after_bye_confirmed, call_branches, MOS, multi-leg call, Legs by CID, Legs by header, B2BUA, SBC, CDR merging, BYE termination, call transfer, filter_ip, IP restrictions, packet loss per stream

Key Questions:

  • Why do I see only one CDR when my call has multiple legs?
  • How to link call legs with different Call-IDs?
  • What is the difference between matchheader and callidmerge_header?
  • How to merge multiple call legs into a single CDR?
  • Why is MOS only showing for the longest RTP stream?
  • How to see MOS for individual legs in a merged CDR?
  • Why is audio missing for transferred calls?
  • How to preserve audio after BYE during call transfer?
  • Why can users with IP restrictions download PCAPs with unpermitted traffic?
  • How to view exact packet loss per RTP stream?