DocumentationAbout MeContact

Discovering Jitsi Meet IFrame

By Olivier Anguenot
Published in api
December 08, 2022
8 min read

Table Of Contents

1
The needs expressed
2
The candidates for the conferencing solution
3
Why Jitsi Meet?
4
Using Jitsi Meet
5
Communicating both sides with the IFrame
6
Health and usage stats
7
The pro and const
8
Conclusion
Discovering Jitsi Meet IFrame

In this first article dedicated to CPaaS solutions, I wanted to focus on Jitsi Meet.

Why ? On one hand because it is the solution I chose for a project that requires a conference server and on the other hand because it was the opportunity for me to finally discover this product and more precisely its CPaaS side. I never had the opportunity to use it as a user nor as a developer.

Note: webRTCH4cKS already shared an excellent article on Jitsi called The ultimate guide to Jitsi Meet and JaaS that describes completely the solution. The Jitsi Architecture scheme really helped me to understand the CPaaS possibilities.

This article focuses on the reasons why I used Jitsi and then my development experiences.

The needs expressed

Several needs were expressed for this project:

  • Data protection: This is due to the specific context of the project. Without going into details, a self-hosted solution was preferred over using an existing global cloud solution as a service. And while sovereign CPaaS platforms exist in Europe that meet these requirements, they are too expensive for a startup. So only hosting will have to be considered here.

  • Time to market: The solution must be available ‘now’ without having to spend weeks or months on the development part.

  • Convenient conferencing solution: No need to be lost by the features: Just the essentials: Video + chat + screen-sharing.

Scalability? There will not be many meetings with a high number of persons and at the beginning there will be few parallel meetings. Simple monitoring will be used to check health, usage and system resources used.

The low cost was part of the needs (as usual…).

But there is no specific need for call quality, specific devices or environments. Just a way to connect people.

The candidates for the conferencing solution

When I looked at the possible solution, I came up with 3 (open-source) possibilities:

  • Janus: A SFU conference server that comes with a JS library. I’ve already developed with Janus before but my experience was limited to using it as a WebRTC gateway between web users and Freeswitch conferences.

  • BigBlueButton : A complete conferencing and collaboration solution: My experience was limited to connecting the collaboration part (desktop sharing) to enhance an existing SIP web client.

  • Jitsi Meet: The open-source conferencing server from 8x8. I had never experienced or used it. Here, it is interesting because it is Java and the dev guy has developed the backend in Java. I thought that for him, having another Java component should be less scary…

Jitsi comes with the possibility to use it as a service or to host it in your infrastructure. Then, for the frontend, Jitsi can be used from an IFrame (no user interface to develop) or from a low-level JavaScrip library (design you own conference experience).

And that’s it for the candidates (sorry for the others…).

Why Jitsi Meet?

Actually, the choice was easy because I had to choose between 2 different kinds of solutions:

  • All-in-one solution: Jitsi Meet (IFrame) and BBB come with a client side part that already proposes all the features needed. With these kind of solutions, efforts are more or less equivalent to DevOps tasks only. The minimal part to do is to integrate and customize the client side.

  • Server solution only: Janus is different. This is a pure server side component. A client side JavaScript library is used to dialog with the server but, there is no GUI part. Everything has to be developed, existing samples could help.

Depending on your goals, each can be used for sure. In my case, I have preferred to use an all-in-one solution to bring the conference features in a first step without having to spend time developing the UI part and then if necessary in a second step, to use the SDK to rebuild the frontend experience.

I didn’t choose BigBlueButton. Even if it is an equivalent solution to Jitsi, I felt that BBB is more complex to support because it is composed of different open-source servers such as Kurento and Freeswitch put together. I was more worried about supporting them.

But I didn’t spend too much time on BigBlueButton… Perhaps for a next project!

So, my choice was to use Jitsi Meet and to integrate the IFrame into the existing Web application. For the mobile part, I will rely on the existing Jitsi Meet IOS and Android applications available on the store and connect them to the hosted instance.

Image: Jitsi
Image: Jitsi

Using Jitsi Meet

To assess my choice, I installed Jitsi locally and tried to adapt it to my need: Using a simple HTML web page to load the Jitsi IFrame that connects to the hosted instance and then to try to see what can be done next.

Installation

The first step was to understand how to install my own Jitsi Meet instance. Having a Mac will not help this time as a Linux distribution is required.

I decided to use Parallels Desktop and to install the Ubuntu 22.04 Linux distribution.

Once done, I followed the guide Self-Hosting Guide - Debian/Ubuntu server provided by Jitsi.

And less than an hour, the Jitsi Meet instance was available in my local domain meet.localdomain.com

