Skip to main content

Chapter 18: Audio Files and Streaming Sources

FreeSWITCH resolves audio from multiple source types: plain file paths resolved through the media file system, synthesized tone streams, locally managed playlist streams, and remote MP3 or Icecast feeds. Each source type is handled by a dedicated format module that registers one or more URI schemes or file extensions. This chapter describes every playable source type available to the operator, the modules that back them, and the configuration parameters that govern their behavior.

Playable Sources Overview

Wherever FreeSWITCH accepts an audio source -- dialplan applications such as playback, ringback, hold_music, conference prompts, IVR menus, and so on -- the value is one of:

  • A file path: an absolute path or a path relative to $${sound_prefix}.
  • A stream URI: a scheme-qualified string such as local_stream://moh, tone_stream://..., shout://..., or silence_stream://500.

The sound_prefix Variable

$${sound_prefix} is a preprocessor variable set in conf/vanilla/vars.xml:

<X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/en/us/callie"/>

When a bare filename is given (no leading /), FreeSWITCH prepends $${sound_prefix} to form a full path. The variable can be overridden at runtime with global_setvar sound_prefix=<path>; persistent changes require editing vars.xml and reloading the configuration.

$${sounds_dir} is a built-in variable automatically resolved by FreeSWITCH to the compiled-in sounds installation directory (typically /usr/share/freeswitch/sounds on Debian-family systems).

URI Scheme Summary

SchemeModulePurpose
local_stream://mod_local_streamDirectory-backed playlist stream
tone_stream://mod_tone_streamSynthesized TGML tone
silence_stream://mod_tone_streamTimed silence
shout://mod_shoutHTTP MP3 or Icecast stream (plain)
shouts://mod_shoutHTTP MP3 or Icecast stream (TLS)

Plain file paths (.wav, .ogg, .mp3, etc.) are dispatched to mod_sndfile or mod_shout based on extension.

Additional streaming-source format modules ship with FreeSWITCH and register their own schemes or extensions when loaded: mod_vlc plays and streams media via libVLC, mod_shell_stream streams audio from the standard output of an external command, and mod_http_cache fetches and caches remote audio over HTTP(S) for playback. Each is documented in the Part 9 module reference.


mod_sndfile and Supported File Formats

mod_sndfile wraps libsndfile and is the default handler for recorded audio files. It registers file extensions dynamically at load time based on what libsndfile reports as available on the host system.

Core Extensions

The following extensions are always registered (subject to libsndfile support and the optional allowed-extensions configuration parameter):

Extension(s)Format
wavMicrosoft WAV (PCM, commonly 16-bit)
aiff, iffAIFF / IFF (16-bit PCM)
ogg, ogaOgg Vorbis
flacFLAC
au, sndSun AU
raw, r8Raw PCM 16-bit, 8 kHz
r16Raw PCM 16-bit, 16 kHz
r24Raw PCM 24-bit, 24 kHz
r32Raw PCM 32-bit, 32 kHz
gsmGSM 6.10 raw, 8 kHz
ul, ulawRaw G.711 ulaw, 8 kHz
al, alawRaw G.711 alaw, 8 kHz
voxDialogic VOX ADPCM, 8 kHz, mono
adpcmIMA ADPCM WAV, 8 kHz, mono
wvePsion WVE (alaw), 8 kHz
htkHTK format, 8 kHz
xiInstrument file (DPCM 16-bit, 44.1 kHz)
sdsMidi Sample Dump Standard, 8 kHz

Sample-Rate Resolution

When opening a file, mod_sndfile first attempts to open <dir>/<rate>/<filename> (inserting the session sample rate as a path component). If that path does not exist it falls back to the highest available rate directory (48000, 32000, 16000, 8000) and finally to the literal path provided.

Configuration

mod_sndfile has no mandatory configuration. The vanilla configuration ships conf/autoload_configs/sndfile.conf.xml with all parameters commented out. The optional allowed-extensions parameter (comma-separated list) restricts which extensions are registered. When allowed-extensions is absent, all extensions that libsndfile reports are registered.


mod_native_file

