Client-Observability – iOS (Swift)

Das OpenTok iOS SDK bietet Funktionen für den Zugriff auf Echtzeit-Netzwerk- und Medienstatistiken in einer Videositzung. Diese Funktionen liefern detaillierte Kennzahlen zur Stream-Qualität – wie beispielsweise Paketverlust, empfangene Daten und Bandbreite – und können für jeden veröffentlichten oder abonnierten Stream genutzt werden.

∏ Das OpenTok Video SDK stellt detaillierte Metriken zur Stream-Qualität über eine hochrangige Statistik-API bereit – empfohlen für die meisten Anwendungsfälle –, die Audio-, Video-, Netzwerk- und senderseitige Statistiken in einer einheitlichen, sitzungsbezogenen Form liefert, die auch bei Wechseln der Peer-Verbindungen stabil bleibt. Für die erweiterte Fehlerbehebung bietet das SDK zudem Zugriff auf den Rohdatenbericht der WebRTC-Statistiken, der unverarbeitete Daten zu Peer-Verbindungen enthält.

Das SDK stellt auch Netzwerkzustandsmetriken zur Verfügung, die eine umfassende Bewertung des Verbindungszustands sowohl für Herausgeber als auch für Abonnenten ermöglichen. Diese Metriken umfassen eine Bewertung des Netzwerkzustands, den Grund für diese Bewertung und - für Abonnenten - eine Verschlechterungsquelle, die angibt, welche Seite der Verbindung für die beobachteten Probleme verantwortlich ist. Siehe Netzzustand und Ursache der Verschlechterung für Einzelheiten.

Dieser Leitfaden umfasst die folgenden Abschnitte:

Das OpenTok-iOS-SDK übermittelt regelmäßig Audio-, Video- und Medienlink-Statistiken sowohl für Publisher als auch für Subscriber. Dazu gehören Paketanzahlen, Bitraten, Bildfrequenzdaten, Metriken zu Pausen und Standbildern, Codec-Informationen sowie Netzwerkmetriken auf Transportebene wie Bandbreitenschätzungen und Bewertungen des Netzwerkzustands.

Die Statistiken werden durch geliefert:

  • OTPublisherKitNetworkStatsDelegate - Statistiken auf der Verlagsseite (Audio, Video)

  • OTSubscriberKitNetworkStatsDelegate - Statistiken auf der Abonnentenseite (Audio, Video)

Um sie zu empfangen, aktivieren Sie den entsprechenden Delegaten auf dem Verleger oder Abonnenten.

Freigabe von Statistiken für Verleger

Fügen Sie eine Klasse hinzu, die das OTPublisherKitNetworkStatsDelegate übernimmt:

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

Implementieren Sie die Rückrufe:

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

Für einen Verleger in einer gerouteten Sitzung (eine, die die Vonage Video-Media-Router, Das „stats“-Array enthält ein Objekt, das die Statistiken für den einzelnen Audio- oder Video-Medienstream definiert, der an den Vonage Video Media Router gesendet wird. In einer weitergeleiteten Sitzung enthält das „stats“-Array ein Objekt für jeden Teilnehmer des veröffentlichten Streams.

Empfang von Ereignissen in Videoqualität bei den Herausgebern

Wenn Sie auch an Videoqualitätsereignissen interessiert sind, implementieren Sie diesen Callback:

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

Empfang von Netzwerkzustandsereignissen auf den Publishern

Um Ereignisse zur Änderung von Netzwerkbedingungen für den Herausgeber zu empfangen, implementieren Sie die publisher(_:networkConditionChanged:mediaLinkStats:reason:) Rückruf:

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

Dieser Rückruf wird ausgelöst, wenn eine signifikante Änderung der Netzbedingungen für den Herausgeber festgestellt wird. Er enthält die aktuelle Medienverbindungsstatistik mit Transportmetriken. Siehe Netzzustand und Ursache der Verschlechterung für Einzelheiten zur Interpretation der Netzzustandsnoten und Gründe.

Aktivieren von Statistiken für Abonnenten

Anhängen einer Klasse, die die 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!)
    }
}

