INTEGRITY Dokumentace

Správa stavu

Předpoklady

Tato stránka navazuje na Základní průvodce implementací. Ujistěte se, že jste si je nejprve přečetli.

Příklady kódu na této stránce předpokládají, že jste již importovali potřebné balíčky a inicializovali SDK.

Jak spolu komunikují komponenty UI Kit

Komponenty UI Kit se dokážou vzájemně rozpoznat a synchronizovat, protože jsou vnořené pod RtkMeeting komponenta. RtkMeeting komponenta funguje jako centrální koordinátor, který zajišťuje, aby všechny komponenty pod ní zůstaly synchronizované, pokud jde o stav schůzky, aktualizace účastníků a další změny v reálném čase.

Komponenty UI Kit se dokážou vzájemně rozpoznat a synchronizovat, protože jsou vnořené pod rtk-meeting komponenta. rtk-meeting komponenta funguje jako centrální koordinátor, který zajišťuje, aby všechny komponenty pod ní zůstaly synchronizované, pokud jde o stav schůzky, aktualizace účastníků a další změny v reálném čase.

Komponenty UI Kit se dokážou vzájemně rozpoznat a synchronizovat, protože jsou vnořené pod rtk-meeting komponenta. rtk-meeting komponenta funguje jako centrální koordinátor, který zajišťuje, aby všechny komponenty pod ní zůstaly synchronizované, pokud jde o stav schůzky, aktualizace účastníků a další změny v reálném čase.

Android UI Kit spravuje komunikaci mezi komponentami interně. Když UI Kit sestavíte pomocí RealtimeKitUIBuilder, vytváří a koordinuje všechny potřebné komponenty UI. Chcete-li ve své aplikaci sledovat změny stavu schůzky, připojte event listenery k vlastnosti Core SDK meeting objekt.

iOS UI Kit spravuje komunikaci mezi komponentami interně pomocí RealtimeKitUI modul. Chcete-li ve své aplikaci sledovat změny stavu schůzky, implementujte protokoly posluchačů událostí a zaregistrujte je v rámci Core SDK meeting objekt.

Komponenty React Native UI Kit spolu komunikují a synchronizují se, protože jsou vnořené pod RtkMeeting komponentu, zabalenou v RealtimeKitProvider a RtkUIProvider. Chcete-li sledovat změny stavu, použijte hooky z Core SDK, jako je useRealtimeKitSelector.

Zde je příklad, jak funguje synchronizace stavu při otevření postranního panelu s účastníky:

flowchart LR
    accTitle: Sidebar State Synchronization Example
    accDescr: Example showing how clicking participants toggle updates sidebar through meeting coordination

    Toggle["👤 ParticipantsToggle<br/>(User clicks)"]
    Meeting["Meeting Component<br/>(State Coordinator)"]
    Sidebar["Sidebar<br/>(Opens/Closes)"]
    App["Your App<br/>(Gets notified)"]

    Toggle -->|"emits rtkStateUpdate<br/>{activeSidebar: true,<br/>sidebar: 'participants'}"|Meeting
    Meeting -->|"propagates state"|Sidebar
    Meeting -->|"emits rtkStatesUpdate"|App

    style Meeting fill:#F48120,stroke:#333,stroke-width:2px,color:#fff
    style App fill:#0051C3,stroke:#333,stroke-width:2px,color:#fff

