你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

小组讨论室

本文介绍如何使用 Azure 通信服务实现 Microsoft Teams 分组讨论室。 通过此功能,Teams 会议中的 Azure 通信服务用户可参与分组讨论室。 Teams 管理员使用 Teams 会议策略控制 Teams 会议中分组讨论室的可用性。 可在 Teams 文档中查看更多有关分组讨论室的信息。

先决条件

仅具有组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户有权管理分组讨论室。

支持

下表定义了 Azure 通信服务中的分组讨论室支持。

标识和通话类型

下表显示了分组讨论室中对特定通话类型和标识的支持。

标识 Teams 会议 房间 1 对 1 通话 组呼叫 1:1 Teams 互操作通话 小组 Teams 互操作通话
通信服务用户 ✔️
Microsoft 365 用户 ✔️

Operations

下表显示了与各个标识类型相关的通话 SDK 中对各个 API 的支持。

Operations 通信服务用户 Microsoft 365 用户
获取分配的分组讨论室 ✔️ ✔️
获取所有分组讨论室 ✔️[1]
加入分组讨论室 ✔️ ✔️
管理分组讨论室
参与分组讨论室聊天 ✔️[2]
获取分组讨论室设置 ✔️ ✔️

[1] 仅限具有组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户。

[2] Microsoft 365 用户可使用图形 API 参与分组讨论室聊天。 聊天的会话 ID 在分配的分组讨论室对象中提供。

SDK

下表显示了各个 Azure 通信服务 SDK 中对分组讨论室功能的支持。

支持状态 Web Web UI iOS iOS UI Android Android UI Windows
支持 ✔️

安装 SDK

使用 npm install 命令安装适用于 JavaScript 的 Azure 通信服务通用 SDK 和通话 SDK:

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

初始化所需的对象

大多数通话操作需要 CallClient 实例。 创建新的 CallClient 实例时,可以使用自定义选项(如 Logger 实例)对其进行配置。

有了 CallClient 实例后,可以通过调用 createCallAgent 创建 CallAgent 实例。 此方法将异步返回 CallAgent 实例对象。

createCallAgent 方法使用 CommunicationTokenCredential 作为参数。 它接受用户访问令牌

可在 CallClient 实例上使用 getDeviceManager 方法来访问 deviceManager

const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");

// Set the logger's log level
setLogLevel('verbose');

// Redirect log output to console, file, buffer, REST API, or whatever location you want
AzureLogger.log = (...args) => {
    console.log(...args); // Redirect log output to console
};

const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()

如何最好地管理 SDK 与 Microsoft 基础结构的连接性

Call Agent 实例可帮助你管理通话(以加入或启动通话)。 通话 SDK 需要连接到 Microsoft 基础结构以获取传入通话通知并协调其他通话详细信息,否则无法工作。 你的 Call Agent 有两种可能的状态:

已连接 - Call Agent connectionStatue 值为 Connected 表示客户端 SDK 已连接,能够接收来自 Microsoft 基础结构的通知。

已断开连接 - Call Agent connectionStatue 值为 Disconnected 表示存在阻止 SDK 正确连接的问题。 应重新创建 Call Agent

  • invalidToken:如果令牌已过期或无效,Call Agent 实例会断开连接并出现此错误。
  • connectionIssue:如果客户端连接到 Microsoft 基础结构时出现问题,则在多次重试后,Call Agent 会显示 connectionIssue 错误。

可以通过检查 connectionState 属性的当前值来检查本地 Call Agent 是否已连接到 Microsoft 基础结构。 在通话过程中,可以侦听 connectionStateChanged 事件,以确定 Call Agent 是否从“已连接”状态更改为“已断开连接”状态。

const connectionState = callAgentInstance.connectionState;
console.log(connectionState); // it may return either of 'Connected' | 'Disconnected'

