Recipe: A Conference Bridge with a PIN
Goal
A team wants a single conference number that is protected by a PIN. Callers
dial an extension, are prompted to enter a PIN, and -- if it matches -- join a
shared room. One PIN admits ordinary participants; a second PIN admits
moderators, who get the moderator key map and non_moderator control over
everyone else.
mod_conference already knows how to collect and validate a PIN, so the
simplest build needs no digit-collection logic in the dialplan at all: the
profile carries a pin and a moderator-pin, and the conference application
prompts the caller and checks what they enter. This recipe shows that
profile-driven approach first, then a variation that collects the PIN in the
dialplan with play_and_get_digits when you want full control over the prompt.
Call flow:
- An internal caller dials the conference extension (
3500). - A dialplan extension answers the call and runs the
conferenceapplication with a room name and profile. - The room is created on the first caller's entry from the named profile; later callers join the existing room.
- Because the profile defines a
pin(and amoderator-pin),conferenceplays thepin-soundprompt and collects digits. - If the digits match the moderator PIN, the caller joins with the
moderatorflag; if they match the entry PIN, they join as an ordinary member; otherwise they are re-prompted up topin-retriestimes and then rejected.
Prerequisites
- Conferencing with
mod_conference-- the conference model, profiles, theconferenceapplication argument syntax, and member flags. - IVR Menus -- background on prompt-driven digit collection (used by the dialplan-PIN variation below).
- The Dialplan Application Reference -- the
answer,play_and_get_digits, andconferenceapplications. - A working XML dialplan -- this recipe adds an
extension to the
defaultcontext that ships inconf/vanilla/.
Build it
There are two pieces: a profile in conference.conf.xml that defines the
PINs, and a dialplan extension that answers the call and enters the room.
1. A conference profile with PINs
The vanilla conference.conf.xml ships a default profile but leaves its pin
and moderator-pin commented out. Rather than edit default (which the bundled
30xx extensions reuse), add a dedicated profile. Place it inside the
<profiles> block of conf/autoload_configs/conference.conf.xml:
<profile name="secure">
<param name="domain" value="$${domain}"/>
<param name="rate" value="8000"/>
<param name="interval" value="20"/>
<param name="energy-level" value="100"/>
<!-- Entry PIN for ordinary participants. -->
<param name="pin" value="12345"/>
<!-- A different PIN that grants moderator status on entry. -->
<param name="moderator-pin" value="54321"/>
<!-- Attempts allowed before the caller is rejected. -->
<param name="pin-retries" value="3"/>
<!-- Prompt and error files used while collecting the PIN. -->
<param name="pin-sound" value="conference/conf-pin.wav"/>
<param name="bad-pin-sound" value="conference/conf-bad-pin.wav"/>
<!-- Announce the member count once the room reaches one member. -->
<param name="announce-count" value="1"/>
<!-- Sounds and behaviors carried over from the default profile. -->
<param name="muted-sound" value="conference/conf-muted.wav"/>
<param name="unmuted-sound" value="conference/conf-unmuted.wav"/>
<param name="alone-sound" value="conference/conf-alone.wav"/>
<param name="moh-sound" value="$${hold_music}"/>
<param name="enter-sound" value="tone_stream://%(200,0,500,600,700)"/>
<param name="exit-sound" value="tone_stream://%(500,0,300,200,100,50,25)"/>
<param name="caller-id-name" value="$${outbound_caller_name}"/>
<param name="caller-id-number" value="$${outbound_caller_id}"/>
<param name="comfort-noise" value="true"/>
</profile>
Run reloadxml from the FreeSWITCH console (or fs_cli) after saving so the new
profile is picked up.
2. A dialplan extension that enters the room
Add this extension to conf/dialplan/default.xml, above the catch-all
Local_Extension, so 3500 matches first. It answers the call and runs the
conference application with the room name and the secure profile. No PIN
logic is needed here -- the profile's pin/moderator-pin make conference
prompt and validate on its own:
<extension name="secure_conference">
<condition field="destination_number" expression="^3500$">
<action application="answer"/>
<action application="conference" data="secure-${domain_name}@secure"/>
</condition>
</extension>
Run reloadxml again. Dial 3500 from two registered phones: each is asked for
a PIN. Enter 12345 to join as a participant or 54321 to join as a moderator.
Moderator vs. participant
The two PINs produce two roles on the same room:
- Entering
12345(thepin) joins as an ordinary member. - Entering
54321(themoderator-pin) sets the caller'smoderatormember flag automatically. Moderators are matched by thenon_moderatortarget in the conference API, so a moderator can, for example, mute everyone else withconference secure-${domain_name} mute non_moderator.
You can also assign member flags explicitly at join time with the
+flags{...} suffix on the conference argument. To force a caller into the
room muted, append +flags{mute}; to grant moderator status without a PIN,
append +flags{moderator} (mute and moderator are the verified flag names
parsed from the dial string). The argument grammar is:
conference <room>[@<profile>][+<pin>][+flags{<flag>|<flag>...}]
For example, a separate "listener" extension that joins the same room muted:
<extension name="secure_conference_listener">
<condition field="destination_number" expression="^3501$">
<action application="answer"/>
<action application="conference" data="secure-${domain_name}@secure+flags{mute}"/>
</condition>
</extension>
How it works
Room creation and profile lookup. A conference room is identified by its
name string. When conference runs with room@profile, FreeSWITCH looks up
profile in conference.conf.xml; if the room does not already exist it is
created from that profile, and later callers who dial the same name join the
existing instance. Here the room name is secure-${domain_name}, which
namespaces the room per domain, and the profile is secure. See the
conference model.
PIN handling. When the resolved profile (or the dial-string +<pin> suffix)
supplies an entry or moderator PIN, conference answers the channel, plays the
pin-sound, and collects digits. The entered value is compared against the
entry pin first, then the moderator-pin. A mismatch plays bad-pin-sound
and re-prompts; after pin-retries failures the caller is rejected and the call
is logged as a PIN-rejected CDR. A caller can also supply the PIN ahead of the
prompt via the supplied_pin channel variable (or an X-ConfPin= SIP URL
parameter), which skips the audio prompt when it already matches.
Moderator flag from the moderator PIN. When the entered digits match the
moderator-pin rather than the entry pin, mod_conference records the match
and sets the member's moderator flag (MFLAG_MOD) as it joins. That is the
only difference between the two PINs at the protocol level: same room, same
profile, one bit of member state. Moderator members receive the
moderator-controls key map (if the profile defines one) and are excluded from
the non_moderator API target.
Member flags at join time. Flags can come from three places, all merged: the
profile's member-flags parameter, the conference_member_flags channel
variable, and the +flags{...} suffix on the conference argument. The
mute, deaf, and moderator names used above are taken verbatim from the
dial-string flag parser. See
member flags at join time
and the full conference application syntax.
For the complete profile parameter table -- including pin, moderator-pin,
pin-retries, announce-count, and the sound files -- see
profile parameters.
Variations
Collect the PIN in the dialplan instead
If you want to design the prompt yourself -- a custom greeting, a regex on the
digits, or a transfer on failure -- collect the PIN before entering the room
with play_and_get_digits, then pass it through as the dial-string +<pin>.
Leave the profile's pin/moderator-pin defined so conference still
validates the value you forward:
<extension name="secure_conference_dp_pin">
<condition field="destination_number" expression="^3502$">
<action application="answer"/>
<action application="sleep" data="500"/>
<!-- min max tries timeout(ms) terminators prompt invalid_file var regexp -->
<action application="play_and_get_digits"
data="4 6 3 7000 # conference/conf-pin.wav conference/conf-bad-pin.wav conf_pin \d+"/>
<action application="conference" data="secure-${domain_name}@secure+${conf_pin}"/>
</condition>
</extension>
The play_and_get_digits arguments are positional, in this exact order:
<min> <max> <tries> <timeout_ms> <terminators> <file> <invalid_file> <var_name> <regexp>.
Above it collects 4 to 6 digits, allows 3 tries, waits 7 seconds, accepts # as
a terminator, plays conf-pin.wav, replays conf-bad-pin.wav on a bad regex
match, stores the result in conf_pin, and validates against \d+. The
collected ${conf_pin} is appended as the +<pin> suffix, so conference
checks it against both the entry and moderator PINs -- preserving the
moderator-by-PIN behavior. The full argument list (including the optional
digit_timeout and failure_ext) is documented in the
Dialplan Application Reference.
Separate moderator and listener entry points
Instead of one extension that branches on the PIN, expose distinct numbers and
set the role with the +flags{...} suffix -- no PIN prompt at all on these
internal-only extensions. A moderator extension and a muted-listener extension
that share the same room:
<extension name="conf_moderator_entry">
<condition field="destination_number" expression="^3510$">
<action application="answer"/>
<action application="conference" data="secure-${domain_name}@secure+flags{moderator}"/>
</condition>
</extension>
<extension name="conf_listener_entry">
<condition field="destination_number" expression="^3511$">
<action application="answer"/>
<action application="conference" data="secure-${domain_name}@secure+flags{mute|deaf}"/>
</condition>
</extension>
Dialing 3510 joins as a moderator; 3511 joins muted and deaf (a pure
listener, hearing nothing and contributing no audio -- useful for a monitor
feed). Because these grant roles by extension rather than by PIN, restrict
access to them in your dialplan or directory rather than publishing them
externally.
Play custom entry and exit sounds
The enter-sound and exit-sound profile parameters play to the room when a
member joins or leaves. The vanilla profiles use short tone_stream:// chirps;
point them at recorded files (relative to the conference sound-prefix) for a
spoken announcement instead:
<param name="enter-sound" value="conference/conf-has-joined.wav"/>
<param name="exit-sound" value="conference/conf-has-left.wav"/>
To announce the running member count as people arrive, set
announce-count to the threshold at which counting begins (1 announces from
the first member). See the
profile parameters for
the related sound and announcement options.