To test it, I used a browser and opened the url https://meet.localdomain.com. By default, Jitsi provides a self-signed certificate but all is already set to use your own certificate or to rely on Let’s Encrypt to generate and renew one.

In my case, the self-signed certificate was enough.

Note: I tested with Jitsi version 2.0.7648

Configuration

When I first launched Jitsi Meet, I noticed some labels, features and popup I don’t want to have in my application: I just need to have the video of the participants and allow them to share content if needed.

Jitsi Meet was too rich and distracting for my case :-)

Now is the time to look at the configuration files because as described in the documentation, the GUI part can be customized.

At that time of writing, Jitsi Meet uses two main configuration files:

  • /etc/jitsi/meet/<your-domain>-config.js

  • /var/share/jitsi-meet/interface_config.js

Making changes in these files allows to

1) Enable, disable or change the behavior of features,

2) Customize the text, icons and the positioning & sizing of some elements,

3) Change some technical (advanced) parameters linked to WebRTC.

Don’t be surprised, there is really a huge set of parameters. The documentation helps to understand their functions, but I was a bit lost: the parameters are like spaghetti in these files: everything is mixed up, or I did not understand the logical order :-)

Here are the links for these default files in GitHub:

Note: interface_config.js is noted as deprecated so only one file should stay at the end (?).

Customization

When using the IFrame, some parameters can be customized directly from the JavaScript application (overridden). This is good if you know which ones can be overridden and which ones cannot.

In my case, it won’t be enough because the UX should be homogenous between mobile users and web users. So I preferred to change the parameters on the hosted platform directly to keep a unified solution.

Here are the parameters I used to customize the application

Overriding configuration parameters

I modified the following parameters (from the config)

ParametersValueDetails
enableWelcomePagefalseDon’t display the welcome page.
Enter directly a given conference
prejoin.enabledfalseDon’t display the prejoin page.
Enter directly a given conference
gravatar.disabledtrueDon’t use the Gravatar integration
p2p.enabledtrueAlways start by a P2P call to avoid consuming resources on the server
stunServers[urls]Used when in P2P in case direct call is not possible
disableDeepLinkingtrueAvoid blocking tablet/phone when using a browser to enter the conference
disableInviteFunctionstrueDisable all invite functions (invite, dial out)
hideParticipantsStatstrueDon’t display the participants stats
logging.defaultLogLevelwarnAvoid to much logs from the Iframe
toolbarButtons[..]Removed embedmeeting, etherpad, invite, linktosalesforce, livestreaming, profile, recording, security, stats, shortcuts
breakoutRooms.hideAddRoomButtontrueNo room inside room
disableShortcutstrueDisable Jitsi shortcuts
disableProfiletrueDisable user profile as managed by the external application
readOnlyNametrueDon’t allow to edit the user name inside Jitsi as name is fixed
analytics.disabledtrueDon’t use external analytics

Note: For testing purpose, I let the mobile devices to connect using the Web application instead of forcing them to use the native application (eg: disableDeepLinking=false).

Note: Some parameters can be redundant but this is not straightforward to test each individually.

Overriding interface parameters

Regarding on the interface configuration file, I modified the following parameters

ParametersValueDetails
APP_NAME**Update the application name (labels)
BRAND_WATERMARK_LINKNo link
DEFAULT_LOGO_URLNo logo displayed
DEFAULT_WELCOME_PAGE_LOGO_URLNo welcome page so no logo
JITSI_WATERMARK_LINKNo link to the existing platform
PROVIDER_NAME**Same name as for the application
SHOW_BRAND_WATERMARKfalseDon’t display the brand
SHOW_CHROME_EXTENSION_BANNERfalseDon’t display the extension banner
SHOW_DEEP_LINKING_IMAGEfalseDon’t display image for native
SHOW_JITSI_WATERMARKfalseDon’t display Jitsi logo
HIDE_DEEP_LINKING_LOGOtrueDon’t display Jitsi logo (native)
SHOW_POWERED_BYfalseDon’t display the Jitsi link
VERTICAL_FILMSTRIPfalseI wanted to have horizontal thumbnails and not of vertical
ENABLE_DIAL_OUTfalseDon’t show the contacts
HIDE_INVITE_MORE_HEADERtrueDon’t show the invite when alone

Note: be careful to not be puzzled with ‘enabled’, ‘disabled’ and ‘hide’ :-)

Result

The result is a clean interface with the minimum of features.

Image: Jitsi IFrame
Image: Jitsi IFrame

I didn’t change any advanced WebRTC parameters. For my basic requirements, I hope there is no need to change them. I don’t know if performance could be better by changing some of them…

