Kotlin

Gerenciar estatísticas de vídeo

Nesta etapa, você lidará com os callbacks de vídeo e de links de mídia dos assinantes para diagnosticar falhas de reprodução e avaliar o desempenho da rede em seu aplicativo.

O que você vai monitorar Como pode ser usado
videoPacketsLost / videoBytesReceived Confirme se o caminho de recepção está apresentando problemas (sintoma: falhas, travamentos)
transport (largura de banda do downlink local) Sugerir “Sua conexão parece fraca” quando sua largura de banda de download parece limitada
remotePublisherTransport (transmissão remota) Sugerir “A rede do outro participante pode estar instável” quando o caminho de envio parece estar restrito
networkDegradationSource Escolha entre mensagens locais e remotas — ou registre os dois valores de largura de banda para fins de suporte

1. Gerenciar as estatísticas de vídeo dos inscritos

Implementar SubscriberKit.VideoStatsListener para receber métricas periódicas de vídeo:

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

Os callbacks podem ser recebidos em uma thread de segundo plano. Envie as atualizações da interface do usuário para a thread principal (conforme descrito acima) caso você utilize o Compose ou o Views a partir desses ouvintes.

Implementar SubscriberKit.MediaLinkStatsListener.onMediaLinkStats & SubscriberKit.MediaLinkStatsListener.onNetworkConditionChanged para a largura de banda de transporte e a fonte de degradação. As pontuações das condições da rede também estão disponíveis em transport e remotePublisherTransport em cada amostra periódica — ver Condição da rede.

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

As estatísticas de vídeo e as estatísticas de links de mídia são fornecidas em callbacks separados. A amostra mantém um MediaLinkSnapshot e o integra durante a compilação ou atualização 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",
            )
        }
    }
}

Estender MediaLinkSnapshot e ObservabilityStats com os novos campos (ou mapeie os números inteiros das condições para os rótulos na sobreposição na próxima etapa).

3. Reagir a eventos relacionados à deterioração das condições da rede

Quando o vídeo fica travando, onNetworkConditionChanged disparos contra um significativo alteração. Use-o com networkDegradationSource para escolher o texto voltado para o usuário:

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 em onNetworkConditionChanged descreve o motivo pelo qual o evento foi acionado (por exemplo, uma variação na largura de banda ou perda de pacotes). Combine isso com networkCondition e networkConditionReason em transport para análises.

Definir ObservabilityStats, MediaLinkSnapshot, e fromVideoStats() no seu projeto. O exemplo ObservabilityStats.kt é um ponto de partida.