Search Results for

    Show / Hide Table of Contents

    Connection Statistics

    The stats APIs make it easy to get information about your ongoing connections and other WebRTC internals. They closely follow the WebRTC Statistics API RFC. Note that the underlying WebRTC statistics API is not supported consistently from browser to browser. For instance, Chrome exposes the most full-featured statistics whereas Edge does not implement it at all. In all cases where our statistics API is wrapping that provided by the browser, if the browser does not implement the given API, then the API returns a null stats object. This is the expected behaviour and the app code should be checking for null stats objects.

    Note

    About the code examples on this page:

    • For Unity, Xamarin Android, Xamarin iOS, and Xamarin macOS, use the C# code.
    • For Java, use the Android code.
    • For macOS, use the iOS code.

    getStats

    You can call the getStats function on any active Connection. For example, one way to do so would be to wire up an event to call getStats once the Connection state transitions to Connected, and then unwire the event when the Connection state transitions to Closed (or Failed). Your event could be triggered by some UI element (like a button click), or fired on a Timer, whatever meets your use case.

    • CSharp
    • Android
    • iOS
    • JavaScript
    connection.GetStats().Then((stats) => {
        var transport = stats.Streams[0].Transport;
        if (transport != null)
        {
            var localCandidates = transport.LocalCandidates;
            var remoteCandidates = transport.RemoteCandidates;
            var activeCandidatePair = transport.ActiveCandidatePair;
            var activeLocalCandidateId = activeCandidatePair.LocalCandidateId;
            var activeRemoteCandidateId = activeCandidatePair.RemoteCandidateId;
     
            for (var i = 0; i < localCandidates.Length; i++)
            {
                var localCandidate = localCandidates[i];
                if (localCandidate.Id == activeLocalCandidateId)
                {
                    // this is the active local candidate
     
                    // check the protocol - UDP or TCP
                    var localCandidateProtocol = localCandidate.Protocol;
     
                    if (localCandidate.IsRelayed)
                    {
                        // check the relay server IP
                        var relayServerIPAddress = localCandidate.IPAddress;
                    }
                }
            }
            for (var i = 0; i < remoteCandidates.Length; i++)
            {
                var remoteCandidate = remoteCandidates[i];
                if (remoteCandidate.Id == activeRemoteCandidateId)
                {
                    // this is the active remote candidate
                    if (remoteCandidate.IsRelayed)
                    {
                        // check the relay server IP
                        var relayServerIPAddress = remoteCandidate.IPAddress;
                    }
                }
            }
        }
    });
    
    connection.getStats().then((stats) -> {
        TransportStats transport = stats.getStreams()[0].getTransport();
        CandidateStats[] localCandidates = transport.getLocalCandidates();
        CandidateStats[] remoteCandidates = transport.getRemoteCandidates();
        CandidatePairStats activeCandidatePair = transport.getActiveCandidatePair();
        String activeLocalCandidateId = activeCandidatePair.getLocalCandidateId();
        String activeRemoteCandidateId = activeCandidatePair.getRemoteCandidateId();
        for (int i = 0; i < localCandidates.length; i++) {
            CandidateStats localCandidate = localCandidates[i];
            if (localCandidate.getId() == activeLocalCandidateId) {
                // this is the active local candidate
     
                if (localCandidate.getIsRelayed()) {
                    // check the relay server IP
                    String relayServerIPAddress = localCandidate.getIPAddress();
                }
            }
        }
        for (int i = 0; i < remoteCandidates.length; i++) {
            CandidateStats remoteCandidate = remoteCandidates[i];
            if (remoteCandidate.getId() == activeRemoteCandidateId) {
                // this is the active remote candidate
                if (remoteCandidate.getIsRelayed()) {
                    // check the relay server IP
                    String relayServerIPAddress = remoteCandidate.getIPAddress();
                }
            }
        }
    })
    
    connection!.getStats().then(resolveActionBlock: { (stats) in
        let statistics = stats as! FMLiveSwitchConnectionStats?
        let stream = statistics?.streams()[0] as! FMLiveSwitchStreamStats?
        let transport = stream?.transport()
        if (transport != nil)
        {
            let localCandidates = transport?.localCandidates()
            let remoteCandidates = transport?.remoteCandidates()
            let activeCandidatePair = transport?.activeCandidatePair()
            let activeLocalCandidateId = activeCandidatePair?.localCandidateId()
            let activeRemoteCandidateId = activeCandidatePair?.remoteCandidateId()
             
            for i in stride(from: 0, to: (localCandidates?.count)!-1, by: 1)
            {
                let localCandidate = localCandidates?[i] as! FMLiveSwitchCandidateStats?
                if (localCandidate?.id() == activeLocalCandidateId)
                {
                    // this is the active local candidate
     
                    // check the protocol
                    let localCandidateProtocol = localCandidate?.protocol()
     
                    if (localCandidate?.isRelayed())!
                    {
                        // check the relay server IP
                        let relayServerIPAddress = localCandidate?.ipAddress()
                    }
                }
            }
            for i in stride(from: 0, to: (remoteCandidates?.count)!-1, by: 1)
            {
                let remoteCandidate = remoteCandidates?[i] as! FMLiveSwitchCandidateStats?
                if (remoteCandidate?.id() == activeRemoteCandidateId)
                {
                    // this is the active remote candidate
                    if (remoteCandidate?.isRelayed())!
                    {
                        // check the relay server IP
                        let relayServerIPAddress = remoteCandidate?.ipAddress()
                    }
                }
            }
        }
    });
    
    connection.getStats().then(function(stats) {
        var transport = stats.getStreams()[0].getTransport();
        if (transport) {
            var localCandidates = transport.getLocalCandidates();
            var remoteCandidates = transport.getRemoteCandidates();
            var activeCandidatePair = transport.getActiveCandidatePair();
            var activeLocalCandidateId = activeCandidatePair.getLocalCandidateId();
            var activeRemoteCandidateId = activeCandidatePair.getRemoteCandidateId();
            for (var i = 0; i < localCandidates.length; i++) {
                var localCandidate = localCandidates[i];
                if (localCandidate.getId() == activeLocalCandidateId) {
                    // this is the active local candidate
     
                    // check the protocol - UDP or TCP
                    var localCandidateProtocol = localCandidate.getProtocol();
     
                    if (localCandidate.getIsRelayed()) {
                        // check the relay server IP
                        var relayServerIPAddress = localCandidate.getIPAddress();
                    }
                }
            }
            for (var i = 0; i < remoteCandidates.length; i++) {
                var remoteCandidate = remoteCandidates[i];
                if (remoteCandidate.getId() == activeRemoteCandidateId) {
                    // this is the active remote candidate
                    if (remoteCandidate.getIsRelayed()) {
                        // check the relay server IP
                        var relayServerIPAddress = remoteCandidate.getIPAddress();
                    }
                }
            }
        }
    });
    

    OnStats

    The OnStats event is raised when the current connection's statistics are gathered.

    • CSharp
    • Android
    • iOS
    • JavaScript
    connection.OnStats += stats =>
    {
        // stats is a snapshot of the current connection stats
    };
    
    connection.addOnStats((fm.liveswitch.ConnectionStats stats) -> {
        // stats is a snapshot of the current connection stats
    });
    
    connection.addOnStats { stats in
        // stats is a snapshot of the current connection stats
    }
    
    connection.addOnStats((stats) => {
        // stats is a snapshot of the current connection stats
    });
    

    OnNetworkQuality

    The OnNetworkQuality event is raised when the connection's network quality is estimated. OnNetworkQuality returns a value that ranges from 0.0 to 1.0, where 0.0 is the lowest quality and 1.0 is the highest quality.

    • CSharp
    • Android
    • iOS
    • JavaScript
    connection.OnNetworkQuality += networkQuality =>
    {
        // networkQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    };
    
    connection.addOnNetworkQuality((double networkQuality) -> {
        // networkQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    });
    
    connection.addOnNetworkQuality { networkQuality in
        // networkQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    }
    
    connection.addOnNetworkQuality((networkQuality) => {
        // networkQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    });
    

    OnMediaQuality

    The OnMediaQuality event is raised when the connection's media quality is estimated. OnMediaQuality returns a value that ranges from 0.0 to 1.0, where 0.0 is the lowest quality and 1.0 is the highest quality.

    The OnMediaQuality and OnNetworkQuality events are intentionally independent of each other. SFU downstream connections need to be able to distinguish between a poor network connection to the Media Server (a problem with me) and a poor media feed (a problem with you).

    • CSharp
    • Android
    • iOS
    • JavaScript
    connection.OnMediaQuality += mediaQuality =>
    {
        // mediaQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    };
    
    connection.addOnMediaQuality((double mediaQuality) -> {
        // mediaQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    });
    
    connection.addOnMediaQuality { mediaQuality in
        // mediaQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    }
    
    connection.OnMediaQuality += mediaQuality =>
    {
        // mediaQuality is value ranging from 0.0 (lowest quality) to 1.0 (highest quality)
    };
    

    Set Statistic Events Frequency

    Use StatsEventInterval to set the interval, in milliseconds, in which statistics events like OnStats, OnNetworkQuality, and onMediaQuality are raised.

    • CSharp
    • Android
    • iOS
    • JavaScript
    connection.StatsEventInterval = 5000; // once every 5 seconds
    
    connection.setStatsEventInterval(5000); // once every 5 seconds
    
    connection.setStatsEventInterval(5000)  // once every 5 seconds
    
    connection.setStatsEventInterval(5000); // once every 5 seconds
    
    In This Article
    Back to top Copyright © LiveSwitch Inc. All Rights Reserved.Documentation for LiveSwitch Version 1.6.2