Skip to content

Conference Calls

Multi-party audio and video conference calling with participant management.

Try It Live

Run pnpm dev → Navigate to ConferenceCallDemo in the playground

Overview

The conference call demo showcases:

  • Multi-party audio/video conferences
  • Participant list and management
  • Mute individual participants
  • Join/leave notifications
  • Active speaker detection
  • Conference moderation controls

Quick Start

vue
<script setup lang="ts">
import { useSipClient, useConference, useActiveSpeaker } from 'vuesip'

const { isRegistered } = useSipClient()

const {
  conferenceState,
  participants,
  isInConference,
  joinConference,
  leaveConference,
  muteParticipant,
  kickParticipant,
} = useConference()

const { activeSpeaker, activeSpeakers } = useActiveSpeaker(participants)

const conferenceId = ref('')

async function handleJoin() {
  if (conferenceId.value) {
    await joinConference(conferenceId.value, {
      audio: true,
      video: true,
    })
  }
}
</script>

<template>
  <div class="conference-demo">
    <!-- Join Conference -->
    <div v-if="!isInConference" class="join-form">
      <input v-model="conferenceId" placeholder="Conference ID" />
      <button @click="handleJoin" :disabled="!conferenceId">Join Conference</button>
    </div>

    <!-- Active Conference -->
    <div v-else class="conference-active">
      <div class="conference-header">
        <h3>Conference: {{ conferenceId }}</h3>
        <span class="participant-count"> {{ participants.length }} participants </span>
      </div>

      <!-- Active Speaker Indicator -->
      <div v-if="activeSpeaker" class="active-speaker">
        Speaking: {{ activeSpeaker.displayName }}
      </div>

      <!-- Participant Grid -->
      <div class="participant-grid">
        <div
          v-for="participant in participants"
          :key="participant.id"
          :class="['participant-tile', { speaking: activeSpeakers.includes(participant) }]"
        >
          <video
            v-if="participant.videoStream"
            :srcObject="participant.videoStream"
            autoplay
            playsinline
            :muted="participant.isLocal"
          />
          <div class="participant-info">
            <span class="name">{{ participant.displayName }}</span>
            <span v-if="participant.isMuted" class="muted-badge">Muted</span>
          </div>

          <!-- Moderator Controls -->
          <div class="controls" v-if="!participant.isLocal">
            <button @click="muteParticipant(participant.id)">
              {{ participant.isMuted ? 'Unmute' : 'Mute' }}
            </button>
            <button @click="kickParticipant(participant.id)">Remove</button>
          </div>
        </div>
      </div>

      <button @click="leaveConference" class="leave-btn">Leave Conference</button>
    </div>
  </div>
</template>

Features

  • Multi-Party Support: Up to 50+ participants
  • Audio/Video: Full bidirectional media
  • Active Speaker: Automatic detection and highlighting
  • Participant Management: Mute, kick, promote
  • Join/Leave Events: Real-time notifications
  • Moderation: Host controls for managing participants

Key Composables

ComposablePurpose
useConferenceConference lifecycle and participant management
useActiveSpeakerDetect who is currently speaking
useGalleryLayoutGrid layout calculations for video tiles
useParticipantControlsIndividual participant controls

Conference States

StateDescription
idleNot in a conference
joiningConnecting to conference
activeIn an active conference
leavingDisconnecting from conference

Advanced Features

Active Speaker Detection

typescript
const { activeSpeaker, speakerHistory } = useActiveSpeaker(participants, {
  threshold: 0.15, // Audio level threshold
  debounceMs: 300, // Prevent rapid switching
  historySize: 10, // Track recent speakers
})
typescript
const { gridCols, gridRows, tileDimensions, gridStyle } = useGalleryLayout(participants, {
  containerSize: containerRef,
  gap: 8,
  maxCols: 4,
  maxRows: 4,
  aspectRatio: 16 / 9,
})

Released under the MIT License.