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

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

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

## 核心概念

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

## 实现步骤

### 步骤1：组件集成

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

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

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

作为呼叫方调用`RoomStore`的`callUserToRoom`接口，可以批量呼叫用户进房。
``` java
import 'package:atomic_x_core/atomicxcore.dart';

Future<void> callUserToRoom({
  required List<String> userIDList,
  int timeout = 30,
  String? extensionInfo,
}) async {
  final result = await RoomStore.shared.callUserToRoom(
    roomID: "roomID",
    userIDList: userIDList,
    timeout: timeout,
    extensionInfo: extensionInfo,
  );

  if (result.isSuccess) {
    print("呼叫用户请求发送成功");
  } else {
    print("呼叫用户失败: [错误码: ${result.errorCode}]: ${result.errorMessage}");
  }
}
```

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

作为呼叫方调用`RoomStore`的`cancelCall`接口，可以批量取消正在呼叫申请。
``` java
import 'package:atomic_x_core/atomicxcore.dart';

Future<void> cancelCall(List<String> userIDList) async {
  final result = await RoomStore.shared.cancelCall(
    roomID: "roomID",
    userIDList: userIDList,
  );

  if (result.isSuccess) {
    print("取消呼叫成功");
  } else {
    print("取消呼叫失败: [错误码: ${result.errorCode}]: ${result.errorMessage}");
  }
}
```

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

进入房间后，调用`RoomStore`的`getPendingCalls`接口，可以分页查询当前房间正在呼叫的用户列表信息。
``` java
import 'package:atomic_x_core/atomicxcore.dart';

Future<void> getPendingCalls(String roomID, String? cursor) async {
  // cursor 为分页游标，首次调用时传入 null，获取第一页数据，后续调用时传入上次返回的 cursor 值。
  final result = await RoomStore.shared.getPendingCalls(
    roomID: roomID,
    cursor: cursor,
  );

  if (result.isSuccess) {
    print("获取呼叫列表成功，列表信息: ${result.data}, 分页游标: ${result.cursor}");
  } else {
    print("获取呼叫列表失败: [错误码: ${result.errorCode}]: ${result.errorMessage}");
  }
}
```

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

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

late RoomListener _listener;

/// 订阅会中呼叫相关事件
void addRoomCallListener() {
  _listener = RoomListener(
    onCallTimeout: (roomInfo, call) {
      print("呼叫超时 房间信息: ${roomInfo.roomID}, 呼叫者: ${call.caller.userID}");
    },
    onCallAccepted: (roomInfo, call) {
      print("呼叫已被接受 房间信息: ${roomInfo.roomID}, 被呼叫者: ${call.callee.userID}");
    },
    onCallRejected: (roomInfo, call, reason) {
      print("呼叫被拒绝 房间信息: ${roomInfo.roomID}, 被呼叫者: ${call.callee.userID}, 拒绝原因: $reason");
    },
    onCallHandledByOtherDevice: (roomInfo, isAccepted) {
      print("呼叫已被其他设备处理 房间信息: ${roomInfo.roomID}, 处理结果: $isAccepted");
    },
  );

  RoomStore.shared.addRoomListener(_listener);
}

void removeRoomCallListener() {
  RoomStore.shared.removeRoomListener(_listener);
}
```

**呼叫事件函数详细说明**
| 事件函数 | 触发时机与说明 |
| --- | --- |
| [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` 可以实时监听并响应来自呼叫方的呼叫行为。以下是构建呼叫提醒界面以及维护呼叫链路状态的关键事件。
``` java
import 'package:atomic_x_core/atomicxcore.dart';

late RoomListener _listener;

/// 订阅会中呼叫相关事件
void addRoomCallListener() {
  _listener = RoomListener(
    onCallReceived: (roomInfo, call, extensionInfo) {
      print("收到房间呼叫 房间信息: ${roomInfo.roomID}, 呼叫者: ${call.caller.userID}, 扩展信息: $extensionInfo");
    },
    onCallCancelled: (roomInfo, call) {
      print("呼叫被取消 房间信息: ${roomInfo.roomID}, 呼叫者: ${call.caller.userID}");
    },
    onCallRevokedByAdmin: (roomInfo, call, operatorUser) {
      print("呼叫被管理员移除 房间信息: ${roomInfo.roomID}, 呼叫者: ${call.caller.userID}, 移除操作者: ${operatorUser.userID}");
    },
  );

  RoomStore.shared.addRoomListener(_listener);
}

void removeRoomCallListener() {
  RoomStore.shared.removeRoomListener(_listener);
}
```

**事件函数详细说明**
| 事件函数 | 触发时机与说明 |
| --- | --- |
| [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`接口，处理接受或者拒绝呼叫邀请。
``` java
import 'package:atomic_x_core/atomicxcore.dart';

late RoomListener _listener;

/// 订阅会中呼叫相关事件
void addRoomCallListener() {
  _listener = RoomListener(
    onCallReceived: (roomInfo, call, extensionInfo) {
      print("收到房间呼叫 房间信息: ${roomInfo.roomID}, 呼叫者: ${call.caller.userID}, 扩展信息: $extensionInfo");
      // 接受、拒绝呼叫邀请操作
    },
  );

  RoomStore.shared.addRoomListener(_listener);
}

void removeRoomCallListener() {
  RoomStore.shared.removeRoomListener(_listener);
}

// 接受呼叫邀请
Future<void> acceptCall(String roomID) async {
  final result = await RoomStore.shared.acceptCall(roomID);

  if (result.isSuccess) {
    print("接受呼叫成功，房间ID: $roomID");
  } else {
    print("接受呼叫失败: [错误码: ${result.errorCode}] ${result.errorMessage}");
  }
}

// 拒绝呼叫邀请
Future<void> rejectCall(String roomID, {CallRejectionReason reason = CallRejectionReason.rejected}) async {
  final result = await RoomStore.shared.rejectCall(
    roomID: roomID,
    reason: reason,
  );

  if (result.isSuccess) {
    print("拒绝呼叫成功，房间ID: $roomID");
  } else {
    print("拒绝呼叫失败: [错误码: ${result.errorCode}] ${result.errorMessage}");
  }
}
```

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