AWS Chime SDK : Comment réaliser une visioconférence interactive

mercredi 26 mars 202517 min de lecturePar Damien Gilbrin
AWS Chime SDK : Comment réaliser une visioconférence interactive

Table des matières

📹

Introduction

Dans un monde où le travail à distance et les interactions virtuelles sont devenus omniprésents, les solutions de communication en temps réel représentent un pilier fondamental de la collaboration moderne. AWS Chime SDK se distingue comme une plateforme puissante qui permet aux développeurs d'intégrer des fonctionnalités avancées de visioconférence, d'audioconférence et de partage d'écran directement dans leurs applications.

Contrairement aux solutions packagées comme Zoom ou Microsoft Teams, AWS Chime SDK n'est pas une application clé en main, mais un ensemble de composants modulaires qui offrent une flexibilité exceptionnelle. Cette approche permet de créer des expériences sur mesure, parfaitement adaptées à vos besoins spécifiques et à votre marque.

AWS Chime SDK fournit les blocs de construction fondamentaux pour créer des expériences de communication en temps réel dans vos applications web, iOS, Android et autres plateformes, sans que vos utilisateurs n'aient besoin d'installer des logiciels supplémentaires ou de créer des comptes séparés.

Dans cet article, nous explorerons en profondeur les capacités d'AWS Chime SDK, comment il fonctionne, et surtout, comment l'implémenter dans vos propres applications pour créer des expériences de visioconférence véritablement interactives. Que vous construisiez une application de télémédecine, une plateforme éducative, un outil de service client ou tout autre système nécessitant des communications en temps réel, vous découvrirez comment Chime SDK peut vous aider à atteindre vos objectifs.

🔍

Qu'est-ce qu'AWS Chime SDK ?

AWS Chime SDK est un ensemble d'API, de composants et de bibliothèques client permettant aux développeurs d'intégrer des communications audio, vidéo et de partage d'écran en temps réel dans leurs applications. Contrairement au service AWS Chime standard qui est une solution complète de réunion, Chime SDK est conçu pour les développeurs souhaitant créer leurs propres expériences personnalisées.

Composants clés

  • Media Services : Pour la gestion des flux audio et vidéo en temps réel

  • Messaging : Pour l'envoi et la réception de messages texte en temps réel

  • PSTN Audio : Pour l'intégration avec des systèmes téléphoniques traditionnels

  • Identity : Pour la gestion des identités et l'attribution des autorisations

  • Data Messages : Pour l'envoi de données personnalisées entre participants

  • Meeting Events : Pour recevoir des notifications sur les événements de réunion

  • Client Libraries : Des bibliothèques pour JavaScript, iOS et Android

Architecture du service

AWS Chime SDK suit une architecture distribuée qui comprend plusieurs composants clés :

  • Backend AWS Chime : Géré par AWS, ce backend orchestre les sessions de communication

  • API de contrôle : Permet de créer et gérer des réunions, des participants et des politiques

  • Service multimédia : Gère les flux audio/vidéo et optimise la qualité en fonction des conditions réseau

  • Bibliothèques client : S'intègrent dans vos applications pour connecter les utilisateurs au service

  • AWS Global Network : Infrastructure mondiale qui garantit une faible latence et une haute disponibilité

Modèle de tarification

AWS Chime SDK utilise un modèle de paiement à l'usage, ce qui signifie que vous ne payez que pour ce que vous utilisez. Les tarifs sont basés sur le nombre d'attendees-minutes pour les réunions, le nombre de messages envoyés pour la messagerie, et le nombre de minutes d'appel pour les services PSTN. Il n'y a pas de frais minimum, de coûts d'installation ou d'engagements à long terme.

⚙️

Capacités principales d'AWS Chime SDK

AWS Chime SDK offre un ensemble complet de fonctionnalités qui permettent de créer des expériences de communication riches et interactives :

Communications audio et vidéo en temps réel

  • Vidéo HD : Support pour la vidéo haute définition avec adaptation dynamique de la qualité

  • Audio cristallin : Traitement audio avancé avec suppression du bruit et de l'écho

  • Partage d'écran : Capacité à partager des écrans entiers ou des applications spécifiques

  • Arrière-plans virtuels : Possibilité d'implémenter le flou ou le remplacement d'arrière-plan

  • Mise en page adaptative : Organisation dynamique des vignettes vidéo en fonction du nombre de participants

  • Mode présentateur : Mise en évidence automatique de l'orateur actif

Messagerie en temps réel

La messagerie Chime SDK permet d'enrichir vos réunions avec des interactions textuelles :

  • Chats de réunion : Communication textuelle pendant les sessions

  • Canaux persistants : Discussions continues en dehors des réunions

  • Messagerie 1:1 : Communications privées entre participants

  • Transfert de fichiers : Partage de documents et de médias

  • Indicateurs de présence : Statuts en ligne/hors ligne des utilisateurs

  • Notifications de lecture : Confirmation de lecture des messages

