Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Note
Cette fonctionnalité est actuellement en préversion publique. Cet aperçu est fourni sans accord de niveau de service et n’est pas recommandé pour les charges de travail de production. Certaines fonctionnalités peuvent ne pas être prises en charge ou avoir des fonctionnalités contraintes. Pour plus d’informations, consultez les Conditions d’utilisation supplémentaires des versions préliminaires de Microsoft Azure.
L’API Voice Live prend en charge une connexion WebRTC (Web Real-Time Communication), ce qui permet une faible latence, des interactions vocales en temps réel directement à partir de clients web et mobiles.
WebRTC fournit les fonctionnalités suivantes pour la diffusion en continu audio en temps réel :
- Latence inférieure : WebRTC est conçu pour réduire le délai, ce qui le rend plus adapté à la communication audio et vidéo où la faible latence est essentielle pour maintenir la qualité et la synchronisation.
- Gestion des médias intégrée : WebRTC prend en charge les codecs audio et vidéo intégrés, offrant ainsi une gestion optimisée des flux multimédias.
- Résilience du réseau : WebRTC inclut des mécanismes de gestion de la perte de paquets et de la gigue, qui sont essentiels pour maintenir la qualité des flux audio sur des réseaux imprévisibles.
- Connexion peer-to-peer : WebRTC établit une connexion directe entre le client et l’API Voice Live pour l’audio en temps réel, éliminant ainsi la nécessité d’un serveur intermédiaire pour relayer les données audio et réduire davantage la latence. Pendant ce temps, votre serveur conserve le contrôle total de la session : il peut envoyer des commandes, configurer le comportement et gérer les appels d’outils via le canal de signalisation WebSocket à tout moment.
Conseil
WebRTC vs WebSocket : WebRTC est recommandé pour la diffusion audio en temps réel, car il utilise le transport UDP, qui hiérarchise la vitesse et la livraison continue ( si un paquet est perdu, la lecture continue sans attendre la retransmission). Les connexions WebSocket utilisent TCP, ce qui garantit l'ordre de livraison, mais peut entraîner des retards lorsque des paquets sont perdus, car il attend la retransmission. Pour les interactions vocales en temps réel où l’audio naturel et à faible latence est critique, WebRTC offre une expérience remarquablement meilleure.
Conditions préalables
Avant d’utiliser la connexion WebRTC, découvrez comment utiliser la voix en direct pour les modèles et régions pris en charge, l’authentification et les détails de configuration de session.
Important
L’API Voice Live avec WebRTC utilise actuellement des déploiements standard globaux et achemine automatiquement les requêtes vers la région la plus proche pour optimiser la latence. Pour plus d’informations sur les régions prises en charge par la voix en direct, consultez la prise en charge des régions.
Configurer la connexion WebRTC
Dans une configuration classique, le client établit un canal de signalisation basé sur WebSocket avec l’API Voice Live pour échanger des messages d’offre/réponse SDP requis pour la négociation de session WebRTC. Une fois la négociation terminée, l’audio est transmis via des pistes multimédias RTP WebRTC.
Étape 1 : Créer un canal de contrôle
La négociation de session WebRTC est effectuée en échangeant des messages SDP (Protocole de description de session) sur un canal de contrôle WebSocket.
Lors du lancement d’une session d’appel WebRTC, utilisez le voice-live/realtime/calls point de terminaison au lieu de voice-live/realtime. Par exemple :
wss://<your-ai-foundry-resource-name>.services.ai.azure.com/voice-live/realtime/calls?api-version=2026-01-01-preview&model=gpt-realtime
Pour obtenir des instructions générales sur la configuration de WebSocket, consultez la configuration du point de terminaison WebSocket.
Étape 2 : Créer la connexion entre pairs WebRTC et procéder à un échange SDP
Dans le navigateur, utilisez des API WebRTC standard pour créer une connexion homologue et échanger SDP avec l’API Voice Live via une connexion WebSocket. L’audio est diffusé sur des pistes multimédias WebRTC, tandis que les événements non audio sont échangés séparément.
L’exemple suivant illustre une configuration minimale du navigateur.
async function setupWebRTC(signalWs, model) {
// Create peer connection
const pc = new RTCPeerConnection();
// Get microphone access
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// Setup audio playback for remote stream
const audio = document.createElement('audio');
audio.autoplay = true;
document.body.appendChild(audio);
pc.ontrack = event => {
audio.srcObject = event.streams[0];
};
// Create and set local offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// Wait for ICE candidates in SDP
await new Promise(resolve => {
if (pc.iceGatheringState === 'complete') {
resolve();
} else {
pc.addEventListener('icegatheringstatechange', () => {
if (pc.iceGatheringState === 'complete') {
resolve();
}
});
}
});
// Send offer to server
// If migrating from websocket to webrtc, you can use the same session config used in websocket
signalWs.send(JSON.stringify({
type: 'rtc.call.sdp.create',
sdp_offer: pc.localDescription.sdp
sdp_offer: pc.localDescription.sdp,
session: {
modalities: ['text', 'audio'],
instructions: 'You are a helpful assistant. Respond concisely.',
voice: { type: 'azure-realtime-native', name: 'diya' },
turn_detection: {
type: 'server_vad',
threshold: 0.5,
prefix_padding_ms: 300,
silence_duration_ms: 500
}
}
}));
// Wait for answer from server
const answer = await new Promise(resolve => {
signalWs.addEventListener('message', event => {
const message = JSON.parse(event.data);
if (message.type === 'rtc.call.sdp.created' && message.sdp_answer) {
resolve(message);
}
}, { once: true });
});
return { pc, stream, audio };
}
Pour plus d’informations sur les API WebRTC utilisées dans cet exemple, consultez RTCPeerConnection
Étape 3 : Appliquer la réponse SDP distante
Une fois la réponse SDP reçue, appliquez-la pour compléter la négociation WebRTC. Une fois la description distante définie et les vérifications de connectivité terminées, l’audio commence à circuler.
// Apply the remote SDP answer (activates WebRTC + starts audio flow)
await pc.setRemoteDescription({
type: 'answer',
sdp: answer.sdp_answer
});
Étape 4 (facultative) : Échanger des événements non audio via le canal de données
Les sessions d’API Voice Live utilisent des événements envoyés par le client à partir de votre application et des événements de cycle de vie envoyés par le serveur à partir du service. Lors de l’utilisation de WebRTC, l’audio généré par le modèle est transmis via des pistes multimédias RTP. Contrairement aux connexions webSocket, les données audio ne sont pas envoyées en tant qu’événements discrets.
Pour envoyer et recevoir des événements et des métadonnées de réponse non audio, utilisez le canal de données de la connexion homologue WebRTC.
// Data channel created on the WebRTC peer connection for non-audio events
const dataChannel = pc.createDataChannel('voice-live-events');
dataChannel.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('Event:', message.type);
};
Étape 5 (facultative) : contrôles avancés
Le canal de contrôle WebSocket est requis pour l’échange SDP initial. Une fois la négociation terminée, vous pouvez laisser le canal ouvert pour l’utiliser pour le contrôle de session (session.update), la configuration de session, la surveillance, les événements d’appel d’outil/fonction et d’autres scénarios avancés tels que le contrôle audio manuel et les interruptions. Pour plus d’informations sur la configuration et la mise à jour d’une session en direct vocale, consultez la configuration de session.
Note
Les configurations d’avatar ne sont actuellement pas prises en charge avec le contrôle de bande latérale.
Exemple de navigateur autonome
Cet exemple montre une application autonome simple qui utilise Voice Live WebRTC. Entrez votre point de terminaison Cognitive Services et votre clé API, puis connectez-vous.
Exemple de bout en bout (cliquez pour développer)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voice Live WebRTC - Starter</title>
<style>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
.container { max-width: 700px; margin: 0 auto; }
h1 { color: #1a1a2e; }
label { display: block; margin-bottom: 4px; font-weight: 500; font-size: 14px; }
input { width: 100%; padding: 10px; margin-bottom: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; }
button { padding: 12px 24px; border: none; border-radius: 6px; font-size: 14px; font-weight: 600; cursor: pointer; margin-right: 8px; }
.btn-connect { background: #10b981; color: white; }
.btn-disconnect { background: #ef4444; color: white; }
.status { padding: 10px; background: white; border-radius: 8px; margin-bottom: 16px; font-weight: 500; }
.log { font-family: monospace; font-size: 12px; background: #1a1a2e; color: #10b981; padding: 12px; border-radius: 6px; height: 300px; overflow-y: auto; white-space: pre-wrap; }
.section { background: white; padding: 20px; border-radius: 8px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
</style>
</head>
<body>
<div class="container">
<h1>🎙️ Voice Live WebRTC - Starter Example</h1>
<p style="color:#666;">Minimal working example. Edit the fields below and click Connect.</p>
<div class="section">
<label>Endpoint</label>
<input type="text" id="endpoint" value="wss://westus2.api.cognitive.microsoft.com/voice-live/realtime/calls" />
<label>API Key</label>
<input type="password" id="apiKey" placeholder="Enter your API key here" />
<label>Model</label>
<input type="text" id="model" value="azure-realtime" />
<label>Voice</label>
<input type="text" id="voice" value="ava" />
<p style="color:#666;font-size:12px;margin:-8px 0 12px;">Try these voices (name only): aarti, andrew, ava, denise, diya, elsa, florian, francisca, meera, xiaoxiao, yunxi, ximena.</p>
<label>API Version</label>
<input type="text" id="apiVersion" value="2026-01-01-preview" />
</div>
<div class="section">
<button class="btn-connect" onclick="connect()">🎤 Connect</button>
<button class="btn-disconnect" onclick="disconnect()">🔌 Disconnect</button>
<div class="status" id="status">Disconnected</div>
</div>
<div class="section">
<h3 style="margin-top:0;">Event Log</h3>
<div class="log" id="log"></div>
</div>
</div>
<script>
let pc = null, signalWs = null, localStream = null, audioEl = null;
function log(msg) {
const el = document.getElementById('log');
el.textContent = '[' + new Date().toLocaleTimeString() + '] ' + msg + '\n' + el.textContent;
}
function setStatus(s) { document.getElementById('status').textContent = s; }
// Pick a voice config that matches the selected model. The azure-realtime model
// uses native voices; other models use Azure standard voices.
function buildVoiceConfig(model, voice) {
if (model === 'azure-realtime') {
return { type: 'azure-realtime-native', name: voice || 'diya' };
}
return { type: 'azure-standard', name: voice || 'en-US-AvaNeural' };
}
async function connect() {
const endpoint = document.getElementById('endpoint').value;
const apiKey = document.getElementById('apiKey').value;
const model = document.getElementById('model').value;
const voice = document.getElementById('voice').value;
const apiVersion = document.getElementById('apiVersion').value;
if (!apiKey) { alert('Please enter your API key'); return; }
setStatus('Connecting...');
log('Starting WebRTC connection...');
try {
// 1. Create peer connection
pc = new RTCPeerConnection();
pc.onconnectionstatechange = () => {
log('WebRTC: ' + pc.connectionState);
if (pc.connectionState === 'connected') setStatus('Connected ✅ — Speak into your mic!');
if (pc.connectionState === 'failed') disconnect();
};
// 2. Audio output
audioEl = document.createElement('audio');
audioEl.autoplay = true;
document.body.appendChild(audioEl);
pc.ontrack = (e) => { audioEl.srcObject = e.streams[0]; log('Remote audio track received'); };
// 3. Microphone
localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
localStream.getTracks().forEach(t => pc.addTrack(t, localStream));
log('Microphone connected');
// 4. Data channel
const dc = pc.createDataChannel('voice-live-events');
dc.onopen = () => log('📡 Data channel open');
dc.onmessage = (e) => {
try {
const msg = JSON.parse(e.data);
log('DC: ' + msg.type);
} catch {}
};
// 5. SDP offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
await new Promise(r => {
if (pc.iceGatheringState === 'complete') r();
else pc.onicegatheringstatechange = () => { if (pc.iceGatheringState === 'complete') r(); };
setTimeout(r, 3000);
});
log('SDP offer created');
// 6. WebSocket signaling
const wsUrl = endpoint + '?api-version=' + encodeURIComponent(apiVersion) + '&model=' + encodeURIComponent(model) + '&api-key=' + encodeURIComponent(apiKey);
signalWs = new WebSocket(wsUrl, ['realtime']);
await new Promise((resolve, reject) => {
signalWs.onopen = () => { log('WebSocket connected'); resolve(); };
signalWs.onerror = () => reject(new Error('WebSocket failed'));
setTimeout(() => reject(new Error('Timeout')), 10000);
});
// 7. Send SDP offer with session config
const sdpMsg = {
type: 'rtc.call.sdp.create',
sdp_offer: pc.localDescription.sdp,
session: {
modalities: ["text", "audio"],
instructions: "You are a helpful assistant. Respond concisely.",
voice: buildVoiceConfig(model, voice),
turn_detection: { type: "server_vad", threshold: 0.5, prefix_padding_ms: 300, silence_duration_ms: 500 }
}
};
signalWs.send(JSON.stringify(sdpMsg));
log('Sent rtc.call.sdp.create with session config');
// 8. Wait for SDP answer
const answer = await new Promise((resolve, reject) => {
signalWs.onmessage = (e) => {
const msg = JSON.parse(e.data);
log('WS: ' + msg.type);
if (msg.type === 'rtc.call.sdp.created') resolve(msg);
else if (msg.type === 'error' || msg.type === 'rtc.call.error') reject(new Error(msg.error?.message || 'Error'));
};
setTimeout(() => reject(new Error('Timeout')), 30000);
});
// 9. Set remote SDP — audio flows after this!
await pc.setRemoteDescription({ type: 'answer', sdp: answer.sdp_answer });
log('🎉 WebRTC connected! SDP answer set.');
// 10. Ongoing WebSocket events
signalWs.onmessage = (e) => {
try { const msg = JSON.parse(e.data); log('WS: ' + msg.type); } catch {}
};
signalWs.onclose = () => log('WebSocket closed');
} catch (e) {
log('Error: ' + e.message);
setStatus('Error: ' + e.message);
disconnect();
}
}
function disconnect() {
if (localStream) { localStream.getTracks().forEach(t => t.stop()); localStream = null; }
if (pc) { pc.close(); pc = null; }
if (signalWs) { signalWs.close(); signalWs = null; }
if (audioEl) { audioEl.remove(); audioEl = null; }
setStatus('Disconnected');
log('Disconnected');
}
</script>
</body>
</html>
Routage des événements
Lorsque vous utilisez WebRTC, une session Voice Live WebRTC établit trois canaux de communication :
Canal de contrôle WebSocket : connexion WebSocket utilisée pour lancer la session (échange SDP). Une fois la négociation terminée, elle reste ouverte et porte les messages de contrôle de session, les notifications d’erreur et les événements d’appel d’outil/fonction qui doivent atteindre votre back-end pour le traitement afin de contrôler la session WebRTC. Ce canal est généralement initié par votre serveur à l’API Voice Live.
Canal de données WebRTC (
voice-live-events) : canal de données pair à pair sur RTCPeerConnection entre le client et l’API Voice Live. Il contient des événements de détection d'activité vocale (VAD), des événements du cycle de vie des réponses et les données de transcription. Il s’agit d’événements non audio à faible latence remis directement au client/navigateur.Piste multimédia WebRTC (RTP) : flux audio en temps réel. L’audio généré par le modèle est acheminé sur les pistes multimédias RTP sous forme de flux continu, et non sous forme d’événements de message discrets. L'audio de l'utilisateur provenant du microphone est également envoyé via RTP dans la direction opposée.
Conseil
Pour obtenir la liste complète des événements d’API en direct vocaux pris en charge, consultez la référence de l’API.
Contrôler les événements de canal
Le canal de contrôle WebSocket transporte les messages de contrôle de session et les événements d’appel d’outil/fonction.
| Événement | Direction | Description |
|---|---|---|
rtc.call.sdp.created |
Client → serveur | Réponse SDP après la création réussie de la session |
rtc.call.error |
Client → serveur | Réponse d’erreur pour toute opération ayant échoué |
session.created |
Client → serveur | Session VoiceLive établie, inclut l’ID de session et le modèle |
session.updated |
Client → serveur | Configuration de session confirmée |
error |
Client → serveur | Erreur du back-end VoiceLive |
response.function_call_arguments.delta |
Client → serveur | Arguments d’appel de fonction de streaming |
response.function_call_arguments.done |
Client → serveur | Arguments d’appel de fonction terminés |
response.output_item.added |
Client → serveur | Élément de sortie d’appel de fonction/outil ajouté |
response.output_item.done |
Client → serveur | Élément de résultat de l'appel de fonction/outil complété |
conversation.item.created |
Client → serveur | Élément de sortie d’appel de fonction créé |
Les événements d’appel de fonction et d’outil sont routés vers le webSocket de contrôle afin qu’ils puissent atteindre votre serveur principal pour le traitement. Les événements response.output_item.* et conversation.item.created sont routés vers le canal de données à la place.
Événements de canal de données (voice-live-events)
Le canal de données WebRTC contient des événements d’activité vocale, de cycle de vie de réponse et de transcription.
Événements transférés à partir du back-end VoiceLive :
| Événement | Description |
|---|---|
input_audio_buffer.speech_started |
Reconnaissance vocale de l’utilisateur détectée (VAD) |
input_audio_buffer.speech_stopped |
La parole de l'utilisateur est terminée |
response.created |
Démarrage de la génération de réponse IA |
response.done |
Génération de réponse IA terminée |
conversation.item.input_audio_transcription.completed |
Transcription vocale de l’utilisateur terminée |
conversation.item.input_audio_transcription.delta |
Transcription vocale en streaming de l'utilisateur |
response.audio_transcript.delta |
Transcription de réponse en temps réel de l'intelligence artificielle |
response.audio_transcript.done |
Transcription de réponse IA terminée |
response.text.delta |
Réponse texte en streaming |
response.text.done |
Réponse de texte terminée |
conversation.item.created |
Élément de conversation créé |
response.output_item.added |
Élément de sortie ajouté |
response.output_item.done |
Élément de sortie terminé |
Gestion des erreurs
Lorsqu’une erreur se produit, le service envoie un rtc.call.error message sur le webSocket de contrôle :
{
"type": "rtc.call.error",
"operation": "rtc.call.sdp.create",
"rtc_call_id": "session-id",
"error": {
"type": "invalid_request_error",
"code": "missing_sdp",
"message": "SDP offer is required"
}
}
Le error.type champ est soit invalid_request_error pour des erreurs client, soit server_error pour des échecs côté service. Le error.code champ contient un identificateur lisible par l’ordinateur et error.message fournit une description lisible par l’homme.
Contenu connexe
- Tester le démarrage rapide de l’API Voice Live
- Consultez la référence de l’API Voice Live