mod_native_file handles files whose data is already encoded in a codec-native format, bypassing any PCM transcoding. At load time it enumerates every audio codec implementation that has a non-zero encoded_bytes_per_packet and registers the codec's IANA name as a file extension.

Typical extensions registered: PCMU, PCMA, G722, G729, GSM, iLBC, OPUS, and others depending on which codec modules are loaded.

Files handled by mod_native_file are transmitted directly without re-encoding (the SWITCH_FILE_NATIVE and SWITCH_FILE_NOMUX flags are set). The module infers the sample rate from the extension: G722 files default to 16000 Hz; all others default to 8000 Hz.


mod_local_stream and Music on Hold

mod_local_stream provides a shared, continuously running audio stream backed by a directory of audio files. Multiple channels can attach to the same stream simultaneously; all listeners receive the same audio at the same position. This makes it suitable for music-on-hold (MOH) and background music applications.

The URI scheme is:

local_stream://<directory-name>

where <directory-name> matches the name attribute of a <directory> element in local_stream.conf.xml.

When FreeSWITCH opens local_stream://moh it first attempts to find moh/<session_sample_rate> (e.g., moh/16000). If that directory is not configured it falls back to moh, and if that is also absent it falls back to default.

Configuration File

conf/autoload_configs/local_stream.conf.xml defines one or more named directories. The vanilla configuration ships four rate-specific MOH directories and a default directory:

<configuration name="local_stream.conf" description="stream files from local dir">

<!-- fallback to default if requested moh class isn't found -->
<directory name="default" path="$${sounds_dir}/music/8000">
<param name="rate" value="8000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="20"/>
<param name="timer-name" value="soft"/>
</directory>

<directory name="moh/8000" path="$${sounds_dir}/music/8000">
<param name="rate" value="8000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="20"/>
<param name="timer-name" value="soft"/>
</directory>

<directory name="moh/16000" path="$${sounds_dir}/music/16000">
<param name="rate" value="16000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="20"/>
<param name="timer-name" value="soft"/>
</directory>

<directory name="moh/32000" path="$${sounds_dir}/music/32000">
<param name="rate" value="32000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="20"/>
<param name="timer-name" value="soft"/>
</directory>

<directory name="moh/48000" path="$${sounds_dir}/music/48000">
<param name="rate" value="48000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="10"/>
<param name="timer-name" value="soft"/>
</directory>

</configuration>

The path attribute specifies the filesystem directory from which audio files are read. The module reads every supported audio file in that directory; files with a .loc extension are treated as plain-text lists of file paths, one per line.

Directory Parameter Reference

ParameterPurposeAccepted ValuesDefault
rateSample rate of the stream. Files are opened at this rate.8000, 12000, 16000, 24000, 32000, 480008000
shuffleRandomize playback order across the directory. When true, the stream starts at a random position in the file list.true, falsefalse
channelsNumber of audio channels.1 (mono), 2 (stereo)1
intervalPacketization interval in milliseconds. Must be a multiple of 10 and no greater than 120 ms; out-of-range values fall back to the default.Integer, multiple of 10, 10-12020
timer-nameTimer used to pace audio output. soft is the software timer; posix uses the POSIX timer.soft, posixsoft
chime-listComma-separated list of audio files to interject periodically. Files are played in rotation.Comma-separated file paths(none)
chime-freqHow often (in seconds) a chime file is played. Must be greater than 1.Integer > 130
chime-maxMaximum number of seconds the chime file plays before cutting back to the main stream. Must be greater than 1.Integer > 1(unlimited)
volumeAdjusts output volume. Granular volume control; the value is clamped to the allowed range internally.Integer -50-500 (no change)
auto-volumeTarget energy average for automatic gain control. 0 disables AGC.Integer 0-200000
auto-volume-low-pointLow-energy threshold for the AGC. Used alongside auto-volume.Integer 0-200000
prebufPre-buffer size in bytes. Controls how much audio is buffered before distribution to listeners.Integer (bytes)65536
blank-imgPath to a PNG image displayed when the stream has no video.File path to a .png(none)
logo-imgPath to a PNG logo overlaid on video frames when a banner is active.File path to a .png(none)
logo-alwaysWhen true, the logo is displayed even when no banner text is present.true, falsefalse
logo-positionPosition of the logo image on the video frame.left-top, left-mid, left-bot, center-top, center-mid, center-bot, right-top, right-mid, right-bot, none(none)
logo-opacityOpacity of the logo overlay (0 = transparent, 100 = opaque).Integer 0-100100
text-opacityOpacity of banner text overlaid on video frames.Integer 0-100100