Intégration téléphonique (PSTN)

AWS Chime SDK permet d'intégrer des communications téléphoniques traditionnelles à vos applications :

  • SIP Trunking : Connexion aux systèmes téléphoniques existants

  • Numéros de téléphone : Attribution de numéros dans 100+ pays

  • Appels entrants/sortants : Gestion des appels téléphoniques

  • IVR (Réponse Vocale Interactive) : Création de menus vocaux

  • Transcription en temps réel : Conversion voix-texte pendant les appels

  • Routage intelligent : Acheminement des appels basé sur des règles

Fonctionnalités interactives

AWS Chime SDK permet de créer des expériences de réunion hautement engageantes grâce à ces fonctionnalités interactives :

  • Sondages et quizz : Création de questionnaires interactifs pendant les réunions

  • Tableaux blancs : Collaboration visuelle en temps réel

  • Réactions : Émojis et autres réactions non verbales

  • Levée de main : Système de gestion des tours de parole

  • Breakout rooms : Séparation des participants en sous-groupes

  • Contrôles de modération : Gestion des droits et permissions des participants

Le saviez-vous ?

AWS Chime SDK est utilisé par de grandes entreprises comme Slack, Mural et Epic Games pour leurs solutions de communication. Par exemple, Slack utilise Chime SDK pour alimenter ses fonctionnalités d'appels audio et vidéo directs entre utilisateurs.

🚀

Commencer avec AWS Chime SDK

Maintenant que nous avons une bonne compréhension de ce qu'est AWS Chime SDK et de ses capacités, voyons comment l'intégrer dans une application web.

Prérequis

  • Un compte AWS actif

  • Node.js et npm installés

  • Des connaissances de base en JavaScript et React

  • Un éditeur de code comme Visual Studio Code

  • Les permissions IAM appropriées pour utiliser AWS Chime SDK

Implémentation basique d'une visioconférence

Voici un guide étape par étape pour intégrer une visioconférence basique dans une application React :

Étape 1 : Installation des dépendances

1# Création d'un nouveau projet React (si vous n'en avez pas déjà un)
2npx create-react-app chime-video-demo
3cd chime-video-demo
4
5# Installation des bibliothèques AWS Chime SDK
6npm install amazon-chime-sdk-js
7npm install aws-sdk
8
9# Installation des dépendances de backend (pour notre serveur)
10npm install express cors uuid

Étape 2 : Configuration du backend

Créez un fichier server.js à la racine du projet :

1// server.js
2const express = require('express');
3const cors = require('cors');
4const AWS = require('aws-sdk');
5const { v4: uuidv4 } = require('uuid');
6
7// Configuration d'AWS
8AWS.config.update({
9  region: 'us-east-1', // Remplacez par votre région
10  credentials: new AWS.Credentials({
11    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
12    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
13  })
14});
15
16const chime = new AWS.Chime({ region: 'us-east-1' });
17// Définir le point de terminaison Chime (choisir le bon point de terminaison pour votre région)
18chime.endpoint = new AWS.Endpoint('https://service.chime.aws.amazon.com');
19
20const app = express();
21app.use(cors());
22app.use(express.json());
23
24// Route pour créer une nouvelle réunion
25app.post('/meetings', async (req, res) => {
26  try {
27    // Créer une nouvelle réunion
28    const meeting = await chime.createMeeting({
29      ClientRequestToken: uuidv4(),
30      MediaRegion: 'us-east-1', // Ou une région plus proche de vos utilisateurs
31      ExternalMeetingId: `ChimeDemo-${uuidv4().substring(0, 8)}` // ID externe pour votre référence
32    }).promise();
33    
34    // Créer un participant (attendee)
35    const attendee = await chime.createAttendee({
36      MeetingId: meeting.Meeting.MeetingId,
37      ExternalUserId: `user-${uuidv4().substring(0, 8)}` // ID externe pour le participant
38    }).promise();
39    
40    // Renvoyer les informations de réunion et de participant
41    res.json({
42      meeting: meeting.Meeting,
43      attendee: attendee.Attendee
44    });
45  } catch (err) {
46    console.error('Error creating meeting:', err);
47    res.status(500).json({ error: err.message });
48  }
49});
50
51// Route pour rejoindre une réunion existante
52app.post('/attendees', async (req, res) => {
53  try {
54    const { meetingId } = req.body;
55    if (!meetingId) {
56      return res.status(400).json({ error: 'Meeting ID is required' });
57    }
58    
59    // Créer un nouveau participant pour une réunion existante
60    const attendee = await chime.createAttendee({
61      MeetingId: meetingId,
62      ExternalUserId: `user-${uuidv4().substring(0, 8)}`
63    }).promise();
64    
65    res.json({ attendee: attendee.Attendee });
66  } catch (err) {
67    console.error('Error creating attendee:', err);
68    res.status(500).json({ error: err.message });
69  }
70});
71
72// Route pour terminer une réunion
73app.post('/meetings/:meetingId/end', async (req, res) => {
74  try {
75    const { meetingId } = req.params;
76    await chime.deleteMeeting({
77      MeetingId: meetingId
78    }).promise();
79    
80    res.json({ message: 'Meeting deleted successfully' });
81  } catch (err) {
82    console.error('Error deleting meeting:', err);
83    res.status(500).json({ error: err.message });
84  }
85});
86
87const PORT = process.env.PORT || 3001;
88app.listen(PORT, () => {
89  console.log(`Server running on port ${PORT}`);
90});

