Skip to main content

Chapter 7: SIP Profiles with Sofia

mod_sofia is the SIP endpoint module in FreeSWITCH, built on the Sofia-SIP stack. A SIP profile defines one independent SIP user agent bound to a specific IP address and port; every SIP user agent in FreeSWITCH is a distinct profile with its own transport, codec preferences, authentication policy, and dialplan routing target.

The Sofia Profile Model

Each Sofia SIP profile services exactly one IP address and port combination. Running multiple profiles is how FreeSWITCH presents separate SIP user agents on the same host, for example, one for internal registered phones and another for outbound carrier trunks. Profiles are independent: each has its own transport socket, ACL rules, codec preferences, authentication requirements, and dialplan context.

All profile XML files live under conf/sip_profiles/. The module-level configuration file conf/autoload_configs/sofia.conf.xml uses an X-PRE-PROCESS include directive to load every *.xml file from that directory:

<profiles>
<X-PRE-PROCESS cmd="include" data="../sip_profiles/*.xml"/>
</profiles>

To add a profile, place a new XML file in conf/sip_profiles/ and execute sofia profile <name> start from the FreeSWITCH console, or restart the module.


Global Sofia Settings

sofia.conf.xml also contains a global_settings block that applies across all profiles.

<global_settings>
<param name="log-level" value="0"/>
<param name="debug-presence" value="0"/>
<!-- <param name="auto-restart" value="false"/> -->
<!-- <param name="abort-on-empty-external-ip" value="true"/> -->
<!-- <param name="capture-server" value="udp:homer.domain.com:5060"/> -->
</global_settings>
ParameterPurposeAccepted ValuesDefault
log-levelSofia-SIP stack verbosity0-90
debug-presencePresence subsystem debug verbosity0-90
auto-restartReload profiles automatically after config changetrue, falsetrue
abort-on-empty-external-ipAbort profile load when ext-rtp-ip or ext-sip-ip resolve to emptytrue, falsefalse
capture-serverHEP capture server for SIP mirroringudp:host:port or udp:host:port;hep=3;capture_id=N(none)

Profile File Structure

A profile XML file follows this skeleton:

<profile name="internal">
<aliases>
<!-- <alias name="default"/> -->
</aliases>

<gateways>
<!-- outbound provider registrations -->
</gateways>

<domains>
<domain name="all" alias="true" parse="false"/>
</domains>

<settings>
<param name="sip-port" value="5060"/>
<!-- ... additional parameters ... -->
</settings>
</profile>

The gateways Block

Outbound SIP registrations to upstream carriers or SIP trunks are defined inside <gateways>. The external profile uses an include to load individual gateway files:

<gateways>
<X-PRE-PROCESS cmd="include" data="external/*.xml"/>
</gateways>

Each gateway XML file defines one outbound registration. Gateways are covered in Chapter 8: Gateways and Trunk Registration.

The aliases Block

An alias is an alternative name by which a profile can be referenced in dialplan strings and API calls. Multiple aliases are permitted per profile.

<aliases>
<alias name="default"/>
<alias name="outbound"/>
</aliases>

Aliases allow dialplan bridge strings such as sofia/default/1000@domain.com to resolve to the internal profile even when the profile is named internal.

The domains Block

The domains block controls two independent behaviors: whether the profile parses the directory for domain-level gateway definitions, and whether each listed domain is aliased to this profile for routing purposes.

<domains>
<domain name="all" alias="true" parse="false"/>
</domains>
AttributePurposeAccepted Values
nameThe domain to act on, or the special value all to match every configured domainFQDN or all
aliasAlias this domain name to the profile so SIP URIs addressed to the domain resolve heretrue, false
parseParse the FreeSWITCH directory for this domain and load any gateways defined theretrue, false

Setting alias="true" and name="all" causes every domain in the directory to be aliased to this profile. This is the default in the internal profile and enables multi-domain routing for registered endpoints.

Setting parse="true" instructs the profile to read the XML directory for the named domain and load any <gateway> stanzas found there. The external profile uses parse="true" and alias="false" by default, loading directory-defined gateways without routing all domain traffic through it.

The settings Block

All per-profile operational parameters are declared as <param name="..." value="..."/> elements inside <settings>. The complete reference is in Section 5.


Bundled Profiles

The vanilla configuration ships two profiles: internal and external. They cover the two dominant use cases and serve as templates for custom profiles.

The internal Profile

File: conf/sip_profiles/internal.xml

The internal profile is designed for registered SIP endpoints such as desk phones, softphones, and WebRTC clients. It binds on port 5060 (variable $${internal_sip_port}) and enforces digest authentication by default (auth-calls resolves to true via $${internal_auth_calls}).

