Todos los productos
Search
Centro de documentos

Alibaba Cloud Model Studio:Conexión WebRTC

Última actualización: Oct 12, 2026

Conozca el flujo de trabajo de WebRTC: prepare la autenticación, configure las direcciones de medios, intercambie SDP y eventos del modelo, y libere recursos.

WebRTC transporta audio y video en pistas multimedia, y eventos de modelo y texto a través de DataChannels. Las aplicaciones web pueden usar las API nativas del navegador; otras plataformas pueden utilizar bibliotecas WebRTC estándar. Model Studio no proporciona un SDK dedicado para WebRTC.

Requisitos previos

  • Complete los preparativos en Descripción general de la conexión.

  • Consulte Resumen de la API Realtime para confirmar la compatibilidad con WebRTC de su modelo objetivo. Las categorías compatibles incluyen interacción multimodal en tiempo real, conversaciones de voz, traducción de voz y el conjunto de interacción multimodal. Para síntesis o reconocimiento de voz, utilice AOQ o WebSocket según sea compatible con el modelo.

  • Prepare una clave API para la región y el espacio de trabajo en su servidor de aplicaciones (AppServer), que actúa como proxy para el intercambio de SDP. Para los campos de autenticación, consulte Autenticación por token.

NotaUtilice un contexto de navegador seguro y solicite permisos de micrófono o cámara según sea necesario. Gestione las restricciones de reproducción automática del navegador al recibir audio.

Flujo de trabajo

Secuencia de conexión WebRTC
  1. Prepare la clave de API y los parámetros del modelo objetivo en AppServer.
  2. Crear el objeto de conexión del cliente y registrar devoluciones de llamada.
  3. Configure las direcciones de medios y los DataChannels sin adjuntar pistas de medios ascendentes.
  4. Intercambie SDP a través de AppServer y espere a que la conexión y el canal de eventos estén listos.
  5. Configure el modelo según su protocolo. Adjunte las pistas de medios ascendentes necesarias después de la confirmación.
  6. Detenga la captura, cierre la conexión y libere los recursos cuando la interacción haya terminado.

Nota

  • Las pistas multimedia de WebRTC transportan audio y video. Su aplicación obtiene pistas multimedia locales, adjunta reproductores remotos e intercambia mensajes de DataChannel según las definiciones de eventos del modelo objetivo.

  • La autenticación de WebRTC se realiza durante el intercambio de SDP; no se requiere ningún token AOQ. Utilice AppServer como proxy para la autenticación y el SDP a fin de mantener la clave API de largo plazo fuera del código frontend.

  • Una conexión exitosa significa que el transporte está establecido, pero los medios deben esperar hasta que el modelo objetivo se inicialice correctamente. Por ejemplo, los modelos Realtime deben esperar a session.updated. El cliente puede habilitar los medios ascendentes necesarios únicamente después de que la inicialización del modelo sea exitosa.

1. Preparar autenticación y parámetros de conexión

AppServer configura el intercambio de SDP para el modelo, la región y el espacio de trabajo objetivo. Los siguientes parámetros se aplican a conexiones Realtime estándar. Para parámetros específicos de la aplicación, siga la mejor práctica correspondiente.

ConfiguraciónValor
MétodoPOST
URLhttps://{endpoint}/api/v1/webrtc/realtime?model={model_name}
Content-Typeapplication/sdp
AuthorizationBearer <API_KEY>
Cuerpo de la solicitudSDP de oferta
Respuesta exitosaSDP de respuesta

Para regiones, endpoints y autenticación, consulte Autenticación por token. Implemente la interfaz de AppServer en su aplicación; no es una API del SDK de Model Studio.

2. Inicializar el objeto de conexión y registrar devoluciones de llamada

Cree un RTCPeerConnection en el navegador o inicialice la biblioteca correspondiente en otra plataforma. Antes de conectarse, registre controladores para:

  • Cambios en el estado de la conexión, incluidos éxito, fallo y desconexión.

  • Creación, apertura, mensajes y cierre de DataChannel.

  • Pistas de medios remotos para recibir y reproducir audio o video.

const pc = new RTCPeerConnection({ iceServers: [ ] });

const channels = new Set();
const senders = new Map();
const remoteAudio = document.createElement("audio");
remoteAudio.controls = true; // Allow manual playback if autoplay is blocked.
remoteAudio.autoplay = true;
document.body.appendChild(remoteAudio);

let localStream = null;
let eventChannel = null;
let stopped = false;
let started = false;
let sessionCreated = false;
let updateSent = false;
let modelReady = false;
let mediaStarted = false;
const requestController = new AbortController();

