`RoomParticipantStore` 是 `AtomicXCore` 中专用于房间参与者管理的模块。该模块为多人房间场景提供了核心能力，支持构建完整的成员管理体系。

## 房间模式说明

在开始使用成员管理功能之前，需要了解 `AtomicXCore` 中房间模块支持的两种房间模式，不同模式下的成员管理功能有所区别：
| **标准房间模式（Standard Room）** | **网络研讨会房间模式（Webinar Room）** |
| --- | --- |
| - **适用场景：**小型会议、团队协作、朋友聊天等。<br>- **成员特点：**所有成员都是参与者，可以自由开启/关闭音视频设备。<br>- **管理特点：**扁平化管理，房主可设置管理员进行协助管理。 | - **适用场景**：网络研讨会、在线培训等。<br>- **成员特点**：<br>- **嘉宾（Participants）**：可以开启音视频设备，参与互动。<br>- **观众（Audience）**：只能观看，无法开启音视频设备。<br>- **管理特点**：分层管理，支持观众与嘉宾身份转换。 |

## 核心功能
- **获取参与者列表**：获取并展示当前房间内所有参与者信息（网络研讨会房间模式下，获取到的是嘉宾列表，嘉宾可以开启麦克风与其他嘉宾互动）。

- **获取观众列表：**网络研讨会房间模式下，获取观众列表信息。

- **搜索房间内成员：**搜索所在房间内的指定用户。

- **将观众提升为嘉宾：**网络研讨会房间模式下，可以将观众提升为嘉宾，提升为嘉宾的用户可以开启麦克风与房间内其他的嘉宾互动。

- **将嘉宾降级为观众：**网络研讨会房间模式下，可以将嘉宾降级为观众， 降级为观众的用户无法与房间内的嘉宾进行语音互动。

- **转移房主身份**：房主可以将房主身份转移给房间内任意一名参与者。

- **设置/撤销管理员**：房主可以设置参与者为管理员，同时也可撤销房间内的管理员。

- **将参与者移出房间**：房主或者管理员可以将房间内任意一名参与者移出房间。

- **参与者信息更新**：房间内所有人都可以更新自己的参与者信息。

- **音视频设备管理**：支持申请/邀请打开摄像头、麦克风，关闭远端摄像头、麦克风，以及房主和管理员设置全体静音，全体禁画功能。

## 功能对比
| **功能** | **标准房间模式** | **网络研讨会房间模式** |
| --- | --- | --- |
| 获取参与者列表 | 获取所有房间成员 | 获取嘉宾列表 |
| 获取观众列表 | 不适用 | 获取观众列表 |
| 搜索房间内成员 | 支持 | 支持 |
| 将观众提升为嘉宾 | 不适用 | 支持 |
| 将嘉宾降级为观众 | 不适用 | 支持 |
| 转移房主身份 | 支持 | 支持 |
| 设置/撤销管理员 | 支持 | 支持 |
| 移出房间 | 支持 | 支持 |
| 更新参与者信息 | 支持 | 支持 |
| 音视频设备管理 | 支持 | 支持 |

## 核心概念

