`RoomStore` 是 `AtomicXCore` 中专职房间事务管理的模块，深度集成了会中呼叫能力。本章节旨在指导如何利用 `RoomStore` 高效完成会中呼叫相关功能的开发与接入。

## 核心功能
- **会中呼叫**：房间内任意参与者均可呼叫房间外任意成员加入房间。

- **获取会中呼叫用户列表**：可以获取指定房间的会中呼叫的用户列表。

## 核心概念

在开始集成之前，需要通过下表了解一下`RoomStore`中与会中呼叫相关的几个核心概念：
| **核心概念** | **类型** | **核心职责与描述** |
| --- | --- | --- |
| [RoomCallStatus](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomcallstatus) | `enum` | 代表会中呼叫的状态，包含：<br>- `none`（默认态）。<br>- `calling`（呼叫中）。<br>- `timeout`（呼叫超时）。<br>- `rejected`（呼叫被拒绝）。 |
| [RoomCallResult](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomcallresult) | `enum` | 代表会中呼叫的结果，包含：<br>- `success`（呼叫成功）。<br>- `alreadyInCalling`（已在呼叫中）。<br>- `alreadyInRoom`（已在房间中）。 |
| [CallRejectionReason](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callrejectionreason) | `enum` | 代表呼叫被拒绝的原因，目前仅支持：<br>- `rejected`（主动拒绝）。<br>- `inOtherRoom`（在其他房间中）。 |
| [RoomCall](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomcall) | `struct` | 代表会中呼叫业务的核心数据结构。负责存储呼叫者信息、被呼叫者信息、以及当前呼叫状态。 |
| [RoomEvent](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent) | `enum` | 代表房间动态的实时事件。其中包含会中呼叫相关的事件。 |
| [RoomStore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomstore) | `class` | 这是与房间全生命周期相关的核心类。功能包含：发起会中呼叫，响应会中呼叫，获取房间的会中呼叫列表，并通过订阅其 `roomEventPublisher` 来接收与会中呼叫相关的实时动态事件。 |

## 实现步骤

### 步骤1：组件集成

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

### 步骤2：呼叫方功能

#### **1. 发起呼叫**

作为呼叫方调用`RoomStore`的`callUserToRoom`接口，可以批量呼叫用户进房。
``` swift
import Foundation
import AtomicXCore

// 发起呼叫
func callUserToRoom(userIDList: [String], timeout: Int = 30, extensionInfo: String? = nil) {
    RoomStore.shared.callUserToRoom(roomID: "roomID", userIDList: userIDList, timeout: timeout, extensionInfo: extensionInfo) { result in
        switch result {
        case .success(let callResults):
            print("呼叫用户请求发送成功")
        case .failure(let error):
            print("呼叫用户失败: [错误码: \(error.code)]: \(error.message)")
        }
    }
}
```

#### **2. 取消呼叫**

作为呼叫方调用`RoomStore`的`cancelCall`接口，可以批量取消正在呼叫申请。
``` swift
import Foundation
import AtomicXCore

// 取消呼叫
func cancelCall(userIDList: [String]) {
    RoomStore.shared.cancelCall(roomID: "roomID", userIDList: userIDList) { result in
        switch result {
        case .success():
            print("取消呼叫成功")
        case .failure(let error):
            print("取消呼叫失败: [错误码: \(error.code)]: \(error.message)")
        }
    }
}
```

#### **3. 获取呼叫列表信息**

进入房间后，调用`RoomStore`的`getPendingCalls`接口，可以分页查询当前房间正在呼叫的用户列表信息。
``` swift
import Foundation
import AtomicXCore

// 获取待处理的呼叫列表
func getPendingCalls(roomID: String, cursor: String?) {
    // cursor 为分页游标，首次调用时传入 null，获取第一页数据， 后续调用时传入上次返回的 nextCursor 值。
    RoomStore.shared.getPendingCalls(roomID: roomID, cursor: cursor) { result in
        switch result {
        case .success(let callInfo):
            print("获取呼叫列表成功，列表信息: \(callInfo.0), 分页游标: \(callInfo.1)")
        case .failure(let error):
            print("获取呼叫列表失败: [错误码: \(error.code)]: \(error.message)")
        }
    }
}
```

