接入概览(Web)

最近更新时间:2025-12-29 17:09:52

我的收藏
Atomicx 是腾讯云推出的音视频业务全新原子化接入方案。它将复杂的音视频房间功能拆解为独立的数据逻辑(State Hooks)与 UI 组件,旨在帮助开发者灵活可控的将多人音视频控制、屏幕共享、互动聊天等能力集成到业务系统中。本文将引导开发者使用 Atomicx 快速实现多人音视频房间的基础能力。


核心能力

通过 Atomicx,您可以快速获得构建专业多人音视频场景所需的完整能力。
多人房间管理:支持房间预约、创建、加入、及向特定用户发起房间邀请呼叫。
音视频通话:支持多人实时音视频通信及布局动态切换(例如九宫格、演讲者模式)。
屏幕共享:提供全屏内容共享及系统音频采集能力。
成员与权限管理:包含成员列表展示、角色转移(房主/管理员)及禁言/禁画等控场功能。
视觉增强:集成基础美颜(磨皮/美白)及虚拟背景(背景模糊/图片替换)功能。
互动聊天:支持房间内发送文本、表情消息及消息撤回、删除操作。

准备工作

步骤1:开通服务

请参考 开通服务 领取 TUIRoomKit 体验版。

步骤2:环境准备

Node.js: ≥ 18.19.1 (推荐使用官方 LTS 版本)。
Vue: ≥ 3.4.21。
现代浏览器:支持 WebRTC APIs 的现代浏览器。
设备:摄像头、麦克风、扬声器。

步骤3:安装 Atomicx 依赖

npm
pnpm
yarn
npm install tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3
pnpm install tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3
yarn add tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3

搭建基础多人房间

步骤1:配置全局 UIKitProvider

App.vue 中配置全局 UIKitProvider这是使用 Atomicx 组件的基础
// src/App.vue
<template>
<UIKitProvider theme="light" language="zh-CN">
<!-- 您项目的 Dom 节点 -->
</UIKitProvider>
</template>

<script>
import { UIKitProvider } from '@tencentcloud/uikit-base-component-vue3';
</script>

步骤2:登录与身份鉴权

在进行身份鉴权前,您需要准备以下信息:
SDKAppID:从腾讯云 控制台 获取,通常是以 140 或 160 开头的 10 位整数。
userId:当前用户的唯一 ID,仅包含英文字母、数字、连字符和下划线。为避免多端登录冲突,请勿使用 1、123 等简单 ID。
userSig:用于腾讯云鉴权的票据。开发测试阶段,您可以通过 UserSig 辅助工具 快速生成临时 userSig。
注意:
控制台生成的 userSig 仅用于开发测试,正式环境请在您的服务器端生成。详细参见 如何计算及使用 UserSig
components 目录下创建 LoginUserInfo.vue 组件,拷贝以下代码实现并填入您自己的 SDKAppID 信息。
<template>
<div class="login-user-info-container">
<template v-if="loginUserInfo">
<div class="login-userid">用户 Id: {{ loginUserInfo.userId }}</div>
<div class="login-userid">用户名称: {{ loginUserInfo.userName }}</div>
<TUIButton type="primary" @click="handleLogout">退出登录</TUIButton>
</template>
<template v-else>
<TUIInput style="max-width: 200px;" v-model="userId" placeholder="请输入 userId" />
<TUIInput style="max-width: 200px;" v-model="userName" placeholder="请输入 userName" />
<TUIInput style="max-width: 200px;" v-model="userSig" :maxLength="1000" placeholder="请输入 userSig" />
<TUIButton type="primary" @click="handleLogin">登录</TUIButton>
</template>
</div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { TUIInput, TUIButton } from '@tencentcloud/uikit-base-component-vue3';
import { useLoginState } from 'tuikit-atomicx-vue3';

const { loginUserInfo, login, logout, setSelfInfo } = useLoginState();

const SDKAppID = 1400704311; // TODO: 请替换为您的 SDKAppID,从腾讯云控制台获取
const userId = ref('');
const userName = ref('');
const userSig = ref('');

async function handleLogin() {
console.log('userId.value', userId.value);
console.log('userSig.value', userSig.value);
if (userId.value) {
await login({
sdkAppId: SDKAppID,
userId: userId.value,
userSig: userSig.value,
});
sessionStorage.setItem('atomicx-demo-loginUserInfo', JSON.stringify(loginUserInfo.value));
}
if (userName.value) {
await setSelfInfo({
userName: userName.value,
avatarUrl: '',
});
}
}

async function handleLogout() {
await logout();
sessionStorage.removeItem('atomicx-demo-loginUserInfo');
}

