ConfBridge Conferencing Guide
This guide covers managing Asterisk ConfBridge conferences via the Asterisk Manager Interface (AMI) in VueSIP.
Overview
VueSIP provides a reactive useAmiConfBridge composable for managing ConfBridge audio conferences. This enables:
| Feature | Description |
|---|---|
| Room Management | List, lock/unlock, mute conferences |
| Recording | Start/stop conference recording |
| Participant Control | Mute, unmute, kick users |
| Video Source | Set single video source for video conferences |
| Real-time Events | Join, leave, talking status updates |
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ VueSIP App │◄────►│ amiws Proxy │◄────►│ Asterisk PBX │
│ (Browser) │ WS │ (WebSocket) │ AMI │ (ConfBridge) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Conference │
│ Rooms │
└─────────────────┘Components
- Asterisk PBX - Hosts ConfBridge conferences
- amiws Proxy - Converts AMI protocol to WebSocket (JSON)
- VueSIP -
useAmiConfBridgecomposable for reactive conference management
Prerequisites
Asterisk Configuration
1. Configure ConfBridge
Create or edit /etc/asterisk/confbridge.conf:
; /etc/asterisk/confbridge.conf
[general]
; Default user profile
[default_user]
type=user
admin=no
marked=no
startmuted=no
music_on_hold_when_empty=yes
music_on_hold_class=default
quiet=no
announce_user_count=yes
announce_join_leave=yes
dtmf_passthrough=no
announce_user_count_all=yes
; Admin user profile
[admin_user]
type=user
admin=yes
marked=yes
startmuted=no
dtmf_passthrough=no
; Default bridge profile
[default_bridge]
type=bridge
max_members=50
record_conference=no
internal_sample_rate=auto
mixing_interval=20
video_mode=follow_talker2. Create Conference Dialplan
Edit /etc/asterisk/extensions.conf or use FreePBX Custom Extensions:
; /etc/asterisk/extensions.conf
[confbridge-rooms]
; Room 1000 - Regular conference
exten => 1000,1,Answer()
same => n,ConfBridge(1000,default_bridge,default_user)
same => n,Hangup()
; Room 1001 - Admin conference
exten => 1001,1,Answer()
same => n,ConfBridge(1001,default_bridge,admin_user)
same => n,Hangup()
; Dynamic room - dial any 4-digit number starting with 1
exten => _1XXX,1,Answer()
same => n,ConfBridge(${EXTEN},default_bridge,default_user)
same => n,Hangup()3. Configure AMI User
Edit /etc/asterisk/manager.conf:
; /etc/asterisk/manager.conf
[general]
enabled = yes
port = 5038
bindaddr = 127.0.0.1
[vuesip]
secret = your-secure-password
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.255
read = call,user,reporting
write = call,originate
eventfilter = !Event: RTCP*
eventfilter = !Event: VarSetRequired Permissions:
read = call- Receive ConfBridge eventswrite = call- Send ConfBridge commands
4. Reload Configuration
asterisk -rx "module reload app_confbridge.so"
asterisk -rx "manager reload"FreePBX Configuration
In FreePBX, conferences are managed via the GUI:
- Navigate to Applications > Conferences
- Click + Add Conference
- Configure:
- Conference Number: e.g.,
1000 - Conference Name: e.g.,
Main Conference - User PIN: Optional access PIN
- Admin PIN: Optional admin PIN
- Options: Join/Leave announcements, recording, etc.
- Conference Number: e.g.,
- Submit and Apply Config
For AMI access, configure via Settings > Asterisk Manager Users as described in the AMI CDR Guide.
VueSIP Integration
Basic Setup
import { computed } from 'vue'
import { useAmi, useAmiConfBridge } from 'vuesip'
// Create AMI connection
const ami = useAmi()
// Connect to amiws proxy
await ami.connect('ws://pbx.example.com:8080')
// Initialize ConfBridge management
const {
rooms, // Map<string, ConfBridgeRoom>
users, // Map<string, ConfBridgeUser>
roomList, // Computed array of rooms
userList, // Computed array of users
totalParticipants, // Total participant count
isLoading, // Loading state
error, // Error state
listRooms, // Fetch all conferences
listUsers, // Fetch users in a conference
lockRoom, // Lock a conference
unlockRoom, // Unlock a conference
startRecording, // Start recording
stopRecording, // Stop recording
muteUser, // Mute a participant
unmuteUser, // Unmute a participant
kickUser, // Remove a participant
setVideoSource, // Set video source
refresh, // Refresh all data
} = useAmiConfBridge(computed(() => ami.getClient()))Conference Dashboard
<template>
<div class="confbridge-dashboard">
<!-- Conference List -->
<div class="conferences">
<h2>Active Conferences</h2>
<div v-for="room in roomList" :key="room.conference" class="conference-card">
<div class="conference-header">
<h3>Room {{ room.conference }}</h3>
<span class="participant-count">{{ room.parties }} participants</span>
</div>
<div class="conference-status">
<span v-if="room.locked" class="badge locked">Locked</span>
<span v-if="room.recording" class="badge recording">Recording</span>
<span v-if="room.muted" class="badge muted">Muted</span>
</div>
<div class="conference-actions">
<button @click="toggleLock(room)">
{{ room.locked ? 'Unlock' : 'Lock' }}
</button>
<button @click="toggleRecording(room)">
{{ room.recording ? 'Stop Recording' : 'Start Recording' }}
</button>
<button @click="viewParticipants(room)">View Participants</button>
</div>
</div>
</div>
<!-- Participant List -->
<div v-if="selectedRoom" class="participants">
<h2>Participants in {{ selectedRoom.conference }}</h2>
<div v-for="user in roomParticipants" :key="user.channel" class="participant-card">
<div class="participant-info">
<span class="name">{{ user.callerIdName || user.callerIdNum }}</span>
<span v-if="user.admin" class="badge admin">Admin</span>
<span v-if="user.talking" class="badge talking">Speaking</span>
</div>
<div class="participant-actions">
<button @click="toggleMute(user)">
{{ user.muted ? 'Unmute' : 'Mute' }}
</button>
<button @click="kick(user)" class="danger">Kick</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useAmi, useAmiConfBridge } from 'vuesip'
import type { ConfBridgeRoom, ConfBridgeUser } from 'vuesip'
const ami = useAmi()
const {
roomList,
userList,
lockRoom,
unlockRoom,
startRecording,
stopRecording,
muteUser,
unmuteUser,
kickUser,
listUsers,
} = useAmiConfBridge(computed(() => ami.getClient()))
const selectedRoom = ref<ConfBridgeRoom | null>(null)
const roomParticipants = computed(() =>
userList.value.filter((u) => u.conference === selectedRoom.value?.conference)
)
async function viewParticipants(room: ConfBridgeRoom) {
selectedRoom.value = room
await listUsers(room.conference)
}
async function toggleLock(room: ConfBridgeRoom) {
if (room.locked) {
await unlockRoom(room.conference)
} else {
await lockRoom(room.conference)
}
}
async function toggleRecording(room: ConfBridgeRoom) {
if (room.recording) {
await stopRecording(room.conference)
} else {
await startRecording(room.conference)
}
}
async function toggleMute(user: ConfBridgeUser) {
if (user.muted) {
await unmuteUser(user.conference, user.channel)
} else {
await muteUser(user.conference, user.channel)
}
}
async function kick(user: ConfBridgeUser) {
await kickUser(user.conference, user.channel)
}
</script>Real-time Events
Subscribe to conference events for live updates:
const { rooms, users } = useAmiConfBridge(
computed(() => ami.getClient()),
{
// Auto-refresh room list on connect
autoRefresh: true,
// Handle user join events
onUserJoin: (user) => {
console.log(`${user.callerIdName} joined ${user.conference}`)
showNotification(`${user.callerIdName} joined the conference`)
},
// Handle user leave events
onUserLeave: (user) => {
console.log(`${user.callerIdName} left ${user.conference}`)
},
// Handle talking status changes
onTalkingChange: (user, isTalking) => {
if (isTalking) {
console.log(`${user.callerIdName} is speaking`)
// Update active speaker indicator
}
},
// Optional: Filter conferences
conferenceFilter: (room) => {
// Only show conferences starting with '100'
return room.conference.startsWith('100')
},
// Optional: Transform user data
transformUser: (user) => ({
...user,
displayName: user.callerIdName || `Ext ${user.callerIdNum}`,
}),
}
)Recording Management
// Start recording with custom filename
const result = await startRecording(
'1000',
'/var/spool/asterisk/monitor/conf-1000-${TIMESTAMP}.wav'
)
if (result.success) {
console.log('Recording started')
} else {
console.error('Recording failed:', result.error)
}
// Stop recording
await stopRecording('1000')Video Conferencing
For video conferences, set the single video source:
// Set a specific participant as the video source
await setVideoSource('1000', 'PJSIP/1001-00000001')
// The video source participant's video will be broadcast to allNote: Video mode must be configured in confbridge.conf:
[video_bridge]
type=bridge
video_mode=single_source ; or follow_talkerAPI Reference
ConfBridgeRoom Interface
| Field | Type | Description |
|---|---|---|
conference | string | Conference name/number |
parties | number | Number of participants |
locked | boolean | Whether room is locked |
muted | boolean | Whether room is globally muted |
recording | boolean | Recording active |
markedUsers | number | Count of admin/marked users |
ConfBridgeUser Interface
| Field | Type | Description |
|---|---|---|
conference | string | Conference name |
callerIdNum | string | Caller's number |
callerIdName | string | Caller's display name |
channel | string | Channel identifier |
admin | boolean | Is admin/moderator |
marked | boolean | Is marked user |
muted | boolean | Is muted |
talking | boolean | Currently talking |
joinedAt | Date | Join timestamp |
Actions
| Method | Parameters | Description |
|---|---|---|
listRooms() | - | Fetch all active conferences |
listUsers(conference) | conference: string | Fetch users in a conference |
lockRoom(conference) | conference: string | Lock conference (no new joins) |
unlockRoom(conference) | conference: string | Unlock conference |
startRecording(conference, file?) | conference: string, file?: string | Start recording |
stopRecording(conference) | conference: string | Stop recording |
muteUser(conference, channel) | conference: string, channel: string | Mute participant |
unmuteUser(conference, channel) | conference: string, channel: string | Unmute participant |
kickUser(conference, channel) | conference: string, channel: string | Remove participant |
setVideoSource(conference, channel) | conference: string, channel: string | Set video source |
refresh() | - | Refresh all room and user data |
AMI Events Reference
VueSIP automatically handles these AMI events:
| Event | Description |
|---|---|
ConfbridgeJoin | User joined conference |
ConfbridgeLeave | User left conference |
ConfbridgeTalking | User talking status changed |
ConfbridgeMute | User was muted |
ConfbridgeUnmute | User was unmuted |
ConfbridgeLock | Conference was locked |
ConfbridgeUnlock | Conference was unlocked |
ConfbridgeRecord | Recording started |
Troubleshooting
No Conferences Visible
Verify ConfBridge is loaded:
bashasterisk -rx "module show like app_confbridge" # Should show: app_confbridge.soCheck active conferences:
bashasterisk -rx "confbridge list"Verify AMI permissions:
bashasterisk -rx "manager show user vuesip" # Check read permissions include 'call'
Lock/Recording Actions Fail
Check write permissions:
- AMI user needs
write = callpermission
- AMI user needs
Verify conference exists:
bashasterisk -rx "confbridge show 1000"Check for error responses:
typescriptconst result = await lockRoom('1000') if (!result.success) { console.error('Lock failed:', result.error) }
Talking Events Not Working
Enable talk detection in confbridge.conf:
ini[default_bridge] type=bridge talk_detection_events=yesReload configuration:
bashasterisk -rx "module reload app_confbridge.so"
Recording Path Issues
Ensure directory exists and is writable:
bashmkdir -p /var/spool/asterisk/monitor chown asterisk:asterisk /var/spool/asterisk/monitorUse absolute paths:
typescriptawait startRecording('1000', '/var/spool/asterisk/monitor/conf-1000.wav')
Security Best Practices
- Restrict AMI permissions - Only grant required read/write permissions
- Use conference PINs - Configure user/admin PINs for access control
- Enable TLS - Use WSS for WebSocket connections
- Limit conference sizes - Set
max_membersin bridge profiles - Monitor recordings - Implement retention policies for recorded conferences
Related Documentation
- AMI CDR Guide - Call Detail Records via AMI
- Call Parking - Park and retrieve calls
- Voicemail - Voicemail management