在开始集成之前，需要通过下表了解一下`RoomParticipantStore`相关的几个核心概念：
| **核心概念** | **类型** | **核心职责与描述** |
| --- | --- | --- |
| [RoomParticipant](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.room/-room-participant/index.html) | `data class` | 代表参与者的核心数据模型，封装了参与者的完整信息和状态管理能力。<br>**标准房间模式：**代表房间内的所有成员。<br>**网络研讨会房间模式：**代表嘉宾，可以开启/关闭麦克风。<br>核心功能包括：参与者基本信息管理（用户 ID 、用户名称、用户头像、房间内角色身份）、参与者设备状态管理（麦克风状态，摄像头状态，屏幕分享状态，消息状态）。 |
| [RoomParticipantState](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.room/-room-participant-state/index.html) | `data class` | 代表参与者状态管理的核心数据结构，负责维护房间内与参与者相关状态信息。<br>核心属性：<br>- `participantList`**标准房间模式**存储所有房间成员，**网络研讨会房间模式**存储嘉宾列表。<br>- `participantListCursor`**标准房间模式**代表房间内所有成员列表的分页游标，**网络研讨会房间模式**代表房间内嘉宾列表的分页游标。<br>- `localParticipant` 代表自身所在房间内的参与者信息。 |
| [RoomParticipantListener](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.room/-room-participant-listener/index.html) | `abstract class` | 代表房间内和参与者相关的实时事件。主要事件分为三大类：参与者进退房事件、 参与者身份改变事件，参与者设备控制事件。 |
| [RoomParticipantStore](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.room/-room-participant-store/index.html) | `abstract class` | 这是参与者控制相关的核心类。功能包含：控制房间内参与者音视频状态、执行参与者管理操作，并通过订阅其 `RoomParticipantListener` 来接收实时事件。 |

## 实现步骤

### 步骤1：组件集成

请参考 接入概览 集成 **AtomicXCore SDK**，并已完成 实现登录逻辑 部分接入。

### 步骤2：获取参与者列表

在加入房间后，调用 `RoomParticipantStore` 的 `getParticipantList` 接口获取到房间内参与者列表。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipant
import io.trtc.tuikit.atomicxcore.api.ListResultCompletionHandler

fun getParticipantList() {
    // 1. 业务逻辑说明
    // 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
    val roomID = "test_room_001"
    val participantStore = RoomParticipantStore.create(roomID)

    // 2. 首次获取参与者列表（从头开始）
    // 支持分页加载，可以通过 cursor 参数实现增量获取
    val initialCursor: String? = null  // null 表示从第一页开始获取

    participantStore.getParticipantList(initialCursor, object : ListResultCompletionHandler<RoomParticipant> {
        override fun onSuccess(result: List<RoomParticipant>, cursor: String) {
            Log.d("Participant", "成功获取参与者列表，数量: ${result.size}")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "获取参与者列表失败 [错误码: $code]: $desc")
        }
    })
}
```

### 步骤3：获取观众列表

在进入的房间类型为`WEBINAR`类型时，可以通过调用`RoomParticipantStore`的`getAudienceList`接口获取房间内的观众列表。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.ListResultCompletionHandler
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

fun getAudienceList() {
    // 前提：需要先完成进房操作, 并且进房时 roomType 设置为 WEBINAR 类型。
    // 1. 业务逻辑说明
    // 通过进房的roomID创建RoomParticipantStore实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 首次获取观众列表（从头开始）
    // 支持分页加载，可以通过 cursor 参数实现增量获取
    val initialCursor: String? = null  // null 表示从第一页开始获取

    participantStore.getAudienceList(cursor = initialCursor, completion = object : ListResultCompletionHandler<RoomUser> {
        override fun onSuccess(result: List<RoomUser>, cursor: String) {
            Log.d("Test", "获取观众列表成功，观众数量: ${result.size}")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Test", "获取观众列表失败 [错误码: $code]: $desc")
        }
    })
}
```

### 步骤4：搜索房间内成员

进入房间成功后，可以通过调用`RoomParticipantStore`的`searchUsers`接口搜索房间内的成员。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.ListResultCompletionHandler
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