Registre los listeners de mensajes antes de inicializar el modelo para no perder eventos de sesión iniciados por el servidor. No escuche únicamente el canal creado por el cliente: el servidor envía eventos en un canal llamado txt, así que gestione también el callback datachannel.

3. Configurar direcciones de medios y DataChannels

Seleccionar direcciones de medios

Las direcciones son relativas al cliente. Los transceptores WebRTC negocian el envío y la recepción: sendrecv es bidireccional, sendonly solo envía y recvonly solo recibe. Las capacidades disponibles también dependen de la respuesta SDP del servidor y de la compatibilidad del modelo.

DirecciónConfiguración
Enviar audioNegociar la transmisión de audio y preparar un micrófono o una pista de audio externa; adjuntarla después de que el modelo esté listo
Recibir audioNegociar la recepción de audio y adjuntar la reproducción en la devolución de llamada de pista remota
Enviar videoNegociar la transmisión de video solo si el modelo admite entrada visual; preparar una cámara o una pista de video externa
Recibir videoNegociar la recepción e implementar la renderización solo si el modelo o la aplicación admiten explícitamente la salida de video

Las conversaciones de voz generalmente requieren audio bidireccional; la entrada visual requiere además video ascendente. El SDP de oferta debe incluir una sección de medios m=audio. No la elimine simplemente porque la aplicación no necesite reproducción de audio.

Elegir direcciones para su modelo

Modelo o aplicaciónEnviar audioRecibir audioEnviar videoRecibir video
Qwen-Omni-RealtimePara entrada de vozPara respuestas habladasPara entrada visualNo compatible
Qwen-Audio-RealtimePara conversaciones de vozPara respuestas habladasNo compatibleNo compatible
Qwen-LiveTranslate-RealtimePara entrada de vozPara traducciones habladasDepende de la versión y el escenarioNo compatible
multimodal-dialogBasado en la entrada de la aplicaciónBasado en la salida de la aplicaciónBasado en las capacidades de la aplicaciónSolo si la aplicación lo admite explícitamente

Esta tabla describe las direcciones de medios requeridas por la aplicación; no garantiza que cada combinación pueda negociarse de forma independiente. La configuración depende del modelo objetivo y de las capacidades de negociación del servidor.

Preparar medios sin enviarlos

Negocie las direcciones necesarias antes de crear la oferta. Para modelos que requieren confirmación de inicialización, reserve capacidades de envío sin adjuntar pistas capturadas. Una vez que el modelo esté listo, utilice replaceTrack en el remitente correspondiente para iniciar la transmisión. Registre previamente los controladores de recepción de medios.

Configure de forma independiente el envío de audio, la recepción de audio, el envío de video y la recepción de video. Abrir el micrófono, reproducir audio e inicializar el modelo son operaciones separadas.

Ejemplo de configuración de medios

Este ejemplo utiliza audio bidireccional con video ascendente opcional. Los cuatro interruptores media expresan los requisitos de la aplicación. Habilite la recepción de video únicamente si la aplicación objetivo lo admite explícitamente. addTransceiver negocia las direcciones con antelación; las pistas capturadas permanecen locales hasta que se adjuntan a los remitentes tras la disponibilidad del modelo.

const media = {
  sendAudio: true,
  receiveAudio: true,
  sendVideo: false,
  receiveVideo: false,
};

function mediaDirection(send, receive) {
  if (send && receive) return "sendrecv";
  if (send) return "sendonly";
  if (receive) return "recvonly";
  return "inactive";
}

async function configureMedia() {
  for (const kind of ["audio", "video"]) {
    const send = kind === "audio" ? media.sendAudio : media.sendVideo;
    const receive = kind === "audio" ? media.receiveAudio : media.receiveVideo;
    // Keep m=audio; the target service must support the selected directions.
    if (kind === "audio" || send || receive) {
      const transceiver = pc.addTransceiver(kind, {
        direction: mediaDirection(send, receive),
      });
      if (send) senders.set(kind, transceiver.sender);
    }
  }
  if (!media.sendAudio && !media.sendVideo) return;
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: media.sendAudio,
    video: media.sendVideo ? {
      width: { ideal: 640 }, height: { ideal: 480 },
      frameRate: { ideal: 2, max: 2 },
    } : false,
  });
  // The user may end the session while the permission prompt is open.
  if (stopped) {
    stream.getTracks().forEach(track => track.stop());
    throw new Error("Session ended");
  }
  localStream = stream;
  // sender.track is still null; captured data is not sent to the model.
}

Configure la resolución de video y la tasa de cuadros según el modelo objetivo. Si las tasas de cuadros de la vista previa local y de la transmisión ascendente deben diferir, consulte la implementación de Canvas en la mejor práctica.

