Observabilidad del cliente: Web

El SDK de video de Vonage expone métricas detalladas de la calidad de la transmisión a través de una API de estadísticas de alto nivel, recomendada para la mayoría de los casos de uso, que proporciona estadísticas de audio, video, red y del lado del emisor en una forma unificada y consciente de la sesión que permanece estable a través de las transiciones de conexión entre pares. Para la depuración avanzada, el SDK también ofrece acceso al informe de estadísticas WebRTC sin procesar, que refleja los datos de la conexión entre pares sin procesar.

El SDK también proporciona métricas sobre el estado de la red que ofrecen una evaluación general del estado de la conexión, tanto para los emisores como para los suscriptores. Estas métricas incluyen una puntuación del estado de la red, el motivo que explica dicha puntuación y, en el caso de los suscriptores, una fuente de degradación que indica qué lado de la conexión es responsable de los problemas observados. Véase Estado de la red y origen de la degradación Para más información.

API de estadísticas de audio, vídeo y enlaces multimedia

El Vonage Video Web SDK envía estadísticas periódicas de audio, video y enlaces multimedia tanto para editores como para suscriptores. Estas incluyen recuentos de paquetes, velocidades de bits, datos de velocidad de fotogramas, métricas de pausa/congelación, información de códec y métricas de red a nivel de transporte, como estimación de ancho de banda y puntuación del estado de la red.

Cómo obtener estadísticas de un editor

El Publisher.getStats() le proporciona una matriz de objetos que definen las estadísticas de audio y vídeo actuales del editor. Para un editor en una sesión enrutada (que utiliza el método OpenTok Router multimedia), este array incluye un objeto que define las estadísticas de la única secuencia de audio y vídeo que se envía al Vonage Video Media Router. En una sesión retransmitida, el array incluye un objeto por cada suscriptor de la secuencia publicada.

El siguiente código registra algunas métricas del flujo del editor cada segundo:

window.setInterval(() => {
  publisher.getStats((error, statsArray) => {
    if (error) {
      console.error(error);
      return;
    }

    statsArray.forEach(statsContainer => {
      const stats = statsContainer.stats;
      const connectionId = stats.connectionId || 'routed';

      console.log(`\nStats for ${connectionId}`);
      if (stats.video) {
        const video = stats.video;

        if (video.layers && video.layers.length > 0) {
          console.log(`Video layers: ${video.layers.length}`);

          video.layers.forEach((layer, index) => {
            console.log(` Layer ${index}: ${layer.width}x${layer.height}`);
            console.log(`   encodedFrameRate: ${layer.encodedFrameRate} fps`);
            console.log(`   bitrate: ${layer.bitrate} bps`);
            console.log(`   totalBitrate: ${layer.totalBitrate} bps`);
            console.log(`   codec: ${layer.codec}`);
            console.log(`   scalabilityMode: ${layer.scalabilityMode}`);
            if (layer.qualityLimitationReason) {
              console.log(`   qualityLimitationReason: ${layer.qualityLimitationReason}`);
            }
          });
        }

        console.log('transport estimated bandwidth:', stats.mediaLink.transport.connectionEstimatedBandwidth, 'bps');
        console.log('network condition:', stats.mediaLink.transport.networkCondition);
        console.log('network condition reason:', stats.mediaLink.transport.networkConditionReason);
      }
    });
  });
}, 1000);

Recepción de eventos de calidad de vídeo en los editores

Además de sondear las estadísticas con Publisher.getStats(), puedes recibir notificaciones en tiempo real cuando el editor detecte un cambio significativo en la calidad del vídeo suscribiéndote a la videoQualityChanged evento:

publisher.on('videoQualityChanged', ({ reason, statsContainer }) => {
  console.log('Video quality change reason:', reason);

  const { stats } = statsContainer;

  if (stats.video && stats.video.layers) {
    stats.video.layers.forEach((layer) => {
      console.log(
        `Resolution: ${layer.width}x${layer.height}, FPS: ${layer.frameRate}`
      );
    });
  }
});

Recepción de eventos de estado de la red en los editores

