Skip to content

Meeting Room

The Meeting Room plugin (Meeting) provides professional video conferencing capabilities for Monibuca V6. Suitable for online meetings, remote collaboration, training sessions, and other scenarios.

  • Multi-participant Video Conferencing: Support 50+ concurrent participants
  • Meeting Management:
    • Agenda management (Agenda)
    • Meeting timer and speaker timer
    • Raise Hand feature
    • Lobby (waiting room) control
  • Real-time Transcription: Automatic speech-to-text (requires external ASR service)
  • AI Intelligence Services:
    • Automatic meeting minutes generation
    • Extract action items from transcription
    • Meeting decision summaries
  • Recording and Control:
    • Meeting recording (MP4 format)
    • Screen sharing
    • Host permission control
  • Participant Management: Kick, mute, lock room, ban
Cargo.toml
features = ["meeting"]
# Meeting plugin depends on Room Service
# room feature is automatically enabled
graph TB
subgraph Meeting["MeetingPlugin"]
SM["SessionManager<br/>Meeting info, participants"]
Agenda["AgendaManager<br/>Agenda control"]
Trans["TranscriptionManager<br/>Real-time transcription"]
AI["AIService<br/>Summary & Task Extraction"]
Record["RecordingManager<br/>Recording control"]
Lobby["LobbyManager<br/>Waiting room"]
DB["Data Persistence<br/>Meetings, agenda, transcription"]
end
subgraph RS["Room Service"]
Room["Room Management<br/>Host + Participants"]
WS["WebSocket<br/>Signaling"]
API["RoomApi"]
end
subgraph Media["Media Layer"]
WHIP["WebRTC WHIP<br/>Publish"]
WHEP["WebRTC WHEP<br/>Subscribe"]
ASR["ASR Service<br/>Speech Recognition"]
end
Meeting -->|register_callbacks| RS
SM --> DB
Agenda --> DB
Trans --> AI
Trans --> DB
Record --> Media
Lobby --> API
Room --> API
API -->|set_room_locked<br/>set_lobby_enabled| Meeting
WS --> Meeting
WHIP --> Media
WHEP --> Media
Trans -->|Real-time push| ASR
Scheduled → Starting → Active → Paused → Ended
StatusDescription
ScheduledMeeting scheduled, waiting to start
StartingLobby is admitting participants
ActiveMeeting in progress
PausedMeeting paused
EndedMeeting ended
ActionDirectionDescription
start_meetingC→SHost starts meeting
end_meetingC→SHost ends meeting
pause_meetingC→SHost pauses meeting
resume_meetingC→SHost resumes meeting
ActionDirectionDescription
mute_participantC→SHost mutes participant
unmute_participantC→SHost unmutes participant
kick_participantC→SHost kicks participant
raise_handC→SParticipant raises hand
lower_handC→SParticipant lowers hand
participant_mutedS→CParticipant muted notification
participant_kickedS→CParticipant kicked notification
hand_raisedS→CHand raised notification (broadcast)
ActionDirectionDescription
update_agendaC→SUpdate current agenda item
next_agendaC→SMove to next agenda item
agenda_changedS→CAgenda change notification (broadcast)
ActionDirectionDescription
start_transcriptionC→SStart real-time transcription
stop_transcriptionC→SStop real-time transcription
transcription_resultS→CTranscription result push
start_recordingC→SStart recording
stop_recordingC→SStop recording
ActionDirectionDescription
toggle_lobbyC→SToggle lobby on/off
admit_userC→SAdmit user to join
reject_userC→SReject user from joining
user_pendingS→CUser in lobby notification (broadcast)
ActionDirectionDescription
lock_roomC→SLock room (prevent new users)
unlock_roomC→SUnlock room
{
"meeting_id": "meeting_001",
"agenda": [
{
"id": "agenda_1",
"title": "Opening Remarks",
"speaker": "Host",
"duration": 5, // minutes
"order": 1
},
{
"id": "agenda_2",
"title": "Business Update",
"speaker": "Department Lead",
"duration": 20,
"order": 2
},
{
"id": "agenda_3",
"title": "Q&A Session",
"speaker": "All Participants",
"duration": 10,
"order": 3
}
],
"current_agenda_id": "agenda_2"
}
{
"action": "update_agenda",
"agenda": [
{
"title": "Opening Remarks",
"speaker": "Host",
"duration": 5
}
]
}
{
"action": "mute_participant",
"target_user_id": "user_005",
"mute_audio": true, // Mute microphone
"mute_video": false // Keep camera on
}