Crear canales de eventos

Cree un DataChannel antes de la oferta para que el SDP incluya la negociación del canal de datos. Para canales creados por el cliente y por el servidor, consulte las mejores prácticas de WebRTC a continuación.

Los DataChannels transportan la inicialización del modelo, texto y eventos de control, y devuelven resultados, estado y errores del modelo. Las pistas multimedia transportan audio y video.

// See Send and receive events over DataChannels for bindDataChannel.
pc.ondatachannel = ({ channel }) => bindDataChannel(channel);
const clientChannel = pc.createDataChannel("oai-events");
bindDataChannel(clientChannel);

4. Establecer la conexión

  1. Llame a createOffer y setLocalDescription.
  2. Recopile candidatos mediante un modo ICE compatible con el servidor. Este ejemplo espera a que finalice la recopilación de ICE antes de enviar el SDP local.
  3. Envíe el SDP local a AppServer, que llama al endpoint de intercambio de SDP de Model Studio con la clave de API.
  4. Verifique el estado HTTP. Si tiene éxito, pase el SDP de respuesta devuelto a setRemoteDescription.
  5. Espere a que la conexión tenga éxito y confirme que el DataChannel utilizado para enviar eventos del modelo esté abierto.

Un intercambio de SDP exitoso o la finalización de setRemoteDescription solo completa ese paso de negociación; no garantiza que la conexión multimedia esté lista. No se pueden enviar eventos del modelo hasta que el DataChannel esté open.

Código de conexión y devoluciones de llamada de estado

Escuche connectionstatechange para determinar el estado de la conexión y icegatheringstatechange para esperar el SDP local completo. La inicialización del modelo también depende de que el DataChannel esté abierto y de los eventos del modelo; el intercambio de SDP por sí solo es insuficiente.

pc.onconnectionstatechange = () => {
  console.log("WebRTC state:", pc.connectionState);
  if (pc.connectionState === "connected") {
    tryInitializeModel();
  } else if (["failed", "disconnected", "closed"].includes(pc.connectionState)) {
    // This example ends the session; implement recovery as needed.
    endSession();
  }
};

function waitForIceComplete() {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => finish(new Error("ICE gathering timed out")), 15000);
    function finish(error) {
      clearTimeout(timer);
      pc.removeEventListener("icegatheringstatechange", check);
      requestController.signal.removeEventListener("abort", cancel);
      error ? reject(error) : resolve();
    }
    function check() {
      if (pc.iceGatheringState === "complete") finish();
    }
    function cancel() { finish(new Error("Session ended")); }
    pc.addEventListener("icegatheringstatechange", check);
    requestController.signal.addEventListener("abort", cancel, { once: true });
    if (stopped) cancel();
    else check();
  });
}

function normalizeAnswerSdp(sdp) {
  return String(sdp).trim().replace(/\r?\n/g, "\r\n") + "\r\n";
}

async function startSession() {
  if (started || stopped) return;
  started = true;
  try {
    await configureMedia();
    if (stopped) return;
    const offer = await pc.createOffer();
    await pc.setLocalDescription(offer);
    await waitForIceComplete();

    // Implement this same-origin application endpoint; it is not a Model Studio API.
    // AppServer forwards SDP with the API key and returns the raw Answer SDP.
    const response = await fetch("/api/realtime/sdp", {
      method: "POST",
      headers: { "Content-Type": "application/sdp" },
      body: pc.localDescription.sdp,
      signal: requestController.signal,
    });
    if (!response.ok) {
      throw new Error(`SDP exchange failed:${response.status} ${await response.text()}`);
    }
    const answerSdp = normalizeAnswerSdp(await response.text());
    if (stopped) return;
    await pc.setRemoteDescription({ type: "answer", sdp: answerSdp });
    // Continue through connectionstatechange, DataChannel, and model events.
  } catch (error) {
    if (!stopped) console.error("Connection failed:", error);
    endSession();
  }
}

AppServer debe reenviar la oferta utilizando el endpoint y los encabezados de la sección 1. La interfaz de ejemplo devuelve texto SDP sin formato. No pase encabezados HTTP, registros ni un contenedor JSON a setRemoteDescription.

5. Intercambiar eventos del modelo y medios

Inicializar el modelo

Cuando la conexión y el canal de eventos estén disponibles, inicialice el modelo objetivo según su protocolo. Almacene los eventos de inicialización del servidor y combínelos con el estado del canal para avanzar en el flujo; no asuma un orden fijo de llegada de callbacks.

