> ## 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.

# Video Conference

> Learn how to add video conference calls to your app.

<Warning>
  This feature is available for customers on the **Enterprise plan** only. Take advantage of Enterprise features to unlock new value and opportunities for users. For more information and if you want to request a Demo, please contact us by mail: [enterprise@quickblox.com](mailto:enterprise@quickblox.com.).
</Warning>

QuickBlox provides a Multiparty Video Conferencing solution allowing to set up a video conference between 10-12 people. It is built on top of [WebRTC SFU](https://webrtcglossary.com/sfu/) technologies.

Features supported:

* Video/Audio Conference with 10-12 people.
* Join/Rejoin video room functionality (like Skype).
* Mute/Unmute audio/video stream.
* Switch video input device (camera).

## Initialize

In order to start working with Multiparty Video Conferencing API, you need to initialize the conference module by calling the `init()` method. The conference module allows to process conference calls. If the module is not initialized, it will not be able to create the session and process calls consequently.

<Warning>
  You must call the `init()` method before calling any other methods. If you attempt to call a method without initializing the module, the error is returned.
</Warning>

```Dart Dart theme={null}
try {
  String conferenceServer = "your_conference_server";
  await QB.conference.init(conferenceServer);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument         | Required | Description                   |
| ---------------- | -------- | ----------------------------- |
| conferenceServer | yes      | A conference server endpoint. |

## Manage calls

To process events such as a received video track, you should subscribe to an event(s) first and assign an event handler. If you've subscribed to the event(s), you receive `StreamSubscription` that you should unsubscribe when you need, for example, in the `dispose()` method.

You can subscribe to several events at the same time. However, you should handle these events as different subscriptions. For example, if you subscribe to three events, you should call three `subscribeConferenceEvent()` methods. And if you need to unsubscribe from these three events, you should have the same number of unsubscriptions.

```Dart Dart theme={null}
// Conference Events
// QBConferenceEventTypes.CONFERENCE_VIDEO_TRACK_RECEIVED
// QBConferenceEventTypes.CONFERENCE_PARTICIPANT_RECEIVED
// QBConferenceEventTypes.CONFERENCE_PARTICIPANT_LEFT
// QBConferenceEventTypes.CONFERENCE_ERROR_RECEIVED
// QBConferenceEventTypes.CONFERENCE_CLOSED
// QBConferenceEventTypes.CONFERENCE_STATE_CHANGED

StreamSubscription? _someSubscription;

// Unsubscribe

@override
void dispose() {
  if(_someSubscription != null) {
  	_someSubscription!.cancel();
    _someSubscription = null;
  }
}

// Subscribe
String event = QBConferenceEventTypes.CONFERENCE_CLOSED;

try {
  someSubscription = await QB.conference.subscribeConferenceEvent(event ,(data) {
  String sessionId = data["payload"]["sessionId"];
});
} on PlatformException catch (e) {
  // Some error occured, look at the exception message for more details
}
```

The table below lists all supported conference session events.

| Event                                                     | Description                                                       |
| --------------------------------------------------------- | ----------------------------------------------------------------- |
| QBConferenceEventTypes.CONFERENCE\_VIDEO\_TRACK\_RECEIVED | A remote video track has been received by the remote participant. |
| QBConferenceEventTypes.CONFERENCE\_PARTICIPANT\_RECEIVED  | A new participant has joined a conference session.                |
| QBConferenceEventTypes.CONFERENCE\_PARTICIPANT\_LEFT      | A participant has left a conference session.                      |
| QBConferenceEventTypes.CONFERENCE\_ERROR\_RECEIVED        | An error was received.                                            |
| QBConferenceEventTypes.CONFERENCE\_CLOSED                 | A conference session was closed.                                  |
| QBConferenceEventTypes.CONFERENCE\_STATE\_CHANGED         | A conference session state has been changed.                      |

## Create session

To be able to interact with the Video Conferencing API, you need to create a conference session by calling the `create()` method. Each conference session is tied to a specific `dialogId` taken from the QuickBlox Chat. See [this section](/sdks/flutter-chat-dialogs) for more information about dialogs.

<Warning>
  It is important to store the current session in the `session` variable to be able to interact with the current conference session. For example, if you don't store the current session, you won't be able to hang up or reject a call.
</Warning>

```Dart Dart theme={null}
// Session Types
// QBConferenceSessionTypes.VIDEO
// QBConferenceSessionTypes.AUDIO

...

QBConferenceRTCSession? _session;

...

String dialogId = "1148462029";
String sessionType = QBConferenceSessionTypes.VIDEO;

try {
  _session = await QB.conference.create(dialogId, sessionType);
  int sessionId = session!.id;
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument    | Required | Description                                                                              |
| ----------- | -------- | ---------------------------------------------------------------------------------------- |
| sessionType | yes      | Conference session type: QBConferenceSessionTypes.VIDEO, QBConferenceSessionTypes.AUDIO. |
| dialogId    | yes      | ID of the dialog. Taken from the QuickBlox Chat.                                         |

## Join video room

Once a conference session is created, you need to establish a call. To establish a call, you need to join an already-created conference session by calling the `joinAsPublisher()` method. This method joins the session and publishes your feed making you an active publisher in the room. Everyone in the room will be able to subscribe and receive your feed. Once the room is joined, you receive an array of participants' IDs.

<Warning>
  Make sure to subscribe to each participant to be able to receive video/audio tracks from them. If you don't subscribe, you won't receive audio and video of the participant joined to the room. See [this section](/sdks/flutter-video-conference#subscribe) for more information.
</Warning>

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";

try {
  List<int?> participants = await QB.conference.joinAsPublisher(sessionId);
  for (int i = 0; i < participants.length; i++) {
    int userId = participants[i]!;
    subscribeToParticipant(sessionId, userId);
  }
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description                                                                                                                     |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| sessionId | yes      | Conference session ID. Received from the QBConferenceRTCSession object that is returned in the response to the create() method. |

## Subscribe

Use the `subscribeToParticipant()` method to subscribe to a participant.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";
int userid = 567527986;

try {
  await QB.conference.subscribeToParticipant(sessionId, userId);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description                                                                                                  |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| sessionId | yes      | Conference session ID.                                                                                       |
| userId    | yes      | User ID. Taken from the array of participants' IDs received in the responce to the joinAsPublisher() method. |

## Unsubscribe

Use the `unsubscribeFromParticipant()` method to unsubscribe from the participant's audio/video track.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";
int userid = 567527986;

try {
  await QB.conference.unsubscribeFromParticipant(sessionId, userId);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description                                                                                                 |
| --------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| sessionId | yes      | Conference session ID.                                                                                      |
| userId    | yes      | User ID. Taken from the array of participants' IDs received in the responce to the joinAsPublisher() mthod. |

## Set up video view

Set up the `ConferenceVideoView` for remote and local video tracks to be able to show the video. The `ConferenceVideoView` allows displaying the video stream while the `ConferenceVideoViewController` allows to control the video view. Thus, you can play, release the video stream from video view.

* A **remote video track** represents a remote peer video stream from a remote camera app. Specify the initial value to `ConferenceVideoView` - `RTCVideoViewController` for the remote camera app of the remote peer. There can be multiple remote video tracks in the conference call. In this case, you should set up the `ConferenceVideoView` for each remote video track individually.
* A **local video track** represents a local peer video stream from a local camera app. Specify the initial value to `ConferenceVideoView` - `RTCVideoViewController` for the local camera app of the remote peer. There can be only one local video track in the conference call.

```Dart Dart theme={null}
...
ConferenceVideoViewController? _localVideoViewController
ConferenceVideoViewController? _remoteVideoViewController

// Some widgets code
...

child: new Container(
  margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
  width: 160.0,
  height: 160.0,
  child: ConferenceVideoView(
    onVideoViewCreated: onRemoteVideoViewCreated,
),
  decoration: BoxDecoration(color: Colors.black54),
)

child: Container(
  margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
  width: 160.0,
  height: 160.0,
  child: ConferenceVideoView(
    onVideoViewCreated: onLocalVideoViewCreated,
  ),
  decoration: BoxDecoration(color: Colors.black54),
)

...

void onRemoteVideoViewCreated(ConferenceVideoViewController controller) {
  _remoteVideoViewController = controller;
}

void onLocalVideoViewCreated(ConferenceVideoViewController controller) {
  _localVideoViewController = controller;
}

...
```

Subscribe to the `QBConferenceEventTypes.CONFERENCE_VIDEO_TRACK_RECEIVED` event. Thus, once the SDK receives data that a remote video track was received, it creates the event of `CONFERENCE_VIDEO_TRACK_RECEIVED` type with `userId` and `sessionId` properties. See [this section](/sdks/flutter-video-conference#manage-calls) to learn how to subscribe the event.

After this, invoke method `play()` and pass `sessionId` and `userId` parameters to it. If the `userId` matches with the one in properties, the video starts playing.

```Dart Dart theme={null}
...

String sessionId = "114846dfsJKJDdls8dsfj2029";
int opponentId = 2182763;

Future<void> startRenderingRemote() async {
  try {
    await remoteVideoViewController.play(sessionId, opponentId);
  } on PlatformException catch (e) {
    // Some error occurred, look at the exception message for more details
  }
}

String sessionId = "114846dfsJKJDdls8dsfj2029";
int opponentId = 2182763;

Future<void> startRenderingLocal() async {
  try {
    await localVideoViewController.play(sessionId, userId);
  } on PlatformException catch (e) {
    // Some error occurred, look at the exception message for more details
  }
}
```

| Argument   | Required | Description                |
| ---------- | -------- | -------------------------- |
| sessionId  | yes      | Conference session ID.     |
| userId     | yes      | The ID of the local peer.  |
| opponentId | yes      | The ID of the remote peer. |

## Mute local audio

You can mute/unmute your own audio by using the `enableAudio()` method.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";
bool enable = true;

try {
  await QB.conference.enableAudio(sessionId, enable: enable);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument   | Required | Description                                                |
| ---------- | -------- | ---------------------------------------------------------- |
| sesssionId | yes      | Conference session ID.                                     |
| enabled    | no       | Boolean parameter. Allows to enable/disable a local audio. |

## Disable local video

You can enable/disable your own video by using the `enableVideo()` method.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";
bool enable = true;

try {
  await QB.conference.enableVideo(sessionId, enable: enable);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description                                                |
| --------- | -------- | ---------------------------------------------------------- |
| sessionId | yes      | Conference session ID.                                     |
| enabled   | no       | Boolean parameter. Allows to enable/disable a local video. |

## Switch video input device

You can switch a video input to the rear or front camera. The SDK automatically finds all cameras and chooses the two cameras with the highest video quality. Call the `switchCamera()` method to switch between the two cameras.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";

try {
  await QB.conference.switchCamera(sessionId);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description            |
| --------- | -------- | ---------------------- |
| sessionId | yes      | Conference session ID. |

## Switch audio output device

You can switch an audio output. Call the `switchAudioOutput()` method and pass the type of the audio device to it.

<Warning>
  You can switch the audio input only after calling the `create()` method.
</Warning>

```Dart Dart theme={null}
// Audio output
// EARSPEAKER = 0
// LOUDSPEAKER = 1
// HEADPHONES = 2
// BLUETOOTH = 3

int output = QBConferenceAudioOutputTypes.LOUDSPEAKER;

try {
  await QB.conference.switchAudioOutput(output);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument | Required | Description                                                                                                                                                                                 |
| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| output   | yes      | Type of the audio device:QBConferenceAudioOutputTypes.EARSPEAKER ,QBConferenceAudioOutputTypes.LOUDSPEAKER ,QBConferenceAudioOutputTypes.HEADPHONES,QBConferenceAudioOutputTypes.BLUETOOTH. |

## Leave video room

To leave the video room, use the `leave()` method. After calling this method, the current session is deleted from SDK and you can't access this session any more.

```Dart Dart theme={null}
String sessionId = "114846dfsJKJDdls8dsfj2029";

try {
  await QB.conference.leave(sessionId);
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

| Argument  | Required | Description            |
| --------- | -------- | ---------------------- |
| sessionId | yes      | Conference session ID. |

## Release resource

If you don't want to receive and process video calls, for example, when a user is logged out or the `ConferenceVideoView` is going to close, you have to release the conference module. Call the `release()` method that allows to unregister the conference module from receiving any video conference events and closes existing signaling channels.

If you want to create another conference session after the `release()` method, you should call the `init()` method first to initialize the conference module. After the module is initialized, you can create another conference session by calling the `create()` method.

```Dart Dart theme={null}
...

ConferenceVideoViewController? _localVideoViewController;
ConferenceVideoViewController? _remoteVideoViewController;

...

try {
  await QB.conference.release();

  // Release video views
  await _localVideoViewController!.release();
  await _remoteVideoViewController!.release();
} on PlatformException catch (e) {
  // Some error occurred, look at the exception message for more details
}
```

<Note>
  The `release()` method should be called when a video track is no more valid. If you don't call this method, you will get a memory leak.
</Note>