Key characteristics of the vanilla internal profile:

  • Binds sip-ip and rtp-ip to $${local_ip_v4} (the system's detected local IPv4 address).
  • Routes inbound calls to the public context.
  • Applies the domains ACL for inbound call authorization (apply-inbound-acl = domains).
  • Enables presence (manage-presence = true).
  • Enables WebSocket (ws-binding = :5066) and secure WebSocket (wss-binding = :7443) for WebRTC clients.
  • Forces all registrations into a single domain defined by $${domain} via force-register-domain.
  • Sets challenge-realm to auto_from, meaning the SIP realm in digest challenges is derived from the From header.
  • Enables inbound-late-negotiation to allow codec selection in the dialplan.
<profile name="internal">
<aliases></aliases>
<gateways></gateways>
<domains>
<domain name="all" alias="true" parse="false"/>
</domains>
<settings>
<param name="context" value="public"/>
<param name="sip-port" value="$${internal_sip_port}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
<param name="dialplan" value="XML"/>
<param name="auth-calls" value="$${internal_auth_calls}"/>
<param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>
<param name="outbound-codec-prefs" value="$${global_codec_prefs}"/>
<param name="inbound-codec-negotiation" value="generous"/>
<param name="inbound-late-negotiation" value="true"/>
<param name="manage-presence" value="true"/>
<param name="presence-hosts" value="$${domain},$${local_ip_v4}"/>
<param name="apply-inbound-acl" value="domains"/>
<param name="apply-nat-acl" value="nat.auto"/>
<param name="nonce-ttl" value="60"/>
<param name="auth-calls" value="$${internal_auth_calls}"/>
<param name="auth-all-packets" value="false"/>
<param name="auth-subscriptions" value="true"/>
<param name="inbound-reg-force-matching-username" value="true"/>
<param name="challenge-realm" value="auto_from"/>
<param name="rtp-timeout-sec" value="300"/>
<param name="rtp-hold-timeout-sec" value="1800"/>
<param name="hold-music" value="$${hold_music}"/>
<param name="record-path" value="$${recordings_dir}"/>
<param name="record-template" value="${caller_id_number}.${target_domain}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
<param name="tls" value="$${internal_ssl_enable}"/>
<param name="tls-bind-params" value="transport=tls"/>
<param name="tls-sip-port" value="$${internal_tls_port}"/>
<param name="tls-version" value="$${sip_tls_version}"/>
<param name="ws-binding" value=":5066"/>
<param name="wss-binding" value=":7443"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="force-subscription-domain" value="$${domain}"/>
<param name="force-register-db-domain" value="$${domain}"/>
</settings>
</profile>

The external Profile

File: conf/sip_profiles/external.xml

The external profile is designed for outbound registrations to SIP carriers and upstream trunks. It binds on port 5080 (variable $${external_sip_port}) and disables inbound call authentication (auth-calls = false) because carriers do not register as users and instead authenticate at the network or IP level.

Key characteristics of the vanilla external profile:

  • Binds on port 5080.
  • Sets auth-calls = false; carrier traffic is typically trusted by IP.
  • Sets manage-presence = false; presence is not needed for trunk traffic.
  • Loads gateway definitions from conf/sip_profiles/external/*.xml via the gateways include.
  • Uses parse="true" in the domains block to load directory-defined gateways; alias="false" so domain SIP URIs are not automatically routed here.
<profile name="external">
<gateways>
<X-PRE-PROCESS cmd="include" data="external/*.xml"/>
</gateways>
<aliases></aliases>
<domains>
<domain name="all" alias="false" parse="true"/>
</domains>
<settings>
<param name="context" value="public"/>
<param name="sip-port" value="$${external_sip_port}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
<param name="dialplan" value="XML"/>
<param name="auth-calls" value="false"/>
<param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>
<param name="outbound-codec-prefs" value="$${outbound_codec_prefs}"/>
<param name="inbound-codec-negotiation" value="generous"/>
<param name="inbound-late-negotiation" value="true"/>
<param name="manage-presence" value="false"/>
<param name="nonce-ttl" value="60"/>
<param name="rtp-timeout-sec" value="300"/>
<param name="rtp-hold-timeout-sec" value="1800"/>
<param name="hold-music" value="$${hold_music}"/>
<param name="tls" value="$${external_ssl_enable}"/>
<param name="tls-bind-params" value="transport=tls"/>
<param name="tls-sip-port" value="$${external_tls_port}"/>
<param name="tls-version" value="$${sip_tls_version}"/>
</settings>
</profile>

Settings Parameter Reference

Identity and Binding

These parameters define what address and port the profile binds to, and how inbound calls are dispatched.

ParameterPurposeAccepted ValuesDefault
sip-ipLocal IP address for the SIP transport socket. Use only IP addresses, not hostnames. Accepts auto (use the system-guessed IP), interface:NAME (resolve from a named network interface), or an explicit dotted-decimal address.IP address, auto, interface:[auto|ipv4|ipv6]/IFNAMESystem-guessed local IPv4
sip-portUDP/TCP port the SIP transport listens on. Accepts auto to let the OS assign a port.Port number or auto5060
rtp-ipLocal IP address used as the RTP source/destination in SDP. Accepts the same forms as sip-ip. Multiple rtp-ip entries are supported and the profile will select an appropriate address per call.IP address, auto, interface:[auto|ipv4|ipv6]/IFNAMESystem-guessed local IPv4
contextThe dialplan context inbound calls are delivered to. Can be overridden per-call by the user_context channel variable or ACL pass/fail contexts.Any defined dialplan context namedefault
dialplanThe dialplan module used to process inbound calls.XML, inline, or any loaded dialplan module nameXML
bind-paramsExtra transport parameters appended to the SIP bind URI, for example to restrict transport protocol.Transport param string, e.g. transport=udp(none)
user-agent-stringOverride the User-Agent SIP header sent by this profile. Set to _undef_ to omit the header entirely.Any string or _undef_FreeSWITCH-mod_sofia/<version>
contact-userThe user portion placed in the SIP Contact URI built for this profile.Stringmod_sofia
sip-domainOverride the SIP domain reported by this profile. When not set, defaults to the sip-ip value.FQDN or IP addressValue of sip-ip
outbound-proxyForce all outbound SIP requests through this proxy URI. sip: scheme is prepended if absent.SIP URI, e.g. sip:proxy.example.com(none)
max-callsMaximum simultaneous calls allowed on this profile. 0 means unlimited.Integer0

Authentication and Registration

ParameterPurposeAccepted ValuesDefault
auth-callsRequire digest authentication on inbound INVITE requests.true, falsefalse
auth-all-packetsWhen authentication is enabled, challenge every SIP request method, not only INVITE.true, falsefalse
auth-messagesRequire digest authentication for inbound MESSAGE requests.true, falsetrue
auth-subscriptionsRequire digest authentication for SUBSCRIBE requests.true, falsetrue
accept-blind-regAccept any REGISTER request without verifying credentials against the directory. Intended only for testing environments.true, falsefalse
accept-blind-authAccept any digest authentication response without verifying the password. Intended only for testing environments.true, falsefalse
apply-inbound-aclACL name applied to inbound call source IPs. Calls passing the ACL may be delivered to an optional context specified with acl-name:pass-context:fail-context syntax. Multiple instances of this parameter are supported. Use none to clear.ACL name, none, or acl:pass-ctx:fail-ctx(none)
apply-register-aclACL name applied to REGISTER source IPs. Registrations from IPs not on the ACL are rejected. Multiple instances supported. Use none to clear.ACL name or none(none)
apply-proxy-aclACL name applied to requests that arrive via a proxy (based on Via header). Multiple instances supported. Use none to clear.ACL name or none(none)
nonce-ttlLifetime in seconds of digest authentication nonces. Values below 60 are coerced to 60 at startup.Integer seconds60
max-auth-validityMaximum number of times a nonce may be reused before requiring a fresh challenge. 0 means unlimited reuse within nonce-ttl.Integer0
challenge-realmValue placed in the realm field of digest authentication challenges. auto_from derives the realm from the SIP From header host; auto_to derives it from the To header host; any other string is used literally. Using a fixed string disables multi-domain authentication.auto_from, auto_to, or any literal stringauto_to
inbound-reg-force-matching-usernameReject registrations where the username field of the Authorization header does not match the user portion of the From URI.true, falsefalse
multiple-registrationsAllow a single user to register from multiple devices simultaneously. call-id tracks registrations by Call-ID; contact tracks by Contact URI. true is treated as contact.false, call-id, contact, truefalse

Presence and Registration Domain

ParameterPurposeAccepted ValuesDefault
manage-presenceEnable the presence engine on this profile. true enables full presence. passive enables presence in read-only/relay mode (used to share presence from the internal profile). pnp enables Plug and Play provisioning presence. false disables presence.true, false, passive, pnpfalse
presence-hostsComma-separated list of hostnames or IPs that this profile serves for presence. Used to match presence subscriptions to the correct profile.Comma-separated host list(none)
force-register-domainOverride the domain under which all inbound registrations are stored in the user directory. Use when operating a single-domain server to prevent registrations from scattering across different domain values in requests.Domain name(none; uses domain from request)
force-register-db-domainOverride the domain used as the database key when storing registrations. Usually set to the same value as force-register-domain.Domain name(none; uses domain from request)
force-subscription-domainOverride the domain used when routing SUBSCRIBE requests.Domain name(none; uses domain from request)
record-pathDefault directory where call recordings initiated from this profile are stored.Absolute pathValue of $${recordings_dir}
record-templateFilename template for auto-recordings. Supports FreeSWITCH channel variable expansion and ${strftime(...)}.String with variable references(none)

Media

ParameterPurposeAccepted ValuesDefault
inbound-codec-prefsOrdered list of codecs offered to inbound callers in the SDP answer.Comma-separated codec names, e.g. OPUS,G722,PCMU,PCMA(none; uses global codec list)
outbound-codec-prefsOrdered list of codecs offered in SDP offers for outbound calls.Comma-separated codec names(none; uses global codec list)
codec-prefsSets both inbound-codec-prefs and outbound-codec-prefs to the same value in one parameter.Comma-separated codec names(none)
inbound-codec-negotiationControls how the profile reconciles its codec list against the remote party's SDP offer. generous accepts the first codec in the remote offer that the profile also supports. greedy reorders the remote offer to prefer the profile's own priority list. scrooge behaves like greedy and additionally refuses to accept any codec not in the profile's list.generous, greedy, scroogegenerous
disable-transcodingWhen bridging, restrict the outbound leg to offer only the codec in use on the inbound leg, preventing transcoding.true, falsefalse
media-optionModifies bypass-media behavior. resume-media-on-hold brings a bypass-media call back into media when hold is pressed. bypass-media-after-att-xfer returns a call to bypass-media after an attended transfer. bypass-media-after-hold returns to bypass-media after hold ends (requires resume-media-on-hold to also be set). none clears all options. This parameter can appear multiple times.resume-media-on-hold, bypass-media-after-att-xfer, bypass-media-after-hold, none(none)
rtp-timeout-secSeconds of RTP inactivity on an active (non-held) call before FreeSWITCH terminates the call. Deprecated: prefer the media_timeout channel variable.Integer seconds0 (disabled; zero-initialized)
rtp-hold-timeout-secSeconds of RTP inactivity while a call is on hold before FreeSWITCH terminates the call. Deprecated: prefer the media_hold_timeout channel variable.Integer seconds0 (disabled; zero-initialized)
rtp-timer-nameName of the RTP timer to use. soft is the software timer; other values depend on compiled timer modules. The vanilla config sets this to soft.soft, or any loaded timer name(none; uses stack default)
hold-musicMusic-on-hold source URI played to parties placed on hold by this profile's calls.Any FreeSWITCH sound URI, e.g. local_stream://moh(none)
inbound-late-negotiationAllow the call to reach the dialplan before FreeSWITCH selects the codec for the A-leg. Enables codec selection based on dialplan logic. Automatically enabled when inbound-bypass-media is set.true, falsefalse
inbound-bypass-mediaPlace all inbound calls immediately into bypass-media (no-media proxy) mode. Also accepted as inbound-no-media. Implicitly enables inbound-late-negotiation.true, falsefalse
inbound-proxy-mediaPlace all inbound calls immediately into proxy-media mode.true, falsefalse
suppress-cngSuppress Comfort Noise Generation on this profile. Also accepted as supress-cng.true, falsefalse
pass-rfc2833Pass RFC 2833 telephone-event RTP packets through without processing them, rather than converting to DTMF events internally. Useful in pure-proxy scenarios.true, falsefalse
rtp-rewrite-timestampsRewrite RTP timestamps from scratch rather than passing through the originating timestamps. Required in some transcoding or bridging scenarios to prevent timestamp discontinuities.true, falsefalse
disable-rtp-auto-adjustDisable the automatic RTP source-address learning that updates the remote RTP destination when packets arrive from a different address than negotiated. Required when rtp-rewrite-timestamps is in use or when fixed RTP routing is required.true, falsefalse
rtp-autofix-timingAutomatically fix RTP packet timing irregularities caused by jitter in the sending endpoint.true, falsetrue
vadEnable Voice Activity Detection on this profile. in applies VAD to inbound audio; out to outbound audio; both to both directions.in, out, both, nonenone
bitpackingCodec bitpacking mode for G.726. aal2 enables AAL2-style bitpacking required by some ATM-derived equipment.aal2, or omit for standardStandard (not set)
rtcp-audio-interval-msecInterval in milliseconds at which RTCP packets are sent for audio streams. Set to passthru to relay RTCP across a bridge.Integer milliseconds or passthru(none; RTCP disabled)
rtcp-video-interval-msecInterval in milliseconds at which RTCP packets are sent for video streams.Integer milliseconds or passthru(none; RTCP disabled)
auto-jitterbuffer-msecEnable an automatic jitter buffer of the specified size (in milliseconds) on every call on this profile. Values below 20 ms are ignored. Can also be set per-channel with the jitterbuffer_msec channel variable.Integer milliseconds(none; jitter buffer disabled)

DTMF

ParameterPurposeAccepted ValuesDefault
dtmf-typeDTMF method used for outbound legs. rfc2833 sends DTMF as RFC 2833 telephone-event packets. info sends DTMF as SIP INFO messages. none disables automatic DTMF handling.rfc2833, info, nonerfc2833
rfc2833-ptRTP payload type number for RFC 2833 telephone-event. Must match the remote endpoint's expectation.Integer payload type101
dtmf-durationDuration in RTP timestamp units (8000 Hz clock) of generated RFC 2833 DTMF digits. Valid range is SWITCH_MIN_DTMF_DURATION (400) to SWITCH_MAX_DTMF_DURATION (192000); values outside this range fall back to 2000.Integer2000 (vanilla default; raw profile default is 100 before param is applied)
liberal-dtmfAccept DTMF using either RFC 2833 or SIP INFO without requiring the signaled method, improving compatibility with endpoints that send both.true, falsefalse
rtp-digit-delayMilliseconds of delay to inject between consecutive RFC 2833 DTMF digits on send. Can help slow DTMF processors. Also overridable per-channel with the rtp_digit_delay variable.Integer milliseconds40

Call Control and Timers

ParameterPurposeAccepted ValuesDefault
enable-timerEnable SIP session timers (RFC 4028). When false, session refresh is disabled.true, falsetrue
session-timeoutSession timer interval in seconds placed in the Session-Expires SIP header. 0 disables session timers.Integer seconds0
minimum-session-expiresMinimum acceptable session-expires value in seconds for incoming requests. RFC 4028 requires this to be at least 90; values below 90 are coerced to 90.Integer seconds0 (disabled)
sip-expires-max-deviationRandom seconds added to registration expiry to spread re-registrations. Prevents thundering-herd re-registrations after an outage.Integer seconds0
sip-options-respond-503-on-busyRespond to SIP OPTIONS requests with 503 Service Unavailable when the system is at capacity, instead of 200 OK.true, falsefalse
unregister-on-options-failWhen sending keepalive OPTIONS pings to registered endpoints, unregister an endpoint if the OPTIONS probe fails.true, falsefalse
nat-options-pingSend periodic OPTIONS pings to NATed registered endpoints to maintain NAT binding. udp-only restricts pings to UDP endpoints.true, false, udp-onlyfalse
all-reg-options-pingSend periodic OPTIONS pings to all registered endpoints, not only NATed ones.true, falsefalse
disable-transferDisable SIP REFER (blind and attended transfer) on this profile.true, falsefalse
disable-registerDisable REGISTER handling on this profile.true, falsefalse
caller-id-typeSupplementary caller ID header format. rpid adds a Remote-Party-ID header. pid adds a P-Asserted-Identity header. none suppresses supplementary caller-ID headers.rpid, pid, none(none added)
max-proceedingMaximum number of simultaneous outbound dialogs in the proceeding state. 0 means unlimited.Integer0
max-recv-requests-per-secondRate limit for inbound SIP requests per second per profile. 0 disables the limit.Integer1000

NAT Traversal

ParameterPurposeAccepted ValuesDefault
ext-rtp-ipPublic IP address advertised in SDP for RTP. Used when the FreeSWITCH host is behind NAT. Accepts a literal IP, auto (system-guessed external IP), auto-nat (IP learned via NAT-PMP or UPnP), stun:host (STUN query), or host:hostname (DNS lookup).IP address, auto, auto-nat, stun:host, host:hostname(none; uses rtp-ip)
ext-sip-ipPublic IP address advertised in SIP Contact and Via headers for the SIP transport. Accepts the same forms as ext-rtp-ip.IP address, auto, auto-nat, stun:host, host:hostname(none; uses sip-ip)
apply-nat-aclACL name used to detect NATed endpoints. Source IPs matching this ACL are treated as being behind NAT, causing the profile to adjust Contact and RTP addresses accordingly. Multiple instances supported. Use none to clear.ACL name or none(none)
aggressive-nat-detectionCompare the source IP and port of received SIP packets against the values in the Contact header. If they differ, treat the endpoint as NATed regardless of the apply-nat-acl result.true, falsefalse
local-network-aclACL that defines the local network. Endpoints on the local network are not subjected to NAT handling. FreeSWITCH automatically generates localnet.auto for this purpose. Set to none to disable.ACL name or nonelocalnet.auto
NDLB-received-in-nat-reg-contactAppend ;received="ip:port" to the Contact in REGISTER responses to assist NATed phones that do not detect their own public address.true, falsefalse
NDLB-force-rportForce rport handling for NAT. true enables forced rport on both server and client; safe enables it only where it will not break compliant endpoints; client-only or server-only restrict to one direction; disabled turns it off entirely.true, false, safe, client-only, server-only, disabledServer and client both at level 1 (standard rport)

TLS

TLS is disabled by default. Enabling it requires setting tls to true and providing valid certificate files in tls-cert-dir. The default TLS port for the internal profile is 5061; for the external profile it is 5081.

ParameterPurposeAccepted ValuesDefault
tlsEnable TLS transport on this profile.true, falsefalse
tls-onlyWhen true, the profile does not bind the plain SIP port (sip-port) and accepts connections only on the TLS port.true, falsefalse
tls-bind-paramsAdditional parameters appended to the TLS bind URI. transport=tls is always injected automatically when TLS is enabled.Parameter stringtransport=tls
tls-sip-portPort number the TLS transport listens on. Accepts auto. Default is 5061 for the internal profile (from $${internal_tls_port}) and 5081 for the external profile (from $${external_tls_port}).Port number or auto5061 (internal) / 5081 (external)
tls-cert-dirDirectory containing the TLS certificate files agent.pem and cafile.pem. Required for TLS server operation. Defaults to the FreeSWITCH global certs_dir.Absolute directory path$${certs_dir}
tls-passphrasePassphrase used by OpenSSL to decrypt a password-protected private key file. Leave empty if the key is not encrypted.String(empty)
tls-versionComma-separated list of TLS/SSL protocol versions to enable. Accepted tokens: sslv2, sslv3, sslv23, tlsv1, tlsv1.1, tlsv1.2, tlsv1.3. The compiled default enables all of TLSv1 through TLSv1.3; the vanilla config variable $${sip_tls_version} sets tlsv1,tlsv1.1,tlsv1.2.Comma-separated version tokenstlsv1,tlsv1.1,tlsv1.2,tlsv1.3 (compiled default)
tls-ciphersOpenSSL cipher string controlling which cipher suites are permitted.OpenSSL cipher stringALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH
tls-verify-policyControls certificate verification for inbound and outbound TLS connections. none disables verification. in verifies inbound connections. out verifies outbound connections. all verifies both. Prefix with subjects_ to also validate the certificate Subject. Multiple policies can be combined with |.none, in, out, all, subjects_in, subjects_out, subjects_allnone
tls-verify-depthMaximum certificate chain depth for peer certificate validation when tls-verify-policy is not none.Integer2
tls-verify-dateVerify that peer certificates are within their validity dates.true, falsetrue
tls-verify-in-subjectsPipe-separated (|) list of allowed certificate subjects when using a subjects_* verify policy.Pipe-separated subject strings(empty)
tls-timeoutTimeout in seconds for inactive TLS connections before they are closed.Integer seconds300
tls-orq-connect-timeoutTimeout in milliseconds for outgoing TLS connection attempts. When the timeout expires, FreeSWITCH retries and may use an alternate DNS-resolved address. 0 disables the timeout.Integer milliseconds0

WebSocket Bindings

These parameters add WebSocket and secure WebSocket listeners to the profile, enabling SIP over WebSocket for WebRTC clients. They are independent of the TLS setting.

ParameterPurposeAccepted ValuesDefault
ws-bindingIP address and port for the WebSocket (WS) listener. Format is [ip]:port. Omitting the IP binds all interfaces.[ip]:port, e.g. :5066(none)
wss-bindingIP address and port for the secure WebSocket (WSS) listener. Requires a wss.pem certificate in $${certs_dir}, which is auto-generated if absent. When tls-cert-dir is set, FreeSWITCH also looks for wss.key and wss.crt in that directory.[ip]:port, e.g. :7443(none)

Advanced Settings

The following parameters are accepted by the parser but are less commonly set by operators. They are listed here for completeness. Verify current behavior against sofia.c before use.

ParameterPurposeDefault
debugSofia module debug level for this profile.0
sip-traceLog raw SIP messages to the FreeSWITCH log for this profile.false
sip-captureSend SIP messages to the HEP capture server configured in global_settings.false
odbc-dsnODBC data source name for using an external database instead of SQLite for registration storage. Format: dsn:user:pass.(none; uses SQLite)
dbnameOverride the SQLite database filename for this profile.sofia_reg_<profilename>
db-spin-up-wait-msMilliseconds to wait for the database to become available on profile load.1000
inbound-use-callid-as-uuidUse the SIP Call-ID of inbound calls as the FreeSWITCH channel UUID.false
outbound-use-uuid-as-callidUse the FreeSWITCH channel UUID as the SIP Call-ID for outbound calls.false
enable-100relEnable RFC 3262 reliable provisional responses (100rel / PRACK).false
enable-compact-headersSend SIP messages using compact header forms.false
enable-3pccEnable third-party call control. true accepts immediately; proxy waits for answer.false
enable-rfc-5626Include reg-id and sip.instance parameters in REGISTER requests (RFC 5626 outbound).false
rtp-autoflush-during-bridgeFlushes RTP buffers during bridge when the socket already has data, reducing latency on lossy links. Not configurable: mod_sofia does not parse this as a profile param; the behavior is a hardcoded profile default that is always on.true (hardcoded)
manage-shared-appearanceEnable Bridged Line Appearance (BLA/SCA) for shared line management per the BroadSoft spec.false
parse-all-invite-headersParse and expose all SIP headers from inbound INVITE requests as channel variables.false
pass-callee-idPass callee identity information to the far end as X- headers.true
allow-updateAllow SIP UPDATE method processing.true
send-display-updateSend re-INVITEs to update the remote display name when it changes. Requires allow-update to be true.true
disable-holdDisable SIP hold (re-INVITE with sendonly/inactive).false
proxy-refer-replacesPass SIP REFER with Replaces header to the dialplan rather than processing internally. Also accepted as proxy-refer.false
t38-passthruEnable T.38 fax passthrough mode.false
manual-redirectPass SIP 302 redirect responses to the dialplan rather than following them automatically.false
presence-probe-on-registerSend a presence probe to registered endpoints on every REGISTER to force them to re-publish presence state.false
send-presence-on-registerPush presence information to subscribers on each register. true or all pushes on every REGISTER; first-only pushes only on the first REGISTER.false
NDLB-broken-auth-hashWork around endpoints that use INVITE instead of the correct method name when computing the digest hash for a challenged ACK.false
NDLB-sendrecv-in-sessionSend a=sendrecv in the SDP session-level as well as in the media-level for compatibility with some devices.false
NDLB-allow-bad-iananameAccept codecs with non-IANA-compliant names in SDP.false
NDLB-expires-in-register-responseInclude an Expires header in REGISTER 200 responses (some phones require this).false
NDLB-allow-crypto-in-avpAllow SDES crypto lines in AVP (non-SAVP) SDP for compatibility with some SBC and gateway equipment.false
NDLB-allow-nondup-sdpAllow duplicate or non-unique SDP bodies in re-INVITEs.true
NDLB-proxy-never-patch-reinvitesNever rewrite SDP in re-INVITEs when in proxy mode.false
disable-srvDisable SRV DNS lookups for outbound SIP destinations.false
disable-naptrDisable NAPTR DNS lookups for outbound SIP destinations.false
disable-srv503Do not try the next SRV destination on a 503 response (disables RFC 3263 Section 4.3 failover).false
auto-rtp-bugsComma-separated list of RTP bug workarounds to enable automatically. Supported tokens include CISCO_SKIP_MARK_BIT_2833 and SONUS_SEND_INVALID_TIMESTAMP_2833. Use clear to disable all.CISCO_SKIP_MARK_BIT_2833
timer-T1SIP transaction T1 retransmission interval in milliseconds.500
timer-T1X64SIP transaction timeout (T1 x 64) in milliseconds.32000
timer-T2Maximum SIP retransmission interval in milliseconds.4000
timer-T4Completed SIP transaction lifetime in milliseconds.4000
registration-thread-frequencyInterval in seconds at which the profile re-checks active registrations.30
bind-attemptsNumber of times to retry binding the SIP port on startup if it is unavailable.2
bind-attempt-intervalSeconds to wait between bind retry attempts.5
watchdog-enabledEnable a watchdog that crashes FreeSWITCH if the Sofia stack stops processing events. Do not enable on idle systems.false
watchdog-step-timeoutMilliseconds without a Sofia stack step before the watchdog fires.30000
watchdog-event-timeoutMilliseconds without a Sofia stack event before the watchdog fires.30000
log-auth-failuresLog failed authentication attempts at the INFO level.false
shutdown-on-failShut down FreeSWITCH if this profile fails to start.false
profile-standbyPlace this profile in standby mode (accepts no calls).false
reuse-connectionsReuse existing TCP/TLS connections for outbound requests rather than opening a new connection each time.true
sip-expires-late-marginSeconds before a registration expires that FreeSWITCH considers the registration stale and allows re-registration.60
sip-force-expiresForce all registration expiry to this value in seconds. 0 disables forcing.0
sip-force-expires-minMinimum value applied when forcing registration expiry.0
sip-force-expires-maxMaximum value applied when forcing registration expiry.0
sip-subscription-max-deviationRandom seconds of deviation added to subscription expiry values in 202 Accepted responses.0
force-subscription-expiresForce all subscription expiry to this value in seconds.(none)
force-publish-expiresForce all PUBLISH expiry to this value in seconds.(none)
require-secure-rtpRequire SRTP on all calls on this profile.false
p-asserted-id-parseControls how the P-Asserted-Identity header is parsed for inbound calls. default uses the display name and URI. user-only extracts only the user portion. user-domain extracts user and domain. verbatim passes the raw header value.default
user-agent-filterA regex or string; only process requests whose User-Agent header matches.(none)
max-registrations-per-extensionLimit the number of simultaneous registrations per extension number. 0 means unlimited.0

Proxy and Relay

These parameters make the profile pass selected SIP requests through to the dialplan (or bridged leg) instead of handling them internally. Each can also be toggled per-call with the matching sip_proxy_* channel variable.

ParameterPurposeAccepted ValuesDefault
proxy-infoRelay inbound SIP INFO requests across a bridge instead of handling them locally. Can be overridden per-call with the sip_proxy_info channel variable.true, falsefalse
proxy-info-content-typesRestrict proxy-info to INFO messages whose Content-Type matches one of the listed types. Empty or unset proxies all INFO content types.Comma/space-separated content-type list(none; all types proxied)
proxy-messageRelay inbound SIP MESSAGE requests across a bridge instead of handling them as chat locally. Can be overridden per-call with the sip_proxy_message channel variable.true, falsefalse
proxy-notify-eventsRelay in-dialog NOTIFY requests for the listed event packages to the bridged leg. all proxies every event type; otherwise a substring match against the NOTIFY Event type is used.all, or event-type list(none)
proxy-holdPass hold/unhold (re-INVITE with sendonly/inactive) through transparently in proxy/bypass-media scenarios rather than generating hold locally.true, falsefalse
sip-messages-respond-200-okAnswer inbound SIP MESSAGE requests with 200 OK instead of 202 Accepted. Vanilla internal.xml ships this commented out.true, falsefalse
sip-subscribe-respond-200-okAnswer inbound SIP SUBSCRIBE requests with 200 OK instead of 202 Accepted. Vanilla internal.xml ships this commented out.true, falsefalse
pnp-provision-urlProvisioning URL handed to Plug-and-Play (PnP) endpoints. Used together with manage-presence = pnp.URL string(none)

Transfer and REFER

ParameterPurposeAccepted ValuesDefault
confirm-blind-transferWait for the transfer target to answer before completing (and acknowledging) a blind REFER, so the transferee is not dropped if the target fails.true, falsefalse
make-every-transfer-a-nightmareForce the "nightmare transfer" code path (full re-routing through the dialplan) for all transfers, not only cross-profile ones. Diagnostic/compatibility option.true, falsefalse
channel-xml-fetch-on-nightmare-transferDuring a nightmare transfer, fetch the channel XML from the directory/dialplan to rebuild caller data on the transferred leg.true, falsefalse
fire-transfer-eventsFire a FreeSWITCH event for each SIP transfer (REFER) processed on this profile.true, falsefalse

Extended Authentication and Blind Auth

ParameterPurposeAccepted ValuesDefault
auth-calls-acl-onlyWhen auth-calls is enabled, treat a successful inbound ACL match as sufficient authorization and skip the digest challenge. Requires auth-calls = true.true, falsefalse
auth-require-userRequire the SIP From user (or Authorization username) to be present and resolvable before authenticating a request.true, falsefalse
accept-blind-authAccept any digest response without verifying the password. Testing only. (Documented for context; see Section 5.2.)true, falsefalse
enforce-blind-auth-resultWhen accept-blind-auth is on, still honor the underlying directory lookup result: reject the request if blind auth lookup fails rather than blindly accepting.true, falsefalse
blind-auth-reply-403When enforce-blind-auth-result rejects a blind-auth request, reply 403 Forbidden instead of re-challenging.true, falsefalse
disable-auth-messagesInverse of auth-messages. true disables digest auth for inbound MESSAGE requests; false requires it. Overrides auth-messages when both are present.true, falsefalse (auth on)
disable-auth-subscriptionsInverse of auth-subscriptions. true disables digest auth for SUBSCRIBE requests; false requires it. Overrides auth-subscriptions when both are present.true, falsefalse (auth on)
rfc8760-auth-algorithmsComma-separated, priority-ordered list of RFC 8760 digest algorithms to offer/accept (in addition to MD5). Up to 6 algorithms; unknown tokens are ignored and the list is sorted into the compiled priority order.e.g. SHA-256,SHA-512-256(none; MD5 only)

Extended ACL

ParameterPurposeAccepted ValuesDefault
apply-candidate-aclACL applied to ICE/media candidate addresses (WebRTC). Multiple instances are supported up to the candidate-ACL maximum. Use none to clear.ACL name or none(none)
apply-inbound-acl-x-tokenName of an X- header whose value supplies a token-based source identity for the inbound ACL check, allowing ACL evaluation against a trusted upstream-supplied address.Header name(none)
apply-proxy-acl-x-tokenName of an X- header whose value supplies the token-based source identity for the proxy ACL check.Header name(none)
use-port-for-acl-checkInclude the source (or token-supplied) port, not just the IP, when evaluating ACLs.true, falsefalse

TCP, Keepalive, and NAT Transport

ParameterPurposeAccepted ValuesDefault
tcp-keepaliveEnable and set the TCP keepalive interval (milliseconds) on SIP TCP connections, passed to the transport as TPTAG_KEEPALIVE.Integer milliseconds(off unless set)
socket-tcp-keepaliveEnable and set the OS socket-level TCP keepalive (SO_KEEPALIVE) interval in milliseconds (TPTAG_SOCKET_KEEPALIVE).Integer milliseconds(off unless set)
tcp-pingpongEnable Sofia ping-pong keepalive on TCP and set its interval (milliseconds).Integer milliseconds(off unless set)
tcp-ping2pongEnable the stricter ping2pong keepalive variant on TCP and set its interval (milliseconds).Integer milliseconds(off unless set)
keepalive-methodMethod used for SIP-level keepalive pings to endpoints. info sends SIP INFO; any other value uses SIP MESSAGE.info, messagemessage
tcp-always-natTreat all endpoints reached over TCP as NATed, regardless of ACL detection.true, falsefalse
tls-always-natTreat all endpoints reached over TLS as NATed, regardless of ACL detection.true, falsefalse
tcp-unreg-on-socket-closeUnregister a contact when its TCP/TLS connection socket closes (useful with reuse-connections).true, falsefalse

Extended Media and RTP

ParameterPurposeAccepted ValuesDefault
cng-ptRTP payload type used for Comfort Noise Generation. Ignored when suppress-cng is set (which forces it to 0).Integer payload type13
manual-rtp-bugsComma-separated list of RTP bug workarounds applied manually to audio (same token set as auto-rtp-bugs). Use clear to reset.RTP-bug token list or clear(none)
manual-video-rtp-bugsComma-separated list of RTP bug workarounds applied manually to video.RTP-bug token list or clear(none)
rtp-notimer-during-bridgeDisable the RTP soft timer while a call is bridged, letting the bridged peer pace media.true, falsefalse
ignore-183nosdpIgnore 183 Session Progress responses that arrive without SDP rather than treating them as early media. Also settable per-call via sip_ignore_183nosdp.true, falsefalse
enable-soaUse the Sofia SOA (SDP offer/answer) engine. Set false for raw SDP passthrough where FreeSWITCH should not parse/rewrite SDP via SOA.true, falsetrue
NDLB-support-asterisk-missing-srtp-authDisable SRTP authentication to interoperate with Asterisk builds that omit the SRTP auth tag.true, falsefalse

Presence, MWI, and Chat

ParameterPurposeAccepted ValuesDefault
presence-disable-earlySuppress early (ringing) dialog state in presence/BLF NOTIFYs, reporting only confirmed and terminated states. Also settable per-call.true, falsefalse
mwi-use-reg-callidSend MWI NOTIFYs using the Call-ID stored from the endpoint's REGISTER, improving delivery to phones that key MWI on the registration dialog.true, falsefalse
forward-unsolicited-mwi-notifyForward unsolicited (gateway-originated) MWI NOTIFY messages on to matching subscribers.true, falsefalse
send-message-query-on-registerOn REGISTER, query stored messages (SIP MESSAGE) for the user. true/all runs on every REGISTER; first-only runs only on the first REGISTER.true, all, first-only, falsefirst-only
fire-message-eventsFire a FreeSWITCH event for each inbound SIP MESSAGE processed on this profile.true, falsefalse
enable-chatEnable SIP chat (MESSAGE) handling on this profile. When false, chat is disabled.true, falsetrue
in-dialog-chatAllow SIP MESSAGE within an established dialog to be delivered as in-call chat.true, falsefalse

Registration Ping

These parameters tune the background thread that probes registered users (the user-ping loop, distinct from nat-options-ping).

ParameterPurposeAccepted ValuesDefault
sip-user-ping-minMinimum consecutive successful probes before a user is considered reachable/up.Integer1
sip-user-ping-maxMaximum consecutive failed probes before a user is considered unreachable/down.Integer3
ping-thread-frequencyHow often (seconds) the ping thread wakes to process due pings. Negative values reset to the compiled default.Integer seconds1
ping-mean-intervalMean interval (seconds) between pings for a given registered user. Negative values reset to the compiled default.Integer seconds30

Database Transaction Hooks

SQL statements executed by the profile's registration/dialog database thread. Use with care; intended for tuning external databases (for example PRAGMA or session settings).

ParameterPurposeAccepted ValuesDefault
db-pre-trans-executeSQL executed before each outer database transaction.SQL string(none)
db-post-trans-executeSQL executed after each outer database transaction.SQL string(none)
db-inner-pre-trans-executeSQL executed before each inner database transaction.SQL string(none)
db-inner-post-trans-executeSQL executed after each inner database transaction.SQL string(none)

Identity, RFC 7989, and RFC 8760

ParameterPurposeAccepted ValuesDefault
usernameUsername placed in the SDP origin (o=) line generated by this profile.StringFreeSWITCH
ext-sip-portPublic SIP port advertised in Contact/Via when behind NAT, when it differs from the bound sip-port. Set automatically by ext-sip-ip STUN resolution; can be overridden explicitly. Values of 0 or less are ignored.Port number(none; uses sip-port)
rfc-7989Enable RFC 7989 SIP Session-ID generation and propagation.true, falsefalse
rfc-7989-filterHeader-name filter controlling which messages carry the Session-ID, used with rfc-7989.Filter string(none)
rfc-7989-force-oldForce the older (pre-final) RFC 7989 Session-ID format for interoperability with early implementations.true, falsefalse
cid-in-1xxInclude caller/callee identity (Remote-Party-ID / P-Asserted-Identity) in 1xx provisional responses. Vanilla internal.xml ships this commented out.true, falsetrue
full-id-in-dialplanExpose the full SIP From identity (URI including parameters) to the dialplan rather than just the user portion.true, falsefalse
extended-info-parsingParse and expose additional fields from inbound SIP INFO requests.true, falsefalse
parse-invite-tel-paramsParse tel: URI parameters from inbound INVITE Request-URIs and expose them to the channel.true, falsefalse

Miscellaneous

ParameterPurposeAccepted ValuesDefault
track-callsEnable call tracking (recovery state persisted to the database for this profile). Once enabled it is not cleared by a false value during the same load.truefalse
update-refresherInclude the refresher parameter in Session-Expires on UPDATE requests. Also settable per-call via sip_update_refresher.true, falsefalse
auto-invite-100Automatically send 100 Trying for inbound INVITEs. Vanilla internal.xml ships this commented out.true, falsetrue
3pcc-reinvite-bridged-on-ackIn 3PCC, send the bridged re-INVITE on receipt of ACK rather than earlier, improving compatibility with some 3PCC flows.true, falsefalse
inbound-reg-in-new-threadProcess each inbound REGISTER in its own thread. Vanilla internal.xml ships this commented out.true, falsefalse
fire-bye-response-eventsFire a FreeSWITCH event when a response to an outbound BYE is received.true, falsefalse

Getting Started: Minimal Working Profile

The following is a minimal profile sufficient to accept and authenticate SIP calls on a single NATed host. Expand it by adding parameters from the reference tables above as your deployment requires.

<profile name="myprofile">
<aliases></aliases>
<gateways></gateways>
<domains>
<domain name="all" alias="true" parse="false"/>
</domains>

<settings>
<!-- Bind to the local LAN address -->
<param name="sip-ip" value="192.0.2.10"/>
<param name="rtp-ip" value="192.0.2.10"/>
<param name="sip-port" value="5060"/>

<!-- Advertise the public IP to remote parties (NAT scenario) -->
<param name="ext-sip-ip" value="203.0.113.1"/>
<param name="ext-rtp-ip" value="203.0.113.1"/>

<!-- Dialplan dispatch -->
<param name="context" value="default"/>
<param name="dialplan" value="XML"/>

<!-- Authentication -->
<param name="auth-calls" value="true"/>
<param name="nonce-ttl" value="60"/>
<param name="challenge-realm" value="auto_from"/>

<!-- ACL -->
<param name="apply-nat-acl" value="nat.auto"/>
<param name="apply-inbound-acl" value="domains"/>

<!-- Codec preferences -->
<param name="inbound-codec-prefs" value="OPUS,G722,PCMU,PCMA"/>
<param name="outbound-codec-prefs" value="OPUS,G722,PCMU,PCMA"/>
<param name="inbound-codec-negotiation" value="generous"/>

<!-- RTP timer -->
<param name="rtp-timer-name" value="soft"/>

<!-- DTMF -->
<param name="dtmf-type" value="rfc2833"/>

<!-- Hold music -->
<param name="hold-music" value="local_stream://moh"/>
</settings>
</profile>

After creating this file at conf/sip_profiles/myprofile.xml, load it with:

sofia profile myprofile start

Verify it is running with:

sofia status

The profile should appear with its bound SIP URI and transport.


Presence, BLF, and MWI

Presence, Busy Lamp Field (BLF), and Message Waiting Indication (MWI) all rely on the SIP SUBSCRIBE/NOTIFY mechanism. A phone sends a SUBSCRIBE for a specific event package; FreeSWITCH responds with a NOTIFY whenever the relevant state changes. The profile parameters in this section control whether FreeSWITCH accepts those subscriptions and how it handles them.

Enabling Presence

Presence is controlled by the manage-presence parameter on each profile. When set to true, the profile registers a full presence engine: it accepts SUBSCRIBE requests for dialog (BLF) and message-summary (MWI) event packages, stores subscriptions in the sip_subscriptions database table, and sends NOTIFY messages when state changes.

<param name="manage-presence" value="true"/>

Setting manage-presence to passive enables a read-only relay mode. A passive profile accepts presence events generated by the primary presence-enabled profile and forwards NOTIFYs to its own subscribers. This is used when a second profile (for example, an external profile) needs to relay presence state without driving it independently.

Setting manage-presence to false disables presence entirely on the profile. The external profile uses false by default because carrier trunks do not register or subscribe to presence.

The presence-hosts parameter is a comma-separated list of hostnames or IP addresses that this profile is responsible for in the presence domain. FreeSWITCH uses this list when matching an incoming SUBSCRIBE's Request-URI host against known profiles, and also when querying the sip_subscriptions table for matching subscribers. In the vanilla internal profile, this is set to the primary domain and the local IP:

<param name="presence-hosts" value="$${domain},$${local_ip_v4}"/>

If a phone subscribes to sip:1001@pbx.example.com and pbx.example.com is listed in presence-hosts, that profile will service the subscription.

The presence-privacy parameter suppresses caller identity in presence NOTIFYs. When true, the status line in NOTIFY bodies for early, confirmed, and hold states omits the remote party name or number, showing only generic text such as Ring, On The Phone, or Hold. This limits information visible to BLF watchers.

BLF (Busy Lamp Field)

BLF is implemented using the dialog SIP event package (RFC 4235). A phone with a BLF key sends a SUBSCRIBE request targeting the extension it wants to monitor:

SUBSCRIBE sip:1001@pbx.example.com SIP/2.0
Event: dialog
Accept: application/dialog-info+xml

When manage-presence is true on the receiving profile, FreeSWITCH accepts the SUBSCRIBE, stores it in sip_subscriptions, and immediately sends a NOTIFY reflecting the current call state of extension 1001. Subsequent NOTIFYs are sent whenever the dialog state of that extension changes: when a call arrives (early), when it is answered (confirmed), and when it ends (terminated).

BLF keys on the monitoring phone must target the extension's presence identity. By default the presence identity (presence_id channel variable) is user@domain. If the force-subscription-domain parameter is set on the profile, that domain is used in place of the domain from the SUBSCRIBE URI, ensuring subscriptions resolve correctly in single-domain deployments.

FreeSWITCH looks up active dialogs in the sip_dialogs table and joins them against sip_registrations to determine the current state of the subscribed entity. The NOTIFY body is formatted as application/dialog-info+xml.

Shared Line Appearance (SLA)

The manage-shared-appearance parameter enables Shared Line Appearance per the BroadSoft SCA specification. Setting it to true also forces manage-presence to full mode and enables multiple registrations (PFLAG_MULTIREG). SLA allows multiple phones registered to the same extension to coordinate call state through presence, so that all devices reflect whether the shared line is seized, active, or on hold. Set this on the profile serving the shared-line endpoints:

<param name="manage-shared-appearance" value="true"/>

MWI (Message Waiting Indication)

MWI uses the message-summary SIP event package (RFC 3842). A phone subscribes to the event package for its own address:

SUBSCRIBE sip:1001@pbx.example.com SIP/2.0
Event: message-summary
Accept: application/simple-message-summary

FreeSWITCH stores the subscription and sends a NOTIFY whenever the voicemail state for that mailbox changes. The NOTIFY body uses application/simple-message-summary format, for example:

Messages-Waiting: yes
Message-Account: sip:1001@pbx.example.com
Voice-Message: 3/1 (0/0)

How MWI is driven from voicemail

mod_voicemail fires a SWITCH_EVENT_MESSAGE_WAITING event each time a message is deposited, read, or deleted. That event carries the headers MWI-Messages-Waiting, MWI-Message-Account, and MWI-Voice-Message. mod_sofia listens for this event and queries sip_subscriptions for any subscriber whose sub_to_user and sub_to_host match the message account. For each matching subscription it sends a NOTIFY.

The mwi-account directory user variable

If a user's voicemail mailbox is different from their SIP registration address, set the mwi-account variable in the directory user entry. When the phone registers, FreeSWITCH stores the value of mwi-account as the mwi_user and mwi_host in sip_registrations. When a voicemail event arrives for that account, FreeSWITCH matches on mwi_user and mwi_host and delivers the NOTIFY to the registered contact even without an explicit subscription. This allows a phone registered as 1001@pbx.example.com to receive MWI for a mailbox at a different address.

<!-- In conf/directory/default/1001.xml -->
<user id="1001">
<params>
<param name="password" value="1234"/>
</params>
<variables>
<variable name="mwi-account" value="1001@voicemail.example.com"/>
</variables>
</user>

The mwi-account value is a user@host string. If the host portion is absent, FreeSWITCH falls back to the registration host.

presence_map.conf.xml

presence_map.conf.xml maps extension regex patterns to presence protocol identifiers. It is consulted when the profile parameter presence-proto-lookup is true and a SUBSCRIBE arrives for an extension whose protocol cannot be determined from the subscription itself. FreeSWITCH calls switch_ivr_check_presence_mapping(), which opens the config, iterates domain/extension entries, and returns the first proto whose regex matches the subscribed extension name.

The primary use case is routing subscriptions for conference room extensions (matching a regex) to the conf presence protocol instead of the default endpoint presence handling.

Enable the lookup on the profile:

<param name="presence-proto-lookup" value="true"/>

The file lives at conf/autoload_configs/presence_map.conf.xml. Structure:

<configuration name="presence_map.conf" description="PRESENCE MAP">
<domains>
<domain name="pbx.example.com">
<!-- Extensions matching 3xxx map to conference presence -->
<exten regex="3\d+" proto="conf"/>
<!-- Extensions matching 4xxx map to park presence -->
<exten regex="4\d+" proto="park"/>
</domain>
</domains>
</configuration>

Use name="*" on the domain element to match all domains. Each exten element is evaluated in document order and the first match wins. If no entry matches, FreeSWITCH uses standard presence handling.

Presence Parameter Reference

The following parameters appear in the profile settings block. Parameters already covered in Section 5.3 are repeated here for completeness as part of the presence feature group.

ParameterPurposeAccepted ValuesDefault
manage-presenceEnable or disable the presence engine on this profile. true enables full SUBSCRIBE/NOTIFY handling. passive relays presence from a primary profile. pnp enables plug-and-play provisioning presence. false disables presence.true, false, passive, pnpfalse
presence-hostsComma-separated list of hostnames or IP addresses that this profile services for presence subscriptions. Used to match SUBSCRIBE Request-URI hosts and to query sip_subscriptions.Comma-separated host list(none)
presence-privacyWhen true, suppress caller identity in BLF NOTIFYs; status shows generic text only (Ring, On The Phone, Hold) without the remote party number or name.true, falsefalse
presence-probe-on-registerOn each REGISTER, send a presence probe to the registering endpoint to force it to re-publish its current presence state.true, falsefalse
send-presence-on-registerPush presence information to all watchers of this user on REGISTER. true or all pushes on every REGISTER; first-only pushes only on the initial REGISTER for a contact.true, all, first-only, falsefalse
manage-shared-appearanceEnable BroadSoft Shared Call Appearance (SCA/SLA) for shared line management. Setting true also enables full presence and multiple registrations.true, falsefalse
presence-proto-lookupWhen true, consult presence_map.conf.xml to determine the presence protocol for a subscribed extension when it cannot be inferred from the SUBSCRIBE itself.true, falsefalse
presence-hold-stateControls the dialog state reported in BLF NOTIFYs when a call is on hold. confirmed reports held calls as confirmed (active). terminated reports them as terminated. Default leaves hold state as-is in the dialog XML.confirmed, terminated(none)
force-subscription-domainOverride the domain used when routing SUBSCRIBE requests, ensuring single-domain deployments resolve subscriptions correctly.Domain name(none; uses domain from request)
auth-subscriptionsRequire digest authentication for SUBSCRIBE requests. Set true on profiles that serve registered endpoints to prevent unauthenticated presence subscriptions.true, falsetrue