Étape 3 : Création du composant de visioconférence

Maintenant, créons le composant React pour la visioconférence :

1// src/components/VideoMeeting.js
2import React, { useState, useEffect, useRef } from 'react';
3import {
4  ConsoleLogger,
5  DefaultDeviceController,
6  DefaultMeetingSession,
7  LogLevel,
8  MeetingSessionConfiguration
9} from 'amazon-chime-sdk-js';
10
11const VideoMeeting = () => {
12  const [meetingId, setMeetingId] = useState('');
13  const [joinedMeeting, setJoinedMeeting] = useState(false);
14  const [audioVideo, setAudioVideo] = useState(null);
15  const [attendeeId, setAttendeeId] = useState('');
16  const [attendees, setAttendees] = useState([]);
17  
18  const videoTileRef = useRef({});
19  const meetingSessionRef = useRef(null);
20  const localVideoRef = useRef(null);
21  const remoteVideoTilesRef = useRef({});
22  
23  // Fonction pour créer une nouvelle réunion
24  const createMeeting = async () => {
25    try {
26      const response = await fetch('http://localhost:3001/meetings', {
27        method: 'POST',
28        headers: {
29          'Content-Type': 'application/json'
30        }
31      });
32      
33      const data = await response.json();
34      setMeetingId(data.meeting.MeetingId);
35      setAttendeeId(data.attendee.AttendeeId);
36      
37      joinMeeting(data.meeting, data.attendee);
38    } catch (err) {
39      console.error('Error creating meeting:', err);
40    }
41  };
42  
43  // Fonction pour rejoindre une réunion
44  const joinMeeting = async (meeting, attendee) => {
45    try {
46      // Configurer le logger
47      const logger = new ConsoleLogger('ChimeMeetingLogs', LogLevel.INFO);
48      
49      // Configurer le contrôleur de périphériques
50      const deviceController = new DefaultDeviceController(logger);
51      
52      // Créer la configuration de la session
53      const configuration = new MeetingSessionConfiguration(meeting, attendee);
54      
55      // Créer la session de réunion
56      const meetingSession = new DefaultMeetingSession(
57        configuration,
58        logger,
59        deviceController
60      );
61      
62      meetingSessionRef.current = meetingSession;
63      const av = meetingSession.audioVideo;
64      setAudioVideo(av);
65      
66      // Configurer les observateurs
67      setupVideoTileObservers(av);
68      setupAttendeeObservers(av);
69      
70      // Démarrer la session
71      await av.start();
72      
73      // Activer les périphériques locaux
74      await av.startLocalVideoTile();
75      await av.realtimeMuteLocalAudio(); // Commencer en mode muet
76      
77      setJoinedMeeting(true);
78    } catch (err) {
79      console.error('Error joining meeting:', err);
80    }
81  };
82  
83  // Configurer les observateurs de tuiles vidéo
84  const setupVideoTileObservers = (av) => {
85    // Gestion des tuiles vidéo
86    av.addObserver({
87      // Appelé quand une nouvelle tuile vidéo est créée
88      videoTileDidUpdate: (tileState) => {
89        if (!tileState.boundAttendeeId) {
90          return;
91        }
92        
93        const tileId = tileState.tileId;
94        videoTileRef.current[tileId] = tileState;
95        
96        // Si c'est une vidéo locale
97        if (tileState.localTile) {
98          av.bindVideoElement(tileId, localVideoRef.current);
99        } else {
100          // Si c'est une vidéo distante
101          const videoElement = document.createElement('video');
102          videoElement.id = `video-${tileId}`;
103          document.getElementById('remote-videos').appendChild(videoElement);
104          av.bindVideoElement(tileId, videoElement);
105          
106          // Stocker la référence pour le nettoyage ultérieur
107          remoteVideoTilesRef.current[tileId] = videoElement;
108        }
109      },
110      
111      // Appelé quand une tuile vidéo est supprimée
112      videoTileWasRemoved: (tileId) => {
113        if (remoteVideoTilesRef.current[tileId]) {
114          const videoElement = remoteVideoTilesRef.current[tileId];
115          if (videoElement.parentNode) {
116            videoElement.parentNode.removeChild(videoElement);
117          }
118          delete remoteVideoTilesRef.current[tileId];
119        }
120        delete videoTileRef.current[tileId];
121      }
122    });
123  };
124  
125  // Configurer les observateurs de participants
126  const setupAttendeeObservers = (av) => {
127    // Gérer les participants
128    av.realtimeSubscribeToAttendeeIdPresence((attendeeId, present) => {
129      if (present) {
130        // Nouveau participant rejoint
131        setAttendees(prev => [...prev, attendeeId]);
132      } else {
133        // Participant quitte
134        setAttendees(prev => prev.filter(id => id !== attendeeId));
135      }
136    });
137  };
138  
139  // Fonction pour quitter la réunion
140  const leaveMeeting = async () => {
141    if (audioVideo) {
142      audioVideo.stopLocalVideoTile();
143      audioVideo.stop();
144      
145      // Nettoyer les éléments vidéo distants
146      Object.values(remoteVideoTilesRef.current).forEach(videoElement => {
147        if (videoElement.parentNode) {
148          videoElement.parentNode.removeChild(videoElement);
149        }
150      });
151      
152      remoteVideoTilesRef.current = {};
153      setJoinedMeeting(false);
154      setAttendees([]);
155      
156      // Si vous êtes l'hôte, vous pouvez aussi terminer la réunion
157      if (meetingId) {
158        try {
159          await fetch(`http://localhost:3001/meetings/${meetingId}/end`, {
160            method: 'POST'
161          });
162        } catch (err) {
163          console.error('Error ending meeting:', err);
164        }
165      }
166    }
167  };
168  
169  // Fonction pour activer/désactiver le micro
170  const toggleMute = async () => {
171    if (!audioVideo) return;
172    
173    const muted = await audioVideo.realtimeIsLocalAudioMuted();
174    if (muted) {
175      await audioVideo.realtimeUnmuteLocalAudio();
176    } else {
177      await audioVideo.realtimeMuteLocalAudio();
178    }
179  };
180  
181  // Fonction pour activer/désactiver la caméra
182  const toggleVideo = async () => {
183    if (!audioVideo) return;
184    
185    const videoTile = audioVideo.getLocalVideoTile();
186    if (videoTile && videoTile.state().active) {
187      audioVideo.stopLocalVideoTile();
188    } else {
189      audioVideo.startLocalVideoTile();
190    }
191  };
192  
193  // Nettoyer lors du démontage du composant
194  useEffect(() => {
195    return () => {
196      if (joinedMeeting) {
197        leaveMeeting();
198      }
199    };
200  }, [joinedMeeting]);
201  
202  return (
203    <div className="video-meeting-container">
204      <h1>AWS Chime SDK Video Meeting</h1>
205      
206      {!joinedMeeting ? (
207        <div className="meeting-controls">
208          <button onClick={createMeeting}>Créer une nouvelle réunion</button>
209          <div>
210            <input 
211              type="text" 
212              placeholder="Entrez l'ID de réunion" 
213              value={meetingId} 
214              onChange={(e) => setMeetingId(e.target.value)} 
215            />
216            <button onClick={() => joinExistingMeeting()}>Rejoindre une réunion existante</button>
217          </div>
218        </div>
219      ) : (
220        <div className="meeting-room">
221          <div className="video-container">
222            <div className="local-video-container">
223              <h3>Vous</h3>
224              <video ref={localVideoRef} className="local-video" />
225            </div>
226            
227            <div id="remote-videos" className="remote-videos-container">
228              <h3>Participants ({attendees.length - 1})</h3>
229              {/* Les vidéos distantes seront injectées ici */}
230            </div>
231          </div>
232          
233          <div className="meeting-controls">
234            <button onClick={toggleMute}>Activer/Désactiver Micro</button>
235            <button onClick={toggleVideo}>Activer/Désactiver Caméra</button>
236            <button onClick={leaveMeeting} className="leave-button">Quitter la réunion</button>
237          </div>
238          
239          <div className="meeting-info">
240            <p>ID de réunion: {meetingId}</p>
241            <p>Partagez cet ID avec d'autres personnes pour qu'elles puissent rejoindre votre réunion.</p>
242          </div>
243        </div>
244      )}
245    </div>
246  );
247};
248
249export default VideoMeeting;