Por ejemplo, los modelos configurados con session.update requieren un evento que siga su protocolo y una confirmación antes de enviar la entrada. Obtenga los parámetros de voz, modalidades de salida, VAD y tasa de muestreo de la documentación actual del modelo. El conjunto de interacción multimodal utiliza su propio protocolo de eventos.

session.created significa que la sesión fue creada, no necesariamente que la configuración haya surtido efecto. Para modelos que requieren confirmación de configuración de sesión, espere a session.updated. Otros modelos o aplicaciones tienen sus propias condiciones de disponibilidad.

La navegación de modelos en Resumen de conexión WebSocket incluye enlaces a las definiciones de eventos. Reutilice únicamente esas definiciones; el transporte de medios y las restricciones de WebRTC siguen rigiéndose por esta página.

Ejemplo de evento del modelo: Omni

Este ejemplo demuestra el flujo session.created → session.update → session.updated de Omni. Para otros modelos, reemplace el evento de inicialización y la gestión de respuestas según sus definiciones de eventos vinculadas a continuación. Adjunte pistas multimedia ascendentes únicamente después de que session.updated confirme la configuración.

function tryInitializeModel() {
  if (stopped || updateSent || !sessionCreated ||
      pc.connectionState !== "connected" ||
      eventChannel?.readyState !== "open") return;
  sendModelEvent({
    event_id: `event_${crypto.randomUUID()}`,
    type: "session.update",
    session: {
      modalities: media.receiveAudio ? ["text", "audio"] : ["text"],
      input_audio_format: "pcm",
      output_audio_format: "pcm",
      turn_detection: { type: "server_vad", threshold: 0.5,
                        silence_duration_ms: 800 },
    },
  });
  updateSent = true;
}

async function handleModelEvent(event, channel) {
  if (stopped) return;
  if (event.type === "session.created") {
    sessionCreated = true;
    eventChannel = channel; // Send configuration on the channel that delivered the session event.
    tryInitializeModel();
  } else if (event.type === "session.updated" && updateSent) {
    modelReady = true;
    await startSendingMedia();
  } else if (event.type === "error") {
    console.error("Model error:", event.error);
    endSession();
  } else {
    // Handle text, transcripts, and response state; receive audio on media tracks.
    console.log("Model event:", event);
  }
}

Iniciar transmisión y recepción de medios

Una vez que el modelo esté listo, adjunte las pistas de audio y video necesarias para la transmisión ascendente. Gestione la salida del modelo en el callback de pista remota y continúe analizando los eventos del DataChannel.

  • El audio viaja a través de pistas de medios RTP; no se requiere el evento input_audio_buffer.append.

  • Las imágenes viajan a través de pistas de video. WebRTC no admite input_image_buffer.append.

  • Los DataChannels transportan eventos de texto, estado, control y error.

async function startSendingMedia() {
  if (stopped || !modelReady || mediaStarted) return;
  mediaStarted = true;

  for (const track of localStream?.getTracks() ?? []) {

    if (stopped) return;
    const sender = senders.get(track.kind);
    if (sender) await sender.replaceTrack(track);
  }
}

// Register before startSession(); also handle tracks with no streams.
const remoteAudioStream = new MediaStream();
const remoteVideo = media.receiveVideo ? document.createElement("video") : null;
if (remoteVideo) {
  remoteVideo.autoplay = true;
  remoteVideo.playsInline = true;
  remoteVideo.controls = true;
  document.body.appendChild(remoteVideo);
}
pc.ontrack = ({ track }) => {
  if (stopped) return;
  if (track.kind === "audio" && media.receiveAudio) {
    remoteAudioStream.addTrack(track);
    remoteAudio.srcObject = remoteAudioStream;
    remoteAudio.play().catch(() => {
      console.info("Autoplay blocked. Use the audio controls to play.");
    });
  }
  if (track.kind === "video" && remoteVideo) {
    remoteVideo.srcObject = new MediaStream([track]);
    remoteVideo.play().catch(() => console.info("Use the video controls to play."));
  }
};

6. Finalizar interacción y liberar recursos

Cuando ya no se necesite la conexión, detenga las pistas de captura locales propiedad de su aplicación, cierre los DataChannels y la RTCPeerConnection, libere los reproductores y borre el estado de la aplicación.

Restablezca el estado de disponibilidad del modelo tras una desconexión fallida o inesperada. Inicialice el modelo nuevamente en una nueva conexión en lugar de reutilizar el estado de sesión de la conexión anterior.