State Flow

  1. Potomci komponent vysílají aktualizace stavu: Když jakákoli komponenta UI potřebuje aktualizovat stav, vyšle rtkStateUpdate událost
  2. Komponenta Meeting naslouchá a koordinuje: Komponenta meeting naslouchá všem těmto událostem aktualizace stavu od svých potomků
  3. Šíření stavu: Komponenta meeting předává aktualizovaný stav všem ostatním podřízeným komponentám, aby zůstaly synchronizované
  4. Externí oznámení: Komponenta meeting také vysílá rtkStatesUpdate událost, kterou může vaše aplikace sledovat, aby aktualizovala vlastní uživatelské rozhraní nebo prováděla akce na základě změn stavu
  1. UI Kit spravuje interní stav: UI Kit interně zajišťuje veškerou komunikaci mezi komponentami a synchronizaci stavu
  2. Vaše aplikace registruje event listenery: Připojíte posluchače událostí (event listeners), jako je RtkMeetingRoomEventListener a RtkSelfEventListener) do Core SDK meeting objekt
  3. Callbacky se spouštějí při změnách stavu: Když se změní stav schůzky (například se připojí účastník nebo se přepne zvuk), zavolá se příslušný callback listeneru
  4. Aktualizujete své uživatelské rozhraní: Data z callbacku použijte k aktualizaci uživatelského rozhraní aplikace nebo ke spuštění dalších akcí
  1. UI Kit spravuje interní stav: RtkMeeting komponenta zajišťuje veškerou interní komunikaci mezi komponentami a synchronizaci stavu
  2. Vaše aplikace sleduje stav pomocí hooks: Použijte useRealtimeKitSelector a vybrat tak konkrétní vlastnosti schůzky a znovu vykreslit při jejich změně
  3. React se při změnách překresluje: Když se vybraná hodnota změní, React automaticky znovu vykreslí komponentu s novým stavem
  4. Aktualizujete své uživatelské rozhraní: Sledované hodnoty stavu použijte k podmíněnému vykreslování prvků UI nebo ke spouštění vedlejších efektů

Naslouchání aktualizacím stavu

Chcete-li vytvořit vlastní uživatelské rozhraní nebo provádět akce na základě změn stavu schůzky, musíte sledovat aktualizace stavu z UI Kit.

Naslouchejte rtkStatesUpdate událost vysílaná komponentou meeting. Tato událost vám poskytuje aktuální stav UI Kit, včetně stavu postranního panelu, stavu sdílení obrazovky, typu zobrazení a dalších informací.

Připojte posluchače událostí k Core SDK meeting ke sledování změn stavu schůzky. Mobilní UI Kit spravuje svůj vlastní interní stav a vaše aplikace komunikuje přímo s podkladovým objektem schůzky.

Použijte useRealtimeKitSelector hook z @cloudflare/realtimekit-react-native a sledovat tak konkrétní vlastnosti objektu schůzky. Tento hook znovu vykreslí vaši komponentu vždy, když se vybraná hodnota změní, podobně jako fungují selektory v knihovnách pro správu stavu.

Ukázkový kód

V Reactu můžete použít onRtkStatesUpdate prop na RtkMeeting komponentu pro naslouchání aktualizacím stavu.

import {
	RealtimeKitProvider,
	useRealtimeKitClient,
} from "@cloudflare/realtimekit-react";
import { RtkMeeting } from "@cloudflare/realtimekit-react-ui";
import { useEffect, useState } from "react";

function App() {
	const [meeting, initMeeting] = useRealtimeKitClient();
	const [authToken, setAuthToken] = useState("<participant_auth_token>");
	const [states, setStates] = useState({});

	useEffect(() => {
		if (authToken) {
			initMeeting({
				authToken: authToken,
			});
		}
	}, [authToken]);

	return (
		<RealtimeKitProvider value={meeting}>
			<RtkMeeting
				showSetupScreen={true}
				meeting={meeting}
				onRtkStatesUpdate={(e) => {
					// Update states when rtk-meeting emits state updates
					setStates(e.detail);

					// Example: Access various state properties
					console.log("Meeting state:", e.detail.meeting); // 'idle', 'setup', 'joined', 'ended', 'waiting'
					console.log("Is sidebar active:", e.detail.activeSidebar);
					console.log("Current sidebar section:", e.detail.sidebar);
					console.log("Is screen sharing:", e.detail.activeScreenShare);
				}}
			/>

			{/* Use states to build custom UI */}
			<div className="custom-ui">
				<p>Meeting State: {states.meeting}</p>
				<p>Sidebar Open: {states.activeSidebar ? "Yes" : "No"}</p>
			</div>
		</RealtimeKitProvider>
	);
}

Alternativa: použití refs (více schůzek)

Pokud vytváříte zážitek s více schůzkami na stejné stránce nebo se schůzkami probíhajícími bezprostředně po sobě, doporučujeme použít refs, abyste předešli konfliktům stavu mezi jednotlivými instancemi schůzky:

import {
	RealtimeKitProvider,
	useRealtimeKitClient,
} from "@cloudflare/realtimekit-react";
import { RtkMeeting } from "@cloudflare/realtimekit-react-ui";
import { useEffect, useState, useRef } from "react";

function App() {
	const [meeting, initMeeting] = useRealtimeKitClient();
	const [authToken, setAuthToken] = useState("<participant_auth_token>");
	const [states, setStates] = useState({});
	const meetingRef = useRef(null);

	useEffect(() => {
		if (authToken) {
			initMeeting({
				authToken: authToken,
			});
		}
	}, [authToken]);

	useEffect(() => {
		if (!meetingRef.current) return;

		const handleStatesUpdate = (e) => {
			setStates(e.detail);
			console.log("Meeting state:", e.detail.meeting);
			console.log("Is sidebar active:", e.detail.activeSidebar);
		};

		// Add event listener via ref
		meetingRef.current.addEventListener("rtkStatesUpdate", handleStatesUpdate);

		// Cleanup listener when component unmounts or meeting changes
		return () => {
			meetingRef.current?.removeEventListener(
				"rtkStatesUpdate",
				handleStatesUpdate,
			);
		};
	}, [meetingRef.current]);

	return (
		<RealtimeKitProvider value={meeting}>
			<RtkMeeting ref={meetingRef} showSetupScreen={true} meeting={meeting} />

			{/* Use states to build custom UI */}
			<div className="custom-ui">
				<p>Meeting State: {states.meeting}</p>
				<p>Sidebar Open: {states.activeSidebar ? "Yes" : "No"}</p>
			</div>
		</RealtimeKitProvider>
	);
}

U Web Components musíte přidat posluchače událostí k rtk-meeting komponentu pro naslouchání rtkStatesUpdate události.

<body>
	<rtk-meeting id="meeting-component"></rtk-meeting>
</body>
<script type="module">
	import RealtimeKitClient from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit@latest/dist/index.es.js";

	const meeting = await RealtimeKitClient.init({
		authToken: "<participant_auth_token>",
	});

	// Add <rtk-meeting id="meeting-component" /> to your HTML, otherwise you will get error
	const meetingComponent = document.querySelector("#meeting-component");

	// Listen for state updates from rtk-meeting
	meetingComponent.addEventListener("rtkStatesUpdate", (event) => {
		console.log("RTK states updated:", event.detail);

		// Store states to update your custom UI
		const states = event.detail;

		// Example: Access various state properties
		console.log("Meeting state:", states.meeting); // 'idle', 'setup', 'joined', 'ended', 'waiting'
		console.log("Is sidebar active:", states.activeSidebar);
		console.log("Current sidebar section:", states.sidebar); // 'chat', 'participants', 'polls', etc.
		console.log("Is screen sharing:", states.activeScreenShare);

		// Update your custom UI based on states
		// For example: Show/hide elements based on meeting state
		if (states.meeting === "joined") {
			// Show meeting controls
		}
	});

	meetingComponent.showSetupScreen = true;
	meetingComponent.meeting = meeting;
</script>

V Angularu musíte přidat posluchače událostí k rtk-meeting komponentu pro naslouchání rtkStatesUpdate události.

meeting.component.ts
import {
	Component,
	ElementRef,
	OnInit,
	OnDestroy,
	ViewChild,
} from "@angular/core";

@Component({
	selector: "app-meeting",
	template: `
		<rtk-meeting #meetingComponent id="meeting-component"></rtk-meeting>

		<!-- Use states to build custom UI -->
		<div class="custom-ui" *ngIf="states">
			<p>Meeting State: {{ states.meeting }}</p>
			<p>Sidebar Open: {{ states.activeSidebar ? "Yes" : "No" }}</p>
			<div *ngIf="states.meeting === 'joined'" class="meeting-controls">
				<!-- Show meeting controls when joined -->
				<p>Meeting controls would go here</p>
			</div>
		</div>
	`,
	styleUrls: ["./meeting.component.css"],
})
export class MeetingComponent implements OnInit, OnDestroy {
	@ViewChild("meetingComponent", { static: true }) meetingElement!: ElementRef;