Runtime Management

mod_local_stream exposes an API command for runtime control:

local_stream <show|start|reload|stop|hup|vol> <stream-name> [<args>]
SubcommandEffect
showLists all running streams (name and path). With a stream name, shows detail. Append as xml for XML output.
startStarts a stopped or newly added stream by name.
stopStops the named stream. Attached listeners receive silence.
reloadReloads the stream's configuration and restarts playback. If the stream is in use, a partial reload applies the subset of parameters that can change without restarting the thread.
hupSkips the current file and begins the next one immediately.
volAdjusts the stream volume at runtime. Form: local_stream vol <name> <level|auto:avg[:low]>. A plain integer level (clamped to -50-50) sets a fixed gain and disables AGC. The auto: form enables automatic gain control: avg is the target energy average and the optional :low is the low-energy point (each 0-20000). With no argument it reports the current setting.

Example:

local_stream show moh/8000
local_stream reload moh/8000

mod_tone_stream and the TGML Generator

mod_tone_stream synthesizes audio from a text description using the Teletone Generation Markup Language (TGML). The URI scheme is:

tone_stream://<tgml-string>[;loops=<n>]

The optional loops suffix (separated by ;) specifies how many times the tone sequence repeats. A value of -1 loops indefinitely.

TGML Syntax

TGML is a semicolon-delimited sequence of commands and tone specifications. Each tone specification has the form:

%(on_ms,off_ms,freq1[,freq2,...])
FieldMeaning
on_msTone-on duration in milliseconds
off_msSilence duration in milliseconds (0 for continuous tone)
freq1, freq2, ...One or more frequencies in Hz (mixed together)

Additional TGML modifiers (applied before a tone spec, terminated with ;):

ModifierSyntaxMeaning
Volumev=<db>Set initial volume in dB (e.g., v=-7)
Duration limitd=<ms>Maximum duration in milliseconds applied to subsequent tones
Loops (spec)l=<n>Repeat count for the immediately following tone spec
Loops (sequence)L=<n>Repeat count for the entire tone sequence
Volume decay step>=<ms>Apply volume decay every <ms> milliseconds; volume decreases by the decay factor each step
Volume growth step<=<ms>Apply volume growth every <ms> milliseconds; volume increases by the decay factor each step
Volume decay amount+=<db>Amount in dB to change volume on each decay or growth step (used with > or <)
Waitw=<ms>Insert a silent wait period in milliseconds before the next tone
Channelsc=<n>Set the number of output channels
Sample rater=<hz>Set the sample rate for subsequent generation

Example: US dial tone (350 Hz + 440 Hz, continuous)

tone_stream://%(10000,0,350,440);loops=-1

Example: US ringback (2 seconds on, 4 seconds off)

tone_stream://%(2000,4000,440,480);loops=-1

Example: SIT (Special Information Tone)

tone_stream://%(274,0,913.8);%(274,0,1370.6);%(380,0,1776.7)

The vars.xml vanilla configuration defines national ringback tones using this syntax, for example:

<X-PRE-PROCESS cmd="set" data="us-ring=%(2000,4000,440,480)"/>

These variables are then referenced as $${us-ring} wherever a ringback tone is needed.

Tone File Input

Instead of an inline TGML string, tone_stream can read from a file:

tone_stream://path=</path/to/tone.tgml>

The file contains TGML lines, one command or tone spec per line.

silence_stream

mod_tone_stream also registers the silence_stream:// scheme, which generates silence:

silence_stream://<duration_ms>[,<comfort_noise_level>]

