Android&iOS

最近更新时间:2025-01-22 09:27:42

我的收藏

功能介绍

TUIRoomKit 支持会中呼叫功能。用户在会议进行过程中,可以随时呼叫其他用户加入当前会议,无需提前预定或安排。通过会中呼叫功能,用户可以灵活地邀请或提醒相关人员参与会议,提升会议的互动性和效率。本文将详细介绍该特性的相关功能,并说明如何在 TUIRoomKit 组件中使用这一特性。
呼叫端
被呼叫端







使用说明

呼叫用户

当您在会议中时,您可以通过如下两种方式对未进房的用户进行呼叫:

方式一:呼叫成员列表中的未进入用户

在房间的成员列表中,您会看到一个名为未进入的标题栏。点击未进入,会显示所有当前未进入会议的成员,您可以对这些尚未进入会议的成员进行呼叫。
未进入的列表中包含两类用户:
当前会议在预定时邀请且未进入的成员
已对其进行呼叫但仍未入会的成员




方式二:呼叫通讯录中的用户

默认情况下通讯录中的好友列表使用 IM 的关系链,您也可以通过以下接口设置您自己的通讯录列表不同平台请参考:
Android
iOS

设置通讯录数据

您可以通过 setParticipants 方法设置您的通讯录用户列表。
java
kotlin
List<ConferenceDefine.User> participants = new ArrayList<>();
ConferenceDefine.User user = new ConferenceDefine.User();
user.id = "Jack";
participants.add(user);

ConferenceSession.sharedInstance().setParticipants(participants);
// 获取已选择的用户列表
val participants = bundle.getSerializable(CONFERENCE_PARTICIPANTS) as ConferenceParticipants
val selectedList: ArrayList<User> = participants.selectedList

设置通讯录数据

您可以通过 setParticipants 接口设置您的通讯录用户列表。
Swift
OC
let user = User(userId: "111", userName: "Jack", avatarUrl: "")
ConferenceSession.sharedInstance.setParticipants([user])
User *user = [[User alloc] initWithUserId:@"111" userName:@"Jack" avatarUrl:@""];
[ConferenceSession.sharedInstance setParticipants:@[user]];
通过点击底部栏中的邀请 > 添加成员,您可以唤起通讯录界面,并对其中您所选定的成员进行呼叫。
会中呼叫入口
通讯录页面




说明:
若 TUIRoomKit 的通讯录 UI 不满足您的业务,我们支持您将自己的通讯录 UI 与 TUIRoomKit 关联,请参考:如何设置自定义通讯录

收到呼叫

当您在应用内收到呼叫时,会弹出如下图所示的页面。您可以拖动滑块选择立即加入,或点击暂不进入以拒绝此呼叫。



说明:
当用户已在会议中正在被呼叫时,该用户会自动拒绝所有呼叫。

功能定制

铃声定制

iOS
Android

自定义被呼叫铃声

如果您想要自定义被呼叫的铃声,可以先将音乐资源下载到本地,然后调用以下接口传入资源的路径。
Swift
OC
ConferenceSession.sharedInstance.setCallingBell(filePath: "yourCallingBellPath")
[ConferenceSession.sharedInstance setCallingBellWithFilePath:@"yourCallingBellPath"];

设置被呼叫时静音模式

如果您的被叫端在收到会中呼叫后不想要响铃,可以调用以下接口设置静音模式。
Swift
OC
ConferenceSession.sharedInstance.enableMuteMode(enable: true)
[ConferenceSession.sharedInstance enableMuteModeWithEnable:YES];

设置被呼叫时震动模式

如果您的被叫端在收到会中呼叫后不想要震动,可以调用以下接口关闭震动模式。
Swift
OC
ConferenceSession.sharedInstance.enableVibrationMode(enable: false)
[ConferenceSession.sharedInstance enableVibrationModeWithEnable:NO];
Android 暂时不支持会中呼叫铃声。

页面定制

自定义通讯录

