Back to Developers

< Flutter UIKit />

UTD Audio Room Kit

Drop-in live audio rooms with seats, real-time chat, and moderation.

Version 1.5.0On pub.dev
iOS 11+Android 21+
audio_room_kit.dart
import 'package:utd_audio_room_kit/utd_audio_room_kit.dart';

UTDAudioRoom(
  appId: '<utd-app-id>',
  appKey: '<utd-app-key>',
  userId: 'user123',
  userName: 'John Doe',
  roomId: 'room456',
  roomOwnerId: 'owner789',
);

Drop-in

Full UI

0

Backend servers

EN · AR

Built-in i18n

PiP

+ minimize

< utd_audio_room_kit />

Key features

A complete, customizable Flutter package for live audio-room experiences powered by LiveKit and the UTD Stream Engine. Drop-in room UI with seat management, speak requests, member lists, real-time chat, media controls, minimize/PiP, and full host/admin moderation — with no backend token server required.

Drop-in audio room UI — no extra code

Seat management: take, leave, switch, lock, unlock, kick, mute, swap

Speak-request queue with approve/reject

Member list with host/admin actions (mute, kick, invite, ban, promote/demote)

Real-time data-channel chat with batching and dedup

Mic and speaker controls with Bluetooth-preferring routing

Tiered reconnection (light sync <15s, full sync <60s)

Minimize to floating overlay and Android OS Picture-in-Picture

Theme customization and built-in i18n (EN/AR)

Full section replacement (header, messages, controls, background, seats)

No backend token server — appKey-based token flow

< utd_audio_room_kit />

Get started

1

Install

Terminal
flutter pub add utd_audio_room_kit
2

View on pub.dev

Drop-in live audio rooms with seats, real-time chat, and moderation.

< utd_audio_room_kit />

API reference

Main widget

The drop-in prebuilt audio-room widget that hosts the full UI and connection lifecycle.

UTDAudioRoomwidget
const UTDAudioRoom({required String appId, required String appKey, required String userId, required String userName, required String roomId, required String roomOwnerId, Set<String> adminIds, UTDAudioRoomConfig config, List<UTDRoomMode> modes, UTDRoomController? controller, ...})

Prebuilt audio-room widget. Mints a token directly from the engine with the publishable appKey (no backend), connects to LiveKit, and renders seats, chat and controls. Self-upgrades admins post-join.

Parameters

  • appIdStringrequired

    UTD Stream Engine app ID.

  • appKeyStringrequired

    Publishable app key (no backend); used to mint tokens via X-App-Key. The server secret never ships.

  • userIdStringrequired

    Local user identity.

  • userNameStringrequired

    Local user display name.

  • roomIdStringrequired

    Room name to join.

  • roomOwnerIdStringrequired

    Identity of the room owner; the owner joins as host.

  • adminIdsSet<String>Default = const {}

    Identities the app treats as admins at join.

  • adminIdsResolverFuture<Set<String>> Function()?Default = null

    Async admin-list source; triggers a non-blocking self-upgrade if it lists the local user.

  • adminIdsNowSet<String> Function()?Default = null

    Sync admin-list probe used at token time without waiting.

  • layoutModeStringDefault = '3'

    Room mode id selecting the seat layout / seat count.

  • configUTDAudioRoomConfigDefault = const UTDAudioRoomConfig()

    Behavior, theming and custom-widget configuration.

  • modesList<UTDRoomMode>Default = const []

    Custom room modes registered on the controller.

  • controllerUTDRoomController?Default = null

    Optional externally-owned controller (e.g. when restoring from minimize).

  • onControllerReadyvoid Function(UTDRoomController)?Default = null

    Called once the controller is created/attached.

  • onConnectionChangedvoid Function(bool isConnected)?Default = null

    Fired on connect success/failure.

  • onSeatTapvoid Function(int index, SeatState seat)?Default = null

    Called when a seat is tapped.

  • onSeatChangedvoid Function(List<SeatState> seats)?Default = null

    Called whenever seat state changes.

  • onConnectErrorvoid Function(Object error, StackTrace)?Default = null

    Called when the initial connect fails.

