Create Video Conferencing Application with Zoom
Time to read: 10 minutes
Create a Video Conferencing Application With Zoom
Twilio’s Programmable Video API made it very simple to integrate video communication into applications. However this service offering is being discontinued, with End of Life (EOL) expected on December 5, 2024.
It’s not all bad news, however. In this tutorial I will show you how to use an alternative, the Zoom Video SDK, to build a video chat application with Symfony.
The Zoom Video SDK provides a similar process flow to what you were used to with Twilio Video. To start (or join) a session, you first generate a JSON Web Token (JWT) on the backend. After that, you initiate a client using the Video SDK and render the video stream onto a designated HTML element. In addition to that, the Zoom Video SDK allows you to determine video size and position, as you will see later on.
Prerequisites
To follow this tutorial, you will require the following.
- A Zoom Video SDK account
- A basic understanding of and familiarity with PHP and Symfony
- PHP 8.2 or above
- Composer globally installed
- The Symfony CLI
- A JavaScript package manager ( Yarn will be used in this tutorial)
Get Zoom Video SDK credentials
To generate your Zoom Video JWT, sign into your Video SDK account, go to the Zoom App Marketplace , hover over Develop, and click Build Video SDK.
Then, scroll down to the SDK credentials section to see your SDK key and SDK secret.
Copy the values for SDK Key and SDK Secret as they will be used for JWT generation, later in the tutorial.
Create a new Symfony project
Create a new Symfony project and change into the new project directory using the following commands.
Next, add the project dependencies using the following commands.
Docker won’t be used in this tutorial, so press the n key when prompted to create a docker.yaml file.
Here’s what each dependency is for.
Doctrine: This package will be used to handle database-related activity.
Firebase/PHP-JWT: This package will be used for JWT generation.
Maker: This bundle helps with the auto generation of code associated with authentication, controllers, fixtures, and user entities.
Orm-fixtures: This package is used in collaboration with the Maker bundle to auto-generate fixtures.
Security: This bundle provides the required features for authentication in your Symfony application.
Twig and Symfony/twig-pack: These packages allow you to use Twig templating in your application.
Uid: This will be used for generating unique identifiers for your video chat rooms.
Webpack: This will be used to compile CSS and JS assets. It will also be used to pass data from Twig templates to JavaScript modules.
Set the required environment variables
You need a secure way to save your Zoom Video SDK credentials, as well as variables that change depending on the application environment. To do that, create a .env.local file from the .env file, which Symfony generated during creation of the project, by running the command below.
Then, update the relevant values in .env.local as shown below.
Then, comment out the default DATABASE_URL
setting, and uncomment the one below.
For this tutorial, SQLite will be used for the database. The database will be saved to a file named data.db in the var folder. Create this file using the following command.
Create entities
The application you build will have two entities: User
and Room
. First, create the User
entity using the following command.
Respond to the prompted questions as shown below. Press Enter to accept the default option.
Open the newly created file, src/Entity/User.php, and update the code to match the following:
There isn’t a big difference from what was autogenerated. All you did was create a constructor function which takes the user’s email address as a parameter. The appropriate attributes are also included, as this parameter corresponds to a column in the user
table.
Next, create the Room
entity with the following command.
Respond to the prompted questions as shown below. Press Enter to accept the default option or finish the process.
Open the newly created src/Entity/Room.php and update the code to match the following.
In this file, you added a constructor function which takes the name of the room, and the owner of the room. Similar to the constructor of the User
entity, these parameters correspond to columns in the room table hence the appropriate attributes are specified.
When the __construct()
function is called, the public ID for the room is created using the Uid component provided by Symfony.
Since there is no need for the setter functions in this class, they’ve been removed. An additional function named belongsToUser()
is used to determine if the room belongs to the user provided as an argument.
With your entities in place, update the database schema to create tables for the entities using the following command.
Create default users and rooms
To quickly get started, add some fixtures for rooms and users. To do that, open src/DataFixtures/AppFixtures.php and update the code to match the following.
This function adds six users and five rooms to the database. Load the fixtures with the following command.
Confirm that the database is seeded with the rooms and users using the following commands.
Implement user authentication
To join a room, the user must be logged in. This requires some form of authentication. You can take advantage of the default implementation provided by Symfony using the following command.
Respond to the prompted questions as shown below. Press Enter to accept the default option or finish the process.
Symfony writes most of the code for you. The only thing you need to do is specify where the user should be redirected to on successful authentication. To do this, open the newly created src/Security/FormLoginAuthenticator.php and update the onAuthenticationSuccess()
function to match the following.
When the user is successfully authenticated, the application will redirect to list all the rooms available for joining. The controller responsible for handling this action will be created later.
Create the JWT generation service
As mentioned earlier, to start a video session on the backend, you need a JWT created and signed using your Zoom Video SDK credentials. Create that now. In the src folder, create a new folder named Service, and in it create a new file named JWTGenerator.php. Add the following code to the newly created file.
Using the Autowire attribute provided by Symfony, you retrieve the Zoom Video SDK credentials from your .env.local file. You also retrieved the TOKEN_TTL
variable, which determines the validity period of the generated JWT. For this tutorial, the validity period is 3600 seconds (one hour).
Next, the generate()
function takes the room identity, a unique identifier for a user, and a boolean corresponding to whether or not the user is the host. Using these (and the injected constructor parameters) a JWT is created and returned.
Create a controller for room-related activity
So far, you have created the backend functionality for your application. You have a functional database and token generation service. Before creating the frontend, you’ll need some controller functions to tie the frontend and backend together. These functions will be kept in a controller class.
Create a new controller class using the following command.
Open the newly created file, src/Controller/RoomController.php, and update the code to match the following.
The index()
function retrieves all the rooms in the database and passes them to the room/index.html.twig file in the templates folder.
The join()
function takes three parameters:
The currently logged in user (provided via the CurrentUser attribute)
The room to be joined (retrieved via Parameter Conversion)
The
JWTGenerator
service you created earlier
Using these, a new JWT is generated for the user and returned as part of the parameters for the Twig template to render.
Specify the default route
At the moment, the index route redirects to the default Symfony page, which you can see below.
For this application, the default page will show the list of rooms in the application. To do this, open the config/routes.yaml file and update it to match the following.
With this configuration, the index()
function in the src/Controller/RoomController.php file will be called to handle the request.
Restrict room joining to authenticated users
While anybody can see the available rooms, only authenticated users should be able to join a room and start a video session. To do this, open config/packages/security.yaml and update the access_control
section to match the following.
With this, if an unauthenticated user tries to join a room, they will first be redirected to the login page before they can start a video session.
Prepare webpack assets
For this tutorial, Webpack Encore is used to bundle the CSS and JS assets in the application. In this section, we will prepare and compile those assets.
When Webpack Encore was added to the project, a folder named assets was created at the root of the project folder. Update the content of assets/styles/app.css to match the following.
Create a JS module for Zoom functionality
The next asset you will prepare is a JavaScript module which connects the user to the Zoom session and renders the video streams on the appropriate elements. In the assets folder, create a new folder named js for your JavaScript assets. Next, create a new file named zoom.js in the assets/js folder and add the following code to it.
This module handles the connection to a session and the rendering of video streams. The renderParticipant()
function is used to render a single participant video on the canvas. It does this by calling the renderVideo()
function on a Zoom Video stream. This function takes seven parameters namely:
A
<canvas>
element on which the participant video can be rendered. You can use the same element to render multiple participants as will be done in this tutorial.The user identifier of the participant whose video is to be rendered
The width of the video being rendered
The height of the video being rendered
The x-axis coordinate of the video on the canvas
The y-axis coordinate of the video on the canvas
The resolution of the video
For the application, your video will be rendered separately from that of other participants. Hence, when rendering the participants, you will need to exclude the current user from the list. This is done using the filteredParticipants()
function. This function also returns a maximum of six participants as that will be the maximum number of participants to be rendered in this tutorial.
The connect()
function is called when the page is loaded. This function requires three parameters: the session name, a valid JWT, and the user identifier (whom the JWT is associated with). Using these parameters, a Zoom Video client is instantiated and used to start a video stream; one for the logged in user (rendered on a <video>
element with id self-view-video
, and the rest for the other participants in the video session (rendered by a call to the previously mentioned renderParticipants()
function.
Next, you need to register the newly created module as an entrypoint in your webpack config. To do that, open your webpack configuration (webpack.config.js) located at the root folder of the project, and update the code to match the following.
Compile your assets using the following command.
Update the templates
The next step is to update the project’s Twig templates. For this tutorial, Bootstrap will be used for the layouts. Start by updating the Twig configuration to include Bootstrap. Open config/packages/twig.yaml and update the twig
configuration to match the following.
Next, update the base template to include the Bootstrap CDN. Open templates/base.html.twig and update the code to match the following.
Next, update the login form. Open templates/security/login.html.twig and update the content to match the following.
When you created the RoomController, a template was created to render the view for the index()
function. This view will be a simple table to display the list of rooms and their owners. Update the templates/room/index.html.twig file to match the following.
The last step is to prepare the Twig template that will be rendered when a user joins a room. In the templates/room folder, create a new file named join.html.twig and add the following code to it.
In the body
block, you declare a <video>
element which renders the video stream for the logged in user, and a <canvas>
element for the other participants. These elements are targeted in the zoom.js module and used by the Zoom client in rendering the appropriate video streams.
You also declared a <div>
with class name video-container
. This element has three data attribute tags (data-user-identifier
, data-jwt
, and data-session-name
). This element is used to pass the relevant data from your Twig template to your JavaScript module (courtesy of Webpack Encore).
In the javascripts
block, the Zoom Video SDK is loaded via CDN, while your zoom.js module is also loaded via the encore_entry_script_tags()
Twig directive.
With these in place, your application is ready for a test run. Start your application using the following command.
By default, your application will listen on localhost on port 8000. So, opening http://localhost:8000 will show you a list of rooms you can join, as shown below:
Select one of the rooms and login to start a video session. With one or more users connected to the same room, you should see an output similar to the recording below.
That's how to create a video conferencing application with Zoom's Video SDK
There you have it. You’ve successfully integrated Zoom Video into your Symfony application.
If you have used the Twilio Programmable Video offering, you will see that the overall concept is the same. You generate a JWT on the backend and use it to render a video on the frontend. The only difference (perhaps) is with regards to video rendering.
To render the self view, Twilio appends a video element inside the specified div. Zoom requires more logic to start and render video because Zoom optimises video performance for each device and browser. This is why you had to write more code with regards to handling state changes on the session.
You can review the final codebase for this article on GitHub, should you get stuck at any point. I’m excited to see what else you come up with. Until next time, make peace not war ✌🏾
Joseph Udonsak is a software engineer with a passion for solving challenges – be it building applications, or conquering new frontiers on Candy Crush. When he’s not staring at his screens, he enjoys a cold beer and laughs with his family and friends. Find him at LinkedIn, Medium, and Dev.to.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.