Home » Agora Web SDK with Laravel – The Ultimate Integration Guide

Agora Web SDK with Laravel – The Ultimate Integration Guide

Loved it? Please Share on Social Media

Introduction:

Hello, fellow developers. What’s up?, I hope you are doing fine. In this extended tutorial, we will learn how to use agora web sdk with laravel. We will discuss the walkthrough of the agora web sdk installation so you can follow it easily.

What is Agora?

Agora is a real-time technology provider. They work with real-time engagement, offering developers easy, flexible, and powerful APIs for integrating real-time audio, video, interactive streaming, chat, and artificial intelligence capabilities into their apps.

Fresh Laravel Installation for Agora Web SDK:

First thing first, we need to download a fresh copy of the laravel application. Please follow the below command to download the laravel application from GitHub.

composer create-project laravel/laravel agora-laravel-app

Install Laravel UI for Frontend Scafolding:

Now, we also need Laravel UI for our front-end scaffolding. In this case, our frontend preset will be vue. First, go to your project root directory and open a new terminal, and copy & paste the following command to download Laravel UI into our machine.

composer require laravel/ui

after the Laravel UI installation, you need to install the vue front-end scaffolding using the below command.

php artisan ui vue --auth

after the above command, you have to use more two commands to install javascript dependencies. Please copy & paste the following command and press enter from your keyboard.

npm install 

npm run dev

Our front-end scaffolding setup is complete. Now take a look at our next task.

Pusher Account Setup:

First, You have to create a free pusher account. Then we have to install two packages into our laravel project. Please copy & paste the following commands and execute them one by one into your terminal.

composer require pusher/pusher-php-server

npm install --save laravel-echo pusher-js

Configuring Our Web.php File:

At this stage, you have to configure your web.php file. Copy & paste the following code into your file and save it.