Implementieren Sie die Rückrufe:

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

Empfang von Videoqualitätsereignissen bei den Abonnenten

Zusätzlich können Sie Ereignisse mit geänderter Videoqualität für Abonnenten behandeln:

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

Empfang von Ereignissen zum Netzwerkstatus auf dem Teilnehmergerät

Um Ereignisse zur Änderung von Netzbedingungen für den Teilnehmer zu empfangen, implementieren Sie die subscriber(_:networkConditionChanged:mediaLinkStats:reason:) Rückruf:

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

Dieser Rückruf wird ausgelöst, wenn eine signifikante Änderung der Netzbedingungen für den Teilnehmer oder den entfernten Herausgeber festgestellt wird. Er enthält die aktuelle Medienverbindungsstatistik mit lokalen und entfernten Transportmetriken und der Degradationsquelle. Siehe Netzzustand und Ursache der Verschlechterung für Einzelheiten zur Interpretation der Netzzustandsnoten und Gründe.

Statistik-Datenstrukturen

In diesem Abschnitt werden die Strukturen und Eigenschaften beschrieben, die von der iOS-Audio- und Videostatistik-API bereitgestellt werden. Während alle Video-SDK-Plattformen die gleichen Statistiken bereitstellen, kann es geringfügige Unterschiede in der Strukturierung oder Benennung einzelner Felder geben. Diese Unterschiede spiegeln eher plattformspezifische SDK-Designkonventionen als Unterschiede in den zugrunde liegenden Metriken wider.

Eine plattformunabhängige Erläuterung der verfügbaren Statistiken und ihrer Bedeutung finden Sie unter Übersicht über die Beobachtbarkeit der Kunden.

OTTransportStats

Stellt gemeinsame Metriken auf Transportebene dar.

  • connectionEstimatedBandwidth - Geschätzte verfügbare Verbindungsbandbreite (bps).
  • networkCondition - Aktuelle Netzzustandsbewertung (OTNetworkConditionUnknown, OTNetworkConditionCritical, OTNetworkConditionWarning, OTNetworkConditionFair, OTNetworkConditionGood, oder OTNetworkConditionExcellent).
  • networkConditionReason - Hauptgrund für die Beeinträchtigung des Netzzustandes (OTNetworkReasonNone, OTNetworkReasonUnknown, OTNetworkReasonBandwidth, OTNetworkReasonPacketLoss, oder OTNetworkReasonNetworkConditionChange).

OTPublisherKitVideoNetworkStats

Liefert Statistiken über die Videospur eines Herausgebers. Sie umfasst:

  • connectionId - In einer weitergeleiteten Sitzung die Verbindungs-ID des Clients, der den Stream abonniert. Undefiniert in einer gerouteten Sitzung.
  • subscriberId - In einer weitergeleiteten Sitzung die abonnierte ID des Clients, der den Stream abonniert. Undefiniert in einer gerouteten Sitzung.
  • videoPacketsLost - Geschätzte verlorene Videopakete.
  • videoPacketsSent - Gesendete Videopakete.
  • videoBytesSent - Video-Bytes gesendet.
  • timestamp - Unix-Zeitstempel in Millisekunden, als die Statistiken erfasst wurden.
  • startTime - Der Zeitstempel in Millisekunden seit der Unix-Epoche, ab dem die kumulativen Summen zu kumulieren begannen.
  • videoLayers - Das Array der Video-Layer-Statistiken (siehe OTPublisherKitVideoLayerStats).

OTPublisherKitAudioNetworkStats

Liefert Statistiken über den Audiotrack eines Verlags. Sie umfasst:

  • connectionId - In einer weitergeleiteten Sitzung die Verbindungs-ID des Clients, der den Stream abonniert. Undefiniert in einer gerouteten Sitzung.
  • subscriberId - In einer weitergeleiteten Sitzung die abonnierte ID des Clients, der den Stream abonniert. Undefiniert in einer gerouteten Sitzung.
  • audioPacketsLost - Geschätzte verlorene Pakete.
  • audioPacketsSent - Audio-Pakete gesendet.
  • audioBytesSent - Gesendete Audio-Bytes.
  • timestamp - Unix-Zeitstempel in Millisekunden.

