Appearance
WebRTC avec Angular
La communication en temps réel est devenue essentielle dans nos applications web modernes. Imaginez que vous développez une application de téléconsultation médicale : les patients doivent pouvoir parler directement à leur médecin via vidéo, sans que les données sensibles ne transitent par un serveur. C'est exactement ce que permet WebRTC !
Qu'est-ce que WebRTC ?
WebRTC (Web Real-Time Communication) est une technologie qui permet aux navigateurs web de communiquer directement entre eux (peer-to-peer), sans passer par un serveur intermédiaire. C'est comme si deux personnes se parlaient directement plutôt que de passer par un intermédiaire pour transmettre leurs messages.
AVANTAGES
- Communication directe et rapide
- Sécurisé par défaut (chiffrement bout en bout)
- Parfait pour l'audio, la vidéo et le partage de données
- Réduit la charge serveur
Implémentation dans Angular
Commençons par créer un service qui gérera notre connexion WebRTC :
ts
import { Injectable, signal } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class WebRTCService {
// Signal pour gérer l'état de la connexion
private connectionState = signal<'disconnected' | 'connecting' | 'connected'>('disconnected');
// Configuration des serveurs STUN pour la négociation de connexion
private configuration: RTCConfiguration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
};
// Instance de la connexion peer-to-peer
private peerConnection: RTCPeerConnection | null = null;
// Flux local de la webcam
private localStream = signal<MediaStream | null>(null);
constructor() {
this.initializePeerConnection();
}
/**
* Initialise la connexion WebRTC avec la configuration STUN
*/
private initializePeerConnection() {
this.peerConnection = new RTCPeerConnection(this.configuration);
// Gestion des changements d'état de la connexion
this.peerConnection.onconnectionstatechange = () => {
this.connectionState.set(this.peerConnection?.connectionState as any);
};
}
/**
* Démarre la capture vidéo locale
*/
async startLocalStream() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
this.localStream.set(stream);
// Ajout des tracks au peer connection
stream.getTracks().forEach(track => {
this.peerConnection?.addTrack(track, stream);
});
return stream;
} catch (error) {
console.error('Erreur lors de l\'accès à la webcam:', error);
throw error;
}
}
}
ts
import { Component } from '@angular/core';
import { WebRTCService } from './webrtc.service';
@Component({
selector: 'app-video-chat',
template: `
<div class="video-container">
@if (localVideoStream()) {
<video #localVideo [srcObject]="localVideoStream()" autoplay playsinline></video>
}
@if (remoteVideoStream()) {
<video #remoteVideo [srcObject]="remoteVideoStream()" autoplay playsinline></video>
}
<div class="controls">
<button (click)="startCall()">Démarrer l'appel</button>
<button (click)="endCall()">Terminer l'appel</button>
</div>
</div>
`,
styles: [`
.video-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
padding: 1rem;
}
video {
width: 100%;
border-radius: 8px;
background: #000;
}
.controls {
grid-column: 1 / -1;
display: flex;
justify-content: center;
gap: 1rem;
}
`]
})
export class VideoChatComponent {
private webRTCService = inject(WebRTCService);
localVideoStream = signal<MediaStream | null>(null);
remoteVideoStream = signal<MediaStream | null>(null);
async startCall() {
try {
const stream = await this.webRTCService.startLocalStream();
this.localVideoStream.set(stream);
} catch (error) {
console.error('Erreur lors du démarrage de l\'appel:', error);
}
}
endCall() {
this.localVideoStream()?.getTracks().forEach(track => track.stop());
this.localVideoStream.set(null);
}
}
Établissement de la connexion
Pour établir une connexion WebRTC entre deux pairs, nous devons suivre un processus appelé "signaling". C'est comme si deux personnes voulaient se rencontrer et avaient besoin d'un intermédiaire pour échanger leurs coordonnées.
IMPORTANT
WebRTC ne fournit pas le mécanisme de signaling. Vous devez implémenter votre propre solution (WebSocket, HTTP, etc.) pour échanger les informations de connexion entre les pairs.
Voici comment fonctionne le processus :
- Le pair A crée une offre
- Le pair A envoie cette offre au pair B via le serveur de signaling
- Le pair B reçoit l'offre et crée une réponse
- Le pair B envoie sa réponse au pair A
- Les deux pairs échangent des candidats ICE pour établir la meilleure connexion possible
https://excalidraw.com/#json=fPn62ObxdpM-DxBMrl4k0,9eVZdzCiAXhJL7loI-on4A
Voici comment implémenter ce processus :
ts
/**
* Crée une offre de connexion
*/
async createOffer() {
if (!this.peerConnection) return;
try {
const offer = await this.peerConnection.createOffer();
await this.peerConnection.setLocalDescription(offer);
return offer;
} catch (error) {
console.error('Erreur lors de la création de l\'offre:', error);
throw error;
}
}
/**
* Traite une offre reçue et crée une réponse
*/
async handleOffer(offer: RTCSessionDescriptionInit) {
if (!this.peerConnection) return;
try {
await this.peerConnection.setRemoteDescription(offer);
const answer = await this.peerConnection.createAnswer();
await this.peerConnection.setLocalDescription(answer);
return answer;
} catch (error) {
console.error('Erreur lors du traitement de l\'offre:', error);
throw error;
}
}
Gestion des événements
WebRTC génère plusieurs événements importants que nous devons gérer :
ts
// Réception d'une nouvelle piste média
this.peerConnection.ontrack = (event) => {
// Mise à jour du flux vidéo distant
const [remoteStream] = event.streams;
this.remoteStream.set(remoteStream);
};
// Gestion des candidats ICE
this.peerConnection.onicecandidate = (event) => {
if (event.candidate) {
// Envoyer le candidat à l'autre pair via le serveur de signaling
}
};
CONSEIL
Pour une meilleure expérience utilisateur, ajoutez des indicateurs visuels pour :
- L'état de la connexion
- La qualité du réseau
- Les problèmes de périphériques
Bonnes pratiques
Gestion des erreurs : Implémentez une gestion robuste des erreurs pour les cas où :
- L'utilisateur refuse l'accès à la caméra/micro
- La connexion échoue
- Un pair se déconnecte
Adaptabilité : Utilisez les contraintes média pour s'adapter aux capacités du dispositif :
ts
const constraints = {
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { max: 30 }
},
audio: {
echoCancellation: true,
noiseSuppression: true
}
};
- Sécurité : Bien que WebRTC soit sécurisé par défaut, assurez-vous de :
- Utiliser HTTPS pour votre serveur de signaling
- Valider les pairs avant d'établir une connexion
- Implémenter un système d'authentification
POUR ALLER PLUS LOIN
- Implémentez le partage d'écran avec
getDisplayMedia()
- Ajoutez des filtres vidéo avec WebGL
- Utilisez les DataChannels pour le partage de fichiers