const connectionStateCallback = (args) => {
    console.log(args); // it will return an object with oldState and newState, each of having a value of either of 'Connected' | 'Disconnected'
    // it will also return reason, either of 'invalidToken' | 'connectionIssue'
}
callAgentInstance.on('connectionStateChanged', connectionStateCallback);

实现分组讨论室

BreakoutRooms 是类 Callfeature。 首先,需要从呼叫 SDK 导入包 Features

import { Features} from "@azure/communication-calling";

创建 breakoutRoom 功能

然后,从通话实例获取功能 API 对象:

const breakoutRoomsFeature = mainMeetingCall.feature(Features.BreakoutRooms);

订阅 breakoutRoom 事件

BreakoutRooms API 支持订阅 BreakoutRooms 事件。 breakoutRoomsUpdated 事件来自 BreakoutRoomsCallFeature 实例,包含有关创建、更新和分配的分组讨论室的信息。

若要接收分组讨论室的详细信息,请订阅 breakoutRoomsUpdated 事件。

breakoutRoomsFeature.on('breakoutRoomsUpdated', breakoutRoomsUpdatedListener);

处理 breakoutRoom 事件

事件 breakoutRoomsUpdated 提供以下类之一的实例作为输入参数。 可以使用属性 type 来区分各个事件类型。

  • BreakoutRoomsEvent:当具有组织者、共同组织者或分组讨论室管理者角色的用户创建或更新分组讨论室时,会触发此事件。 具有组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户可接收此类事件。 开发人员可以使用属性 data 中的分组讨论室来呈现所有分组讨论室的详细信息。 此类具有属性 type 并等于 "breakoutRooms"

      export interface BreakoutRoomsEvent {
        /**
         * Breakout room event type
        */
        type: "breakoutRooms",
        /**
         * list of Breakout rooms
        */
        data: BreakoutRoom[] | undefined;
      }
    
  • BreakoutRoomsSettingsEvent:当具有组织者、共同组织者或分组讨论室管理者角色的用户更新分组讨论室的设置时,它触发此事件。 开发人员可以使用此信息来呈现分组讨论室结束的时间,或决定是否呈现用于加入主讨论室的按钮。 此类具有属性 type 并等于 "breakoutRoomSettings"

      export interface BreakoutRoomSettingsEvent {
        /**
        * Breakout room event type
        */
        type: "breakoutRoomSettings",
        /**
        * Breakout Room setting details
        */
        data: BreakoutRoomSettings | undefined;
      }
    
  • AssignedBreakoutRoomsEvent:将用户分配到分组讨论室时或分配的分组讨论室更新时,将触发此事件。 用户可在属性 state 设置为 open 时加入分组讨论室,在属性 state 设置为 closed 时离开分组讨论室,或呈现分组讨论室的详细信息。 此类具有属性 type 并等于 "assignedBreakoutRoom"

      export interface AssignedBreakoutRoomEvent {
        /**
         * Breakout room event type
         */
        type: "assignedBreakoutRoom";
        /**
         * Assigned breakout room details
         */
        data: BreakoutRoom | undefined;
      }
    
  • JoinBreakoutRoomsEvent:当参与者加入分组讨论室通话时,将触发此事件。 当用户自动移动到分组讨论室(也即 assignedBreakoutRoom 的属性 state 设置为 openautoMoveParticipantToBreakoutRoom 设置为 true),或当用户显式加入分组讨论室(即 autoMoveParticipantToBreakoutRoom 设置为 false时对 assignedBreakoutRoom 实例调用方法 join)时,可能会发生此事件。 属性 data 包含分组讨论室 call 实例,开发人员可使用该实例来控制分组讨论室呼叫。 此类具有属性 type 并等于 "join"

      export interface JoinBreakoutRoomEvent {
        /**
         * Breakout room event type
         */
        type: "join";
        /**
         * Breakoutroom call object
         */
        data: Call | TeamsCall;
      }
    

