utd_live_room_kit 1.6.3
utd_live_room_kit: ^1.6.3 copied to clipboard
LiveKit-based video live room for Flutter: host camera plus up to three guest tiles, go-live requests, host media control, chat, and minimize/PiP.
Changelog #
1.6.3 #
Fix — OTHER users on the stage saw a peer's OLD avatar/name after that peer changed them mid-session (1.6.2 fixed only the changer's own tile).
- Root cause: repainting a peer's tile relied on the SFU fanning the changer's
setAttributesout to present participants as aParticipantAttributesChangedevent. That fan-out is as unreliable as the sender echo 1.6.2 worked around, so peers kept the stale attributes/_stagesnapshot until they rejoined. updateSelfAttributesnow ALSO broadcasts the changed cosmetics over the reliable data channel as a_cosmetic_updatemessage ({type, identity, attrs}). Each recipient applies it to the sender's tile viaapplyCosmeticOverride.setAttributesis still called so LiveKit's attribute sync covers late joiners (who never receive the one-shot data message).applyLocalCosmeticOverride(attrs)→ generalized toapplyCosmeticOverride(identity, attrs), andlocalCosmeticOverrides→ per-identitycosmeticOverrides(Map<identity, Map<key,value>>). The stage's_avatarOf/_nameOf(via_liveAttr) now overlay the override for ANY identity, not just the local one. Empty values are honored (an unequip clears a stale value). A departed participant's override is dropped on participant-left; the whole map clears on dispose.
1.6.2 #
Fix — the local user's OWN tile did not repaint on a mid-session cosmetic change.
LocalParticipant.setAttributes(livekit_client) only sends the change to the SFU and awaits an ack; it does not updatelocalParticipant.attributes, and the server does not necessarily echo a participant update back to the sender. So afterupdateSelfAttributes,live_stage's_avatarOf/_nameOfre-read the still-stale local attribute map and the user's own tile kept the old avatar/name until they rejoined.- New
UTDSeatController.applyLocalCosmeticOverride(attrs), called fromupdateSelfAttributes, records the freshly published values inlocalCosmeticOverridesand re-emitsseatsso the stage rebuilds. The stage helpers now overlay these overrides for the local identity, so the local tile repaints immediately. Cleared on dispose.
1.6.1 #
Live cosmetics update — additive and backward compatible.
- New
UTDRoomController.updateSelfAttributes(Map<String, String>)re-publishes the local participant's cosmetic attributes (avatar, name, …) after join. LiveKit fans the change to everyone in the room and to late joiners, so a user who changes their photo mid-session updates on their host/guest tile — for themselves and others — without leaving and re-entering. UTDLiveStagenow resolves the tile avatar and name from the live participant attributes first, falling back to the_seatssnapshot. The snapshot is built at the last seat mutation and would otherwise render a mid-session change stale.
1.6.0 #
- Developer-controlled video publish quality. New
UTDVideoQualityenum (low360p /sd540p /hd720p /fullHd1080p) exposed asUTDLiveRoomConfig.videoQualityandUTDRoomController.setVideoQuality(call beforeconnect). The tier drives BOTH the camera capture resolution and the publish encoding (defaultVideoPublishOptions.videoEncoding+ simulcast layers) for every local camera path: host self-preview → Go Live, guest go-live,setCameraEnabled, and reconnect re-publish. Default is HD (720p) — unchanged capture behavior, but the publish bitrate is now pinned to the tier (~1.7 Mbps for HD) instead of LiveKit's derived default.
1.5.1 #
- Distinguish a not-activated service from a ban on the token endpoint. A non-ban
403(e.g.Type 'live_stream' is not enabled for this project) now throws the newUTDServiceNotAvailableExceptioninstead ofUTDBannedException. - The built-in connect-error view shows a distinct "not available" message and hides Retry
for that refusal (retrying can't help). Adds
UTDRoomStrings.serviceNotAvailable(EN + AR).
1.5.0 #
- Video Effects entitlement (trusted, token-signed). The kit now decodes a
server-signed
videoEffectsentitlement from the join token (the engine resolves it per-platform against the requesting client'sosat mint and stamps a boolean into the token'smetadataclaim) and threads it into the video-processor factory. Effects therefore run only when the customer has activated + paid for the current platform; unentitled sessions get a passthrough processor. The signature is read client-side WITHOUT verifying it (the SFU verifies the token on join); the processor is the authoritative gate.- Breaking: the processor factory now receives the entitlement —
UTDLiveRoomConfig.buildVideoProcessorandUTDRoomController.setVideoProcessorFactorychanged fromTrackProcessor Function()?toTrackProcessor Function(bool entitled)?. Forward the flag to your processor, e.g.(entitled) => VideoEffectsProcessor.create(entitled: entitled). - New
UTDRoomController.videoEffectsEntitledgetter (valid afterconnect) so UI can surface an "activate to unlock" hint. - Backward-compatible / fail-open: a token with no
videoEffectsclaim (older engine) keeps effects working; only an explicitfalsedisables them.
- Breaking: the processor factory now receives the entitlement —
1.4.0 #
-
Seat grid → unbounded stage. A live room is no longer a fixed 4-tile seat grid (host on seat 0 + up to 3 guest tiles).
live_streamis now ALWAYS the engine's unbounded seatless stage: the LiveKit room is uncapped (maxParticipants: 0) so viewers are unlimited, and this package decides how many co-host tiles to surface (still 4 by default — the cap is now purely a UI choice, not an engine limit). Every non-owner joins asaudience; the host promotes co-publishers post-join. -
Type-first token.
generateTokennow sendstype: 'live_stream'toPOST /api/v1/tokenand no longer sendsservice/kindorseat_count/seat_mode/host_seat— those are ignored forlive_stream. The engine still accepts the legacyservice(rooms)+kind(live) fields, so an un-migrated app keeps working; this version opts into the canonical type. The sameapp_id/app_keyworks for every product type the project has enabled —typeis a per-request field, not a credential. A request for a type the project hasn't enabled returns403 "Type 'live_stream' is not enabled for this project". -
Publishing decoupled from moderation. Roles are server-authoritative and the engine clamps a non-owner's claimed role to
audience(a client can no longer self-grant publish by claimingrole: 'host'):host— the verified room owner (publishes and moderates).guest— a host-invited co-publisher (publishes only).admin— an owner-promoted moderator that moderates only and is never on camera (decoupled — promoting to admin no longer grants a tile).audience— default (neither).
-
New
stage_api(UTDStageApi, exported viastage_api.dart) for thelive_streamstage endpoints (alllive_stream-only; the engine returns400on a seated/non-live_streamroom and403iflive_streamisn't enabled):getStage→GET /api/v1/rooms/:name/stage→{ members: [{ identity, name, role }] }(publishers = host + guests).addToStage→POST /api/v1/rooms/:name/stage/add{ target_identity }(host/admin → grants publish, sets roleguest).removeFromStage→POST /api/v1/rooms/:name/stage/remove{ target_identity }(host/admin → back toaudience).leaveStage→POST /api/v1/rooms/:name/stage/leave(self step-down).requestStage→POST /api/v1/rooms/:name/stage/request(viewer raise-hand; the engine notifies host/admins via a_stage_requestdata message — no server-side queue).
The actor is resolved server-side from the per-user bearer;
identityrides the body as a dual-mode fallback. Stage state arrives over the data channel as_stage_update(roster) and via the_stageroom-metadata key for late joiners;_stage_requestis the raise-hand ping. -
Moderator promotion reuses the existing role endpoint —
PUT /api/v1/rooms/:name/participants/:identity/role{ role: 'admin' }, owner-only. On a stage room this grants moderation but not publish; the engine refuses (409) to add anadminto the stage to keep the two capabilities disjoint (demote first). -
Removed
seat_apiandspeaker_apialong with the invite/request-to-go- live invitation handshake (/seats/*,/speakers/*includingspeakers/invite+invitations/:id/accept|decline). The live room is the stage now; seats/speakers remain inutd_audio_room_kit(and on the engine foraudio_room+ the legacy live kit) but are gone from this package. Breaking for integrators driving seats/speakers directly: switch toUTDStageApi. -
Minimum engine version: requires an engine build with the type-first token path and the
live_streamstage endpoints (enabled_types+/stage/*). Older engines that only understandservice/kindwill reject thetypefield — stay on1.3.0against those until the engine is upgraded.
1.3.0 #
- No-backend credentials (recommended): pass
UTDLiveRoom(appKey: ...)/UTDRoomController.initApi(appKey: ...)— the project's publishable app key. The kit mints tokens directly from the engine (X-App-KeyonPOST /api/v1/token), and the engine signs the returned per-useruser_tokenwith the projectserver_secretserver-side, so the secret never ships in the app and no integrator backend is required. The kit applies thatuser_tokenas theAuthorization: Bearerfor all in-room/moderation calls (persisted acrossinitApire-inits, so it survives restore-from-minimize). - Removed
tokenProviderand itsUTDTokenRequest/UTDTokenBundle/UTDTokenProvidertypes (added in 1.2.0). The no-backendappKeyflow above replaces it. Breaking for integrators who adoptedtokenProvider: migrate toappKey. - Removed
serverSecretfromUTDLiveRoomandUTDRoomController.initApi(deprecated in 1.2.0). Shipping the project secret in an app let anyone extract it and mint tokens for any identity/room. Breaking:appKeyis now the only credential and is required onUTDLiveRoom. The legacyX-App-Secretheader path is gone (UTDApiClientno longer takesappSecret). - A leaked
app_keycannot forge bearers offline or call the server-to-server API, and rotates independently via the engineregenerate-credentialsadmin endpoint.
1.2.0 #
- Secure credential mode: new
tokenProvidercallback mints tokens via the integrator's own backend (which holds the project secret and authenticates the real user) instead of embeddingserverSecretin the app. The kit never sees the secret; the returned per-useruser_tokenbecomes theAuthorization: Bearerfor all in-room/moderation REST calls. - Deprecate
serverSecretonUTDLiveRoomandUTDRoomController.initApi(now optional). Shipping it in an app lets anyone extract it and mint tokens for any identity/room. Existing callers keep working in legacy/dual mode. - Add the
UTDTokenRequest,UTDTokenBundle, andUTDTokenProvidertypes (exported viatoken_provider.dart);UTDTokenResponsegainsuserToken. - The secure-mode per-user bearer is persisted on the controller and re-applied whenever the API clients are rebuilt (e.g. restore-from-minimize re-inits without re-minting a token), so in-room/moderation calls stay authenticated.
generateTokenvalidates thetokenProviderbundle and throwsUTDTokenExceptionon an empty token/url instead of failing later in connect.
1.1.0 #
- Single-active-session enforcement: send a stable per-install
device_id(persisted viashared_preferences, auto-resolved ingenerateToken) and handle the_kicked(signed_in_elsewhere) data event through the existing exit funnel with a distinct "signed in on another device" notice and dialog. - Add
UTDRateLimitedExceptionfor429responses from the token endpoint. - Split the API into separate token (
udt-stream.com) and engine (engine.udt-stream.com, grey-cloud) clients; configure via the newengineBaseUrlparameter oninitApi. - Security: stop mirroring user attributes into participant metadata (server-owned, spoofing vector); chat text/sender name are treated as untrusted and rendered plain-text only.
1.0.0 #
- Initial standalone release. Extracted from the Tempo-Live monorepo into its own package repository.
- LiveKit-based video live room (host camera + up to 3 guest video tiles) built
on the same seat state machine as
utd_audio_room_kit. - Camera tiles, invite / request-to-go-live, host force-control of guest media, real-time chat over the data channel, tiered reconnection, and minimize / Android OS Picture-in-Picture.
- Pairs with
utd_video_effects_kitviaUTDLiveRoomConfig.buildVideoProcessor(a LiveKitTrackProcessor) for real-time filters / beauty effects.