Para recibir eventos de cambio de estado de la red para el editor, escuche el comando networkConditionChanged evento:

publisher.on('networkConditionChanged', ({ reason, statsContainer }) => {
  const { stats } = statsContainer;
  console.log('Network condition changed.');
  console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
});

Este evento se activa cuando se detecta un cambio significativo en el estado de la red del editor. El statsContainer El objeto incluye las estadísticas de enlaces multimedia del abonado afectado. En las sesiones retransmitidas, solo se incluyen en el evento las estadísticas del abonado afectado.

Obtener estadísticas de un abonado

El getStats() El método de un objeto suscriptor te proporciona información sobre el flujo del suscriptor.

El siguiente código registra varias métricas del flujo de abonados cada segundo:

window.setInterval(() => {
  subscriber.getStats((error, stats) => {
    if (error) {
      console.error('Error getting subscriber stats: ', error.message);
      return;
    }

    const video = stats.video;

    if (video) {
      console.log('video bitrate:', video.bitrate, 'bps');
      console.log('video totalBitrate:', video.totalBitrate, 'bps');
      console.log('decoded frame rate:', video.decodedFrameRate, 'fps');
      console.log('codec:', video.codec);
      console.log('res:', `${video.width}x${video.height}`);

      console.log('freezeCount:', video.freezeCount);
      console.log('totalFreezesDuration:', video.totalFreezesDuration, 'ms');
      console.log('pauseCount:', video.pauseCount);
      console.log('totalPausesDuration:', video.totalPausesDuration, 'ms');
    }
  });
}, 1000);

Recepción de eventos de calidad de vídeo en los abonados

Los suscriptores pueden escuchar el videoQualityChanged evento que se activa cuando se detectan interrupciones o cambios significativos en la calidad del vídeo.

subscriber.on('videoQualityChanged', ({ reason, stats }) => {
  if (reason === 'videoInterruption') {
    console.warn('Video playback was interrupted');

    if (stats.video.freezeCount > 0) {
      console.log(`Freeze count: ${stats.video.freezeCount}`);
    }

    if (stats.video.pauseCount > 0) {
      console.log(`Pause count: ${stats.video.pauseCount}`);
    }
  }
});

Recepción de eventos de estado de la red en los abonados

Para recibir eventos de cambio de estado de la red del abonado, hay que escuchar el networkConditionChanged evento:

subscriber.on('networkConditionChanged', ({ reason, stats }) => {
  console.log('Network condition changed.');
  console.log(`Degradation source: ${stats.mediaLink.networkDegradationSource}`);
  if (stats.mediaLink.networkDegradationSource === 'local') {
    console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
  } else if (stats.mediaLink.networkDegradationSource === 'remote') {
    console.log(`Network Condition: ${stats.mediaLink.remotePublisherTransport.networkCondition}, Reason: ${stats.mediaLink.remotePublisherTransport.networkConditionReason}`);
  }
});

Este evento se activa cuando se detecta un cambio significativo en las condiciones de la red para el abonado o el editor remoto. La dirección stats incluye las estadísticas del enlace multimedia con métricas de transporte local y remoto y la fuente de degradación.

Problemas conocidos

Los valores y condiciones concretos que activan las restricciones de calidad dependen de la implementación y pueden variar según el navegador y la plataforma. Por ejemplo:

  • Los flujos de vídeo de pantalla compartida nunca activan el videoQualityChanged evento.
  • Firefox no admite qualityLimitationReason, por lo que esta propiedad no aparece en las estadísticas del editor. Además, videoQualityChanged acontecimientos con sus motivos bandwidth, cpu y other no son compatibles con este navegador.
  • La codificación de vídeo acelerada por hardware y los codificadores de vídeo dedicados impiden que macOS active cpu limitaciones.

Estadística y estructuras de datos

En esta sección se describen las estructuras y propiedades proporcionadas por la API de estadísticas de audio y vídeo web. Aunque todas las plataformas Video SDK exponen el mismo conjunto de estadísticas, puede haber pequeñas diferencias en la forma en que cada plataforma estructura o nombra los campos individuales. Estas variaciones reflejan convenciones de diseño del SDK específicas de cada plataforma más que diferencias en las métricas subyacentes.

