Observabilité côté client — iOS (Swift)

Le SDK OpenTok pour iOS propose des appels permettant d'accéder aux statistiques en temps réel relatives au réseau et aux médias au cours d'une session vidéo. Ces appels fournissent des indicateurs détaillés sur la qualité du flux — tels que la perte de paquets, les données reçues et la bande passante — et peuvent être utilisés sur n'importe quel flux émetteur ou abonné.

∏ Le SDK vidéo OpenTok fournit des indicateurs détaillés sur la qualité du flux via une API de statistiques de haut niveau — recommandée pour la plupart des cas d'utilisation — qui propose des statistiques audio, vidéo, réseau et côté émetteur sous une forme unifiée et adaptée à la session, qui reste stable lors des transitions entre connexions entre pairs. Pour un débogage avancé, le SDK offre également l'accès au rapport brut des statistiques WebRTC, qui reflète les données brutes relatives aux connexions entre pairs.

Le SDK expose également des mesures de l'état du réseau qui fournissent une évaluation de haut niveau de la santé de la connexion pour les éditeurs et les abonnés. Ces mesures comprennent un score d'état du réseau, la raison de ce score et, pour les abonnés, une source de dégradation indiquant quel côté de la connexion est responsable des problèmes observés. Voir État du réseau et source de dégradation pour plus de détails.

Ce guide comprend les sections suivantes :

API de statistiques sur les liens audio, vidéo et multimédia

Le SDK OpenTok pour iOS envoie régulièrement des statistiques relatives à l'audio, à la vidéo et aux liens multimédias, tant pour les émetteurs que pour les abonnés. Ces statistiques comprennent le nombre de paquets, les débits binaires, les données relatives à la fréquence d'images, les indicateurs de pause/gel, les informations sur les codecs, ainsi que des indicateurs réseau au niveau du transport, tels que l'estimation de la bande passante et l'évaluation de l'état du réseau.

Les statistiques sont fournies par l'intermédiaire de :

  • OTPublisherKitNetworkStatsDelegate - statistiques côté éditeur (audio, vidéo)

  • OTSubscriberKitNetworkStatsDelegate - statistiques relatives aux abonnés (audio, vidéo)

Pour les recevoir, activez le délégué approprié sur l'éditeur ou l'abonné.

Activation des statistiques pour les éditeurs

Attachez une classe qui adopte OTPublisherKitNetworkStatsDelegate :

class MyViewController: UIViewController, OTPublisherKitDelegate, OTPublisherKitNetworkStatsDelegate {
    var publisher: OTPublisher?

    func setupPublisher() {
        let settings = OTPublisherSettings()
        // Configure settings as needed
        publisher = OTPublisher(delegate: self, settings: settings)
        publisher?.networkStatsDelegate = self
    }
}

Mettre en œuvre les rappels :

func publisher(_ publisher: OTPublisherKit, videoNetworkStatsUpdated stats: [OTPublisherKitVideoNetworkStats]) {
    let first = stats.first

    // For routed sessions, stats.first is enough.
    // For relayed sessions (one object per subscriber), you would iterate all elements.
    let connectionId = first.connectionId.isEmpty ? "<none>" : first.connectionId
    let subscriberId = first.subscriberId.isEmpty ? "<none>" : first.subscriberId

    print("Publisher Video Stats for connectionId: \(connectionId), subscriberId: \(subscriberId)")
    print("Video bytes sent: \(first.videoBytesSent)")
    print("Video packets sent: \(first.videoPacketsSent)")
    print("Video packets lost: \(first.videoPacketsLost)")
    print("Current average frame rate: \(first.videoFrameRate) fps")

    for layer in first.videoLayers {
        print("Layer: \(layer.width)x\(layer.height)")
        print("  Encoded FPS: \(layer.encodedFrameRate)")
        print("  Bitrate: \(layer.bitrate) bps")
        print("  Total bitrate (incl. RTP overhead): \(layer.totalBitrate) bps")
        print("  Codec: \(layer.codec ?? "<none>")")
        print("  Scalability mode: \(layer.scalabilityMode ?? "<none>")")
        print("  Quality limitation: \(layer.qualityLimitationReason.rawValue)")
    }

}

