Adding Video Chat To Your Laravel App

Call banner

INTRODUCTION

I was required to build a custom video chat application for a Vuejs and Laravel project. I went through a lot of hoops to get it working. I will share all that I learnt throughout the process over here.

Final Project Repository: https://github.com/Mupati/laravel-video-chat

REQUIREMENTS

  1. This tutorial assumes you know how to set up a new Laravel project with VueJs authentication. Create some users after setting up your project. You should be familiar with Laravel's broadcasting mechanism and have a fair idea of how WebSockets work.
  2. Set up a free pusher account on pusher.com
  3. Set up your ICE SERVER (TURN SERVER) details. This tutorial is a good guide. HOW TO INSTALL COTURN.

PROJECT SETUP

CONFIGURING BACKEND

  1. Add routes for video page in routes/web.php. The routes will be used to visit the video call page, make calls and receive calls.

2. Uncomment BroadcastServiceProvider in config/app.php. This allows us to use Laravel's broadcasting system.

3. Create a Presence Channel for the Video Chat Application in routes/channels.php. When an authenticated user subscribes to the channel (presence-video-channel), we return the user's id and name. This is how we are able to get the user who is logged in and can be called.

4. Create StartVideoChat event. This event will be called when placing a call or accepting a call and it will broadcast on the presence-video-call channel. Users subscribed to the channel will be listening to this event on the frontend so that incoming call notifications can be triggered.

5. Add the following code to app/Events/StartVideoChat.php. The StartVideoChat event broadcasts to presence-video-channel so that the data needed to initiate the video call is shared on the channel.

6. Create VideoChatController to make and accept calls and add the code that follows.

Explanation of Methods in the VideoChatController
One thing to understand is that the VideoChat Application is a realtime application that works with web sockets. The endpoints are just needed to establish the link between the 2 calling parties after which the communication data is exchanged via WebSockets.
Let’s try to understand what the 2 methods in the Controller are doing:

callUser Method
* user_to_call: id of the user, the initiator of the call wants to reach.
* signal_data: The initial signal data (offer) sent by the caller from the webrtc client (simple-peerjs is the webrtc wrapper we are using). These are the parameters received. We create a data object with 2 additional properties,from and type then broadcast the data with the StartVideoChat event which will be listened to on the frontend.
* from: is the id of the user placing the call. We use the authenticated user's id.
* type: is a property of the data which will indicate that there is an incoming call on the channel. The notification will be shown to the user whose id corresponds to the value of user_to_call.

acceptCall Method
* signal: This is the callee's answer data.
* to: The caller's of the call's id. The signal data for the answered call is sent to the user whose id matches to and this is supposed to be the caller's id. *type: A property added to the data to be sent over the channel indicating that the call recipient has accepted the call.

CONFIGURING FRONTED

  1. Instantiate Laravel Echo and Pusher in resources/js/bootstrap.js by uncommenting the following block of code.

2. Create resources/js/helpers.js. Add a getPermissions function to help with permission access for microphone and videos. This method handles the video and audio permission that is required by browsers to make the video calls. It waits for the user to accept the permissions before we can proceed with the video call. We allow both audio and video. Read more on MDN Website.

3. Create a Video Chat Component, resources/js/components/VideoChat.vue.

Breakdown of the video-chat component.

  1. We import Peer from simple-peer which is the package that makes interacting with webrtc easier for us.
  • The component accepts the following props:
    allusers: All registered users excluding the currently authenticated user. These users will be displayed. We don't want to permit the authenticated user to call oneself.
  • authuserid: The id of the authenticated user.
  • turn_url: The URL of your turn server to be used in an instance of simple-peer i.e Peer.
  • turn_username: Username from TURN Server.
  • turn_credential: The password for the turn_username.

2. When the component is mounted we subscribe to the presence-video-channel with the initializeChannel method. We use Laravel-echo for that.

3. We initializeCallListeners on the channel, we subscribed to. There are methods provided by Laravel-echo to know how many users have subscribed to the channel, users who are joining and users leaving the channel. We also listen to the StartVideoChat event on the presence-video-channel for incoming calls.

4. We list all the users in the database from the allUsers prop and indicate whether they are online or not. Online means they have also subscribed to the presence-video-channel. This will take effect on whichever page you place the video-chat component. In this tutorial, we have a video-chat page where we place the component.

5. placeVideoCall is used to make a call. We pass the id and name of the user being called as parameters.
We ask the user to grant the browser access to the microphone and camera with getMediaPermission method. The streaming data is displayed in the browser. The caller now sees their face in the browser.
We create a Peer for the caller. When there is a signalling event, peer.on('signal',..) we send the signalling data to the /video/call-user endpoint on our backend.
The recipient receives the incoming call notification and when they accept the call, we signal the caller with an answer signal.
The peer.on('stream',...)listener receives the streaming data which is displayed on the recipients part in the browser.

6. acceptCall method is used to accept an incoming call. When a user sees an incoming call notification, they click on the accept button. We signal the receiver with the signal data received from the caller.
We get permission to access the camera and microphone and display the streaming data on our UI.
This creates a second instance of the Peer with the initiator property set to false to indicate that the new Peer is a receiver.
We hit the accept-call endpoint and send our signalling data (an answer) to the caller.

When the streaming starts, we display the caller’s stream in the browser as well and now communication continues without hitting our backend but through the WebSocket powered by pusher.

  • The remaining functions are used for muting audio, disable video stream and to end the call.

7. Register the VideoChat.vue component in resources/js/app.js

8. Create the video chat view in resources/views/video-chat.blade.php

9. Update env variables. Insert your Pusher API keys and TURN SERVER details.

CREDITS

I found a lot of resources beneficial which I cannot share all over here, but the following YouTube videos helped in my understanding and arriving at this implementation.

  1. Coding With Chaim
  2. We Code

I’d like to hear your thoughts about how easy it is to follow through this article.

Building Products and Services, and Sharing Knowledge.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store