fun searchUsers() {
    // 前提：需要先完成进房操作。
    // 1. 业务逻辑说明
    // 通过进房的roomID创建RoomParticipantStore实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 通过用户名称为关键字搜索房间内成员
    val keyword = "userName"

    participantStore.searchUsers(keyword = keyword, completion = object : ListResultCompletionHandler<RoomUser> {
        override fun onSuccess(result: List<RoomUser>, cursor: String) {
            Log.d("Test", "搜索房间成员成功，成员数量: ${result.size}")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Test", "搜索房间成员失败 [错误码: $code]: $desc")
        }
    })
}
```

### 步骤5：将**观众提升为嘉宾**

网络研讨会房间模式下，作为房主或管理员，调用`RoomParticipantStore`的`promoteAudienceToParticipant`接口可以将房间内的观众提升成为嘉宾。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

fun promoteAudienceToParticipant(userID: String) {
    // 前提：需要先完成进房操作。
    // 1. 业务逻辑说明
    // 通过进房的 roomID 创建 RoomParticipantStore 实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 调用 RoomParticipantStore 提升观众为嘉宾接口
    // 注意：只有房主或管理员才有权限执行此操作。
    participantStore.promoteAudienceToParticipant(userID = userID, completion = object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Test", "提升为嘉宾成功")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Test", "提升为嘉宾失败 [错误码: $code]: $desc")
        }
    })
}
```

作为房间内成员订阅`RoomParticipantStore`的`RoomParticipantListener`中的`onAudiencePromotedToParticipant`事件，被动接收观众提升为嘉宾的变化通知。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

fun subscribeParticipantEvent() {
    // 1. 业务逻辑说明
    // 前提：需要先完成进房操作,通过进房的 roomID 创建 RoomParticipantStore 实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 订阅参与者事件
    // 通过添加 RoomParticipantListener 监听所有参与者相关的事件
    val listener = object : RoomParticipantListener() {
        override fun onAudiencePromotedToParticipant(userInfo: RoomUser) {
            Log.d("Test", "观众被提升为嘉宾，userInfo: $userInfo")
        }
    }

    participantStore.addRoomParticipantListener(listener)

    // 注意：在不需要监听时，记得移除监听器
    // participantStore.removeRoomParticipantListener(listener)
}

```

### 步骤6：将**嘉宾降级为观众**

网络研讨会房间模式下，作为房主或管理员，调用`RoomParticipantStore`的`demoteParticipantToAudience`接口可以将房间内的嘉宾降级成为观众。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

fun demoteParticipantToAudience(userID: String) {
    // 前提：需要先完成进房操作。
    // 1. 业务逻辑说明
    // 通过进房的 roomID 创建 RoomParticipantStore 实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 调用 RoomParticipantStore 降级嘉宾为观众接口
    // 注意：只有房主或管理员才有权限执行此操作。
    participantStore.demoteParticipantToAudience(userID = userID, completion = object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Test", "降级为观众成功")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Test", "降级为观众失败 [错误码: $code]: $desc")
        }
    })
}
```

作为房间内成员订阅`RoomParticipantStore`的`RoomParticipantListener`中的`onParticipantDemotedToAudience`事件，被动接收嘉宾降级为观众的变化通知。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

