tencent cloud

实时音视频

动态与公告
产品动态
产品近期公告
关于 TRTC Live 正式上线的公告
关于TRTC Conference 正式版上线的公告
Conference 商业化版本即将推出
关于多人音视频 Conference 开启内测公告
关于音视频通话 Call 正式版上线的公告
关于腾讯云音视频终端 SDK 播放升级及新增授权校验的公告
关于 TRTC 应用订阅套餐服务上线的相关说明
产品简介
产品概述
基本概念
产品功能
产品优势
应用场景
性能数据
购买指南
计费概述
免费时长说明
月订阅
现收现付
TRTC 逾期与暂停政策
常见问题解答
退款说明
新手指引
Demo 体验
视频通话 SDK
组件介绍
开通服务
跑通 Demo
快速接入
离线唤醒
会话聊天
云端录制
AI 降噪
界面定制
Chat 集成通话能力
更多特性
无 UI 集成
服务端 API
客户端 API
解决方案
错误码表
发布日志
常见问题
视频会议 SDK
组件介绍(TUIRoomKit)
开通服务(TUIRoomKit)
跑通 Demo(TUIRoomKit)
快速接入(TUIRoomKit)
屏幕共享(TUIRoomKit)
预定会议(TUIRoomKit)
会中呼叫(TUIRoomKit)
界面定制(TUIRoomKit)
虚拟背景(TUIRoomKit)
会议控制(TUIRoomKit)
云端录制(TUIRoomKit)
AI 降噪(TUIRoomKit)
会中聊天(TUIRoomKit)
机器人推流(TUIRoomKit)
更多特性(TUIRoomKit)
客户端 API(TUIRoomKit)
服务端 API(TUIRoomKit)
常见问题(TUIRoomKit)
错误码 (TUIRoomKit)
SDK更新日志(TUIRoomKit)
直播与语聊 SDK
Live 视频直播计费说明
组件介绍
开通服务(TUILiveKit)
跑通 Demo
无 UI 集成
UI 自定义
直播监播
视频直播
语聊房
高级功能
客户端 API
服务端 API
错误码
发布日志
常见问题
RTC Engine
开通服务
SDK 下载
API-Example
接入指引
API-参考手册
高级功能
AI 集成
概述
MCP 配置
Skills 配置
集成指南
常见问题
RTC RESTFUL API
History
Introduction
API Category
Room Management APIs
Stream mixing and relay APIs
On-cloud recording APIs
Data Monitoring APIs
Pull stream Relay Related interface
Web Record APIs
AI Service APIs
Cloud Slicing APIs
Cloud Moderation APIs
Making API Requests
Call Quality Monitoring APIs
Usage Statistics APIs
Data Types
Appendix
Error Codes
控制台指南
应用管理
套餐包管理
用量统计
监控仪表盘
开发辅助
解决方案
实时合唱
常见问题
迁移指南
计费相关
功能相关
UserSig 相关
应对防火墙限制相关
缩减安装包体积相关
Andriod 与 iOS 相关
Web 端相关
Flutter 相关
Electron 相关
TRTCCalling Web 相关
音视频质量相关
其他问题
旧版文档
RTC RoomEngine SDK(旧)
集成 TUIRoom (Web)
集成 TUIRoom (Android)
集成 TUIRoom (iOS)
集成 TUIRoom (Flutter)
集成 TUIRoom (Electron)
TUIRoom API 查询
实现云端录制与回放(旧)
监控仪表盘计费(旧)
协议与策略
安全合规认证
安全白皮书
信息安全说明
服务等级协议
苹果隐私策略:PrivacyInfo.xcprivacy
TRTC 政策
隐私协议
数据处理和安全协议
词汇表

观众上麦(Android)

PDF
聚焦模式
字号
最后更新时间: 2025-12-04 15:09:53
AtomicXCore 提供了 CoGuestStoreLiveSeatStore模块,用于管理观众连麦的完整业务流程。您无需关心复杂的状态同步和信令交互,只需调用几个简单的方法,即可为您的直播添加强大的观众与主播音视频互动功能。本文档将指导您如何使用 CoGuestStore LiveSeatStoreAndroid 应用中快速实现语音连麦功能。


核心场景

CoGuestStoreLiveSeatStore支持以下几个主流的场景:
观众申请上麦:观众主动发起连麦请求,主播在收到请求后进行同意或拒绝。
主播邀请上麦:主播可以主动向直播间内的任意一位观众发起连麦邀请。
主播管理麦位:主播可以对麦位上的用户进行踢人、闭麦、锁麦等操作。

