T
Telephony SOPKnowledge Base
Search
← All topics

Conference Bridging — SIP Mixers, Mute, Recording, Coaching

runnable

Conference bridging mixes 3+ audio streams into a single shared room. SignalWire conferences are named rooms; participants join by routing a call into `connect: { to: conference:name }`. Supports mute/unmute, hold, beep on entry/exit, recording, talk-detection, coaching (whisper), barge-in, and dial-out to add participants mid-call.

conferencebridgemixersignalwireswmlmulti-party
Agent trigger phrases: SignalWire conference · conference bridge · multi party call · join conference room · conference mute · conference coaching · barge in conference

Conference Bridging

A conference room is a named audio mixer. Multiple participants join, all audio mixes together, all participants hear the mix. SignalWire conferences are the building block for warm transfers, team huddles, customer-agent-supervisor coaching sessions, and ad-hoc group calls.

Conference vs connect — when to use which

| Need | Use | |---|---| | Two-party call | connect (peer-to-peer through SignalWire) | | Three or more parties | conference | | Need mute/coach controls | conference | | Need recording with separate tracks | conference (stereo or per-leg) | | Just bridging two PSTN endpoints | connect (lower cost, simpler) |

Basic join

SWML:

version: 1.0.0
sections:
  main:
    - answer: {}
    - connect:
        to: conference:weekly_standup

LaML:

<Response>
  <Dial>
    <Conference>weekly_standup</Conference>
  </Dial>
</Response>

Any caller hitting this script joins the room named weekly_standup. First participant typically hears music-on-hold until a second participant joins; configurable.

Conference verb parameters (LaML/SWML)

| Parameter | Default | Notes | |---|---|---| | beep | true | Play a beep when participant enters/leaves | | muted | false | Join muted (can be unmuted via API) | | start_conference_on_enter | false | When true, the conference starts only when this participant joins (admin pattern) | | end_conference_on_exit | false | When true, all participants leave when this participant leaves (host pattern) | | wait_url | (silence or default music) | URL or TTS to play while alone | | max_participants | 250 | Hard cap | | record | false | Record the entire conference | | recording_status_callback | none | Webhook fires when recording completes | | region | (closest) | Force a specific region for the mixer | | coach | none | Participant SID to coach (whisper-only) | | region | nearest | Force a media region for latency optimization |

Host and participant roles

The host pattern uses start_conference_on_enter and end_conference_on_exit:

<!-- Host -->
<Response>
  <Dial>
    <Conference startConferenceOnEnter="true" endConferenceOnExit="true">
      meeting_42
    </Conference>
  </Dial>
</Response>

<!-- Participant -->
<Response>
  <Dial>
    <Conference startConferenceOnEnter="false" endConferenceOnExit="false">
      meeting_42
    </Conference>
  </Dial>
</Response>

Participants wait on hold until the host joins. When the host leaves, everyone is disconnected.

Naming conventions

Conference rooms are global — any participant joining weekly_standup joins the same room. Two key implications:

  1. Names must be unique per use case — using support as a conference name will collide across customers.
  2. Use deterministic, prefixed namescust_${customer_id}_${session_id} avoids collisions.

For ephemeral conferences (warm transfer rooms, ad-hoc bridges):

- connect:
    to: conference:transfer_${call.id}

The ${call.id} is unique to the originating call, so each transfer gets its own room.

Adding participants mid-call

To bring in an additional party while a conference is in progress, place an outbound call to the new party with SWML/TwiML that joins them to the same conference name:

client.calls.create(
    to="+13105553333",
    from_="+12125551111",
    url="https://your.api/conference-join.xml?room=cust_42_abc"
)
<Response>
  <Dial>
    <Conference>cust_42_abc</Conference>
  </Dial>
</Response>

Mute and unmute

Via the LaML/REST API on the participant resource:

curl -X POST "https://{space}/api/laml/2010-04-01/Accounts/{project}/Conferences/{conf_sid}/Participants/{call_sid}.json" \
  -u "${PROJECT}:${TOKEN}" \
  -d "Muted=true"

Set Muted=false to unmute. Useful for an admin/host UI that displays the conference roster with mute toggles.

Hold

Place a single participant on hold (they hear hold music, others continue talking):

curl -X POST ".../Participants/{call_sid}.json" \
  -d "Hold=true" \
  -d "HoldUrl=http://twimlets.com/holdmusic"

Recording

Set record="record-from-start" on the conference:

<Conference record="record-from-start"
            recordingStatusCallback="https://your.api/conf-recording">
  meeting_42
</Conference>

Modes:

| Mode | Behavior | |---|---| | do-not-record | No recording (default) | | record-from-start | Start when the first participant joins | | record-from-answer | Same as record-from-start for conferences |