以下代码显示分组讨论室事件中接收到的有用信息:

    const breakoutRoomsUpdatedListener = (event) => {
    switch(event.type) {
        case "breakoutRooms":
          const breakoutRooms = event.data;
          console.log(`Breakout rooms are created or updated. There are ${breakoutRooms.length} breakout rooms in total.`);
          breakoutRooms.forEach((room)=>{
          console.log(`- ${room.displayName}`);
          });    
          break;
        case "assignedBreakoutRooms":
          const assignedRoom = event.data;
          console.log(`You are assigned to breakout room named: ${assignedRoom.displayName}`);      
          console.log(`Assigned breakout room thread Id: ${assignedRoom.threadId}`);
          console.log(`Automatically move participants to breakout room: ${assignedRoom.autoMoveParticipantToBreakoutRoom}`);
          console.log(`Assigned breakout room state : ${assignedRoom.state }`);      
          break;
        case "breakoutRoomsSettings":
          const breakoutRoomSettings = event.data;
          console.log(`Breakout room ends at: ${breakoutRoomSettings.roomEndTime}`);          
          console.log(`Disable the user to return to main meeting from breakout room call : ${breakoutRoomSettings.disableReturnToMainMeeting}`);         
          break;
        case "join":
          const breakoutRoomCall = event.data;
          console.log(`You have joined breakout room with call ID: ${breakoutRoomCall.id}`);      
          break;      
      }
    }
breakoutRoomsFeature.on('breakoutRoomsUpdated', breakoutRoomsUpdatedListener);

列出可用的分组讨论室

具有组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户可访问所有分组讨论室。

const breakoutRooms = breakoutRoomsFeature.breakoutRooms;
breakoutRooms.forEach((room)=>{
      console.log(`- ${room.displayName}`);
       }); 

列出被邀请者

具有组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户可访问分配给各分组讨论室的参与者。

breakoutRooms.forEach((room)=>{
      console.log(`${room.displayName}`);
      room.invitees.forEach((invitee) => {
          console.log(`- ${invitee.id}`);         
          })
      })

加入分组讨论室

如果 assignedBreakoutRoom 的属性 autoMoveParticipantToBreakoutRoom 设置为 true,则当属性 state 设置为 open 时,用户会自动移动到分组讨论室。 如果 autoMoveParticipantToBreakoutRoom 设置为 false,则使用以下代码加入分组讨论室。

这会触发具有属性 type 设置为 join 的类 JoinBreakoutRoomsEventbreakoutRoomsUpdated 事件。 可以使用属性 data 中类 call 的实例来管理分组讨论室呼叫。

const breakoutRoom = breakoutRoomsFeature.assignedBreakoutRoom;
if(breakoutRoom.state == 'open' && !breakoutRoom.autoMoveParticipantToBreakoutRoom) {
  const breakoutRoomCall = await breakoutRoom.join();
}

当用户位于分组讨论室中,并且组织者为用户分配了一个新的分组讨论室时,用户将获得类型为 assignedBreakoutRoomsbreakoutRoomsUpdated 事件。 此事件包含最新的分组讨论室详细信息。 用户必须 hangUp() 上一个分组讨论室呼叫。 如果 autoMoveParticipantToBreakoutRoom 设置为 true,则会自动移动用户,否则用户必须对新的分组讨论室显式调用 join 方法。

//Breakout room which is assigned initially.
const breakoutRoom = breakoutRoomsFeature.assignedBreakoutRoom;
if(breakoutRoom.state == 'open' && !breakoutRoom.autoMoveParticipantToBreakoutRoom) {
  const breakoutRoomCall = await breakoutRoom.join();
}

// `breakoutRoomsUpdated` event which contains the details of the new breakout room
let assignedRoom = undefined;
const breakoutRoomsUpdatedListener = (event) => {
     switch(event.type) {
          case "assignedBreakoutRooms":
          const assignedRoom = event.data;
          break;
     }
}

