https://d226lax1qjow5r.cloudfront.net/blog/blogposts/creating-an-online-classroom-in-laravel-with-vonage-video-api/blog_online-classroom_laravel_1200x600.png

Creación de un Aula Online en Laravel con Vonage Video API

Publicado el December 11, 2020

Tiempo de lectura: 15 minutos

Este artículo mostrará cómo configurar una clase virtual/de Video en tiempo real utilizando la API de Video de Vonage donde el profesor puede estar en cualquier lugar del mundo y aún así comunicarse y tener clases con el estudiante en tiempo real.

¿Qué es exactamente Video API de Vonage?

Vonage Video API es un servicio que facilita a los desarrolladores la creación de aplicaciones que utilizan WebRTC y Web Sockets para ofrecer comunicación en tiempo real por video, texto, audio y otros para aplicaciones web, aplicaciones móviles e incluso dispositivos de escritorio. Proporcionan potentes SDKs para varias plataformas para implementar y dar a los usuarios la API a utilizar para sus aplicaciones.

¿Cómo funciona?

Todas las aplicaciones que utilizan la Video API de Vonage constan de tres componentes principales y todo lo que haces gira en torno a ellos. Ellos son:

  1. Sesiones

  2. Servidor

  3. Cliente

Veamos cada uno de ellos con un poco de detalle:

Sesiones

Una sesión puede considerarse como la sala de chat virtual en la que tienen lugar las comunicaciones. Para que dos computadoras puedan intercambiar video o audio, deben estar conectadas a la misma sesión. Las sesiones se alojan/almacenan en la nube de la API de Vonage y todas tienen un ID único. Las sesiones administran los flujos de usuarios (video y audio) y realizan un seguimiento de todos los eventos (como cuando los usuarios se unen o se van o envían un mensaje de texto).

Servidor

Los servidores son el código backend que escribes para administrar las sesiones en tu aplicación. Para que la comunicación tenga lugar, tu servidor debe comunicarse con la nube de la API de Vonage para crear una sesión y usar el ID de sesión recibido para generar tokens que los clientes (navegadores y teléfonos móviles) pueden usar para unirse a la sesión e intercambiar secuencias. Para que tu servidor funcione, tendrás que usar uno de los muchos SDK del lado del servidor de la API de Vonage disponibles para varios lenguajes del lado del servidor.

Cliente

Los clientes son los navegadores o dispositivos móviles con los que los usuarios interactúan directamente para intercambiar flujos de vídeo y audio. Los clientes siempre necesitan un token (generado por el servidor) para unirse a una sesión y poder interactuar con otros clientes en la misma sesión.

Cuando un cliente está conectado, puede publicar (enviar vídeo/audio) y suscribirse (recibir audio/vídeo) a otros clientes en la misma sesión. Un cliente puede ser editor, suscriptor o moderador.

Los editores pueden enviar y recibir contenidos de audio y vídeo. Los suscriptores no pueden enviar, pero reciben audio/vídeo. Los moderadores pueden hacer lo mismo que los editores, pero también impedir que otros clientes se suscriban.

Para resumir, esto es lo que sucede para que se produzca la comunicación cuando se utiliza la API de Vonage:

Tu servidor crea una sesión en la nube de API de Vonage que tiene un ID único. Cuando un cliente quiere unirse, tu servidor usa el ID de sesión para generar un token para tu cliente. El cliente se une a la sesión y publica streams en la sesión. Cuando otro cliente se une, el servidor genera un nuevo token, y los dos clientes pueden suscribirse entre sí en la sesión y recibir los streams del otro.

Cómo configurar nuestra clase en línea con la API de Vonage

En este tutorial, configuraremos una transmisión de video básica con la API de Vonage para permitir que los clientes envíen transmisiones de audio y video. La API de Vonage proporciona un SDK para PHP y lo usaremos para crear nuestra clase virtual.

Configurar un proyecto Laravel

El primer paso para crear nuestra clase virtual es configurar un proyecto Laravel.