Étape 4 : Intégration dans l'application principale

1// src/App.js
2import React from 'react';
3import './App.css';
4import VideoMeeting from './components/VideoMeeting';
5
6function App() {
7  return (
8    <div className="App">
9      <VideoMeeting />
10    </div>
11  );
12}
13
14export default App;

Étape 5 : Ajout de styles CSS basiques

1/* src/App.css */
2.video-meeting-container {
3  max-width: 1200px;
4  margin: 0 auto;
5  padding: 20px;
6}
7
8.meeting-controls {
9  margin: 20px 0;
10  display: flex;
11  gap: 10px;
12  flex-wrap: wrap;
13}
14
15.video-container {
16  display: flex;
17  flex-wrap: wrap;
18  gap: 20px;
19  margin-bottom: 20px;
20}
21
22.local-video-container, .remote-videos-container {
23  background-color: #f5f5f5;
24  border-radius: 8px;
25  padding: 10px;
26}
27
28.local-video {
29  width: 300px;
30  height: 225px;
31  background-color: #333;
32  border-radius: 4px;
33}
34
35.remote-videos-container {
36  flex-grow: 1;
37  min-height: 225px;
38  display: flex;
39  flex-wrap: wrap;
40  gap: 10px;
41}
42
43.remote-videos-container video {
44  width: 300px;
45  height: 225px;
46  background-color: #333;
47  border-radius: 4px;
48}
49
50button {
51  padding: 10px 15px;
52  background-color: #4CAF50;
53  color: white;
54  border: none;
55  border-radius: 4px;
56  cursor: pointer;
57}
58
59button:hover {
60  background-color: #45a049;
61}
62
63.leave-button {
64  background-color: #f44336;
65}
66
67.leave-button:hover {
68  background-color: #d32f2f;
69}
70
71input[type="text"] {
72  padding: 8px;
73  border: 1px solid #ddd;
74  border-radius: 4px;
75  margin-right: 5px;
76}
77
78.meeting-info {
79  background-color: #e1f5fe;
80  padding: 10px;
81  border-radius: 4px;
82  margin-top: 20px;
83}

