> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quickblox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced

> Learn how to mute audio, disable video,  switch camera, share your screen, configure media settings, etc.

## Media management

To manage audio & video streams `QBRTCSession` provides `QBMediaStreamManager` class.
`QBMediaStreamManager` holds a user's **local audio & video tracks** and provides a way to change the video capturer.

<Note>
  `QBMediaStreamManager` is attached to `QBRTCSession` lifecycle. According to `QBRTCSession` lifecycle, you should use `QBMediaStreamManager` only when `QBRTCSession` is active or has been started.
</Note>

## Mute audio

Mute the audio by calling `setEnabled()` or `setAudioEnabled()` method. Using these methods, we can tell SDK to send/not send audio data either from a local or remote peer in the specified call session.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBMediaStreamManager mediaStreamManager = currentSession.getMediaStreamManager();

    QBRTCAudioTrack localAudioTrack = mediaStreamManager.getLocalAudioTrack();

    // mute
    localAudioTrack.setEnabled(false);
    // or
    mediaStreamManager.setAudioEnabled(false);

    // unmute
    localAudioTrack.setEnabled(true);
    // or
    mediaStreamManager.setAudioEnabled(true);

    // is muted?
    boolean isEnabled = localAudioTrack.enabled();
    // or
    mediaStreamManager.isAudioEnabled();
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val mediaStreamManager = currentSession.mediaStreamManager

    val localAudioTrack = mediaStreamManager.localAudioTrack

    // mute
    localAudioTrack.setEnabled(false)
    // or
    mediaStreamManager.isAudioEnabled = false

    // unmute
    localAudioTrack.setEnabled(true)
    // or
    mediaStreamManager.isAudioEnabled = true

    // is muted?
    val isEnabled = localAudioTrack.enabled()
    // or
    mediaStreamManager.isAudioEnabled
    ```
  </Tab>
</Tabs>

## Disable video

Turn off the video by calling `setEnabled()` or `setVideoEnabled()` method. Using these methods, we can tell SDK not to send video data either from a local or remote peer in the specified call session.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBMediaStreamManager mediaStreamManager = currentSession.getMediaStreamManager();

    QBRTCVideoTrack localVideoTrack = mediaStreamManager.getLocalVideoTrack();

    // enable
    localVideoTrack.setEnabled(false);
    // or
    mediaStreamManager.setVideoEnabled(false);

    // disable
    localVideoTrack.setEnabled(true);
    // or
    mediaStreamManager.setVideoEnabled(true);

    // is enabled?
    boolean isEnabled = localVideoTrack.enabled();
    // or
    mediaStreamManager.isVideoEnabled();



    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val mediaStreamManager = currentSession.mediaStreamManager

    val localVideoTrack = mediaStreamManager.localVideoTrack

    // enable
    localVideoTrack.setEnabled(false)
    // or
    mediaStreamManager.isVideoEnabled = false

    // disable
    localVideoTrack.setEnabled(true)
    // or
    mediaStreamManager.isVideoEnabled = true

    // is Enabled?
    val isEnabled = localVideoTrack.enabled()
    // or
    mediaStreamManager.isVideoEnabled
    ```
  </Tab>
</Tabs>

## Capture video from camera

