Breakout rooms
This article describes how to implement Microsoft Teams breakout rooms with Azure Communication Services. This capability enables Azure Communication Services users in Teams meetings to participate in breakout rooms. Teams administrators control the availability of breakout rooms in Teams meeting with Teams meeting policy. You can find additional information about breakout rooms in Teams documentation.
Important
Functionality described in this article is currently in public preview. This preview version is provided without a service-level agreement, and we don't recommend it for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.
Prerequisites
- An Azure account with an active subscription. See Create an account for free.
- A deployed Communication Services resource. See Create a Communication Services resource.
- A user access token to enable the calling client. For more information, see Create and manage access tokens.
- Teams meeting organizer needs to assign Teams meeting policy that enables breakout rooms. See Teams meeting policy.
- Optional: Complete the quickstart to add voice calling to your application.
Only Microsoft 365 Users with Organizer, Co-Organizer, or Breakout Room manager roles can manage the breakout rooms.
Support
The following tables define support of breakout rooms in Azure Communication Services.
Identities and call types
The following table shows support in breakout rooms for specific call type and identity.
Identities | Teams meeting | Room | 1:1 call | Group call | 1:1 Teams interop call | Group Teams interop call |
---|---|---|---|---|---|---|
Communication Services user | ✔️ | |||||
Microsoft 365 user | ✔️ |
Operations
The following table show support for individual APIs in the calling SDK related to individual identity types.
Operations | Communication Services user | Microsoft 365 user |
---|---|---|
Get assigned breakout room | ✔️ | ✔️ |
Get all breakout rooms | ✔️[1] | |
Join breakout room | ✔️ | ✔️ |
Manage breakout rooms | ||
Participate in breakout room chat | ✔️[2] | |
Get breakout room settings | ✔️ | ✔️ |
[1] Only Microsoft 365 user with role organizer, co-organizer, or breakout room manager.
[2] Microsoft 365 users can use Graph API to participate in breakout room chat. The thread ID of the chat is provided in the assigned breakout room object.
SDKs
The following tables show support for the breakout rooms feature in individual Azure Communication Services SDKs.
Support status | Web | Web UI | iOS | iOS UI | Android | Android UI | Windows |
---|---|---|---|---|---|---|---|
Is Supported | ✔️ |
Install the SDK
Use the npm install
command to install the Azure Communication Services Common and Calling SDK for JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Initialize required objects
A CallClient
instance is required for most call operations. When you create a new CallClient
instance, you can configure it with custom options like a Logger
instance.
With the CallClient
instance, you can create a CallAgent
instance by calling the createCallAgent
. This method asynchronously returns a CallAgent
instance object.
The createCallAgent
method uses CommunicationTokenCredential
as an argument. It accepts a user access token.
You can use the getDeviceManager
method on the CallClient
instance to access 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()
How to best manage SDK connectivity to Microsoft infrastructure
The Call Agent
instance helps you manage calls (to join or start calls). In order to work your calling SDK needs to connect to Microsoft infrastructure to get notifications of incoming calls and coordinate other call details. Your Call Agent
has two possible states:
Connected - A Call Agent
connectionStatue value of Connected
means the client SDK is connected and capable of receiving notifications from Microsoft infrastructure.
Disconnected - A Call Agent
connectionStatue value of Disconnected
states there's an issue that is preventing the SDK it from properly connecting. Call Agent
should be re-created.
invalidToken
: If a token is expired or is invalidCall Agent
instance disconnects with this error.connectionIssue
: If there's an issue with the client connecting to Microsoft infrascture, after many retriesCall Agent
exposes theconnectionIssue
error.
You can check if your local Call Agent
is connected to Microsoft infrastructure by inspecting the current value of connectionState
property. During an active call you can listen to the connectionStateChanged
event to determine if Call Agent
changes from Connected to Disconnected state.
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);
Implement breakout rooms
BreakoutRooms
is a feature
of the class Call
. First you need to import package Features
from the Calling SDK:
import { Features} from "@azure/communication-calling";
Create breakoutRoom feature
Then get the feature API object from the call instance:
const breakoutRoomsFeature = mainMeetingCall.feature(Features.BreakoutRooms);
Subscribe to breakoutRoom events
The BreakoutRooms
API enables you to subscribe to BreakoutRooms
events. A breakoutRoomsUpdated
event comes from a BreakoutRoomsCallFeature
instance and contains information about the created, updated, and assigned breakout rooms.
To receive breakout room details, subscribe to the breakoutRoomsUpdated
event.
breakoutRoomsFeature.on('breakoutRoomsUpdated', breakoutRoomsUpdatedListener);
Handle breakoutRoom events
Event breakoutRoomsUpdated
provides an instance of one of the following classes as an input parameter. You can use property type
to distinguish between individual event types.
Class
BreakoutRoomsEvent
: This event is triggered when a user with the role organizer, co-organizer, or breakout room manager creates or updates the breakout rooms. Microsoft 365 users with role organizer, co-organizer, or breakout room manager can receive this type of event. Developers can use the breakout rooms in propertydata
to render details about all breakout rooms. This class has propertytype
equal to"breakoutRooms"
.export interface BreakoutRoomsEvent { /** * Breakout room event type */ type: "breakoutRooms", /** * list of Breakout rooms */ data: BreakoutRoom[] | undefined; }
Class
BreakoutRoomsSettingsEvent
: When a user with a role organizer, co-organizer, or breakout room manager updates the breakout room's settings, it triggers this event. Developers can use this information to render the time when breakout room ends or decide whether to render a button to join main room. This class has propertytype
equal to"breakoutRoomSettings"
.export interface BreakoutRoomSettingsEvent { /** * Breakout room event type */ type: "breakoutRoomSettings", /** * Breakout Room setting details */ data: BreakoutRoomSettings | undefined; }
Class
AssignedBreakoutRoomsEvent
: This event is triggered when user is assigned to a breakout room, or assigned breakout room is updated. Users can join the breakout room when propertystate
is set toopen
, leave the breakout room when propertystate
is set toclosed
, or render details of the breakout room. This class has propertytype
equal to"assignedBreakoutRoom"
.export interface AssignedBreakoutRoomEvent { /** * Breakout room event type */ type: "assignedBreakoutRoom"; /** * Assigned breakout room details */ data: BreakoutRoom | undefined; }
Class
JoinBreakoutRoomsEvent
: This event is triggered when the participant is joining a breakout room call. This event can happen when a user is automatically moved to breakout room (that is, ifassignedBreakoutRoom
has propertystate
set toopen
andautoMoveParticipantToBreakoutRoom
is set totrue
) or when a user explicitly joins a breakout room (that is, calls methodjoin
on the instanceassignedBreakoutRoom
whenautoMoveParticipantToBreakoutRoom
is set tofalse
). Propertydata
contains the breakout roomcall
instance, that developers can use to control breakout room call. This class has propertytype
equal to"join"
.export interface JoinBreakoutRoomEvent { /** * Breakout room event type */ type: "join"; /** * Breakoutroom call object */ data: Call | TeamsCall; }
The following code shows the useful information received in the breakout room events:
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);
List available breakout rooms
Microsoft 365 users with role organizer, co-organizer, or breakout room manager can access all breakout rooms.
const breakoutRooms = breakoutRoomsFeature.breakoutRooms;
breakoutRooms.forEach((room)=>{
console.log(`- ${room.displayName}`);
});
List invitees
Microsoft 365 user with role organizer, co-organizer, or breakout room manager can access participants assigned to individual breakout rooms.
breakoutRooms.forEach((room)=>{
console.log(`${room.displayName}`);
room.invitees.forEach((invitee) => {
console.log(`- ${invitee.id}`);
})
})
Join breakout room
If the assignedBreakoutRoom
has property autoMoveParticipantToBreakoutRoom
set to true
, then the user is automatically moved to the breakout room when the property state
is set to open
. If autoMoveParticipantToBreakoutRoom
is set to false
, then use the following code to join breakout room.
This triggers breakoutRoomsUpdated
event with class JoinBreakoutRoomsEvent
that has property type
set as join
. You can use the instance of a class call
in property data
to manage breakout room call.
const breakoutRoom = breakoutRoomsFeature.assignedBreakoutRoom;
if(breakoutRoom.state == 'open' && !breakoutRoom.autoMoveParticipantToBreakoutRoom) {
const breakoutRoomCall = await breakoutRoom.join();
}
Leave breakout room
When the breakout room state is closed
, then the user is automatically moved to the main meeting. User is informed about the end of breakout room by receiving event breakoutRoomsUpdated
with class AssignedBreakoutRoomsEvent
and property type
equal to assignedBreakoutRooms
that indicates that assignedBreakoutRoom
has property state
set to closed
.
If the user wants to leave the breakout room even before the room is closed and the breakout room settings breakoutRoomsFeature.breakoutRoomsSettings
have property disableReturnToMainMeeting
set to false
then user can join the main meeting call with the following code:
const breakoutRoomsSettings = breakoutRoomsFeature.breakoutRoomsSettings;
if(breakoutRoomCall != null && !breakoutRoomsSettings.disableReturnToMainMeeting){
breakoutRoomCall.hangUp();
mainMeetingCall.resume();
}
Get participants of the breakout room
When you join the breakout room, you can use the following code to get the list of remote participants of the breakout room:
const breakoutRoomParticipants = [breakoutRoomCall.remoteParticipants.values()].map((p: SDK.RemoteParticipant) => { p.displayName || p.identifier });
console.log(`Participants of the breakoutRoom : <br/>" + breakoutRoomParticipants.join("<br/>")`);
Stop receiving breakout rooms events
Use the following code to stop receiving breakoutRooms events.
breakoutRoomsFeature.off('breakoutRoomsUpdated', breakoutRoomsUpdatedListener);
Breakout room properties
Breakout rooms have the following properties:
Note
The following sample code efficiently displays all breakout room properties. It is not intended to be reused as shown. In practice you only use the properties needed for your breakout room scenario.
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;
Breakout room properties | Description |
---|---|
displayName |
Name of the breakout room. This property is read-only. |
threadId |
Use the chat thread ID to join chat of the breakout room. This property is read-only. |
state |
State of the breakout room. It can be either open or closed . Users would be able to join the breakout room only when the state is open . This property is read-only. |
autoMoveParticipantToBreakoutRoom |
Boolean value indicating whether the users are moved to breakout rooms automatically when the state of assignedBreakoutRoom is set to open . This property is read-only. In the Teams UI settings for breakout rooms, the organizer, co-organizer, or breakout room manager can adjust this specific setting. By setting this option to true , participants are automatically transferred to their designated breakout room. Conversely, if you set this property to false , then you must manually call the join method to move participants into the breakout room. |
call |
Breakout room call object. This object is returned when the user joins the breakout room call automatically or by calling the join method on assignedBreakoutRoom object. This property is read-only. |
invitees |
The list of invitees who are assigned to the breakout room. This property is read-only. |
Breakout room settings
Breakout rooms share setting that has the following properties:
const disableReturnToMainMeeting : boolean = breakoutRoomsSettings.disableReturnToMainMeeting;
const roomEndTime : TimestampInfo = breakoutRoomsSettings.roomEndTime;
Breakout room properties | Description |
---|---|
disableReturnToMainMeeting |
Disable participants to return to the main meeting from the breakout room call. This property is read-only. In the Teams UI settings for breakout rooms, the organizer, co-organizer, or breakout room manager can adjust this specific setting to control when the participant of breakout rooms can return to the main meeting. |
roomEndTime |
Breakout room end time set by the Microsoft 365 user with role organizer, co-organizer, or breakout room manager of the main meeting. This property is read-only. |
Troubleshooting
Error code | Subcode | Result Category | Reason | Resolution |
---|---|---|---|---|
400 | 46250 | ExpectedError | Breakout Rooms feature is only available in Teams meetings. | Implement your own breakout room mechanism or use Teams meetings. |
405 | 46251 | ExpectedError | Azure Communication Services currently disabled this feature. | Try the APIs in a couple of days. |
500 | 46254 | UnexpectedServerError | Unable to join breakout room due to an unexpected error. | Ensure that the state of assignedBreakoutRoom is open and call breakoutRoomsFeature.assignedBreakoutRoom.join() method explicitly. If the issue persists, gather browser console logs and contact Azure Communication Services support. |
500 | 46255 | UnexpectedServerError | Unable to hold main meeting. | Ensure that the state of assignedBreakoutRoom is open and call breakoutRoomsFeature.assignedBreakoutRoom.join() method explicitly. If the issue persists, gather browser console logs and contact Azure Communication Services support. |
412 | 46256 | ExpectedError | Unable to join Breakout Room as the room is closed. | Ensure that the state of assignedBreakoutRoom is open and call breakoutRoomsFeature.assignedBreakoutRoom.join() method explicitly. |
412 | 46257 | UnexpectedServerError | Unable to resume main meeting. | Follow the instructions defined in the section Leave breakout room for manual leaving of breakout room. If the issue persists, gather browser console logs and contact Azure Communication Services support. |
412 | 46258 | UnexpectedClientError | Unable to read breakout room details. | Gather browser console logs and contact Azure Communication Services support. |
500 | 46259 | UnexpectedServerError | Couldn't hang up the Breakout room call. | Follow the instructions defined in the section Leave breakout room for manual leaving of breakout room. |
412 | 46260 | UnexpectedClientError | Can't join Breakout Room as it isn't yet assigned. | Ensure that the breakoutRoomsFeature.assignedBreakoutRoom is having the details of the assigned breakout room. Ensure that the state of assignedBreakoutRoom is open and call breakoutRoomsFeature.assignedBreakoutRoom.join() method explicitly. |