Para una explicación independiente de la plataforma de las estadísticas disponibles y lo que representan, consulte visión general de la observabilidad del cliente.

Estadísticas de la editorial (stats)

Proporciona estadísticas sobre un editor.

  • connectionId — El identificador único de la conexión del cliente, que coincide con la propiedad «id» del connection propiedad del connectionCreated que el objeto Session envió para el cliente remoto (sólo disponible en sesiones retransmitidas).
  • subscriberId - El identificador único del abonado, que coincide con la propiedad id del archivo Subscriber en la aplicación del cliente suscriptor (sólo disponible en sesiones retransmitidas).

Estadísticas de audio del editor (stats.audio)

Proporciona estadísticas sobre la pista de audio de un editor.

  • bytesSent — Total de bytes de audio enviados.
  • packetsLost — Total de paquetes de audio que no llegaron al abonado ni al enrutador multimedia.
  • packetsSent — Total de paquetes de audio enviados.
  • timestamp — Marca de tiempo Unix (ms) en la que se recopilaron las estadísticas.

Estadísticas de vídeo del editor (stats.video)

Estos campos representan el rendimiento de vídeo actual del editor:

  • bytesSent — Total de bytes de vídeo enviados.
  • packetsLost — Total de paquetes de vídeo que no llegaron al abonado ni al enrutador multimedia.
  • packetsSent — Total de paquetes de vídeo enviados.
  • layers - Una lista ordenada de las capas de codificación de vídeo activas de mayor a menor resolución.

Estadísticas de la capa de vídeo del editor (stats.video.layers)

Representa una capa de emisión simultánea o una capa SVC.

  • width - Anchura codificada en píxeles.
  • height — Altura codificada en píxeles.
  • encodedFrameRate- Frecuencia de imagen real de codificación para esta capa.
  • bitrate — Velocidad de transmisión de la carga útil (bps).
  • totalBitrate — Velocidad de bits, incluyendo los encabezados RTP y el relleno (bps).
  • scalabilityMode— Configuración de escalabilidad (por ejemplo, «L1T3» para SVC o «L3T3» para emisión simultánea).
  • codec - Codec utilizado para esta capa.
  • qualityLimitationReason - Indica por qué el codificador ajustó la calidad ('ancho de banda', 'cpu', 'otros').

Estadísticas de enlaces multimedia de editores (stats.mediaLink.transport)

El transport proporciona métricas de estimación de red a nivel de conexión entre pares que se aplican al transporte global de audio-vídeo, en lugar de a pistas o capas individuales.

  • connectionEstimatedBandwidth — Ancho de banda de subida estimado disponible para la conexión (bps).
  • networkCondition — Puntuación del estado actual de la red ("unknown", "critical", "warning", "fair", "good", o "excellent").
  • networkConditionReason — Motivo principal que afecta al estado de la red ("none", "unknown", "bandwidth", o "packetLoss").

Estadísticas de vídeo de abonados (stats.video)

Estos campos describen el rendimiento de la recepción y la decodificación de vídeo en tiempo real del abonado:

  • bytesReceived - Total de bytes de vídeo recibidos.
  • packetsLost - Total de paquetes de vídeo que no llegaron al abonado.
  • packetsReceived - Total de paquetes de vídeo recibidos.
  • timestamp — Marca de tiempo Unix (ms) en la que se recopilaron las estadísticas.
  • decodedFrameRate — Frecuencia de fotogramas real generada por el decodificador (fps).
  • bitrate — Velocidad de transmisión de la carga útil en bits por segundo.
  • totalBitrate — Velocidad de bits, incluyendo los encabezados RTP y el relleno (bps).
  • codec — Códec utilizado para este abonado.
  • pauseCount — Número de pausas en las que no se renderizó ningún fotograma durante ≥5 segundos.
  • totalPausesDuration - Duración acumulada (ms) de todas las pausas.
  • freezeCount - Numbers of short freezes (from the WebRTC stats definition).
  • totalFreezesDuration — Duración acumulada (ms) de todas las interrupciones.

Estimación por parte del remitente del abonado (stats.senderStats)