#### **4. 订阅会中呼叫事件**

作为呼叫方订阅 `RoomStore` 的 `roomEventPublisher` 能够实时获取呼叫的生命周期事件。通过监听以下回调，可以精准捕捉呼叫的最终结果并据此更新 UI 状态或执行后续业务逻辑。
``` swift
import Combine
import AtomicXCore
import Foundation

private var cancellableSet = Set<AnyCancellable>()

/// 订阅会中呼叫相关事件
private func subscribeRoomCallEvents() {
    RoomStore.shared.roomEventPublisher
        .receive(on: DispatchQueue.main)
        .sink { event in
            switch event {
            case .onCallTimeout(let roomInfo, let call):
                print("呼叫超时 房间信息: \(roomInfo), 呼叫者: \(call.caller)")
            case .onCallAccepted(let roomInfo, let call):
                print("呼叫已被接受 房间信息: \(roomInfo), 被呼叫者: \(call.callee)")
            case .onCallRejected(let roomInfo, let call, let reason):
                print("呼叫被拒绝 房间信息: \(roomInfo), 被呼叫者: \(call.callee), 拒绝原因: \(reason)")
            case .onCallHandledByOtherDevice(let roomInfo, let isAccepted):
                print("呼叫已被其他设备处理 房间信息: \(roomInfo) 处理结果: \(isAccepted)")
            default:
                // 处理其他非呼叫相关事件
                break
            }
        }
        .store(in: &cancellableSet)
}
```

**呼叫事件函数详细说明**
| 事件函数 | 触发时机与说明 |
| --- | --- |
| [onCallTimeout](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncalltimeout(roominfo:call:)) | 呼叫超时。当呼叫请求在预设的时间内（由调用 callUserToRoom 时指定）未得到被呼叫方的响应时触发。此时，呼叫自动结束，呼叫方通常需要提示“对方无人接听”。 |
| [onCallAccepted](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallaccepted(roominfo:call:)) | 呼叫被接受。被呼叫方主动点击了“接听”或“接受”按钮。收到此回调后，表示双方已达成呼叫意图，呼叫方通常应立即执行进入房间或开始推流的操作。 |
| [onCallRejected](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallrejected(roominfo:call:reason:)) | 呼叫被拒绝。被呼叫方主动拒绝了通话请求，或者因为被呼叫方当前正处于其他房间中而自动拒绝。回调中通常包含拒绝原因（如主动拒绝或在其他房间中）。 |
| [onCallHandledByOtherDevice](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallhandledbyotherdevice(roominfo:isaccepted:)) | 呼叫已在其他设备处理。当用户在多个设备（例如手机和 iPad）同时登录时，如果呼叫已在其中一台设备上被处理（接受或拒绝），当前设备会收到此通知，用于同步 UI 状态并自动消除呼叫界面。 |

### 步骤3：被呼叫方功能

#### **1. 订阅会中呼叫事件**

作为被呼叫方订阅 `RoomStore` 的 `roomEventPublisher` 可以实时监听并响应来自呼叫方的呼叫行为。以下是构建呼叫提醒界面以及维护呼叫链路状态的关键事件。
``` swift
import Combine
import AtomicXCore
import Foundation

private var cancellableSet = Set<AnyCancellable>()

/// 订阅会中呼叫相关事件
private func subscribeRoomCallEvents() {
    RoomStore.shared.roomEventPublisher
        .receive(on: DispatchQueue.main)
        .sink { [weak self] event in
            guard let self = self else { return }
            switch event {
            case .onCallReceived(let roomInfo, let call, let extensionInfo):
                print("收到房间呼叫 房间信息: \(roomInfo), 呼叫者: \(call.caller), 扩展信息: \(extensionInfo)")
            case .onCallCancelled(let roomInfo, let call):
                print("呼叫被取消 房间信息: \(roomInfo), 呼叫者: \(call.caller)")
            case .onCallRevokedByAdmin(let roomInfo, let call, let operatorUser):
                print("呼叫被管理员移除 房间信息: \(roomInfo), 呼叫者: \(call.caller), 移除操作者: \(operatorUser)")
            default:
                // 处理其他非呼叫相关事件
                break
            }
        }
        .store(in: &cancellableSet)
}
```

