
Partager:
Hui Jing est développeuse chez Nexmo. Elle a un amour immodéré pour le CSS et la typographie, et est généralement passionnée par tout ce qui touche au web.
Ajouter la fonction de texte à une conversation vidéo avec l'API Video de Vonage
Temps de lecture : 10 minutes
Cette série de tutoriels explorera l'API vidéo de Vonage (anciennement TokBox OpenTok). Video API de Vonage (anciennement TokBox OpenTok) et ce que vous pouvez construire avec. L'API Video est très robuste et hautement personnalisable. Dans chaque article, nous montrerons comment mettre en œuvre une fonctionnalité spécifique à l'aide de l'API. Cette fois-ci, nous allons voir comment ajouter du texte à un chat audio-vidéo de base.
Comme cette application nécessitera un peu de code côté serveur, nous utiliserons Glitch pour faciliter l'installation. Vous pouvez également télécharger le code de ce projet Glitch et le déployer sur votre propre serveur ou sur la plateforme d'hébergement de votre choix (ce qui nécessitera probablement quelques ajustements de configuration en fonction des exigences de votre plateforme).
Nous n'utiliserons pas de frameworks frontaux pour cette série, mais uniquement du Javascript vanille pour nous concentrer sur l'API Video elle-même. À la fin de ce tutoriel, vous devriez être en mesure d'avoir une application de chat audio-vidéo avec une fonctionnalité de chat textuel. Le chat textuel est implémenté à l'aide de l'API API de signalisation.
Screenshot of video chat with text chat
Le code final pour cette application peut être trouvé dans ce dépôt GitHub ou remixé sur Glitch.
Conditions préalables
Avant de commencer, vous aurez besoin d'un compte Video API de Vonage, que vous pouvez créer gratuitement ici. Vous aurez également besoin de Node.js installé (si vous n'utilisez pas Glitch).
Ce tutoriel s'appuie sur le premier billet d'introduction de la série : Construire un chat vidéo de base. Si vous utilisez l'API Video pour la première fois, nous vous conseillons vivement de lire cet article car il couvre la configuration de base suivante :
Créer un projet Video API de Vonage
S'installer sur Glitch
Structure de base du projet
Initialisation d'une session
Connexion à la session, abonnement et publication
Styles de mise en page de base pour un chat vidéo
Principes de base du clavardage avec l'API Video de Vonage
La mise en œuvre du chat textuel avec l'API Video se fait par l'intermédiaire de l'API API de signalisation. Ce mécanisme de signalisation permet aux clients connectés à une session de s'envoyer du texte et des données. Pour l'instant, nous nous concentrerons uniquement sur le texte.
Le client Video API SDK envoie un événement lorsque le client reçoit un signal. Pour un chat textuel de base où les messages sont visibles par tous les clients connectés, nous utiliserons la méthode signal() de la méthode Session de l'objet Session. Les clients participants recevront ce signal en écoutant l'événement de signal envoyé par l'objet Session .
Pour un examen approfondi de ce qui est accessible par le biais de l'option session ses propriétés, ses méthodes et ses événements, veuillez vous référer à Référence SDK pour l'objet Session.
Configuration initiale
Comme nous construisons sur un chat vidéo de base, commencez par remixer le projet pour le chat vidéo de base construit dans le tutoriel précédent. Cliquez sur le gros bouton Remix ci-dessous pour le faire. 👇

