In FreeSWITCH, every individual call leg is represented by two inseparable objects: a session (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/signalwire/freeswitch/llms.txt
Use this file to discover all available pages before exploring further.
switch_core_session_t) that owns the media resources and the execution thread, and a channel (switch_channel_t) that holds the signaling state, variables, and caller information for that leg. Understanding the distinction between these two objects — and how they interact — is fundamental to working with FreeSWITCH at any level.
A session is the media container: it owns the codec handles, the message queue, the memory pool, and the thread that runs the call. A channel is the signaling and state container: it holds the call state machine, channel flags, channel variables, and the caller profile. The channel always belongs to exactly one session, and a session always has exactly one channel.
Sessions
Aswitch_core_session_t (defined in src/include/switch_types.h as an opaque struct switch_core_session) is the top-level object for a call leg. It contains:
- A pointer to its associated
switch_channel_t. - Codec handles for the read (inbound) and write (outbound) audio streams.
- A message queue for inter-session communication (e.g., bridge signals, DTMF forwarding).
- A memory pool whose lifetime matches the call — all per-call allocations use this pool.
- The codec implementation tables for the current negotiated codec.
- An application log (
switch_app_log) recording every application executed on the session.
mod_sofia) when a call arrives or is originated. The core registers the session in a global hash table, making it findable by UUID from anywhere in the system.
Channels
Theswitch_channel_t (defined in src/include/switch_channel.h) owns the call’s state machine. Every channel progresses through a defined sequence of states; the state at any moment determines what operations are legal and what event will fire next.
Channel State Machine
Theswitch_channel_state_t enum (from src/include/switch_types.h) defines all valid states:
switch_channel_get_state() and tested with convenience macros:
Channel Timetable
The channel records timestamps for key lifecycle events in itsswitch_channel_timetable_t:
Channel Variables
Channel variables are a key-value store on the channel — essentially a hash map ofchar * strings. They are the primary mechanism for communicating state between dialplan steps, between modules, and across call legs.
Variables are set and read through the channel API:
set application writes a variable and ${variable_name} reads it:
| Variable | Set by | Meaning |
|---|---|---|
uuid | Core | The session UUID |
caller_id_name | Endpoint | Caller’s display name |
caller_id_number | Endpoint | Caller’s number |
destination_number | Endpoint | Dialed number |
sip_to_user | mod_sofia | SIP To: user portion |
hangup_cause | Core | Reason for call termination |
bridge_uuid | Core | UUID of the bridged B-leg |
recording_follow_transfer | Application | Whether recording follows a transfer |
Bridging
Bridging connects two sessions so that audio flows between them. The core function isswitch_ivr_uuid_bridge(), which takes the UUIDs of two existing sessions and connects their media paths.
bridge dialplan application is used, it:
- Originates a new B-leg session (using the endpoint specified in the bridge string).
- Places both the A-leg and B-leg into
CS_EXCHANGE_MEDIA. - Connects the RTP engines of the two legs so audio flows between them.
bypass_media channel variable.
UUID
Every session is assigned a UUID (Universally Unique Identifier) at the moment it is created. The UUID is the primary key used to reference a specific call from any part of the system:- ESL / API commands:
uuid_kill <uuid>,uuid_transfer <uuid>,uuid_record <uuid>. - Channel variables:
${uuid}and${bridge_uuid}are set automatically. - CDR records: the UUID links A-leg and B-leg CDRs for a complete call record.
- Event headers: every channel event includes a
Unique-IDheader with the session UUID.
Call Parks and Transfers
FreeSWITCH provides several mechanisms for moving calls between agents or placing them in a waiting state.Blind Transfer
Blind Transfer
A blind transfer immediately redirects the A-leg to a new destination without waiting to confirm the target is available. The The core function
transfer dialplan application performs a blind transfer within FreeSWITCH:switch_ivr_session_transfer() handles moving the session to a new context/extension:Attended Transfer
Attended Transfer
An attended transfer places the original caller on hold, dials the transfer target, waits for the agent to speak with the target, and then completes the transfer. This is typically handled by the SIP endpoint via SIP REFER with the
Replaces header, but can also be orchestrated by mod_dptools.Call Park
Call Park
Parking places a call in a holding state where it waits to be retrieved. FreeSWITCH provides two park mechanisms:
switch_ivr_park()— generic park that holds the session in a loop.mod_fifo— a queue-based parking system where callers wait in named queues and agents log in to retrieve them.