AtomicXCore SDK. You'll leverage LiveListState and LiveSeatState to implement core functionality.# 1. Install the core voice chat module and native build tools (required)npx expo install react-native-tuikit-atomic-x expo-dev-client expo-build-properties# 2. Install UI adaptation and utility libraries (recommended)npx expo install react-native-safe-area-context react-native-toast-message react-native-localize
app.json and configure system permissions for voice chat (microphone, background audio):{"expo": {"name": "ExpoLive","slug": "ExpoLive",// ... other settings"ios": {// ... other settings"bundleIdentifier": "com.anonymous.ExpoLive","infoPlist": {"NSMicrophoneUsageDescription": "This app requires access to your microphone for live streaming.","UIBackgroundModes": ["audio"]}},"plugins": ["react-native-localize",["expo-build-properties",{"ios": {"useFrameworks": "static"}}]]}}
# If you have local Android and iOS development environments:npx expo run:ios // Ensure CocoaPods is installednpx expo run:android# Or use Expo's cloud build to regenerate the development install package:npx eas build --profile development --platform all
npx expo start
login method from LoginState. login in LoginState only after your app's own user authentication succeeds, keeping your login logic clear and consistent.import { useLoginState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LoginState';const { login } = useLoginState();const handleLogin = () => {login({sdkAppID: 1400000001, // Replace with your SDKAppIDuserID: "test_001", // Replace with your UserIDuserSig: "xxxxxxxxxx" // Replace with your UserSig});}
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. |
LiveSeatState. Listen for reactive data changes to obtain mic seat information and render the UI.import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';// Define the voice chat room ID (must match the liveID used in createLive)// Use a unique identifier (e.g., UUID or timestamp)// Format: Only English letters, numbers, and underscores; max 64 charactersconst liveID = 'your_live_room_id'; // Replace with your voice chat room ID// Get LiveSeatState instance with liveIDconst { seatList } = useLiveSeatState(liveID);
openLocalMicrophone from DeviceState to turn on the microphone.import { useDeviceState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/DeviceState';const { openLocalMicrophone } = useDeviceState();const openMic = () => {openLocalMicrophone();};
createLive from LiveListState to start broadcasting in the voice chat room.import { useLiveListState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveListState';// Get LiveListState instanceconst { createLive } = useLiveListState();const startLive = () => {createLive({liveInfo: {liveID: liveID, // Voice chat room IDliveName: 'test', // Room namekeepOwnerOnSeat: true, // Host remains on the mic seatisSeatEnabled: true,seatLayoutTemplateID: 70, // Mic seat layout template (70 for voice chat)seatMode: 'APPLY', // Seat mode (apply to join mic)maxSeatCount: 10 // Maximum number of mic seats},onSuccess: () => {console.log('Voice chat room created successfully');// Navigate to another page if needed},onError: (error) => {console.log('Failed to create voice chat room', error);}});};
Parameter Name | Type | Required/Optional | Description |
liveID | string | Required | Unique identifier for the voice chat room. |
liveName | string | Optional | Voice chat room title. |
notice | string | Optional | Announcement for the voice chat room. |
isMessageDisable | boolean | Optional | Mute status ( true: muted, false: not muted). |
isPublicVisible | boolean | Optional | Room visibility ( true: public, false: private). |
isSeatEnabled | boolean | Optional | Enable mic seat functionality. |
keepOwnerOnSeat | boolean | Optional | Keeps the host on the mic seat. |
maxSeatCount | number | Required | Maximum number of mic seats. |
seatMode | string | Optional | Mic seat mode ( FREE: open, APPLY: application required). |
seatLayoutTemplateID | number | Required | Mic seat layout template ID; 70 for voice chat. |
coverURL | string | Optional | Cover image URL for the room. |
backgroundURL | string | Optional | Background image URL for the room. |
activityStatus | number | Optional | Voice chat activity status. |
isGiftEnabled | boolean | Optional | Enable gift functionality. |
LiveSeatState instance to listen for changes in seatList and render mic seat UI in real time.import React, { useEffect } from 'react';import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';// Get LiveSeatState instance with liveIDconst { seatList } = useLiveSeatState(liveID);// Generate displaySeats for UIconst displaySeats = React.useMemo(() => {return Array.from({ length: 10 }, (_, i) => {const foundSeat = (seatList || []).find(seat => seat.index === i) || {};return {...foundSeat,displayIndex: i + 1, // UI display index (1-10)userId: foundSeat.userInfo?.userID || foundSeat.userId || null,};});}, [seatList]);
endLive from LiveListState to stop streaming and close the room.import { useLiveListState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveListState';const { endLive } = useLiveListState();// End voice chatconst handleEndLive = () => {endLive({onSuccess: () => {console.log('Voice chat ended successfully');// Navigate if needed},onError: (error) => {console.log('Failed to end voice chat', error);}});}
LiveSeatState and listen for seatList changes to render mic seats.import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';// Define the voice chat room ID (must match the liveID used in joinLive)const liveID = 'your_live_room_id'; // Replace with your voice chat room ID// Get LiveSeatState instance with liveIDconst { seatList } = useLiveSeatState(liveID);
joinLive from LiveListState to join the voice chat room.import { useLiveListState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveListState';// Get LiveListState instanceconst { joinLive } = useLiveListState();// Join voice chatconst handleJoinLive = () => {joinLive({liveID: liveID, // Voice chat room ID to joinonSuccess: () => {console.log('Successfully entered the voice chat room');// Navigate if needed},onError: (error) => {console.log('Failed to enter the voice chat room', error);}});};
leaveLive from LiveListState.import { useLiveListState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveListState';// Get LiveListState instanceconst { leaveLive } = useLiveListState();// Exit voice chat roomconst handleLeaveLive = () => {leaveLive({liveID: liveID, // Voice chat room ID joinedonSuccess: () => {console.log('Exited the voice chat room successfully');// Navigate if needed},onError: (error) => {console.log('Failed to exit the voice chat room', error);}});}

LiveSeatState provides the speakingUsers stream for this purpose.
speakingUsers in your mic seat UI and update the speaking status.import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';// Get LiveSeatState instance with liveIDconst { speakingUsers } = useLiveSeatState(liveID);useEffect(() => {console.log('Users currently speaking', speakingUsers);// Combine this with seatList to update UI}, [speakingUsers]);
Voice Chat Room Feature | Feature Description | Feature State | Implementation Guide |
Audience Audio Co-hosting | Audience can apply to join the mic and interact with the host in real time. | ||
Add Live Comments Chat | Audience can send and receive real-time text messages in the voice chat room. | ||
Build Gift System | Audience can send virtual gifts to the host to increase interaction and fun. | ||
Add Audio Effects Settings | Voice changer (child/masculine), reverb (KTV, etc.), ear monitoring, real-time effect switching. |
State | Feature Description | API Documentation |
LiveListState | Manage the entire lifecycle of voice chat rooms: create, join, leave, destroy, query room list, modify room info (name, announcement), listen for room status (e.g., kicked out, ended). | |
DeviceState | Audio/video device control: turn microphone on/off, adjust volume, monitor device status in real time. | |
CoGuestState | Audience co-host management: apply/invite/accept/reject, manage co-host member microphone permissions, synchronize status. | |
CoHostState | Host cross-room connection: supports multiple layout templates (dynamic grid, etc.), initiate/accept/reject connection, manage co-host interactions. | |
GiftState | Gift interaction: get gift list, send/receive gifts, listen for gift events (sender, gift details). | |
BarrageState | Live comments: send text/custom comments, maintain comment list, monitor comment status in real time. | |
LikeState | Like interaction: send likes, listen for like events, synchronize total like count. | |
LiveAudienceState | Audience management: obtain real-time audience list (ID/name/avatar), count audience numbers, listen for audience entry/exit events. | |
AudioEffectState | Audio effects: voice changer (child/masculine), reverb (KTV, etc.), ear monitoring, real-time effect switching. |
openLocalMicrophone() to enable the microphone.endLive on iOS causes an immediate app crash.expo-modules-core uses KVO to monitor video stream properties (such as size, frame rate). When the stream is destroyed, these properties revert to -1. Without boundary checks, -1 is passed to memory allocation functions. On iOS, -1 converts to an unsigned integer (UInt64/size_t), resulting in a massive allocation ($2^{64}-1$, or $18,446,744,073,709,551,615$), which triggers a system-level out-of-memory kill.피드백