Room controller

Top-level controller owning connection, sub-controllers, roles, bans and speaker flows.

UTDRoomControllerconstructor
UTDRoomController()

Creates the controller and its seat, media, chat, minimize and PiP sub-controllers. Usually created internally by UTDAudioRoom.

initApimethod
void initApi({String baseUrl, String tokenBaseUrl, String? appId, required String appKey})

Initializes the engine and token API clients. Must be called before connect/generateToken. Token issuance and in-room ops use different hosts.

Parameters

  • baseUrlStringDefault = UTDApiClient.defaultBaseUrl

    In-room engine host for seat/speaker/ban/role calls.

  • tokenBaseUrlStringDefault = UTDApiClient.defaultTokenBaseUrl

    Edge host used for token generation.

  • appIdString?Default = null

    Engine app ID.

  • appKeyStringrequired

    Publishable app key sent as X-App-Key for minting.

connectmethodasync
Future<void> connect({required String url, required String token, int seatCount = 9, bool enableMicOnJoin = false, bool useSpeaker = true, Map<String,String> userAttributes, String? roomName})

Connects to the LiveKit room with the given url/token, initializes seats, wires data/role/ban/chat-lock handlers, and optionally enables the mic and speaker.

Parameters

  • urlStringrequired

    LiveKit server URL.

  • tokenStringrequired

    LiveKit access token.

  • seatCountintDefault = 9

    Number of seats to initialize.

  • enableMicOnJoinboolDefault = false

    Publish the local mic on connect.

  • useSpeakerboolDefault = true

    Prefer Bluetooth/loudspeaker output on join.

  • userAttributesMap<String,String>Default = const {}

    Cosmetic LiveKit participant attributes (avatar/frame/etc.).

  • roomNameString?Default = null

    Room name used for seat API calls.

Returns: Future<void>

generateTokenmethodasync
Future<UTDTokenResponse> generateToken({required String identity, required String roomName, required String roomOwnerId, String role = 'audience', String? name, int? seatCount, String? seatMode, int? hostSeat, String? modeId, ...})

Requests a LiveKit token from the engine and applies the returned per-user bearer to the in-room clients. Throws UTDBannedException on a 403 banned response.

Parameters

  • identityStringrequired

    User identity.

  • roomNameStringrequired

    Room name.

  • roomOwnerIdStringrequired

    Room owner identity.

  • typeStringDefault = 'audio_room'

    Room type.

  • roleStringDefault = 'audience'

    Requested role (host/admin/audience).

  • nameString?Default = null

    Display name.

  • seatCountint?Default = null

    Initial seat count (host only).

  • modeIdString?Default = null

    Room mode id (host only).

Returns: Future<UTDTokenResponse>

leavemethodasync
Future<void> leave()

Leaves the room: tears down listeners, drains any pending mic publish, disconnects LiveKit, and resets minimize/PiP state.

Returns: Future<void>

changeRolemethodasync
Future<UTDRoleChangeResult> changeRole({required String targetIdentity, required String role})

Changes a participant's role (owner-only; server returns 403 otherwise). Optimistically caches the result; throws on REST error.

Parameters

  • targetIdentityStringrequired

    Identity whose role changes.

  • roleStringrequired

    New role (host/admin/guest/audience).

Returns: Future<UTDRoleChangeResult>

banUsermethodasync
Future<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 and durationSeconds null for permanent. Returns true on success.

Parameters

  • identityStringrequired

    User to ban.

  • reasonString?Default = null

    Optional ban reason.

  • durationSecondsint?Default = null

    Ban duration; null = permanent.

  • globalboolDefault = false

    True for a project-wide ban.

Returns: Future<bool>

lockCommentsmethodasync
Future<bool> lockComments()

Locks room chat so only host/admin may send (host/admin-only). State is confirmed by the server broadcast, not set optimistically.

Returns: Future<bool>

requestToSpeakmethodasync
Future<Map<String,dynamic>?> requestToSpeak()

Audience requests to speak (request mode). Returns the API result map, or null on error / when not ready.