When a call session is started, the Camera Capturer is used by default. If you want to use it manually, you should set `QBRTCCameraVideoCapturer` as Video Capturer.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    try {
        currentSession.getMediaStreamManager().setVideoCapturer(new QBRTCCameraVideoCapturer(context, null));
    } catch (QBRTCCameraVideoCapturer.QBRTCCameraCapturerException exception) {
        exception.printStackTrace();
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    try {
        currentSession.mediaStreamManager.videoCapturer = QBRTCCameraVideoCapturer(context, null)
    } catch (exception: QBRTCCameraVideoCapturer.QBRTCCameraCapturerException) {
        exception.printStackTrace()
    }
    ```
  </Tab>
</Tabs>

<Warning>
  Creating a new instance of `QBRTCCameraVideoCapturer` throws the `QBRTCCameraCapturerException` so you should handle this exception.
</Warning>

## Switch camera

You can switch the video camera during a call. (Default: **front camera**)

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCCameraVideoCapturer videoCapturer = (QBRTCCameraVideoCapturer) currentSession.getMediaStreamManager().getVideoCapturer();
    videoCapturer.switchCamera(cameraSwitchHandler);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val videoCapturer = currentSession.mediaStreamManager.videoCapturer as QBRTCCameraVideoCapturer
    videoCapturer.switchCamera(cameraSwitchHandler)
    ```
  </Tab>
</Tabs>

You should use `CameraSwitchHandler` to handle the camera switching process.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    CameraVideoCapturer.CameraSwitchHandler cameraSwitchHandler = new CameraVideoCapturer.CameraSwitchHandler() {
        @Override
        public void onCameraSwitchDone(boolean switched) {

        }

        @Override
        public void onCameraSwitchError(String message) {

        }
    };
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val cameraSwitchHandler = object : CameraVideoCapturer.CameraSwitchHandler {
        override fun onCameraSwitchDone(switched: Boolean?) {

        }

        override fun onCameraSwitchError(message: String?) {

        }
    }
    ```
  </Tab>
</Tabs>

## Change capture format

You can change framerate and frame size during an active call session using `videoCapturer`.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCCameraVideoCapturer videoCapturer = (QBRTCCameraVideoCapturer) currentSession.getMediaStreamManager().getVideoCapturer();
    videoCapturer.changeCaptureFormat(width, height, framerate);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val videoCapturer = currentSession.mediaStreamManager.videoCapturer as QBRTCCameraVideoCapturer
    videoCapturer.changeCaptureFormat(width, height, framerate)
    ```
  </Tab>
</Tabs>

## Screen sharing

To share the screen of your device with the opponents, follow the steps below:

1. Ask appropriate permission.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
        QBRTCScreenCapturer.requestPermissions(CallActivity.this);
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
        QBRTCScreenCapturer.requestPermissions(this@CallActivity)
    }
    ```
  </Tab>
</Tabs>

<Warning>
  Instead of `CallActivity.this`, you can use the context of the activity where you are asking this permission.
</Warning>

1. Handle results of asking the permission.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == QBRTCScreenCapturer.REQUEST_MEDIA_PROJECTION) {
            if (resultCode == Activity.RESULT_OK) {
                // now you can start Screen Sharing
                startScreenSharing(data);
            }
        }
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == QBRTCScreenCapturer.REQUEST_MEDIA_PROJECTION) {
            if (resultCode == Activity.RESULT_OK) {
                // now you can start Screen Sharing
                startScreenSharing(data)
            }
        }
    }
    ```
  </Tab>
</Tabs>

<Warning>
  You should pass the Intent (data) to `startScreenSharing()` method to use it for `setVideoCapturer()`.
</Warning>

1. Set `QBRTCScreenCapturer` as Video Capturer.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCSession currentSession = getCurrentSession(); // simply use your current session variable
    currentSession.getMediaStreamManager().setVideoCapturer(new QBRTCScreenCapturer(data, null)); // data - it's Intent from onActivityResult
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val currentSession = getCurrentSession() // Simply use your current session variable
    currentSession.getMediaStreamManager().setVideoCapturer(QBRTCScreenCapturer(data, null)) // data - it's Intent from onActivityResult
    ```
  </Tab>
</Tabs>

## WebRTC stats reporting

You are able to receive an information report about the current connection, audio, video tracks, and other useful information. To set a receiving time interval, use the code snippet below.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCConfig.setStatsReportInterval(60);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    QBRTCConfig.setStatsReportInterval(60)
    ```
  </Tab>
</Tabs>