IFrame setup

Now that the functionality is ok, I can integrate Jitsi inside the existing web application.

As mentioned, Jitsi provides an IFrame to embed the user interface directly without having to develop the GUI.

You need to do the following

  • Load the appropriate Jitsi JavaScript library from your hosted environment.

  • Create an HTML node element to contain the IFrame.

  • Instantiate the JitsiMeetExternalAPI interface.

Here, I was limited to get the JitsiMeetExternalAPI from the window global object. It is not really nice, but I couldn’t find a way to properly integrate the Jitsi library within the existing Angular application (for example using an import).

If you don’t bundle the library within the existing code base, you will have to target the right hosted server depending on the environment you’re using: Staging and production can be two different domains.

For testing purposes, I injected the correct script tag based on the platform by inserting the script at runtime.

To summarize, you should have something similar to the following

// Loading the library depending on the environment
const scriptEl = window.document.createElement('script');
const domain = 'staging.myDomain.com';  // Got from an env variable
scriptEl.src = `https://${domain}/external_api.js`;
window.document.body.appendChild(scriptEl);

// Jitsi IFrame container somewhere in your HTML stuff
<div id="jitsi-container" class="jitsi-container"></div>

// Function to connect to the conference (create the IFrame)
const connect = () => {
  const options = {
    roomName: `a_room_name`,
    parentNode: document.querySelector('#jitsi-container'),
    lang: 'fr',
    configOverwrite: {...}, // overridden config parameters,
    interfaceConfigOverwrite: {...}, // overridden interface parameters,
    userInfo: {
      displayName: 'bob'
    },
  };

  const api = new window["JitsiMeetExternalAPI"]('staging.myDomain.com', options);
}

Once done, the conference will appear within you defined tag.

Communicating both sides with the IFrame

Displaying the conference in a “black box” may not be enough

In my case, I needed a way to:

  • Detach the IFrame in a separate popup. The user needs continue to navigate inside the application (desktop web)

  • Indicate to others that the user is busy when connected to the conference

  • Stop the conference from the application

  • Capture errors for logging purpose

For doing that, Jitsi offers events to listen and commands to execute.

Dock/Undock the IFrame

Inside the IFrame, the two buttons can be displayed in the toolbars:

  • undock-iframe

  • dock-iframe

Clicking on these buttons does nothing except trigger the iframeDockStateChanged event.

In my case, when in the main window, I chose to display only the undock-iframe and when in the external window to display the other option.

Here is the implementation I made to handle the dock/undock function.

// Code for undocking / docking the Iframe
api.addListener("iframeDockStateChanged", () => {
  let endedFromExternalWindow = false;  // Detect when conference is ended from the external Window
  let state = "disconnected";

  // Create the external window
  const externalWindow = window.open(`about:config?width=${640}&height=${480}&?ontop`, 'newWindow', `height=600, width=800, popup=yes, scrollbars=auto, resizable=no, location=no, status=no`);
  externalWindow.document.open();
  externalWindow.document.write("<!DOCTYPE html><html style='overflow:hidden;height: 100%; width: 100%;margin: 0'><head></head><body id='container' style='height: 100%; width: 100%;margin: 0'><div id='jitsi-container' style='height: 100%; width: 100%;margin: 0'></div></body></html>");
  const scriptEl = externalWindow.document.createElement('script');
  scriptEl.src = `https://${domain}/external_api.js`;
  externalWindow.document.body.appendChild(scriptEl);
  externalWindow.document.close();
  externalWindow.document.title = "My Application";

  // Listen to the window load event (external window)
  externalWindow.onload = () => {
    // External window loaded, load the conference (options could be different from the main window)
    const externalApi = new externalWindow["JitsiMeetExternalAPI"]('staging.myDomain.com', options);

    externalApi.addListener("videoConferenceJoined", () => {
      state = "connected_external";
    });

    // Listen when the dock option is clicked from the external window
    externalApi.addListener("iframeDockStateChanged", () => {
      externalWindow.close();
    });

    // Listen when the conference is ended from the external window
    externalApi.addListener("readyToClose", () => {
      // close the external window when the conference is ended
      endedFromExternalWindow = true;   // Avoid to reload the conference from the main window
      externalWindow.close();
    });

    // Dispose the conference in the main window when in the external one
    api.dispose();
  };

  // Listen to the window unload event (external window)
  externalWindow.onbeforeunload = () => {
    // When the external window is closed, connect again the application to the conference
    if(!endedFromExternalWindow) {
      connect();
      return;
    }
    endedFromExternalWindow = false;
  }
});

The counterpart of this approach is that the user is briefly disconnected from the conference and then reconnected each time he undocks or docks his conference.