Étape 6 : Démarrer l'application

1# Dans un terminal, démarrez le serveur backend
2node server.js
3
4# Dans un autre terminal, démarrez l'application frontend
5npm start

Cette implémentation de base permet la création de réunions, la gestion des participants, et les contrôles audio/vidéo essentiels. Elle peut être étendue avec des fonctionnalités plus avancées comme le partage d'écran, le chat, ou les arrière-plans virtuels.

Fonctionnalités avancées

Maintenant que nous avons mis en place une application de visioconférence de base, explorons quelques fonctionnalités plus avancées qui peuvent rendre votre expérience véritablement interactive.

Partage d'écran

Le partage d'écran est une fonctionnalité essentielle pour les réunions collaboratives. Voici comment l'implémenter :

1// Ajoutez ces fonctions à votre composant VideoMeeting
2
3// Fonction pour démarrer le partage d'écran
4const startScreenShare = async () => {
5  if (!audioVideo) return;
6  
7  try {
8    // Demander l'accès au flux d'écran
9    const screenStream = await navigator.mediaDevices.getDisplayMedia({
10      video: true
11    });
12    
13    // Récupérer la piste vidéo du flux d'écran
14    const screenTrack = screenStream.getVideoTracks()[0];
15    
16    // Arrêter le partage d'écran lorsque l'utilisateur termine
17    screenTrack.addEventListener('ended', () => {
18      stopScreenShare();
19    });
20    
21    // Démarrer le partage d'écran via Chime SDK
22    await audioVideo.startContentShare(screenStream);
23    setIsScreenSharing(true);
24  } catch (err) {
25    console.error('Error starting screen share:', err);
26  }
27};
28
29// Fonction pour arrêter le partage d'écran
30const stopScreenShare = async () => {
31  if (!audioVideo) return;
32  
33  try {
34    await audioVideo.stopContentShare();
35    setIsScreenSharing(false);
36  } catch (err) {
37    console.error('Error stopping screen share:', err);
38  }
39};
40
41// Ajouter cet observateur dans setupVideoTileObservers
42audioVideo.addContentShareObserver({
43  contentShareDidStart: () => {
44    console.log('Content share started');
45  },
46  contentShareDidStop: () => {
47    console.log('Content share stopped');
48  }
49});
50
51// Puis ajouter un bouton dans l'interface
52<button onClick={isScreenSharing ? stopScreenShare : startScreenShare}>
53  {isScreenSharing ? 'Arrêter le partage' : 'Partager l\'écran'}
54</button>

Chat en temps réel

Ajouter un chat textuel à votre visioconférence enrichit l'interaction :

