Observabilité du client : Web

Le SDK Video de Vonage expose des mesures détaillées de la qualité du flux par le biais d'une API de statistiques de haut niveau - recommandée pour la plupart des cas d'utilisation - qui fournit des statistiques audio, vidéo, réseau et côté expéditeur sous une forme unifiée et consciente de la session, qui reste stable lors des transitions de connexion entre pairs. Pour le débogage avancé, le SDK permet également d'accéder au rapport de statistiques WebRTC brut, qui reflète les données de connexion entre pairs non traitées.

API pour les statistiques audio et vidéo

Le SDK vidéo Web de Vonage envoie des statistiques périodiques sur le réseau audio et vidéo pour les éditeurs et les abonnés. Ces statistiques comprennent le nombre de paquets, les débits binaires, les données sur la fréquence d'images, les mesures de pause et de gel, les informations sur les codecs et l'estimation optionnelle du réseau du côté de l'expéditeur.

Obtenir des statistiques pour un éditeur

Les Publisher.getStats() vous fournit un tableau d'objets définissant les statistiques audio-vidéo actuelles de l'éditeur. Pour un éditeur dans une session acheminée (qui utilise la méthode OpenTok Routeur média), ce tableau comprend un objet, définissant les statistiques pour un seul flux audio-vidéo envoyé au routeur vidéo de Vonage. le flux audio-vidéo unique envoyé au routeur vidéo de Vonage. Dans une session relayée, le tableau comprend un objet pour chaque abonné au flux publié.

Le code suivant enregistre certaines mesures du flux de l'éditeur toutes les secondes :

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}`);
            }
          });
        }

        if (stats.transportStats) {
          console.log(
            'transport estimated bandwidth:',
            stats.transportStats.connectionEstimatedBandwidth,
            'bps'
          );
        }
      }
    });
  });
}, 1000);

Réception d'événements de qualité vidéo sur les éditeurs

En plus des statistiques de sondage avec Publisher.getStats()vous pouvez recevoir des notifications en temps réel lorsque l'éditeur détecte un changement significatif dans la qualité de la vidéo en vous abonnant au service de notification de l'éditeur. videoQualityChanged événement :

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}`
      );
    });
  }
});

Obtenir des statistiques pour un abonné

Les getStats() d'un objet abonné vous fournit des informations sur le flux de l'abonné. de l'abonné.

Le code suivant enregistre plusieurs mesures pour le flux de l'abonné toutes les secondes :

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);

Réception d'événements relatifs à la qualité vidéo sur les abonnés