Estas métricas proporcionan estimaciones de ancho de banda notificadas para la conexión saliente del remitente:

  • connectionMaxAllocatedBitrate - Tasa de bits máxima asignada estimada para el remitente (bps).
  • connectionEstimatedBandwidth - Ancho de banda de enlace ascendente actual estimado para el remitente (bps).

El mediaLink Este objeto proporciona información sobre el nivel de transporte y la degradación de la red en la conexión de un abonado. Tiene la misma estructura que el del editor mediaLink.transport para los transportes local y remoto, además de un indicador de fuente de degradación:

  • transport - Estadísticas de transporte local para la conexión de enlace descendente de este abonado (misma estructura que la del editor stats.mediaLink.transport). Puede verse limitado si las estadísticas del remitente y/o el sistema de reserva de audio están desactivados.
  • remotePublisherTransport — Estadísticas de transporte del editor remoto para la conexión de subida (misma estructura que la del editor stats.mediaLink.transport). Puede verse limitado si las estadísticas del remitente y/o el sistema de reserva de audio están desactivados.
  • networkDegradationSource — Indica qué parte ha provocado la degradación de la red, si la hubiera. Valores posibles: "none", "local", "remote", o "bothOrUnclear". Puede verse limitado si las estadísticas del remitente y/o la opción de audio alternativo están desactivadas.

Supervisión de la calidad de las llamadas

Además de las API de estadísticas básicas, OpenTok.js ofrece funciones adicionales para supervisar y responder a los cambios en la calidad de las llamadas. Estas funciones ayudan a las aplicaciones a optimizar el rendimiento adaptándose a las limitaciones del dispositivo y a las condiciones de la red.

Supervisión del rendimiento de la CPU

Applications may run on various mobile and desktop devices on different platforms. Además, las especificaciones de hardware de los dispositivos no son homogéneas. Por ejemplo, algunos dispositivos móviles pueden tener mejor rendimiento de CPU que muchos dispositivos de sobremesa y viceversa.

La gran variedad de configuraciones de hardware posibles —CPU, GPU, RAM, codificadores/decodificadores de hardware, etc.— implica que puede ser necesario realizar algunos ajustes. Los dispositivos con menos prestaciones pueden configurarse para desactivar las funciones que consumen más recursos de la CPU, mientras que los dispositivos más potentes pueden ofrecer de forma predeterminada una experiencia más inmersiva.

Detección de cambios en el rendimiento de la CPU

Puede detectar cambios en la carga de la CPU del dispositivo monitorizando la Sesión cpuPerformanceChanged evento. El evento contiene un cpuPerformanceState propiedad, cuyo valor puede ser uno de los siguientes:

  • 'nominal' — El dispositivo puede asumir trabajo adicional.
  • 'fair' - El dispositivo puede seguir realizando trabajo adicional, pero la duración de la batería puede verse reducida; además, en el caso de los dispositivos con ventiladores, éstos pueden activarse y hacerse audibles.
  • 'serious' - El dispositivo está estresado, por lo que puede producirse un estrangulamiento de los recursos (por ejemplo, la CPU).
  • 'critical' - El dispositivo está muy estresado; si no se alivia, pueden surgir problemas.

Para más información, consulte esta especificación del W3C.

Optimización de una aplicación en función de los cambios en el rendimiento de la CPU

Ante esta situación, una aplicación puede notificar a los usuarios el consumo de recursos o desactivar procesos que requieren un gran esfuerzo computacional, como transformadores de vídeo. Ver la sesión cpuPerformanceChanged.

El siguiente código desactiva la captura de vídeo cuando la CPU entra en un 'critical' estado de rendimiento y vuelve a activarlo cuando el estado vuelve a ser 'fair' o mejor:

let isVideoDisabledByCPU = false;

session.on('cpuPerformanceChanged', (event) => {
  if (event.cpuPerformanceState === 'critical') {
    // The application should alert the user why their video is being disabled
    publisher.publishVideo(false);
    isVideoDisabledByCPU = true;
  } else if (event.cpuPerformanceState === 'nominal' || event.cpuPerformanceState === 'fair') {
    if (isVideoDisabledByCPU) {
      publisher.publishVideo(true);
      isVideoDisabledByCPU = false;
    }
  }
})