onMounted(() => {
let loginUserInfo = sessionStorage.getItem('atomicx-demo-loginUserInfo');
if (loginUserInfo) {
loginUserInfo = JSON.parse(loginUserInfo);
userId.value = loginUserInfo.userId;
handleLogin();
}
});
</script>

<style scoped>
.login-user-info-container {
display: flex;
align-items: center;
gap: 12px;
}

.login-userid {
font-size: 14px;
color: #666;
}
</style>

步骤3:创建或加入房间

在您项目的 src/components 目录下创建 RoomControl.vue 文件并拷贝以下代码实现创建/加入房间,离开/销毁房间能力。
<template>
<div class="room-control-container">
<div v-if="currentRoom">房间 Id: {{ currentRoom?.roomId }}</div>
<div v-if="currentRoom">房间名称: {{ currentRoom?.roomName }}</div>
<TUIInput v-if="!currentRoom" style="max-width: 200px;" v-model="roomId" placeholder="请输入房间 ID" />
<TUIButton v-if="!currentRoom" type="primary" @click="handleCreateRoom">创建房间</TUIButton>
<TUIButton v-if="!currentRoom" type="primary" @click="handleJoinRoom">加入房间</TUIButton>
<TUIButton v-if="currentRoom && localParticipant?.role === RoomParticipantRole.Owner" type="primary" @click="handleEndRoom">结束房间</TUIButton>
<TUIButton v-if="currentRoom" type="primary" @click="handleLeaveRoom">离开房间</TUIButton>
</div>
</template>

<script setup>
import { ref, watch } from 'vue';
import { TUIInput, TUIButton, TUIToast } from '@tencentcloud/uikit-base-component-vue3';
import { useLoginState, useRoomState, useRoomParticipantState, TUIErrorCode, RoomParticipantRole } from 'tuikit-atomicx-vue3/room';

const { loginUserInfo } = useLoginState();
const { currentRoom, createAndJoinRoom, joinRoom, endRoom,leaveRoom } = useRoomState();
const { localParticipant, getParticipantList } = useRoomParticipantState();
const roomId = ref('');

async function handleCreateRoom() {
try {
await createAndJoinRoom({
roomId: roomId.value,
options: {
roomName: `${loginUserInfo.value.userName || loginUserInfo.value.userId}的临时房间`,
},
});
TUIToast.success({ message: '创建房间成功' });
} catch (error) {
if (error.code === TUIErrorCode.ERR_ROOM_ID_OCCUPIED) {
TUIToast.error({ message: '房间已存在, 请重新输入房间 ID' });
} else {
TUIToast.error({ message: '创建房间失败,请重试' });
}
}
}

async function handleJoinRoom() {
try {
await joinRoom({
roomId: roomId.value,
});
TUIToast.success({ message: '加入房间成功' });
} catch (error) {
TUIToast.error({ message: '加入房间失败,请重试' });
}
}

async function handleEndRoom() {
try {
await endRoom();
TUIToast.success({ message: '结束房间成功' });
} catch (error) {
TUIToast.error({ message: '结束房间失败,请重试' });
}
}

async function handleLeaveRoom() {
try {
await leaveRoom();
TUIToast.success({message: '离开房间成功'});
} catch (error) {
TUIToast.error({ message: '离开房间失败,请重试' });
}
}

watch(() => currentRoom.value?.roomId, (val, oldVal) => {
if (!oldVal && val) {
getParticipantList({ cursor: '' });
}
});
</script>

<style scoped>
.room-control-container {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: white;
border: 1px solid #e5e5e5;
border-radius: 8px;
flex: 1;
min-width: 300px;
}

.room-control-container > div {
font-size: 14px;
color: #666;
white-space: nowrap;
}
</style>

步骤4:采集媒体设备

在您项目的 src/components 目录下创建 DeviceControl.vue 文件并拷贝以下代码实现音视频媒体采集能力。
<template>
<div class="device-control-container">
<TUIButton v-if="!isLocalCameraOpen" type="primary" @click="openLocalCamera">打开摄像头</TUIButton>
<TUIButton v-if="isLocalCameraOpen" type="primary" @click="closeLocalCamera">关闭摄像头</TUIButton>
<TUIButton v-if="!isLocalMicrophoneOpen" type="primary" @click="openLocalMicrophone">打开麦克风</TUIButton>
<TUIButton v-if="isLocalMicrophoneOpen" type="primary" @click="closeLocalMicrophone">关闭麦克风</TUIButton>
</div>
</template>

