Manage participants

Overview

Note: This tutorial comes after Integrate video. It is highly recommended to follow this previous tutorial before going through this one.

You have a basic Video Conference application with which you can video call your friends on a conference room. But you have no controls or information about the participants.

This tutorial will take you through some simple steps to follow to have a full participants list with the possibility to mute/unmute the differents participants.

Note: If you want to skip this tutorial, at the end of it you can get full access to the source code.

Step 1 : Create the participants list

Note: Participants list will only be visible when the user has joined the conference.

Open your index.html file and add participants <div> and participants-list <ul> elements in join-panel, right after the actions div :

    <div id="actions">...</div>
    <!-- Add participants div just after actions div -->
    <div id="participants">
        <h2>Participants</h2>
        <ul id="participants-list"></ul>
    </div>
    <div id="footer">...</div>

We will also create an object named participants that will be useful to store participants information.

Open the client.js file and initialize the participants object

let participants = {};

Let's implement participants list in ViewController.swift.

Layout modification

class ViewController: UIViewController {
    ...

    // Participant label.
    var participantsLabel: UILabel!
    
    ...
}

Interface linking

...

func initConferenceUI() {
    ...

    // Participants label.
    participantsLabel = UILabel(frame: CGRect(x: 100, y: videosView1.frame.origin.y + videosView1.frame.height + 16, width: 200, height: 30))
    participantsLabel.backgroundColor = .lightGray
    participantsLabel.adjustsFontSizeToFitWidth = true
    participantsLabel.minimumScaleFactor = 0.1
    self.view.addSubview(participantsLabel)
}

...

@objc func leaveButtonAction(sender: UIButton!) {
    VoxeetSDK.shared.conference.leave { error in
    
        ...
        self.participantsLabel.text = nil /* Reset participants label */
        
    }
}

...

Layout modification

Edit the main_activity.xml with the following items :

<LinearLayout ...>
    ...

    <!-- Step 6. Please put below the layout modification with the view participants step -->

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="users :" />

    <EditText
        android:id="@+id/participants"
        android:enabled="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Interface linking

Fields for MainActivity

@Bind(R.id.participants)
EditText participants;

Methods for MainActivity

public void updateUsers() {
    List<User> participants = VoxeetSdk.conference().getUsers();
    List<String> names = new ArrayList<>();


    for (User participant : participants) {
        names.add(participant.getUserInfo().getName());
    }

    participants.setText(TextUtils.join(",", names));
}

Step 2 : Update the participants list

Note: The participants list will be updated upon receiving the participantJoined and participantLeft events, the same way the participants' stream were added in the previous tutorial.

Add a participant to the list

First we'll need to catch the participantAdded event, that is triggered once a user is added to the conference, and update our participants objects with the specific user info.

Open the client.js file and catch the participantAdded event with the on method :

const main = () => {
    /* Events handlers */
    ...
     voxeet.on('participantAdded', (userId, userInfo) => {
        participants[userId] = userInfo;
    });
};

Open the ui.js file and create a function named addParticipantNode :

const addParticipantNode = (userId) => {
    const participantsList = document.getElementById('participants-list');
    let participantNode = document.getElementById('participant-' + userId);

    // if the participant is the current session user, don't add himself to the list
    if (userId === voxeet.userId) return;

    let participant = participants[userId];
    participantNode = document.createElement('li');
    participantNode.setAttribute('id', 'participant-' + userId);
    participantNode.innerText = `${participant.name}`;

    participantsList.appendChild(participantNode);
};

This function adds a participant child node to the participants-list element.

Then open the client.js file and update the participantJoined handler by calling the addParticipantNode :

const main = () => {
    /* Events handlers */
     voxeet.on('participantJoined', (userId, stream) => {
        ...
        addParticipantNode(userId);
    });
};

...

extension ViewController: VTConferenceDelegate {
    ...

    func participantUpdated(userID: String, stream: MediaStream) {
        ...
        
        // Update participants label.
        updateParticipantsLabel()
    }
    
    func updateParticipantsLabel() {
        // Update participants label.
        var users = VoxeetSDK.shared.conference.users.filter({ $0.hasStream }) /* Gets only users with stream */
        if let sessionUser = VoxeetSDK.shared.session.user {
            users.append(sessionUser)
        }
        let usernames = users.map({ $0.name ?? "" })
        participantsLabel.text = usernames.joined(separator: ", ")
    }
}

Logic implementation

Implementation for the related event

This step will register our ui update call to the participant added related event :

  • UserAddedEvent
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(UserAddedEvent event) {
    updateUsers();
}

Remove a participant from the list

Open the client.js file and edit the participantLeft handler to delete the participant's info from the participants object.

voxeet.on('participantLeft', (userId) => {
        ...
        delete participants[userId];
    });

Open the ui.js file and create a function named removeParticipantNode :

const removeParticipantNode = (userId) => {
    var participantNode = document.getElementById('participant-' + userId);

    if (participantNode) {
        participantNode.parentNode.removeChild(participantNode);
    }
};

This function removes a child nodes of participants-list based on the participant ID.

Then open the client.js file and update the streamRemoved handler by calling the removeParticipantNode :

const main = () => {
    /* Events handlers */
    ...
    voxeet.on('participantLeft', (userId) => {
        ...
        removeParticipantNode(userId);
    });
};

...

extension ViewController: VTConferenceDelegate {
    ...
    
    func participantLeft(userID: String) {
        updateParticipantsLabel()
    }
}

Logic implementation

Implementation for the related event

This step will register our ui update call to the updated participant related event :

  • UserUpdatedEvent
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(UserUpdatedEvent event) {
    updateUsers();
}

The list is ready to work. Let's now add actions to it.