fun subscribeParticipantEvent() {
    // 1. 业务逻辑说明
    // 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
    val participantStore = RoomParticipantStore.create(roomID = "your_room_id")

    // 2. 订阅参与者事件
    // 通过添加 RoomParticipantListener 监听所有参与者相关的事件
    val listener = object : RoomParticipantListener() {
        override fun onParticipantDemotedToAudience(userInfo: RoomUser) {
            Log.d("Test", "嘉宾被降级为观众，userInfo: $userInfo")
        }
    }

    participantStore.addRoomParticipantListener(listener)

    // 注意：在不需要监听时，记得移除监听器
    // participantStore.removeRoomParticipantListener(listener)
}
```

### 步骤7：转移房主身份

作为房主，调用 `RoomParticipantStore` 的 `transferOwner` 接口可以将房主身份直接转移给房间内任意一位参与者，转移后原房主身份将变为普通参与者，一个房间内有且仅有一名房主。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

fun transferOwner(userID: String) {
    // 1. 业务逻辑说明
    // 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
    val roomID = "test_room_001"
    val participantStore = RoomParticipantStore.create(roomID)

    // 2. 调用 RoomParticipantStore 转移房主接口
    // 注意：只有当前房主才有权限执行此操作，转移后原房主将变为普通用户
    participantStore.transferOwner(userID, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "房主权限转移成功，新房主: $userID")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "转移房主权限失败 [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，订阅 `RoomParticipantStore` 的 `RoomParticipantListener` 中的 `onOwnerChanged` 事件，被动接收房主变化通知。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 参与者事件监听器
private val participantListener = object : RoomParticipantListener() {
    override fun onOwnerChanged(newOwner: RoomUser, oldOwner: RoomUser) {
        Log.d("Participant", "房主变更通知，newOwner: $newOwner, oldOwner: $oldOwner")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvent() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

### 步骤8：设置/撤销管理员

作为房主，调用 `RoomParticipantStore` 的 `setAdmin` 接口，指定房间内任意一位用户为管理员，也可以将管理员身份撤销。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 设置用户为管理员
fun setUserAsAdmin(userID: String) {
    participantStore.setAdmin(userID, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "成功设置用户 $userID 为管理员")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "设置管理员失败 [错误码: $code]: $desc")
        }
    })
}

// 撤销用户的管理员权限
fun revokeAdmin(userID: String) {
    participantStore.revokeAdmin(userID, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "成功撤销用户 $userID 的管理员权限")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "撤销管理员失败 [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，订阅 `RoomParticipantStore` 的 `RoomParticipantListener` 中的 `onAdminSet` 和 `onAdminRevoked` 事件，被动接收参与者身份变化通知。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 参与者事件监听器
private val participantListener = object : RoomParticipantListener() {
    override fun onAdminSet(userInfo: RoomUser) {
        Log.d("Participant", "设置管理员事件通知，userInfo: $userInfo")
    }

    override fun onAdminRevoked(userInfo: RoomUser) {
        Log.d("Participant", "撤销管理员事件通知，userInfo: $userInfo")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvents() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

### 步骤9：**将参与者移出房间**

作为房主和管理员，调用 `RoomParticipantStore` 的 `kickUser` 可以将房间内参与者移出房间。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun kickUser(userID: String) {
    // 1. 业务逻辑说明
    // kickUser 接口用于将指定用户移出房间
    // 注意：只有房主或管理员才有权限执行此操作
    // 被移出的用户将立即离开房间，并收到相应的通知

    // 2. 调用 RoomParticipantStore 移出用户接口
    participantStore.kickUser(userID, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "用户移出成功，被移出用户: $userID")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "移出用户失败 [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，订阅 `RoomParticipantStore` 的 `RoomParticipantListener` 中的 `onKickedFromRoom` 事件，被动接收参与者被移出房间通知。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.KickedOutOfRoomReason
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

private val participantListener = object : RoomParticipantListener() {
    override fun onKickedFromRoom(reason: KickedOutOfRoomReason, message: String) {
        Log.d("Participant", "已被移出房间，被移出原因：$reason, 额外信息：$message")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvents() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

### 步骤10：更新参与者信息

在加入房间后，调用 `RoomParticipantStore` 的 `updateParticipantNameCard`、 `updateParticipantMetaData` 更新您在房间里的参与者信息，包含：参与者名片信息，参与者自定义信息。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun updateParticipantNameCard(userID: String, nameCard: String) {
    // 1. 业务逻辑说明
    // updateParticipantNameCard 接口用于更新指定参与者的名片信息
    // 名片通常用于显示用户的自定义昵称或标识
    // 注意：通常只有管理员或用户本人才能修改名片

    // 2. 调用 RoomParticipantStore 更新名片接口
    participantStore.updateParticipantNameCard(userID, nameCard, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "名片更新成功，用户: $userID, 新名片: $nameCard")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "名片更新失败 [错误码: $code]: $desc")
        }
    })
}

fun updateParticipantMetaData(userID: String, metaData: HashMap<String, ByteArray>) {
    // 1. 业务逻辑说明
    // updateParticipantMetaData 接口用于更新指定参与者的自定义信息
    // 存储自定义的业务数据，如用户标签、扩展属性等
    // 注意：自定义信息的键值对数量和大小有限制，键长度不能超过 50 字节，值长度不超过 200 字节

    // 2. 调用 RoomParticipantStore 更新自定义信息接口
    participantStore.updateParticipantMetaData(userID, metaData, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "自定义信息数据更新成功，用户: $userID, 键数量: ${metaData.size}")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "自定义信息更新失败 [错误码: $code]: $desc")
        }
    })
}
```

