LiveListStore and LiveSeatStore.Core Concept | Type | Core Responsibilities & Description |
LiveListStore | class | createLive(): Start live stream as host.endLive(): End live stream as host.joinLive(): Audience joins live room.leaveLive(): Leave live room. |
LiveInfo | struct | liveID: Unique room identifier.seatLayoutTemplateID: Layout template ID (e.g., 600 for dynamic grid). |
LiveSeatStore | class | Core seat management class. Manages all seat information and seat-related operations in the room. Provides a real-time seat list data stream via liveSeatState.seatList. |
LiveSeatState | struct | Represents the current state of all seats. seatList: a StateFlow containing the real-time seat list.speakingUsers: users currently speaking and their volume. |
SeatInfo | class | Data model for a single seat. The seat list (seatList) emitted by LiveSeatStore is a list of SeatInfo objects. Key fields: index: seat position.isLocked: whether the seat is locked.userInfo: user information for the seat. If the seat is empty, this field is empty. |
SeatUserInfo | class | Detailed data model for the user occupying a seat. When a user successfully takes a seat, the userInfo field in SeatInfo is populated. Key fields: userID: unique user ID.userName: user nickname.avatarURL: user avatar URL.microphoneStatus: microphone status (on/off).cameraStatus: camera status (on/off). |
SDKAppID: Application identifier (required). Tencent Cloud uses SDKAppID for billing and details.SDKSecretKey: Application secret key, used to initialize the configuration file with secret information.
pod 'AtomicXCore' to your Podfile, then run pod install.target 'xxxx' dopod 'AtomicXCore'end
Info.plist file.<key>NSMicrophoneUsageDescription</key><string>TUILiveKit needs microphone permission to enable sound in recorded videos</string>