1// Ajouter ces états et fonctions à votre composant VideoMeeting
2const [messages, setMessages] = useState([]);
3const [messageInput, setMessageInput] = useState('');
4
5// Configurer la gestion des messages de données
6const setupDataMessageObservers = (av) => {
7  // S'abonner au canal de chat (topic: 'chat')
8  av.realtimeSubscribeToReceiveDataMessage('chat', (dataMessage) => {
9    const messageInfo = {
10      senderId: dataMessage.senderAttendeeId,
11      timestamp: new Date(dataMessage.timestampMs),
12      text: dataMessage.text()
13    };
14    
15    setMessages(prev => [...prev, messageInfo]);
16  });
17};
18
19// Fonction pour envoyer un message
20const sendMessage = () => {
21  if (!messageInput.trim() || !audioVideo) return;
22  
23  // Créer un encodeur de texte
24  const textEncoder = new TextEncoder();
25  // Convertir le message en tableau d'octets
26  const messageData = textEncoder.encode(messageInput);
27  
28  // Envoyer le message sur le canal 'chat'
29  audioVideo.realtimeSendDataMessage('chat', messageData);
30  
31  // Effacer l'input
32  setMessageInput('');
33};
34
35// Ajouter cet appel dans la fonction joinMeeting après avoir configuré les autres observateurs
36setupDataMessageObservers(av);
37
38// Puis ajouter ce composant d'interface à votre composant de réunion
39<div className="chat-container">
40  <h3>Chat</h3>
41  <div className="messages-container">
42    {messages.map((msg, index) => (
43      <div key={index} className="message">
44        <span className="sender">{msg.senderId === attendeeId ? 'Vous' : `Participant ${msg.senderId.substring(0, 5)}`}</span>
45        <span className="timestamp">{msg.timestamp.toLocaleTimeString()}</span>
46        <p className="message-text">{msg.text}</p>
47      </div>
48    ))}
49  </div>
50  <div className="message-input">
51    <input
52      type="text"
53      value={messageInput}
54      onChange={(e) => setMessageInput(e.target.value)}
55      placeholder="Tapez votre message..."
56      onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
57    />
58    <button onClick={sendMessage}>Envoyer</button>
59  </div>
60</div>

Sondages interactifs

Les sondages sont un excellent moyen d'engager les participants pendant une réunion :

1// Ajouter ces états et fonctions à votre composant VideoMeeting
2const [polls, setPolls] = useState([]);
3const [showPollCreator, setShowPollCreator] = useState(false);
4const [pollQuestion, setPollQuestion] = useState('');
5const [pollOptions, setPollOptions] = useState(['', '']);
6
7// Configuration pour les messages de sondage
8const setupPollObservers = (av) => {
9  // S'abonner au canal 'poll'
10  av.realtimeSubscribeToReceiveDataMessage('poll', (dataMessage) => {
11    try {
12      const pollData = JSON.parse(dataMessage.text());
13      
14      if (pollData.type === 'new_poll') {
15        // Nouvel sondage
16        setPolls(prev => [...prev, {
17          id: pollData.pollId,
18          question: pollData.question,
19          options: pollData.options,
20          votes: pollData.options.map(() => 0),
21          createdBy: dataMessage.senderAttendeeId,
22          myVote: null
23        }]);
24      } else if (pollData.type === 'vote') {
25        // Vote pour un sondage existant
26        setPolls(prev => prev.map(poll => {
27          if (poll.id === pollData.pollId) {
28            const newVotes = [...poll.votes];
29            newVotes[pollData.optionIndex] += 1;
30            return { ...poll, votes: newVotes };
31          }
32          return poll;
33        }));
34      }
35    } catch (err) {
36      console.error('Error processing poll message:', err);
37    }
38  });
39};
40
41// Fonction pour créer un nouveau sondage
42const createPoll = () => {
43  if (!pollQuestion.trim() || !audioVideo) return;
44  
45  // Filtrer les options vides
46  const validOptions = pollOptions.filter(option => option.trim() !== '');
47  if (validOptions.length < 2) return;
48  
49  const pollId = `poll-${Date.now()}`;
50  const pollData = {
51    type: 'new_poll',
52    pollId,
53    question: pollQuestion,
54    options: validOptions
55  };
56  
57  // Envoyer le sondage à tous les participants
58  const textEncoder = new TextEncoder();
59  const messageData = textEncoder.encode(JSON.stringify(pollData));
60  audioVideo.realtimeSendDataMessage('poll', messageData);
61  
62  // Réinitialiser le créateur de sondage
63  setPollQuestion('');
64  setPollOptions(['', '']);
65  setShowPollCreator(false);
66};
67
68// Fonction pour voter à un sondage
69const votePoll = (pollId, optionIndex) => {
70  if (!audioVideo) return;
71  
72  // Enregistrer le vote localement d'abord
73  setPolls(prev => prev.map(poll => {
74    if (poll.id === pollId) {
75      return { ...poll, myVote: optionIndex };
76    }
77    return poll;
78  }));
79  
80  // Envoyer le vote à tous les participants
81  const voteData = {
82    type: 'vote',
83    pollId,
84    optionIndex
85  };
86  
87  const textEncoder = new TextEncoder();
88  const messageData = textEncoder.encode(JSON.stringify(voteData));
89  audioVideo.realtimeSendDataMessage('poll', messageData);
90};
91
92// Fonction pour ajouter une option de sondage
93const addPollOption = () => {
94  setPollOptions([...pollOptions, '']);
95};
96
97// Ajouter cet appel dans la fonction joinMeeting après avoir configuré les autres observateurs
98setupPollObservers(av);
99
100// Puis ajouter ces composants d'interface
101<div className="poll-container">
102  <h3>Sondages</h3>
103  
104  {/* Liste des sondages actifs */}
105  {polls.map((poll, index) => (
106    <div key={index} className="poll">
107      <h4>{poll.question}</h4>
108      <div className="poll-options">
109        {poll.options.map((option, optIndex) => (
110          <div key={optIndex} className="poll-option">
111            <button 
112              onClick={() => votePoll(poll.id, optIndex)}
113              disabled={poll.myVote !== null}
114              className={poll.myVote === optIndex ? 'selected' : ''}
115            >
116              {option}
117            </button>
118            <div className="poll-result">
119              <div 
120                className="poll-bar" 
121                style={{ 
122                  width: `${poll.votes.reduce((a, b) => a + b, 0) > 0 ? 
123                    (poll.votes[optIndex] / poll.votes.reduce((a, b) => a + b, 0) * 100) : 0}%` 
124                }}
125              ></div>
126              <span>{poll.votes[optIndex]} votes</span>
127            </div>
128          </div>
129        ))}
130      </div>
131    </div>
132  ))}
133  
134  {/* Créateur de sondage */}
135  {showPollCreator ? (
136    <div className="poll-creator">
137      <h4>Créer un nouveau sondage</h4>
138      <input
139        type="text"
140        placeholder="Question"
141        value={pollQuestion}
142        onChange={(e) => setPollQuestion(e.target.value)}
143      />
144      {pollOptions.map((option, index) => (
145        <input
146          key={index}
147          type="text"
148          placeholder={`Option ${index + 1}`}
149          value={option}
150          onChange={(e) => {
151            const newOptions = [...pollOptions];
152            newOptions[index] = e.target.value;
153            setPollOptions(newOptions);
154          }}
155        />
156      ))}
157      <button onClick={addPollOption}>+ Ajouter une option</button>
158      <div className="poll-actions">
159        <button onClick={() => setShowPollCreator(false)}>Annuler</button>
160        <button onClick={createPoll}>Créer le sondage</button>
161      </div>
162    </div>
163  ) : (
164    <button onClick={() => setShowPollCreator(true)}>Créer un sondage</button>
165  )}
166</div>