duration_ms specifies the length of silence in milliseconds. A negative value produces silence indefinitely. The optional comfort_noise_level is a positive integer divisor that controls the amplitude of generated comfort noise: smaller values produce louder noise, larger values produce quieter noise (e.g., 400 is a typical light comfort noise level). When omitted, the stream produces pure digital silence (all zeros).

Example: 5 seconds of silence

silence_stream://5000

Example: infinite silence with comfort noise

silence_stream://-1,400

mod_shout and the shout:// Scheme

mod_shout provides read and write access to MP3 files and HTTP-based Icecast/SHOUTcast streams. It links against libshout, libmp3lame, and libmpg123.

Registered Extensions and Schemes

mod_shout registers the following file extensions: mp3, mpga.

It registers the following URI schemes: shout, shouts.

When a shout:// or shouts:// URI is used, the module constructs an HTTP or HTTPS URL internally and fetches the stream using libcurl. The shouts:// scheme maps to https://.

The source comment in the module source documents the URL form for Icecast broadcasting:

shout://user:pass@host.com/mount.mp3

Reading: HTTP and Icecast Streams

To play an MP3 file from HTTP or an Icecast stream:

<action application="playback" data="shout://icecast.example.com/stream.mp3"/>
<action application="playback" data="shout://user:password@broadcast.example.com/live.mp3"/>

For TLS-secured streams:

<action application="playback" data="shouts://secure.example.com/stream.mp3"/>

Local MP3 files are opened directly by path using the registered mp3 extension; no shout:// prefix is needed:

<action application="playback" data="/var/sounds/hold_music.mp3"/>

Writing: Icecast Broadcasting

mod_shout can encode and broadcast audio to an Icecast server when used as a recording target with a shout:// URL. The module encodes PCM audio to MP3 using LAME at runtime.

Global Configuration

The vanilla configuration ships conf/autoload_configs/shout.conf.xml with all parameters commented out. mod_shout reads this file at load time for optional global settings:

ParameterPurposeDefault
decoderForce a specific mpg123 decoder architecture (e.g., i586). When empty, mpg123 selects the optimal decoder automatically.(empty, auto-select)
volumempg123 playback volume as a floating-point multiplier (e.g., 0.1). Applied only when decoder or outscale is also set.(unset)
outscalempg123 output scale factor (integer). On 64-bit builds, FreeSWITCH applies a default of 8192 when no explicit globals are configured; set this param to override.(unset; 8192 applied on 64-bit when no other globals are set)
encode-brateEncoding bit rate in kbps for the LAME encoder when writing MP3 or broadcasting to Icecast.16 * (samplerate/8000) * channels kbps (16 kbps at 8 kHz mono)
encode-resampleOutput sample rate for the LAME encoder in Hz.(unset, LAME uses session rate)
encode-qualityLAME encoding quality (integer; lower is higher quality). When unset, FreeSWITCH uses quality 2 (high).2

The hold_music Variable

The global variable hold_music specifies the audio source played to a caller placed on hold. It is set in conf/vanilla/vars.xml:

<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>

Any playable source accepted by the FreeSWITCH file interface can be assigned to hold_music: a local_stream:// URI, a tone_stream:// URI, an absolute file path, or a shout:// stream URL.

The variable is evaluated at hold time. Overriding it on a per-call or per-directory basis follows standard variable precedence: a channel variable set in the dialplan or user directory takes precedence over the global value.

Examples:

<!-- Use a local stream (default) -->
<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>

<!-- Use a synthesized ringback tone as hold music -->
<X-PRE-PROCESS cmd="set" data="hold_music=tone_stream://%(2000,4000,440,480);loops=-1"/>

<!-- Use a remote Icecast stream -->
<X-PRE-PROCESS cmd="set" data="hold_music=shout://icecast.example.com/jazz.mp3"/>

<!-- Per-call override in dialplan -->
<action application="set" data="hold_music=local_stream://moh/16000"/>

When hold_music points to local_stream://moh, FreeSWITCH automatically selects the sample-rate-appropriate sub-directory (moh/8000, moh/16000, etc.) based on the session's negotiated codec rate, falling back through moh to default if no matching directory exists.


Recording Calls

