Skip to main content

Leave, End, and Rejoin a Room

A close button can mean three different things. Choose the meaning before you wire the control:

IntentResult
Participant leavesThat participant disconnects; everyone else continues.
Host leaves and preserves the roomThe host disconnects; participants and room duration continue; the host may rejoin.
Host ends the roomThe room closes for everyone.

Do not implement any of these by navigating away first. Await the semantic room action, stop app-owned media, then unmount the runtime.

The default remains host end​

For SDKs that expose endRoomOnHostExit, its default is true. This preserves the historical behavior: a host who uses the normal leave action ends the room. Pass false only from a control explicitly labelled, for example, Leave and keep room open. Never change the default globally to simulate this feature.

ReactJS 4.4.2​

import { useState } from 'react';
import { useMediasfuHeadless } from 'mediasfu-reactjs';

export function ExitControls({ isHost }: { isHost: boolean }) {
const room = useMediasfuHeadless();
const [error, setError] = useState('');

async function leave(endRoomOnHostExit: boolean) {
const result = await room.controls.leave(false, endRoomOnHostExit);
if (!result.ok) return setError(result.error);
// Stop app-owned tracks and navigate only after success.
}

return <>
<button onClick={() => void leave(true)}>{isHost ? 'End room' : 'Leave'}</button>
{isHost && <button onClick={() => void leave(false)}>Leave and keep room open</button>}
{error && <p role="alert">{error}</p>}
</>;
}

Calling room.controls.leave() with no arguments uses the same true default.

Angular 2.5.0​

async leaveAndKeepOpen() {
const result = await this.room.controls.leave(false, false);
this.error = result.ok ? '' : result.error;
}

async endRoom() {
const result = await this.room.controls.leave(false, true);
this.error = result.ok ? '' : result.error;
}

Keep MediasfuHeadlessService scoped to the room screen and dispose the screen only after the promise resolves.

Vue 1.3.0​

const room = useMediasfuHeadless();

const leaveAndKeepOpen = () => room.controls.leave(false, false);
const endRoom = () => room.controls.leave(false, true);

Show result.error when ok is false and run router navigation afterward.

React Native 2.5.0​

const room = useMediasfuHeadless();

async function leaveAndKeepOpen() {
const result = await room.controls.leave(false, false);
if (result.ok) navigation.goBack();
else setNotice(result.error);
}

Await track, renderer, and audio-route cleanup before destroying the room screen. A native back gesture should call the same semantic handler.

Expo 2.6.0​

Use the React Native call from mediasfu-reactnative-expo. Verify it in a development build: Expo Go is not a substitute for native WebRTC teardown.

Flutter 2.4.1​

final params = controller.parameters;
if (params == null) return;

final keepOpen = await leaveRoom(
params,
endRoomOnHostExit: false,
);
if (!keepOpen.ok) showError(keepOpen.error);

// The historical host-end path:
final end = await leaveRoom(params, endRoomOnHostExit: true);

The default is also true. Dispose the controller and app-owned tracks after the selected action completes.

Android 1.0.8​

The headless controller exposes disconnect() but no host-end or leave-without-ending option, and disconnect() alone does neither. Keep those two host controls out of a fully headless Compose screen. In the supplied Compose room, MediasfuGenericState.exitSession(endRoomOnHostExit = true) ends the room and false leaves it open.

Kotlin Multiplatform 1.0.8​

Use the supplied Compose room's supported exit flow. Disposing its state or disconnecting a headless transport is local cleanup, not confirmation that the server preserved or ended the room. If your application owns the host controls, keep leave and end separate and wait for the documented room action's result before displaying success. Release platform media resources after that action.

Swift and Apple platforms 0.1.3​

The Apple package does not currently publish an independent Swift headless leave/end facade. Let the hosted MediaSFUIosHostBridge room own its supported exit flow. A Swift navigation dismissal is local UI cleanup; it neither preserves nor ends the room.

Unity 0.1.0-preview.2​

var leaveAndKeepOpen = await headless.LeaveRoomAsync(endRoomOnHostExit: false);
if (!leaveAndKeepOpen.Success) ShowError(leaveAndKeepOpen.Error);

var end = await headless.EndMeetingAsync(); // verifies host and active room
if (!end.Success) ShowError(end.Error);

LeaveRoomAsync() without the Boolean keeps the historical true default.

Shared core 1.3.1​

import { leaveRoom } from 'mediasfu-shared';

const result = await leaveRoom({
parameters: latestParameters,
ban: false,
endRoomOnHostExit: false,
});

Consuming framework SDKs must still expose and bind this shared action; the shared export alone does not establish platform support.

Rejoin after preserving the room​

  1. Await the host's preserve-room leave result.
  2. Remove the departed host's local tracks, renderers, and subscriptions.
  3. Keep the room identifier and application invitation authority server-side or in your authenticated session; do not retain a reusable Cloud credential.
  4. Run the normal join flow again with a fresh authorized join result.
  5. Wait for readiness and a current participant projection before restoring host controls.

If your application requires unique display names, wait for the old membership to clear before rejoining with the same name. Removing a participant prevents that current membership from remaining in the room; a durable account ban is an application/server policy unless the room contract explicitly binds identity beyond a user-chosen display name.

Reconnect is not rejoin​

A transient socket interruption should use the SDK's reconnect lifecycle and retain the participant's original role. An intentional semantic leave creates a new join lifecycle. A host-ended room is terminal and should not display a reconnect button.

Prevent duplicate joins and participant aliases​

Treat one user attempt as one room-registration transaction. Do not create or join from a mount effect and then repeat the same operation from a button, router callback, retry timer, or a second independent component.

  1. Generate one idempotency key when an application backend begins a room creation or participant-registration attempt.
  2. Reuse that key only while retrying the same uncertain request.
  3. Generate a new key for a new room, a deliberate replacement session, or a new participant attempt.
  4. Keep the submission pending until the first result resolves; do not let a second handler issue a parallel join.
  5. After a successful leave, wait for the old membership to clear before registering the same display alias again when the product requires aliases to be unique.

The backend is the authority for idempotency and participant registration. Browser or mobile state can disable a duplicate button, but it cannot safely deduplicate two accepted server requests by itself.

Teardown checklist​

  • Label host End room and Leave and keep room open separately.
  • Await the chosen semantic action before navigation.
  • Stop app-created tracks and clear their srcObject/native renderer bindings.
  • Close or release superseded producers, consumers, send/receive transports, audio outputs, and screen/background processors owned by the application.
  • Remove socket subscriptions, DOM/native event listeners, observers, and retry/reconnect timers created by the application.
  • Ignore only safe late acknowledgements from state already confirmed closed; show other transport and cleanup errors.
  • Clear room-scoped invitations and business state according to your application policy.
  • Test with a second participant: preserve, continue media, rejoin, then end.

Continue with media lifecycle, headless UI, and secure room authority.