LoginStore.shared.login in your project to complete authentication. This is required before using any functionality of AtomicXCore.import AtomicXCore// AppDelegate.swiftfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {LoginStore.shared.login(sdkAppID: 1400000001, // Replace with your SDKAppIDuserID: "test_001", // Replace with your UserIDuserSig: "xxxxxxxxxxx") { result in // Replace with your UserSigswitch result {case .success(let info):debugPrint("login success")case .failure(let error):debugPrint("login failed code:\\(error.code), message:\\(error.message)")}}return true}
Parameter | Type | Description |
sdkAppID | Int | |
userID | String | The unique ID for the current user. Must contain only English letters, numbers, hyphens, and underscores. |
userSig | String | A ticket for Tencent Cloud authentication. Please note: Development Environment: You can use the local GenerateTestUserSig.genTestSig function to generate a UserSig or generate a temporary UserSig via the UserSig Generation Tool.Production Environment: To prevent key leakage, you must use a server-side method to generate UserSig. For details, see Generating UserSig on the Server. For more information, see How to Calculate and Use UserSig. |
ViewController, instantiate LiveSeatStore. Use the Combine framework to observe changes in liveSeatStore.state for real-time seat updates and UI rendering.import UIKitimport AtomicXCoreimport Combineclass YourAnchorViewController: UIViewController {private let liveListStore = LiveListStore.sharedprivate let deviceStore = DeviceStore.shared// Initialize LiveSeatStore with liveIDprivate let liveID = "test_voice_room_001"private lazy var liveSeatStore = LiveSeatStore.create(liveID: liveID)// Manage subscription lifecycleprivate var cancellables = Set<AnyCancellable>()override func viewDidLoad() {super.viewDidLoad()// Initialize your layout here// setupUI()// Listen for seat list changesobserveSeatList()}private func observeSeatList() {// Subscribe to seat list updates and refresh seat UIliveSeatStore.state.subscribe(StatePublisherSelector(keyPath: \\LiveSeatState.seatList)).removeDuplicates().receive(on: DispatchQueue.main).sink { [weak self] seatInfoList in// Update seat UI with seatInfoList// Example: self?.updateMicSeatView(seatInfoList)print("Seat list updated: \\(seatInfoList.count) seats")}.store(in: &cancellables)}}
openLocalMicrophone from DeviceStore:import UIKitimport AtomicXCoreclass YourAnchorViewController: UIViewController {// ... other code ...private func openDevices() {DeviceStore.shared.openLocalMicrophone(completion: nil)}}
createLive on LiveListStore:import UIKitimport AtomicXCoreclass YourAnchorViewController: UIViewController {// ... other code ...private let liveID = "test_voice_room_001"override func viewDidLoad() {super.viewDidLoad()// ... other code ...// Start voice chatstartLive()}private func startLive() {var liveInfo = LiveInfo()liveInfo.liveID = liveIDliveInfo.liveName = "test voice chat room"liveInfo.isSeatEnabled = trueliveInfo.keepOwnerOnSeat = trueliveInfo.seatLayoutTemplateID = 70 // Use correct ID per product specliveInfo.seatMode = .applyliveInfo.maxSeatCount = 10liveListStore.createLive(liveInfo) { [weak self] result inguard let self = self else { return }switch result {case .success(let liveInfo):print("Response startLive onSuccess")// Host is on seat by default; unmute microphone if neededliveSeatStore.unmuteMicrophone(completion: nil)case .failure(let errorInfo):print("Response startLive onError: \\(errorInfo.message)")}}}}
Parameter Name | Type | Required | Description |
liveID | String | Required | Unique identifier for the live room |
liveName | String | Optional | Room title |
notice | String | Optional | Room announcement |
isMessageDisable | Bool | Optional | Mute chat ( true: muted, false: not muted) |
isPublicVisible | Bool | Optional | Public visibility ( true: visible, false: not visible) |
isSeatEnabled | Bool | Optional | Enable seat feature ( true: enabled, false: disabled) |
keepOwnerOnSeat | Bool | Optional | Keep host on seat |
maxSeatCount | Int | Required | Maximum number of seats |
seatMode | TakeSeatMode | Optional | Seat mode ( .free: free seat, .apply: apply for seat) |
seatLayoutTemplateID | UInt | Required | Seat layout template ID |
coverURL | String | Optional | Room cover image URL |
backgroundURL | String | Optional | Room background image URL |
categoryList | [NSNumber] | Optional | Room category tags |
activityStatus | Int | Optional | Live activity status |
isGiftEnabled | Bool | Optional | Enable gift feature ( true: enabled, false: disabled) |
LiveSeatStore instance to subscribe to state.seatList and update the UI in real time:import UIKitimport AtomicXCoreimport Combineclass YourAnchorViewController: UIViewController {// ... other code ...private var cancellables = Set<AnyCancellable>()private lazy var liveSeatStore = LiveSeatStore.create(liveID: "your_live_id")override func viewDidLoad() {super.viewDidLoad()// ... other code ...observeSeatList()}private func observeSeatList() {liveSeatStore.state.subscribe(StatePublisherSelector(keyPath: \\LiveSeatState.seatList)).removeDuplicates().receive(on: DispatchQueue.main).sink { [weak self] seatInfoList in// seatInfoList contains the latest seat dataprint("Seat list updated: \\(seatInfoList.count) seats")}.store(in: &cancellables)}}
endLive on LiveListStore. The SDK will handle stream termination and room cleanup.import UIKitimport AtomicXCoreimport RTCRoomEngineclass YourAnchorViewController: UIViewController {// ... other code ...private func stopLive() {liveListStore.endLive { result inswitch result {case .success(let data):print("endLive success")case .failure(let errorInfo):print("endLive error: \\(errorInfo.message)")}}}}
ViewController, instantiate LiveSeatStore and subscribe to state.seatList for seat UI updates.import UIKitimport AtomicXCoreimport Combineclass YourAudienceViewController: UIViewController {private let liveListStore = LiveListStore.shared// Use the same liveID as the hostprivate let liveID = "test_voice_room_001"private lazy var liveSeatStore = LiveSeatStore.create(liveID: liveID)private var cancellables = Set<AnyCancellable>()override func viewDidLoad() {super.viewDidLoad()// Initialize your layout here// setupUI()observeSeatList()}private func observeSeatList() {liveSeatStore.state.subscribe(StatePublisherSelector(keyPath: \\LiveSeatState.seatList)).removeDuplicates().receive(on: DispatchQueue.main).sink { [weak self] seatInfoList in// Update seat UI with seatInfoList// Example: self?.updateMicSeatView(seatInfoList)print("AudienceVC Seat list updated: \\(seatInfoList.count) seats")}.store(in: &cancellables)}}
joinLive on LiveListStore:import UIKitimport AtomicXCoreclass YourAudienceViewController: UIViewController {// ... other code ...override func viewDidLoad() {super.viewDidLoad()// ... other code ...joinLive()}private func joinLive() {liveListStore.joinLive(liveID: liveID) { result inDispatchQueue.main.async {switch result {case .success(let liveInfo):print("joinLive success")case .failure(let errorInfo):print("joinLive error: \\(errorInfo.message)")}}}}}
leaveLive on LiveListStore:import UIKitimport AtomicXCoreclass YourAudienceViewController: UIViewController {// ... other code ...private func leaveLive() {liveListStore.leaveLive { result inswitch result {case .success:print("leaveLive success")case .failure(let errorInfo):print("leaveLive error: \\(errorInfo.message)")}}}}

LiveSeatStore provides a speakingUsers stream for this purpose.
YourAnchorViewController or YourAudienceViewController, subscribe to speakingUsers and update the UI accordingly:import UIKitimport AtomicXCoreimport Combineclass YourAnchorViewController: UIViewController {// ... (other code omitted) ...private var cancellables = Set<AnyCancellable>()override func viewDidLoad() {super.viewDidLoad()// ... (other code omitted) ...observeSpeakingUsersState()}private func observeSpeakingUsersState() {liveSeatStore.state.subscribe(StatePublisherSelector(keyPath: \\LiveSeatState.speakingUsers)).removeDuplicates().receive(on: DispatchQueue.main).sink { [weak self] speakingUserMap in// Update UI to indicate which users are speakingprint("Speaking users updated: \\(speakingUserMap.count) users")}.store(in: &cancellables)}}
metaData feature of LiveListStore to achieve this.updateLiveMetaData API. AtomicXCore will synchronize these changes in real time to all audience members.LiveListState.currentLive and listen for changes in metaData. When a relevant key is updated, parse its value and update your business state.import AtomicXCoreimport Combine// 1. Define a background music model (recommended: Codable)struct MusicModel: Codable {let musicId: Stringlet musicName: String}// 2. Host side: Push background music infofunc updateBackgroundMusic(music: MusicModel) {guard let jsonData = try? JSONEncoder().encode(music),let jsonString = String(data: jsonData, encoding: .utf8) else { return }let metaData = ["music_info": jsonString]LiveListStore.shared.updateLiveMetaData(metaData) { result inif case .success = result {print("Background music \\(music.musicName) pushed successfully")} else if case .failure(let error) = result {print("Background music push failed: \\(error.message)")}}}// 3. Audience side: Subscribe and update business logicprivate func subscribeToDataUpdates() {LiveListStore.shared.state// Listen for metaData changes in the current room.subscribe(StatePublisherSelector(keyPath: \\LiveListState.currentLive)).map { $0.metaData["music_info"] }.removeDuplicates().receive(on: DispatchQueue.main).sink { jsonString inguard let jsonString = jsonString,let data = jsonString.data(using: .utf8),let music = try? JSONDecoder().decode(MusicModel.self, from: data) else {return}// Update business state, play new music// ... (e.g.: playMusic(music))}.store(in: &cancellables)}
Feature | Description | Store | Implementation Guide |
Audience Take Seat | Audience members can apply to take a seat and interact with the host in real time. | ||
Host Cross-Room PK | Hosts from different rooms can connect for interaction or PK. | ||
Add Barrage Chat | Room members can send and receive real-time text messages. | ||
Gift System | Audience can send virtual gifts to hosts to increase interaction and engagement. |
Store/Component | Description | API Docs |
LiveListStore | Manages the full live room lifecycle: create, join, leave, destroy room; query room list; modify room info; listen for room status changes. | |
LiveSeatStore | Seat management: handle seat list, user status, seat operations (take seat, leave seat, kick, lock, toggle mic/camera), and seat events. | |
DeviceStore | Audio/video device control: microphone, camera, screen sharing, device status monitoring. | |
CoGuestStore | Audience co-host management: application, invitation, acceptance, rejection, member permissions, status sync. | |
CoHostStore | Host cross-room connection: supports multiple layouts, initiate/accept/reject connection, manage co-host interaction. | |
BattleStore | Host PK battle: initiate PK, manage PK status, synchronize scores, listen for battle results. | |
GiftStore | Gift interaction: fetch gift list, send/receive gifts, listen for gift events. | |
BarrageStore | Barrage (chat overlay): send text/custom barrage, maintain barrage list, monitor barrage status. | |
LikeStore | Like interaction: send likes, listen for like events, synchronize like count. | |
LiveAudienceStore | Audience management: get real-time audience list, count, entry/exit events. | |
AudioEffectStore | Audio effects: voice change, reverb, in-ear monitoring, effect switching. | |
BaseBeautyStore | Basic beauty: adjust smoothing/whitening/redness (0-100), reset beauty status, synchronize effect parameters. |
NSMicrophoneUsageDescription) in Info.plist.DeviceStore.shared.openLocalMicrophone(completion: nil).LiveSeatStore instance (LiveSeatStore.create(liveID: liveID)) with the same liveID before calling createLive or joinLive.liveSeatStore.state.seatList, and the cancellables lifecycle matches your ViewController.createLive (host) or joinLive (audience) was called successfully (check the .success branch in switch result).Feedback