Returns: Future<Map<String,dynamic>?>

inviteToSpeakmethodasync
Future<Map<String,dynamic>?> inviteToSpeak(String targetIdentity, {int? seatIndex})

Host/admin invites a user to speak, optionally targeting a specific seat. Returns the API result map or null.

Parameters

  • targetIdentityStringrequired

    Identity to invite.

  • seatIndexint?Default = null

    Target seat the invitee is seated on if accepted.

Returns: Future<Map<String,dynamic>?>

isConnectedgetter
bool get isConnected

True when the room connection state is connected.

Returns: bool

isHostOrAdmingetter
bool get isHostOrAdmin

Whether the local participant's role is host or admin.

Returns: bool

participantsStreamgetterasync
Stream<List<UTDParticipant>> get participantsStream

Stream of all room participants, emitting on join/leave/attribute/metadata changes.

Returns: Stream<List<UTDParticipant>>

roleChangeStreamgetterasync
Stream<UTDRoleChangeEvent> get roleChangeStream

Stream of role changes for all participants (promotions, demotions, engine auto-corrections).

Returns: Stream<UTDRoleChangeEvent>

activeSpeakersproperty
final ValueNotifier<Set<String>> activeSpeakers

Reactive set of identities currently speaking, polled from LiveKit every 300ms.

Returns: ValueNotifier<Set<String>>

commentsLockedproperty
final ValueNotifier<bool> commentsLocked

Reactive whether room chat is currently locked (server-driven; never set optimistically).

Returns: ValueNotifier<bool>

onBannedcallback
void Function(UTDBanNotice notice)? onBanned

Fired once when the local user is banned from any source (data message, removal, or token 403). Wired internally by UTDAudioRoom.

Returns: void Function(UTDBanNotice)?

disposemethod
void dispose()

Releases all resources: timers, subscriptions, notifiers, sub-controllers and API clients.

Seat & stage control

Seat state management; all mutations go through the REST API and apply from server _seat_update messages.

UTDSeatControllerclass
UTDSeatController(UTDRoomManager roomManager)

Manages reactive seat state. Mutations call the REST API; local state updates only from _seat_update data messages or room _seats metadata.

takeSeatmethodasync
Future<bool> takeSeat(int index, String userId)

Requests microphone (and Bluetooth on Android) permissions then takes the seat at index via the API. State arrives via _seat_update.

Parameters

  • indexintrequired

    Target seat index.

  • userIdStringrequired

    Identity taking the seat.

Returns: Future<bool>

leaveSeatmethodasync
Future<bool> leaveSeat(String userId)

Leaves the user's current seat via the API.

Parameters

  • userIdStringrequired

    Identity leaving the seat.

Returns: Future<bool>

moveSeatmethodasync
Future<bool> moveSeat(String userId, int targetSeat)

Atomically moves the user to another seat via the API.

Parameters

  • userIdStringrequired

    Identity to move.

  • targetSeatintrequired

    Destination seat index.

Returns: Future<bool>

lockSeatmethodasync
Future<bool> lockSeat(int index, {required String identity})

Admin locks the seat at index (host/admin). State arrives via _seat_update.

Parameters

  • indexintrequired

    Seat to lock.

  • identityStringrequired

    Acting host/admin identity.

Returns: Future<bool>

kickFromSeatmethodasync
Future<bool> kickFromSeat(int index, {required String identity})

Removes the occupant from the seat at index (host/admin only).

Parameters

  • indexintrequired

    Seat to vacate.

  • identityStringrequired

    Acting host/admin identity.

Returns: Future<bool>

setupSeatsmethodasync
Future<bool> setupSeats({required String identity, required int seatCount, required String seatMode, String? modeId})

Changes seat configuration mid-room (count/mode/modeId) (host/admin only).

Parameters

  • identityStringrequired

    Acting host/admin identity.

  • seatCountintrequired

    New seat count.

  • seatModeStringrequired

    New seat mode ('free'/'request').

  • modeIdString?Default = null

    New room mode id.

Returns: Future<bool>

seatsproperty
final ValueNotifier<List<SeatState>> seats