**事件函数详细说明**
| 事件函数 | 触发时机与说明 |
| --- | --- |
| [onCallReceived](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallreceived(roominfo:call:extensioninfo:)) | 收到呼叫邀请。当有其他用户向您发起入会邀请时触发。收到此回调后，被呼叫方通常应立即弹出“呼叫提醒”界面，展示呼叫者信息、房间信息，并提供“接听”和“拒绝”按钮。 |
| [onCallCancelled](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallcancelled(roominfo:call:)) | 呼叫被发起方取消。呼叫方在您未做出响应前，主动撤回了呼叫请求。收到此回调后，被呼叫方应立即关闭当前的来电界面，并提示“对方已取消呼叫”，以恢复应用正常操作流程。 |
| [onCallRevokedByAdmin](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomevent/oncallrevokedbyadmin(roominfo:call:operator:)) | 呼叫被管理员撤销。房间管理员或后台系统因权限变更、房间解散等原因强行终止了该笔呼叫邀请。收到此通知后，被呼叫方需立即停止呼叫流程并隐藏相关 UI，处理逻辑通常类似于呼叫被取消。 |

#### **2. 接受呼叫、拒绝呼叫**

作为被呼叫方调用`RoomStore`的`acceptCall`或者`rejectCall`接口，处理接受或者拒绝呼叫邀请。
``` swift
import Combine
import AtomicXCore
import Foundation

private var cancellableSet = Set<AnyCancellable>()

/// 订阅会中呼叫相关事件
private func subscribeRoomCallEvents() {
    RoomStore.shared.roomEventPublisher
        .receive(on: DispatchQueue.main)
        .sink { event in
            switch event {
            case .onCallReceived(let roomInfo, let call, let extensionInfo):
                print("收到房间呼叫 房间信息: \(roomInfo), 呼叫者: \(call.caller), 扩展信息: \(extensionInfo)")
                // 接受、拒绝呼叫邀请操作
            default:
                // 处理其他非呼叫相关事件
                break
            }
        }
        .store(in: &cancellableSet)
}

// 接受呼叫邀请
func acceptCall(roomID: String) {
    RoomStore.shared.acceptCall(roomID: roomID) { result in
        switch result {
        case .success:
            print("接受呼叫成功，房间ID: \(roomID)")
        case .failure(let error):
            print("接受呼叫失败: [错误码: \(error.code)] \(error.message)")
        }
    }
}

// 拒绝呼叫邀请
func rejectCall(roomID: String, reason: CallRejectionReason = .rejected) {
    RoomStore.shared.rejectCall(roomID: roomID, reason: reason) { result in
        switch result {
        case .success:
            print("拒绝呼叫成功，房间ID: \(roomID)")
        case .failure(let error):
            print("拒绝呼叫失败: [错误码: \(error.code)] \(error.message)")
        }
    }
}
```

## API 文档
| **Store/Component** | **功能描述** | **API文档** |
| --- | --- | --- |
| **RoomStore** | 房间全生命周期管理：创建并加入 / 加入 / 离开 / 结束房间 / 更新、获取房间信息 / 预定房间 / 呼叫房间外成员 / 监听房间内被动事件（例如房间解散，房间信息更新等）。 | [API 文档](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/roomstore) |