Recording is a single mixed file. For separate per-participant tracks, record each individual leg via Dial's record attribute and reconcile in post.

Coaching (whisper)

Coaching is when a supervisor joins a conference but only one specific participant (the agent) hears them — the customer doesn't. Useful for live training and quality assurance.

client.calls.create(
    to="sip:supervisor@example.com",
    from_="+12125551111",
    url=f"https://your.api/coach.xml?coach={agent_call_sid}&room=cust_42_abc"
)
<Response>
  <Dial>
    <Conference coach="{agent_call_sid}">cust_42_abc</Conference>
  </Dial>
</Response>

coach attribute set to the agent's CallSid → supervisor's audio goes only to the agent.

Barge-in

Barge-in is when a supervisor joins as a full participant (everyone hears them). No special parameter — just join the conference normally.

A common workflow is "monitor → whisper → barge":

  1. Supervisor joins muted (monitor only).
  2. Supervisor unmutes to whisper (coach attribute on agent only).
  3. Supervisor removes coach attribute → full barge-in.

Talk detection events

Conferences can fire a webhook when participants start or stop talking:

<Conference statusCallback="https://your.api/conf-events"
            statusCallbackEvent="join leave mute hold talking">
  meeting_42
</Conference>

Events delivered:

| Event | Trigger | |---|---| | join | Participant joined | | leave | Participant left | | mute | Participant muted/unmuted | | hold | Participant placed on/off hold | | talking | Talk-detection threshold crossed | | start | Conference started (first participant) | | end | Conference ended (last participant left) |

Useful for showing live conference UI ("Bob is talking now") or detecting silent participants.

Wait URL — music while alone

Default wait behavior plays SignalWire's hold music. Override for branded experience:

<Conference waitUrl="https://cdn.example.com/hold-music.mp3"
            waitMethod="GET">
  meeting_42
</Conference>

Or for dynamic wait audio (different music, announcements, "estimated wait time"):

<Conference waitUrl="https://your.api/wait-twiml">
  meeting_42
</Conference>

Your endpoint returns TwiML with <Play> or <Say> instructions that loop.

Max participants and pricing

| Plan tier | Max participants | Pricing model | |---|---|---| | Standard | 250 | Per-participant per-minute | | Enterprise | Higher (negotiated) | Per-minute + flat conference fee |

Per-participant per-minute billing means a 30-minute conference with 5 participants = 150 billable minutes.

Region selection

Conferences are mixed in a SignalWire region. By default, the region is chosen based on the first participant. To force a region for latency optimization:

<Conference region="us2">meeting_42</Conference>

Regions: us1 (US East), us2 (US West), eu1 (Europe), eu2, au1 (Australia). Pick the region geographically closest to most participants.

REST conference resource

List active conferences:

GET /api/laml/2010-04-01/Accounts/{project}/Conferences.json?Status=in-progress

Update conference attributes mid-flight (e.g., end the conference, mute all):

POST /api/laml/2010-04-01/Accounts/{project}/Conferences/{conf_sid}.json
  Status=completed

This terminates the conference and disconnects all participants.

Common patterns

Three-way call

A is on a call with B. A wants to add C. The standard pattern:

  1. Move A's leg into a conference: redirect A's call to SWML that joins conference triple_${call_id}.
  2. Move B's leg into the same conference: redirect B's call to SWML joining the same conference.
  3. Dial out to C, route to SWML joining the same conference.

A, B, C are all conferenced.

Customer-agent-supervisor coaching

  1. Customer-agent call active (peer-to-peer).
  2. Supervisor wants to listen → redirect the agent leg into a conference, dial out and redirect the customer leg into the same conference.
  3. Supervisor joins the conference with coach=${agent_call_sid} — only the agent hears them.

Town hall

Host + 100 listeners. Host joins normally. Listeners join with muted="true" and endConferenceOnExit="false". Host's endConferenceOnExit="true" ends the meeting when the host leaves.

Common pitfalls

  • Beep fatigue — default beep on every join/leave is annoying with large groups. Set beep="false".
  • Host disconnect ends call for all — if host's network drops momentarily and endConferenceOnExit="true", the entire conference dies. Consider grace periods or co-hosts.
  • Recording without consent — see call recording compliance. Conferences with consent-required participants need affirmative consent.
  • Conference name collision — using meeting as a name globally collides. Always namespace.
  • Forgetting startConferenceOnEnter — without it, first participant hears music indefinitely.

Related patterns

References

  • SignalWire LaML <Conference> documentation
  • SignalWire SWML connect: conference: syntax
  • RFC 4575 — SIP Event Package for Conference State