Voix
(3.0.0+ — transport LiveKit, remplace le maillage WebRTC des versions 2.x) Référence complète du système vocal : rejoindre un salon vocal, diffuser de l'audio, et écouter la présence des participants. Voir aussi le guide Salons vocaux pour une introduction pas-à-pas.
Changement majeur en 3.0.0
Le SDK ne fait plus sa propre signalisation WebRTC en maillage (un RTCPeerConnection par participant) — il se connecte au SFU LiveKit self-hosted de BloumeChat, exactement comme le client web. L'API publique (VoiceConnection, play(), setState()…) reste la même dans l'esprit, mais VoicePeerConnection a disparu et l'événement audioPacket (Opus brut) est remplacé par audioFrame (PCM déjà décodé). Voir le CHANGELOG.
Notation des signatures
Les signatures sont écrites en notation TypeScript, mais s'appellent à l'identique en JavaScript — voir Utiliser le SDK en JavaScript.
VoiceManager
Accessible via client.voice. Gère la connexion vocale unique du bot — la session socket du bot ne peut être membre que d'un seul salon vocal à la fois côté serveur, VoiceManager ne suit donc jamais qu'une seule VoiceConnection.
| Propriété/Méthode | Type | Description |
|---|---|---|
connection | VoiceConnection | null (getter) | La connexion vocale active, ou null. |
join(channel, options?) | Promise<VoiceConnection> | Rejoint un salon vocal — quitte d'abord la connexion précédente si elle existe. Préférez channel.join(). |
leave() | void | Quitte le salon vocal actif, si le bot y est connecté. |
VoiceStateManager
(4.1.0+) Accessible via client.voiceStates. Cache de l'état vocal courant de chaque utilisateur connu (userPublicId → VoiceState), alimenté automatiquement par les événements voice:* (voir le guide Événements) — aucun appel réseau, aucun fetch à faire. BloumeChat n'expose aucune route REST « état vocal courant » : ce cache est la seule source pour répondre à « dans quel salon vocal est cet utilisateur ? ».
| Propriété | Type | Description |
|---|---|---|
cache | Collection<string, VoiceState> | Clé = userPublicId. Voir Collection. |
Préférez member.voice
Si vous avez déjà un Member sous la main, member.voice fait exactement client.voiceStates.cache.get(member.user.id) — plus lisible dans la plupart des cas.
Cache best-effort
Une entrée n'existe que si le bot a déjà reçu au moins un événement voice:* concernant cet utilisateur (le rejoindre un salon en fait partie). Un utilisateur en vocal avant le démarrage du bot n'y apparaîtra qu'après le prochain événement le concernant — ce n'est pas une garantie équivalente à une requête REST.
Channel.join(options?): Promise<VoiceConnection>
join(options?: VoiceJoinOptions): Promise<VoiceConnection>Rejoint ce salon vocal. Lève une BloumeChatVoiceError si channel.type !== "VOICE", ou si le serveur ne confirme pas la connexion avant options.timeoutMs.
VoiceJoinOptions
interface VoiceJoinOptions {
selfMute?: boolean; // rejoint directement en muet — défaut false
selfDeaf?: boolean; // rejoint directement en sourdine — défaut false
timeoutMs?: number; // délai max d'attente de confirmation serveur — défaut 15000
}Channel.leave(): void
Quitte ce salon vocal si le bot y est actuellement connecté (ne fait rien sinon, y compris si le salon n'est pas de type "VOICE").
VoiceConnection
Retournée par channel.join() / client.voice.join(). Étend EventEmitter.
Propriétés
| Propriété | Type | Description |
|---|---|---|
channelId | string | Identifiant public du salon vocal. |
state | "connecting" | "ready" | "destroyed" | État de la connexion. |
participants | VoiceUser[] (getter) | Snapshot courant des participants (y compris le bot). |
isPlaying | boolean (getter) | true si un flux audio est en cours de lecture (et non en pause). |
isPaused | boolean (getter) | true si la lecture est en pause. |
Méthodes — état
| Méthode | Description |
|---|---|
setState(state: VoiceStateUpdate): void | Envoie un patch d'état brut (muted, deafened, speaking…). |
setMuted(muted: boolean): void | Raccourci pour setState({ muted }). |
setDeafened(deafened: boolean): void | Raccourci pour setState({ deafened }). |
Méthodes — lecture audio
play(resource, options?): void
play(resource: string | NodeJS.ReadableStream, options?: PlayOptions): voidDécode resource (chemin de fichier, URL http(s), ou flux Readable) via FFmpeg (sauf inputType: "raw") et publie une trame PCM de 20ms toutes les 20ms sur la piste audio LiveKit du bot — LiveKit encode l'Opus et diffuse à tous les participants du salon. Interrompt toute lecture déjà en cours.
PlayOptions
interface PlayOptions {
inputType?: "auto" | "raw"; // "raw" attend un flux PCM s16le 48kHz stéréo déjà décodé — défaut "auto"
volume?: number; // multiplicateur linéaire appliqué avant l'encodage Opus — défaut 1
ffmpegArgs?: string[]; // arguments FFmpeg additionnels insérés juste après `-i <input>`
}connection.play("./musique.mp3");
connection.play("https://example.com/stream.mp3", { volume: 0.7 });
// Flux PCM brut déjà décodé (pas de passage par FFmpeg)
connection.play(pcmReadableStream, { inputType: "raw" });connection.play("./musique.mp3");
connection.play("https://example.com/stream.mp3", { volume: 0.7 });
connection.play(pcmReadableStream, { inputType: "raw" });Autres contrôles
| Méthode | Description |
|---|---|
pause(): void | Suspend la lecture (position conservée). Ne fait rien si rien ne joue. |
resume(): void | Reprend une lecture en pause. |
setVolume(volume: number): void | Ajuste le volume en cours de lecture (0 = silence, 1 = inchangé). |
stopPlaying(): void | Arrête et libère le pipeline de décodage/encodage. |
Méthodes — cycle de vie
| Méthode | Description |
|---|---|
destroy(): void | Quitte le salon et se déconnecte de LiveKit. Idempotent (sans effet si déjà détruite). Préférez channel.leave() / client.voice.leave(). |
Événements
| Event | Payload | Notes |
|---|---|---|
ready | — | Le salon LiveKit est rejoint et la piste audio du bot est publiée. |
destroyed | — | La connexion a été fermée (départ volontaire ou expulsion). |
userJoined | VoiceUser | Un autre participant a rejoint le salon (présence — indépendant du transport média). |
userLeft | userPublicId: string | Un participant est parti. |
userStateUpdate | VoiceUserStateData | État d'un participant modifié (muet, sourdine, parle, partage d'écran…). |
playerStart | — | La lecture audio démarre. |
playerFinish | — | La lecture audio se termine (fin de flux ou stopPlaying()). |
audioFrame | (userPublicId: string, samples: Int16Array, sampleRate: number, channels: number) | Trame PCM décodée reçue d'un participant — voir Audio entrant. LiveKit décode déjà l'Opus pour vous, contrairement à l'ancien audioPacket (Opus brut) — PCM directement exploitable pour de la reconnaissance vocale. |
error | Error | Erreur de connexion LiveKit ou de pipeline audio. |
Types
VoiceUser
interface VoiceUser {
userPublicId: string;
userName: string;
userTag: string;
userImage: string | null;
socketId: string;
muted: boolean;
deafened: boolean;
speaking: boolean;
joinedAt: number;
isStreaming: boolean;
isCameraOn: boolean;
cameraStreamId?: string | null;
screenStreamId?: string | null;
cameraTrackId?: string | null;
screenTrackId?: string | null;
}VoiceState
(4.1.0+) L'état vocal courant d'un utilisateur, tel que mis en cache par VoiceStateManager (client.voiceStates) et exposé par member.voice. Étend VoiceUser en y ajoutant le salon concerné.
interface VoiceState extends VoiceUser {
channelId: string;
}VoiceStateUpdate
Patch partiel accepté par connection.setState() — tous les champs sont optionnels, seuls ceux fournis sont modifiés côté serveur.
interface VoiceStateUpdate {
muted?: boolean;
deafened?: boolean;
speaking?: boolean;
isStreaming?: boolean;
isCameraOn?: boolean;
cameraStreamId?: string | null;
screenStreamId?: string | null;
cameraTrackId?: string | null;
screenTrackId?: string | null;
}VoiceUserJoinedData
interface VoiceUserJoinedData {
channelPublicId: string;
user: VoiceUser;
users: VoiceUser[]; // snapshot complet du salon au moment de l'événement
}VoiceUserStateData
interface VoiceUserStateData extends VoiceStateUpdate {
channelPublicId: string;
userPublicId: string;
}VoiceUsersSnapshot
interface VoiceUsersSnapshot {
channelPublicId: string;
users: VoiceUser[];
startedAt?: number;
}VoiceIncomingCallData
interface VoiceIncomingCallData {
channelPublicId: string;
fromUser: { userPublicId: string; userName: string; userImage: string | null };
}Toutes les exportations
import {
VoiceManager,
VoiceStateManager,
VoiceConnection,
AudioPlayer,
BloumeChatVoiceError,
} from "bloumechat";
import type {
VoiceUser,
VoiceState,
VoiceStateUpdate,
VoiceUserJoinedData,
VoiceUserLeftData,
VoiceUserStateData,
VoiceUsersSnapshot,
VoiceIncomingCallData,
VoiceCallCancelledData,
VoiceJoinOptions,
PlayOptions,
AudioResource,
VoiceConnectionState,
LiveKitTokenData,
} from "bloumechat";AudioPlayer est un détail d'implémentation
Il est exporté pour un usage avancé (inspection, tests), mais dans l'immense majorité des cas vous n'interagissez qu'avec VoiceConnection — le SDK crée et gère AudioPlayer en interne.
Voir aussi
- Guide — Salons vocaux — introduction, architecture LiveKit (SFU self-hosted), exemples pas-à-pas.
- Exemple — Bot de musique vocal
- Channel —
join()/leave(). - Gestion des erreurs —
BloumeChatVoiceError.