FreeSWITCH provides two complementary mechanisms for recording calls: the record_session dialplan application, which attaches a recorder to the session at call setup time, and the uuid_record API command, which starts or stops recording on a live call from the CLI or ESL. Both mechanisms write to any file format supported by the loaded format modules (WAV, MP3 via mod_shout, OGG, etc.). Recording behavior is governed by a set of channel variables prefixed with RECORD_.

record_session: Full-Call Recording from the Dialplan

record_session starts a background media tap that captures both the read (inbound, caller) and write (outbound, callee) audio legs mixed together into a single file. The recorder runs independently of dialplan execution; it continues until the call ends, an explicit stop_record_session is executed, or the optional timeout expires.

Syntax:

record_session <path> [+<timeout_sec>] [{var1=val1,var2=val2,...}]
ArgumentDescription
<path>Destination file path. Must be an absolute path or a path relative to sound_prefix. The file extension determines the output format.
+<timeout_sec>Optional. Stops the recording after the specified number of seconds. The + prefix is required.
{var=val,...}Optional inline variable block. Sets RECORD_* variables scoped to this recording only (preferred over channel variables when multiple recordings are active).

To stop a recording started with record_session:

stop_record_session <path>

The <path> argument to stop_record_session must match the path given to record_session exactly.

Additional per-recording controls (all accept <path> matching the active recording):

ApplicationEffect
record_session_pause <path>Pauses writing audio to the file. Audio received during a pause is discarded.
record_session_resume <path>Resumes writing to a paused recording.
record_session_mask <path>Replaces audio with silence (comfort noise) in the file without stopping the recording. See section 18.8.5.
record_session_unmask <path>Restores normal audio capture after a mask.

uuid_record: Live Recording Control via API

uuid_record is a FreeSWITCH API command (available at the fs_cli prompt and over ESL) that attaches or detaches a recorder on an already-established call.

Syntax:

uuid_record <uuid> <start|stop|mask|unmask|pause|resume> <path> [<limit>] [<recording_vars>]
FieldDescription
<uuid>The UUID of the target session.
<start|stop|mask|unmask|pause|resume>Action to perform.
<path>Destination file path. Required for all actions; must match the path used at start when stopping or masking.
<limit>Optional. Maximum recording duration in seconds (applies to start only).
<recording_vars>Optional. URL-encoded inline variable block (same {var=val,...} syntax as the dialplan application).

Examples:

uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 start /var/recordings/2dcb9f46.wav
uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 stop /var/recordings/2dcb9f46.wav
uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 pause /var/recordings/2dcb9f46.wav
uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 resume /var/recordings/2dcb9f46.wav

Stereo Recordings

By default, record_session mixes both legs of a call into a mono file. Setting RECORD_STEREO=true produces a 2-channel WAV where channel 1 carries the read stream (caller audio) and channel 2 carries the write stream (callee audio). This requires a file format that supports stereo; .wav and .ogg both qualify. .mp3 encoding via mod_shout also supports stereo output.

RECORD_STEREO_SWAP=true produces the same stereo split but reverses the channel assignment: channel 1 receives the write stream and channel 2 receives the read stream.

RECORD_STEREO and RECORD_STEREO_SWAP are mutually exclusive; if both are set, RECORD_STEREO takes precedence. Stereo recording is only available when the session leg being tapped is mono; if the codec negotiated for the leg is already stereo, neither flag has any effect.

RECORD_* Control and Metadata Variables

The following channel variables (or inline recording variables) control recording behavior. Variables can be set as standard channel variables with set, or scoped to a single recording by passing them in the inline variable block {...} argument.