Puntuación media de opinión (MOS)

La calidad de la experiencia que un usuario percibe de un servicio puede calificarse utilizando Puntuación media de la opinión (MOS).

El sistema de clasificación

El MOS se expresa como un número positivo. La puntuación puede oscilar entre 1 (la peor calidad) y 5 (la mejor calidad):

  • 5 (Excelente) - Un hipotético límite superior a la mejor calidad que puede experimentar un usuario.
  • 4 (Bueno) — Una calificación más alcanzable. Los usuarios de Vonage pueden esperar recibir este nivel de calidad.
  • 3 (Regular) - La calidad es aceptable.
  • 2 (Pobre) - La calidad es inaceptable.
  • 1 (Malo) - La calidad es horrible.

El algoritmo

La clasificación MOS tiene en cuenta varios factores, todos los cuales afectan (y pueden degradar) la experiencia del usuario. Estos factores incluyen (pero no se limitan a) los siguientes:

  • Pérdida de paquetes: los paquetes perdidos reducen la calidad de la transmisión
  • Velocidad de bits: cuanto mayor sea la velocidad de bits, mayor será la fidelidad potencial del archivo multimedia.
  • Latencia de la red: los paquetes que llegan demasiado tarde pueden descartarse, lo que puede provocar pérdidas de audio y/o saltos en el vídeo

Optimización de una aplicación en función de los cambios en la calidad de las llamadas

Utilizar el abonado qualityScoreChanged evento para supervisar los cambios en la calidad del audio y el vídeo. Sin embargo, no basta con observar los cambios en la calidad de los contenidos multimedia. Dada la naturaleza en tiempo real de las aplicaciones de llamadas, también es necesario responder a los cambios observados ajustando la aplicación para ofrecer continuamente la mejor experiencia de usuario.

A continuación se muestra una heurística sencilla. Una aplicación se optimiza dinámicamente en función de las restricciones de recursos.

// We want to know if the CPU is overloaded. If it is, then we
// can disable certain features so that the best call possible
// can still take place.
let isCpuOverloaded = false;

session.on('cpuPerformanceChanged', (event) => {
  isCpuOverloaded = event.cpuPerformanceState === 'critical';
});

// We monitor for changes in call quality. This allows us to
// tune our application, taking into account multiple factors
// (inlined below)
subscriber.on('qualityScoreChanged', (event) => {
  const { qualityScore } = event;
  const isVideoQualityBad = qualityScore.video < 2;

  if (!isVideoQualityBad && !isCpuOverloaded) {
    // Subscribe to the highest quality video since the CPU isn't taxed
    // and the quality received is good
    subscriber.setPreferredResolution('1280x720');
    subscriber.setPreferredFrameRate(30);
  }
  else if (isVideoQualityBad && !isCpuOverloaded) {
    // Even though the CPU isn't taxed, the video quality received is
    // bad. This might be due to (hopefully) intermittent network issues, so
    // we subscribe to lower quality video.
    subscriber.setPreferredResolution('320x180');
    subscriber.setPreferredFrameRate(7);
  }
  else if (isVideoQualityBad && isCpuOverloaded) {
    // The video quality received is bad and the CPU not being overloaded.
    // Let's disable video for now.
    // We can enable video once conditions improve. See statement below.
    subscriber.subscribeToVideo(false);
  }
  else {
    // Enable video
    subscriber.subscribeToVideo(true);
  }
});

Estimación de la calidad de la llamada en una prueba previa a la llamada

Puedes usar Vonage Video Biblioteca de pruebas de red para Web para ver si el cliente admite la publicación de audio y vídeo e informa de las puntuaciones MOS de audio y vídeo estimadas para la transmisión publicada de un cliente. Esta biblioteca utiliza el módulo Publisher.getRtcStatsReport() y Subscriber.subscriber.getStats() métodos para calcular la puntuación MOS.

Estadísticas del remitente

Véase el Resumen de las estadísticas del lado del remitente.