<script setup>
import { computed } from 'vue';
import { TUIButton } from '@tencentcloud/uikit-base-component-vue3';
import { useDeviceState, DeviceStatus } from 'tuikit-atomicx-vue3/room';

const { microphoneStatus, cameraStatus, openLocalCamera, openLocalMicrophone, closeLocalCamera, closeLocalMicrophone } = useDeviceState();

const isLocalCameraOpen = computed(() => cameraStatus.value === DeviceStatus.On);
const isLocalMicrophoneOpen = computed(() => microphoneStatus.value === DeviceStatus.On);
</script>

<style scoped>
.device-control-container {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: white;
border: 1px solid #e5e5e5;
border-radius: 8px;
flex: 1;
min-width: 300px;
}
</style>

步骤5:渲染视频布局

在您项目的 src/components 目录下创建 RoomMain.vue 文件并拷贝以下代码实现音视频流渲染能力。
<template>
<div class="room-main-container">
<RoomView v-if="currentRoom?.roomId">
<template #participantViewUI="{ participant, streamType }">
<div :class="['participant-view-container', { 'camera-off': isCameraOff(participant) }]">
<Avatar
v-if="isCameraOff(participant)"
class="avatar-region"
size="xxl"
:src="participant.avatarUrl"
:user-id="participant.userId"
/>
<div class="user-info-container">
<div v-if="!isScreen(streamType)">
<IconMicOff v-if="isMicriophoneOff(participant)" size="20"/>
<IconMicOn v-else size="20" />
</div>
<span>{{ participant.userName || participant.userId }}</span>
</div>
</div>
</template>
</RoomView>

<div v-else class="empty-state">
<div class="empty-content">
<h3 class="empty-title">暂未加入房间</h3>
<p class="empty-description">请在上方创建房间或加入已有房间</p>
</div>
</div>
</div>
</template>

<script setup>
import { IconMicOff, IconMicOn } from '@tencentcloud/uikit-base-component-vue3';
import { RoomView, Avatar, DeviceStatus, VideoStreamType, useRoomState } from 'tuikit-atomicx-vue3/room';

const { currentRoom } = useRoomState();

const isCameraOff = (participant) => participant.cameraStatus !== DeviceStatus.On;
const isMicriophoneOff = (participant) => participant.microphoneStatus !== DeviceStatus.On;
const isScreen = (streamType) => streamType === VideoStreamType.Screen;
</script>

