# In-call quality monitoring (/en/realtime-media/interactive-live-streaming/build/optimize-quality-and-connection/in-call-quality-monitoring/macos)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

During a call, Video SDK triggers callbacks related to the video calling quality. These callbacks enable you to monitor your users' experience, troubleshoot issues, and optimize their overall experience

      
  
      
  
      
    ## Understand the tech [#understand-the-tech-2]

    After a user joins a channel, Video SDK triggers a series of callbacks every 2 seconds, reporting information such as uplink and downlink network quality, real-time interaction statistics, and statistics of local and remote audio and video streams.

    When there is a change in the audio or video state of a user, Video SDK triggers a callback to report the latest state and the reason for the change. The following figure shows the audio transmission process between app clients:

    **Audio transmission process**

    ![Audio transmission process](https://assets-docs.agora.io/images/video-sdk/in-call-quality.svg)

    To monitor the call quality, Agora provides the following call quality notifications:

    **Network quality**

    The network quality callback provides insight into the uplink and downlink last mile network quality for each participant in the channel. Last mile refers to the network from your device to Agora server. The [Network quality scores](#network-quality-score) are calculated based on factors such as sending or receiving bitrate, network packet loss rate, round-trip delay, and network jitter.

    **Statistics**

    The statistics callback, triggered every 2 seconds, reports key metrics such as call duration, the number of participants, system CPU usage, and app CPU usage.

    **Audio quality**

    Callbacks related to audio quality cover both local and remote audio streams. You monitor statistics and status changes, to gain insights into the quality of audio streams and any related reasons for status changes.

    **Video quality**

    Video quality callbacks provide information on both local and remote video streams. You receive statistics and status change notifications, that enable you to understand the quality of video streams and any related reasons for status changes.

    ## Prerequisites [#prerequisites-2]

    Ensure that you have implemented the [SDK quickstart](/en/realtime-media/video/get-started-sdk) in your project.

    ## Implement in-call quality monitoring [#implement-in-call-quality-monitoring-2]

    In the `AgoraRtcEngineDelegate`, implement the necessary callbacks to monitor real-time interaction quality and audio or video stream status. Key callbacks include:

    * `networkQuality`: Reports upstream and downstream last mile network quality.
    * `reportRtcStats`: Provides real-time interaction statistics.
    * `localAudioStats`: Reports statistics on sent audio streams.
    * `localAudioStateChange`: Reports local audio stream state changes.
    * `remoteAudioStats`: Reports statistics on received remote audio streams.
    * `remoteAudioStateChangedOfUid`: Reports remote audio stream state changes.
    * `localVideoStats`: Reports statistics on sent video streams.
    * `localVideoStateChangedOfState`: Reports local video stream state changes.
    * `remoteVideoStats`: Reports statistics on received remote video streams.
    * `remoteVideoStateChangedOfUid`: Reports remote video stream state changes.

    In your app, add the following code:

    ```swift
    extension JoinChannelVideoMain: AgoraRtcEngineDelegate {
      // Reports upstream and downstream last mile network quality
      func rtcEngine(_ engine: AgoraRtcEngineKit, networkQuality uid: UInt, txQuality: AgoraNetworkQuality, rxQuality: AgoraNetworkQuality) {
        // Add logic to state the network quality
      }

      // Provides real-time interaction statistics
      func rtcEngine(_ engine: AgoraRtcEngineKit, reportRtcStats stats: AgoraChannelStats) {
        // Add your logic here
      }

      // Reports statistics on sent audio streams
      func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStats stats: AgoraRtcLocalAudioStats) {
        // Handle the local audio stats
      }

      // Reports local audio stream state changes
      func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStateChange state: AgoraAudioLocalState, error: AgoraAudioLocalError) {
        // Handle local audio state change
      }

      // Reports statistics on received remote audio streams
      func rtcEngine(_ engine: AgoraRtcEngineKit, remoteAudioStats stats: AgoraRtcRemoteAudioStats) {
        // Handle the remote audio stats
      }

      // Reports remote audio stream state changes
      func rtcEngine(_ engine: AgoraRtcEngineKit, remoteAudioStateChangedOfUid uid: UInt, state: AgoraAudioRemoteState, reason: AgoraAudioRemoteStateReason, elapsed: Int) {
        // Handle remote audio state change
      }

      // Reports statistics on sent video streams
      func rtcEngine(_ engine: AgoraRtcEngineKit, localVideoStats stats: AgoraRtcLocalVideoStats) {
        // Handle video stream statistics
      }

      // Reports local video stream state changes
      func rtcEngine(_ engine: AgoraRtcEngineKit, localVideoStateChangedOfState state: AgoraLocalVideoStreamState, error: AgoraLocalVideoStreamError) {
        // Handle local video state change
      }

      // Reports statistics on received remote video streams
      func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) {
        // Handle the remote video stream's statistics
      }

      // Reports remote video stream state changes
      func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStateChangedOfUid uid: UInt, state: AgoraRemoteVideoState, reason: AgoraRemoteVideoStateReason, elapsed: Int) {
        // Handle remote video state change
      }
    }
    ```

    ## Reference [#reference-2]

    ### Network quality score [#network-quality-score-2]

    | Value | Enumeration                    | Description                                                                                 |
    | :---: | :----------------------------- | :------------------------------------------------------------------------------------------ |
    |   0   | `AgoraNetworkQualityUnknown`   | Network quality is unknown.                                                                 |
    |   1   | `AgoraNetworkQualityExcellent` | The network quality is excellent.                                                           |
    |   2   | `AgoraNetworkQualityGood`      | The network quality is good, but the bitrate may be slightly lower than excellent.          |
    |   3   | `AgoraNetworkQualityPoor`      | The network quality is average, and users may experience a slight decrease in call quality. |
    |   4   | `AgoraNetworkQualityBad`       | The network quality is poor, and users are unable to make smooth calls.                     |
    |   5   | `AgoraNetworkQualityVBad`      | The network quality is extremely poor, making it almost impossible for users to make calls. |
    |   6   | `AgoraNetworkQualityDown`      | The network connection is interrupted, and the user is completely unable to make a call.    |
    |   8   | `AgoraNetworkQualityDetecting` | Last-mile detection tests are underway.                                                     |

    ### API reference [#api-reference-2]

    * [`rtcEngine(_:networkQuality:txQuality:rxQuality:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:networkquality\:txquality\:rxquality:\))
    * [`rtcEngine(_:reportRtcStats:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:reportrtcstats:\))
    * [`rtcEngine(_:localAudioStats:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:localaudiostats:\))
    * [`rtcEngine(_:localAudioStateChanged:reason:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:localaudiostatechanged\:error:\))
    * [`rtcEngine(_:remoteAudioStats:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:remoteaudiostats:\))
    * [`rtcEngine(_:remoteAudioStateChangedOfUid:state:reason:elapsed:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:remoteaudiostatechangedofuid\:state\:reason\:elapsed:\))
    * [`rtcEngine(_:localVideoStats:sourceType:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:localvideostats\:sourcetype:\))
    * [`rtcEngine(_:localVideoStateChangedOf:reason:sourceType:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:localvideostatechangedof\:error\:sourcetype:\))
    * [`rtcEngine(_:remoteVideoStats:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:remotevideostats:\))
    * [`rtcEngine(_:remoteVideoStateChangedOfUid:state:reason:elapsed:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginedelegate/rtcengine\(_\:remotevideostatechangedofuid\:state\:reason\:elapsed:\))

    
  
      
  
      
  
      
  
      
  
      
  
      
  
      
  
