CoHostState 核心模块,用于处理主播连线。本文档将指导您如何组合使用该工具,来完成直播场景下连线的完整流程。
CoHostState 来完成。requestHostConnection 方法。import { useCoHostState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoHostState';const liveID = 'xxx'; // 主播 A 的房间 ID// 通过 liveID 获取 CoHostState 的实例const { requestHostConnection } = useCoHostState(liveID);// 用户点击"连线"按钮,并选择了主播Bconst handleRequestHostConnection = (targetHostLiveID) => {requestHostConnection({liveID, // 主播 A 的房间 IDtargetHostLiveID, // 主播 B 的房间 IDlayoutTemplate: 'HOST_DYNAMIC_GRID', // 选择一个布局模版timeout: 30, // 邀请超时时间onSuccess: () => { console.log('连线邀请已发送,等待对方处理...'); },onError: (error) => { console.log('邀请发送失败', error); },});};
addCoHostListener 订阅对应的事件,您可以接收到主播 B 的处理结果。import { useEffect } from 'react';import { useCoHostState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoHostState';const liveID = 'xxx'; // 主播 A 的房间 ID// 通过 liveID 获取 CoHostState 的实例const { addCoHostListener, removeCoHostListener } = useCoHostState(liveID);useEffect(() => {const onCoHostRequestAccepted = (event) => {console.log('主播同意了您的连线邀请', event);};const onCoHostRequestRejected = (event) => {console.log('主播拒绝了您的连线邀请', event);};const onCoHostRequestTimeout = () => {console.log('邀请超时,对方未回应');};addCoHostListener('onCoHostRequestAccepted', onCoHostRequestAccepted);addCoHostListener('onCoHostRequestRejected', onCoHostRequestRejected);addCoHostListener('onCoHostRequestTimeout', onCoHostRequestTimeout);return () => {removeCoHostListener('onCoHostRequestAccepted', onCoHostRequestAccepted);removeCoHostListener('onCoHostRequestRejected', onCoHostRequestRejected);removeCoHostListener('onCoHostRequestTimeout', onCoHostRequestTimeout);};}, []);
addCoHostListener 订阅 onCoHostRequestReceived 事件,主播 B 可以监听到来自主播 A 的邀请。import { useEffect } from 'react';import { useCoHostState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoHostState';const liveID = 'xxx'; // 主播 B 的房间 ID// 通过 liveID 获取 CoHostState 的实例const { addCoHostListener, removeCoHostListener } = useCoHostState(liveID);useEffect(() => {const onCoHostRequestReceived = (event) => {const inviterData = JSON.parse(event.inviter);console.log('收到连线邀请', inviterData);// 可以在这里进行弹窗提示};addCoHostListener('onCoHostRequestReceived', onCoHostRequestReceived);return () => {removeCoHostListener('onCoHostRequestReceived', onCoHostRequestReceived);};}, []);
import { useCoHostState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/CoHostState';const liveID = 'xxx'; // 主播 B 的房间 ID// 通过 liveID 获取 CoHostState 的实例const { acceptHostConnection, rejectHostConnection } = useCoHostState(liveID);// 主播 B 接受连线邀请const handleAcceptHostConnection = (fromHostLiveID) => {acceptHostConnection({liveID,fromHostLiveID, // 从 onCoHostRequestReceived 事件中获取该数据onSuccess: () => { console.log('已接受连线邀请'); },onError: (error) => { console.log('接受连线失败', error); },});};// 主播 B 拒绝连线邀请const handleRejectHostConnection = (fromHostLiveID) => {rejectHostConnection({liveID,fromHostLiveID, // 从 onCoHostRequestReceived 事件中获取该数据onSuccess: () => { console.log('已拒绝连线邀请'); },onError: (error) => { console.log('拒绝连线失败', error); },});};


import React, { useMemo } from 'react';import { View, Text, Image, StyleSheet, Dimensions } from 'react-native';const DEFAULT_AVATAR = 'https://liteav-test-1252463788.cos.ap-guangzhou.myqcloud.com/voice_room/voice_room_cover1.png';const { width: SCREEN_WIDTH } = Dimensions.get('window');// 接收来自父组件的核心数据:seatList 和 canvasexport default function ParticipantOverlay({ seatList, canvas }) {if (!seatList || seatList.length === 0) return null;// 根据 canvas 计算缩放比例const scale = useMemo(() => {if (!canvas?.w || !canvas?.h) return { scaleX: 1, scaleY: 1 };const displayWidth = SCREEN_WIDTH;const displayHeight = SCREEN_WIDTH * (canvas.h / canvas.w);return {scaleX: displayWidth / canvas.w,scaleY: displayHeight / canvas.h,};}, [canvas]);// 计算每个成员 UI 容器的精确位置和大小const getParticipantStyle = (participant) => {if (!participant?.region) return {};return {position: 'absolute',left: participant.region.x * scale.scaleX,top: participant.region.y * scale.scaleY,width: participant.region.w * scale.scaleX,height: participant.region.h * scale.scaleY,};};return (// overlay-container<View style={styles.overlayContainer} pointerEvents="none">{/* 遍历 seatList,为每个麦位成员创建独立的 UI 容器 */}{seatList.map((participant) => {if (!participant?.userInfo?.userID) return null;const isCameraOff = participant.userInfo.cameraStatus === 'OFF';return (// participant-ui-container<View key={participant.userInfo.userID} style={getParticipantStyle(participant)}>{/* 条件渲染:根据摄像头状态显示不同 UI */}{isCameraOff ? (// 1. 当摄像头关闭时,显示居中的头像和昵称<View style={styles.avatarPlaceholder}><Imagestyle={styles.avatarImage}source={{ uri: participant.userInfo.userAvatar || DEFAULT_AVATAR }}/><Text style={styles.avatarName}>{participant.userInfo.userName || participant.userInfo.userID}</Text></View>) : (// 2. 当摄像头开启时,显示左下角的昵称条<View style={styles.nicknameBar}><Text style={styles.nicknameText}>{participant.userInfo.userName || participant.userInfo.userID}</Text></View>)}</View>);})}</View>);}const styles = StyleSheet.create({overlayContainer: {position: 'absolute',top: 0,left: 0,right: 0,bottom: 0,},avatarPlaceholder: {flex: 1,backgroundColor: '#2E323A',justifyContent: 'center',alignItems: 'center',},avatarImage: {width: 60,height: 60,borderRadius: 30,},avatarName: {marginTop: 8,fontSize: 13,color: '#fff',},nicknameBar: {position: 'absolute',left: 6,bottom: 6,backgroundColor: 'rgba(0, 0, 0, 0.5)',paddingHorizontal: 8,paddingVertical: 3,borderRadius: 10,},nicknameText: {color: '#fff',fontSize: 11,},});
import React from 'react';import { StyleSheet, View } from 'react-native';import { LiveCoreView } from 'react-native-tuikit-atomic-x/lib/module/components/LiveCoreView';import { useLiveSeatState } from 'react-native-tuikit-atomic-x/lib/module/atomic-x/state/LiveSeatState';import ParticipantOverlay from '../../components/ParticipantOverlay';export default function YourAnchorScreen({ route, navigation }) {const { liveID } = route.params || {};const { seatList, canvas } = useLiveSeatState(liveID);return (// page-container<View style={styles.pageContainer}>{/* live-container */}<View style={styles.liveContainer}>{/* 底层:视频渲染层 */}<LiveCoreViewliveID={liveID}coreViewType="pushView" // 主播端: pushView, 观众端: playViewstyle={styles.videoLayer}/>{/* 上层:自定义 UI 覆盖层 */}<ParticipantOverlay seatList={seatList} canvas={canvas} /></View>{/* 页面的其他 UI,例如底部的操作栏 */}{/* <View style={styles.bottomControls}>...</View> */}</View>);}const styles = StyleSheet.create({pageContainer: {flex: 1,backgroundColor: '#000',},liveContainer: {flex: 1,},videoLayer: {flex: 1,},});
targetHostLiveID 是否正确,并且对方直播间处于正常开播状态。文档反馈