LiveAudienceStore is a module in AtomicXCore designed for managing audience information in live streaming rooms. With LiveAudienceStore, you can implement a comprehensive audience list and management system for your live streaming application.
Core Concept | Type | Core Responsibilities & Description |
LiveUserInfo | class | Data model representing a viewer. Contains basic profile information such as userID, userName, and avatarURL. |
LiveAudienceState | struct | State container for the audience module. Exposes audienceList (StateFlow) for the real-time user list and audienceCount for the total viewer count. |
LiveAudienceEvent | enum | Event listener for audience changes. Provides callbacks like .onAudienceJoined and .onAudienceLeft to handle incremental list updates. |
LiveAudienceStore | class | Primary interface for audience management. Used to fetch list snapshots, perform admin operations (e.g., kicking users), and subscribe to real-time events. |
LiveAudienceStore instance linked to the liveId and fetch the initial audience snapshot. import Foundationimport AtomicXCoreimport Combineclass AudienceManager {private let liveId: Stringprivate let audienceStore: LiveAudienceStoreprivate var cancellables = Set<AnyCancellable>()// Expose the [full] audience list publisher for UI layer subscriptionlet audienceListPublisher = CurrentValueSubject<[LiveUserInfo], Never>([])// Expose the audience count publisherlet audienceCountPublisher = PassthroughSubject<UInt, Never>()init(liveId: String) {self.liveId = liveId// 1. Get the LiveAudienceStore instance by liveIdself.audienceStore = LiveAudienceStore.create(liveID: liveId)// 2. Subscribe to state and eventssubscribeToAudienceState()subscribeToAudienceEvents()// 3. Proactively fetch initial data for the first screenfetchInitialAudienceList()}/// Proactively fetch a snapshot of the audience listfunc fetchInitialAudienceList() {audienceStore.fetchAudienceList { [weak self] result inswitch result {case .success:print("Successfully fetched the audience list for the first time")// On success, data will be automatically updated via the state subscription channel belowcase .failure(let error):print("Failed to fetch the audience list for the first time: \\(error.localizedDescription)")}}}// ... subsequent code}
audienceStore state and listen for events to receive list snapshots and real-time join/leave updatesextension AudienceManager {/// Subscribe to state to get audience count and list snapshotprivate func subscribeToAudienceState() {audienceStore.state.subscribe().receive(on: DispatchQueue.main).sink { [weak self] state in// state.audienceList is a full snapshotself?.audienceListPublisher.send(state.audienceList)// state.audienceCount is the real-time totalself?.audienceCountPublisher.send(state.audienceCount)}.store(in: &cancellables)}/// Subscribe to events to handle real-time audience join/leaveprivate func subscribeToAudienceEvents() {audienceStore.liveAudienceEventPublisher.receive(on: DispatchQueue.main).sink { [weak self] event inguard let self = self else { return }var currentList = self.audienceListPublisher.valueswitch event {case .onAudienceJoined(let newAudience):print("Audience \\(newAudience.userName) joined the live room")// Incremental update: add the new audience member to the end of the current listif !currentList.contains(where: { $0.userID == newAudience.userID }) {currentList.append(newAudience)self.audienceListPublisher.send(currentList)}case .onAudienceLeft(let departedAudience):print("Audience \\(departedAudience.userName) left the live room")// Incremental update: remove the departed audience member from the current listcurrentList.removeAll { $0.userID == departedAudience.userID }self.audienceListPublisher.send(currentList)}}.store(in: &cancellables)}}
kickUserOutOfRoom API to remove a specified user from the live room.extension AudienceManager {func kick(userId: String) {audienceStore.kickUserOutOfRoom(userID: userId) { result inswitch result {case .success:print("Successfully kicked user \\(userId) out of the room")// After a successful kick, you will receive an onAudienceLeft eventcase .failure(let error):print("Failed to kick user \\(userId) out: \\(error.localizedDescription)")}}}}
setAdministrator and revokeAdministrator APIs to grant or revoke administrator privileges for a user.extension AudienceManager {/// Promote user to administratorfunc promoteToAdmin(userId: String) {audienceStore.setAdministrator(userID: userId) { result inif case .success = result {print("Successfully promoted user \\(userId) to administrator")}}}/// Revoke user's administrator statusfunc revokeAdmin(userId: String) {audienceStore.revokeAdministrator(userID: userId) { result inif case .success = result {print("Successfully revoked administrator status for user \\(userId)")}}}}
"Welcome [User Nickname] to the live room".LiveAudienceEvent.onAudienceJoined callback in LiveAudienceStore to receive real-time notifications when a new user enters.appendLocalTip API in BarrageStore to insert the system message locally.import Foundationimport AtomicXCoreimport Combineclass LiveRoomManager {private let liveId: Stringprivate let audienceManager: AudienceManagerprivate let barrageManager: BarrageManager // Assume you have implemented BarrageManager as described in the barrage documentationprivate var cancellables = Set<AnyCancellable>()init(liveId: String) {self.liveId = liveId// Initialize two core managersself.audienceManager = AudienceManager(liveId: liveId)self.barrageManager = BarrageManager(liveId: liveId)// Set up linkagesetupWelcomeMessageFlow()}private func setupWelcomeMessageFlow() {// 1. Get the LiveAudienceStore instancelet audienceStore = LiveAudienceStore.create(liveID: self.liveId)// 2. Get the BarrageStore instance (thanks to internal mechanisms, this will be the same instance)let barrageStore = BarrageStore.create(liveID: self.liveId)// 3. Subscribe to audience eventsaudienceStore.liveAudienceEventPublisher.receive(on: DispatchQueue.main).sink { event in// 4. Only handle audience join eventsguard case .onAudienceJoined(let newAudience) = event else {return}// 5. Create a local tip messagevar welcomeTip = Barrage()welcomeTip.messageType = .textwelcomeTip.textContent = "Welcome \\(newAudience.userName) to the live room!"// 6. Call BarrageStore's API to insert it into the barrage listbarrageStore.appendLocalTip(message: welcomeTip)}.store(in: &cancellables)}}
Store/Component | Feature Description | API Documentation |
LiveCoreView | Core view component for live video stream display and interaction: responsible for video stream rendering and view widget handling, supporting scenarios such as host streaming, audience co-hosting, and host-to-host connection. | |
LiveAudienceStore | Audience management: obtain real-time audience list (ID / name / avatar), count audience numbers, and listen for audience join/leave events. | |
BarrageStore | Barrage feature: send text/custom barrage, maintain barrage list, and listen to barrage status in real time. |
audienceCount is a high-precision estimate. Updates occur based on specific triggers and are subject to system frequency controls:LiveAudienceState.audienceCount as a metric for UI display purposes only. Do not rely on it for billing, critical statistics, or scenarios requiring 100% accuracy, as brief delays or data loss may occur during high-concurrency events.Feedback