Activación de las estadísticas del remitente

Las estadísticas del remitente se reciben en los suscriptores. Para recibir las estadísticas del remitente, actívalas para el editor de la transmisión pasando el publishSenderStats con el valor true en el OT.initPublisher llamar:

const publisher = OT.initPublisher({
  publishSenderStats: true
});

Si publishSenderStats no está activado, no se publicará ningún canal de estadísticas del remitente para este editor. El valor por defecto es false.

Recepción de estadísticas del remitente

Si el editor ha activado las estadísticas del lado del remitente, los abonados las reciben automáticamente a través de Subscriber.getStats() descrito anteriormente. En senderStats del objeto stats devuelto proporciona dos métricas:

  • connectionMaxAllocatedBitrate - El bitrate máximo que se puede estimar para la conexión (bps)
  • connectionEstimatedBandwidth - El ancho de banda actual estimado para la conexión (bps)

Estas métricas se calculan por paquete de audio y vídeo, por lo que aparecen los mismos valores en las estadísticas de vídeo y audio. Tenga en cuenta que la primera llamada a getStats Es posible que no se incluyan las estadísticas del remitente debido a la latencia de la red.

subscriber.getStats((stats) => {
  if (stats.senderStats) {
    console.log(`Connection max allocated bitrate: ${stats.senderStats.connectionMaxAllocatedBitrate} bps`);
    console.log(`Connection current estimated bandwidth: ${stats.senderStats.connectionEstimatedBandwidth} bps`);
  }
});

Problemas conocidos

En algunos casos, cuando la sesión se retransmite -o en determinadas configuraciones enrutadas con sólo dos participantes- y el Editor utiliza Firefox, es posible que las estadísticas del lado del remitente no estén disponibles debido a las limitaciones del navegador.

Estado y degradación de la red Fuente

El SDK proporciona métricas en tiempo real sobre el estado de la red tanto para los editores como para los suscriptores, incluyendo una puntuación de estado, el motivo que la determina y, en el caso de los suscriptores, la fuente de la degradación. Para obtener una explicación detallada del modelo de estado de la red, las puntuaciones, los motivos y cómo activarlo, consulta el visión general de la observabilidad del cliente.

Los datos sobre el estado de la red están disponibles a través de dos canales:

  • Estadísticas periódicas: Los eventos de estadísticas de enlaces multimedia incluyen métricas de transporte con connectionEstimatedBandwidth, networkCondition y networkConditionReason. Las estadísticas de los abonados también exponen remotePublisherTransport y networkDegradationSource.
  • Eventos relacionados con cambios en el estado de la red: Eventos específicos en ambos editor y suscriptor se activan cuando se detecta un cambio significativo en el estado de la red.

El siguiente ejemplo muestra cómo utilizar los datos de estado de la red del abonado para identificar la fuente de degradación:

subscriber.on('networkConditionChanged', ({ reason, stats }) => {
  console.log('Network condition changed.');
  console.log(`Degradation source: ${stats.mediaLink.networkDegradationSource}`);
  if (stats.mediaLink.networkDegradationSource === 'local') {
    console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
  } else if (stats.mediaLink.networkDegradationSource === 'remote') {
    console.log(`Network Condition: ${stats.mediaLink.remotePublisherTransport.networkCondition}, Reason: ${stats.mediaLink.remotePublisherTransport.networkConditionReason}`);
});

Informe de estadísticas de RTC

Para obtener estadísticas de conexión entre pares de bajo nivel para un editor, utilice la función Publisher.getRtcStatsReport() método. Devuelve una promesa que, en caso de éxito, se resuelve con un RtcStatsReport para el flujo suscrito:

publisher.getRtcStatsReport()
  .then((stats) => stats.forEach(console.log))
  .catch(console.log);

Para obtener estadísticas de conexión entre pares de bajo nivel para un abonado, utilice la función Subscriber.getRtcStatsReport() método. Devuelve una promesa que, en caso de éxito, se resuelve con un RtcStatsReport para el flujo suscrito:

subscriber.getRtcStatsReport()
  .then((stats) => stats.forEach(console.log))
  .catch(console.log);