OTPublisherKitVideoLayerStats

Steht für eine Simulcast- oder SVC-Schicht.

  • width - Kodierte Bildbreite.
  • height - Kodierte Rahmenhöhe.
  • encodedFrameRate - Kodierte Bilder pro Sekunde.
  • bitrate - Bitrate der Schicht (bps).
  • totalBitrate - Bitrate der Schicht einschließlich RTP-Overhead (bps).
  • scalabilityMode - SVC/Skalierbarkeitsdeskriptor (z. B. "L3T3").
  • qualityLimitationReason - Grund für die Qualitätseinschränkung (Bandbreite, CPU, Codec, Auflösung oder Ebenenwechsel).
  • codec - Der von dieser Videoebene verwendete Codec.

OTSenderStats

Abschätzungsmetriken auf der Senderseite (gespiegelt auf Audio und Video).

  • connectionMaxAllocatedBitrate - Geschätzte maximale Bitrate für die Senderverbindung.
  • connectionEstimatedBandwidth - Aktuelle Bandbreitenabschätzung (bps).

OTSubscriberKitVideoNetworkStats

Liefert Statistiken über die Videospur eines Abonnenten. Sie umfasst:

  • videoPacketsLost - Geschätzte verlorene Videopakete.
  • videoPacketsReceived - Empfangene Videopakete.
  • videoBytesReceived - Empfangene Videobytes.
  • timestamp - Unix-Zeitstempel in Millisekunden, als die Statistiken erfasst wurden.
  • senderStats - Metriken auf der Absenderseite (optional).
  • width - Dekodierte Bildbreite in Pixel.
  • height - Dekodierte Bildhöhe in Pixel.
  • decodedFrameRate - Dekodierte Bilder pro Sekunde.
  • bitrate - Video-Bitrate (bps).
  • totalBitrate - Bitrate einschließlich RTP-Overhead (bps).
  • pauseCount - Numbers of pauses (>5s seit dem letzten Frame). Einschließlich absichtlicher Deaktivierungen und Audio-Fallback-Fälle.
  • totalPausesDuration - Gesamte Pausendauer (ms).
  • freezeCount - Freeze Count (von WebRTC definiertes Freeze-Ereignis).
  • totalFreezesDuration - Gesamtdauer des Einfrierens (ms).
  • codec - Aktueller Decoder-Codec.

OTSubscriberKitAudioNetworkStats

Liefert Statistiken über den Audiotrack eines Abonnenten. Sie umfasst:

  • audioPacketsLost - Geschätzte verlorene Pakete.
  • audioPacketsReceived - Empfangene Pakete.
  • audioBytesReceived - Empfangene Bytes.
  • timestamp - Unix-Zeitstempel in Millisekunden.
  • senderStats - Metriken auf der Absenderseite (optional).

OTPublisherKitMediaLinkStats

Liefert Statistiken auf Transportebene für die Verbindungen eines Verlags.

  • transport - Transportstatistiken für die Uplink-Verbindung dieses Verlags (siehe OTTransportStats)

OTSubscriberKitMediaLinkStats

Liefert Statistiken auf Transportebene für die Verbindungen eines Teilnehmers, einschließlich Einblick in die Netzwerkleistung des entfernten Herausgebers. So können Applications diagnostizieren, ob Verbindungsprobleme vom Downlink des Teilnehmers oder vom Uplink des Publishers ausgehen.

  • transport - Transportstatistiken für die Downlink-Verbindung dieses Teilnehmers (siehe OTTransportStats)
  • remotePublisherTransport - Transportstatistiken für die Uplink-Verbindung des entfernten Herausgebers (erhalten über Statistik der Absender-Seitesiehe OTTransportStats). Diese Statistiken können eingeschränkt sein, wenn die absenderseitigen Statistiken nicht aktiviert sind.
  • networkDegradationSource - Zeigt die Quelle der Netzverschlechterung an (OTNetworkDegradationSourceLocal, OTNetworkDegradationSourceRemote, OTNetworkDegradationSourceBothOrUnclear, oder OTNetworkDegradationSourceUnknown)

