主播连线(uni-app)

最近更新时间:2025-11-12 17:54:22

我的收藏
AtomicXCore 提供了 CoHostState 核心模块,用于处理跨房连线。本文档将指导您如何组合使用该工具,来完成直播场景下连线的完整流程。

核心场景

一次完整的“主播连线”通常包含两个核心阶段,其整体流程如下:


实现步骤

步骤1:组件集成

请参考 开始直播 集成 AtomicXCore,并完成 LiveCoreView 的接入。

步骤2:实现跨房连线

此步骤的目标是让两个主播的画面出现在同一个视图中,我们将使用 CoHostState 来完成。

邀请方(主播 A)实现

1. 发起连线邀请
当主播A在界面上选择目标主播 B 并发起连线时,调用 requestHostConnection 方法。
import { useCoHostState } from "@/uni_modules/tuikit-atomic-x/state/CoHostState"

const liveID = 'xxx' // 主播 A 的房间 ID
//通过 liveID 获取 CoHostState 的实例
const { requestHostConnection } = useCoHostState(liveID)

// 用户点击“连线”按钮,并选择了主播B
const inviteHostB = (targetHostLiveId: string) => {
requestHostConnection({
liveID, // 主播 A 的房间 ID
targetHostLiveID: targetHostLiveID, // 主播 B 的房间 ID
layoutTemplate: 'HOST_DYNAMIC_GRID', // 选择一个布局模版
timeout: 30, // 邀请超时时间
success: () => {
console.log("连线邀请已发送,等待对方处理...")
},
fail: (error) => {
console.log("邀请发送失败", error)
// 可以在这里进行弹窗提示
}
})
}
2. 监听邀请结果
通过 addCoHostListener订阅对应的事件,您可以接收到主播 B 的处理结果。
import { useCoHostState } from "@/uni_modules/tuikit-atomic-x/state/CoHostState"
import { onMounted } from 'vue';

const liveID = 'xxx' // 主播 A 的房间 ID
//通过 liveID 获取 CoHostState 的实例
const { addCoHostListener } = useCoHostState(liveID)

onMounted(() => {
addCoHostListener(liveID, 'onCoHostRequestAccepted', {
callback: (event) => {
const result = JSON.parse(event)
console.log('主播 ${reult.invitee.userName} 同意了您的连线邀请')
}
})
addCoHostListener(liveID, 'onCoHostRequestRejected', {
callback: (event) => {
const result = JSON.parse(event)
console.log('主播 ${reult.invitee.userName} 拒绝了您的连线邀请')
}
})
addCoHostListener(liveID, 'onCoHostRequestTimeout', {
callback: () => {
console.log('邀请超时,对方未回应')
}
})
})

受邀方(主播 B)实现

1. 接收连线邀请
通过 addCoHostListener订阅 onCoHostRequestReceived 事件,主播B可以监听到来自主播 A 的邀请。
import { useCoHostState } from "@/uni_modules/tuikit-atomic-x/state/CoHostState"
import { onMounted } from 'vue';

const liveID = 'xxx' // 主播 B 的房间 ID
//通过 liveID 获取 CoHostState 的实例
const { addCoHostListener } = useCoHostState(liveID)


onMounted(() => {
addCoHostListener(liveID, 'onCoHostRequestReceived', {
callback: (event) => {
const result = JSON.parse(event)
console.log('收到主播 ${reult.inviter.userName} 的连线邀请')
// 可以在这里进行弹窗提示
}
})
})
2. 响应连线邀请
当主播 B 在弹出的对话框中做出选择后,调用相应的方法。
import { useCoHostState } from "@/uni_modules/tuikit-atomic-x/state/CoHostState"
import { onMounted } from 'vue';

const liveID = 'xxx' // 主播 B 的房间 ID
//通过 liveID 获取 CoHostState 的实例
const { acceptHostConnection, rejectHostConnection } = useCoHostState(liveID)

const acceptInvitation = () => {
acceptHostConnection({
liveID,
fromHostLiveId: 'xxx' // 从 onCoHostRequestReceived 事件中获取该数据
})
}

const rejectInvitation = () => {
rejectHostConnection({
liveID,
fromHostLiveId: 'xxx' // 从 onCoHostRequestReceived 事件中获取该数据
})
}

运行效果

当您集成以上功能实现后,请分别使用主播 A 和主播 B 进行对应操作,运行效果如下,您可以参考下一章节 完善 UI 细节 来定制您想要的 UI 逻辑。


完善 UI 细节

您可以通过修改源码的方式,在视频流画面上添加自定义视图,用于显示昵称、头像等信息,或在他们关闭摄像头时提供占位图,以优化视觉体验。

实现视频流画面的昵称显示

实现效果



实现方式

