CoGuestStore and LiveSeatStore.
CoGuestStore and LiveSeatStore support the following primary live streaming scenarios:applyForSeat method:import io.trtc.tuikit.atomicxcore.api.CompletionHandlerimport io.trtc.tuikit.atomicxcore.api.live.CoGuestStoreval liveId = "Room ID"val guestStore = CoGuestStore.create(liveId)// User taps "Request to Co-host"fun requestToConnect() {// timeout: request timeout, e.g., 30 secondsguestStore.applyForSeat(-1, 30, null, object : CompletionHandler {override fun onSuccess() {print("Co-hosting request sent, waiting for host to respond...")}override fun onFailure(code: Int, desc: String) {print("Failed to send request: $desc")}})}
GuestListener to handle the host’s approval or rejection:import io.trtc.tuikit.atomicxcore.api.device.DeviceStoreimport io.trtc.tuikit.atomicxcore.api.live.GuestListenerimport io.trtc.tuikit.atomicxcore.api.live.LiveUserInfo// Add listener during Activity/Fragment initializationfun subscribeGuestEvents() {val guestListener = object : GuestListener() {override fun onGuestApplicationResponded(isAccept: Boolean, hostUser: LiveUserInfo) {if (isAccept) {print("Host ${hostUser.userName} approved your request. Preparing to join mic.")// 1. Enable camera and microphoneDeviceStore.shared().openLocalCamera(true, null)DeviceStore.shared().openLocalMicrophone(null)// 2. Update UI, e.g., disable request button, show co-hosting status} else {print("Host ${hostUser.userName} rejected your request.")// Notify user of rejection}}}guestStore.addGuestListener(guestListener)}
disconnect:// User taps "Leave Mic"fun leaveSeat() {guestStore.disconnect(object : CompletionHandler {override fun onSuccess() {print("Successfully left the mic")}override fun onFailure(code: Int, desc: String) {print("Failed to leave mic: $desc")}})}
cancelApplication:// User taps "Cancel Request" while waitingfun cancelRequest() {guestStore.cancelApplication(object : CompletionHandler {override fun onSuccess() {print("Request cancelled")}override fun onFailure(code: Int, desc: String) {print("Failed to cancel request: $desc")}})}
HostListener to receive notifications when an audience member requests to join the mic:import io.trtc.tuikit.atomicxcore.api.live.CoGuestStoreimport io.trtc.tuikit.atomicxcore.api.live.HostListenerimport io.trtc.tuikit.atomicxcore.api.live.LiveUserInfoval liveId = "Room ID"val guestStore = CoGuestStore.create(liveId)// Subscribe to host eventsval hostListener = object : HostListener() {override fun onGuestApplicationReceived(guestUser: LiveUserInfo) {print("Received co-hosting request from ${guestUser.userName}")// Update UI, e.g., show notification on "Request List" button}// ... Override other needed callback methods}guestStore.addHostListener(hostListener)
applicants property in CoGuestStore’s state to update the UI in real time:import kotlinx.coroutines.CoroutineScopeimport kotlinx.coroutines.Dispatchersimport kotlinx.coroutines.launch// Subscribe to state changesfun observeApplicants() {CoroutineScope(Dispatchers.Main).launch {guestStore.coGuestState.applicants.collect { applicants ->print("Current number of applicants: ${applicants.size}")// Update "Applicant List" UI}}}
// Host taps "Approve"fun accept(userId: String) {guestStore.acceptApplication(userId,object : CompletionHandler {override fun onSuccess() {print("Approved $userId's request. They are joining the mic.")}override fun onFailure(code: Int, desc: String) {print("Failed to approve request: $desc")}})}// Host taps "Reject"fun reject(userId: String) {guestStore.rejectApplication(userId,object : CompletionHandler {override fun onSuccess() {print("Rejected $userId's request")}override fun onFailure(code: Int, desc: String) {print("Failed to reject request: $desc")}})}
inviteToSeat:// Host selects audience and sends invitationfun invite(userId: String) {// timeout: invitation timeoutguestStore.inviteToSeat(userId, -1, 30, null, object : CompletionHandler {override fun onSuccess() {print("Invitation sent to $userId, waiting for response...")}override fun onFailure(code: Int, desc: String) {print("Failed to send invitation: $desc")}})}
HostListener:// Add to hostListener implementationoverride fun onHostInvitationResponded(isAccept: Boolean, guestUser: LiveUserInfo) {if (isAccept) {print("Audience ${guestUser.userName} accepted your invitation")} else {print("Audience ${guestUser.userName} rejected your invitation")}}
GuestListener:// Add to guestListener implementationoverride fun onHostInvitationReceived(hostUser: LiveUserInfo) {print("Received co-hosting invitation from host ${hostUser.userName}")// Show dialog for user to accept or reject}
val inviterId = "Host ID who sent the invitation" // From onHostInvitationReceived// User taps "Accept"fun accept() {guestStore.acceptInvitation(inviterId, object : CompletionHandler {override fun onSuccess() {// Enable microphoneDeviceStore.shared().openLocalMicrophone(null)}override fun onFailure(code: Int, desc: String) {print("Failed to accept invitation: $desc")}})}// User taps "Reject"fun reject() {guestStore.rejectInvitation(inviterId, object : CompletionHandler {override fun onSuccess() {// ...}override fun onFailure(code: Int, desc: String) {// ...}})}
LiveSeatStore, which functions with CoGuestStore.LiveSeatStore interface.muteMicrophone(). This is a one-way request with no callback.unmuteMicrophone(completion).import io.trtc.tuikit.atomicxcore.api.live.LiveSeatStoreval seatStore = LiveSeatStore.create(liveId)seatStore.muteMicrophone() // MuteseatStore.unmuteMicrophone(null) // Unmute
Parameter | Type | Description |
completion | CompletionHandler? | Callback after operation completes. |
closeRemoteMicrophone to mute and lock a user’s microphone. The user receives the onLocalMicrophoneClosedByAdmin event in LiveSeatListener, and their "Unmute Microphone" button should be disabled.openRemoteMicrophone to unlock mic permissions. The user receives the onLocalMicrophoneOpenedByAdmin event and can unmute themselves.unmuteMicrophone() to resume audio transmission.import io.trtc.tuikit.atomicxcore.api.CompletionHandlerimport io.trtc.tuikit.atomicxcore.api.live.DeviceControlPolicyval targetUserId = "userD"// 1. Force mute and lockseatStore.closeRemoteMicrophone(targetUserId, object : CompletionHandler {override fun onSuccess() {print("$targetUserId has been muted and locked")}override fun onFailure(code: Int, desc: String) {print("Operation failed: $desc")}})// 2. Unlock mic permissions (userD remains muted)seatStore.openRemoteMicrophone(targetUserId, DeviceControlPolicy.UNLOCK_ONLY, object : CompletionHandler {override fun onSuccess() {print("Invited $targetUserId to unmute (unlocked)")}override fun onFailure(code: Int, desc: String) {print("Operation failed: $desc")}})
import io.trtc.tuikit.atomicxcore.api.live.DeviceControlPolicyimport io.trtc.tuikit.atomicxcore.api.live.LiveSeatListener// userD listens for host actionsval seatListener = object : LiveSeatListener() {override fun onLocalMicrophoneClosedByAdmin() {print("Muted by host")}override fun onLocalMicrophoneOpenedByAdmin(policy: DeviceControlPolicy) {print("Host has unlocked mute")}}seatStore.addLiveSeatEventListener(seatListener)
Parameter | Type | Description |
userID | String | The user ID of the target user. |
completion | CompletionHandler? | Callback after request completes. |
Parameter | Type | Description |
userID | String | The user ID of the target user. |
completion | CompletionHandler? | Callback after request completes. |
kickUserOutOfSeat to forcibly remove a user from a mic seat.onKickedOffSeat event in GuestListener.// Remove "userB" from mic seatval targetUserId = "userB"seatStore.kickUserOutOfSeat(targetUserId, object : CompletionHandler {override fun onSuccess() {print("$targetUserId has been removed from the mic seat")}override fun onFailure(code: Int, desc: String) {print("Failed to remove user: $desc")}})// "userB" receives the event in GuestListeneroverride fun onKickedOffSeat(seatIndex: Int, hostUser: LiveUserInfo) {// Show notification}
Parameter | Type | Description |
userID | String | The user ID of the user to remove. |
completion | CompletionHandler? | Callback after request completes. |
lockSeat to lock a mic seat at the specified index. Locked seats cannot be occupied via applyForSeat or takeSeat.unlockSeat to make the seat available again.// Lock mic seat 2seatStore.lockSeat(2, object : CompletionHandler {override fun onSuccess() {print("Mic seat 2 locked")}override fun onFailure(code: Int, desc: String) {print("Failed to lock: $desc")}})// Unlock mic seat 2seatStore.unlockSeat(2, object : CompletionHandler {override fun onSuccess() {print("Mic seat 2 unlocked")}override fun onFailure(code: Int, desc: String) {print("Failed to unlock: $desc")}})
Parameter | Type | Description |
seatIndex | Int | Index of the mic seat to lock. |
completion | CompletionHandler? | Callback after request completes. |
Parameter | Type | Description |
seatIndex | Int | Index of the mic seat to unlock. |
completion | CompletionHandler? | Callback after request completes. |
moveUserToSeat to move users between mic seats.userID, the target seat index as targetIndex, and use the policy parameter to specify the seat movement strategy if the target seat is occupied (see parameter details below).userID must be the user's own ID, targetIndex is the desired new seat index, and the policy parameter is ignored. If the target seat is occupied, the move fails with an error.import io.trtc.tuikit.atomicxcore.api.CompletionHandlerimport io.trtc.tuikit.atomicxcore.api.live.MoveSeatPolicyseatStore.moveUserToSeat("userC",newSeatIndex,MoveSeatPolicy.ABORT_WHEN_OCCUPIED,object : CompletionHandler {override fun onSuccess() {print("Successfully moved to mic seat $newSeatIndex")}override fun onFailure(code: Int, desc: String) {print("Failed to switch seat, seat may be occupied: $desc")}})
Parameter | Type | Description |
userID | String | The user ID of the user to move. |
targetIndex | Int | Target mic seat index. |
policy | MoveSeatPolicy? | Seat movement policy if the target seat is occupied:<br>- abortWhenOccupied: Abort move if seat is occupied (default)<br>- forceReplace: Force replace the user on the target seat; replaced user will be removed<br>- swapPosition: Swap positions with the user on the target seat. |
completion | CompletionHandler? | Callback after request completes. |
Store/Component | Feature Description | API Documentation |
CoGuestStore | Audience co-hosting management: co-hosting requests/invitations, approval/rejection, co-host member permission control (microphone/camera), state synchronization. | |
LiveSeatStore | Mic seat management: mute/unmute, lock/unlock mic seat, remove user from mic, remote microphone control, mic seat list state monitoring. |
Video Live Streaming: The video feed is central. Use LiveCoreView to render host and co-host video streams. The UI focuses on video layout, sizing, and overlays (such as nickname or placeholder images) via VideoViewAdapter. Both camera and microphone can be enabled.Voice Room (Audio Chat Room): The mic seat grid is central. Do not use LiveCoreView; instead, build a grid UI (e.g., RecyclerView) based on LiveSeatStore.state (especially seatList). The UI displays each mic seat’s SeatInfo—occupied, muted, locked, or speaking—in real time. Only the microphone needs to be enabled.seatList property in LiveSeatState, which is a reactive List<SeatInfo>. When the array changes, update your mic seat UI. For each seat:seatInfo.userInfo for user details.seatInfo.isLocked to check if the seat is locked.seatInfo.userInfo.microphoneStatus for the user’s microphone status.DeviceStore manages the physical microphone device, while LiveSeatStore manages mic seat business logic (audio stream).DeviceStore:openLocalMicrophone: Requests system permission and starts the microphone device for audio capture. This is a resource-intensive operation.closeLocalMicrophone: Stops audio capture and releases the microphone device.LiveSeatStore:muteMicrophone: Mutes the audio stream sent to remote users; the microphone device remains active.unmuteMicrophone: Unmutes the audio stream.openLocalMicrophone once to start the device.muteMicrophone and unmuteMicrophone to control the audio stream.disconnect), call closeLocalMicrophone to release the device.Feedback