实现步骤

步骤1:组件集成

请参考 快速接入 集成 AtomicXCore

步骤2:实现观众申请上麦

观众端实现

作为观众,您的核心任务是发起申请、接收结果主动下麦
1. 发起连麦申请
当用户点击界面上的“申请连麦”按钮时,调用 applyForSeat 方法。
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.live.CoGuestStore

val liveId = "房间ID"
val guestStore = CoGuestStore.create(liveId)

// 用户点击“申请连麦”
fun requestToConnect() {
// timeout: 请求超时时间,例如 30 秒
guestStore.applyForSeat(-1, 30, null, object : CompletionHandler {
override fun onSuccess() {
print("连麦申请已发送,等待主播处理...")
}

override fun onFailure(code: Int, desc: String) {
print("申请发送失败: $desc")
}
})
}
2. 监听主播的处理结果
通过订阅 GuestListener,您可以接收到主播的处理结果。
import io.trtc.tuikit.atomicxcore.api.device.DeviceStore
import io.trtc.tuikit.atomicxcore.api.live.GuestListener
import io.trtc.tuikit.atomicxcore.api.live.LiveUserInfo

// 在您的 Activity/Fragment 初始化时添加监听
fun subscribeGuestEvents() {
val guestListener = object : GuestListener() {
override fun onGuestApplicationResponded(isAccept: Boolean, hostUser: LiveUserInfo) {
if (isAccept) {
print("主播 ${hostUser.userName} 同意了你的申请,准备上麦")
// 1. 打开摄像头、麦克风
DeviceStore.shared().openLocalCamera(true, null)
DeviceStore.shared().openLocalMicrophone(null)
// 2. 在此更新 UI,例如关闭申请按钮,显示连麦中的状态
} else {
print("主播 ${hostUser.userName} 拒绝了你的申请")
// 弹窗提示用户申请被拒绝
}
}
}
guestStore.addGuestListener(guestListener)
}
3. 主动下麦
当连麦观众想结束互动时,调用 disConnect 方法即可返回普通观众状态。
// 用户点击“下麦”按钮
fun leaveSeat() {
guestStore.disconnect(object : CompletionHandler {
override fun onSuccess() {
print("已成功下麦")
}

override fun onFailure(code: Int, desc: String) {
print("下麦失败: $desc")
}
})
}
4. (可选) 取消申请
如果观众在主播处理前想撤回申请,可以调用 cancelApplication
// 用户在等待时,点击“取消申请”
fun cancelRequest() {
guestStore.cancelApplication(object : CompletionHandler {
override fun onSuccess() {
print("申请已取消")
}

override fun onFailure(code: Int, desc: String) {
print("申请取消失败: $desc")
}
})
}

主播端实现

作为主播,您的核心任务是接收申请、展示申请列表处理申请
1. 监听新的连麦申请
通过订阅 HostListener,您可以在有新观众申请时立即收到通知,并给出提示。
import io.trtc.tuikit.atomicxcore.api.live.CoGuestStore
import io.trtc.tuikit.atomicxcore.api.live.HostListener
import io.trtc.tuikit.atomicxcore.api.live.LiveUserInfo

val liveId = "房间ID"
val guestStore = CoGuestStore.create(liveId)

// 订阅主播事件
val hostListener = object : HostListener() {
override fun onGuestApplicationReceived(guestUser: LiveUserInfo) {
print("收到观众 ${guestUser.userName} 的连麦申请")
// 在此更新 UI,例如在“申请列表”按钮上显示红点
}

// ... 覆盖其他需要的回调方法
}
guestStore.addHostListener(hostListener)
2. 展示申请列表
CoGuestStorestate 会实时维护当前的申请者列表,您可以订阅它来刷新您的 UI。
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

// 订阅状态变更
fun observeApplicants() {
CoroutineScope(Dispatchers.Main).launch {
guestStore.coGuestState.applicants.collect { applicants ->
print("当前申请人数: ${applicants.size}")
// 在此刷新您的“申请者列表”UI
}
}
}
3. 处理连麦申请
当您在列表中选择一位观众并点击“同意”或“拒绝”时,调用相应的方法。
// 主播点击“同意”按钮,传入申请者的 userID
fun accept(userId: String) {
guestStore.acceptApplication(
userId,
object : CompletionHandler {
override fun onSuccess() {
print("已同意 $userId 的申请,对方正在上麦")
}

override fun onFailure(code: Int, desc: String) {
print("同意申请失败: $desc")
}
}
)
}

