Kotlin

Videostatistiken verwalten

In diesem Schritt bearbeiten Sie Callbacks für Abonnentenvideos und Medienlinks, um Ruckeln zu diagnostizieren und den Netzwerkzustand in Ihrer App anzuzeigen.

Was Sie überwachen werden Anwendungsmöglichkeiten
videoPacketsLost / videoBytesReceived Überprüfen Sie, ob der Empfangspfad Probleme bereitet (Symptom: Ruckeln, Einfrieren)
transport (lokale Downlink-Bandbreite) Vorschlagen „Deine Verbindung scheint schwach zu sein“ wenn Ihre Downlink-Kapazität begrenzt zu sein scheint
remotePublisherTransport (Fernübertragung) Vorschlagen „Das Netzwerk des anderen Teilnehmers ist möglicherweise instabil.“ wenn ihr Sendepfad eingeschränkt erscheint
networkDegradationSource Wählen Sie zwischen lokaler und Remote-Übermittlung – oder protokollieren Sie beide Bandbreitenwerte für den Support

1. Videostatistiken der Abonnenten verwalten

Umsetzung SubscriberKit.VideoStatsListener um regelmäßig Kennzahlen zum Videoempfang zu erhalten:

private val videoStatsListener = SubscriberKit.VideoStatsListener { _, stats ->
    Log.d(TAG, "videoBytesReceived=${stats.videoBytesReceived}")
    Log.d(TAG, "videoPacketsLost=${stats.videoPacketsLost}")
    Log.d(TAG, "videoPacketsReceived=${stats.videoPacketsReceived}")
    Log.d(TAG, "timeStamp=${stats.timeStamp}")

    mainHandler.post {
        latestObservabilityStats = ObservabilityStats.fromVideoStats(
            stats,
            latestMediaLinkSnapshot,
        )
    }
}

Callbacks können in einem Hintergrund-Thread eintreffen. Übertragen Sie UI-Aktualisierungen in den Haupt-Thread (wie oben beschrieben), wenn Sie Compose oder Views über diese Listener steuern.

Umsetzung SubscriberKit.MediaLinkStatsListener.onMediaLinkStats & SubscriberKit.MediaLinkStatsListener.onNetworkConditionChanged für die Transportbandbreite und die Ursache der Beeinträchtigung. Die Bewertungen des Netzwerkzustands sind ebenfalls zu finden unter transport und remotePublisherTransport in jeder periodischen Stichprobe – siehe Zustand des Netzes.

private val mediaLinkStatsListener = object : SubscriberKit.MediaLinkStatsListener {
    //
    // Triggers on regular intervals while subscribed
    // Good place for: Overlay numbers, charts, steady telemetry
    //
    override fun onMediaLinkStats(
        subscriber: SubscriberKit,
        mediaLinkStats: SubscriberKit.SubscriberMediaLinkStats,
    ) {
        applyMediaLinkStats(mediaLinkStats)
    }

    //
    // Triggers when the SDK detects a **significant** network condition change
    // Good place for: Toasts, banners, support logs, adaptive UI
    //
    override fun onNetworkConditionChanged(
        subscriber: SubscriberKit,
        mediaLinkStats: SubscriberKit.SubscriberMediaLinkStats,
        reason: String,
    ) {
        Log.d(TAG, "onNetworkConditionChanged reason=$reason")
        applyMediaLinkStats(mediaLinkStats, networkConditionChangeReason = reason)
        handleNetworkDegradation(mediaLinkStats)
    }
}

Videostatistiken und Medienlink-Statistiken werden über separate Callbacks übermittelt. Das Beispiel verwaltet ein MediaLinkSnapshot und integriert es beim Erstellen oder Aktualisieren ObservabilityStats:

private fun applyMediaLinkStats(
    mediaLinkStats: SubscriberKit.SubscriberMediaLinkStats,
    networkConditionChangeReason: String? = null,
) {
    val localBandwidth = mediaLinkStats.transport?.connectionEstimatedBandwidth
    val remoteBandwidth =
        mediaLinkStats.remotePublisherTransport?.connectionEstimatedBandwidth
    val localCondition = mediaLinkStats.transport?.networkCondition
    val remoteCondition = mediaLinkStats.remotePublisherTransport?.networkCondition
    val conditionReason = mediaLinkStats.transport?.networkConditionReason

    mainHandler.post {
        latestMediaLinkSnapshot = MediaLinkSnapshot(
            localEstimatedBandwidth = localBandwidth,
            remoteEstimatedBandwidth = remoteBandwidth,
            networkDegradationSource = mediaLinkStats.networkDegradationSource,
            localNetworkCondition = localCondition,
            remoteNetworkCondition = remoteCondition,
            lastNetworkConditionChangeReason = networkConditionChangeReason,
        )
        latestObservabilityStats?.let { current ->
            latestObservabilityStats = current.copy(
                localEstimatedBandwidth = localBandwidth,
                remoteEstimatedBandwidth = remoteBandwidth,
                networkDegradationSource = mediaLinkStats.networkDegradationSource,
                localNetworkCondition = localCondition,
                remoteNetworkCondition = remoteCondition,
                lastNetworkConditionChangeReason = networkConditionChangeReason,
            )
        }
        networkConditionChangeReason?.let { changeReason ->
            Log.d(
                TAG,
                "network condition event: $changeReason local=$localCondition remote=$remoteCondition",
            )
        }
    }
}

Erweitern MediaLinkSnapshot und ObservabilityStats mit den neuen Feldern (oder ordnen Sie im nächsten Schritt die Ganzzahlwerte der Bedingungen den Beschriftungen in der Überlagerung zu).

3. Auf Ereignisse im Zusammenhang mit einer Verschlechterung der Netzwerkbedingungen reagieren

Wenn das Video ruckelt, onNetworkConditionChanged Feuer auf einem erheblich Änderung. Verwenden Sie es mit networkDegradationSource So wählen Sie Texte für die Benutzeroberfläche aus:

private fun handleNetworkDegradation(
    mediaLinkStats: SubscriberKit.SubscriberMediaLinkStats,
) {
    val localCondition = mediaLinkStats.transport?.networkCondition
        ?: TransportStats.NETWORK_CONDITION_UNKNOWN
    val remoteCondition = mediaLinkStats.remotePublisherTransport?.networkCondition
        ?: TransportStats.NETWORK_CONDITION_UNKNOWN

    when (mediaLinkStats.networkDegradationSource) {
        NetworkDegradationSource.LOCAL -> {
            Log.w(TAG, "Local network degraded (condition=$localCondition)")
            // e.g. show: "Your connection looks weak"
        }
        NetworkDegradationSource.REMOTE -> {
            Log.w(TAG, "Remote publisher network degraded (condition=$remoteCondition)")
            // e.g. show: "The other participant's network may be unstable"
        }
        NetworkDegradationSource.BOTH_OR_UNCLEAR -> {
            Log.w(TAG, "Degradation unclear — local=$localCondition remote=$remoteCondition")
        }
        else -> { /* NetworkDegradationSource.NONE — no action */ }
    }
}

reason in onNetworkConditionChanged beschreibt, warum das Ereignis ausgelöst wurde (z. B. eine Änderung der Bandbreite oder Paketverluste). Kombinieren Sie dies mit networkCondition und networkConditionReason auf transport für Analysen.

Definieren Sie ObservabilityStats, MediaLinkSnapshotund fromVideoStats() in Ihrem Projekt. Das Beispiel ObservabilityStats.kt ist ein Ausgangspunkt.