如果当前的通讯录页面不满足您的需求,我们支持您将自己的通讯录 UI 与 TUIRoomKit 关联。
Android
iOS
1. TUIRoomKit 关联自定义通讯录:您需要在呼叫通讯录中的用户之前,通过以下方法设置自定义通讯录:
java
kotlin
// 将 SelectParticipantActivity.class 替换为自定义通讯录的activity
ConferenceSession.sharedInstance().setContactsViewProvider(SelectParticipantActivity.class);
// 将 SelectParticipantActivity::class.java 替换为自定义通讯录的 activity
ConferenceSession.sharedInstance().setContactsViewProvider(SelectParticipantActivity::class.java)
2. 您的通讯录向 TUIRoomKit 返回选择完毕的用户名单:
在通讯录完成用户选择后,您需要将已选用户列表返回给 TUIRoomKit。您可以通过以下方法将数据返回给 TUIRoomKit。
java
kotlin
Intent intent = new Intent();
// participants 为选择完毕的用户列表,必须为 ArrayList<User> 类型。
intent.putExtra(SELECTED_PARTICIPANTS, participants);
setResult(3, intent);
finish();
val intent = Intent()
// participants 为选择完毕的用户列表,必须为 ArrayList<User> 类型。
intent.putExtra(SELECTED_PARTICIPANTS, participants)
setResult(3, intent)
finish()
3. TUIRoomKit 向您的通讯录传入已选择的用户列表:
您可通过以下方法获得已选择的呼叫用户名单。
java
kotlin
// 获取已选择的用户列表
ConferenceParticipants participants = (ConferenceParticipants) bundle.getSerializable(CONFERENCE_PARTICIPANTS);
ArrayList<User> selectedList = participants.selectedList;
// 获取已选择的用户列表
val participants = bundle.getSerializable(CONFERENCE_PARTICIPANTS) as ConferenceParticipants
val selectedList: ArrayList<User> = participants.selectedList
1. 准备好您的好友选择页 viewController,实现ContactViewProtocol协议。
// 示例代码
class SelectMemberViewController: UIViewController, ContactViewProtocol {
weak var delegate: ContactViewSelectDelegate?
var selectedList: [User]
func didSelectFinished() {
// 在完成选择的方法中通过delegate把选择的成员回调给RoomKit
delegate?.onMemberSelected(self, invitees: selectedMembers)
}
}
说明:
这里建议您将一个ConferenceParticipants对象置于您通讯录页面的构造函数参数中,数据来源在第二步的代码中提到。
ConferenceParticipants类中有两个成员:
selectedList:已选择的成员;
unSelectableList:不可选择的成员,您可以在UI上将对应的成员设置其为不可选择。在会中呼叫时,不可选择的成员为已在会中的成员。
2. 在呼叫通讯录中的用户之前,您需要通过以下方法将您自定义的通讯录传入TUIRoomKit:
ConferenceSession.sharedInstance.setContactsViewProvider { participants in
return SelectMemberViewController(participants: participants)
}

自定义被呼叫页面视图

如您需要自定义被呼叫页面的视图,请参考以下路径更改源代码:
Android
iOS
// 文件位置:Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/view/component/

component
└──InvitationReceivedView.java
// 文件位置:iOS/TUIRoomKit/Source/View/ConferenceOptions/ConferenceInvitation

ConferenceInvitation
└── ConferenceInvitationViewController.swift // 被呼叫页面视图

自定义成员列表中呼叫视图

如您需要自定义成员列表中呼叫成员的视图,请参考以下路径更改源代码:
Android
iOS
// 文件位置:Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/view/page/widget/UserControlPanel/

UserControlPanel
└── CallUserView.java // 成员列表呼叫按钮
// 文件位置:iOS/TUIRoomKit/Source/Page/Widget/UserControlPanel

UserControlPanel // 成员列表相关的视图目录
└── UserListCell.swift // 成员列表中单个成员视图,包含用户呼叫状态视图

关键代码

呼叫用户

Android
iOS
// 文件位置:TUIRoomKit/blob/main/Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/model/controller/InvitationController.java