	meeting: any;
	states: any = {};
	private authToken = "<participant_auth_token>";
	private stateUpdateListener?: (event: any) => void;

	async ngOnInit() {
		// Import RealtimeKit client dynamically
		const RealtimeKitClient = await import(
			"https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit@latest/dist/index.es.js"
		);

		// Initialize the meeting
		this.meeting = await RealtimeKitClient.default.init({
			authToken: this.authToken,
		});

		// Set up the meeting component
		const meetingComponent = this.meetingElement.nativeElement;

		// Create the event listener
		this.stateUpdateListener = (event: any) => {
			console.log("RTK states updated:", event.detail);

			// Store states to update your custom UI
			this.states = event.detail;

			// Example: Access various state properties
			console.log("Meeting state:", this.states.meeting); // 'idle', 'setup', 'joined', 'ended', 'waiting'
			console.log("Is sidebar active:", this.states.activeSidebar);
			console.log("Current sidebar section:", this.states.sidebar); // 'chat', 'participants', 'polls', etc.
			console.log("Is screen sharing:", this.states.activeScreenShare);

			// Update your custom UI based on states
			// For example: Show/hide elements based on meeting state
			if (this.states.meeting === "joined") {
				// Show meeting controls
				console.log("Meeting joined - showing controls");
			}
		};

		// Listen for state updates from rtk-meeting
		meetingComponent.addEventListener(
			"rtkStatesUpdate",
			this.stateUpdateListener,
		);

		// Configure the meeting component
		meetingComponent.showSetupScreen = true;
		meetingComponent.meeting = this.meeting;
	}

	ngOnDestroy() {
		// Clean up event listener when component is destroyed
		if (this.stateUpdateListener && this.meetingElement) {
			this.meetingElement.nativeElement.removeEventListener(
				"rtkStatesUpdate",
				this.stateUpdateListener,
			);
		}
	}
}

V systému Android připojte posluchače událostí k meeting ke sledování změn stavu. Použijte RtkMeetingRoomEventListener pro události životního cyklu schůzky a RtkSelfEventListener pro změny stavu místního účastníka.

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

class MeetingActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // After initializing the meeting and UI Kit (see Getting Started guide),
        // add event listeners to observe state changes.

        // Listen for meeting room state changes
        meeting.addMeetingRoomEventListener(object : RtkMeetingRoomEventListener {
            override fun onMeetingRoomJoinStarted() {
                Log.d("Meeting", "Join started")
            }

            override fun onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) {
                Log.d("Meeting", "Joined the meeting")
                // Update UI to show meeting controls
            }

            override fun onMeetingRoomJoinFailed(exception: Exception) {
                Log.e("Meeting", "Join failed: ${exception.message}")
            }

            override fun onMeetingRoomLeaveStarted() {
                Log.d("Meeting", "Leave started")
            }

            override fun onMeetingRoomLeft() {
                Log.d("Meeting", "Left the meeting")
            }

            override fun onMeetingEnded() {
                Log.d("Meeting", "Meeting ended for all participants")
            }

            override fun onActiveTabUpdate(activeTab: ActiveTab) {
                Log.d("Meeting", "Active tab changed: $activeTab")
            }
        })

        // Listen for local participant state changes
        meeting.addSelfEventListener(object : RtkSelfEventListener {
            override fun onAudioUpdate(isEnabled: Boolean) {
                Log.d("Meeting", "Audio: ${if (isEnabled) "on" else "off"}")
            }

            override fun onVideoUpdate(isEnabled: Boolean) {
                Log.d("Meeting", "Video: ${if (isEnabled) "on" else "off"}")
            }

            override fun onRemovedFromMeeting() {
                Log.d("Meeting", "Removed from meeting by host")
            }
        })
    }
}

V systému iOS implementujte protokoly posluchačů událostí a zaregistrujte je na meeting. Použijte RtkMeetingRoomEventListener pro události životního cyklu schůzky a RtkSelfEventListener pro změny stavu místního účastníka.