<style scoped>
.room-main-container { flex: 1; display: flex; background: white; border: 1px solid #e5e5e5; border-radius: 8px; overflow: hidden; min-height: 0;}.participant-view-container { position: absolute; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background: transparent; &.camera-off { background: #f0f0f0; }}.avatar-region { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);}.user-info-container { position: absolute; bottom: 12px; left: 12px; height: 32px; gap: 6px; max-width: calc(100% - 24px); background: rgba(0, 0, 0, 0.75); color: white; font-size: 13px; border-radius: 16px; display: flex; align-items: center; padding: 0 12px;}.empty-state { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px;}.empty-content { text-align: center; max-width: 320px;}.empty-icon { width: 80px; height: 80px; color: #d1d5db; margin: 0 auto 24px;}.empty-title { margin: 0 0 8px 0; font-size: 18px; font-weight: 500; color: #333;}.empty-description { margin: 0; font-size: 14px; color: #999; line-height: 1.6;}
</style>

步骤6:修改 App.vue 文件

拷贝以下代码到 src/App.vue 中,即完成了多人音视频房间基础能力。
<template>
<UIKitProvider theme="light" language="zh-CN">
<div class="app-container">
<header class="app-header">
<div class="header-content">
<h1 class="app-title">AtomicX Room</h1>
<LoginUserInfo />
</div>
</header>
<main class="app-main" v-if="loginUserInfo">
<div class="control-panel">
<RoomControl />
<DeviceControl />
</div>
<RoomMain />
</main>
<div v-else class="welcome-screen">
<div class="welcome-content">
<h2>欢迎使用 AtomicX Room</h2>
<p>请先登录以开始使用</p>
</div>
</div>
</div>
</UIKitProvider>
</template>

<script setup>
import { UIKitProvider } from '@tencentcloud/uikit-base-component-vue3';
import LoginUserInfo from './components/LoginUserInfo.vue';
import RoomControl from './components/RoomControl.vue';
import DeviceControl from './components/DeviceControl.vue';
import RoomMain from './components/RoomMain.vue';

import { useLoginState } from 'tuikit-atomicx-vue3';
const { loginUserInfo } = useLoginState();
</script>

<style>
* { box-sizing: border-box;}html, body { width: 100%; height: 100%; margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;}#app { width: 100%; height: 100%; background: #f5f5f5;}.app-container { width: 100%; height: 100%; display: flex; flex-direction: column;}.app-header { background: white; border-bottom: 1px solid #e5e5e5; padding: 16px 24px;}.header-content { max-width: 1400px; margin: 0 auto; display: flex; justify-content: space-between; align-items: center;}.app-title { margin: 0; font-size: 20px; font-weight: 500; color: #333;}.app-main { flex: 1; display: flex; flex-direction: column; padding: 20px; gap: 16px; max-width: 1400px; width: 100%; margin: 0 auto; overflow: hidden;}.control-panel { display: flex; gap: 16px; flex-wrap: wrap;}.welcome-screen { flex: 1; display: flex; align-items: center; justify-content: center;}.welcome-content { text-align: center; color: #666;}.welcome-content h2 { font-size: 24px; margin: 0 0 8px 0; font-weight: 500; color: #333;}.welcome-content p { font-size: 14px; margin: 0;}
</style>


步骤7:运行和测试

启动开发服务器。
npm
pnpm
yarn
npm run dev
pnpm run dev
yarn run dev
启动成功后,请在浏览器中打开调试地址(通常为 http://localhost:5173)访问应用。您将看到 Atomicx Room 的示例 Demo。

准备两个测试账号

在腾讯云 控制台 生成两个不同的 userId 和对应的 userSig(例如 user_001、user_002)。

打开两个浏览器标签页

窗口 A:使用 user_test_A 登录。
窗口 B:使用 user_test_B 登录。


测试流程

在窗口 A 中:输入房间 ID(例如 "test_room_A"),点击创建房间
在窗口 A 中:点击打开摄像头打开麦克风
在窗口 B 中:输入相同的房间 ID("test_room_A"),点击加入房间
在窗口 B 中:点击打开摄像头打开麦克风
验证两个窗口能否看到对方的视频画面并听到声音。


API 文档

State Hook 名称
核心作用与场景
API 文档
useLoginState
登录鉴权。 管理用户登录生命周期和身份信息。
useDeviceState
设备与网络。 管理麦克风、摄像头、屏幕共享设备,以及网络质量。
useRoomState
房间管理。 管理实时房间的生命周期(创建、加入、结束)和核心信息。
useRoomParticipantState
成员管理。 管理房间内所有参会者信息、角色和权限。
useMessageListState
聊天消息。 管理消息收发和展示。
useMessageInputState
聊天输入。管理消息的发送

下一步

当您完成了基础的多人音视频房间功能后,您可以参考以下功能指南,进一步丰富和扩展您的特色业务能力。
多人音视频房间功能
功能介绍
实现指南
媒体设备切换
支持用户切换麦克风、摄像头和扬声器设备。
视频布局切换
提供宫格模式和演讲者模式的视频布局。
屏幕分享
支持用户分享屏幕、窗口或浏览器标签页。
成员管理
房主/管理员可进行踢人、转让房主等权限操作。
会中聊天
实现参会者间的实时文本消息通信。
会中呼叫
支持房间中用户邀请其他用户加入当前房间。
预定房间
提供房间的提前预约和列表管理功能。
虚拟背景
支持用户设置背景模糊或替换为虚拟背景图。
基础美颜
支持用户设置磨皮、美白、红润的美颜效果。

常见问题

Atomicx 在本地开发时使用正常,但部署到线上环境后无法正常采集用户的摄像头或麦克风设备

原因分析:浏览器出于安全和隐私保护的考虑,对音视频设备(麦克风、摄像头)的采集有着严格限制。只有在安全环境下,采集操作才会被允许。安全环境协议包括:https://、localhost、file:// 等。HTTP 协议被视为不安全,浏览器会默认禁止其访问媒体设备。
解决方案:若您在本地(localhost)测试一切正常,但部署后出现采集失败,请立即检查您的网页是否部署在 HTTP 协议上。您必须使用 HTTPS 协议部署您的网页,并确保具备有效的安全证书。
相关资源:更多关于 URL 域名及协议的限制详情,请参见 URL 域名及协议限制说明

Atomicx 是否支持使用 iframe 集成?

支持。使用 iframe 集成 Atomicx 时, 需要在 iframe 标签中配置 allow 属性以授予必要的浏览器权限(麦克风、摄像头、屏幕共享、全屏等),示例如下:
// 开启麦克风、摄像头、屏幕分享、全屏权限
<iframe allow="microphone; camera; display-capture; display; fullscreen;">

联系我们

如果您在接入或使用过程中有任何疑问或者建议,欢迎 联系我们 提交反馈。