VariablePurpose
RECORD_STEREOWhen true, write a 2-channel file with read leg on channel 1 and write leg on channel 2.
RECORD_STEREO_SWAPWhen true, write a 2-channel file with write leg on channel 1 and read leg on channel 2.
RECORD_READ_ONLYWhen true, record only the read (inbound/caller) leg; the write leg is excluded.
RECORD_WRITE_ONLYWhen true, record only the write (outbound/callee) leg; the read leg is excluded.
RECORD_ANSWER_REQWhen true, do not begin writing audio until the channel is answered.
RECORD_BRIDGE_REQWhen true, do not begin writing audio until the channel is bridged to another leg.
RECORD_MIN_SECMinimum duration in seconds. If the recording is shorter than this value when stopped, the file is deleted. Default is 0 (no minimum); when RECORD_APPEND is active, the effective default is 3.
RECORD_APPENDWhen true, open the file in append mode rather than overwriting it.
record_sample_rateForce the recording sample rate (e.g., 8000, 16000). When unset, the session's negotiated sample rate is used.
record_waste_resourcesWhen true (or a positive integer specifying amplitude), generate comfort noise to keep the encoder active even during silence. Useful for formats that require continuous frames.
RECORD_TITLETitle metadata tag written to the output file (supported formats: WAV, OGG, FLAC). Cleared from the channel after being applied.
RECORD_ARTISTArtist metadata tag written to the output file. Cleared after being applied.
RECORD_COMMENTComment metadata tag written to the output file. Cleared after being applied.
RECORD_COPYRIGHTCopyright metadata tag written to the output file. Cleared after being applied.
RECORD_DATEDate metadata tag written to the output file. Cleared after being applied.
RECORD_SOFTWARESoftware metadata tag written to the output file. Cleared after being applied.
record_post_process_exec_appDialplan application to execute after the recording completes. Format: app_name::app_args. Channel variables are expanded at execution time.
record_post_process_exec_apiAPI command to execute after the recording completes. Format: api_name:api_args. Channel variables are expanded at execution time.

Masking Sensitive Audio

When a call enters a phase where audio must not appear in the recording (for example, while a caller enters a payment card number on their keypad), the recording can be masked without being stopped and restarted. Masking replaces captured audio with silence in the output file; the timestamp of the recording continues advancing normally so the surrounding context is preserved.

From the dialplan:

<!-- Begin masking -->
<action application="record_session_mask" data="/var/recordings/${uuid}.wav"/>

<!-- ... IVR steps for card-number entry ... -->

<!-- End masking -->
<action application="record_session_unmask" data="/var/recordings/${uuid}.wav"/>

From the CLI or ESL:

uuid_record <uuid> mask /var/recordings/<uuid>.wav
uuid_record <uuid> unmask /var/recordings/<uuid>.wav

The path supplied to record_session_mask/record_session_unmask must match the path of an active recording on that session.

Post-Processing Recordings

Two channel variables trigger automatic post-processing after a recording stops.

record_post_process_exec_app specifies a dialplan application to execute. The value format is <app_name>::<app_args>. Channel variables in <app_args> are expanded at execution time, so the recording file path can be passed via ${record_file_path} or any other variable set by the session.

record_post_process_exec_api specifies a FreeSWITCH API command to execute. The value format is <api_name>:<api_args>. Channel variables are expanded in <api_args> before the command is dispatched.

Both variables are checked after every recording stops on the session, including recordings stopped by stop_record_session or by call hangup.

Example: convert WAV to MP3 after the call ends

<action application="set"
data="record_post_process_exec_api=system:lame --quiet /var/recordings/${uuid}.wav /var/recordings/${uuid}.mp3"/>

Worked Examples

Dialplan: record a bridged call to a per-UUID file in stereo

<extension name="outbound-record">
<condition field="destination_number" expression="^(\d+)$">

<!-- Enable stereo recording: caller on ch1, callee on ch2 -->
<action application="set" data="RECORD_STEREO=true"/>

<!-- Delete the file if the call is shorter than 3 seconds -->
<action application="set" data="RECORD_MIN_SEC=3"/>

<!-- Start recording before bridge so hold audio is captured -->
<action application="record_session"
data="/var/recordings/${uuid}.wav"/>

<action application="bridge" data="sofia/gateway/mygateway/$1"/>

<!-- Explicit stop is optional; the recording stops on hangup -->
<action application="stop_record_session"
data="/var/recordings/${uuid}.wav"/>
</condition>
</extension>

CLI: attach a recording to an active call, then stop it

uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 start /var/recordings/2dcb9f46.wav
uuid_record 2dcb9f46-3a73-11ef-8d62-b7e5a3d1e2f9 stop /var/recordings/2dcb9f46.wav

Sofia profile auto-recording (cross-reference)

The Sofia SIP profile parameters record-template and record-path instruct mod_sofia to call record_session automatically for every call handled by that profile, without requiring dialplan actions. Refer to Chapter 7: SIP Profiles with Sofia for the full parameter reference for those settings.


Phrases and the Say System

FreeSWITCH provides two higher-level audio primitives that sit above fixed file playback: the say application, which renders a value (a number, date, currency amount, and so on) by passing it to a language-specific say module; and the phrase application, which executes a named macro that can combine pre-recorded files, say actions, and dialplan application calls into a single compound prompt. Together they form the system used to build spoken IVR prompts, voicemail announcements, and any other prompt that depends on run-time data.

Three-Layer Model

LayerApplicationWhat it does
Fixed fileplaybackPlays a static audio file from disk. No run-time rendering.
Say modulesayPasses a value to a language say module (mod_say_en, and so on) which assembles pre-recorded digit and word files into spoken output.
Phrase macrophraseLooks up a named macro in the loaded language XML, then executes its sequence of play-file, say, execute, and phrase actions.

The phrase system is the highest level: a single phrase call can play a fixed file, invoke say to render a number, and insert a pause, all in the correct order for the target language.

Language Loading: the languages Section

conf/vanilla/freeswitch.xml contains a languages configuration section that includes every lang file at startup:

<section name="languages" description="Language Management">
<X-PRE-PROCESS cmd="include" data="lang/de/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/en/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/fr/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/ru/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/he/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/es/es_ES.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/pt/pt_BR.xml"/>
</section>

Each included XML file defines one <language> element. FreeSWITCH parses all included <language> elements at startup and makes them available to the phrase and say applications by language name. Changes to lang files take effect on a full reloadxml.

Language File Structure

conf/vanilla/lang/en/en.xml is the English language root file. It defines the en language entry and uses <X-PRE-PROCESS cmd="include"> to pull in macro files from subdirectories:

<language name="en" say-module="en" sound-prefix="$${sound_prefix}"
tts-engine="cepstral" tts-voice="callie">
<phrases>
<macros>
<X-PRE-PROCESS cmd="include" data="demo/*.xml"/>
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/>
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/>
<X-PRE-PROCESS cmd="include" data="ivr/*.xml"/>
</macros>
</phrases>
</language>
AttributePurpose
nameThe language identifier used by phrase and say to look up this language.
say-moduleThe say module (mod_say_en) loaded to handle say actions within macros and say application calls.
sound-prefixBase path prepended to relative filenames in play-file actions. Overrides the channel sound_prefix variable for the duration of the macro.
tts-engineDefault TTS engine for speak-text actions within macros (requires a TTS module).
tts-voiceDefault TTS voice paired with tts-engine.

The <phrases> element contains one or more <macros> blocks. Each <macros> block holds <macro> elements, which are the named phrase macros the phrase application looks up by name.

Phrase Macro Structure

A phrase macro is a <macro> element containing one or more <input> blocks. Each <input> tests the data string passed to phrase against a regular expression pattern. If the pattern matches, the actions inside <match> execute; if it does not match, actions inside <nomatch> execute (if present).

General skeleton:

<macro name="macro-name">
<input pattern="<regex>">
<match>
<action function="play-file" data="path/to/file.wav"/>
<action function="say" data="$1" method="pronounced" type="number"/>
<action function="execute" data="sleep(100)"/>
</match>
<nomatch>
<action function="play-file" data="path/to/error.wav"/>
</nomatch>
</input>
</macro>

Real example from conf/vanilla/lang/en/vm/sounds.xml -- voicemail_message_count:

<macro name="voicemail_message_count">
<input pattern="^(1):(.*)$" break_on_match="true">
<match>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="$1" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-$2.wav"/>
<action function="play-file" data="voicemail/vm-message.wav"/>
</match>
</input>
<input pattern="^(\d+):(.*)$">
<match>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="$1" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-$2.wav"/>
<action function="play-file" data="voicemail/vm-messages.wav"/>
</match>
</input>
</macro>