Reactive list of all seat states.

Returns: ValueNotifier<List<SeatState>>

pendingRequestsproperty
final ValueNotifier<List<SpeakerRequest>> pendingRequests

Reactive list of pending speaker requests (for host/admin UI).

Returns: ValueNotifier<List<SpeakerRequest>>

getSeatIndexByUserIdmethod
int getSeatIndexByUserId(String userId)

Returns the seat index occupied by a user, or -1 if not seated.

Parameters

  • userIdStringrequired

    Identity to look up.

Returns: int

isSeatAvailablemethod
bool isSeatAvailable(int index, {String? userId})

Whether the seat at index is empty, unlocked and not reserved for someone else.

Parameters

  • indexintrequired

    Seat index to test.

  • userIdString?Default = null

    User to evaluate reservations against.

Returns: bool

Media control

Mic, camera, speaker and Bluetooth-routing controls, kept in sync with server/host-side mutes.

UTDMediaControllerclass
UTDMediaController(UTDRoomManager roomManager)

Controls mic, camera and speaker state and listens to LiveKit mute/permission events to keep reactive state authoritative.

setMicrophoneEnabledmethodasync
Future<void> setMicrophoneEnabled(bool enabled)

Enables/disables the local mic. Refuses to publish on a non-connected room to avoid the addTransceiver-on-disposed-track crash.

Parameters

  • enabledboolrequired

    Target mic state.

Returns: Future<void>

toggleMicrophonemethodasync
Future<void> toggleMicrophone()

Toggles the local microphone on/off.

Returns: Future<void>

applyBluetoothAudioRoutingmethodasync
Future<void> applyBluetoothAudioRouting()

Re-applies the Android communication audio config with forceHandleAudioRouting so Bluetooth routing works after connect/publish; iOS uses the AVAudioSession path.

Returns: Future<void>

setSpeakerOnmethodasync
Future<void> setSpeakerOn(bool on)

Routes audio to the loudspeaker (true) or earpiece (false).

Parameters

  • onboolrequired

    Speakerphone on/off.

Returns: Future<void>

muteAllRemoteAudiomethod
void muteAllRemoteAudio(bool mute)

Mutes/unmutes playback of all remote participants' audio (and enforces it on late-subscribed tracks).

Parameters

  • muteboolrequired

    Whether to mute remote audio.

isMicEnabledproperty
final ValueNotifier<bool> isMicEnabled

Reactive local mic state, kept in sync with LiveKit track mute/unmute events.

Returns: ValueNotifier<bool>

canPublishproperty
final ValueNotifier<bool> canPublish

Reactive whether the local participant may publish mic/camera; flips false on demotion.

Returns: ValueNotifier<bool>

Chat

Room chat send/receive with comment-lock gating and a bounded message buffer.

UTDChatControllerclass
UTDChatController(UTDRoomManager roomManager)

Sends and receives room chat over the data channel, enforcing the comment-lock gate and capping retained messages at 300.

sendMessagemethodasync
Future<void> sendMessage(String text, {Map<String,dynamic>? userData})

Sends a chat message (trimmed, non-empty). Refused when comments are locked and the local user is not host/admin.

Parameters

  • textStringrequired

    Message body.

  • userDataMap<String,dynamic>?Default = null

    Optional extra payload attached to the message.

Returns: Future<void>

addDisplayMessagemethod
void addDisplayMessage(UTDChatMessage message)

Appends a message to the local list without sending it (used for system lines).

Parameters

  • messageUTDChatMessagerequired

    Message to display locally.

clearMessagesmethod
void clearMessages()

Clears the local message list.

messagesproperty
final ValueNotifier<List<UTDChatMessage>> messages

Reactive list of chat messages (bounded to the most recent 300).

Returns: ValueNotifier<List<UTDChatMessage>>

Configuration & theming

Behavior config, color tokens, localized strings and minimize/PiP options.

UTDAudioRoomConfigconstructor
const UTDAudioRoomConfig({bool showControlsBar = true, bool turnOnMicrophoneWhenJoining = false, bool useSpeakerWhenJoining = true, int hostSeatIndex = 0, UTDRoomTheme theme, UTDRoomStrings? strings, bool enableMinimize = true, Widget? headerWidget, ...})