function endSession() {
  if (stopped) return;
  stopped = true;
  modelReady = false;
  sessionCreated = false;
  updateSent = false;
  mediaStarted = false;
  requestController.abort(); // Cancel the pending SDP request and ICE wait.
  localStream?.getTracks().forEach(track => track.stop());
  localStream = null;
  channels.forEach(channel => channel.close());
  channels.clear();
  eventChannel = null;
  pc.close();
  senders.clear();
  remoteAudioStream.getTracks().forEach(track => track.stop());
  remoteAudio.pause();
  remoteAudio.srcObject = null;
  remoteAudio.remove();
  if (remoteVideo) {
    remoteVideo.srcObject?.getTracks().forEach(track => track.stop());
    remoteVideo.pause();
    remoteVideo.srcObject = null;
    remoteVideo.remove();
  }
}

Llame a endSession() cuando el usuario finalice la llamada o abandone la página. Si su aplicación incorpora las funciones de Canvas o grabación de la mejor práctica, cancele también los bucles de animación y detenga las pistas multimedia de Canvas y el MediaRecorder.

Enviar y recibir eventos a través de DataChannels

Verifique que el canal esté open antes de llamar a send con un evento serializado. Analice los mensajes entrantes en su callback message, incluidos los eventos en canales creados por el servidor.

Siga las definiciones de eventos del cliente del modelo objetivo para los nombres, campos, parámetros y tiempos de los eventos salientes. Siga sus definiciones de eventos del servidor para el análisis de respuestas, cambios de estado, resultados y errores. Envíe eventos de inicialización según lo requiera el modelo y eventos posteriores de texto y control según lo requiera su aplicación.

Ejemplo de DataChannel

Utilice la misma función de enlace para canales creados por el cliente y por el servidor. Esta gestiona el transporte y el análisis JSON; handleModelEvent en la sección 5 gestiona la semántica del modelo. Utilice sendModelEvent para la inicialización del modelo, texto o eventos de control únicamente cuando lo permita el protocolo del modelo.

function sendModelEvent(event, channel = eventChannel) {
  if (stopped || pc.connectionState !== "connected" ||
      channel?.readyState !== "open") {
    throw new Error("Data channel is not ready");
  }
  channel.send(JSON.stringify(event));
}

function bindDataChannel(channel) {
  channels.add(channel);
  channel.onopen = () => {
    if (stopped) return;
    console.log("DataChannel opened:", channel.label);
    tryInitializeModel();
  };
  channel.onmessage = ({ data }) => {
    if (stopped) return;
    let event;
    try { event = JSON.parse(data); }
    catch (error) {
      console.warn("Cannot parse model event:", error);
      return;
    }
    if (!event || typeof event !== "object") return;
    handleModelEvent(event, channel).catch(error => {
      if (!stopped) console.error("Model event handling failed:", error);
      endSession();
    });
  };
  channel.onerror = error => console.error("DataChannel error:", error);
  channel.onclose = () => {
    channels.delete(channel);
    if (channel === eventChannel) endSession();
  };
  if (channel.readyState === "open") channel.onopen();
}

Coloque todos los fragmentos en el mismo script. Después de registrar todas las declaraciones y callbacks, llame a startSession() desde el controlador del botón de inicio y a endSession() desde el controlador del botón de finalización. Estas son funciones de ejemplo, no API integradas de WebRTC.

Definiciones de eventos del modelo

Modelo o aplicaciónEventos del cliente (envío)Eventos del servidor (recepción)
Qwen-Omni-RealtimeEventos del clienteEventos del servidor
Qwen-Audio-RealtimeEventos del clienteEventos del servidor
Qwen-LiveTranslate-RealtimeEventos del clienteEventos del servidor
multimodal-dialogMensaje de entrada en el protocolo de interacciónMensaje de salida en el protocolo de interacción

El conjunto de interacción multimodal define ambas direcciones en un único protocolo de interacción. Seleccione las definiciones de eventos correspondientes a la versión real del modelo; los modelos no comparten un esquema de eventos fijo.

Siga también estas reglas:

  • Identifique los tipos de eventos y los identificadores de correlación según el modelo. Los eventos Realtime suelen utilizar type; el conjunto de interacción multimodal utiliza header.action para eventos del cliente, header.event para eventos del servidor y task_id para la correlación.

  • Gestione la confirmación de inicialización, el envío de entradas, la cancelación de respuestas y la finalización de tareas a través de DataChannels según lo requiera el protocolo. Estas operaciones son distintas del cierre de la conexión de transporte.

  • Los medios utilizan pistas multimedia. Al consultar la documentación de eventos del modelo, siga esta página de WebRTC para el transporte de medios y los modos de interacción disponibles; no copie los mecanismos de carga de medios de WebSocket.

Mejores prácticas