Then you should use the `QBRTCStatsReportCallback` and add them.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    currentSession.addStatsReportCallback(new QBRTCStatsReportCallback() {
        @Override
        public void onStatsReportUpdate(QBRTCStatsReport statsReport, Integer userId) {
            statsReport.getAudioReceivedCodec();
            statsReport.getAudioReceivedBitrate();

            statsReport.getVideoSendCodec();
            statsReport.getVideoSendBitrate();
            statsReport.getVideoReceivedBitrate();

            statsReport.getVideoReceivedFps();

            statsReport.getAudioSendInputLevel();

            statsReport.getVideoReceivedWidth();
            statsReport.getVideoReceivedHeight();
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    currentSession.addStatsReportCallback { statsReport, userId ->
        statsReport.audioReceivedCodec
        statsReport.audioReceivedBitrate

        statsReport.videoSendCodec
        statsReport.videoSendBitrate
        statsReport.videoReceivedBitrate

        statsReport.videoReceivedFps

        statsReport.audioSendInputLevel

        statsReport.videoReceivedWidth
        statsReport.videoReceivedHeight
    }
    ```
  </Tab>
</Tabs>

<Note>
  The `qbrtcStatsReport.audioReceivedCodec()` and `qbrtcStatsReport.videoReceivedFps()` are not all you can get from the `QBRTCStatsReport`. This is just the example.
</Note>

<Tip>
  Using `QBRTCStatsReport`, you can define when your opponent is speaking by using the `qbrtcStatsReport.getAudioReceiveOutputLevel()` parameter. This parameter is the **microphone level** from the participant’s **audio track** at the moment of collecting the statistics report.
</Tip>

## General settings

You can change different settings for your calls using the `QBRTCConfig` class. All of them are listed below.

### Answer time interval

If an opponent hasn't answered you within an answer time interval, then the `onUserNotAnswer()` callback will be returned. The answer time interval shows how much time an opponent has to answer your call. Set the answer time interval using the code snippet below.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    // time interval to wait opponents answer
    QBRTCConfig.setAnswerTimeInterval(answerTimeInterval);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    // time interval to wait opponents answer
    QBRTCConfig.setAnswerTimeInterval(answerTimeInterval)
    ```
  </Tab>
</Tabs>

<Note>
  **By default**, the answer time interval is 60 seconds.
</Note>

### Disconnect time interval

Set maximum allowed time to repair a connection after it was lost. Set the disconnect time interval using the code snippet below.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    // time to repair the connection after it was lost
    QBRTCConfig.setDisconnectTime(disconnectTimeInterval);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    // time to repair the connection after it was lost
    QBRTCConfig.setDisconnectTime(disconnectTimeInterval)
    ```
  </Tab>
</Tabs>

<Note>
  **By default**, the disconnect time interval is 10 seconds.
</Note>

### Dialing time interval

Dialing time interval indicates how often to notify your opponents about your call. Set the dialing time interval using the code snippet below.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    // time interval for establishing connection with the opponent
    QBRTCConfig.setDialingTimeInterval(dialingTimeInterval);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    // time interval for establishing connection with the opponent
    QBRTCConfig.setDialingTimeInterval(dialingTimeInterval)
    ```
  </Tab>
</Tabs>

<Note>
  **By default**, the dialing time interval is 5 seconds.
</Note>

### Maximum number of opponents

Set the maximum number of opponents in a group call using the snippet below.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    // max number of opponents in group call
    QBRTCConfig.setMaxOpponentsCount(maxOpponentCount);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    // max number of opponents in group call
    QBRTCConfig.setMaxOpponentsCount(maxOpponentCount)
    ```
  </Tab>
</Tabs>

<Note>
  **By default**, the maximum number of opponents is 10.
</Note>

### Custom ICE servers

You can customize a list of ICE servers. **By default**, WebRTC module will use internal ICE servers that are usually enough, but you can always set your own. WebRTC engine will choose the TURN relay with the lowest round-trip time. Thus, setting multiple TURN servers allows your application to scale-up in terms of bandwidth and number of users. Review our [Setup](/sdks/android-setup#custom-ice-servers) guide to learn how to configure custom ICE servers.

## Media settings

You can use the `QBRTCMediaConfig` class instance to configure a variety of media settings such as video/audio codecs, bitrate, fps, etc.

### Video codecs

It's possible to set a video codec. You can choose from the following values: **H264**, **VP8**, and **VP9**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCMediaConfig.VideoCodec videoCodec;
    videoCodec = QBRTCMediaConfig.VideoCodec.H264;
    videoCodec = QBRTCMediaConfig.VideoCodec.VP8;
    videoCodec = QBRTCMediaConfig.VideoCodec.VP9;

    QBRTCMediaConfig.setVideoCodec(videoCodec);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    var videoCodec: QBRTCMediaConfig.VideoCodec
    videoCodec = QBRTCMediaConfig.VideoCodec.H264
    videoCodec = QBRTCMediaConfig.VideoCodec.VP8
    videoCodec = QBRTCMediaConfig.VideoCodec.VP9

    QBRTCMediaConfig.setVideoCodec(videoCodec)
    ```
  </Tab>
</Tabs>

### Camera resolution

You can also set the custom video resolution to provide guarantees for the predictable behavior of the video stream.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    int videoWidth = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.width;
    int videoHeight = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.height;

    // VGA Resolution
    //videoWidth = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width;
    //videoHeight = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height;

    // HD Resolution
    //videoWidth = QBRTCMediaConfig.VideoQuality.HD_VIDEO.width;
    //videoHeight = QBRTCMediaConfig.VideoQuality.HD_VIDEO.height;

    // custom Resolution (for example FullHD)
    //videoWidth = 1920;
    //videoHeight = 1080;

    QBRTCMediaConfig.setVideoWidth(videoWidth);
    QBRTCMediaConfig.setVideoHeight(videoHeight);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    var videoWidth = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.width
    var videoHeight = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.height

    // VGA Resolution
    //videoWidth = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width
    //videoHeight = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height

    // HD Resolution
    //videoWidth = QBRTCMediaConfig.VideoQuality.HD_VIDEO.width
    //videoHeight = QBRTCMediaConfig.VideoQuality.HD_VIDEO.height

    // Custom Resolution (for example FullHD)
    //videoWidth = 1920
    //videoHeight = 1080

    QBRTCMediaConfig.setVideoWidth(videoWidth)
    QBRTCMediaConfig.setVideoHeight(videoHeight)
    ```
  </Tab>
</Tabs>

### Audio codecs

Set an audio codec using the snippet below. You can choose from the following values: **ISAC** and **OPUS**. Default: **ISAC**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    QBRTCMediaConfig.AudioCodec audioCodec;
    audioCodec = QBRTCMediaConfig.AudioCodec.OPUS;
    audioCodec = QBRTCMediaConfig.AudioCodec.ISAC;

    QBRTCMediaConfig.setAudioCodec(audioCodec)
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    var audioCodec: QBRTCMediaConfig.AudioCodec
    audioCodec = QBRTCMediaConfig.AudioCodec.OPUS
    audioCodec = QBRTCMediaConfig.AudioCodec.ISAC

    QBRTCMediaConfig.setAudioCodec(audioCodec)
    ```
  </Tab>
</Tabs>

### Bitrate

It's possible to set the custom bitrate to provide guarantees for the predictable behavior of the video stream.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    int startBitrate = 0;
    //startBitrate = 2000;
    QBRTCMediaConfig.setVideoStartBitrate(startBitrate);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    var startBitrate: Int = 0
    //startBitrate = 2000
    QBRTCMediaConfig.setVideoStartBitrate(startBitrate)
    ```
  </Tab>
</Tabs>

### Hardware acceleration

Enable hardware acceleration if the device supports it. Default: **false**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    boolean useHWAcceleration = true;
    QBRTCMediaConfig.setVideoHWAcceleration(useHWAcceleration);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val useHWAcceleration = true
    QBRTCMediaConfig.setVideoHWAcceleration(useHWAcceleration)
    ```
  </Tab>
</Tabs>

### Frames per second

It's possible to set the custom fps to provide guarantees for the predictable behavior of the video stream.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    int fps = 30;
    //fps = 30;
    QBRTCMediaConfig.setVideoFps(fps);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val fps = 30
    //fps = 30;
    QBRTCMediaConfig.setVideoFps(fps)
    ```
  </Tab>
</Tabs>

### Acoustic echo cancellation

Enable a built-in acoustic echo cancellation if the device supports it. Default: **true**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    boolean useAEC = true;
    QBRTCMediaConfig.setUseBuildInAEC(useAEC);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val useAEC = true
    QBRTCMediaConfig.setUseBuildInAEC(useAEC)
    ```
  </Tab>
</Tabs>

### Open sound library for embedded systems

Enable open sound library for embedded systems (OpenSL ES audio) if the device supports it. Default: **false**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    boolean useOpenSLES = true;
    QBRTCMediaConfig.setUseOpenSLES(useOpenSLES);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val useOpenSLES = true
    QBRTCMediaConfig.setUseOpenSLES(useOpenSLES)
    ```
  </Tab>
</Tabs>

### Audio processing

Enable audio processing if the device supports it. Default: **true**.

<Tabs>
  <Tab title="Java">
    ```Java theme={null}
    boolean useAudioProcessing = true;
    QBRTCMediaConfig.setAudioProcessingEnabled(useAudioProcessing);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```Kotlin theme={null}
    val useAudioProcessing = true
    QBRTCMediaConfig.setAudioProcessingEnabled(useAudioProcessing)
    ```
  </Tab>
</Tabs>