Autres fonctionnalités interactives

AWS Chime SDK permet également d'implémenter des fonctionnalités comme les réactions emoji, les tableaux blancs collaboratifs, la transcription en temps réel, la levée de main, et bien d'autres. Chacune de ces fonctionnalités peut être construite en utilisant une combinaison de l'API de base et des messages de données en temps réel.

👍

Bonnes pratiques pour AWS Chime SDK

Pour créer une expérience de visioconférence optimale avec AWS Chime SDK, voici quelques bonnes pratiques à suivre :

Optimisation des performances

  • Gestion adaptative de la qualité vidéo : Ajustez la résolution et le framerate en fonction de la bande passante disponible

  • Mise en cache des ressources : Stockez localement les informations de réunion pour une reconnexion rapide en cas de déconnexion

  • Préchargement des bibliothèques : Chargez les bibliothèques Chime SDK à l'avance pour réduire le temps de démarrage

  • Gestion efficace des tuiles vidéo : Limitez le nombre de flux vidéo affichés simultanément pour préserver les performances

  • Optimisation des ressources média : Relâchez les ressources inutilisées (caméra, micro) lorsqu'elles ne sont pas actives

Amélioration de l'expérience utilisateur

  • Feedback visuel clair : Indiquez clairement l'état des périphériques (micro, caméra) et de la connexion

  • Tests de périphériques : Permettez aux utilisateurs de tester leur micro et caméra avant de rejoindre une réunion

  • Mode économie de données : Offrez des options pour réduire la consommation de bande passante

  • Disposition adaptative : Ajustez l'interface en fonction du nombre de participants et de la taille de l'écran

  • Gestion des erreurs élégante : Fournissez des messages d'erreur clairs et des solutions de secours

1// Exemple de test de périphériques avant la réunion
2const testAudioVideoDevices = async () => {
3  try {
4    // Créer un contrôleur de périphériques
5    const logger = new ConsoleLogger('DeviceTest', LogLevel.INFO);
6    const deviceController = new DefaultDeviceController(logger);
7    
8    // Liste des périphériques audio d'entrée (microphones)
9    const audioInputDevices = await deviceController.listAudioInputDevices();
10    console.log('Microphones disponibles:', audioInputDevices);
11    
12    // Liste des périphériques audio de sortie (haut-parleurs)
13    const audioOutputDevices = await deviceController.listAudioOutputDevices();
14    console.log('Haut-parleurs disponibles:', audioOutputDevices);
15    
16    // Liste des périphériques vidéo (caméras)
17    const videoInputDevices = await deviceController.listVideoInputDevices();
18    console.log('Caméras disponibles:', videoInputDevices);
19    
20    // Tester l'accès au microphone
21    if (audioInputDevices.length > 0) {
22      await deviceController.startAudioInput(audioInputDevices[0].deviceId);
23      console.log('Microphone connecté avec succès');
24      
25      // Créer un analyseur audio pour visualiser le niveau sonore
26      const audioAnalyserNode = deviceController.createAnalyserNodeForAudioInput();
27      // Utiliser audioAnalyserNode pour créer un indicateur de niveau sonore
28    }
29    
30    // Tester l'accès à la caméra
31    if (videoInputDevices.length > 0) {
32      await deviceController.startVideoInput(videoInputDevices[0].deviceId);
33      console.log('Caméra connectée avec succès');
34      
35      // Prévisualiser la vidéo
36      const videoElement = document.getElementById('video-preview');
37      deviceController.bindVideoElement(videoElement);
38    }
39    
40    return {
41      audioInputDevices,
42      audioOutputDevices,
43      videoInputDevices
44    };
45  } catch (err) {
46    console.error('Erreur lors du test des périphériques:', err);
47    throw err;
48  }
49};

