Capacidades multimedia de Live Share

El vídeo y el audio forman parte fundamental del mundo moderno y de los lugares de trabajo. Hemos escuchado comentarios muy amplios sobre que podemos hacer más para aumentar la calidad, la accesibilidad y las protecciones de licencia de ver vídeos juntos en reuniones.

El SDK de Live Share permite una sincronización de medios sólida para cualquier html <video> y <audio> elemento con solo unas pocas líneas de código. Al sincronizar medios en la capa de controles de transporte y estado del reproductor, podrá atribuir vistas y licencias individualmente, a la vez que proporciona la mayor calidad posible disponible a través de la aplicación.

Instalar

Live Share Media es un paquete de JavaScript publicado en npm y se puede descargar a través de npm o yarn. También debe instalar sus dependencias del mismo nivel, que incluyen @microsoft/live-share, fluid-framework y @fluidframework/azure-client. Si usa Live Share en la aplicación de pestaña, también debe instalar @microsoft/teams-js la versión 2.11.0 o posterior.

npm install @microsoft/live-share @microsoft/live-share-media fluid-framework @fluidframework/azure-client --save
npm install @microsoft/teams-js --save

O

Para agregar la versión más reciente del SDK a la aplicación mediante Yarn:

yarn add @microsoft/live-share @microsoft/live-share-media fluid-framework @fluidframework/azure-client
yarn add @microsoft/teams-js

Introducción a la sincronización multimedia

El SDK de Live Share tiene dos clases principales relacionadas con la sincronización de medios:

Clases Descripción
LiveMediaSession Objeto dinámico personalizado diseñado para coordinar los controles de transporte multimedia y el estado de reproducción en secuencias de medios independientes.
MediaPlayerSynchronizer Sincroniza cualquier objeto que implemente la IMediaPlayer interfaz , incluidos HTML5 <video> y <audio> , mediante LiveMediaSession.

Ejemplo:

<body>
  <video id="player">
    <source src="YOUR_VIDEO_SRC" type="video/mp4" />
  </video>
</body>
import {
  LiveShareClient,
  UserMeetingRole,
  MediaPlayerSynchronizerEvents,
} from "@microsoft/live-share";
import { LiveMediaSession } from "@microsoft/live-share-media";
import { LiveShareHost } from "@microsoft/teams-js";

// Setup the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
  initialObjects: { mediaSession: LiveMediaSession },
};
const { container } = await liveShare.joinContainer(schema);
const { mediaSession } = container.initialObjects;

// Get the player from your document and create synchronizer
const player = document.getElementById("player");
const synchronizer = mediaSession.synchronize(player);

// Listen for groupaction events (optional)
synchronizer.addEventListener(MediaPlayerSynchronizerEvents.groupaction, async (evt) => {
  // See which user made the change (e.g., to display a notification)
  const clientInfo = await synchronizer.mediaSession.getClientInfo(evt.details.clientId);
});

// Define roles you want to allow playback control and start sync
const allowedRoles = [UserMeetingRole.organizer, UserMeetingRole.presenter];
await mediaSession.initialize(allowedRoles);

LiveMediaSession escucha automáticamente los cambios en el estado de reproducción del grupo. MediaPlayerSynchronizer escucha los cambios de estado emitidos por LiveMediaSession y los aplica al objeto proporcionado IMediaPlayer , como un elemento HTML5 <video> o <audio> . Para evitar los cambios de estado de reproducción que un usuario no inició intencionadamente, como un evento de búfer, deberemos llamar a los controles de transporte a través del sincronizador, en lugar de directamente a través del reproductor.

Ejemplo:

<body>
  <video id="player">
    <source src="YOUR_VIDEO_SRC" type="video/mp4" />
  </video>
  <div class="player-controls">
    <button id="play-button">Play</button>
    <button id="pause-button">Pause</button>
    <button id="restart-button">Restart</button>
    <button id="change-track-button">Change track</button>
  </div>
</body>
// ...

document.getElementById("play-button").onclick = async () => {
  // Plays for all users in the session.
  // If using role verification, this throws an error if the user doesn't have the required role.
  await synchronizer.play();
};

document.getElementById("pause-button").onclick = async () => {
  // Pauses for all users in the session.
  // If using role verification, this throws an error if the user doesn't have the required role.
  await synchronizer.pause();
};

document.getElementById("restart-button").onclick = async () => {
  // Seeks for all users in the session.
  // If using role verification, this throws an error if the user doesn't have the required role.
  await synchronizer.seekTo(0);
};

