< Flutter UIKit />
UTD Live Room Kit
호스트 카메라, 게스트 타일, 무대 관리를 갖춘 비디오 라이브 룸.
import 'package:utd_live_room_kit/utd_live_room_kit.dart';
UTDLiveRoom(
appId: '<utd-app-id>',
appKey: '<utd-app-key>', // publishable; no backend needed
userId: 'user123',
userName: 'Jane',
roomId: 'room456',
roomOwnerId: 'owner789',
adminIds: const {'mod1', 'mod2'},
config: const UTDLiveRoomConfig(maxGuestTiles: 3),
);3
게스트 타일
4
역할
Drop-in
완전한 UI
PiP
+ 최소화
< utd_live_room_kit />
주요 기능
LiveKit과 UTD Stream Engine으로 구동되는 인터랙티브 비디오 라이브 룸을 위한 프로덕션 준비형 Flutter 패키지입니다. 전체 화면 호스트 카메라와 최대 3개의 플로팅 게스트 타일, 서버 권한 기반 역할(호스트, 게스트, 관리자, 시청자), 공동 게시자 초대를 위한 동적 무대 작업, 실시간 채팅, 오디오 라우팅이 포함된 미디어 컨트롤, 그리고 최소화/PiP를 제공합니다.
호스트 + 게스트 타일을 갖춘 바로 쓰는 라이브 룸 UI
제한 없는 라이브 스트림 무대(좌석 그리드 없음)
무대 흐름: 발언 요청, 호스트 초대, 제거
서버 권한 기반 역할: 호스트, 게스트, 관리자(모더레이터), 시청자
호스트 미디어 제어: 강제 음소거/해제, 카메라 중지, 무대에서 제거
중복 제거를 갖춘 실시간 데이터 채널 채팅
계층형 재연결(라이트 <15s, 풀 <60s, 종료 >60s)
선택적 Android OS PiP와 함께 플로팅 오버레이로 최소화
TrackProcessor를 통한 비디오 효과(Video Effects Kit와 함께 사용)
백엔드 없는 자격 증명: 사용자별 bearer 인증을 적용한 appKey 토큰 발급
< utd_live_room_kit />
시작하기
설치
flutter pub add utd_live_room_kit< utd_live_room_kit />
API 레퍼런스
Main widget
The drop-in LiveKit live-streaming room widget.
UTDLiveRoomwidgetconst UTDLiveRoom({required String appId, required String appKey, required String userId, required String userName, required String roomId, required String roomOwnerId, Set<String> adminIds, ..., UTDLiveRoomConfig config, void Function(UTDRoomController)? onControllerReady, ...})A LiveKit-based video live room. The host's camera fills the screen as the background; up to maxGuestTiles invited guests appear as floating video tiles. Audience watch + chat and may request to go live.
매개변수
appIdString필수App ID for the UTD Stream Engine (X-App-Id).
appKeyString필수Publishable app key (no backend). The kit mints tokens directly with X-App-Key; the server secret never ships.
userIdString필수Local user's identity.
userNameString필수Local user's display name.
roomIdString필수Room / LiveKit room name to join.
roomOwnerIdString필수Identity of the room owner (becomes host); everyone else joins as audience.
adminIdsSet<String>기본값 = const {}Identities the owner will promote to admin (moderators) once present in the room.
adminIdsResolverFuture<Set<String>> Function()?기본값 = nullAsync source for adminIds resolved after join; the owner self-promotes them via the role endpoint.
adminIdsNowSet<String> Function()?기본값 = nullOptional sync probe for the admin list at token time (no waiting).
configUTDLiveRoomConfig기본값 = const UTDLiveRoomConfig()Behaviour, theming, and section/tile override configuration.
onControllerReadyvoid Function(UTDRoomController)?기본값 = nullCalled once the room controller is created (use it to drive the room imperatively).
onConnectionChangedvoid Function(bool)?기본값 = nullCalled when the connection succeeds (true) or fails (false).
onConnectErrorvoid Function(Object, StackTrace)?기본값 = nullCalled on connect failure; if null the kit shows its built-in connect-error view.
controllerUTDRoomController?기본값 = nullReuse an existing already-connected controller, e.g. restoring from a minimized overlay.
Room controller
Imperative facade over the room: connection lifecycle, participants, roles, stage, moderation, and sub-controllers.
UTDRoomControllerconstructorUTDRoomController()Creates a room controller that wires up the seat/stage, media, chat, minimize, and PiP sub-controllers.
initApimethodvoid initApi({String baseUrl, String engineBaseUrl, String? appId, String? appKey})Initializes the engine REST clients (token host + in-room ops host). Must be called before connect to use the backend APIs.
매개변수
baseUrlString기본값 = UTDApiClient.defaultBaseUrlToken/auth host (POST /api/v1/token).
engineBaseUrlString기본값 = UTDApiClient.defaultEngineBaseUrlIn-room ops host (stage, roles, bans, participants).
appIdString?기본값 = nullApp ID sent as the X-App-Id header.
appKeyString?기본값 = nullPublishable app key (no-backend mint credential, sent as X-App-Key).
connectmethodasyncFuture<void> connect({required String url, required String token, int seatCount = 9, bool enableMicOnJoin = false, bool useSpeaker = true, Map<String, String> userAttributes = const {}, String? roomName, String? hostIdentity})Connects to the LiveKit room, initializes seats/stage, starts chat + media listeners, and begins participant/speaking tracking.
매개변수
urlString필수LiveKit server URL from the token response.
tokenString필수LiveKit access token from generateToken.
seatCountint기본값 = 9Tile-layout capacity (host slot + guest tiles); the engine stage is uncapped.
enableMicOnJoinbool기본값 = falseEnable the local mic immediately after connecting.
useSpeakerbool기본값 = trueRoute audio to the speaker (preferring Bluetooth) on join.
userAttributesMap<String, String>기본값 = const {}Participant attributes (avatar, name, VIP frame, etc.) published after connect.
roomNameString?기본값 = nullRoom name used for in-room REST calls; falls back to the LiveKit room name.
hostIdentityString?기본값 = nullOwner identity, used to detect when the host leaves and end the live for others.
generateTokenmethodasyncFuture<UTDTokenResponse> generateToken({required String identity, required String roomName, required String roomOwnerId, String type = 'live_stream', String? name, String role = 'audience', ..., Map<String, dynamic>? metadata})Mints a LiveKit token via the engine and, in app-key mode, applies the returned per-user bearer to the in-room clients. Throws UTDBannedException on a 403 ban.
매개변수
identityString필수User identity to mint the token for.
roomNameString필수Target room name.
roomOwnerIdString필수Identity of the room owner.
typeString기본값 = 'live_stream'Engine product type; live_stream is the unbounded seatless stage.
nameString?기본값 = nullDisplay name.
roleString기본값 = 'audience'Requested role; the engine clamps non-owners to audience.
deviceIdString?기본값 = nullStable per-install id for single-active-session enforcement; auto-resolved when omitted.
metadataMap<String, dynamic>?기본값 = nullExtra metadata to embed in the token.
leavemethodasyncFuture<void> leave()Leaves the room: a host broadcasts _live_ended first, then all listeners/timers are cancelled and LiveKit is disconnected.
disposemethodvoid dispose()Releases all controller resources (timers, subscriptions, notifiers, sub-controllers, and REST clients). Idempotent.
requestToSpeakmethodasyncFuture<Map<String, dynamic>?> requestToSpeak()Local audience member asks to go on stage (transient host-side signal). Returns a result map on success, null on failure.
inviteToSpeakmethodasyncFuture<Map<String, dynamic>?> inviteToSpeak(String targetIdentity)Host/admin invites a user onto the stage (grants publish immediately, no accept/decline). Returns null when guest tiles are full.
매개변수
targetIdentityString필수Identity of the user to invite on stage.
approveSpeakerRequestmethodasyncFuture<Map<String, dynamic>?> approveSpeakerRequest(String identity)Host/admin approves a pending stage request by adding the user to the stage. Returns null when guest tiles are full.
매개변수
identityString필수Identity of the requester to approve.
changeRolemethodasyncFuture<UTDRoleChangeResult> changeRole({required String targetIdentity, required String role})Owner-only: changes a participant's role via the engine. Throws on REST error (403/404/409/422) so callers can surface a message.
매개변수
targetIdentityString필수Identity of the participant whose role changes.
roleString필수New role (e.g. 'admin', 'audience').
banUsermethodasyncFuture<bool> banUser(String identity, {String? reason, int? durationSeconds, bool global = false})Bans a user. Room-scoped by default; pass global true for a project-wide ban. Returns true on success.
매개변수
identityString필수Identity to ban.
reasonString?기본값 = nullOptional ban reason.
durationSecondsint?기본값 = nullBan duration; null = permanent.
globalbool기본값 = falseWhen true, bans across the whole project rather than this room.
kickParticipantmethodasyncFuture<bool> kickParticipant(String targetIdentity)Host/admin: removes a user from the broadcast entirely (engine-side disconnect). Returns true on success.
매개변수
targetIdentityString필수Identity to remove from the room.
setRemoteMicEnabledmethodasyncFuture<bool> setRemoteMicEnabled(String targetIdentity, bool enabled)Host/admin: server-side force-mute or unmute another participant's microphone. Returns true on success.
매개변수
targetIdentityString필수Identity whose mic is controlled.
enabledbool필수True to enable, false to mute.
sendChatMessagemethodasyncFuture<void> sendChatMessage(String text)Sends a chat message to the room (delegates to the chat controller).
매개변수
textString필수Message body to send.
participantsStreamgetterasyncStream<List<UTDParticipant>> get participantsStreamStream of all room participants; emits on join/leave/attribute/metadata changes.
반환값: Stream<List<UTDParticipant>> — Live participant list.
roleChangeStreamgetterasyncStream<UTDRoleChangeEvent> get roleChangeStreamStream of role changes (_role_change) for all participants — owner promotions/demotions and engine auto-corrections.
반환값: Stream<UTDRoleChangeEvent> — Role-change events.
isConnectedgetterbool get isConnectedWhether the room is currently in the connected state.
반환값: bool — True when connected.
isLocalHostgetterbool get isLocalHostWhether this device is the room owner (host).
반환값: bool — True if the local user is the host.
activeSpeakerspropertyfinal ValueNotifier<Set<String>> activeSpeakersSet of user IDs currently speaking, driven by LiveKit active-speaker events plus a 300ms backstop poll.
반환값: ValueNotifier<Set<String>> — Speaking identities.
onBannedcallbackvoid Function(UTDBanNotice notice)? onBannedFired once when the local user is banned (data message, removal, or token 403). The widget wires this to show the banned dialog and leave.
반환값: void Function(UTDBanNotice)? — Ban callback.
Media controller
Mic, camera, speaker, and host preview/Go-Live control (UTDRoomController.mediaController).
startPreviewmethodasyncFuture<LocalVideoTrack?> startPreview({CameraPosition position = CameraPosition.front})Creates a local, unpublished camera preview for the host 'Go Live' screen (no remote sees it). Idempotent.
매개변수
positionCameraPosition기본값 = CameraPosition.frontFront/back camera to open the preview with.
goLivemethodasyncFuture<void> goLive({bool withMic = true})Host 'Go Live': publishes the camera (reusing the preview track for no flicker) and, by default, enables the mic.
매개변수
withMicbool기본값 = trueAlso enable the microphone when going live.
setMicrophoneEnabledmethodasyncFuture<void> setMicrophoneEnabled(bool enabled)Sets the local microphone to a specific enabled state and updates isMicEnabled.
매개변수
enabledbool필수True to enable, false to mute.
setCameraEnabledmethodasyncFuture<void> setCameraEnabled(bool enabled)Sets the local camera to a specific state (requests camera permission first) and updates isCameraEnabled.
매개변수
enabledbool필수True to enable, false to disable.
switchCameramethodasyncFuture<void> switchCamera()Flips between front and back camera for the active (published or preview) camera track, re-attaching any video-effects processor.
setSpeakerOnmethodasyncFuture<void> setSpeakerOn(bool on)Turns the speaker on/off. Off truly silences the room (disables remote audio tracks), not just reroutes to the earpiece.
매개변수
onbool필수True for loudspeaker, false to silence the room.
setVideoProcessormethodasyncFuture<void> setVideoProcessor(TrackProcessor<VideoProcessorOptions>? processor)Attaches (or detaches with null) a beauty/filter processor to the active local camera track at runtime, without re-capturing.
매개변수
processorTrackProcessor<VideoProcessorOptions>?필수Effects processor to attach; null detaches.
isMicEnabledpropertyfinal ValueNotifier<bool> isMicEnabledReactive local microphone enabled state, kept in sync with server/host-initiated mutes.
반환값: ValueNotifier<bool> — Mic state.
canPublishpropertyfinal ValueNotifier<bool> canPublishWhether the local participant may publish mic/camera; driven by LiveKit permission events. Gate publish UI on this.
반환값: ValueNotifier<bool> — Publish permission.
isPreviewingpropertyfinal ValueNotifier<bool> isPreviewingWhether a local, unpublished camera preview (host 'Go Live' screen) is active.
반환값: ValueNotifier<bool> — Preview-active state.
Stage REST API
Direct REST client for the live_stream stage endpoints (UTDStageApi). The stage is the unbounded publisher set: host plus host-invited co-publishers.
getStagemethodasyncFuture<Map<String, dynamic>> getStage({required String roomName})Returns the current stage publishers as { members: [{ identity, name, role }] }. GET /api/v1/rooms/:name/stage.
매개변수
roomNameString필수Room name.
addToStagemethodasyncFuture<Map<String, dynamic>> addToStage({required String roomName, required String targetIdentity, required String actorIdentity})Host/admin invites a user onto the stage (grants A/V publish). POST /api/v1/rooms/:name/stage/add.
매개변수
roomNameString필수Room name.
targetIdentityString필수User being added to the stage.
actorIdentityString필수Host/admin performing the action (dual-mode fallback).
removeFromStagemethodasyncFuture<Map<String, dynamic>> removeFromStage({required String roomName, required String targetIdentity, required String actorIdentity})Host/admin removes a user from the stage (revokes publish). POST /api/v1/rooms/:name/stage/remove.
매개변수
roomNameString필수Room name.
targetIdentityString필수User being removed from the stage.
actorIdentityString필수Host/admin performing the action.
leaveStagemethodasyncFuture<Map<String, dynamic>> leaveStage({required String roomName, required String identity})A co-publisher steps down from the stage on their own. POST /api/v1/rooms/:name/stage/leave.
매개변수
roomNameString필수Room name.
identityString필수The co-publisher leaving the stage.
requestStagemethodasyncFuture<Map<String, dynamic>> requestStage({required String roomName, required String identity})A viewer asks to go on stage; the engine notifies host/admins via a _stage_request message (no persisted queue). POST /api/v1/rooms/:name/stage/request.
매개변수
roomNameString필수Room name.
identityString필수The requesting viewer's identity.
Chat controller
Room chat: send, receive, and retain messages (UTDRoomController.chatController).
sendMessagemethodasyncFuture<void> sendMessage(String text, {Map<String, dynamic>? userData})Sends a chat message (trims and skips empty text), appends it locally, and broadcasts it over the data channel.
매개변수
textString필수Message body.
userDataMap<String, dynamic>?기본값 = nullOptional sender metadata (e.g. avatar, VIP frame) attached to the message.
addDisplayMessagemethodvoid addDisplayMessage(UTDChatMessage message)Appends a message to the list for display only (e.g. local system notices), without sending it.
매개변수
messageUTDChatMessage필수Message to append locally.
clearMessagesmethodvoid clearMessages()Clears the retained chat message list.
messagespropertyfinal ValueNotifier<List<UTDChatMessage>> messagesReactive list of retained chat messages (capped at the most recent 300).
반환값: ValueNotifier<List<UTDChatMessage>> — Chat history.
Configuration & theming
Room behaviour, layout overrides, video effects, and color tokens.
UTDLiveRoomConfigconstructorconst UTDLiveRoomConfig({bool showControlsBar = true, bool enableMinimize = true, bool autoHostCamera = false, bool frontCameraOnJoin = true, bool mirrorLocalVideo = true, int maxGuestTiles = 3, ..., UTDRoomTheme theme = const UTDRoomTheme(), UTDRoomStrings? strings, ...})Configuration for UTDLiveRoom: shared room behaviour, live video behaviour, theming, section/tile builder overrides, video effects, and user attributes.
매개변수
showControlsBarbool기본값 = trueRender the built-in controls bar.
enableMinimizebool기본값 = trueAllow minimizing the room to an overlay.
useSpeakerWhenJoiningbool기본값 = trueRoute audio to the speaker on join.
showGoLiveButtonbool기본값 = trueShow the built-in centered Go Live button during host preview.
autoHostCamerabool기본값 = falseHost publishes the camera immediately on connect, skipping self-preview.
frontCameraOnJoinbool기본값 = trueStart on the front camera.
mirrorLocalVideobool기본값 = trueMirror the local camera tile (selfie view).
maxGuestTilesint기본값 = 3Max simultaneous guest tiles (host excluded); enforced server-side too.
hostFitVideoViewFit기본값 = VideoViewFit.coverHow the host's full-bleed video is fitted.
guestFitVideoViewFit기본값 = VideoViewFit.coverHow each floating guest tile's video is fitted.
themeUTDRoomTheme기본값 = const UTDRoomTheme()Color tokens for the built-in UI.
stringsUTDRoomStrings?기본값 = nullLocalized strings; null = English defaults.
headerWidgetWidget?기본값 = nullOverride for the room header section.
messagesWidgetWidget?기본값 = nullOverride for the chat/messages area.
controlsBarWidgetWidget?기본값 = nullOverride for the controls bar.
guestTileFooterBuilderWidget Function(BuildContext, String)?기본값 = nullOverlay at the bottom of each guest tile, receives the guest identity.
onStageTapvoid Function()?기본값 = nullCalled when the empty host-video stage area is tapped (e.g. tap-hearts).
userInRoomAttributesMap<String, String>기본값 = const {}Attributes shared with other participants.
buildVideoProcessorTrackProcessor<VideoProcessorOptions> Function()?기본값 = nullFactory building a fresh video-effects (beauty/filter) processor per camera capture.
UTDRoomThemeconstructorconst UTDRoomTheme({Color background, Color surface, Color onSurface, Color primary, Color danger, Color seatRingSpeaking, Color badgeHost, Color badgeAdmin, ...})Color tokens for the package's built-in default UI. Every field has a dark-room default, so const UTDRoomTheme() is a complete, usable theme.
매개변수
backgroundColor기본값 = Color(0xFF14121C)Full-screen room background.
surfaceColor기본값 = Color(0xFF1C1C28)Surface behind grouped content.
onSurfaceColor기본값 = Colors.whitePrimary foreground color for text/icons.
primaryColor기본값 = Color(0xFF6C5CE7)Accent / call-to-action color.
dangerColor기본값 = Color(0xFFE74C3C)Destructive color (leave, kick, ban, mute).
seatRingSpeakingColor기본값 = Color(0xFF2ECC71)Ring around a tile whose occupant is speaking.
badgeHostColor기본값 = Color(0xFFFFA726)Badge color for the host role.
badgeAdminColor기본값 = Color(0xFF448AFF)Badge color for the admin role.
copyWithmethodUTDRoomTheme copyWith({Color? background, Color? surface, Color? primary, Color? danger, ...})Returns a copy of the theme with the given tokens overridden — rebrand without replacing whole widgets.
Models & enums
Data types for participants, seats, roles, bans, chat, and exceptions.
UTDParticipantclassconst UTDParticipant({required String id, required String name, bool isMicEnabled = false, bool isSpeaking = false, Map<String, String> attributes = const {}})A room participant: id, display name, mic/speaking state, and custom attributes (e.g. 'fr' frame, 'frt' frame type, 'cn' color name).
매개변수
idString필수Unique user ID.
nameString필수Display name.
isMicEnabledbool기본값 = falseWhether the participant's mic is on.
isSpeakingbool기본값 = falseWhether the participant is currently speaking.
attributesMap<String, String>기본값 = const {}Custom participant attributes.
UTDRoleenumenum UTDRole { visitor, audience, guest, admin, host }The known engine roles, lowest to highest privilege. The room owner is identified separately (owner_identity), not by these roles.
SeatStateclassconst SeatState({required int index, String? occupantUserId, Map<String, String> attributes = const {}})One tile in the live room: index 0 = host, 1..N = guest tiles. On the wire this is a backend seat.
매개변수
indexint필수Tile/seat index (0 = host).
occupantUserIdString?기본값 = nullUser occupying the tile; null = empty.
attributesMap<String, String>기본값 = const {}Occupant attributes (name, avatar, fr, frt).
UTDRoleChangeEventclassconst UTDRoleChangeEvent({required String identity, required String role, String? previousRole})Realtime _role_change event broadcast to all participants. Server-sent, so identify the affected user from identity (the LiveKit sender is null).
매개변수
identityString필수Affected user's identity.
roleString필수New role.
previousRoleString?기본값 = nullRole before the change.
UTDChatMessageclassUTDChatMessage({required String senderUserId, required String senderName, required String text, required DateTime timestamp, Map<String, dynamic> userData = const {}, String? messageID})A chat message. The text field is untrusted, peer-supplied input relayed verbatim — render as plain text only.
매개변수
senderUserIdString필수Sender's identity.
senderNameString필수Sender's display name.
textString필수Message body (untrusted plain text).
timestampDateTime필수When the message was created.
userDataMap<String, dynamic>기본값 = const {}Optional sender metadata.
messageIDString?기본값 = autoMessage id; defaults to a millisecond timestamp string.
UTDBanNoticeclassconst UTDBanNotice({String? roomName, String? reason, DateTime? expiresAt, UTDBanSource source = UTDBanSource.dataMessage})A ban (or forced-exit) notice delivered to the local user, with named constructors for data-message, disconnect, token-403, and signed-in-elsewhere sources.
매개변수
roomNameString?기본값 = nullRoom the ban applies to; null = global.
reasonString?기본값 = nullBan reason when known.
expiresAtDateTime?기본값 = nullExpiry; null = permanent.
sourceUTDBanSource기본값 = UTDBanSource.dataMessageWhere the notice originated.
UTDBannedExceptionclassconst UTDBannedException([String message = 'User is banned', int statusCode = 403])Thrown by token generation when the server returns 403 User is banned.
매개변수
messageString기본값 = 'User is banned'Error message.
statusCodeint기본값 = 403HTTP status code.