public void inviteUsers(List<UserState.UserInfo> userInfoList, TUIConferenceInvitationManager.InviteUsersCallback callback) {
Log.d(TAG, "inviteUsers");
if (userInfoList.isEmpty()) {
return;
}
RoomToast.toastShortMessageCenter(TUILogin.getAppContext().getString(R.string.tuiroomkit_invitation_has_been_sent));
mConferenceInvitationManager.inviteUsers(mRoomState.roomId.get(), getUserIdListFromUserList(userInfoList), INVITE_TIME_OUT_SECONDS, "", new TUIConferenceInvitationManager.InviteUsersCallback() {
@Override
public void onSuccess(Map<String, TUIConferenceInvitationManager.InvitationCode> invitationResultMap) {
Log.d(TAG, "inviteUsers success");
if (callback != null) {
callback.onSuccess(invitationResultMap);
}
}

@Override
public void onError(TUICommonDefine.Error error, String message) {
Log.d(TAG, "inviteUsers error=" + error + " message=" + message);
if (callback != null) {
callback.onError(error, message);
}
}
});
}
// 文件位置:TUIRoomKit/iOS/TUIRoomKit/Source/Service/ConferenceInvitationService.swift

func inviteUsers(roomId: String, userIdList: [String]) -> AnyPublisher<InviteUsersResult, RoomError> {
return Future<InviteUsersResult, RoomError> { [weak self] promise in
guard let self = self else { return }
self.invitationManager?.inviteUsers(roomId, userIdList: userIdList, timeout: timeout, extensionInfo: "") {dic in
promise(.success((dic)))
} onError: { error, message in
promise(.failure(RoomError(error: error, message: message)))
}
}
.eraseToAnyPublisher()
}

接受呼叫

Android
iOS
// 文件位置:TUIRoomKit/blob/main/Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/model/controller/InvitationController.java
public void accept(String roomId, TUIRoomDefine.ActionCallback callback) {
Log.d(TAG, "accept");
mConferenceInvitationManager.accept(roomId, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "accept success");
if (callback != null) {
callback.onSuccess();
}
}

@Override
public void onError(TUICommonDefine.Error error, String message) {
Log.d(TAG, "accept error=" + error + " message=" + message);
if (callback != null) {
callback.onError(error, message);
}
}
});
}
// 文件位置:TUIRoomKit/iOS/TUIRoomKit/Source/Service/ConferenceInvitationService.swift

func accept(roomId: String) -> AnyPublisher<String, RoomError> {
return Future<String, RoomError> { [weak self] promise in
guard let self = self else { return }
self.invitationManager?.accept(roomId) {
promise(.success(roomId))
} onError: { error, message in
promise(.failure(RoomError(error: error, message: message)))
}
}
.eraseToAnyPublisher()
}

拒绝呼叫

Android
iOS
// 文件位置:TUIRoomKit/Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/model/controller/InvitationController.java

public void reject(String roomId, TUIConferenceInvitationManager.RejectedReason reason, TUIRoomDefine.ActionCallback callback) {
Log.d(TAG, "reject roomId= " + roomId + " reason=" + reason);
mConferenceInvitationManager.reject(roomId, reason, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {
Log.d(TAG, "reject success");
if (callback != null) {
callback.onSuccess();
}
}

@Override
public void onError(TUICommonDefine.Error error, String message) {
Log.d(TAG, "reject error=" + error + " message=" + message);
if (callback != null) {
callback.onError(error, message);
}
}
});
}
// 文件位置:TUIRoomKit/iOS/TUIRoomKit/Source/Service/ConferenceInvitationService.swift

func reject(roomId: String, reason: TUIInvitationRejectedReason) -> AnyPublisher<String, RoomError> {
return Future<String, RoomError> { [weak self] promise in
guard let self = self else { return }
self.invitationManager?.reject(roomId, reason: reason) {
promise(.success(roomId))
} onError: { error, message in
promise(.failure(RoomError(error: error, message: message)))
}
}
.eraseToAnyPublisher()
}

获取房间内呼叫列表

