Observabilité du client : Android
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.
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.
API pour les statistiques sur les liens audio, vidéo et médias
Le SDK Android de Vonage Video envoie des statistiques périodiques sur l'audio, la vidéo et les liens multimédias 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 les mesures de réseau au niveau du transport, telles que l'estimation de la bande passante et l'évaluation de l'état du réseau.
Les statistiques sont fournies par des auditeurs distincts :
Éditeur :
PublisherKit.VideoStatsListener- statistiques vidéo et événements relatifs à la qualité vidéoPublisherKit.AudioStatsListener- statistiques audioPublisherKit.MediaLinkStatsListener- statistiques sur la liaison média (niveau transport)
Abonné :
SubscriberKit.VideoStatsListener- statistiques vidéo et événements relatifs à la qualité vidéoSubscriberKit.AudioStatsListener- statistiques audioSubscriberKit.MediaLinkStatsListener- statistiques sur la liaison média (niveau transport)
Activation des statistiques pour les éditeurs
Statistiques vidéo
publisher.setVideoStatsListener(new PublisherKit.VideoStatsListener() {
@Override
public void onVideoStats(PublisherKit publisher, PublisherKit.PublisherVideoStats[] statsArray) {
if (statsArray != null && statsArray.length > 0) {
// For routed sessions, first element is sufficient.
// For relayed sessions, iterate all statsArray elements to get per-subscriber info.
PublisherKit.PublisherVideoStats stats = statsArray[0];
String connectionId = (stats.connectionId != null && !stats.connectionId.isEmpty())
? stats.connectionId
: "<none>";
String subscriberId = (stats.subscriberId != null && !stats.subscriberId.isEmpty())
? stats.subscriberId
: "<none>";
Log.d("VideoStats", "Publisher Video Stats for connectionId: " + connectionId
+ ", subscriberId: " + subscriberId);
Log.d("VideoStats", "Video bytes sent: " + stats.videoBytesSent);
Log.d("VideoStats", "Video packets sent: " + stats.videoPacketsSent);
Log.d("VideoStats", "Video packets lost: " + stats.videoPacketsLost);
Log.d("VideoStats", "Stats timestamp: " + stats.timeStamp + " ms");
if (stats.videoLayers != null) {
for (PublisherKit.VideoLayerStats layer : stats.videoLayers) {
Log.d("VideoStats", "Layer: " + layer.width + "x" + layer.height);
Log.d("VideoStats", " Encoded FPS: " + layer.encodedFrameRate);
Log.d("VideoStats", " Bitrate: " + layer.bitrate + " bps");
Log.d("VideoStats", " Total bitrate (incl. RTP overhead): " + layer.totalBitrate + " bps");
Log.d("VideoStats", " Codec: " + (layer.codec != null ? layer.codec : "unknown"));
Log.d("VideoStats", " Scalability mode: " + (layer.scalabilityMode != null ? layer.scalabilityMode : "none"));
Log.d("VideoStats", " Quality limitation: " + layer.qualityLimitationReason);
}
}
}
}
@Override
public void onVideoQualityChanged(PublisherKit publisher, PublisherKit.PublisherVideoStats stats, String reason) {
Log.d("Stats", "Publisher video quality event: " + reason);
}
});
Statistiques audio
publisher.setAudioStatsListener(new PublisherKit.AudioStatsListener() {
@Override
public void onAudioStats(PublisherKit publisher, PublisherKit.PublisherAudioStats[] statsArray) {
if (statsArray != null && statsArray.length > 0) {
// For routed sessions, first element is sufficient.
// For relayed sessions, iterate all statsArray elements to get per-subscriber info.
PublisherKit.PublisherAudioStats stats = statsArray[0];
String connectionId = (stats.connectionId != null && !stats.connectionId.isEmpty())
? stats.connectionId
: "<none>";
String subscriberId = (stats.subscriberId != null && !stats.subscriberId.isEmpty())
? stats.subscriberId
: "<none>";
Log.d("AudioStats", "Publisher Audio Stats for connectionId: " + connectionId
+ ", subscriberId: " + subscriberId);
Log.d("AudioStats", "Audio bytes sent: " + stats.audioBytesSent);
Log.d("AudioStats", "Audio packets sent: " + stats.audioPacketsSent);
Log.d("AudioStats", "Audio packets lost: " + stats.audioPacketsLost);
Log.d("AudioStats", "Stats timestamp: " + stats.timeStamp + " ms");
}
}
});
Statistiques sur les liens avec les médias
publisher.setMediaLinkStatsListener(new PublisherKit.MediaLinkStatsListener() {
@Override
public void onMediaLinkStats(PublisherKit publisher, PublisherKit.PublisherMediaLinkStats[] mediaLinkStats) {
if (mediaLinkStats != null && mediaLinkStats.length > 0) {
PublisherKit.PublisherMediaLinkStats stats = mediaLinkStats[0];
if (stats.transport != null) {
Log.d("MediaLinkStats", "Uplink bandwidth: " + stats.transport.getConnectionEstimatedBandwidth() + " bps");
Log.d("MediaLinkStats", "Network condition: " + stats.transport.networkCondition);
Log.d("MediaLinkStats", "Condition reason: " + stats.transport.networkConditionReason);
}
}
}
@Override
public void onNetworkConditionChanged(PublisherKit publisher, PublisherKit.PublisherMediaLinkStats mediaLinkStats, String reason) {
if (mediaLinkStats.transport != null) {
Log.d("Stats", "Publisher network condition: " + mediaLinkStats.transport.networkCondition);
Log.d("Stats", "Reason: " + mediaLinkStats.transport.networkConditionReason);
}
}
});
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.
Pour un éditeur dans une session acheminée (qui utilise l'option Routeur vidéo multimédia de Vonage), le tableau stats comprend un objet, définissant les statistiques pour le flux audio ou vidéo unique envoyé au routeur vidéo de Vonage. Dans une session relayée, le tableau de statistiques comprend un objet pour chaque abonné au flux publié. le flux publié.
Activation des statistiques pour les abonnés
Statistiques vidéo
subscriber.setVideoStatsListener(new SubscriberKit.VideoStatsListener() {
@Override
public void onVideoStats(SubscriberKit subscriber, SubscriberKit.SubscriberVideoStats stats) {
Log.d("Stats", "Video bytes received: " + stats.videoBytesReceived);
}
@Override
public void onVideoQualityChanged(SubscriberKit subscriber, SubscriberKit.SubscriberVideoStats stats, String reason) {
Log.d("Stats", "Subscriber video quality event: " + reason);
}
});
Statistiques audio
subscriber.setAudioStatsListener(new SubscriberKit.AudioStatsListener() {
@Override
public void onAudioStats(SubscriberKit subscriber, SubscriberKit.SubscriberAudioStats stats) {
Log.d("Stats", "Audio packets received: " + stats.audioPacketsReceived);
}
});
Statistiques sur les liens avec les médias
subscriber.setMediaLinkStatsListener(new SubscriberKit.MediaLinkStatsListener() {
@Override
public void onMediaLinkStats(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats) {
if (mediaLinkStats.transport != null) {
Log.d("MediaLinkStats", "Downlink bandwidth: " + mediaLinkStats.transport.getConnectionEstimatedBandwidth() + " bps");
}
if (mediaLinkStats.remotePublisherTransport != null) {
Log.d("MediaLinkStats", "Remote publisher uplink bandwidth: " + mediaLinkStats.remotePublisherTransport.getConnectionEstimatedBandwidth() + " bps");
}
Log.d("MediaLinkStats", "Degradation source: " + mediaLinkStats.networkDegradationSource);
}
@Override
public void onNetworkConditionChanged(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats, String reason) {
if (mediaLinkStats.transport != null) {
Log.d("Stats", "Local network condition: " + mediaLinkStats.transport.networkCondition);
}
if (mediaLinkStats.remotePublisherTransport != null) {
Log.d("Stats", "Remote publisher network condition: " + mediaLinkStats.remotePublisherTransport.networkCondition);
}
Log.d("Stats", "Degradation source: " + mediaLinkStats.networkDegradationSource);
}
});
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'Android. 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 des SDK spécifiques à 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.
TransportStats
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 (NETWORK_CONDITION_UNKNOWN,NETWORK_CONDITION_CRITICAL,NETWORK_CONDITION_WARNING,NETWORK_CONDITION_FAIR,NETWORK_CONDITION_GOODouNETWORK_CONDITION_EXCELLENT).networkConditionReason- Raison principale de l'impact sur l'état du réseau (NETWORK_CONDITION_REASON_NONE,NETWORK_CONDITION_REASON_UNKNOWN,NETWORK_CONDITION_REASON_BANDWIDTHouNETWORK_CONDITION_REASON_PACKET_LOSS).
PublisherKit.PublisherVideoStats
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 (voirOTPublisherKitVideoLayerStats).
PublisherKit.PublisherAudioStats
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.startTime- Le timestamp, en millisecondes depuis l'époque Unix, à partir duquel les totaux cumulés ont commencé à s'accumuler.
PublisherKit.VideoLayerStats
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.
SubscriberKit.SenderStats
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).
SubscriberKit.SubscriberVideoStats
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.
SubscriberKit.SubscriberAudioStats
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).
PublisherKit.PublisherMediaLinkStats
Fournit des statistiques au niveau du transport pour la connexion d'un éditeur.
transport- Statistiques de transport pour cet éditeur (voirTransportStats)
SubscriberKit.SubscriberMediaLinkStats
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 locales de transport et de réseau pour cet abonné. Peut être limité si les statistiques côté expéditeur et/ou le repli audio sont désactivés.remotePublisherTransport- Statistiques de transport et de réseau de l'éditeur distant. Peut être limité si les statistiques côté expéditeur et/ou le repli audio sont désactivés.networkDegradationSource- Indique la source de la dégradation du réseau, le cas échéant (NetworkDegradationSource.NONE,NetworkDegradationSource.LOCAL,NetworkDegradationSource.REMOTEouNetworkDegradationSource.BOTH_OR_UNCLEAR).
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 senderStatisticsTrack à la propriété true lors de la construction de l'éditeur :
Publisher publisher = new Publisher.Builder(context)
.senderStatsTrack(true) // Enable sender-side stats
.build();
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 false.
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 via les rappels de statistiques vidéo et audio. décrite ci-dessus. Les senderStats sur les deux SubscriberKit.SubscriberVideoStats et SubscriberKit.SubscriberAudioStats fournit deux mesures :
connectionMaxAllocatedBitrate- Le débit maximum qui peut être estimé pour la connexionconnectionEstimatedBandwidth- 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.
subscriber.setVideoStatsListener((subscriber, stats) -> {
if (stats.senderStats != null) {
Log.d(TAG, "Connection max allocated bitrate: " + stats.senderStats.connectionMaxAllocatedBitrate);
Log.d(TAG, "Connection current estimated bandwidth: " + stats.senderStats.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
networkConditionetnetworkConditionReason. Pour les abonnés, les statistiques sur les liens avec les médias comprennent égalementremotePublisherTransportetnetworkDegradationSource. - Événements liés à la modification de l'état du réseau : Des rappels dédiés sur les deux éditeur et 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 :
@Override
public void onNetworkConditionChanged(SubscriberKit subscriber, SubscriberKit.SubscriberMediaLinkStats mediaLinkStats, String reason) {
int localCondition = mediaLinkStats.transport != null ? mediaLinkStats.transport.networkCondition : TransportStats.NETWORK_CONDITION_UNKNOWN;
int remoteCondition = mediaLinkStats.remotePublisherTransport != null ? mediaLinkStats.remotePublisherTransport.networkCondition : TransportStats.NETWORK_CONDITION_UNKNOWN;
int source = mediaLinkStats.networkDegradationSource;
if (source == NetworkDegradationSource.LOCAL) {
Log.d("Stats", "Local network is degraded (condition: " + localCondition + ")");
} else if (source == NetworkDegradationSource.REMOTE) {
Log.d("Stats", "Remote publisher network is degraded (condition: " + remoteCondition + ")");
} else if (source == NetworkDegradationSource.BOTH_OR_UNCLEAR) {
Log.d("Stats", "Degradation source unclear — local: " + localCondition + ", remote: " + remoteCondition);
}
}
Rapport statistique RTC
Pour obtenir des statistiques de bas niveau sur les connexions entre pairs pour un éditeur, utilisez la commande PublisherKit.getRtcStatsReport() méthode. Cette méthode fournit des rapports de statistiques RTC pour le flux multimédia. Il s'agit d'une opération asynchrone. Appelez la méthode PublisherKit.setRtcStatsReportListener(PublisherKit.PublisherRtcStatsReportListener listener) puis mettre en œuvre la méthode PublisherKit.PublisherRtcStatsReportListener.onRtcStatsReport(PublisherKit publisher, PublisherKit.PublisherRtcStats[] stats) avant d'appeler la méthode PublisherKit.getRtcStatsReport().
Lorsque les statistiques sont disponibles, la mise en œuvre de la fonction PublisherKit.PublisherRtcStatsReportListener.onRtcStatsReport(PublisherKit publisher, PublisherKit.PublisherRtcStats[] stats) est appelée.
Un tableau de PublisherRtcStats est transmis à cette méthode. La méthode PublisherRtcStats comprend un objet jsonArrayOfReports propriété. Il s'agit d'un tableau JSON de rapports de statistiques RTC, dont le format est similaire à celui de l'objet RtcStatsReport mis en œuvre dans les navigateurs web (voir ces documents de Mozilla).
Pour obtenir des statistiques de bas niveau sur les connexions entre pairs pour un abonné, utilisez la commande SubscriberKit.getRtcStatsReport() méthode. Cette méthode permet d'obtenir un rapport de statistiques RTC pour le flux multimédia.
Il s'agit d'une opération asynchrone. Appeler le SubscriberKit.setRtcStatsReportListener(SubscriberKit.SubscriberRtcStatsReportListener listener) puis mettre en œuvre la méthode SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) avant d'appeler la méthode SubscriberKit.getRtcStatsReport().
Lorsque les statistiques sont disponibles, la mise en œuvre de la fonction SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) est appelée. La méthode jsonArrayOfReports est un tableau JSON de rapports de statistiques RTC, dont le format est similaire à celui de l'objet RtcStatsReport mis en œuvre dans les navigateurs web (voir ces documents de Mozilla).
Voir aussi cette documentation du W3C.