Configures room behavior, theme, strings and custom section/seat builders. Replaces the prebuilt config.

Parameters

  • showControlsBarboolDefault = true

    Show the default controls bar.

  • showSeatNamesboolDefault = true

    Show occupant names under seats.

  • enableMinimizeboolDefault = true

    Allow minimizing the room to a floating overlay.

  • turnOnMicrophoneWhenJoiningboolDefault = false

    Publish the mic on join.

  • useSpeakerWhenJoiningboolDefault = true

    Prefer speaker/Bluetooth output on join.

  • hostSeatIndexintDefault = 0

    Seat index reserved for the host.

  • themeUTDRoomThemeDefault = const UTDRoomTheme()

    Color tokens for the default UI.

  • stringsUTDRoomStrings?Default = null

    Localized strings; null = English defaults.

  • autoHostMicboolDefault = true

    Auto-enable the host's mic even if join-mic is false.

  • autoSeatHostboolDefault = true

    Auto-seat the host on hostSeatIndex if empty.

  • headerWidgetWidget?Default = null

    Custom header replacing the default.

  • seatBuilderWidget Function(SeatState, double)?Default = null

    Custom builder for a seat slot.

  • avatarBuilderWidget Function(String,double,Map<String,String>,bool,int,String)?Default = null

    Custom occupant avatar builder.

  • userInRoomAttributesMap<String,String>Default = const {}

    Cosmetic attributes published to other participants.

UTDAudioRoomConfig.hostconstructor
factory UTDAudioRoomConfig.host()

Factory preset for a host (microphone on when joining).

resolveStringsmethod
UTDRoomStrings resolveStrings()

Returns the configured strings or the English defaults.

Returns: UTDRoomStrings

UTDRoomThemeconstructor
const UTDRoomTheme({Color background, Color surface, Color onSurface, Color primary, Color danger, Color seatRingSpeaking, Color badgeHost, Color badgeAdmin, Color badgeGuest, Color sheetBackground, Color bubbleBackground, ...})

Color tokens for the built-in default UI. Every field has a dark-room default, so const UTDRoomTheme() is a complete theme.

Parameters

  • backgroundColorDefault = Color(0xFF14121C)

    Full-screen room background.

  • primaryColorDefault = Color(0xFF6C5CE7)

    Accent / call-to-action color.

  • dangerColorDefault = Color(0xFFE74C3C)

    Destructive color (leave/kick/ban).

  • seatRingSpeakingColorDefault = Color(0xFF2ECC71)

    Ring around an actively-speaking seat.

  • badgeHostColorDefault = Color(0xFFFFA726)

    Host role badge color.

  • badgeAdminColorDefault = Color(0xFF448AFF)

    Admin role badge color.

copyWithmethod
UTDRoomTheme copyWith({Color? background, Color? primary, Color? danger, ...})

Returns a copy of the theme overriding only the supplied color tokens.

Returns: UTDRoomTheme

UTDRoomStrings.enconstructor
factory UTDRoomStrings.en()

English defaults for all built-in UI labels (seat actions, requests, host panels, comment-lock, templated lines).

UTDRoomStrings.arconstructor
factory UTDRoomStrings.ar()

Arabic defaults for all built-in UI labels.

UTDMinimizeConfigconstructor
const UTDMinimizeConfig({VoidCallback? onClose, MiniOverlayBuilder? overlayBuilder, double overlayWidth = 120, double overlayHeight = 120, bool enableOSPip = false, int pipAspectWidth = 1, int pipAspectHeight = 1, ...})

Configures the minimize floating overlay and optional Android OS-level Picture-in-Picture (enableOSPip).

Parameters

  • onCloseVoidCallback?Default = null

    Called when the room is closed from the overlay.

  • overlayBuilderMiniOverlayBuilder?Default = null

    Custom floating-overlay builder.

  • enableOSPipboolDefault = false

    Enable Android 12+ system PiP in addition to the overlay.

  • pipAspectWidthintDefault = 1

    PiP aspect ratio numerator.

  • pipAspectHeightintDefault = 1

    PiP aspect ratio denominator.