Route::group(['middleware' => ['auth']], function () {
    Route::get('/agora-chat', ['App\Http\Controllers\AgoraVideoController', 'index']);
    Route::post('/agora/token', ['App\Http\Controllers\AgoraVideoController','token');
    Route::post('/agora/call-user', ['App\Http\Controllers\AgoraVideoController','callUser');
});

Enabling Laravel Broadcasting Feature:

Now, we need to enable the laravel broadcast feature by just simply uncommenting a line from config>app.php

App\Providers\BroadcastServiceProvider::class, //uncomment this line of code.

Creating a Channel for Our Video Calling Feature:

Next, we need to create a broadcast channel for our video calling system. Just simply copy& paste the below line of code inside of routes>channels.php file.

Broadcast::channel('agora-online-channel', function ($user) {
    return ['id' => $user->id, 'name' => $user->name];
});

Creating an Event for Making Video Calls:

Now, we will create an event for our video call. For that, you have to use the below command in your terminal and create an event file.

php artisan make:event MakeAgoraCall

Now, copy & and paste the following code into your app>events>MakeAgoraCall.php file.

<?php

namespace App\Events;

use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MakeAgoraCall implements ShouldBroadcast

{
use Dispatchable, InteractsWithSockets, SerializesModels;

public $data;

/**
* Create a new event instance.
*
* @return void
*/

public function __construct($data)

{
     $this->data = $data;
}

/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/

public function broadcastOn()

{
     return new PresenceChannel('agora-online-channel');
}
}

Creating Custom Service for AgoraDynamicKey:

First of all, you have to download AccessToken.php RtcTokenBuilder.php files from this GitHub repository into your location machine.

Now, create an AgoraDynamicKey folder inside the app folder of your application. Now copy those downloaded files which are AccessToken.php RtcTokenBuilder.php files into the AgoraDynamicKey folder. Next add the below line of code into those downloaded files so that we can access those files into our controller.

namespace App\AgoraDynamicKey;

Creating Controller Video Calling Feature:

Now, We will create our controller for our video calling feature. Please copy & paste the below command into your terminal and hit enter from your keyboard.

php artisan make:controller AgoraVideoController

After that, copy & paste the below code into your created controller.

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Classes\AgoraDynamicKey\RtcTokenBuilder;
use App\Events\MakeAgoraCall;

class AgoraVideoController extends Controller
{

public function index(Request $request)
{
// fetch all users apart from the authenticated user
$users = User::where('id', '<>', Auth::id())->get();
return view('agora-chat', ['users' => $users]);
}

public function token(Request $request)

{
$appID = env('AGORA_APP_ID');
$appCertificate = env('AGORA_APP_CERTIFICATE');
$channelName = $request->channelName;
$user = Auth::user()->name;
$role = RtcTokenBuilder::RoleAttendee;
$expireTimeInSeconds = 3600;
$currentTimestamp = now()->getTimestamp();
$privilegeExpiredTs = $currentTimestamp + $expireTimeInSeconds;
$token = RtcTokenBuilder::buildTokenWithUserAccount($appID, $appCertificate, $channelName, $user, $role, $privilegeExpiredTs);
return $token;
}

public function callUser(Request $request)
{
    $data['userToCall'] = $request->user_to_call;
    $data['channelName'] = $request->channel_name;
    $data['from'] = Auth::id();
    broadcast(new MakeAgoraCall($data))->toOthers();
}
}

Configuring Our Front-end for Video Calling: 

First of all, copy & paste the below script tag into the head section of your resources>views>layouts>app.blade.php file.

<script src="https://cdn.agora.io/sdk/release/AgoraRTCSDK-3.3.1.js"></script>

Next, you have to uncomment the below codes from your resources>js>bootstrap.js file.

//Uncomment the whole code snippet

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Creating Our Our First Vue Component for AgoraChat:

In this stage, we will create an AgoraChat.vue component in the resources/js/components directory. After that copy & paste the following code snippet in that file.

<template>

<main>

<div class="container">

<div class="row">

<div class="col-12 text-center">

<img src="img/agora-logo.png" alt="Agora Logo" class="img-fluid" />

</div>

</div>

</div>

<div class="container my-5">

<div class="row">

<div class="col">

<div class="btn-group" role="group">

<button

type="button"

class="btn btn-primary mr-2"

v-for="user in allusers"

:key="user.id"

@click="placeCall(user.id, user.name)"

>

Call {{ user.name }}

<span class="badge badge-light">{{

getUserOnlineStatus(user.id)

}}</span>

</button>

</div>

</div>

</div>

<!-- Incoming Call -->

<div class="row my-5" v-if="incomingCall">

<div class="col-12">

<p>

Incoming Call From <strong>{{ incomingCaller }}</strong>

</p>

<div class="btn-group" role="group">

<button

type="button"

class="btn btn-danger"

data-dismiss="modal"

@click="declineCall"

>

Decline

</button>

<button

type="button"

class="btn btn-success ml-5"

@click="acceptCall"

>

Accept

</button>

</div>

</div>

</div>

<!-- End of Incoming Call -->

</div>

<section id="video-container" v-if="callPlaced">

<div id="local-video"></div>

<div id="remote-video"></div>

<div class="action-btns">

<button type="button" class="btn btn-info" @click="handleAudioToggle">

{{ mutedAudio ? "Unmute" : "Mute" }}

</button>

<button

type="button"

class="btn btn-primary mx-4"

@click="handleVideoToggle"

>

{{ mutedVideo ? "ShowVideo" : "HideVideo" }}

</button>

<button type="button" class="btn btn-danger" @click="endCall">

EndCall

</button>

</div>

</section>

</main>

</template>

<script>

export default {

name: "AgoraChat",

props: ["authuser", "authuserid", "allusers", "agora_id"],

data() {

return {

callPlaced: false,

client: null,

localStream: null,

mutedAudio: false,

mutedVideo: false,

userOnlineChannel: null,

onlineUsers: [],

incomingCall: false,

incomingCaller: "",

agoraChannel: null,

};

},

mounted() {

this.initUserOnlineChannel();

this.initUserOnlineListeners();

},

methods: {

/**

* Presence Broadcast Channel Listeners and Methods

* Provided by Laravel.

* Websockets with Pusher

*/

initUserOnlineChannel() {

this.userOnlineChannel = window.Echo.join("agora-online-channel");

},

initUserOnlineListeners() {

this.userOnlineChannel.here((users) => {

this.onlineUsers = users;

});

this.userOnlineChannel.joining((user) => {

// check user availability

const joiningUserIndex = this.onlineUsers.findIndex(

(data) => data.id === user.id

);

if (joiningUserIndex < 0) {

this.onlineUsers.push(user);

}

});

this.userOnlineChannel.leaving((user) => {

const leavingUserIndex = this.onlineUsers.findIndex(

(data) => data.id === user.id

);

this.onlineUsers.splice(leavingUserIndex, 1);

});

// listen to the incoming call

this.userOnlineChannel.listen("MakeAgoraCall", ({ data }) => {

if (parseInt(data.userToCall) === parseInt(this.authuserid)) {

const callerIndex = this.onlineUsers.findIndex(

(user) => user.id === data.from

);

this.incomingCaller = this.onlineUsers[callerIndex]["name"];

this.incomingCall = true;

//The channel that was sent over to the user being called is what

// the receiver will use to join the call when accepting the call.

this.agoraChannel = data.channelName;

}

});

},

getUserOnlineStatus(id) {

const onlineUserIndex = this.onlineUsers.findIndex(

(data) => data.id === id

);

if (onlineUserIndex < 0) {

return "Offline";

}

return "Online";

},

async placeCall(id, calleeName) {

try {

// channelName = the caller's and the callee's id. you can use anything. tho.

const channelName = `${this.authuser}_${calleeName}`;

const tokenRes = await this.generateToken(channelName);

// Broadcasts a call event to the callee and also gets back the token

await axios.post("/agora/call-user", {

user_to_call: id,

username: this.authuser,

channel_name: channelName,

});

this.initializeAgora();

this.joinRoom(tokenRes.data, channelName);

} catch (error) {

console.log(error);

}

},

async acceptCall() {

this.initializeAgora();

const tokenRes = await this.generateToken(this.agoraChannel);

this.joinRoom(tokenRes.data, this.agoraChannel);

this.incomingCall = false;

this.callPlaced = true;

},

declineCall() {

// You can send a request to the caller to

// alert them of rejected call

this.incomingCall = false;

},

generateToken(channelName) {

return axios.post("/agora/token", {

channelName,

});

},

/**

* Agora Events and Listeners

*/

initializeAgora() {

this.client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" });

this.client.init(

this.agora_id,

() => {

console.log("AgoraRTC client initialized");

},

(err) => {

console.log("AgoraRTC client init failed", err);

}

);

},

async joinRoom(token, channel) {

this.client.join(

token,

channel,

this.authuser,

(uid) => {

console.log("User " + uid + " join channel successfully");

this.callPlaced = true;

this.createLocalStream();

this.initializedAgoraListeners();

},

(err) => {

console.log("Join channel failed", err);

}

);

},

initializedAgoraListeners() {

// Register event listeners

this.client.on("stream-published", function (evt) {

console.log("Publish local stream successfully");

console.log(evt);

});

//subscribe remote stream

this.client.on("stream-added", ({ stream }) => {

console.log("New stream added: " + stream.getId());

this.client.subscribe(stream, function (err) {

console.log("Subscribe stream failed", err);

});

});

this.client.on("stream-subscribed", (evt) => {

// Attach remote stream to the remote-video div

evt. stream.play("remote-video");

this.client.publish(evt.stream);

});

this.client.on("stream-removed", ({ stream }) => {

console.log(String(stream.getId()));

stream.close();

});

this.client.on("peer-online", (evt) => {

console.log("peer-online", evt.uid);

});

this.client.on("peer-leave", (evt) => {

var uid = evt.uid;

var reason = evt.reason;

console.log("remote user left ", uid, "reason: ", reason);

});

this.client.on("stream-unpublished", (evt) => {

console.log(evt);

});

},

createLocalStream() {

this.localStream = AgoraRTC.createStream({

audio: true,

video: true,

});

// Initialize the local stream

this.localStream.init(

() => {

// Play the local stream

this.localStream.play("local-video");

// Publish the local stream

this.client.publish(this.localStream, (err) => {

console.log("publish local stream", err);

});

},

(err) => {

console.log(err);

}

);

},

endCall() {

this.localStream.close();

this.client.leave(

() => {

console.log("Leave channel successfully");

this.callPlaced = false;

},

(err) => {

console.log("Leave channel failed");

}

);

},

handleAudioToggle() {

if (this.mutedAudio) {

this.localStream.unmuteAudio();

this.mutedAudio = false;

} else {

this.localStream.muteAudio();

this.mutedAudio = true;

}

},

handleVideoToggle() {

if (this.mutedVideo) {

this.localStream.unmuteVideo();

this.mutedVideo = false;

} else {

this.localStream.muteVideo();

this.mutedVideo = true;

}

},

},

};

</script>

<style scoped>

main {

margin-top: 50px;

}

#video-container {

width: 700px;

height: 500px;

max-width: 90vw;

max-height: 50vh;

margin: 0 auto;

border: 1px solid #099dfd;

position: relative;

box-shadow: 1px 1px 11px #9e9e9e;

background-color: #fff;

}

#local-video {

width: 30%;

height: 30%;

position: absolute;

left: 10px;

bottom: 10px;

border: 1px solid #fff;

border-radius: 6px;

z-index: 2;

cursor: pointer;

}