func publisher(_ publisher: OTPublisherKit, audioNetworkStatsUpdated stats: [OTPublisherKitAudioNetworkStats]) {
    let first = stats.first

    // For routed sessions, stats.first is enough.
    // For relayed sessions (one object per subscriber), you would iterate all elements.
    let connectionId = first.connectionId.isEmpty ? "<none>" : first.connectionId
    let subscriberId = first.subscriberId.isEmpty ? "<none>" : first.subscriberId

    print("Publisher Audio Stats for connectionId: \(connectionId), subscriberId: \(subscriberId)")
    print("Audio bytes sent: \(first.audioBytesSent)")
    print("Audio packets sent: \(first.audioPacketsSent)")
    print("Audio packets lost: \(first.audioPacketsLost)")
}

func publisher(_ publisher: OTPublisherKit, mediaLinkStatsUpdated mediaLinkStats: [OTPublisherKitMediaLinkStats]) {
    if let stats = mediaLinkStats.first {
        print("Publisher uplink bandwidth: \(stats.transport.connectionEstimatedBandwidth) bps")
        print("Network condition: \(stats.transport.networkCondition.rawValue)")
        print("Condition reason: \(stats.transport.networkConditionReason.rawValue)")
    }
}

Pour un éditeur dans une session acheminée (qui utilise l'option Routeur vidéo multimédia de Vonage, le tableau « stats » contient un objet définissant les statistiques relatives au flux multimédia audio ou vidéo unique envoyé au routeur multimédia Vonage Video. Dans une session relayée, le tableau « stats » contient un objet pour chaque abonné au flux publié.

Réception d'événements liés à la qualité vidéo chez les éditeurs

Si vous êtes également intéressé par les événements relatifs à la qualité de la vidéo, implémentez ce callback :

func publisher(_ publisher: OTPublisherKit, videoQualityChanged stats: OTPublisherKitVideoNetworkStats, reason: OTPublisherVideoEventReason) {
    print("Publisher video quality event: \(reason.rawValue)")
}

Réception d'événements liés à l'état du réseau sur les éditeurs

Pour recevoir les événements de modification des conditions du réseau pour l'éditeur, implémentez la fonction publisher(_:networkConditionChanged:mediaLinkStats:reason:) rappel :

func publisher(_ publisher: OTPublisherKit, networkConditionChanged mediaLinkStats: OTPublisherKitMediaLinkStats, reason: OTNetworkReason) {
    if let transport = mediaLinkStats.transport {
        print("Publisher network condition changed: \(transport.networkCondition.rawValue)")
        print("Reason: \(transport.networkConditionReason.rawValue)")
    }
}

Ce rappel est déclenché lorsqu'un changement significatif de l'état du réseau est détecté pour l'éditeur. Elle inclut les statistiques de la liaison média en cours avec les métriques de transport. Voir État du réseau et source de dégradation pour plus de détails sur l'interprétation des notes et des raisons de l'état du réseau.

Activation des statistiques pour les abonnés

Joindre une classe qui adopte OTSubscriberKitNetworkStatsDelegate:

class MyViewController: UIViewController, OTSubscriberKitDelegate, OTSubscriberKitNetworkStatsDelegate {
    var subscriber: OTSubscriber?

    func setupSubscriber(stream: OTStream, session: OTSession) {
        subscriber = OTSubscriber(stream: stream, delegate: self)
        subscriber?.networkStatsDelegate = self
        try? session.subscribe(subscriber!)
    }
}

Mettre en œuvre les rappels :

func subscriber(_ subscriber: OTSubscriberKit, videoNetworkStatsUpdated stats: OTSubscriberKitVideoNetworkStats) {
    print("Video bytes received: \(stats.videoBytesReceived)")
}

func subscriber(_ subscriber: OTSubscriberKit, audioNetworkStatsUpdated stats: OTSubscriberKitAudioNetworkStats) {
    print("Audio packets received: \(stats.audioPacketsReceived)")
}

func subscriber(_ subscriber: OTSubscriberKit, mediaLinkStatsUpdated mediaLinkStats: OTSubscriberKitMediaLinkStats) {
    print("Local downlink bandwidth: \(mediaLinkStats.transport.connectionEstimatedBandwidth) bps")
    print("Remote publisher uplink bandwidth: \(mediaLinkStats.remotePublisherTransport.connectionEstimatedBandwidth) bps")
    print("Degradation source: \(mediaLinkStats.networkDegradationSource.rawValue)")
}

Réception d'événements liés à la qualité vidéo chez les abonnés

En outre, gérer les événements de modification de la qualité vidéo de l'abonné :

func subscriber(_ subscriber: OTSubscriberKit, videoQualityChanged stats: OTSubscriberKitVideoNetworkStats, reason: OTSubscriberVideoEventReason) {
    print("Subscriber video quality event: \(reason.rawValue)")
}

Réception d'événements liés à l'état du réseau sur l'abonné

Pour recevoir les événements de changement d'état du réseau pour l'abonné, mettez en œuvre la fonction subscriber(_:networkConditionChanged:mediaLinkStats:reason:) rappel :

func subscriber(_ subscriber: OTSubscriberKit, networkConditionChanged mediaLinkStats: OTSubscriberKitMediaLinkStats, reason: OTNetworkReason) {
    if let transport = mediaLinkStats.transport {
        print("Local network condition: \(transport.networkCondition.rawValue)")
    }
    if let remoteTransport = mediaLinkStats.remotePublisherTransport {
        print("Remote publisher network condition: \(remoteTransport.networkCondition.rawValue)")
    }
    print("Degradation source: \(mediaLinkStats.networkDegradationSource.rawValue)")
}

Ce rappel est déclenché lorsqu'un changement significatif de l'état du réseau est détecté pour l'abonné ou l'éditeur distant. Il inclut les statistiques actuelles de la liaison média avec les métriques de transport locales et distantes et la source de dégradation. Voir État du réseau et source de dégradation pour plus de détails sur l'interprétation des notes et des raisons de l'état du réseau.

Structures de données statistiques

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

Pour une explication indépendante de la plate-forme des statistiques disponibles et de ce qu'elles représentent, voir aperçu de l'observabilité du client.

OTTransportStats

Représente les mesures partagées au niveau du transport.

  • connectionEstimatedBandwidth - Estimation de la largeur de bande de connexion disponible (bps).
  • networkCondition - Score de l'état actuel du réseau (OTNetworkConditionUnknown, OTNetworkConditionCritical, OTNetworkConditionWarning, OTNetworkConditionFair, OTNetworkConditionGoodou OTNetworkConditionExcellent).
  • networkConditionReason - Raison principale de l'impact sur l'état du réseau (OTNetworkReasonNone, OTNetworkReasonUnknown, OTNetworkReasonBandwidth, OTNetworkReasonPacketLossou OTNetworkReasonNetworkConditionChange).

OTPublisherKitVideoNetworkStats

Fournit des statistiques sur la piste vidéo d'un éditeur. Elles comprennent :

  • connectionId - Dans une session relayée, l'identifiant de connexion du client souscrivant au flux. Indéfini dans une session routée.
  • subscriberId - Dans une session relayée, l'identifiant du client abonné au flux. Indéfini dans une session routée.
  • videoPacketsLost - Estimation des paquets vidéo perdus.
  • videoPacketsSent - Paquets vidéo envoyés.
  • videoBytesSent - Octets vidéo envoyés.
  • timestamp - Date Unix en millisecondes à laquelle les statistiques ont été recueillies.
  • startTime - Le timestamp, en millisecondes depuis l'époque Unix, à partir duquel les totaux cumulés ont commencé à s'accumuler.
  • videoLayers - Tableau de statistiques sur la couche vidéo (voir OTPublisherKitVideoLayerStats).

OTPublisherKitAudioNetworkStats

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

  • connectionId - Dans une session relayée, l'identifiant de connexion du client souscrivant au flux. Indéfini dans une session routée.
  • subscriberId - Dans une session relayée, l'identifiant du client abonné au flux. Indéfini dans une session routée.
  • audioPacketsLost - Estimation des paquets perdus.
  • audioPacketsSent - Paquets audio envoyés.
  • audioBytesSent - Octets audio envoyés.
  • timestamp - Horodatage Unix en millisecondes.

OTPublisherKitVideoLayerStats

Représente une couche simulcast ou une couche SVC.

  • width - Largeur de la trame encodée.
  • height - Hauteur du cadre codé.
  • encodedFrameRate - Images codées par seconde.
  • bitrate - Débit binaire de la couche (bps).
  • totalBitrate - Débit de la couche incluant le surdébit RTP (bps).
  • scalabilityMode - Descripteur SVC/scalability (par exemple, "L3T3").
  • qualityLimitationReason - Raison de la limitation de la qualité (bande passante, CPU, codec, résolution ou changement de couche).
  • codec - Le codec utilisé par cette couche vidéo.

OTSenderStats

Mesures d'estimation du côté de l'expéditeur (reflétées à la fois sur l'audio et la vidéo).

  • connectionMaxAllocatedBitrate - Débit maximum estimé pour la connexion de l'expéditeur.
  • connectionEstimatedBandwidth - Estimation de la largeur de bande actuelle (bps).

OTSubscriberKitVideoNetworkStats

Fournit des statistiques sur la piste vidéo d'un abonné. Elles comprennent :

  • videoPacketsLost - Estimation des paquets vidéo perdus.
  • videoPacketsReceived - Paquets vidéo reçus.
  • videoBytesReceived - Octets vidéo reçus.
  • timestamp - Date Unix en millisecondes à laquelle les statistiques ont été recueillies.
  • senderStats - Mesures du côté de l'expéditeur (facultatif).
  • width - Largeur de la trame décodée en pixels.
  • height - Hauteur de l'image décodée en pixels.
  • decodedFrameRate - Images décodées par seconde.
  • bitrate - Débit binaire vidéo (bps).
  • totalBitrate - Débit binaire incluant l'overhead RTP (bps).
  • pauseCount - Nombre de pauses (>5s depuis la dernière image). Inclut les désactivations intentionnelles et les cas de retour audio.
  • totalPausesDuration - Durée totale de la pause (ms).
  • freezeCount - Compte de gel (événement de gel défini par WebRTC).
  • totalFreezesDuration - Durée totale de l'arrêt sur image (ms).
  • codec - Codec du décodeur actuel.

OTSubscriberKitAudioNetworkStats

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

  • audioPacketsLost - Estimation des paquets perdus.
  • audioPacketsReceived - Paquets reçus.
  • audioBytesReceived - Octets reçus.
  • timestamp - Horodatage Unix en millisecondes.
  • senderStats - Mesures du côté de l'expéditeur (facultatif).

OTPublisherKitMediaLinkStats

Fournit des statistiques au niveau du transport pour les connexions d'un éditeur.

  • transport - Statistiques de transport pour la connexion ascendante de cet éditeur (voir OTTransportStats)

OTSubscriberKitMediaLinkStats

Fournit des statistiques au niveau du transport pour les connexions d'un abonné, y compris une visibilité sur les performances du réseau de l'éditeur distant. Cela permet aux Applications de diagnostiquer si les problèmes de connexion proviennent de la liaison descendante de l'abonné ou de la liaison montante de l'éditeur.

  • transport - Statistiques de transport pour la connexion descendante de cet abonné (voir OTTransportStats)
  • remotePublisherTransport - Statistiques de transport pour la connexion ascendante de l'éditeur distant (obtenues via statistiques côté expéditeur, voir OTTransportStats). Ces statistiques peuvent être limitées si les statistiques côté expéditeur ne sont pas activées.
  • networkDegradationSource - Indique la source de la dégradation du réseau (OTNetworkDegradationSourceLocal, OTNetworkDegradationSourceRemote, OTNetworkDegradationSourceBothOrUnclearou OTNetworkDegradationSourceUnknown)

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é émetteur, il faut les activer pour l'éditeur du flux en définissant l'attribut senderStatsTrack à la propriété true pour les OTPublisherKitSettings utilisé pour créer l'éditeur.

let settings = OTPublisherKitSettings()
settings.senderStatsTrack = true

let publisher = OTPublisher(delegate: self, settings: settings)

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

Réception des statistiques côté expéditeur

Si l'éditeur a activé les statistiques côté expéditeur, les abonnés les reçoivent automatiquement par l'intermédiaire de l'option OTSubscriberKitNetworkStatsDelegate rappels décrite ci-dessus. Les senderStats sur les deux OTSubscriberKitVideoNetworkStats et OTSubscriberKitAudioNetworkStats fournit deux mesures :

  • connectionMaxAllocatedBitrate - Le débit maximum qui peut être estimé pour la connexion
  • connectionEstimatedBandwidth - La largeur de bande actuelle estimée pour la connexion

Ces mesures sont calculées par groupe audio-vidéo, de sorte que les mêmes valeurs apparaissent dans les statistiques vidéo et audio.

Mettre en œuvre la méthode de délégation pour les statistiques vidéo :

func subscriber(_ subscriber: OTSubscriberKit, videoNetworkStatsUpdated stats: OTSubscriberKitVideoNetworkStats) {
    if let sender = stats.senderStats {
        print("Connection max allocated bitrate: \(sender.connectionMaxAllocatedBitrate)")
        print("Connection current estimated bandwidth: \(sender.connectionEstimatedBandwidth)")
    }
}

État du réseau et source de dégradation

Le SDK fournit des mesures de l'état du réseau en temps réel pour les éditeurs et les abonnés, y compris une note d'état, la raison de cette note et une source de dégradation pour les abonnés. Pour une explication complète du modèle d'état du réseau, des scores, des raisons et de la manière de l'activer, voir le document aperçu de l'observabilité du client.

Les données sur l'état du réseau sont disponibles par le biais de deux canaux :

  • Statistiques périodiques : Les événements liés aux statistiques des médias comprennent des mesures de transport avec networkCondition et networkConditionReason. Pour les abonnés, les statistiques sur les liens avec les médias comprennent également remotePublisherTransport et networkDegradationSource.
  • Événements liés à la modification de l'état du réseau : Des rappels dédiés à l'éditeur et à l'abonné sont déclenchés lorsqu'un changement significatif de l'état du réseau est détecté.

L'exemple suivant montre comment utiliser les données sur l'état du réseau de l'abonné pour identifier la source de la dégradation :

func subscriber(_ subscriber: OTSubscriberKit, networkConditionChanged mediaLinkStats: OTSubscriberKitMediaLinkStats, reason: OTNetworkReason) {

    let localCondition = mediaLinkStats.transport?.networkCondition ?? .unknown
    let remoteCondition = mediaLinkStats.remotePublisherTransport?.networkCondition ?? .unknown
    let source = mediaLinkStats.networkDegradationSource

    switch source {
    case .local:
        print("Local network is degraded (condition: \(localCondition.rawValue))")
    case .remote:
        print("Remote publisher network is degraded (condition: \(remoteCondition.rawValue))")
    case .bothOrUnclear:
        print("Degradation source unclear — local: \(localCondition.rawValue), remote: \(remoteCondition.rawValue)")
    default:
        break
    }
}

Rapport statistique RTC

Pour obtenir des statistiques de bas niveau sur les flux, utilisez la fonction getRtcStatsReport() méthode sur OTPublisherKit. Cette fonction fournit des rapports de statistiques RTC pour le flux média de manière asynchrone.

Avant d'appeler cette méthode, définissez le paramètre rtcStatsReportDelegate sur votre éditeur et implémenter la méthode delegate publisher(_:rtcStatsReport:) de OTPublisherKitRtcStatsReportDelegate. Lorsque les statistiques sont disponibles, cette méthode est appelée avec un tableau de OTPublisherRtcStats objets. Chaque objet contient un jsonArrayOfReports qui est un tableau JSON de rapports de statistiques RTC similaires au format utilisé par WebRTC dans les navigateurs web.

Exemple

class MyViewController: UIViewController, OTPublisherKitRtcStatsReportDelegate {
    var publisher: OTPublisher?

    func setupPublisher() {
        // Create and configure the publisher
        publisher = OTPublisher(delegate: self, settings: OTPublisherKitSettings())
        publisher?.rtcStatsReportDelegate = self
    }

    func fetchRtcStats() {
        publisher?.getRtcStatsReport()
    }

    // Delegate method called when stats are ready
    func publisher(_ publisher: OTPublisherKit, rtcStatsReport stats: [OTPublisherRtcStats]) {
        for stat in stats {
            print("RTC Stats JSON: \(stat.jsonArrayOfReports)")
        }
    }
}

Voir ces documents de Mozilla. Voir aussi cette documentation du W3C.

Exemple d'application

Voir le Exemple de statistiques côté expéditeur dans le SDK vidéo Vonage pour iOS (Swift).