Listening to connected/disconnected events

There are 3 events to listen to know the connection status of the user: videoConferenceJoined, videoConferenceLeft and readyToClose

Here is the code to subscribe and react when the user is connected.

let state = "disconnected";

api.addListener("videoConferenceJoined", () => {
  state = "connected";
});

api.addListener("videoConferenceLeft", () => {
  state = "disconnected";
});

api.addListener("readyToClose", () => {
  // You can remove the IFrame
  api.dispose();
});

Leaving the conference

From the existing application, you can add a button to leave the conference directly or rely on the IFrame toolbar button.

To send a command to the IFrame, you need to use the function executeCommand.

// Call the JS API from the external window if connected externally
if(state === "connected_external") {
  externalApi.executeCommand('endConference');
} else {
  api.executeCommand('endConference');
}

Capture errors

To capture errors, the following event could be subscribed

  • cameraError: To detect problem when accessing the camera
  • micError: To detect problem when accessing the microphone
  • browserSupport: To detect is the browser is supported
  • errorOccurred: Any occurred errors

This can be a way to react and display a popup message into the main application.

Note: The complete list of events can be found here: Jitsi IFrame Events

Health and usage stats

Jitsi offers a private REST API that can be used to have the minimal health-check metrics and usage data.

For that, you need to edit some configuration files.

Configuring the REST API

As for other points, it is complicated to really know what is mandatory to do, what is obsolete. I did the following, and it worked for me…

JVC Configuration file

I edited the JVC configuration file located here /etc/jitsi/videobridge/jvb.conf. Here is the complete file content

videobridge {
    http-servers {
        public {
            port = 9090
        }
    }
    websockets {
        enabled = true
        domain = "xxx.xxx.xxx:443"
        tls = true
    }
    apis {
        rest {
           enabled = true
        }
        jvb-api {
           enabled = true
        }
    }
    stats {
        enabled = true
    }
}

SIP communicator properties file

Then, I edited and modified the SIP Communicator properties file located here /etc/jitsi/videobridge/sip-communicator.properties and added these lines

org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.ENABLE_REST_COLIBRI=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc,colibri,rest
org.jitsi.videobridge.STATISTICS_INTERVAL=2000

VideoBridge System properties

Finally, I updated the file /etc/jitsi/videobridge/config to pass an extra property to jvb

JVB_OPTS="--apis=rest,xmpp"

With these changes, I can have access to the following APIs.

Health-check

The endpoint /about/health has to be used to have a status.

curl http://localhost:8080/about/health

HTTP 200OK is received if everything works great.

Basic stats

The endpoint colibri/stats can be used to have the conferences stats

curl http://localhost:8080/colibri/stats | jq .

Associated to that, there is the following end-point, but I didn’t succeed to make it works.

curl http://localhost:8080/colibri/conferences | jq .

Other stats

Surprisingly, I find this API available that gives additional information on conferences. Don’t know from which part it comes.

curl http://localhost:8888/stats

Using these API, I was able to make regular health-check of my Jitsi instance as well as to grab some usage statistics.

The pro and const

And here I am. I sent this integration prototype to the person in charge to see how far I’m from his initial request.

But for the time spent, the result is very good. Except the disconnect/reconnect effect when using the external window, I didn’t find any problems when testing with multiple devices.

Note: With my configuration, Jitsi manages the conference when there are 3 participants. The conference is not managed by the server when I’m alone or in P2P.

Here are some other development feedbacks

Pro

  • IFrame integration: It works like a charm
  • Open-source: Having access to the source code helped me to overcome the documentation.
  • Development: Using the IFrame doesn’t require high WebRTC coding skills.
  • Monitoring: Everything is there and easy to collect

Const

  • Documentation and the community forums needs to be read carefully. The good point is that you will find answers to your questions 99% or the time. The bad points is that the answers not always about the current version. Don’t be surprised!
  • Configuration files: There are many, don’t be lost!
  • Translation: I find French labels missing. If it is not my mistake, I will try to correct them :-)

Conclusion

To conclude, I really enjoyed this journey using Jitsi Meet IFrame. Super easy to set up the server even for me who is not a devops guy. IFrame integration not more complicated to do. And the result was as expected: simple and efficient!


Tags

#jitsi
Previous Article
Using the RTP Media APIs
Next Article
Do you hear me?
Olivier Anguenot

Olivier Anguenot

Your WebRTC copilot

Topics

api
dev
others

Related Posts

WebRTC API Landscape in 2023
January 12, 2023
4 min
© 2023, All Rights Reserved.

Quick Links

Work with meAbout MeContact Us

Social Media