Build a Vue Room Lifecycle
Build a Vue 3 room with mediasfu-vue 1.1.1: create or join through
your authenticated backend, list participants, prepare and publish media,
receive participant media, share a screen, and leave cleanly.
Before you start
- Install
mediasfu-vue@1.1.1and its required peer dependencies. - Import
mediasfu-vue/dist/mediasfu-vue.cssonce in your application entry. - Serve the app from HTTPS or localhost for camera, microphone, and screen capture.
- Keep MediaSFU account credentials on your backend.
- Start with
ModernMediasfuGenericwhile you establish room policy and cleanup.
1. Mount a secure room boundary
The Vue entry accepts createMediaSFURoom and joinMediaSFURoom callbacks.
Use them to send room intent to your own authenticated backend. The adapters
below deliberately ignore the callback's account fields so they cannot cross
the browser boundary.
<script setup lang="ts">
import { ModernMediasfuGeneric } from 'mediasfu-vue';
import 'mediasfu-vue/dist/mediasfu-vue.css';
import {
createRoomViaBackend,
joinRoomViaBackend,
} from './secure-room-gateway';
const clientPlaceholderCredentials = {
apiUserName: 'client00',
apiKey: '0'.repeat(64),
};
</script>
<template>
<ModernMediasfuGeneric
:credentials="clientPlaceholderCredentials"
:return-u-i="true"
:connect-media-s-f-u="true"
:create-media-s-f-u-room="createRoomViaBackend"
:join-media-s-f-u-room="joinRoomViaBackend"
/>
</template>
import type {
CreateJoinRoomResult,
CreateRoomOnMediaSFUType,
JoinRoomOnMediaSFUType,
} from 'mediasfu-vue';
async function postRoomIntent(url: string, payload: unknown) {
const response = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) throw new Error(`Room request failed: ${response.status}`);
return response.json() as Promise<CreateJoinRoomResult>;
}
export const createRoomViaBackend: CreateRoomOnMediaSFUType = ({ payload }) =>
postRoomIntent('/api/mediasfu/create-room', payload);
export const joinRoomViaBackend: JoinRoomOnMediaSFUType = ({ payload }) =>
postRoomIntent('/api/mediasfu/join-room', payload);
Your backend must authenticate the app user, authorize the requested role, apply duration and capacity limits, call the trusted MediaSFU service, and return the expected room-grant response. Treat 401 and 403 as policy failures and 429 as a signal to back off. Never fall back to an account key in Vue source, browser storage, or an HTML attribute.
2. Use the prebuilt lifecycle first
ModernMediasfuGeneric owns the connected room state and coordinates permission,
producer, consumer, screen-share, participant, and exit flows. Its visible
controls are the simplest supported path:
- Create or join from the pre-join surface.
- Allow or deny microphone and camera when the browser asks.
- Open Participants to observe membership changes.
- Use the microphone, camera, and screen controls to start or stop media.
- Use Leave meeting and confirm the exit.
Keep the component mounted for the session. Replacing its full parameter object with a partial object can desynchronize transports and UI state.
3. Wire custom controls from an authorized session
For a custom room shell, Vue 1.1.1 exports the operation functions and their exact option types. Build each option object from the live session state supplied by your room integration.
import {
allMembers,
clickAudio,
clickScreenShare,
clickVideo,
confirmExit,
createDeviceClient,
joinRoomClient,
processConsumerTransports,
type AllMembersOptions,
type ClickAudioOptions,
type ClickScreenShareOptions,
type ClickVideoOptions,
type ConfirmExitOptions,
type CreateDeviceClientOptions,
type JoinRoomClientOptions,
type ProcessConsumerTransportsOptions,
} from 'mediasfu-vue';
export const joinAuthorizedRoom = (options: JoinRoomClientOptions) =>
joinRoomClient(options);
export const prepareMediaDevice = (options: CreateDeviceClientOptions) =>
createDeviceClient(options);
export const refreshParticipants = (options: AllMembersOptions) =>
allMembers(options);
export const toggleMicrophone = (options: ClickAudioOptions) =>
clickAudio(options);
export const toggleCamera = (options: ClickVideoOptions) =>
clickVideo(options);
export const receiveParticipantMedia = (options: ProcessConsumerTransportsOptions) =>
processConsumerTransports(options);
export const toggleScreenShare = (options: ClickScreenShareOptions) =>
clickScreenShare(options);
export const leaveRoom = (options: ConfirmExitOptions) =>
confirmExit(options);
Do not invent small placeholder parameter objects. These contracts carry the current socket, transport, producer, permission, stream, and update callbacks that keep one session coherent.
Know what success looks like
| Operation | Observable success | Failure and cleanup |
|---|---|---|
| Secure create | The backend returns an approved room grant and the room opens. | Show a bounded policy/retry message; never expose the upstream response or use a browser key. |
| Join | The authorized member enters the requested room. | Handle expired grant, wrong room, ban, suspension, and host-not-ready separately. |
| Participants | The participant surface reflects joins and leaves. | An empty list is valid; clear app-owned participant state after exit. |
| Media readiness | A device is created from the room's RTP capabilities. | Explain unsupported browser, missing capability, and permission denial separately. |
| Microphone and camera | The local producer state and control state agree. | Stop owned tracks and producers when disabled or leaving. |
| Receive media | Remote audio/video appears for an active producer. | Distinguish missing producer, paused media, transport failure, and autoplay blocking. |
| Screen share | The chosen display appears remotely and the control changes to stop. | Picker cancellation is normal; stop both the display track and producer. |
| Leave | The room receives the participant disconnect and the local session closes. | Remove socket listeners, stop owned tracks, close transports, and clear UI state. |
For a headless host surface, the current composable exposes both host outcomes:
<script setup lang="ts">
import { useMediasfuHeadless } from 'mediasfu-vue';
const room = useMediasfuHeadless();
const endRoom = () => room.controls.leave(false, true);
const leaveAndKeepRoomOpen = () => room.controls.leave(false, false);
</script>
<template>
<button @click="endRoom">End room</button>
<button @click="leaveAndKeepRoomOpen">Leave and keep room open</button>
</template>
The second argument defaults to true. Use false only for an explicit
Leave and keep room open control, await its result, and use the normal
authorized join flow when the host returns.
Release checklist
- Verify unauthenticated create and join requests are rejected by your backend.
- Test host and participant roles in separate browser contexts.
- Test allow, deny, dismiss, and device-loss paths for microphone and camera.
- Verify remote audio, video, and screen media with two real participants.
- Stop screen sharing from both your control and the browser's native control.
- Confirm participant leave removes remote media and clears local resources.
- Verify logs, errors, screenshots, and built assets contain no credentials.
- Verify your backend's grant expiry and room cleanup policy.
Build and test your Vue application, then complete the release checklist in a real two-user room. A successful web build does not prove device permission, active production, remote playback, or cleanup.