if(assignedRoom.threadId != breakoutRoom.threadId && breakoutRooms != null)
{
    await breakoutRoom.hangUp();
}
if(assignedRoom.state == 'open' && !assignedRoom.autoMoveParticipantToBreakoutRoom) {
  const breakoutRoomCall = await assignedRoom.join();
}

具有角色组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户可以获取由分组讨论室管理者或主会议组织者创建的分组讨论室列表。 在这种情况下,此行为略有不同。 此用户必须显式调用 join() 方法,才能加入分组讨论室。 用户最初在主会议中保持暂停状态,最终从主会议中移除。 用户必须初始化 breakoutRoomCall 的分组讨论室功能,才能接收分组讨论室的更新。

如果用户想加入任何分组讨论室,则用户需要显式调用 join 方法。

const breakoutRoom = breakoutRoomsFeature.breakoutRooms[0];
if(breakoutRoom.state == 'open') {
  const breakoutRoomCall = await breakoutRoom.join();
}

要退出分组讨论室,用户应在分组讨论室呼叫中执行 hangUp() 函数。 用户需要调用 ReturnToMainMeeting 以恢复主会议呼叫。

breakoutRoomCall.hangUp();
const mainMeetingCall = breakoutRoomCall.returnToMainMeeting();

离开分组讨论室

当分组讨论室状态为 closed 时,用户通过接收具有类 AssignedBreakoutRoomsEvent 且属性 type 等于 assignedBreakoutRooms(指示 assignedBreakoutRoom 的属性 state 设置为 closed)的事件 breakoutRoomsUpdated 来获知分组讨论室的结束。 用户会自动离开分组讨论室,且可以通过调用 returnToMainMeeting() 返回主会议,如上所示。

如果用户希望在分组讨论室关闭之前离开讨论室,且分组讨论室的设置 breakoutRoomsFeature.breakoutRoomsSettings 的属性 disableReturnToMainMeeting 设置为 false,则用户可使用以下代码返回主会议呼叫:

breakoutRoomCall.hangUp();
const mainMeetingCall = breakoutRoomCall.returnToMainMeeting();

获取分组讨论室的参与者信息

加入分组讨论室时,可使用以下代码获取分组讨论室远程参与者的列表:

const breakoutRoomParticipants = [breakoutRoomCall.remoteParticipants.values()].map((p: SDK.RemoteParticipant) => { p.displayName || p.identifier });
console.log(`Participants of the breakoutRoom : <br/>" + breakoutRoomParticipants.join("<br/>")`);

停止接收分组讨论室事件

使用以下代码停止接收 breakoutRooms 事件。

breakoutRoomsFeature.off('breakoutRoomsUpdated', breakoutRoomsUpdatedListener);

分组讨论室属性

分组讨论室具有以下属性:

注意

以下示例代码有效地显示所有分组讨论室属性。 不应重复使用它,如下所示。 实际上,你仅使用分组讨论室场景所需的属性。

const displayName : string = breakoutRoom.displayName;
const threadId : string = breakoutRoom.threadId;
const state : BreakoutRoomState = breakoutRoom.state;
const autoMoveParticipantToBreakoutRoom : boolean = breakoutRoom.autoMoveParticipantToBreakoutRoom; 
const call : Call | TeamsCall = breakoutRoom.call;
const invitees : Invitee[] = breakoutRoom.invitees;
分组讨论室属性 说明
displayName 分组讨论室的名称。 此属性为只读。
threadId 使用聊天线程 ID 加入分组讨论室的聊天。 此属性为只读。
state 分组讨论室的状态。 它可以是openclosed。 仅当状态为 open 时,用户能加入分组讨论室。 此属性为只读。
autoMoveParticipantToBreakoutRoom 布尔值,指示用户是否在 assignedBreakoutRoomstate 设置为 open 时自动移动到分组讨论室。 此属性为只读。 在分组讨论室的 Teams UI 设置中,组织者、共同组织者或分组讨论室管理员可以调整此特定设置。 将此选项设置为 true,系统自动将参与者转移到指定的分组讨论室。 相反,如果将此属性设置为 false,则必须手动调用 join 方法,将参与者移动到分组讨论室。
call 分组讨论室通话对象。 当用户自动加入或通过对 assignedBreakoutRoom 对象调用 join 方法加入分组讨论室通话时,会返回此对象。 此属性为只读。
invitees 被分配到分组讨论室的受邀者的列表。 此属性为只读。