Android
iOS
// 文件位置:TUIRoomKit/Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/model/controller/InvitationController.java

private void getInvitationList() {
Log.d(TAG, "getInvitationList");
mConferenceInvitationManager.getInvitationList(mRoomState.roomId.get(), getAttendeeListCursor, SINGLE_FETCH_COUNT, new TUIConferenceInvitationManager.GetInvitationListCallback() {
@Override
public void onSuccess(TUIConferenceInvitationManager.InvitationListResult invitationListResult) {
Log.d(TAG, "getInvitationList");
for (TUIConferenceInvitationManager.Invitation invitation : invitationListResult.invitationList) {
InvitationState.Invitation invitationState = new InvitationState.Invitation();
invitationState.invitee = new UserState.UserInfo(invitation.invitee);
invitationState.inviter = new UserState.UserInfo(invitation.inviter);
invitationState.invitationStatus = invitation.status;
mInvitationState.invitationList.add(invitationState);
}
getInvitationListCursor = invitationListResult.cursor;
if (!"".equals(getInvitationListCursor)) {
getInvitationList();
}
}

@Override
public void onError(TUICommonDefine.Error error, String message) {
Log.d(TAG, "getInvitationList onError error=" + error + " message=" + message);
}
});
}
// 文件位置:TUIRoomKit/iOS/TUIRoomKit/Source/Service/ConferenceInvitationService.swift

func getInvitationList(roomId: String, cursor: String, count: Int = 20) -> AnyPublisher<InvitationfetchResult, RoomError> {
return Future<InvitationfetchResult, RoomError> { [weak self] promise in
guard let self = self else { return }
self.invitationManager?.getInvitationList(roomId, cursor: cursor, count: count) {invitations, cursor in
promise(.success((invitations, cursor)))
} onError: { error, message in
promise(.failure(RoomError(error: error, message: message)))
}
}
.eraseToAnyPublisher()
}

用户收到呼叫监听

Android
iOS
// 文件位置:TUIRoomKit/Android/tuiroomkit/src/main/java/com/tencent/cloud/tuikit/roomkit/model/ConferenceServiceInitializer.java

private void initConferenceInvitationObserver() {
TUIConferenceInvitationManager invitationManager = (TUIConferenceInvitationManager) TUIRoomEngine.sharedInstance().getExtension(TUICommonDefine.ExtensionType.CONFERENCE_INVITATION_MANAGER);
invitationManager.addObserver(new TUIConferenceInvitationManager.Observer() {
@Override
public void onReceiveInvitation(TUIRoomDefine.RoomInfo roomInfo, TUIConferenceInvitationManager.Invitation invitation, String extensionInfo) {
if (ConferenceController.sharedInstance().getViewState().isInvitationPending.get()) {
ConferenceController.sharedInstance().getInvitationController().reject(roomInfo.roomId, REJECT_TO_ENTER, null);
return;
}
if (ConferenceController.sharedInstance().getRoomController().isInRoom()) {
ConferenceController.sharedInstance().getInvitationController().reject(roomInfo.roomId, IN_OTHER_CONFERENCE, null);
return;
}

Bundle bundle = new Bundle();
bundle.putString("roomId", roomInfo.roomId);
bundle.putString("conferenceName", roomInfo.name);
bundle.putString("ownerName", roomInfo.ownerName);
bundle.putString("inviterName", invitation.inviter.userName);
bundle.putString("inviterAvatarUrl", roomInfo.ownerAvatarUrl);
bundle.putInt("memberCount", roomInfo.memberCount);
TUICore.startActivity("InvitationReceivedActivity", bundle);
}
});
}
// 文件位置:TUIRoomKit/iOS/TUIRoomKit/Source/Service/InvitationObserverService.swift

func onReceiveInvitation(roomInfo: TUIRoomInfo, invitation: TUIInvitation, extensionInfo: String) {
let store = Container.shared.conferenceStore()
store.dispatch(action: ConferenceInvitationActions.onReceiveInvitation(payload: (roomInfo, invitation)))
}