// Listen for meeting room state changes
extension MeetingViewModel: RtkMeetingRoomEventListener {
    func onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) {
        // Successfully joined the meeting (equivalent to 'joined' state)
    }

    func onMeetingRoomLeft() {
        // Successfully left the meeting
    }

    func onMeetingEnded() {
        // The meeting has ended for all participants (equivalent to 'ended' state)
    }

    func onActiveTabUpdate(activeTab: ActiveTab) {
        // Active tab changed (e.g., chat, polls, participants)
        // Use this to sync your custom UI with the active sidebar section
    }
}

// Listen for local participant state changes
extension MeetingViewModel: RtkSelfEventListener {
    func onAudioUpdate(isEnabled: Bool) {
        // Audio toggled on/off
    }

    func onVideoUpdate(isEnabled: Bool) {
        // Video toggled on/off
    }

    func onRemovedFromMeeting() {
        // Local user was removed from the meeting by host
    }
}

// Register the listeners
meeting.addMeetingRoomEventListener(meetingRoomEventListener: self)
meeting.addSelfEventListener(selfEventListener: self)

V React Native použijte useRealtimeKitSelector hook pro sledování konkrétních vlastností objektu schůzky. Tento vzor je obdobný jako u webového Core SDK.

import { useEffect } from "react";
import { View, Text } from "react-native";
import {
	RealtimeKitProvider,
	useRealtimeKitClient,
	useRealtimeKitMeeting,
	useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
import {
	RtkUIProvider,
	RtkMeeting,
} from "@cloudflare/realtimekit-react-native-ui";

function App() {
	const [meeting, initMeeting] = useRealtimeKitClient();

	useEffect(() => {
		initMeeting({
			authToken: "<participant_auth_token>",
			defaults: { audio: true, video: true },
		});
	}, []);

	return (
		<RealtimeKitProvider value={meeting}>
			<RtkUIProvider>
				<MeetingWithState />
			</RtkUIProvider>
		</RealtimeKitProvider>
	);
}

function MeetingWithState() {
	const { meeting } = useRealtimeKitMeeting();

	// Use selectors to observe meeting state
	const roomState = useRealtimeKitSelector((m) => m.self.roomState);
	const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
	const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);

	useEffect(() => {
		console.log("Room state:", roomState);
		console.log("Audio:", audioEnabled);
		console.log("Video:", videoEnabled);
	}, [roomState, audioEnabled, videoEnabled]);

	return (
		<View>
			{meeting && <RtkMeeting meeting={meeting} showSetupScreen={true} />}

			{/* Use state to build custom UI */}
			<View>
				<Text>Room State: {roomState}</Text>
				<Text>Audio: {audioEnabled ? "On" : "Off"}</Text>
				<Text>Video: {videoEnabled ? "On" : "Off"}</Text>
			</View>
		</View>
	);
}

Alternativa: použití event listenerů

Pro jemnější kontrolu můžete také použít posluchače založené na událostech, podobně jako u webového Core SDK:

import { useEffect } from "react";

function MeetingEvents() {
	const { meeting } = useRealtimeKitMeeting();

	useEffect(() => {
		if (!meeting) return;

		const handleRoomJoined = () => {
			console.log("Successfully joined the meeting");
		};

		const handleRoomLeft = ({ state }) => {
			if (state === "ended") {
				console.log("Meeting ended");
			}
		};

		meeting.self.on("roomJoined", handleRoomJoined);
		meeting.self.on("roomLeft", handleRoomLeft);

		return () => {
			meeting.self.removeListener("roomJoined", handleRoomJoined);
			meeting.self.removeListener("roomLeft", handleRoomLeft);
		};
	}, [meeting]);

	return null;
}

Vlastnosti stavu

rtkStatesUpdate událost poskytuje podrobné informace o vnitřním stavu UI Kit. Mezi klíčové vlastnosti patří:

Na mobilních platformách je stav sledován prostřednictvím posluchačů událostí Core SDK, nikoli pomocí jediného objektu stavu. Mezi klíčové posluchače událostí a jejich callbacky patří:

RtkMeetingRoomEventListener - Životní cyklus schůzky:

RtkSelfEventListener - Místní účastník:

RtkParticipantsEventListener - Vzdálení účastníci:

V React Native použijte useRealtimeKitSelector hook pro sledování konkrétních vlastností objektu schůzky. Mezi klíčové vlastnosti patří:

Osvědčené postupy