// 主播点击“拒绝”按钮
fun reject(userId: String) {
guestStore.rejectApplication(
userId,
object : CompletionHandler {
override fun onSuccess() {
print("已拒绝 $userId 的申请")
}

override fun onFailure(code: Int, desc: String) {
print("拒绝申请失败: $desc")
}
}
)
}


步骤3:实现主播邀请上麦

主播端实现

1. 向观众发起邀请
当主播在观众列表中选择某人并点击“邀请连麦”时,调用 inviteToSeat 方法。
// 主播选择观众并发起邀请
fun invite(userId: String) {
// timeout: 邀请超时时间
guestStore.inviteToSeat(userId, -1, 30, null, object : CompletionHandler {
override fun onSuccess() {
print("已向 $userId 发出邀请,等待对方回应...")
}

override fun onFailure(code: Int, desc: String) {
print("邀请发送失败: $desc")
}
})
}
2. 监听观众的回应
通过 HostListener 监听 onHostInvitationResponded 事件。
// 在 hostListener 的实现中添加
override fun onHostInvitationResponded(isAccept: Boolean, guestUser: LiveUserInfo) {
if (isAccept) {
print("观众 ${guestUser.userName} 接受了你的邀请")
} else {
print("观众 ${guestUser.userName} 拒绝了你的邀请")
}
}

观众端实现

1. 接收主播的邀请
通过 GuestListener 监听 onHostInvitationReceived 事件。
// 在 guestListener 的实现中添加
override fun onHostInvitationReceived(hostUser: LiveUserInfo) {
print("收到主播 ${hostUser.userName} 的连麦邀请")
// 在此弹出一个对话框,让用户选择“接受”或“拒绝”
}
2. 响应邀请
当用户在弹出的对话框中做出选择后,调用相应的方法。
val inviterId = "发起邀请的主播ID" // 从 onHostInvitationReceived 事件中获取

// 用户点击“接受”
fun accept() {
guestStore.acceptInvitation(inviterId, object : CompletionHandler {
override fun onSuccess() {
// 2. 打开麦克风
DeviceStore.shared().openLocalMicrophone(null)
}

override fun onFailure(code: Int, desc: String) {
print("接受邀请失败: $desc")
}
})
}

// 用户点击“拒绝”
fun reject() {
guestStore.rejectInvitation(inviterId, object : CompletionHandler {
override fun onSuccess() {
// ...
}
override fun onFailure(code: Int, desc: String) {
// ...
}
})
}

功能进阶

当用户上麦后,主播可能需要对麦位进行管理。以下功能主要由 LiveSeatStore 提供,它可以与 CoGuestStore 协同工作。

麦上用户自行开/关麦

麦上用户(包括主播自己)可以通过 LiveSeatStore 提供的接口来控制自己的麦克风静音状态。

实现方式:

1. 静音:调用 muteMicrophone() 方法。这是一个无回调的单向请求。
2. 解除静音:调用 unmuteMicrophone(completion) 方法。

示例代码:

import io.trtc.tuikit.atomicxcore.api.live.LiveSeatStore

val seatStore = LiveSeatStore.create(liveId)

seatStore.muteMicrophone() //静音

seatStore.unmuteMicrophone(null) //解除静音

unmuteMicrophone 接口参数:

参数
类型
描述
completion
CompletionHandler?
操作完成后的回调。

主播远程控制麦上用户开麦或关麦

主播可以对其他麦上用户进行“强制静音”或“邀请开麦”的操作。

实现方式:

1. 强制静音(锁定):主播调用 closeRemoteMicrophone 会强制关闭对方的麦克风,并锁定对方的麦克风权限。此时,被静音的用户会收到 LiveSeatListener 中的 onLocalMicrophoneClosedByAdmin 事件,此时其本地的“打开麦克风”按钮应变为不可点击状态。
2. 邀请开麦(解锁):主播调用 openRemoteMicrophone 并非强制打开对方麦克风,而是解除对方的“锁定状态”,允许对方自行开麦。此时,被操作的用户会收到 onLocalMicrophoneOpenedByAdmin 事件,其本地的“打开麦克风”按钮应恢复为可点击状态,但用户仍处于静音中。
3. 用户自行开麦:用户在收到“解除锁定”的通知后,必须主动调用 LiveSeatStoreunmuteMicrophone()方法解除静音,才能让房间内其他人听到自己的声音。