分组讨论室设置

分组讨论室共享设置具有以下属性:

const disableReturnToMainMeeting : boolean = breakoutRoomsSettings.disableReturnToMainMeeting;
const roomEndTime : TimestampInfo = breakoutRoomsSettings.roomEndTime;
分组讨论室属性 说明
disableReturnToMainMeeting 禁止参与者从分组讨论室通话返回主会议。 此属性为只读。 在分组讨论室的 Teams UI 设置中,组织者、共同组织者或分组讨论室管理员可以调整此特定设置,以控制分组讨论室参与者何时可以返回到主会议。
roomEndTime 由具有主会议组织者、共同组织者或分组讨论室管理者角色的 Microsoft 365 用户设置的分组讨论室结束时间。 此属性为只读。

故障排除

错误代码 子代码 结果类别 Reason 解决方法
400 46250 ExpectedError 分组讨论室功能仅在 Teams 会议中可用。 实现自己的分组讨论室机制或使用 Teams 会议。
405 46251 ExpectedError Azure 通信服务当前禁用了此功能。 请在几天后试用 API。
500 46254 UnexpectedServerError 由于发生意外错误,无法加入分组讨论室。 确保 assignedBreakoutRoomstateopen 并显式调用 breakoutRoomsFeature.assignedBreakoutRoom.join() 方法。 如果该问题仍然存在,请收集浏览器控制台日志并联系 Azure 通信服务支持部门。
500 46255 UnexpectedServerError 无法召开主会议。 确保 assignedBreakoutRoomstateopen 并显式调用 breakoutRoomsFeature.assignedBreakoutRoom.join() 方法。 如果该问题仍然存在,请收集浏览器控制台日志并联系 Azure 通信服务支持部门。
412 46256 ExpectedError 无法加入分组讨论室,因为该讨论室已关闭。 确保 assignedBreakoutRoomstateopen 并显式调用 breakoutRoomsFeature.assignedBreakoutRoom.join() 方法。
412 46257 UnexpectedServerError 无法恢复主会议。 按照第 Leave breakout room 节中的说明手动离开分组讨论室。 如果该问题仍然存在,请收集浏览器控制台日志并联系 Azure 通信服务支持部门。
412 46258 UnexpectedClientError 无法读取分组讨论室的详细信息。 收集浏览器控制台日志并联系 Azure 通信服务支持部门。
500 46259 UnexpectedServerError 无法挂断分组讨论室呼叫。 按照第 Leave breakout room 节中的说明手动离开分组讨论室。
412 46260 UnexpectedClientError 无法加入分组讨论室,因为该讨论室尚未分配。 确保 breakoutRoomsFeature.assignedBreakoutRoom 具有分配的分组讨论室的详细信息。 确保 assignedBreakoutRoomstateopen 并显式调用 breakoutRoomsFeature.assignedBreakoutRoom.join() 方法。
412 46261 UnexpectedClientError 无法加入主会议。 请通过调用 breakoutRoomsFeature.assignedBreakoutRoom.returnToMainMeeting() 方法进行重试。 如果该问题仍然存在,请收集浏览器控制台日志并联系 Azure 通信服务支持部门。
412 46262 ExpectedError 已在主会议中。 请仅在参与者处于分组讨论室中并已从主会议中移除的情况下调用此方法。
412 46263 UnexpectedClientError 现有的分组讨论室呼叫挂起失败。 尝试再次调用 hangup() 方法来挂起呼叫。 调用 join() 方法再次加入分组讨论室。

后续步骤