### 步骤11：邀请参与者打开其设备

作为房主和管理员，调用 `RoomParticipantStore` 的 `inviteToOpenDevice` 接口，邀请房间内参与者打开摄像头，麦克风。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun inviteUserToOpenDevice(userID: String, device: DeviceType, timeout: Int = 30) {
    // 1. 业务逻辑说明
    // inviteToOpenDevice 接口用于邀请指定用户开启某个设备
    // 通常用于管理员邀请参与者开启麦克风、摄像头或屏幕共享
    // 被邀请的用户会收到邀请通知，可以选择接受或拒绝

    // 2. 调用 RoomParticipantStore 邀请开启设备接口
    participantStore.inviteToOpenDevice(userID, device, timeout, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "设备邀请发送成功，用户: $userID, 设备: $device")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "设备邀请发送失败 [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，需要：
- 订阅 `RoomParticipantStore` 的 `RoomParticipantListener` 中的 `onDeviceInvitationReceived` 事件，被动接收邀请打开设备通知。

- 接收到邀请打开设备通知后调用 `RoomParticipantStore` 的 `acceptOpenDeviceInvitation` 或者 `declineOpenDeviceInvitation` 接口接受或拒绝邀请。

   ``` java
   import android.util.Log
   import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
   import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
   import io.trtc.tuikit.atomicxcore.api.room.DeviceRequestInfo
   import io.trtc.tuikit.atomicxcore.api.device.DeviceType
   import io.trtc.tuikit.atomicxcore.api.CompletionHandler

   // 业务逻辑说明
   // 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
   private val roomID = "test_room_001"
   private val participantStore = RoomParticipantStore.create(roomID)

   // 参与者事件监听器
   private val participantListener = object : RoomParticipantListener() {
       override fun onDeviceInvitationReceived(invitation: DeviceRequestInfo) {
           Log.d("Participant", "收到设备邀请 - 设备: ${invitation.device}, 发送者: ${invitation.senderUserName}")
           // 处理接受、拒绝设备邀请
       }
   }

   // 订阅参与者相关事件
   private fun subscribeParticipantEvents() {
       participantStore.addRoomParticipantListener(participantListener)
   }

   fun acceptOpenDeviceInvitation(userID: String, device: DeviceType) {
       // 处理接受邀请
       participantStore.acceptOpenDeviceInvitation(userID, device, object : CompletionHandler {
           override fun onSuccess() {
               Log.d("Participant", "接受设备邀请成功 - 设备: $device")
           }

           override fun onFailure(code: Int, desc: String) {
               Log.e("Participant", "接受设备邀请失败 [错误码: $code]: $desc")
           }
       })
   }

   fun declineOpenDeviceInvitation(userID: String, device: DeviceType) {
       // 处理拒绝邀请
       participantStore.declineOpenDeviceInvitation(userID, device, object : CompletionHandler {
           override fun onSuccess() {
               Log.d("Participant", "拒绝设备邀请成功 - 设备: $device")
           }

           override fun onFailure(code: Int, desc: String) {
               Log.e("Participant", "拒绝设备邀请失败 [错误码: $code]: $desc")
           }
       })
   }
   ```

### 步骤12：关闭远端参与者设备

作为房主和管理员，调用`RoomParticipantStore`的`closeParticipantDevice`可以主动关闭远端参与者的摄像头，麦克风。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun closeParticipantDevice(userID: String, device: DeviceType) {
    // 1. 业务逻辑说明
    // closeParticipantDevice 接口用于房主或管理员关闭指定参与者的某个设备
    // 被关闭的用户会收到设备被关闭通知

    // 2. 调用 RoomParticipantStore 关闭参与者设备接口
    participantStore.closeParticipantDevice(userID, device, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "关闭参与者设备成功 - 用户: $userID, 设备: $device")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "关闭参与者设备失败: [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，订阅`RoomParticipantStore`的`RoomParticipantListener`中的`onParticipantDeviceClosed`事件，被动接收设备被关闭通知，并在UI上做出提示。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 参与者事件监听器
private val participantListener = object : RoomParticipantListener() {
    override fun onParticipantDeviceClosed(device: DeviceType, operator: RoomUser) {
        Log.d("Participant", "设备被关闭 - 设备: $device, 操作者: ${operator.userName}")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvents() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

### 步骤13：参与者申请打开自己的设备

作为参与者，调用`RoomParticipantStore`的`requestToOpenDevice`接口，可以在房间被房主或管理员设置全体静音，全体禁画的场景下，主动申请打开摄像头，麦克风。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun requestToOpenDevice(device: DeviceType, timeout: Int = 30) {
    // 1. 业务逻辑说明
    // requestToOpenDevice 接口用于请求开启某个设备
    // 通常用于参与者申请开启麦克风、摄像头或屏幕共享
    // 房主和管理员会收到申请通知，可以选择同意或拒绝

    // 2. 调用 RoomParticipantStore 请求开启设备接口
    participantStore.requestToOpenDevice(device, timeout, object : CompletionHandler {
        override fun onSuccess() {
            Log.d("Participant", "设备开启请求发送成功 - 设备: $device")
        }

        override fun onFailure(code: Int, desc: String) {
            Log.e("Participant", "设备开启请求发送失败 [错误码: $code]: $desc")
        }
    })
}
```

作为房主和管理员，需要：
- 订阅`RoomParticipantStore`的`RoomParticipantListener`中的`onDeviceRequestReceived`事件，被动接收申请打开设备通知。

- 接收到申请打开设备通知后，调用`RoomParticipantStore`的`approveOpenDeviceRequest`或者`rejectOpenDeviceRequest`接口，批准或者拒绝申请。

   ``` java
   import android.util.Log
   import io.trtc.tuikit.atomicxcore.api.CompletionHandler
   import io.trtc.tuikit.atomicxcore.api.device.DeviceType
   import io.trtc.tuikit.atomicxcore.api.room.DeviceRequestInfo
   import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
   import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore

   // 业务逻辑说明
   // 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
   private val roomID = "test_room_001"
   private val participantStore = RoomParticipantStore.create(roomID)

   // 参与者事件监听器
   private val participantListener = object : RoomParticipantListener() {
       override fun onDeviceRequestReceived(request: DeviceRequestInfo) {
           Log.d("Participant", "收到设备请求 - 用户: ${request.senderUserName}, 设备: ${request.device}")
           // 批准、拒绝开启设备请求操作
       }
   }

   // 订阅参与者相关事件
   private fun subscribeParticipantEvents() {
       participantStore.addRoomParticipantListener(participantListener)
   }

   fun approveOpenDeviceRequest(device: DeviceType, userID: String) {
       // 批准开启请求
       participantStore.approveOpenDeviceRequest(device, userID, object : CompletionHandler {
           override fun onSuccess() {
               Log.d("Participant", "批准设备请求成功 - 用户: $userID, 设备: $device")
           }

           override fun onFailure(code: Int, desc: String) {
               Log.e("Participant", "批准设备请求失败: $desc")
           }
       })
   }

   fun rejectOpenDeviceRequest(device: DeviceType, userID: String) {
       // 拒绝开启请求
       participantStore.rejectOpenDeviceRequest(device, userID, object : CompletionHandler {
           override fun onSuccess() {
               Log.d("Participant", "拒绝设备请求成功 - 用户: $userID, 设备: $device")
           }

           override fun onFailure(code: Int, desc: String) {
               Log.e("Participant", "拒绝设备请求失败: [错误码: $code]: $desc")
           }
       })
   }
   ```

### 步骤14：全体静音、全体禁画

作为房主和管理员，调用`RoomParticipantStore`的`disableAllDevices`接口设置全员静音与全员禁用摄像头。开启后，房间内参与者的音视频开启权限将被限制，无法自主打开麦克风或摄像头设备。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.CompletionHandler

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

fun disableAllDevices(device: DeviceType, disable: Boolean) {
    // 1. 业务逻辑说明
    // disableAllDevices 接口用于房主或管理员设置房间禁用、解禁房间内全体成员麦克风，摄像头
    // 设置后房间内参与者会收到禁用、解禁通知

    // 2. 调用 RoomParticipantStore 禁用、解禁全体设备接口
    participantStore.disableAllDevices(device, disable, object : CompletionHandler {
        override fun onSuccess() {
            val action = if (disable) "禁用" else "启用"
            Log.d("Participant", "${action}所有${device}成功")
        }

        override fun onFailure(code: Int, desc: String) {
            val action = if (disable) "禁用" else "启用"
            Log.e("Participant", "${action}所有${device}失败 [错误码: $code]: $desc")
        }
    })
}
```

作为参与者，订阅 `RoomParticipantStore`的`RoomParticipantListener`中的`onAllDevicesDisabled`事件，可以监听全员静音或禁画指令，并在 UI 界面同步受控状态。受限状态下，摄像头与麦克风的主动开启功能将被锁定，参与者需发起开启申请，待房主或管理员核准授权后方可使用。
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.device.DeviceType
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 参与者事件监听器
private val participantListener = object : RoomParticipantListener() {
    override fun onAllDevicesDisabled(device: DeviceType, disable: Boolean, operator: RoomUser) {
        val action = if (disable) "禁用" else "启用"
        Log.d("Participant", "所有${device}被${action} - 操作者: ${operator.userName}")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvents() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

### 步骤15：监听参与者事件

订阅`RoomParticipantListener`参与者相关的被动事件。以订阅参与者加入房间、离开房间为例，示例代码如下：
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantListener
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import io.trtc.tuikit.atomicxcore.api.room.RoomUser

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

// 参与者事件监听器
private val participantListener = object : RoomParticipantListener() {
    override fun onParticipantJoined(participant: RoomUser) {
        Log.d("Participant", "参与者加入房间 - 用户: ${participant.userName}, ID: ${participant.userID}")
    }

    override fun onParticipantLeft(participant: RoomUser) {
        Log.d("Participant", "参与者离开房间 - 用户: ${participant.userName}, ID: ${participant.userID}")
    }
}

// 订阅参与者相关事件
private fun subscribeParticipantEvents() {
    participantStore.addRoomParticipantListener(participantListener)
}
```

订阅`RoomParticipantState`参与者相关的属性状态变化。以订阅房间内正在说话的用户为例，示例代码如下：
``` java
import android.util.Log
import io.trtc.tuikit.atomicxcore.api.room.RoomParticipantStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

// 业务逻辑说明
// 前提：需要先完成进房操作,通过进房的roomID创建RoomParticipantStore实例
private val roomID = "test_room_001"
private val participantStore = RoomParticipantStore.create(roomID)

/// 设置参与者状态监听
private fun subscribeParticipantState() {
    CoroutineScope(Dispatchers.Main).launch {
        participantStore.state.speakingUsers.collect { speakingUsers ->
            Log.d("Participant", "说话用户状态变更 - 当前说话用户数: ${speakingUsers.size}")
        }
    }
}
```

## API 文档
| **Store/Component** | **功能描述** | **API文档** |
| --- | --- | --- |
| **RoomParticipantStore** | 房间内参与者管理：设置管理员 / 转移房主 / 获取参与者列表 / 移出房间 / 参与者设备控制（例如关闭、邀请打开摄像头、麦克风等）/ 申请打开设备（例如申请打开摄像头、麦克风等）。 | [API 文档](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.room/-room-participant-store/index.html) |