document.getElementById("change-track-button").onclick = () => {
  // Changes the track for all users in the session.
  // If using role verification, this throws an error if the user doesn't have the required role.
  synchronizer.setTrack({
    trackIdentifier: "SOME_OTHER_VIDEO_SRC",
  });
};

Nota:

Aunque puede usar el LiveMediaSession objeto para sincronizar los medios manualmente, por lo general se recomienda usar MediaPlayerSynchronizer. En función del reproductor que use en la aplicación, es posible que deba crear una corrección de compatibilidad de delegado para que la interfaz del reproductor web coincida con la interfaz IMediaPlayer .

Suspensiones y puntos de espera

Captura de pantalla que muestra una sincronización de suspensión con el moderador.

Si desea suspender temporalmente la sincronización del objeto LiveMediaSession, puede usar suspensiones. Un MediaSessionCoordinatorSuspension objeto es local de forma predeterminada, lo que puede resultar útil en los casos en los que un usuario podría querer ponerse al día con algo que se perdió, tomarse un descanso, etc. Si el usuario finaliza la suspensión, la sincronización se reanudará automáticamente.

// Suspend the media session coordinator
const suspension = mediaSession.coordinator.beginSuspension();

// End the suspension when ready
suspension.end();

Al iniciar una suspensión, también se puede incluir un parámetro opcional CoordinationWaitPoint, que permite a los usuarios definir las marcas de tiempo en las que se deba producir una suspensión para todos los usuarios. La sincronización no se reanuda hasta que todos los usuarios terminan la suspensión de ese punto de espera.

Estos son algunos escenarios en los que los puntos de espera son especialmente útiles:

  • Agregar un cuestionario o una encuesta en determinados puntos del vídeo.
  • Esperando a que todos carguen adecuadamente un vídeo antes de que se inicie o mientras se almacena en búfer.
  • Permitir que un moderador elija puntos en el vídeo para la discusión en grupo.
// Suspend the media session coordinator
const waitPoint = {
  position: 0,
  reason: "ReadyUp", // Optional.
};
const suspension = mediaSession.coordinator.beginSuspension(waitPoint);
// End the suspension when the user readies up
document.getElementById("ready-up-button").onclick = () => {
  // Sync resumes when everyone ends suspension
  suspension.end();
};

Atenuación de audio

El SDK de Live Share admite la atenuación de audio inteligente. Puede usar la característica en la aplicación agregando lo siguiente al código:

import { meeting } from "@microsoft/teams-js";

// ... set up MediaPlayerSynchronizer

// Register speaking state change handler through Microsoft Teams JavaScript client library (TeamsJS)
let volumeTimer;
meeting.registerSpeakingStateChangeHandler((speakingState) => {
  if (speakingState.isSpeakingDetected && !volumeTimer) {
    // If someone in the meeting starts speaking, periodically
    // lower the volume using your MediaPlayerSynchronizer's
    // VolumeLimiter.
    synchronizer.volumeLimiter?.lowerVolume();
    volumeTimer = setInterval(() => {
      synchronizer.volumeLimiter?.lowerVolume();
    }, 250);
  } else if (volumeTimer) {
    // If everyone in the meeting stops speaking and the
    // interval timer is active, clear the interval.
    clearInterval(volumeTimer);
    volumeTimer = undefined;
  }
});

Además, agregue los siguientes permisos de RSC al manifiesto de la aplicación:

{
  // ...rest of your manifest here
  "authorization": {​
    "permissions": {​
      "resourceSpecific": [
        // ...other permissions here​
        {​
          "name": "OnlineMeetingIncomingAudio.Detect.Chat",​
          "type": "Delegated"
        },
        {​
          "name": "OnlineMeetingIncomingAudio.Detect.Group",​
          "type": "Delegated"​
        }​
      ]​
    }​
  }​
}

Nota:

La registerSpeakingStateChangeHandler API que se usa para el pato de audio solo funciona en el escritorio de Microsoft Teams y en los tipos de reunión programados y que ahora se cumplen.

Ejemplos de código

Ejemplo de nombre Descripción JavaScript TypeScript
Vídeo de React Ejemplo básico que muestra cómo funciona el objeto LiveMediaSession con vídeo HTML5. Ver ND
Plantilla multimedia de React Permitir que todos los clientes conectados vean vídeos juntos, compilen una lista de reproducción compartida, transfieran a quién está al control y anoten sobre el vídeo. View View

Paso siguiente

Vea también