创建自定义 UI 覆盖层组件 (ParticipantOverlay.vue)
这个组件是我们的“UI贴纸”,它只负责根据数据渲染UI,不关心视频。
在您的 components 目录下,创建一个新文件 ParticipantOverlay.vue
将以下代码复制到文件中。
<template>
<view class="overlay-container">
<!-- 遍历 seatList,为每个麦位成员创建独立的UI容器 -->
<view
v-for="participant in seatList"
:key="participant.userInfo.userID"
class="participant-ui-container"
:style="getParticipantStyle(participant)"
>
<!-- 条件渲染:根据摄像头状态显示不同UI -->
<!-- 1. 当摄像头关闭时,显示居中的头像和昵称 -->
<view v-if="participant.userInfo.cameraStatus === 'OFF'" class="avatar-placeholder">
<image class="avatar-image" :src="participant.userInfo.userAvatar || '/static/default-avatar.png'" mode="aspectFill"></image>
<text class="avatar-name">{{ participant.userInfo.userName || participant.userInfo.userID }}</text>
</view>
<!-- 2. 当摄像头开启时,显示左下角的昵称条 -->
<view v-if="participant.userInfo.cameraStatus === 'ON'" class="nickname-bar">
<text class="nickname-text">{{ participant.userInfo.userName || participant.userInfo.userID }}</text>
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
// 1. 接收来自父组件的核心数据:seatList 和 scale
const props = defineProps({
seatList: {
type: Array,
default: () => []
},
scale: {
type: Object,
default: () => ({ scaleX: 1, scaleY: 1 })
}
});

// 2. 定义一个方法来计算每个成员UI容器的精确位置和大小
const getParticipantStyle = (participant) => {
if (!participant || !participant.region) return {};
return {
position: 'absolute',
left: `${participant.region.x * props.scale.scaleX}px`,
top: `${participant.region.y * props.scale.scaleY}px`,
width: `${participant.region.w * props.scale.scaleX}px`,
height: `${participant.region.h * props.scale.scaleY}px`,
};
};
</script>

<style scoped>
.overlay-container {
pointer-events: none;
}

.participant-ui-container {
overflow: hidden;
}
.avatar-placeholder {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #2E323A;
}
.avatar-image {
width: 160rpx;
height: 160rpx;
border-radius: 80rpx;
}
.avatar-name {
margin-top: 20rpx;
font-size: 28rpx;
color: #FFFFFF;
}
.nickname-bar {
position: absolute;
left: 10rpx;
bottom: 10rpx;
background-color: rgba(0, 0, 0, 0.5);
padding: 4rpx 16rpx;
border-radius: 20rpx;
}
.nickname-text {
color: #FFFFFF;
font-size: 24rpx;
}
</style>
步骤 2:在直播间页面中组合所有组件
这是将视频层和 UI 层“叠”在一起的关键步骤,同时需要解决 nvue 的布局问题。
打开您的直播间页面文件
按照以下结构和样式进行修改。
<template>
<view class="page-container">
<view class="live-container">
<!-- 底层:视频渲染层 -->
<LiveCoreView
:liveID="xxx" // 对应直播间的 liveID
:viewType="xxx" // 主播端: PUSH_VIEW, 观众端: PLAY_VIEW
class="video-layer"
/>
<!-- 上层:自定义UI覆盖层 -->
<ParticipantOverlay
:seatList="seatList"
:scale="scale"
class="ui-layer"
/>
</view>
<!-- 页面的其他UI,如底部的操作栏 -->
<!-- <view class="bottom-controls">...</view> -->
</view>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import ParticipantOverlay from '@/components/ParticipantOverlay.vue';
import { useLiveSeatState } from '@/uni_modules/tuikit-atomic-x/state/LiveSeatState';
const liveID = 'xxx' // 当前直播间的 liveID
const { seatList } = useLiveSeatState(liveID);
const scale = ref({ scaleX: 1, scaleY: 1 });

onMounted(() => {
// 在此获取并设置正确的 scale 值。
// 这是保证UI对齐的关键。请根据您的项目实际逻辑实现。
// 示例:
const { windowWidth } = uni.getSystemInfoSync();
const designWidth = 750; // rpx 设计稿宽度
scale.value.scaleX = windowWidth / designWidth;
scale.value.scaleY = scale.value.scaleX;
});
</script>

<style scoped>
.page-container {
flex: 1;
background-color: #000;
}

.live-container {
flex: 1;
position: relative;
}
.video-layer,
.ui-layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

.video-layer {
z-index: 1;
}

.ui-layer {
z-index: 2;
}
</style>

API 文档

关于 CoHostState 及其相关类的所有公开接口、属性和方法的详细信息,请您参阅 AtomicXCore 框架的官方 API 文档。本指南使用到的相关 Store 如下:
State
功能描述
API 文档
DeviceState
音视频设备控制:麦克风(开关 / 音量)、摄像头(开关 / 切换 / 画质)、屏幕共享,设备状态实时监听。
CoHostState
主播跨房连线:支持多布局模板(动态网格等),发起 / 接受 / 拒绝连线,连麦主播互动管理。

常见问题

为什么发起了连线邀请,对方却没收到?

请检查 targetHostLiveID 是否正确,并且对方直播间处于正常开播状态。
检查网络连接是否通畅,邀请信令有30秒的默认超时时间。