Considérations de sécurité

  • Protection des informations de réunion : Utilisez des mécanismes d'authentification pour limiter l'accès aux réunions

  • Contrôle d'accès granulaire : Attribuez des rôles (hôte, participant) avec des permissions appropriées

  • Chiffrement des communications : Assurez-vous que toutes les communications sont chiffrées

  • Rotation des identifiants : Régénérez les jetons de présence pour les sessions de longue durée

  • Audit des événements : Enregistrez les activités importantes comme les connexions et déconnexions

🏢

Cas d'utilisation réels

AWS Chime SDK est utilisé dans de nombreux secteurs pour créer des expériences de communication personnalisées. Voici quelques cas d'utilisation concrets :

Télémédecine

Les plateformes de télémédecine utilisent AWS Chime SDK pour connecter les patients et les professionnels de santé via des consultations vidéo sécurisées. Ces solutions incluent souvent :

  • Salles d'attente virtuelles pour gérer les rendez-vous

  • Partage sécurisé de documents médicaux pendant les consultations

  • Intégration avec des systèmes de dossiers médicaux électroniques

  • Possibilité d'inviter des spécialistes pour des consultations multidisciplinaires

  • Enregistrement des sessions avec le consentement du patient pour le suivi

Exemple : Amwell

Amwell, une plateforme de télésanté leader, utilise AWS Chime SDK pour permettre aux médecins de consulter les patients à distance, réduisant ainsi les délais d'attente et améliorant l'accès aux soins, en particulier dans les zones rurales.

Éducation en ligne

Les plateformes d'apprentissage en ligne utilisent AWS Chime SDK pour créer des salles de classe virtuelles interactives avec des fonctionnalités comme :

  • Tableaux blancs interactifs pour les explications visuelles

  • Salles de sous-groupes pour les travaux collaboratifs

  • Systèmes de levée de main et de sondages pour l'engagement des élèves

  • Partage de documents et de présentations éducatives

  • Enregistrement des cours pour révision ultérieure

Service client virtuel

Les entreprises utilisent AWS Chime SDK pour offrir un support client par vidéo, créant une expérience plus personnelle et efficace :

  • Assistance vidéo intégrée directement dans les applications mobiles ou web

  • Co-navigation pour guider les clients à travers des processus complexes

  • Partage d'écran pour le dépannage technique

  • Intégration avec les systèmes CRM pour un contexte client complet

  • File d'attente intelligente et routage vers les agents appropriés

🏁

Conclusion

AWS Chime SDK représente une solution puissante et flexible pour intégrer des communications audio et vidéo en temps réel dans vos applications. Contrairement aux plateformes de visioconférence prêtes à l'emploi, Chime SDK vous donne un contrôle total sur l'expérience utilisateur, vous permettant de créer des solutions parfaitement adaptées à vos besoins spécifiques.

Les points clés à retenir incluent :

  • Flexibilité et personnalisation : Créez une expérience de communication qui s'intègre parfaitement à votre application et à votre marque

  • Évolutivité : Gérez des milliers d'utilisateurs simultanés grâce à l'infrastructure mondiale d'AWS

  • Richesse des fonctionnalités : Audio, vidéo, partage d'écran, chat, et bien plus encore dans une seule solution

  • Modèle de paiement à l'usage : Optimisez vos coûts en ne payant que pour ce que vous utilisez

  • Intégration transparente : Combinez Chime SDK avec d'autres services AWS pour des solutions complètes

Dans un monde où les communications distantes sont devenues essentielles, AWS Chime SDK offre aux développeurs les outils nécessaires pour créer des expériences de communication riches et engageantes. Que vous développiez une application de télémédecine, une plateforme éducative, ou un système de service client, Chime SDK vous permet d'intégrer des communications en temps réel de manière efficace et économique.

Pour commencer avec AWS Chime SDK, consultez la documentation officielle et explorez les exemples disponibles sur le GitHub d'AWS. N'hésitez pas à expérimenter avec les différentes fonctionnalités pour découvrir comment elles peuvent améliorer votre application.

Damien Gilbrin

Damien Gilbrin

Développeur fullstack passionné, je crée des applications web performantes et modernes grâce à mon expertise en React, Next.js, PHP Symfony et les solutions AWS.