This macro is called with a data string like 1:new or 3:new. The first <input> uses break_on_match="true" so that when its pattern matches, FreeSWITCH stops evaluating further <input> blocks. Capture groups from the regex are available as $1, $2, and so on in data attributes.

Real example from conf/vanilla/lang/en/demo/demo.xml -- saydate:

<macro name="saydate">
<input pattern="(.*)">
<match>
<action function="say" data="$1" method="pronounced" type="current_date_time"/>
</match>
</input>
</macro>

Action functions available inside <match> and <nomatch>:

function valueEffect
play-filePlays the audio file at data. The path is relative to the language sound-prefix.
sayInvokes the language say module. Requires type and method attributes; data is the value to say.
executeRuns a dialplan application named in data (for example, sleep(100)).
phraseRecursively executes another named phrase macro. Requires a phrase attribute naming the target macro.
speak-textPasses data to the TTS engine configured on the <language> element.
breakStops all further action and input processing immediately.

The phrase application is invoked from the dialplan as:

<action application="phrase" data="macro-name,data-string"/>

The phrase application reads the channel variable language (or falls back to default_language, then to en) to select which loaded <language> block to search for the named macro.

The say Application

The say dialplan application passes a value directly to a language say module without going through a phrase macro. It renders numbers, dates, money, time, IP addresses, phone numbers, and spelled names via a language-specific mod_say_* module, which assembles pre-recorded sound files into spoken output.

For the full say syntax, the per-type table (number, currency, current_date_time, ip_address, telephone_number, and so on), the say-method reference (pronounced, iterated, counted, pronounced_year), the list of supported language modules, and dialplan examples, see the Say Modules reference.

sound_prefix and Language Sound Files

When a phrase macro action uses play-file with a relative path, FreeSWITCH prepends the language sound-prefix attribute to build the full path. For the en language, sound-prefix is set to $${sound_prefix} in en.xml, which evaluates to the value of the preprocessor variable from conf/vanilla/vars.xml:

<X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/en/us/callie"/>

So a play-file action with data="voicemail/vm-you_have.wav" resolves to:

/usr/share/freeswitch/sounds/en/us/callie/voicemail/vm-you_have.wav

The say application also uses this same path root: when mod_say_en assembles digit files it references relative paths such as digits/1.wav, digits/million.wav, currency/dollars.wav, and phonetic-ascii/65.wav, all resolved under the active sound_prefix.

The channel variable sound_prefix can be overridden per call:

<action application="set" data="sound_prefix=/var/sounds/en/us/myvoice"/>

The language XML can also lock the prefix so the channel variable cannot override it by setting sound-prefix-enforced="true" on a <macros> block.

Adding a Custom Phrase Macro

Place a new XML file in conf/vanilla/lang/en/ivr/ (the ivr/*.xml glob is already included by en.xml) or create a new file and add an explicit <X-PRE-PROCESS cmd="include"> for it inside the <macros> block in en.xml.

Example: a macro that announces an account balance

<macro name="account_balance">
<!-- Match a decimal amount like "142.50" -->
<input pattern="^(\d+\.\d+)$">
<match>
<action function="play-file" data="custom/your_balance_is.wav"/>
<action function="say" data="$1" method="pronounced" type="currency"/>
</match>
<nomatch>
<action function="play-file" data="custom/invalid_amount.wav"/>
</nomatch>
</input>
</macro>

Save it to conf/vanilla/lang/en/ivr/account.xml. Run reloadxml at the FreeSWITCH console. Call it from the dialplan:

<action application="phrase" data="account_balance,142.50"/>

The phrase application passes the string 142.50 as the data argument. The <input> pattern ^(\d+\.\d+)$ matches, the capture group $1 becomes 142.50, play-file plays custom/your_balance_is.wav from the sound prefix directory, and then say with type currency and method pronounced renders "one hundred forty-two dollars and fifty cents".

To target a language other than the channel default, set the language channel variable before calling phrase:

<action application="set" data="language=en"/>
<action application="phrase" data="account_balance,142.50"/>