Statistik auf der Absenderseite

Siehe die Übersicht der Absenderstatistiken.

Aktivieren von Statistiken auf der Absenderseite

Senderstatistiken werden von den Abonnenten empfangen. Um absenderseitige Statistiken zu erhalten, aktivieren Sie sie für den Herausgeber des Streams, indem Sie die Option senderStatsTrack Eigenschaft zu true für die OTPublisherKitSettings Objekt, das zur Erstellung des Verlags verwendet wird.

let settings = OTPublisherKitSettings()
settings.senderStatsTrack = true

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

Wenn senderStatsTrack nicht aktiviert ist, wird kein Absenderstatistikkanal für diesen Verlag veröffentlicht. Der Standardwert ist NO.

Empfang von Statistiken auf der Absenderseite

Wenn der Herausgeber die Absenderstatistik aktiviert hat, erhalten die Abonnenten diese automatisch über die OTSubscriberKitNetworkStatsDelegate Rückrufe oben beschrieben. Die senderStats Eigenschaft auf beiden OTSubscriberKitVideoNetworkStats und OTSubscriberKitAudioNetworkStats liefert zwei Metriken:

  • connectionMaxAllocatedBitrate - Die maximale Bitrate, die für die Verbindung geschätzt werden kann
  • connectionEstimatedBandwidth - Die aktuell geschätzte Bandbreite für die Verbindung

Diese Metriken werden pro Audio-Video-Bündel berechnet, so dass in den Video- und Audiostatistiken dieselben Werte erscheinen.

Implementieren Sie die Delegierungsmethode für Videostatistiken:

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

Netzzustand und Ursache der Verschlechterung

Das SDK liefert sowohl für Publisher als auch für Abonnenten Echtzeit-Netzwerkzustandsmetriken, einschließlich einer Zustandsbewertung, des Grundes für diese Bewertung und einer Verschlechterungsquelle für Abonnenten. Eine vollständige Erläuterung des Netzwerkzustandsmodells, der Bewertungen, der Gründe und der Aktivierung finden Sie in der Übersicht über die Beobachtbarkeit der Kunden.

Netzzustandsdaten sind über zwei Kanäle verfügbar:

  • Regelmäßige Statistiken: Die Medienverbindungsstatistiken enthalten Transportmetriken mit networkCondition und networkConditionReason. Für Abonnenten umfasst die Medienlink-Statistik auch remotePublisherTransport und networkDegradationSource.
  • Ereignisse, bei denen sich der Netzzustand ändert: Dedizierte Rückrufe sowohl beim Herausgeber als auch beim Teilnehmer werden ausgelöst, wenn eine signifikante Änderung der Netzbedingungen festgestellt wird.

Das folgende Beispiel zeigt, wie die Daten über den Zustand des Teilnehmernetzes verwendet werden können, um die Ursache der Verschlechterung zu ermitteln:

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

RTC-Statistikbericht

Um Low-Level-Stream-Statistiken zu erhalten, verwenden Sie die getRtcStatsReport() Methode auf OTPublisherKit. Dadurch werden RTC-Statistikberichte für den Medienstrom asynchron bereitgestellt.

Bevor Sie diese Methode aufrufen, setzen Sie die rtcStatsReportDelegate Eigenschaft Ihres Verlegers und implementieren Sie die Delegate-Methode publisher(_:rtcStatsReport:) von OTPublisherKitRtcStatsReportDelegate. Wenn die Statistiken verfügbar sind, wird diese Methode mit einem Array von OTPublisherRtcStats Objekte. Jedes Objekt enthält eine jsonArrayOfReports Eigenschaft, bei der es sich um ein JSON-Array mit RTC-Statistiken handelt, die dem von WebRTC in Webbrowsern verwendeten Format ähneln.

Beispiel

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

Siehe diese Mozilla-Dokumente. Siehe auch diese W3C-Dokumentation.

Beispiel-Applikation

Siehe die vonage-video-ios-sdk-beispiele-swift – Beispiel für senderseitige Statistiken.