Host has the following permissions:

  • Start/end/pause meeting
  • Mute/unmute participants
  • Kick out participants (force exit)
  • Control lobby (admit/reject)
  • Lock/unlock room
  • Start/stop recording
  • Start/stop transcription

Participants can raise hands to request to speak. The host can see the raise hand queue:

{
"action": "raise_hand"
}
┌──────────────────┐
│ Participant Mic │
└────────┬─────────┘
│ RTC Audio
┌─────────────┐ ┌──────────────┐
│ AudioBuffer │────────→│ ASR Service │
└─────────────┘ │ (External) │
└──────┬───────┘
│ Recognition Result
┌─────────────────┐
│ TranscriptionDB │
└─────────────────┘
┌────────────────────┐
│ WebSocket Push │
│ to All │
│ Participants │
└────────────────────┘
{
"action": "start_transcription",
"language": "en-US" // Language code
}
{
"action": "transcription_result",
"speaker_id": "user_003",
"speaker_name": "John",
"text": "Our sales grew 25% in the first half",
"is_final": true, // true: sentence complete, false: interim result
"timestamp": "2024-01-15T10:35:00Z"
}

AI automatically generates minutes after meeting ends:

{
"meeting_id": "meeting_001",
"title": "2024 Q1 Summary Meeting",
"date": "2024-01-15",
"duration": "2 hours 15 minutes",
"participants": ["Host", "John", "Jane"],
"summary": "This meeting reviewed Q1 performance and set Q2 targets...",
"key_points": [
"Sales growth of 25% year-over-year",
"Market share increased by 5 percentage points",
"3 new product lines launched"
],
"action_items": [
{
"item": "Complete market research report",
"owner": "Marketing",
"deadline": "2024-01-31"
},
{
"item": "Optimize customer service process",
"owner": "Operations",
"deadline": "2024-02-15"
}
]
}

Automatically extract action items from transcription:

Transcription: "John, can you complete the client requirements analysis by next Friday?"
Extracted task:
{
"item": "Complete client requirements analysis",
"owner": "John",
"deadline": "2024-01-19", // Next Friday
"priority": "high"
}
{
"action": "toggle_lobby",
"enable": true
}
User tries to join → Enter lobby → Host reviews → Admit/Reject
{
"action": "admit_user",
"target_user_id": "user_008"
}
{
"action": "reject_user",
"target_user_id": "user_008"
}
{
"action": "share_screen"
}

Participants select the screen or window to share via browser API. The system automatically handles shared content as a separate media track.

In-session start / stop recording is driven by WebSocket room signaling and RoomApi (see the signaling and architecture sections above). There is no standalone HTTP path such as POST /meeting/.../recording/start, which would break the global {plugin}/api convention.

Like other plugins, Meeting HTTP REST is under /meeting/api/... (engine prefix meeting/api). To list recording entries over HTTP:

Terminal window
curl http://localhost:8080/meeting/api/recordings

(The list may be empty until persistence is fully wired; per-recording play, download, and DELETE are documented under HTTP API — Meeting REST, aligned with repo docs/http-api.md §14.2.)

Base path: http(s)://<host>:<port>/meeting/api. Do not use the legacy /room/meeting/... prefix, and do not omit the api segment (e.g. /meeting/rooms is not the registered REST prefix).

Terminal window
curl http://localhost:8080/meeting/api/rooms
Terminal window
curl -X POST http://localhost:8080/meeting/api/rooms \
-H "Content-Type: application/json" \
-d '{"room_id":"room-demo-1"}'
Terminal window
curl http://localhost:8080/meeting/api/reservations
Terminal window
curl -X POST http://localhost:8080/meeting/api/reservations \
-H "Content-Type: application/json" \
-d '{
"room_id": "room-1",
"room_name": "Weekly standup",
"host_user_id": "u1",
"host_user_name": "Host",
"start_time": "2026-04-21T10:00:00+08:00",
"duration_minutes": 60,
"timezone": "Asia/Shanghai",
"participants": ["u2"],
"has_password": false,
"mute_all": false,
"mute_video_all": false
}'
Terminal window
curl http://localhost:8080/meeting/api/templates
Terminal window
curl -X POST http://localhost:8080/meeting/api/templates \
-H "Content-Type: application/json" \
-d '{
"name": "Default template",
"description": null,
"max_participants": 50,
"default_password": null,
"auto_record": false,
"auto_lock": false,
"enabled": true,
"sort_order": 0
}'
Terminal window
curl http://localhost:8080/meeting/api/stats
curl http://localhost:8080/meeting/api/features

