AtomicXCore 提供了 CoGuestState 和 LiveSeatState 模块,用于管理观众连麦的完整业务流程。您无需关心复杂的状态同步和信令交互,只需调用几个简单的方法,即可为您的直播添加强大的观众与主播音视频互动功能。本文档将指导您如何使用
CoGuestState 和 LiveSeatState 在您的应用中快速实现语音连麦功能。
核心场景
CoGuestState 和 LiveSeatState 支持以下几个主流的场景:观众申请上麦:观众主动发起连麦请求,主播在收到请求后同意或拒绝。
主播邀请上麦:主播可以主动向语聊房内的任意一位观众发起连麦邀请。
主播管理麦位:主播可以对麦位上的用户进行踢人、闭麦、锁麦等操作。
实现步骤
步骤1:组件集成
步骤2:实现观众申请上麦
观众端实现
作为观众,核心任务是发起申请、接收结果和主动下麦。
1. 发起连麦申请
当用户点击界面上的“申请连麦”按钮时,调用
applyForSeat 方法。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';// 先获取要加入的语聊房 ID(liveID)。通常有以下方式:// 通过房间列表选择(可从 LiveListState 的 liveList 数据中获取)const liveID = "xxx" // 您当前加入语聊房的 liveID//通过 liveID 获取 CoGuestState 的实例const { applyForSeat } = useCoGuestState(liveID);// 用户点击“申请连麦”const handleApplyForSeat = () => {applyForSeat({liveID,seatIndex: -1, // 申请的麦位,申请上麦传 -1, 随机分配麦位timeout: 30, // 请求超时时间,例如 30s});};
2. 监听主播的处理结果
通过
addCoGuestGuestListener 订阅 onGuestApplicationResponded 事件,您可以接收到主播的处理结果。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';import { useDeviceState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/DeviceState';const { addCoGuestGuestListener } = useCoGuestState(liveID);const { openLocalMicrophone } = useDeviceState(liveID);// 页面初始化时订阅连麦申请响应事件useEffect(() => {addCoGuestGuestListener('onGuestApplicationResponded', (event) => {const res = typeof event === 'string' ? JSON.parse(event) : event;if (res.isAccept) {console.log('上麦申请被同意');// 1.打开麦克风openLocalMicrophone();// 2. 在此更新 UI,例如变更申请按钮状态,显示为连麦中} else {console.log('上麦申请被拒绝');// 弹窗提示用户申请被拒绝}});}, [liveID]);
3. 主动下麦
当连麦观众想结束互动时,调用
disconnect 方法即可返回普通观众状态。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { disconnect } = useCoGuestState(liveID);// 用户点击"下麦"按钮const handleLeaveSeat = () => {disconnect({liveID,onSuccess: () => {console.log('下麦成功');},onError: (error) => {console.log('下麦失败', error);},});};
4. (可选) 取消申请
如果观众在主播处理前想撤回申请,可以调用
cancelApplication。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { cancelApplication } = useCoGuestState(liveID);// 用户在等待时,点击"取消申请"const handleCancelRequest = () => {cancelApplication({liveID,onSuccess: () => {console.log('取消申请成功');},onError: (error) => {console.log('取消申请失败', error);},});};
主播端实现
作为主播,核心任务是接收申请、展示申请列表和处理申请。
1. 监听新的连麦申请
通过
CoGuestHostListener 订阅 onGuestApplicationReceived 事件,您在有新观众申请时立即收到通知,并给出提示。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';// 获取 CoGuestState 实例const { addCoGuestHostListener } = useCoGuestState(liveID);// 在页面初始化时订阅事件useEffect(() => {addCoGuestHostListener('onGuestApplicationReceived', (event) => {const res = JSON.parse(event);console.log('收到观众的连麦申请');// 在此更新 UI,例如在"申请列表"按钮上显示红点});}, [liveID]);
2. 展示申请列表
CoGuestState 会实时维护当前的申请者列表 applicants,数据本身是响应式数据,您可以直接在 UI 上使用。const { addCoGuestHostListener, applicants } = useCoGuestState(liveID);{/* 申请者列表 */}{applicants && applicants.length > 0 ? (<View style={styles.applicantContainer}><Text style={styles.applicantTitle}>申请列表({applicants.length})</Text>{applicants.map((audience) => (<View key={audience?.userID} style={styles.applicantItem}><Text style={styles.applicantName}>{audience.userName}</Text><Text style={styles.applicantId}>{audience.userID}</Text></View>))}</View>) : null}
3. 处理连麦申请
当您在列表中选择一位观众并点击“同意”或“拒绝”时,调用相应的方法。
import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { acceptApplication, rejectApplication } = useCoGuestState(liveID);// 主播点击"同意"按钮,传入申请者的 userIDconst handleAccept = (userID) => {acceptApplication({liveID,userID,onSuccess: () => {console.log('已同意上麦申请');},onError: (error) => {console.log('同意上麦申请失败', error);},});};// 主播点击"拒绝"按钮,传入申请者的 userIDconst handleReject = (userID) => {rejectApplication({liveID,userID,onSuccess: () => {console.log('已拒绝上麦申请');},onError: (error) => {console.log('拒绝上麦申请失败', error);},});};
步骤3:实现主播邀请上麦
主播端实现
1. 向观众发起邀请
当主播在观众列表中选择某人并点击“邀请连麦”时,调用
inviteToSeat 方法。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { inviteToSeat } = useCoGuestState(liveID);// 主播选择观众并发起邀请const handleInviteToSeat = (inviteeID) => {inviteToSeat({liveID,inviteeID,seatIndex: -1, // 邀请的麦位,传 -1, 随机分配麦位timeout: 30, // 超时时间onSuccess: () => {console.log('已向观众发送上麦邀请,请等待回应...');},onError: (error) => {console.log('向观众发送上麦邀请失败', error);},});};
2. 监听观众的回应
通过
CoGuestHostListener 订阅 onHostInvitationResponded 事件。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { addCoGuestHostListener } = useCoGuestState(liveID);// 在页面初始化时订阅事件useEffect(() => {addCoGuestHostListener('onHostInvitationResponded', (event) => {const res = JSON.parse(event);if (res.isAccept) {console.log('观众接受了您的邀请');} else {console.log('观众拒绝了您的邀请');}});}, [liveID]);
观众端实现
1. 接收主播的邀请
通过
addCoGuestGuestListener 订阅 onHostInvitationReceived 事件。import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';import { useLiveListState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveListState';const { addCoGuestGuestListener } = useCoGuestState(liveID);const { currentLive } = useLiveListState();// 页面初始化时订阅连麦申请响应事件useEffect(() => {addCoGuestGuestListener('onHostInvitationReceived', (event) => {const inviterID = currentLive?.liveOwner?.userID || '';console.log('邀请人ID:', inviterID);// 弹出对话框,让用户选择"接受"或"拒绝"});}, [liveID]);
2. 响应邀请
当用户在弹出的对话框中做出选择后,调用相应的方法。
import { useCoGuestState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoGuestState';const { acceptInvitation, rejectInvitation } = useCoGuestState(liveID);const { openLocalMicrophone } = useDeviceState(liveID);// 用户点击“接受”const handleAcceptInvitation = (inviterID) => {acceptInvitation({liveID,inviterID,onSuccess: () => {console.log('已接受上麦邀请');openLocalMicrophone(); // 可以选择在此处打开麦克风},onError: (error) => {console.log('接受上麦邀请失败', error);},});};// 用户点击“拒绝”const handleRejectInvitation = (inviterID) => {rejectInvitation({liveID,inviterID,onSuccess: () => {console.log('已拒绝上麦邀请');},onError: (error) => {console.log('拒绝上麦邀请失败', error);},});};
功能进阶
当用户上麦后,主播可能需要对麦位进行管理。以下功能主要由
LiveSeatState 提供,它可以与 CoGuestState 协同工作。麦上用户自行开/关麦
麦上用户(包括主播自己)可以通过
LiveSeatState 提供的接口来控制自己的麦克风静音状态。实现方式:
1. 静音:调用
muteMicrophone() 方法。这是一个无回调的单向请求。2. 解除静音:调用
unmuteMicrophone(onSuccess: onError:) 方法。示例代码:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';const { muteMicrophone, unmuteMicrophone } = useLiveSeatState(liveID);//静音const handleMuteMic = () => {muteMicrophone();};// 解除静音const handleUnmuteMic = () => {unmuteMicrophone({onSuccess: () => {console.log('解除静音成功');},onError: (error) => {console.log('解除静音失败', error);},});};
unmuteMicrophone 接口参数:
参数 | 类型 | 描述 |
onSuccess | Function | 解除静音的回调 |
onError | Function | 解除静音失败的回调。 |
主播远程控制麦上用户开麦或关麦
主播可以对其他麦上用户进行“强制静音”或“邀请开麦”的操作。
实现方式:
1. 强制静音(锁定):主播调用
closeRemoteMicrophone 会强制关闭对方的麦克风,并锁定对方的麦克风权限。被静音的用户会收到 'onLocalMicrophoneClosedByAdmin' 事件,此时其本地的“打开麦克风”按钮应变为不可点击状态。2. 邀请开麦(解锁):主播调用
openRemoteMicrophone 并非强制打开对方麦克风,而是解除对方的“锁定状态”,允许对方自行开麦。此时,被操作的用户会收到 onLocalMicrophoneOpenedByAdmin 事件,其本地的“打开麦克风”按钮应恢复为可点击状态,但用户仍处于静音中。3. 用户自行开麦:用户在收到“解除锁定”的通知后,必须主动调用
LiveSeatState 的 unmuteMicrophone()方法解除静音,才能让房间内其他人听到自己的声音。示例代码:
主播端:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';//通过 liveID 获取 LiveSeatState 的实例const { openRemoteMicrophone, closeRemoteMicrophone } = useLiveSeatState(liveID);const targetUserID = "userA"// 1. 强制静音 userA 并锁定const handleCloseRemoteMic = (userID) => {closeRemoteMicrophone({liveID,userID,onSuccess: () => {console.log('静音并锁定成功');},onError: (error) => {console.log('静音并锁定失败', error);},});};// 2. 解锁 userA 的麦克风权限(此时 userA 依然是静音状态)const handleOpenRemoteMic = (userID) => {openRemoteMicrophone({liveID,userID,onSuccess: () => {console.log('邀请打开麦克风成功');},onError: (error) => {console.log('邀请打开麦克风失败', error);},});};
观众端:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';//通过 liveID 获取 LiveSeatState 的实例const { addLiveSeatEventListener } = useLiveSeatState(liveID);// 监听主播的静音/解锁操作useEffect(() => {addLiveSeatEventListener('onLocalMicrophoneClosedByAdmin', () => {console.log('被主播静音了');// 可以在此进行弹框提示});addLiveSeatEventListener('onLocalMicrophoneOpenedByAdmin', () => {console.log('主播已解除静音锁定');// 可以在此进行弹框提示});}, [liveID]);
closeRemoteMicrophone 接口参数:
参数 | 类型 | 描述 |
liveID | string | 当前语聊房的 liveID。 |
userID | string | 被操作的用户 userID。 |
onSuccess | Function | 静音成功的回调。 |
onError | Function | 静音失败的回调。 |
openRemoteMicrophone 接口参数:
参数 | 类型 | 描述 |
liveID | string | 当前语聊房的 liveID。 |
userID | string | 被操作的用户 userID。 |
onSuccess | Function | 解除静音成功的回调。 |
onError | Function | 解除静音失败的回调。 |
主播将麦上用户踢下麦位
实现方式:
1. 踢人下麦:主播可以调用
kickUserOutOfSeat 方法,强制将指定用户踢下麦位。2. 监听事件通知:被踢下麦的用户会收到
onKickedOffSeat 事件通知。示例代码:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';//通过 liveID 获取 LiveSeatState 的实例const { kickUserOutOfSeat, addLiveSeatEventListener } = useLiveSeatState(liveID);// 假设要踢走 "userB"const targetUserID = "userB";// 踢人下麦const handleKickUserOutOfSeat = (userID) => {kickUserOutOfSeat({liveID: liveID,userID: userID,onSuccess: () => {console.log('踢下麦位成功');},onError: (error) => {console.log('踢人失败', error);},});};useEffect(() => {addLiveSeatEventListener('onKickedOffSeat', () => {console.log('被主播踢下麦');// 可以在此进行弹框提示});}, [liveID]);
kickUserOutOfSeat 接口参数:
参数 | 类型 | 描述 |
liveID | string | 当前语聊房的 liveID。 |
userID | String | 被踢下麦的用户 userID。 |
onSuccess | Function | 踢下麦成功的回调。 |
onError | Function | 踢下麦失败的回调。 |
主播锁定和解锁麦位
主播可以锁定或解锁某个麦位。
实现方式:
1. 锁定麦位:主播可调用
lockSeat 方法锁定指定索引的麦位,麦位被锁定后,观众无法通过 applyForSeat 或 takeSeat 占用该麦位。2. 解锁麦位:调用
unlockSeat 可以解锁麦位,解锁后该麦位可以再次被占用。示例代码:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';//通过 liveID 获取 LiveSeatState 的实例const { lockSeat, unlockSeat } = useLiveSeatState(liveID);// 锁定 2 号麦位const handleLockSeat = () => {lockSeat({liveID: liveID,seatIndex: 2,onSuccess: () => {console.log(`已将 2 号麦位锁定`);},onError: (error) => {console.log('锁定麦位失败', error);},});};// 解锁 2 号麦位const handleUnlockSeat = () => {unlockSeat({liveID: liveID,seatIndex: 2,onSuccess: () => {console.log('已将 2 号麦位解锁');},onError: (error) => {console.log('解锁麦位失败', error);},});};
lockSeat 接口参数:
参数 | 类型 | 描述 |
liveID | string | 当前语聊房的 liveID。 |
seatIndex | number | 需要锁定的麦位索引。 |
onSuccess | Function | 锁麦成功的回调。 |
onError | Function | 锁麦失败的回调。 |
unlockSeat 接口参数:
参数 | 类型 | 描述 |
liveID | string | 当前语聊房的 liveID。 |
seatIndex | number | 需要解锁的麦位索引。 |
onSuccess | Function | 解锁麦位成功的回调。 |
onError | Function | 解锁麦位失败的回调。 |
移动麦位
主播和普通上麦用户可以调用
moveUserToSeat 移动麦位。实现方式:
1. 主播移动麦位:主播可以调用此接口将任意用户移动到指定麦位。此时
userID 传入目标用户的 ID,targetIndex 是目标麦位索引,policy 参数来指定如果目标麦位有人时的移动策略,详细参见 接口参数 说明。2. 普通上麦用户移动自己麦位:普通上麦用户也可以调用此接口来移动自己。此时
userID 必须传入用户自己的 ID,targetIndex 传入想去的新麦位索引,此时 policy 参数无效,如果目标麦位有人时会报错并停止移动。示例代码:
import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';//通过 liveID 获取 LiveSeatState 的实例const { moveUserToSeat } = useLiveSeatState(liveID);const newSeatIndex = 2; // 目标麦位索引。const moveSeat = () => {moveUserToSeat({liveID: liveID,userID: "userC",targetIndex: newSeatIndex, // 目标麦位policy: 'FORCE_REPLACE',onSuccess: () => {console.log('移动麦位成功')},onError: (error) => {console.log('换座失败', error)}})}
moveUserToSeat 接口参数:
参数 | 类型 | 描述 |
userID | string | 需要移麦的用户 userID。 |
targetIndex | number | 目标麦位索引。 |
policy | string | 目标麦位有人时的移动策略枚举: ABORT_WHEN_OCCUPIED:目标麦位有人时放弃移动(默认策略)FORCE_REPLACE:强制替换目标麦位上的用户,被替换的用户将会被踢下麦SWAP_POSITION:与目标麦位用户交换位置。 |
onSuccess | Function | 移动麦位成功的回调。 |
onError | Function | 移动麦位失败的回调。 |
API 文档
关于 CoGuestState 和 LiveSeatState 及其相关类的所有公开接口、属性和方法的详细信息,请参阅 AtomicXCore 框架的官方 API 文档。本指南使用到的相关 Store 如下:
常见问题
语音房连麦和视频直播连麦的实现有何不同?
两者的主要区别在于业务形态与 UI 展现:
视频直播:核心是视频画面。您会使用
LiveCoreView 作为核心组件来渲染主播和连麦观众的视频流。UI 的重点是处理视频画面的布局、大小,以及通过 在视频流上添加挂件(例如昵称、占位图)。您可以同时打开摄像头,麦克风。语音房(语聊房):核心是麦位网格。您不会使用
LiveCoreView,而是会基于 LiveSeatState 的数据(特别是 seatList)来构建一个网格 UI 。UI 的重点是实时显示每个麦位 SeatInfo 的状态:是否有人、是否静音、是否被锁定 ,以及是否正在说话。您只需要打开麦克风。如何在 UI 上实时刷新麦位信息(例如是否有人、是否静音)?
您应该订阅
LiveSeatState 中的 seatList 属性,它是一个[SeatInfo] 数组类型的响应式数据,每当数组变化时都会通知您重新渲染麦位列表。遍历此数组,您可以:通过
seatInfo.userInfo 来获取麦位上用户信息。通过
seatInfo.isLocked 判断麦位是否被锁定。通过
seatInfo.userInfo.microphoneStatus 判断麦上用户的麦克风状态。LiveSeatState 和 DeviceState 都有麦克风接口,它们有何区别?
这是一个非常重要的问题。
DeviceState 管理的是物理设备,而 LiveSeatState 管理的是麦位业务(即音频流)。DeviceState:openLocalMicrophone:向系统请求权限并启动麦克风设备进行音频采集。这是一个“重”操作。closeLocalMicrophone:停止音频采集并释放麦克风设备。LiveSeatState:muteMicrophone:静音。停止向远端发送本地的音频流,但麦克风设备本身仍在运行。unmuteMicrophone:解除静音。恢复向远端发送音频流。推荐的工作流程:您应该遵循“设备只开一次,麦上只用静音切换”的原则
1. 上麦时:当观众成功上麦,调用一次
openLocalMicrophone 来启动设备。2. 在麦上时:用户在麦位上所有的“开麦”和“闭麦”操作,都应该调用
unmuteMicrophone 和 muteMicrophone 来控制上行音频流的通断。