Models & enums

Data models for seats, room modes, chat and connection state.

SeatStateclass
const SeatState({required int index, String? occupantUserId, bool isLocked = false, bool isMuted = false, String? reservedFor, Map<String,String> attributes})

Immutable (Equatable) state of a single seat: index, occupant, lock/mute flags, reservation and occupant attributes.

Parameters

  • indexintrequired

    Seat index (0 = host seat).

  • occupantUserIdString?Default = null

    Occupant identity; null = empty.

  • isLockedboolDefault = false

    Whether the seat is admin-locked.

  • isMutedboolDefault = false

    Whether the occupant's mic is muted.

  • reservedForString?Default = null

    Identity this seat is reserved for.

  • attributesMap<String,String>Default = const {}

    Occupant cosmetic attributes (avatar, frame, etc.).

SpeakerRequestclass
const SpeakerRequest({required int id, required String identity, String? createdAt})

A pending request to speak: id, requester identity and createdAt timestamp.

Parameters

  • idintrequired

    Request id.

  • identityStringrequired

    Requesting identity.

  • createdAtString?Default = null

    Creation timestamp.

RoomSeatStateclass
const RoomSeatState({required int count, required String mode, String? modeId, required List<SeatState> seats, required List<SpeakerRequest> requests})

Full seat snapshot from the backend _seats namespace: count, mode, modeId, seats and pending requests.

Parameters

  • countintrequired

    Seat count.

  • modeStringrequired

    Seat mode ('free'/'request').

  • modeIdString?Default = null

    Room mode id.

  • seatsList<SeatState>required

    Per-seat states.

  • requestsList<SpeakerRequest>required

    Pending speaker requests.

UTDRoomModeclass
const UTDRoomMode({required String id, required int seatCount, required List<List<int>> rows, double? seatSize, UTDSeatContainerBuilder? containerBuilder, UTDBackgroundBuilder? backgroundBuilder, String? displayName})

Defines a seat layout mode: id, seat count, row arrangement and optional custom container/background builders. Identity is its id.

Parameters

  • idStringrequired

    Unique mode id (e.g. '3').

  • seatCountintrequired

    Number of seats.

  • rowsList<List<int>>required

    Seat-index layout per row.

  • seatSizedouble?Default = null

    Explicit seat size override.

  • containerBuilderUTDSeatContainerBuilder?Default = null

    Custom seat-grid container builder.

  • backgroundBuilderUTDBackgroundBuilder?Default = null

    Mode-specific background builder.

computeSeatSizemethod
double computeSeatSize(double screenWidth)

Single source of truth for the seat slot size in logical px, scaled sub-linearly (sqrt) with screen width and clamped to 52–120.

Parameters

  • screenWidthdoublerequired

    Available screen width.

Returns: double

UTDRoomMode.defaultModefield
static const UTDRoomMode defaultMode

Built-in default mode: id '3', 9 seats in a 1-4-4 layout.

Returns: UTDRoomMode

UTDChatMessageclass
UTDChatMessage({required String senderUserId, required String senderName, required String text, required DateTime timestamp, Map<String,dynamic> userData, String? messageID})

A chat message with sender, text, timestamp, arbitrary userData and an auto-generated messageID. JSON-serializable.

Parameters

  • senderUserIdStringrequired

    Sender identity.

  • senderNameStringrequired

    Sender display name.

  • textStringrequired

    Message body.

  • timestampDateTimerequired

    Message time.

  • userDataMap<String,dynamic>Default = const {}

    Extra payload (e.g. system-line markers).

  • messageIDString?Default = null

    Message id; auto-generated when omitted.

UTDConnectionStateenum
enum UTDConnectionState { disconnected, connecting, connected, reconnecting, error }

Room connection state: disconnected, connecting, connected, reconnecting, error.

Returns: UTDConnectionState

Ready to build with UTD?

Create your account, fund your master wallet, and turn on the services you need.