La structure de votre dossier devrait ressembler à ceci :
Folder structure of the project
Comme nous l'avons mentionné au début, TokBox OpenTok est maintenant Video API de Vonage. Nous n'avons pas modifié les noms de nos paquets, de sorte que vous ferez toujours référence à OpenTok dans votre code.
Si vous avez remixé le projet Glitch, votre fichier server.js devrait déjà ressembler à ceci :
const express = require("express");
const app = express();
const OpenTok = require("opentok");
const OT = new OpenTok(process.env.API_KEY, process.env.API_SECRET);
let sessions = {};
app.use(express.static("public"));
app.get("/", (request, response) => {
response.sendFile(__dirname + "/views/landing.html");
});
app.get("/session/:room", (request, response) => {
response.sendFile(__dirname + "/views/index.html");
});
app.post("/session/:room", (request, response) => {
const roomName = request.params.room;
// Check if the session already exists
if (sessions[roomName]) {
// Generate the token
generateToken(roomName, response);
} else {
// If the session does not exist, create one
OT.createSession((error, session) => {
if (error) {
console.log("Error creating session:", error);
} else {
// Store the session in the sessions object
sessions[roomName] = session.sessionId;
// Generate the token
generateToken(roomName, response);
}
});
}
});
function generateToken(roomName, response) {
// Configure token options
const tokenOptions = {
role: "publisher",
data: `roomname=${roomName}`
};
// Generate token with the Video API Client SDK
let token = OT.generateToken(
sessions[roomName],
tokenOptions
);
// Send the required credentials back to to the client
// as a response from the fetch request
response.status(200);
response.send({
sessionId: sessions[roomName],
token: token,
apiKey: process.env.API_KEY
});
}
const listener = app.listen(process.env.PORT, () => {
console.log("Your app is listening on port " + listener.address().port);
});
Pour mettre en place le chat vidéo, rendez-vous dans le fichier .env et indiquez la clé API et le secret de votre projet, que vous trouverez dans le tableau de bord. Une fois cela fait, nous travaillerons sur le code côté client pour faire fonctionner le chat textuel avant de revisiter le fichier server.js à nouveau.
Ajouter le balisage requis
Notre application sera composée de 2 pages. Une page d'atterrissage avec deux entrées de texte. La première permet aux utilisateurs de créer une session, que nous appellerons "salle", afin que les participants suivants puissent rejoindre cette même "salle". L'autre entrée de texte permet aux utilisateurs de saisir un nom d'affichage qu'ils peuvent utiliser pour s'identifier.
La page comportera un simple élément de formulaire avec deux champs de saisie permettant aux utilisateurs d'indiquer leur nom de chambre et leur nom d'utilisateur. Ajoutons le champ "nom d'utilisateur" au formulaire.
<form class="registration" id="registration">
<label>
<span>Room</span>
<input
type="text"
name="room-name"
placeholder="Enter room name"
required
/>
</label>
<!-- Add the user name input field and label -->
<label>
<span>User name</span>
<input
type="text"
name="user-name"
placeholder="Enter your name"
required
/>
</label>
<button>Enter</button>
</form>
Nous devons également ajouter une boîte de dialogue à la page index.html à la page. Ajoutons les balises d'une fenêtre de discussion avec un en-tête, une zone d'affichage des messages et une entrée en bas pour taper et envoyer des messages. Pour optimiser l'espace disponible sur l'écran, la fenêtre de discussion sera hors écran par défaut et ne se déclenchera que lorsque vous cliquerez sur le bouton de discussion situé dans le coin inférieur droit de la page.
Chat button to trigger chat window
Nous ajouterons les styles nécessaires pour que le bouton ressemble au modèle ci-dessus dans la section suivante.
<button class="btn-chat" id="showChat" aria-label="Show chat">
<svg viewBox="0 0 512 512">
<path
fill="white"
d="m512 346.5c0-63.535156-36.449219-120.238281-91.039062-147.820312-1.695313 121.820312-100.460938 220.585937-222.28125 222.28125 27.582031 54.589843 84.285156 91.039062 147.820312 91.039062 29.789062 0 58.757812-7.933594 84.210938-23.007812l80.566406 22.285156-22.285156-80.566406c15.074218-25.453126 23.007812-54.421876 23.007812-84.210938zm0 0"
/>
<path
fill="white"
d="m391 195.5c0-107.800781-87.699219-195.5-195.5-195.5s-195.5 87.699219-195.5 195.5c0 35.132812 9.351562 69.339844 27.109375 99.371094l-26.390625 95.40625 95.410156-26.386719c30.03125 17.757813 64.238282 27.109375 99.371094 27.109375 107.800781 0 195.5-87.699219 195.5-195.5zm-225.5-45.5h-30c0-33.085938 26.914062-60 60-60s60 26.914062 60 60c0 16.792969-7.109375 32.933594-19.511719 44.277344l-25.488281 23.328125v23.394531h-30v-36.605469l35.234375-32.25c6.296875-5.761719 9.765625-13.625 9.765625-22.144531 0-16.542969-13.457031-30-30-30s-30 13.457031-30 30zm15 121h30v30h-30zm0 0"
/>
</svg>
</button>
Nous voulons également ajouter le balisage de la fenêtre de discussion au fichier index.html au fichier
Bare bones chat window which will slide in from the right
<aside id="chatWindow">
<header class="chat-header">
<h1><span id="roomName"></span>Chat</h1>
<button class="btn-close" id="closeChat" aria-label="Close chat">
<svg viewBox="0 0 47.971 47.971" role="img">
<path
d="M28.228 23.986L47.092 5.122a2.998 2.998 0 000-4.242 2.998 2.998 0 00-4.242 0L23.986 19.744 5.121.88a2.998 2.998 0 00-4.242 0 2.998 2.998 0 000 4.242l18.865 18.864L.879 42.85a2.998 2.998 0 104.242 4.241l18.865-18.864L42.85 47.091c.586.586 1.354.879 2.121.879s1.535-.293 2.121-.879a2.998 2.998 0 000-4.242L28.228 23.986z"
/>
</svg>
</button>
</header>
<section id="messageArea" class="messages"></section>
<form class="chat-form" id="chatForm">
<input id="chatInput" type="text" />
<input type="submit" value="Send" />
</form>
</aside>
Style des éléments liés au chat
Notre interface de chat sera cachée jusqu'à ce qu'on en ait besoin, puisque la principale caractéristique de cette application est le chat vidéo. Pour activer l'interface de chat, les utilisateurs cliqueront sur le bouton de chat situé dans le coin inférieur droit de la page. Ce bouton comporte une icône SVG qui indique qu'il déclenche le chat.
.btn-chat {
height: 3.5em;
width: 3.5em;
background-color: black;
border-radius: 50%;
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.2), 0 3px 6px 0 rgba(0, 0, 0, 0.19);
position: fixed;
right: 1em;
bottom: 1em;
}
.btn-chat svg {
height: 1.5em;
width: 1.5em;
}Nous utilisons le CSS pour transformer la fenêtre de chat en dehors de la fenêtre de visualisation par défaut. Lorsque quelqu'un clique sur l'icône du chat, il fait basculer une classe CSS qui modifie la valeur de la fenêtre de chat. translateX de manière à ce que la fenêtre s'affiche à partir du côté droit de l'écran.
aside {
position: fixed;
top: 0;
right: 0;
transform: translateX(100%);
display: flex;
flex-direction: column;
min-width: 20em;
width: 25%;
height: 100%;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
transition: transform 0.5s ease;
}
aside.active {
transform: translateX(0);
}Ajoutons également quelques styles pour l'en-tête, la zone des messages et le formulaire de saisie des messages.
.chat-header {
background-color: white;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
display: flex;
align-items: center;
}
.btn-close {
margin-left: auto;
height: 2em;
width: 2em;
background: transparent;
border: none;
cursor: pointer;
}
.btn-close svg {
height: 1em;
width: 1em;
}
.messages {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: scroll;
padding: 0.5em;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
background-color: rgba(255, 255, 255, 0.75);
}
.messages p {
margin-bottom: 0.5em;
display: flex;
word-break: break-word;
}
.chat-form {
padding: 0.5em;
background-color: white;
display: flex;
align-items: center;
}
.chat-form input[type="text"] {
flex: 1;
}
.chat-form input[type="submit"] {
margin-left: 0.5em;
align-self: stretch;
}Avec ces styles, vous devriez pouvoir voir une icône de chat dans le coin inférieur droit du fichier après être entré dans la salle. index.html une fois que vous êtes entré dans la salle. Mais le fait de cliquer sur cette icône n'a pas encore d'effet.
Ajoutons un gestionnaire d'événements pour faire basculer une classe CSS afin de faire glisser la fenêtre de chat dans le fichier client.js dans le fichier De même qu'un autre sur l'icône de fermeture de la fenêtre de chat pour la faire réapparaître.
const showChatBtn = document.getElementById("showChat");
showChatBtn.addEventListener(
"click",
event => {
const chatWindow = document.getElementById("chatWindow");
chatWindow.classList.toggle("active");
},
false
);
const closeChatBtn = document.getElementById("closeChat");
closeChatBtn.addEventListener(
"click",
event => {
const chatWindow = document.getElementById("chatWindow");
chatWindow.classList.remove("active");
},
false
);
Ce n'est pas la seule façon de styliser une interface de chat, alors n'hésitez pas à modifier les choses en fonction de vos besoins.
Utilisation de l'API Signal pour le chat textuel
Nous allons apporter quelques modifications au projet de base et faire fonctionner le chat textuel le plus basique.
Nous allons déplacer la variable session de la fonction initializeSession et la déclarer globalement au début du fichier client.js en haut du fichier.
let session;
function initializeSession(apiKey, sessionId, token) {
// Create a session object with the sessionId
session = OT.initSession(apiKey, sessionId);
// All the rest of the code
}Ajoutez un récepteur d'événements au formulaire de chat, qui enverra un signal à tous les clients connectés à la session lorsque le formulaire sera soumis.
const chat = document.getElementById("chatForm");
const msgTxt = document.getElementById("chatInput");
chat.addEventListener(
"submit",
event => {
event.preventDefault();
session.signal(
{
type: "msg",
data: `${msgTxt.value}`
},
() => {
msgTxt.value = "";
}
);
},
false
);
Nous avons également besoin d'un autre écouteur d'événements pour recevoir ce message en écoutant l'événement signal envoyé par l'objet Session. Les données de cet événement seront utilisées pour imprimer le message dans la zone de message de la fenêtre de chat.
function initializeSession(apiKey, sessionId, token) {
// Create a session object with the sessionId
session = OT.initSession(apiKey, sessionId);
// All the rest of the code
// Event listener for the msg signal
session.on("signal:msg", event => {
const content = event.data;
updateChat(content);
});
}
function updateChat(content) {
const msgHistory = document.getElementById("messageArea");
const msg = document.createElement("p");
msg.textContent = content;
msgHistory.appendChild(msg);
msgHistory.scroll({
top: msgHistory.scrollHeight,
behavior: "smooth"
});
}
Il s'agit du mécanisme de base du chat textuel avec l'API Video. Si vous tapez quelque chose dans la fenêtre de chat et que vous envoyez le message, celui-ci doit s'afficher à l'écran.
Identifier les participants à la session de chat
Cependant, pour rendre le chat plus convivial, nous voulons également ajouter un moyen d'identifier qui a dit quoi dans le chat. Nous utiliserons le nom d'utilisateur saisi sur la page d'accueil pour obtenir cette information, que nous transmettrons au serveur sous la forme d'une chaîne de requête dans l'URL.
Le script suivant sur la page landing.html transmet le nom de la salle et le nom de l'utilisateur saisis à la page index.html à la page.
const form = document.getElementById("registration");
form.addEventListener("submit", event => {
event.preventDefault();
location.href = `/session/${form.elements["room-name"].value}?username=${form.elements["user-name"].value}`;
});
Lorsque la index.html la page se charge, elle déclenche une POST à la route session/:name en extrayant de l'URL le nom d'utilisateur soumis et en le transmettant au serveur.
const url = new URL(window.location.href);
const roomName = url.pathname.split("/")[2];
const userName = url.searchParams.get("username");
fetch(location.pathname, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: userName })
})
.then(res => {
return res.json();
})
.then(res => {
const apiKey = res.apiKey;
const sessionId = res.sessionId;
const token = res.token;
const streamName = res.streamName;
initializeSession(apiKey, sessionId, token, streamName);
})
.catch(handleCallback);
Nous devons maintenant modifier cette route dans le fichier server.js afin qu'elle gère le nom de la salle et le nom de l'utilisateur et qu'elle renvoie les informations nécessaires à la fonction initializeSession . Nous devons également inclure un intergiciel pour gérer la charge utile de la demande.
// Middleware to read the body of the request
app.use(express.json());
app.post("/session/:room", (request, response) => {
const roomName = request.params.room;
const streamName = request.body.username;
// Check if the session already exists
if (sessions[roomName]) {
// Generate the token
generateToken(roomName, streamName, response);
} else {
// If the session does not exist, create one
OT.createSession((error, session) => {
if (error) {
console.log("Error creating session:", error);
} else {
// Store the session in the sessions object
sessions[roomName] = session.sessionId;
// Generate the token
generateToken(roomName, streamName, response);
}
});
}
});
function generateToken(roomName, streamName, response) {
// Configure token options
const tokenOptions = {
role: "publisher",
data: `roomname=${roomName}?streamname=${streamName}`
};
// Generate token with the Video API Client SDK
let token = OT.generateToken(sessions[roomName], tokenOptions);
// Send the required credentials back to to the client
// as a response from the fetch request
response.status(200);
response.send({
sessionId: sessions[roomName],
token: token,
apiKey: process.env.API_KEY
});
}
Sur la page client.jsnous pouvons maintenant afficher le nom d'utilisateur du participant qui a tapé le message en modifiant la propriété data de la méthode session.signal() méthode.
session.signal(
{
type: "msg",
data: `${session.connection.data.split("=")[2]}: ${msgTxt.value}`
},
() => {
msgTxt.value = "";
}
);
Désormais, lorsque vous enverrez un message texte, celui-ci sera précédé du nom d'utilisateur que vous avez utilisé lorsque vous êtes entré dans la salle.
Configurer PouchDB en tant que magasin de données
Cependant, si vous actualisez la page, tous les messages de chat précédents disparaissent. Cela s'explique par le fait que nous n'avons pas stocké les messages, mais que nous les avons simplement affichés à l'écran. Introduisons une sorte de magasin de données pour les messages.
Nous utiliserons PouchDB sur le serveur dans ce tutoriel, mais vous êtes libre de le remplacer par le magasin de données de votre choix.
Installer pouchdb-node avec la commande suivante (notez que l'utilisation de pnpm est un truc de Glitch) :
pouchdb-node installation on Glitch
Vérifions que les choses se déroulent comme prévu.
const PouchDB = require("pouchdb-node");
const sessionDb = new PouchDB("sessionDb");
sessionDb.info().then(info => console.log(info));
Vous devriez voir ce qui suit dans les logs Glitch.
Database information printed to console
PouchDB fournit une API entièrement asynchrone, bien qu'elle inclue également la possibilité pour les utilisateurs de choisir entre le format callback et le format promise. Nous utiliserons le format promesse pour ce tutoriel, et le code en tiendra compte.
Au lieu de stocker les informations de session dans une variable objet, nous les stockerons dans notre nouvelle base de données. Supprimez la ligne suivante du fichier server.js la ligne suivante.
// We no longer need this object
let sessions = {};Apporter d'autres modifications à l'itinéraire /session/:name . Nous vérifions d'abord dans la base de données si une session existe, si c'est le cas, nous récupérons les informations associées et générons le jeton à partir de celles-ci. Si la session n'existe pas, nous créons une nouvelle session, la stockons dans la base de données, puis générons le jeton en conséquence.
app.post("/session/:room", (request, response) => {
const roomName = request.params.room;
const streamName = request.body.username;
const isExistingSession = checkSession(roomName);
isExistingSession.then(sessionExists => {
if (sessionExists) {
sessionDb
.get(roomName)
.then(sessionInfo => {
generateToken(roomName, streamName, sessionInfo, response);
})
.catch(error => error);
} else {
OT.createSession((error, session) => {
if (error) {
console.log("Error creating session:", error);
} else {
const sessionInfo = {
_id: roomName,
sessionId: session.sessionId,
messages: []
};
sessionDb.put(sessionInfo);
generateToken(roomName, streamName, sessionInfo, response);
}
});
}
});
});
function checkSession(roomName) {
return sessionDb
.get(roomName)
.then(() => {
console.log(roomName + "exists");
return Promise.resolve(true);
})
.catch(() => {
console.log("Room does not exist");
return Promise.resolve(false);
});
}
function generateToken(roomName, streamName, sessionInfo, response) {
const tokenOptions = {
role: "publisher",
data: `roomname=${roomName}?streamname=${streamName}`
};
let token = OT.generateToken(sessionInfo.sessionId, tokenOptions);
response.status(200);
response.send({
sessionId: sessionInfo.sessionId,
token: token,
apiKey: process.env.API_KEY,
streamName: streamName
});
}
Ajouter des noms de flux à l'interface utilisateur
Nous pouvons utiliser le nom du flux dans la réponse pour étiqueter les flux afin que les participants puissent survoler le flux vidéo de chaque participant pour voir un nom. La méthode initPublisher() et la méthode subscribe() acceptent toutes deux un argument facultatif properties qui nous permet de passer des options de personnalisation pour le flux.
function initializeSession(apiKey, sessionId, token, streamName) {
// Create a session object with the sessionId
session = OT.initSession(apiKey, sessionId);
// Create a publisher
const publisher = OT.initPublisher(
"publisher",
{
insertMode: "append",
width: "100%",
height: "100%",
name: streamName
},
handleCallback
);
// Subscribe to a newly created stream
session.on("streamCreated", event => {
session.subscribe(
event.stream,
"subscriber",
{
insertMode: "append",
width: "100%",
height: "100%",
name: event.stream.name
},
handleCallback
);
});
}
Hover over a video stream to see the stream name
Enregistrer les messages dans la base de données
Lorsque les participants envoient des messages texte, nous voulons les POST au serveur pour qu'ils soient stockés dans la base de données. Créons une fonction saveMessage() pour ce faire.
function saveMessage(content) {
const message = {
_id: Date.now().toString(),
content: content,
roomname: name,
user: username
};
fetch("/message", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(message)
}).catch(handleCallback);
}Modifiez l'écouteur d'événements sur le formulaire de chat pour déclencher cette fonction chaque fois qu'un participant envoie un message texte.
chat.addEventListener(
"submit",
event => {
event.preventDefault();
session.signal(
{
type: "msg",
data: `${session.connection.data.split("=")[2]}: ${msgTxt.value}`
},
() => {
saveMessage(msgTxt.value);
msgTxt.value = "";
}
);
},
false
);
Dans le fichier server.js nous devons ajouter un gestionnaire pour cette demande de POST pour cette requête.
app.post("/message", (request, response) => {
const roomName = request.body.roomName;
const message = {
timeStamp: request.body._id,
content: request.body.content,
user: request.body.user
};
sessionDb
.get(roomName)
.then(result => {
result.messages = [...result.messages, message];
return sessionDb.put(result);
})
.then(() => {
return sessionDb.get(roomName);
})
.then(result => {
response.status(200);
response.send({
latestMessage: result.messages[result.messages.length - 1]
});
})
.catch(error => console.log(error));
});
Maintenant que nos messages sont stockés, nous voulons les afficher lors du chargement de la page. Nous ajouterons une fonction getChatHistory() côté client qui déclenche une requête GET pour récupérer tous les messages stockés pour cette session et les afficher dans la fenêtre de chat.
function getChatHistory() {
fetch(`/messages/${roomName}`)
.then(res => {
return res.json();
})
.then(res => {
const messageArea = document.getElementById("messageArea");
res.messagesArray.forEach(message => {
const msg = document.createElement("p");
msg.textContent = `${message.user}: ${message.content}`;
messageArea.appendChild(msg);
});
messageArea.scroll({
top: messageArea.scrollHeight,
behavior: "smooth"
});
})
.catch(handleCallback);
}
Et la route correspondante du côté du serveur pour transmettre les messages sous forme de tableau au client.
app.get("/messages/:room", (request, response) => {
const roomName = request.params.room;
sessionDb
.get(roomName)
.then(result => {
response.status(200);
response.send({
messagesArray: result.messages
});
})
.catch(error => console.log(error));
});
Ainsi, même si vous rafraîchissez la page alors que la session est en cours, les messages seront toujours présents. De plus, si vous entrez le même nom de salle qu'une session précédente avec un historique de chat stocké, cet historique de chat sera affiché.
Quelle est la prochaine étape ?
Le code final de Glitch et sur GitHub contient tout ce que nous avons couvert dans ce billet assez long, mais réorganisé de façon à ce que le code soit plus propre et plus facile à maintenir. N'hésitez pas à remixer ou à cloner le code et à jouer avec.
Il existe d'autres fonctionnalités que nous pouvons créer avec l'API Video de Vonage et qui seront abordées dans de futurs tutoriels, mais en attendant, vous pouvez en savoir plus en consultant notre site de documentation complet. Si vous rencontrez des problèmes ou si vous avez des questions, contactez-nous sur notre Communauté Slack. Merci pour votre lecture !