> For a complete documentation index, fetch https://docs.voximplant.ai/llms.txt

# Mobile SDK statistics

This article will help you to receive basic and advanced statistics from the SDKs.

## Basic

Voximplant SDKs provide dedicated events on call quality. You can subscribe to them to handle the following errors:

* Codec mismatch ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#oncodecmismatch), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypecodecmismatch)) is triggered when the local audio, video or screen sharing is encoded by a codec different than the one specified in initialization config or call settings.
* High media latency ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onhighmedialatency), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypehighmedialatency)) is triggered when network-based media latency is detected during the call.
* ICE disconnected ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onicedisconnected), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypeicedisconnected)) is triggered when the ICE connection is switched to the "disconnected" state during the call.
* Local video degradation ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onlocalvideodegradation), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypelocalvideodegradation)) is triggered when the video resolution sent to the endpoint is lower than a captured video resolution.
* Packet loss ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onpacketloss), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypepacketloss)) is triggered every 2.5 seconds and indicates packet loss for the last period.
* No audio signal ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onnoaudiosignal), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuetype#viqualityissuetypenoaudiosignal)) is triggered when no audio is captured by the microphone.
  You can measure how critical an issue is by looking at its code name returned in the event.
* No audio received ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onnoaudioreceive), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuedelegate#calldiddetectnoaudioreceiveonstreamfromendpointissuelevel)) is triggered when no audio stream is received from the remote side.
* No video received ([Android](https://voximplant.com/docs/references/androidsdk/call/iqualityissuelistener#onnovideoreceive), [iOS](https://voximplant.com/docs/references/iossdk/call/viqualityissuedelegate#calldiddetectnovideoreceiveonstreamfromendpointissuelevel)) is triggered when no video stream is received from the remote side.

## Advanced

We recommend the following approaches for gathering connection stats and/or developing custom tools for tracking issues.

The stats are received constantly during an active call. There are two stats interfaces: **CallStats** (the general stats of a call) and **EndpointStats** (the stats of each participant of a call/conference).

<Info title="Web SDK. CallStats === EndpointStats">
  In Web SDK, during a simple call with two participants, CallStats equal EndpointStats.
</Info>

The stats are retrieved from the [didReceiveStatistics](https://voximplant.com/docs/references/iossdk/call/vicalldelegate#calldidreceivestatistics) event for iOS or [onCallStatsReceived](https://voximplant.com/docs/references/androidsdk/call/icalllistener#oncallstatsreceived) event for Android, which contains an object with a special field for an endpoint ([VICallStats](https://voximplant.com/docs/references/iossdk/call/vicallstats) for iOS or [CallStats](https://voximplant.com/docs/references/androidsdk/call/callstats) for Android), the other fields contain details on general stats.

<CodeBlocks>
  ```swift title="iOS (Swift)"
  // 1. Subscribe to VICallDelegate
  class ExampleClass: NSObject, VICallDelegate {
      var exampleCall: VICall?

      override init() {
          super.init()
          // 2. Set call delegate
          exampleCall?.add(self)
      }

      func call(_ call: VICall, didReceiveStatistics stat: VICallStats) {
          // 3. Statistics will appear here
      }
  }
  ```

  ```objc title="iOS (Objective-C)"
  // 1. Subscribe to VICallDelegate
  @interface ExampleClass : NSObject<VICallDelegate>

  @property (strong, nonatomic, readonly) VICall *exampleCall;

  @end

  @implementation ExampleClass

  - (instancetype)init
  {
      self = [super init];
      if (self) {
          // 2. Set call delegate
          [self.exampleCall addDelegate:self];
      }
      return self;
  }

  - (void)call:(VICall *)call didReceiveStatistics:(VICallStats *)stat {
      // 3. Statistics will appear here
  }

  @end
  ```

  ```java title="Android (Java)"
  // 1. Subscribe to ICallListener
  class ExampleClass implements ICallListener {

      ICall exampleCall;

      ExampleClass() {
          // 2. Set call listener
          exampleCall.addCallListener(this);
      }

      @Override
      public void onCallStatsReceived(ICall call, CallStats callStats) {
          // 3. Statistics will appear here
      }
  }
  ```

  ```kotlin title="Android (Kotlin)"
  // 1. Subscribe to ICallListener
  class ExampleClass : ICallListener {
      var exampleCall: ICall? = null

      init {
          // 2. Set call listener
          exampleCall?.addCallListener(this)
      }

      override fun onCallStatsReceived(
          call: ICall,
          callStats: CallStats
      ) {
          // 3. Statistics will appear here
      }
  }
  ```
</CodeBlocks>

By default, the stats arrive every 5 seconds for iOS and Android. You can adjust this value by changing the **statsCollectionInterval** property:

<CodeBlocks>
  ```swift title="iOS (Swift)"
  let settings = VICallSettings()
  settings.statsCollectionInterval = 1000

  self.call = self.client?.call(numberField.text!, settings: settings)
  ```

  ```objc title="iOS (Objective-C)"
  VICallSettings *settings = [[VICallSettings alloc] init];
  settings.statsCollectionInterval = 1000;

  self.call = [self.client call:numberField.text settings:settings];
  ```

  ```java title="Android (Java)"
  // It is possible to adjust the interval for getting statistics.
  // On IClient initialization pass a statsCollectionInterval to its ClientConfig
  ClientConfig config = new ClientConfig();
  config.statsCollectionInterval = 1000;

  IClient client = Voximplant.getClientInstance(
          Executors.newSingleThreadExecutor(),
          getApplicationContext(),
          config
  );
  ```

  ```kotlin title="Android (Kotlin)"
  // It is possible to adjust the interval for getting statistics.
  // On IClient initialization pass a statsCollectionInterval to its ClientConfig
  val config = ClientConfig()
  config.statsCollectionInterval = 1000

  val client = Voximplant.getClientInstance(
      Executors.newSingleThreadExecutor(),
      applicationContext,
      config
  )
  ```
</CodeBlocks>

<Info title="RAM utilization">
  Stats is accumulated in RAM during the interval specified in **StatsCollectionInterval**. Thus, the bigger the interval is, the higher RAM utilization is.
</Info>

Another point worth mentioning is the [timestamp](https://voximplant.com/docs/references/androidsdk/call/endpointstats#timestamp) value in the received stats. Bear in mind that it should differ from the previous received value; if not, you are probably experiencing some issue with gathering stats.