Es importante tener en cuenta que en el momento de escribir esto, la API de Vonage no funciona con la última versión de Laravel* *(8.x). Esto se debe a que el SDK PHP de la API de Vonage depende de la versión 6 de GuzzleHTTP pero Laravel 8 utiliza la versión 7 de GuzzleHTTP. Así que para este tutorial, por favor instala la versión 7 de Laravel. Puedes hacerlo ejecutando el comando install así:

composer create-project --prefer-dist laravel/laravel:^7.0 virtual_classroom

También puede clonar el repositorio repositorio aquí.

Instalación del SDK PHP de API de Vonage

El siguiente paso es instalar el SDK PHP de la API de Vonage. Lo hacemos instalando el paquete con composer a nuestro proyecto.

composer require opentok/opentok 4.4.x -W

Definir nuestras migraciones y modelos

Ahora tenemos que definir nuestros profesores y estudiantes para que puedan tener diferentes permisos en nuestra clase virtual. Nuestra aplicación haría uso de dos tablas - users para almacenar todos los profesores y alumnos y virtual_classes para almacenar los ids de sesión de nuestras clases para que los alumnos puedan ver la clase en curso cuando se conecten y se unan a ella. Estas son las migraciones para ambas tablas:

Abra la migración de usuarios en database/migrations/xxxxxx_create_users_xxxx.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();

            // This enum field tells us if the current user is a teacher or student

            $table->enum('user_type', ['Student', 'Teacher']);
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */

    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Abra la migración de virtual_classes en database/migrations/xxxxxx_create_virtual_classes_xxxx.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateVirtualClassesTable extends Migration
{
   /**
     * Run the migrations.
     *
     * @return void
     */

    public function up()
    {
        Schema::create('virtual_classes', function (Blueprint $table) {
            $table->id();
            $table->string("name");

            // User id to know which teacher created the class

            $table->integer("user_id");            `
            $table->string("session_id");
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */

    public function down()
    {
        Schema::dropIfExists('classes');
    }
}

Después de hacer esto, tendremos que crear una carpeta llamada Models en el directorio de la aplicación y mover nuestros modelos allí. A continuación, actualizaremos el espacio de nombres a App\Models en nuestros modelos. Por último, actualizaremos el modelo User para añadir user_type al array $fillable y crear una relación con las clases virtuales para que podamos acceder a ellas fácilmente.

Abra el modelo User en app/Models/Users.php

//REMEMBER TO UPDATE THE NAMESPACE AFTER MOVING THE FILE

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */

    // DON'T FORGET TO ADD THE USER_TYPE TO THIS ARRAY

    protected $fillable = [
        'name', 'email', 'password', 'user_type'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */

    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    // Relationship tying a virtual class to a user (teacher in our case)

    public function myClass() {
        return $this->hasOne(VirtualClass::class);
    }
}

Autenticación

Ahora que tenemos nuestro modelo de arquitectura configurado, necesitamos permitir a los usuarios registrarse e iniciar sesión. Lo primero que hay que hacer es editar los proveedores en la configuración de nuestro proyecto. Como hemos cambiado la ubicación del modelo de usuario, tenemos que reflejar el cambio. Primero vamos a config/auth.php y editamos el array providers y ejecutamos los comandos para scaffold la autenticación.

'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class, // New location of User model
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

// Rest of auth.php file

Después de hacer esto, simplemente ejecutamos el andamio de autenticación por defecto de Laravel:

composer require laravel/ui:^2.4
php artisan ui vue --auth
npm install
npm run dev

Después de ejecutar los cuatro comandos en ese orden, Laravel debería añadir las vistas necesarias para configurar la autenticación. El último paso para configurar nuestra autenticación es editar el RegisterController y el archivo register.blade.php para saber si un usuario es estudiante o profesor en el momento del registro.

En primer lugar, el app/Http/Controllers/Auth/RegisterController expediente:

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;

// PLEASE REMEMBER TO CHANGE THE IMPORT STATEMENT HERE

use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default, this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */

    protected $redirectTo = RouteServiceProvider::HOME;

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

    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param array $data
     * @return \Illuminate\Contracts\Validation\Validator
     */

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

            // Add the user_type here for validation.
            'user_type' => ['required', 'string', 'in:Student,Teacher'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param array $data
     * @return \App\User
     */

    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'user_type' => $data['user_type'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

A continuación, la vista de registro. Se encuentra en resources/views/auth/register.blade.php:

@extends('layouts.app')
@section('content')

<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>


                <div class="card-body">
                   <form method="POST" action="{{ route('register') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>


                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="user_type" class="col-md-4 col-form-label text-md-right">{{ __('User Type') }}</label>

{{--                        Note the select box here???--}}

                            <div class="col-md-6">
                                <select id="user_type" type="text" class="form-control @error('user_type') is-invalid @enderror" name="user_type" required>
                                    <option value="Student">Student</option>
                                    <option value="Teacher">Teacher</option>
                                </select>

                                @error('user_type')

                                <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                @error('password')
                                   <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@endsection

Una vez hecho esto, deberíamos poder registrarnos e iniciar sesión como profesor o como alumno.

Configuración de nuestro servidor

Antes de que puedas configurar tu servidor, necesitarás una clave y un secreto de API del proyecto. Para obtenerla, debes crear una cuenta gratuita de API de Vonage. Hazlo haciendo haciendo clic en este enlace. Una vez que hayas creado un proyecto, no dudes en volver y continuar :)

En primer lugar, vamos a almacenar nuestra clave de la API y el secreto de la API en nuestro archivo .env en nuestro proyecto Laravel:

### ADD THESE LINES AT THE BOTTOM OF YOUR .env FILE, OR WHEREVER REALLY ###

VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret

### REST OF .ENV FILE ###

Ahora, necesitaremos configurar un controlador para configurar sesiones y generar tokens para nuevos usuarios. Vamos a crear uno y lo llamaremos SessionsController:

php artisan make:controller SessionsController

Rellenémoslo con los métodos necesarios en app/Http/Controllers/SessionsController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\VirtualClass;

#Import necessary classes from the Vonage API (AKA OpenTok)

use OpenTok\OpenTok;
use OpenTok\MediaMode;
use OpenTok\Role;

class SessionsController extends Controller
{
    /** Creates a new virtual class for teachers
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */

    public function createClass(Request $request)
    {
        // Get the currently signed-in user
        $user = $request->user();
        // Throw 403 if student tries to create a class
        if ($user->user_type === "Student") return back(403);
        // Instantiate a new OpenTok object with our api key & secret
        $opentok = new OpenTok(env('VONAGE_API_KEY'), env('VONAGE_API_SECRET'));
        // Creates a new session (Stored in the Vonage API cloud)
        $session = $opentok->createSession(array('mediaMode' => MediaMode::ROUTED));
        // Create a new virtual class that would be stored in db
        $class = new VirtualClass();
        // Generate a name based on the name the teacher entered
        $class->name = $user->name . "'s " . $request->input("name") . " class";
        // Store the unique ID of the session
        $class->session_id = $session->getSessionId();
        // Save this class as a relationship to the teacher
        $user->myClass()->save($class);
        // Send the teacher to the classroom where real-time video goes on
        return redirect()->route('classroom', ['id' => $class->id]);
    }

    public function showClassRoom(Request $request, $id)
    {
        // Get the currently authenticated user
        $user = $request->user();
        // Find the virtual class associated by provided id
        $virtualClass = VirtualClass::findOrFail($id);
        // Gets the session ID
        $sessionId = $virtualClass->session_id;
        // Instantiates new OpenTok object
        $opentok = new OpenTok(env('VONAGE_API_KEY'), env('VONAGE_API_SECRET'));
        // Generates token for client as a publisher that lasts for one week
        $token = $opentok->generateToken($sessionId, ['role' => Role::PUBLISHER, 'expireTime' => time() + (7 * 24 * 60 * 60)]);
        // Open the classroom with all needed info for clients to connect
        return view('classroom', compact('token', 'user', 'sessionId'));
    }
}

Al crear el token, podemos establecer el rol que puede tener el cliente actual. Puede ser Editor, Suscriptor o Moderador. Los roles se explican más arriba. En el fragmento de código anterior, estamos dando a todos los usuarios el estado de editor, lo que significa que todos los usuarios pueden enviar y recibir streams(video-audio feed)

Tendremos que crear un archivo classroom.blade.php en nuestra carpeta resources/views para el método showClassroom método.

También necesitaremos crear rutas para el controlador. Añadiremos estas rutas en el archivo routes/web.php:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

// Add this to your web.php file

// This line makes all routes in it to use the auth middleware, meaning only signed-in users can access these routes

Route::middleware('auth')->group(function () {

    // This route creates classes for teachers

    Route::post("/create_class", 'SessionsController@createClass')
        ->name('create_class');

    // This route is used by both teachers and students to join a class

    Route::get("/classroom/{id}", 'SessionsController@showClassRoom')
        ->where('id', '[0-9]+')
        ->name('classroom');
});

Finalmente, en nuestro dashboard, necesitamos dar a los profesores un punto para crear clases y dar a los estudiantes la lista de clases a las que unirse. Para ello, tendremos que actualizar el HomeController y el archivo home.blade.php. Vamos a ello; espero que sigáis conmigo 🙂 .

Empezaremos con el app/Http/Controllers/HomeController:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\ClassModel as VirtualClass;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */

    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Contracts\Support\Renderable
     */

    public function index(Request $request)
    {
        $user = $request->user();
        $classes = [];

        // If user is a student, give her a list of virtual classes

        if ($user->user_type === "Student") {
            $classes = VirtualClass::orderBy('name', 'asc')->get();
        }

        return view('home', compact('user', 'classes'));
    }
}

Siguiente resources/views/home.blade.php:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{$user->user_type}} {{ __('Dashboard') }}</div>

                    <div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif
                        @if($user->user_type === "Student")
                            <h3>These are the ongoing classes available on the system</h3>
                            @foreach($classes as $key=>$class)
                                <a href="{{route('classroom', ['id' => $class->id])}}">{{$key + 1}}. {{$class->name}}</a>
                                <br />
                            @endforeach
                        @else
                            <h4>Welcome {{$user->name}}. Fill the form below to create a class</h4>
                            <form method="POST" action="{{ route('create_class') }}">
                                @csrf

                                <div class="form-group row">
                                    <label for="name" class="col-md-12 col-form-label">{{ __('Class Name') }}</label>

                                    <div class="col-md-6">
                                        <input id="name" type="text"
                                               class="form-control @error('name') is-invalid @enderror" name="name"
                                               value="{{ old('name') }}" required autocomplete="name" autofocus>

                                        @error('name')
                                        <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                        @enderror

                                    </div>
                                </div>

                                <div class="form-group row mb-0">
                                    <div class="col-md-6">
                                        <button type="submit" class="btn btn-primary">
                                            {{ __('Create Class') }}
                                        </button>
                                    </div>
                                </div>
                            </form>

                        @endif

                    </div>
                </div>
            </div>
        </div>
    </div>

@endsection

Esto proporciona un formulario para crear una clase si el usuario es un profesor o una lista de clases virtuales si el usuario es un estudiante.

Configuración de nuestro cliente y transmisión de vídeo y audio en directo

Para configurar el cliente (que estaría usando el SDK web), necesitaremos crear un archivo blade llamado resources/views/classroom.blade.php para que coincida con el método showClassroom() de nuestro SessionsController. El archivo tendría que tener un enlace al CDN del SDK. Nuestro frontend debería tener este aspecto:

    <html>
    <head>
        <title> OpenTok Getting Started </title>
        <style>
          body, html {
              background-color: gray;
              height: 100%;
          }

          #videos {
              position: relative;
              width: 100%;
              height: 100%;
              margin-left: auto;
              margin-right: auto;
          }

          #subscriber {
              position: absolute;
              left: 0;
              top: 0;
              width: 100%;
              height: 100%;
              z-index: 10;
          }

          #publisher {
              position: absolute;
              width: 360px;
              height: 240px;
              bottom: 10px;
              left: 10px;
              z-index: 100;
              border: 3px solid white;
              border-radius: 3px;
          }

        </style>

        <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>

    </head>

    <body>
        <div id="videos">
            <div id="subscriber"></div>
            <div id="publisher"></div>
        </div>

        <script type="text/javascript">
            var session;
            var connectionCount = 0;
            var apiKey = "{{env('VONAGE_API_KEY')}}";
            var sessionId = "{{$sessionId}}";
            var token = "{{$token}}";
            var publisher;

            function connect() {

                // Replace apiKey and sessionId with your own values:

                session = OT.initSession(apiKey, sessionId);
                session.on("streamCreated", function (event) {
                    console.log("New stream in the session: " + event.stream.streamId);
                    session.subscribe(event.stream, 'subscriber', {
                        insertMode: 'append',
                        width: '100%',
                        height: '100%'
                    });
                });

                session.on({
                    connectionCreated: function (event) {
                        connectionCount++;
                        alert(connectionCount + ' connections.');
                    },
                    connectionDestroyed: function (event) {
                        connectionCount--;
                        alert(connectionCount + ' connections.');
                    },
                    sessionDisconnected: function sessionDisconnectHandler(event) {
                        // The event is defined by the SessionDisconnectEvent class
                        alert('Disconnected from the session.');
                        document.getElementById('disconnectBtn').style.display = 'none';
                        if (event.reason == 'networkDisconnected') {
                            alert('Your network connection terminated.')
                        }
                    }
                });

                var publisher = OT.initPublisher('publisher', {
                    insertMode: 'append',
                    width: '100%',
                    height: '100%'
                }, error => {
                    if (error) {
                        alert(error.message);
                    }
                });

                // Replace token with your own value:
                session.connect(token, function (error) {
                    if (error) {
                        alert('Unable to connect: ', error.message);
                    } else {
                        // document.getElementById('disconnectBtn').style.display = 'block';
                        alert('Connected to the session.');
                        connectionCount = 1;

                        if (session.capabilities.publish == 1) {
                            session.publish(publisher);
                        } else {

                            alert("You cannot publish an audio-video stream.");
                        }
                    }
                });
            }
            connect();

        </script>
    </body>
</html>
   

Para probar la aplicación, ejecute el siguiente comando en el directorio raíz del proyecto.

php artisan serve

Abra http://localhost:8000/ en su navegador y haga clic en el menú de inicio de sesión.

Si se hace correctamente, deberías conectarte con una cuenta de profesor y otra de alumno e intercambiar audio y vídeo.

Log in with a teacher account and a student account and exchange audio and video feedLog in with a teacher account and a student account and exchange audio and video feed

Cuando se conecte con un estudiante, debería ver esta pantalla.

Connected with a studentConnected with a student

Conclusión

Las aplicaciones en tiempo real son increíbles. Están uniendo al mundo, y ahora que el mundo está cada vez más alejado, la demanda de este tipo de aplicaciones es alta.

Trabajar con WebRTC y WebSockets para la comunicación en tiempo real puede ser engorroso, pero la API de Vonage proporciona métodos de ayuda sencillos para una amplia gama de casos de uso. Este artículo muestra cómo configurar un feed de Video utilizando Laravel. Puedes clonar el repositorio repositorio aquí.

Compartir:

https://a.storyblok.com/f/270183/250x250/5e3dc7b6d8/solomon-eseme.png
Solomon Eseme

A Software Developer who is geared towards building high performing and innovative products following best practices and industry standards. He also loves writing about backend development.