示例代码:

主播端:
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.live.DeviceControlPolicy

val targetUserId = "userD"

// 1. 强制静音 userD 并锁定
seatStore.closeRemoteMicrophone(targetUserId, object : CompletionHandler {
override fun onSuccess() {
print("已将 $targetUserId 静音并锁定")
}
override fun onFailure(code: Int, desc: String) {
print("操作失败: $desc")
}
})

// 2. 解锁 userD 的麦克风权限(此时 userD 依然是静音状态)
seatStore.openRemoteMicrophone(targetUserId, DeviceControlPolicy.UNLOCK_ONLY, object : CompletionHandler {
override fun onSuccess() {
print("已邀请 $targetUserId 打开麦克风(已解锁)")
}
override fun onFailure(code: Int, desc: String) {
print("操作失败: $desc")
}
})
观众端:
import io.trtc.tuikit.atomicxcore.api.live.DeviceControlPolicy
import io.trtc.tuikit.atomicxcore.api.live.LiveSeatListener

// userD监听主播的操作
val seatListener = object : LiveSeatListener() {
override fun onLocalMicrophoneClosedByAdmin() {
print("被主播静音了")
}

override fun onLocalMicrophoneOpenedByAdmin(policy: DeviceControlPolicy) {
print("主播已解除静音锁定")
}
}
seatStore.addLiveSeatEventListener(seatListener)

closeRemoteMicrophone 接口参数:

参数
类型
描述
userID
String
被操作的用户userID
completion
CompletionHandler?
请求完成后的回调。

openRemoteMicrophone 接口参数:

参数
类型
描述
userID
String
被操作的用户userID
completion
CompletionHandler?
请求完成后的回调。

主播将麦上用户踢下麦位

实现方式:

1. 踢人下麦:主播可以调用 kickUserOutOfSeat 方法,强制将指定用户踢下麦位。
2. 监听事件通知:被踢下麦的用户会收到 GuestListener 中的 onKickedOffSeat 事件通知。

示例代码:

// 假设要踢走 "userB"
val targetUserId = "userB"
seatStore.kickUserOutOfSeat(targetUserId, object : CompletionHandler {
override fun onSuccess() {
print("已将 $targetUserId 踢下麦位")
}
override fun onFailure(code: Int, desc: String) {
print("踢人失败: $desc")
}
})

// "userB" 在 GuestListener 中收到被踢下麦事件
override fun onKickedOffSeat(seatIndex: Int, hostUser: LiveUserInfo) {
// 弹toast提示
}


kickUserOutOfSeat 接口参数:

参数
类型
描述
userID
String
被踢下麦用户userID
completion
CompletionHandler?
请求完成后的回调。

主播锁定和解锁麦位

主播可以锁定或解锁某个麦位。

实现方式:

1. 锁定麦位:主播可调用 lockSeat 方法锁定指定索引的麦位,麦位被锁定后,观众无法通过 applyForSeattakeSeat 占用该麦位。
2. 解锁麦位:调用 unlockSeat 可以解锁麦位,解锁后该麦位可以再次被占用。

示例代码:

// 锁定2号麦位
seatStore.lockSeat(2, object : CompletionHandler {
override fun onSuccess() {
print("2号麦位已锁定")
}
override fun onFailure(code: Int, desc: String) {
print("锁定失败: $desc")
}
})

// 解锁2号麦位
seatStore.unlockSeat(2, object : CompletionHandler {
override fun onSuccess() {
print("2号麦位已解锁")
}
override fun onFailure(code: Int, desc: String) {
print("解锁失败: $desc")
}
})

lockSeat 接口参数:

参数
类型
描述
seatIndex
Int
需要锁定的麦位索引。
completion
CompletionHandler?
请求完成后的回调。

unlockSeat 接口参数:

参数
类型
描述
seatIndex
Int
需要解锁的麦位索引。
completion
CompletionHandler?
请求完成后的回调。

移动麦位

主播和普通上麦用户可以调用moveUserToSeat移动麦位。

实现方式:

1. 主播移动麦位:主播可以调用此接口将任意用户移动到指定麦位。此时 userID 传入目标用户的 ID,targetIndex是目标麦位索引,policy 参数来指定如果目标麦位有人时的移动策略,详见接口参数说明。
2. 普通上麦用户移动自己麦位:普通上麦用户也可以调用此接口来移动自己。此时 userID 必须传入用户自己的 ID,targetIndex 传入想去的新麦位索引,此时policy 参数无效,如果目标麦位有人时会报错并停止移动。

示例代码:

import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.live.MoveSeatPolicy

seatStore.moveUserToSeat("userC",
newSeatIndex,
MoveSeatPolicy.ABORT_WHEN_OCCUPIED,
object : CompletionHandler {
override fun onSuccess() {
print("已成功移动到 $newSeatIndex 号麦位")
}
override fun onFailure(code: Int, desc: String) {
print("换座失败,可能位置有人了: $desc")
}
})

moveUserToSeat 接口参数:

参数
类型
描述
userID
String
需要移麦的用户userID
targetIndex
Int
目标麦位索引。
policy
MoveSeatPolicy?
目标麦位有人时的移动策略枚举:
abortWhenOccupied:目标麦位有人时放弃移动(默认策略)​​
forceReplace:强制替换目标麦位上的用户​​,被替换的用户将会被踢下麦
swapPosition:与目标麦位用户交换位置​​。
completion
CompletionHandler?
请求完成后的回调。

API 文档

关于 CoGuestStoreLiveSeatStore 及其相关类的所有公开接口、属性和方法的详细信息,请参阅 AtomicXCore 框架的官方 API 文档。本指南使用到的相关 Store 如下:
Store/Component
功能描述
API 文档
CoGuestStore
观众连麦管理:连麦申请 / 邀请 / 同意 / 拒绝,连麦成员权限控制(麦克风 / 摄像头),状态同步。
LiveSeatStore
麦位管理:静音/解除静音,锁定/解锁麦位,踢人下麦、远程控制麦上用户麦克风,麦列表状态监听

常见问题

语音房连麦和视频直播连麦的实现有何不同?

两者的主要区别在于业务形态与 UI 展现:
视频直播:核心是视频画面。您会使用 LiveCoreView 作为核心组件来渲染主播和连麦观众的视频流。UI 的重点是处理视频画面的布局、大小,以及通过 VideoViewAdapter 在视频流上添加挂件(例如昵称、占位图)。您可以同时打开摄像头,麦克风。
语音房(语聊房):核心是麦位网格。您不会使用 LiveCoreView,而是会基于 LiveSeatStorestate(特别是 seatList)来构建一个网格 UI(例如 RecyclerView)。UI 的重点是实时显示每个麦位 SeatInfo 的状态:是否有人、是否静音、是否被锁定 ,以及是否正在说话。您只需要打开麦克风。

如何在 UI 上实时刷新麦位信息(例如是否有人、是否静音)?

您应该订阅 LiveSeatState 中的 seatList 属性,它是一个 List<SeatInfo> 数组类型的响应式数据,每当数组变化时都会通知您重新渲染麦位列表。遍历此数组,您可以:
通过 seatInfo.userInfo 来获取麦位上用户信息。
通过 seatInfo.isLocked 判断麦位是否被锁定。
通过 seatInfo.userInfo.microphoneStatus 判断麦上用户的麦克风状态。

LiveSeatStore 和 DeviceStore 都有麦克风接口,它们有何区别?

这是一个非常重要的问题。DeviceStore 管理的是物理设备,而 LiveSeatStore 管理的是麦位业务(即音频流)。
DeviceStore
openLocalMicrophone:向系统请求权限并启动麦克风设备进行音频采集。这是一个“重”操作。
closeLocalMicrophone:停止音频采集并释放麦克风设备。
LiveSeatStore
muteMicrophone:静音。停止向远端发送本地的音频流,但麦克风设备本身仍在运行。
unmuteMicrophone:解除静音。恢复向远端发送音频流。
推荐的工作流程:您应该遵循“设备只开一次,麦上只用静音切换”的原则
1. 上麦时:当观众成功上麦,调用一次 openLocalMicrophone来启动设备。
2. 在麦上时:用户在麦位上所有的“开麦”和“闭麦”操作,都应该调用 unmuteMicrophonemuteMicrophone来控制上行音频流的通断。
3. 下麦时:当用户下麦(例如调用 disconnect),调用closeLocalMicrophone来释放设备。


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