Principais recursos do Live Share
O SDK do Live Share pode ser adicionado aos contextos sidePanel
e meetingStage
da extensão da sua reunião com o mínimo de esforço.
Este artigo se concentra em como integrar o SDK do Live Share ao seu aplicativo e aos principais recursos do SDK.
Pré-requisitos
Instalar o SDK do JavaScript
O SDK do Live Share é um pacote JavaScript publicado no npm e você pode baixar por meio de npm ou yarn. Você também deve instalar dependências de par do Live Share, que incluem fluid-framework
e @fluidframework/azure-client
. Se você estiver usando o Live Share em seu aplicativo de guia, também deve instalar @microsoft/teams-js
a versão 2.11.0
ou posterior.
npm
npm install @microsoft/live-share fluid-framework @fluidframework/azure-client --save
npm install @microsoft/teams-js --save
Fio
yarn add @microsoft/live-share fluid-framework @fluidframework/azure-client
yarn add @microsoft/teams-js
Registrar permissões de RSC
Para habilitar o SDK do Live Share para sua extensão de reunião, adicione primeiramente as seguintes permissões de RSC ao manifesto do seu aplicativo:
{
// ...rest of your manifest here
"configurableTabs": [
{
"configurationUrl": "<<YOUR_CONFIGURATION_URL>>",
"canUpdateConfiguration": true,
"scopes": [
"groupchat"
],
"context": [
"meetingSidePanel",
"meetingStage"
]
}
],
"validDomains": [
"<<BASE_URI_ORIGIN>>"
],
"authorization": {
"permissions": {
"resourceSpecific": [
// ...other permissions here
{
"name": "LiveShareSession.ReadWrite.Chat",
"type": "Delegated"
},
{
"name": "LiveShareSession.ReadWrite.Group",
"type": "Delegated"
},
{
"name": "MeetingStage.Write.Chat",
"type": "Delegated"
},
{
"name": "ChannelMeetingStage.Write.Group",
"type": "Delegated"
}
]
}
}
}
Ingressar em uma sessão de reunião
Siga as etapas para ingressar em uma sessão associada à reunião de um usuário:
- Inicializar
LiveShareClient
. - Defina as estruturas de dados que você deseja sincronizar. Por exemplo:
LiveState
ouSharedMap
. - Ingressar no contêiner.
Exemplo:
import { LiveShareClient, LiveState } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { SharedMap } from "fluid-framework";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
liveState: LiveState,
sharedMap: SharedMap,
},
};
const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic
Isso é tudo o que foi necessário para configurar seu contêiner e ingressar na sessão da reunião. Agora, vamos revisar os diferentes tipos de estruturas de dados distribuídos que você pode usar com o SDK do Live Share.
Dica
Verifique se o SDK do Cliente do Teams é inicializado antes de chamar LiveShareHost.create()
.
Estruturas de dados do Live Share
O SDK do Live Share inclui um conjunto de novas estruturas de dados distribuídos que estendem a classe do DataObject
Fluid, fornecendo novos tipos de objetos com estado e sem estado. Ao contrário das estruturas de dados fluidas, as classes do LiveDataObject
Live Share não gravam alterações no contêiner Fluid, permitindo uma sincronização mais rápida. Além disso, essas classes foram projetadas do zero para cenários comuns de reunião em reuniões do Teams. Cenários comuns incluem sincronizar o conteúdo que o apresentador está exibindo, exibir metadados para cada usuário na reunião ou exibir um temporizador de contagem regressiva.
Objeto Live | Descrição |
---|---|
LivePresence | Veja quais usuários estão online, defina propriedades personalizadas para cada usuário e transmita as alterações em sua presença. |
Livestate | Sincronizar qualquer valor serializável state JSON. |
LiveTimer | Sincronizar um temporizador de contagem regressiva para um determinado intervalo. |
LiveEvent | Transmita eventos individuais com quaisquer atributos de dados personalizados no conteúdo. |
Exemplo livePresence
A LivePresence
classe torna o acompanhamento de quem está na sessão mais fácil do que nunca. Ao chamar os .initialize()
métodos ou .updatePresence()
, você pode atribuir metadados personalizados para esse usuário, como imagem de perfil, identificador de conteúdo que eles estão exibindo e muito mais. Ao ouvir presenceChanged
eventos, cada cliente recebe o objeto mais recente LivePresenceUser
, colapsando todas as atualizações de presença em um único registro para cada único userId
.
Veja a seguir alguns exemplos em que LivePresence
podem ser usados em seu aplicativo:
- Obtendo o Microsoft Teams
userId
,displayName
eroles
de cada usuário na sessão. - Exibindo informações personalizadas sobre cada usuário conectado à sessão, como uma URL de imagem de perfil.
- Sincronizando as coordenadas em uma cena 3D em que o avatar de cada usuário está localizado.
- Relatar a posição do cursor de cada usuário em um documento de texto.
- Postando a resposta de cada usuário a uma pergunta de quebra de gelo durante uma atividade de grupo.
import {
LiveShareClient,
LivePresence,
PresenceState,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
presence: LivePresence,
},
};
const { container } = await liveShare.joinContainer(schema);
const presence = container.initialObjects.presence;
// Register listener for changes to each user's presence.
// This should be done before calling `.initialize()`.
presence.on("presenceChanged", (user, local) => {
console.log("A user presence changed:")
console.log("- display name:", user.displayName);
console.log("- state:", user.state);
console.log("- custom data:", user.data);
console.log("- change from local client", local);
console.log("- change impacts local user", user.isLocalUser);
});
// Define the initial custom data for the local user (optional).
const customUserData = {
picture: "DEFAULT_PROFILE_PICTURE_URL",
readyToStart: false,
};
// Start receiving incoming presence updates from the session.
// This will also broadcast the user's `customUserData` to others in the session.
await presence.initialize(customUserData);
// Send a presence update, in this case once a user is ready to start an activity.
// If using role verification, this will throw an error if the user doesn't have the required role.
await presence.update({
...customUserData,
readyToStart: true,
});
Os usuários que ingressarem em uma sessão de um único dispositivo têm um único LivePresenceUser
registro compartilhado para todos os seus dispositivos. Para acessar o mais recente data
e state
para cada uma de suas conexões ativas, você pode usar a getConnections()
API da LivePresenceUser
classe. Isso retorna uma lista de LivePresenceConnection
objetos. Você pode ver se uma determinada LivePresenceConnection
instância é do dispositivo local usando a isLocalConnection
propriedade.
Cada LivePresenceUser
instância e LivePresenceConnection
tem uma state
propriedade, que pode ser online
, offline
ou away
. Um presenceChanged
evento é emitido quando o estado de um usuário é alterado. Por exemplo, se um usuário sair de uma reunião, seu estado será alterado para offline
.
Observação
Pode levar até 20 segundos para uma LivePresenceUser
state
atualização offline
após sair de uma reunião.
Exemplo livestate
A LiveState
classe permite sincronizar o estado do aplicativo simples para todos em uma reunião. LiveState
sincroniza um único state
valor, permitindo que você sincronize qualquer valor serializável JSON, como um string
, number
ou object
.
Veja a seguir alguns exemplos em que LiveState
podem ser usados em seu aplicativo:
- Definindo o identificador de usuário do apresentador atual para criar um recurso de controle take .
- Sincronizando o caminho de rota atual do seu aplicativo para garantir que todos estejam na mesma página. Por exemplo,
/whiteboard/:whiteboardId
. - Mantendo o identificador de conteúdo que o apresentador atual está exibindo. Por exemplo, um
taskId
em um quadro de tarefas. - Sincronizando a etapa atual em uma atividade de grupo de várias rodadas. Por exemplo, a fase de adivinhação durante o jogo do Agile Poker.
- Manter uma posição de rolagem em sincronização para um recurso siga-me .
Observação
Ao contrário SharedMap
de , o state
valor em LiveState
será redefinido depois que todos os usuários se desconectarem de uma sessão.
Exemplo:
import { LiveShareClient, LiveState } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { appState: LiveState },
};
const { container } = await liveShare.joinContainer(schema);
const { appState } = container.initialObjects;
// Register listener for changes to the state.
// This should be done before calling `.initialize()`.
appState.on("stateChanged", (planetName, local, clientId) => {
// Update app with newly selected planet.
// To know which user made this change, you can pass the `clientId` to the `getUserForClient()` API from the `LivePresence` class.
});
// Set a default value and start listening for changes.
// This default value will not override existing for others in the session.
const defaultState = "Mercury";
await appState.initialize(defaultState);
// `.set()` will change the state for everyone in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
await appState.set("Earth");
Exemplo liveEvent
LiveEvent
é uma ótima maneira de enviar eventos simples para outros clientes em uma reunião que só são necessárias no momento da entrega. É útil para cenários como enviar notificações de sessão ou implementar reações personalizadas.
import { LiveEvent, LiveShareClient } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { customReactionEvent: LiveEvent },
};
const { container } = await liveShare.joinContainer(schema);
const { customReactionEvent } = container.initialObjects;
// Register listener to receive events sent through this object.
// This should be done before calling `.initialize()`.
customReactionEvent.on("received", (kudosReaction, local, clientId) => {
console.log("Received reaction:", kudosReaction, "from clientId", clientId);
// To know which user made this change, you can pass the `clientId` to the `getUserForClient()` API from the `LivePresence` class.
// Display notification in your UI
});
// Start listening for incoming events
await customReactionEvent.initialize();
// `.send()` will send your event value to everyone in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
const kudosReaction = {
emoji: "❤️",
forUserId: "SOME_OTHER_USER_ID",
};
await customReactionEvent.send(kudosReaction);
Exemplo do LiveTimer
LiveTimer
fornece um temporizador de contagem regressiva simples que é sincronizado para todos em uma reunião. É útil para cenários que têm um limite de tempo, como um temporizador de meditação em grupo ou um temporizador redondo para um jogo.
import { LiveShareClient, LiveTimer } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { timer: LiveTimer },
};
const { container } = await liveShare.joinContainer(schema);
const { timer } = container.initialObjects;
// Register listeners for timer changes
// This should be done before calling `.initialize()`.
// Register listener for when the timer starts its countdown
timer.on("started", (config, local) => {
// Update UI to show timer has started
});
// Register listener for when a paused timer has resumed
timer.on("played", (config, local) => {
// Update UI to show timer has resumed
});
// Register listener for when a playing timer has paused
timer.on("paused", (config, local) => {
// Update UI to show timer has paused
});
// Register listener for when a playing timer has finished
timer.on("finished", (config) => {
// Update UI to show timer is finished
});
// Register listener for the timer progressed by 20 milliseconds
timer.on("onTick", (milliRemaining) => {
// Update UI to show remaining time
});
// Start synchronizing timer events for users in session
await timer.initialize();
// Start a 60 second timer for users in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
const durationInMilliseconds = 1000 * 60;
await timer.start(durationInMilliseconds);
// Pause the timer for users in session
// If using role verification, this will throw an error if the user doesn't have the required role.
await timer.pause();
// Resume the timer for users in session
// If using role verification, this will throw an error if the user doesn't have the required role.
await timer.play();
Verificação de função para estruturas de dados dinâmicas
As reuniões no Teams incluem chamadas, reuniões de todas as mãos e salas de aula online. Os participantes da reunião podem abranger organizações, ter privilégios diferentes ou simplesmente ter objetivos diferentes. Portanto, é importante respeitar os privilégios de diferentes funções de usuário durante as reuniões. Objetos live são projetados para dar suporte à verificação de função, permitindo que você defina as funções que podem enviar mensagens para cada objeto vivo individual. Por exemplo, você pode optar por permitir que apenas os apresentadores e organizadores da reunião controlem a reprodução de vídeo, mas, ainda assim, permitir que convidados e participantes solicitem vídeos para assistir em seguida.
Observação
A LivePresence
classe não dá suporte à verificação de função. O LivePresenceUser
objeto tem um getRoles
método, que retorna as funções de reunião para um determinado usuário.
No exemplo a seguir, em que apenas apresentadores e organizadores podem assumir o controle, LiveState
é usado para sincronizar qual usuário é o apresentador ativo:
import {
LiveShareClient,
LiveState,
UserMeetingRole,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { appState: LiveState },
};
const { container } = await liveShare.joinContainer(schema);
const { appState } = container.initialObjects;
// Register listener for changes to state
appState.on("stateChanged", (state, local) => {
// Update local app state
});
// Set roles who can change state and start listening for changes
const initialState = {
documentId: "INITIAL_DOCUMENT_ID",
};
const allowedRoles = [UserMeetingRole.organizer, UserMeetingRole.presenter];
await appState.initialize(initialState, allowedRoles);
async function onSelectEditMode(documentId) {
try {
await appState.set({
documentId,
});
} catch (error) {
console.error(error);
}
}
async function onSelectPresentMode(documentId) {
try {
await appState.set({
documentId,
presentingUserId: "LOCAL_USER_ID",
});
} catch (error) {
console.error(error);
}
}
Ouça seus clientes para entender seus cenários antes de implementar a verificação de função em seu aplicativo, principalmente para a função de Organizador. Não há nenhuma garantia de que um organizador esteja presente na reunião. Como regra geral, todos os usuários são Organizador ou Apresentador ao colaborar em uma organização. Se um usuário for um Participante, geralmente é uma decisão intencional do organizador.
Em alguns casos, um usuário pode ter várias funções. Por exemplo, um Organizador também é um Apresentador. Além disso, os participantes da reunião que são externos ao locatário que hospeda a reunião têm a função convidado , mas também podem ter privilégios de Apresentador . Isso fornece muita flexibilidade na forma como você usa a verificação de função em seu aplicativo.
Observação
O SDK do Live Share não tem suporte para usuários convidados em reuniões de canal.
Estruturas de dados distribuídos do Fluid
O SDK do Live Share dá suporte a qualquer estrutura de dados distribuída incluída no Fluid Framework. Esses recursos servem como um conjunto de primitivos que você pode usar para criar cenários colaborativos robustos, como atualizações em tempo real de uma lista de tarefas ou texto de coautoria em um HTML <textarea>
.
Ao contrário das classes mencionadas neste artigo, as estruturas de dados fluidas não são redefinidas após o LiveDataObject
fechamento do aplicativo. Isso é ideal para cenários como o painel lateral da reunião, em que os usuários frequentemente fecham e reabrem seu aplicativo usando outras guias na reunião, como chat.
O Fluid Framework dá suporte oficialmente aos seguintes tipos de estruturas de dados distribuídas:
Objeto Compartilhado | Descrição |
---|---|
SharedMap | Um repositório de chave-valor distribuído. Defina qualquer objeto serializável JSON de uma determinada chave para sincronizar esse objeto para todos na sessão. |
SharedSegmentSequence | Uma estrutura de dados semelhante à lista para armazenar um conjunto de itens (chamados segmentos) em posições definidas. |
SharedString | Uma sequência de cadeias de caracteres distribuídas otimizada para editar o texto de documentos ou áreas de texto. |
Vamos ver como o SharedMap
funciona. Neste exemplo, usamos SharedMap
para criar um recurso de playlist.
import { LiveShareClient } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { SharedMap } from "fluid-framework";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { playlistMap: SharedMap },
};
const { container } = await liveShare.joinContainer(schema);
const playlistMap = container.initialObjects.playlistMap as SharedMap;
// Register listener for changes to values in the map
playlistMap.on("valueChanged", (changed, local) => {
const video = playlistMap.get(changed.key);
// Update UI with added video
});
function onClickAddToPlaylist(video) {
// Add video to map
playlistMap.set(video.id, video);
}
Observação
Os objetos DDS do Fluid Framework principal não dão suporte à verificação de função de reunião. Todos na reunião podem alterar os dados armazenados por meio desses objetos.
Exemplos de código
Nome do exemplo | Descrição | JavaScript |
---|---|---|
Dice Roller | Habilite todos os clientes conectados para rolar um dado e exibir o resultado. | Exibir |
Agile Poker | Permita que todos os clientes conectados joguem o Agile Poker. | Exibir |
Próxima etapa
Confira também
- Aplicativos para reuniões do Teams
- Repositório do GitHub
- Consentimento específico do recurso
- Documentos de referência do SDK do Live Share
- Documentos de referência do SDK de Mídia do Live Share
- Perguntas frequentes do Live Share
- Usar Fluido com o Teams
- Criar o Agile Poker usando o SDK do Live Share
- Tutorial de código do Dice Roller