#remote-video {

width: 100%;

height: 100%;

position: absolute;

left: 0;

right: 0;

bottom: 0;

top: 0;

z-index: 1;

margin: 0;

padding: 0;

cursor: pointer;

}

.action-btns {

position: absolute;

bottom: 20px;

left: 50%;

margin-left: -50px;

z-index: 3;

display: flex;

flex-direction: row;

flex-wrap: wrap;

}

#login-form {

margin-top: 100px;

}

</style>

Registering Our AgoraChat Component:

Now, copy & paste the following line into your resources/js/app.js to register our AgoraChat component.

Vue.component("agora-chat",require("./components/AgoraChat.vue").default);

Creating View File for Agora Chat:

Now, we will create an agora-chat.blade.php file inside the resources>views folder. After that copy & paste the below following code into that file.

@extends('layouts.app')

@section('content')

<agora-chat :allusers="{{ $users }}" authuserid="{{ auth()->id() }}" authuser="{{ auth()->user()->name }}"
agora_id="{{ env('AGORA_APP_ID') }}" />

@endsection

Updating Our .env with Agora & Pusher all API Keys:

Now, we will update our .env file with Agora & Pusher API keys. Copy & paste the following code into the .env file.

BROADCAST_DRIVER=pusher

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=

AGORA_APP_ID=
AGORA_APP_CERTIFICATE=

TEST THE APPLICATION:

At last, we will start our local server using our artisan command. php artisan serve & npm run dev If there is no problem, our code will work fine, and the project will be running now at http://127.0.0.1:8000/ or http://locahost:8000/. You can know more from their documentation.

Conclusion:

Finished! That’s all about our tutorial. I’ve tried to teach you the most updated & tested things in this tutorial. Thank you so much for reading the whole tutorial from the beginning. If this tutorial helps you a little bit, then remember to share this post on social media. If you have questions, suggestions, or tips regarding this post, let us know via our Contact Us page.

FAQS REGARDING AGORA WEB SDK WITH LARAVEL:

What is Agora SDK?

Agora is a real-time technology provider. Agora helps you to integrate video calls and other technologies into your website or device more conveniently.

Is Agora free or paid?

Agora is kind of a freemium service provider. It means you can use Agora for your web application for the first 10,000 minutes after that, you must go to their subscription plans.


Loved it? Please Share on Social Media

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.