Les abonnés peuvent écouter les videoQualityChanged pour être averti lorsque des interruptions ou des changements significatifs de la qualité vidéo sont détectés.

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}`);
    }
  }
});

Problèmes connus

Les valeurs et conditions réelles qui déclenchent les limitations de qualité sont spécifiques à l'implémentation et peuvent varier d'un navigateur à l'autre et d'une plate-forme à l'autre. A titre d'exemple :

  • Les flux vidéo de partage d'écran ne déclenchent jamais le videoQualityChanged événement.
  • Firefox ne prend pas en charge qualityLimitationReasonCette propriété n'est donc pas présente dans les statistiques de l'éditeur. En outre, videoQualityChanged événements motivés bandwidth, cpu et other ne sont pas prises en charge par ce navigateur.
  • L'encodage vidéo accéléré par le matériel et les encodeurs vidéo dédiés empêchent macOS de se déclencher cpu limitations.

Statistiques Structures de données

Cette section présente les structures et les propriétés fournies par l'API de statistiques audio et vidéo sur le Web. Bien que toutes les plates-formes SDK vidéo exposent le même ensemble de statistiques, il peut y avoir des différences mineures dans la façon dont chaque plate-forme structure ou nomme les champs individuels. Ces variations reflètent les conventions de conception des SDK spécifiques à chaque plate-forme plutôt que des différences dans les mesures sous-jacentes.

Statistiques de l'éditeur (stats)

Fournit des statistiques sur un éditeur.

  • connectionId - L'identifiant unique de la connexion du client, qui correspond à la propriété id de la balise connection de la propriété connectionCreated que l'objet Session a envoyé au client distant (disponible uniquement dans les sessions relayées).
  • subscriberId - L'identifiant unique de l'abonné, qui correspond à la propriété id de l'élément Subscriber dans l'application du client abonné (disponible uniquement dans les sessions relayées).

Statistiques audio de l'éditeur (stats.audio)

Fournit des statistiques sur la piste audio d'un éditeur.

  • bytesSent - Nombre total d'octets audio envoyés.
  • packetsLost - Total des paquets audio qui n'ont pas atteint l'abonné ou le routeur média.
  • packetsSent - Total des paquets audio envoyés.
  • timestamp - Horodatage Unix (ms) du moment où les statistiques ont été recueillies.

Statistiques vidéo de l'éditeur (stats.video)

Ces champs représentent la performance vidéo actuelle de l'éditeur :

  • bytesSent - Nombre total d'octets vidéo envoyés.
  • packetsLost - Total des paquets vidéo qui n'ont pas atteint l'abonné ou le routeur média.
  • packetsSent - Total des paquets vidéo envoyés.
  • layers - Liste ordonnée des couches de codage vidéo actives, de la résolution la plus élevée à la plus faible.

Statistiques de la couche vidéo de l'éditeur (stats.video.layers)

Représente une couche simulcast ou une couche SVC.

  • width - Largeur encodée en pixels.
  • height - Hauteur codée en pixels.
  • encodedFrameRate- Taux de rafraîchissement réel de l'encodage pour cette couche.
  • bitrate - Débit binaire de la charge utile (bps).
  • totalBitrate - Débit binaire incluant les en-têtes RTP et le rembourrage (bps).
  • scalabilityMode- Configuration de l'évolutivité (par exemple, "L1T3" pour le SVC ou "L3T3" pour la diffusion simultanée).
  • codec - Codec utilisé pour cette couche.
  • qualityLimitationReason - Indique pourquoi l'encodeur a ajusté la qualité ('bandwidth', 'cpu', 'other').

Éditeur Statistiques de transport (stats.transport)

L'objet transportStats fournit des mesures d'estimation du réseau au niveau de la connexion homologue qui s'appliquent à l'ensemble du transport audio-vidéo, plutôt qu'à des pistes ou couches individuelles.

  • connectionEstimatedBandwidth - Estimation de la largeur de bande disponible sur la liaison montante pour la connexion (bps).

Statistiques audio des abonnés (stats.audio)

Fournit des statistiques sur la piste audio d'un abonné.

  • bytesReceived - Nombre total d'octets audio reçus.
  • packetsLost - Total des paquets audio qui n'ont pas atteint l'abonné.
  • packetsReceived - Total des paquets audio reçus avec succès.
  • timestamp - Horodatage Unix (ms) du moment où ces statistiques ont été recueillies.

Statistiques vidéo des abonnés (stats.video)

Ces champs décrivent les performances de réception et de décodage vidéo en temps réel de l'abonné :

  • bytesReceived - Nombre total d'octets vidéo reçus.
  • packetsLost - Total des paquets vidéo qui n'ont pas atteint l'abonné.
  • packetsReceived - Total des paquets vidéo reçus.
  • timestamp - Horodatage Unix (ms) du moment où les statistiques ont été recueillies.
  • decodedFrameRate - Fréquence d'image réelle produite par le décodeur (fps).
  • bitrate - Débit binaire de la charge utile en bits par seconde.
  • totalBitrate - Débit binaire incluant les en-têtes RTP et le rembourrage (bps).
  • codec - Codec utilisé pour cet abonné.
  • pauseCount - Nombre de pauses où aucune image n'a été rendue pendant ≥5 secondes.
  • totalPausesDuration - Durée cumulée (ms) de toutes les pauses.
  • freezeCount - Nombre de blocages brefs (d'après la définition des statistiques WebRTC).
  • totalFreezesDuration - Durée cumulée (ms) de tous les blocages.

Abonné Estimation côté émetteur (stats.senderStats)

Ces mesures fournissent des estimations de la largeur de bande pour la connexion sortante de l'expéditeur :

  • connectionMaxAllocatedBitrate - Débit maximum alloué estimé pour l'émetteur (bps).
  • connectionEstimatedBandwidth - Largeur de bande estimée de la liaison montante pour l'émetteur (bps).

Contrôle de la qualité des appels

Au-delà des API statistiques de base, OpenTok.js offre des capacités supplémentaires pour surveiller les changements de qualité des appels et y répondre. Ces fonctionnalités aident les Applications à optimiser les performances en s'adaptant aux contraintes des appareils et aux conditions du réseau.

Surveillance des performances de l'unité centrale

Les applications peuvent s'exécuter sur divers appareils mobiles et de bureau sur différentes plateformes. En outre, les spécifications matérielles des appareils ne sont pas homogènes. Par exemple, certains appareils mobiles peuvent avoir une meilleure performance de l'unité centrale que de nombreux appareils de bureau et vice-versa.

Le grand nombre de configurations matérielles possibles - CPU(s), GPU, RAM, encodeurs/décodeurs matériels, etc. Les appareils moins performants peuvent être configurés de manière à désactiver les fonctions les plus gourmandes en ressources processeur, tandis que les appareils plus performants peuvent être configurés par défaut pour une expérience plus immersive.

Détection des changements de performances de l'unité centrale

Vous pouvez détecter les changements dans la charge de l'unité centrale de l'appareil en surveillant la Session cpuPerformanceChanged l'événement. L'événement contient un cpuPerformanceState qui prend l'une des valeurs suivantes :

  • 'nominal' - Le dispositif peut prendre en charge des tâches supplémentaires.
  • 'fair' - L'appareil peut encore effectuer des tâches supplémentaires, mais la durée de vie de la batterie peut être réduite ; en outre, pour les appareils équipés de ventilateurs, ces derniers peuvent devenir actifs et audibles.
  • 'serious' - L'appareil est sollicité, ce qui peut entraîner une limitation des ressources (par exemple, le processeur).
  • 'critical' - L'appareil est extrêmement sollicité ; s'il n'est pas soulagé, des problèmes peuvent survenir.

Pour plus de détails, voir cette spécification du W3C.

Optimisation d'une application en fonction de l'évolution des performances du processeur

En réponse à cet événement, une application peut informer les utilisateurs de la consommation des ressources ou désactiver les processus coûteux en temps de calcul, tels que les processus de gestion des ressources. consommation de ressources ou désactiver les processus coûteux en termes de calcul, tels que transformateurs vidéo. Voir la session cpuPerformanceChanged.

Le code suivant désactive la capture vidéo lorsque l'unité centrale entre en mode 'critical' l'état de performance et le réactive une fois que l'état revient à 'fair' ou mieux :

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;
    }
  }
})

Score d'opinion moyen (MOS)

La qualité de l'expérience qu'un utilisateur perçoit d'un service peut être évaluée à l'aide des éléments suivants Score d'opinion moyen (MOS).

Le système de notation

Le MOS est exprimé sous la forme d'un nombre positif. Le score peut aller de 1 (la plus mauvaise qualité) à 5 (la meilleure qualité) :

  • 5 (Excellent) - Limite supérieure hypothétique de la meilleure qualité qu'un utilisateur puisse expérimenter.
  • 4 (Bon) - Une note plus accessible. Les utilisateurs de Vonage peuvent s'attendre à recevoir ce niveau de qualité.
  • 3 (Moyen) - La qualité est correcte.
  • 2 (Médiocre) - La qualité est inacceptable.
  • 1 (Mauvais) - La qualité est mauvaise.

L'algorithme

La note MOS tient compte de plusieurs facteurs, qui ont tous un impact sur (et peuvent dégrader) l'expérience de l'utilisateur. Ces facteurs incluent (mais ne sont pas limités à) ce qui suit :

  • Perte de paquets - les paquets perdus dégradent la qualité du média
  • Débit binaire - plus le débit binaire est élevé, plus la fidélité potentielle du média est importante.
  • Latence du réseau - les paquets qui arrivent trop tard peuvent être abandonnés, ce qui peut entraîner un manque de son et/ou une vidéo saccadée.

Optimisation d'une application en fonction des modifications de la qualité des appels

Utiliser l'abonné qualityScoreChanged pour surveiller les changements de qualité audio et vidéo. L'observation des changements de la qualité des médias n'est cependant pas suffisante. Étant donné la nature en temps réel des applications d'appel, il est également nécessaire de répondre aux changements observés en ajustant votre application pour offrir en permanence la meilleure expérience possible à l'utilisateur.

Une heuristique simple est présentée ci-dessous. Une application est optimisée de manière dynamique, en fonction des contraintes de ressources.

// 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);
  }
});

Estimation de la qualité de l'appel lors d'un test préalable à l'appel

Vous pouvez utiliser la vidéo Vonage Bibliothèque de tests de réseaux pour le Web pour savoir si le client prend en charge la publication de l'audio et de la vidéo et pour indiquer les scores MOS audio et vidéo estimés pour le flux publié par un client. Cette bibliothèque utilise la bibliothèque Publisher.getRtcStatsReport() et Subscriber.subscriber.getStats() pour calculer le score MOS.

Statistiques côté expéditeur

Voir le aperçu des statistiques côté expéditeur.

Activation des statistiques côté expéditeur

Les statistiques côté émetteur sont reçues par les abonnés. Pour recevoir les statistiques côté expéditeur, activez-les pour l'éditeur du flux en passant l'attribut publishSenderStats est définie comme étant la propriété true dans le OT.initPublisher appel :

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

Si publishSenderStats n'est pas activé, aucun canal de statistiques sur les expéditeurs ne sera publié pour cet éditeur. La valeur par défaut est false.

Abonnement aux statistiques côté expéditeur

Les abonnés ne reçoivent automatiquement des statistiques sur les expéditeurs que si l'éditeur les a activées et si l'utilisateur appelle l'option Subscriber.getStats() au moins une fois. Notez qu'en raison de la latence du réseau, le premier appel à getStats peut ne pas inclure de statistiques sur l'expéditeur. Les appels ultérieurs sont plus susceptibles de renvoyer ces données.

Aucun événement ou méthode supplémentaire n'est nécessaire ; les statistiques relatives à l'expéditeur sont incluses dans la base de données existante de l stats renvoyé par getStats().

Statistiques de réception Événements

Les statistiques du côté de l'expéditeur sont incluses en tant qu'élément facultatif. senderStats à l'intérieur de l'objet stats transmis à l'objet Subscriber.getStats() callback. Les senderStats contient deux propriétés :

  • connectionMaxAllocatedBitrate - Le débit maximum qui peut être estimé pour la connexion (en bits par seconde)

  • connectionEstimatedBandwidth - Largeur de bande actuelle estimée pour la connexion (en bits par seconde)

Ces deux mesures sont calculées par paquet audio-vidéo, de sorte que les mêmes valeurs apparaissent dans les statistiques audio et vidéo. Parce qu'elles reflètent le transport plutôt que les pistes individuelles, les mesures sont partagées entre l'audio et la vidéo.

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`);
  } else {
    console.log("Sender stats not available yet.");
  }
});

Problèmes connus

Dans certains cas, lorsque la session est relayée - ou dans certaines configurations routées avec seulement deux participants - et que l'éditeur utilise Firefox, les statistiques côté expéditeur peuvent ne pas être disponibles en raison des limitations du navigateur.

Rapport statistique RTC

Pour obtenir des statistiques de bas niveau sur les connexions entre pairs pour un éditeur, utilisez la commande Publisher.getRtcStatsReport() . Elle renvoie une promesse qui, en cas de succès, est résolue avec un numéro d'identification. Elle renvoie une promesse qui, en cas de succès, se résout avec un RtcStatsReport pour le flux souscrit :

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

Pour obtenir des statistiques de bas niveau sur les connexions entre pairs pour un abonné, utilisez la commande Subscriber.getRtcStatsReport() . Elle renvoie une promesse qui, en cas de succès, est résolue avec un numéro d'identification. Elle renvoie une promesse qui, en cas de succès, se résout avec un RtcStatsReport pour le flux souscrit :

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