Lock/unlock, mute/kick, and per-recording URLs are listed under HTTP API — Meeting REST (same content as repo docs/http-api.md §14.2). Agenda, transcription, and minutes are primarily WebSocket features; they are not exposed as GET /meeting/meetings/... in the current engine HTTP surface.

FieldTypeDescription
idstringMeeting ID
titlestringMeeting title
organizer_idstringOrganizer ID
statusenumMeeting status
start_timetimestampStart time
end_timetimestampEnd time
participant_countintParticipant count
recording_filestringRecording file path
FieldTypeDescription
idstringAgenda ID
meeting_idstringMeeting ID
titlestringAgenda title
speakerstringSpeaker
durationintDuration (seconds)
orderintOrder
FieldTypeDescription
idstringTranscription ID
meeting_idstringMeeting ID
speaker_idstringSpeaker ID
texttextTranscription content
timestamptimestampTimestamp
languagestringLanguage
meeting:
# Basic configuration
max_participants: 50 # Maximum participants
session_timeout: 7200 # Meeting timeout (seconds)
# Lobby
enable_lobby: true # Enable lobby
lobby_timeout: 300 # Lobby timeout (seconds)
# Recording
enable_recording: true # Enable recording
recording_format: "mp4" # Recording format
recording_dir: "./recordings"
# Transcription
enable_transcription: false # Enable transcription (requires ASR service)
asr_service_url: "" # ASR service URL
transcription_language: "en-US"
# AI Service
enable_ai_summary: false # Enable AI summary
ai_service_url: "" # AI service URL
# Timer
timer:
max_duration: 7200 # Maximum meeting duration (seconds)
warning_before_end: 300 # Warning before end (seconds)
enable_agenda_timer: true # Enable agenda timer
const room = document.getElementById('room') as MbRoom;
const publisher = document.getElementById('publisher') as MbPublisher;
// Connect to meeting room
room.setAttribute('ws-url', 'ws://localhost:8080/room?type=meeting');
room.setAttribute('room-id', 'meeting_001');
// Enable audio/video
await publisher.startCapture({ audio: true, video: true });
await publisher.startPublish();
const room = document.getElementById('room') as MbRoom;
// Start meeting
room.sendMessage({
action: 'start_meeting'
});
// Mute participant
room.sendMessage({
action: 'mute_participant',
target_user_id: 'user_005',
mute_audio: true
});
// Enable lobby
room.sendMessage({
action: 'toggle_lobby',
enable: true
});
// Start transcription
room.sendMessage({
action: 'start_transcription',
language: 'en-US'
});
// Listen for transcription results
room.addEventListener('transcription_result', (event) => {
console.log(`${event.speaker_name}: ${event.text}`);
// Display in transcription panel in real-time
});
const publisher = document.getElementById('publisher') as MbPublisher;
// Start screen sharing
await publisher.startScreenShare();
// Stop screen sharing
await publisher.stopScreenShare();

Complete Meeting Room Demo is located at web-sdk/packages/demo/meeting/:

meeting/
├── src/
│ ├── pages/
│ │ ├── Lobby/index.tsx # Meeting list
│ │ ├── MeetingRoom/index.tsx # Meeting room
│ │ └── Waiting/index.tsx # Waiting room
│ ├── components/
│ │ ├── VideoGrid/index.tsx # Video grid
│ │ ├── Transcription/index.tsx # Real-time transcription panel
│ │ ├── Agenda/index.tsx # Agenda panel
│ │ ├── Participants/index.tsx # Participant list
│ │ └── Controls/index.tsx # Control bar
│ ├── services/api.ts # API wrapper
│ └── types/index.ts # Type definitions
├── package.json # port: 5475
└── vite.config.ts
Terminal window
cd web-sdk/packages/demo/meeting
pnpm install
pnpm dev
# Visit http://localhost:5475
http://localhost:5475?meeting_id=meeting_001&user_id=user_123&role=participant

Demo automatically detects device type. For mobile devices:

  • Responsive video grid (max 4 videos)
  • Fixed control bar at bottom
  • Swipe up to show participant list
  • Swipe down to show agenda panel
  • Transcription results scroll display