Voz e IA — Módulo 10: telefonía y el mundo real
Décimo módulo del Curso de Voz e IA en tiempo real: conectar un agente de voz a una llamada telefónica de verdad. SIP y WebRTC, cómo entra el audio desde el teléfono (Twilio Media Streams), el castigo del canal telefónico — 8 kHz, códecs con pérdida y ruido — y los detalles operativos que solo aparecen con llamadas reales.
☰ Índice del contenido
- La tesis del módulo
- El mapa de la telefonía
- El castigo del canal telefónico
- DTMF: los tonos del teclado
- Los detalles operativos que solo aparecen con llamadas reales
- El camino de una llamada
- SIP vs WebRTC vs Media Streams: ¿cuál uso?
- Recibir un Media Stream de Twilio por WebSocket
- Errores comunes
- La frase para llevarse
- Qué viene
- Material relacionado
En el módulo 9 montamos el agente de voz completo: un modelo que escucha y responde hablando, con la latencia bajo control y el turno bien gestionado. En tu laptop suena impecable — micrófono limpio, audio de estudio, red local. Este módulo lo saca de esa burbuja y lo conecta al canal donde de verdad se usa un agente de voz: el teléfono. Y el teléfono no es un micrófono más. Es una red que no controlas, un audio recortado a la mitad y un códec que le come agudos a la voz antes de que tu ASR la vea. El agente que brillaba en la demo tiene que sobrevivir ahora en una llamada real, con ruido de fondo, eco y paquetes perdidos.
La tesis del módulo
El teléfono es el caso de uso más grande de los agentes de voz y también el más hostil: 8 kHz de sample rate, códecs con pérdida, ruido de fondo y una red que no controlas. Un agente que suena perfecto en tu laptop puede desmoronarse en una llamada real — y la mayoría de los problemas no están en tu modelo, están en el canal por el que le llega el audio.
El mapa de la telefonía
Antes de conectar nada, hay que entender por dónde viaja una llamada y quién traduce entre mundos. Son cuatro piezas.
PSTN (Public Switched Telephone Network, la red telefónica tradicional). Es la red de los números de teléfono “de verdad”: líneas fijas, celulares, la infraestructura de las operadoras. Cuando alguien marca tu número desde su celular, la llamada nace aquí. Para efectos prácticos, es el mundo analógico/legado con el que tu agente tiene que hablar aunque él viva en la nube.
SIP (Session Initiation Protocol, protocolo de inicio de sesión). Es el protocolo de señalización: no lleva el audio, sino que negocia la llamada — quién llama a quién, con qué códec, empezar, colgar, transferir. El audio en sí viaja aparte, típicamente por RTP (Real-time Transport Protocol, el protocolo que transporta los paquetes de voz). SIP es el estándar de la telefonía IP; si conectas centrales telefónicas o trunks de operadora, hablas SIP.
WebRTC (Web Real-Time Communication). Es el equivalente de SIP+RTP pero pensado para el navegador y las apps: permite audio en tiempo real desde una página web o una app móvil sin instalar nada. No pasa por la PSTN. Es lo que usas cuando el usuario habla con tu agente desde un botón “llamar” dentro de tu web, no desde su teléfono.
Proveedores CPaaS (Communications Platform as a Service, plataformas de comunicación como servicio). Son los que unen esos mundos y te ahorran operar SIP crudo: Twilio, Telnyx, Vonage. Te dan un número, reciben la llamada de la PSTN, y te la entregan a tu servidor en un formato que puedes procesar. Son el puente entre la red telefónica y tu código.
La pregunta operativa concreta es: ¿cómo llega el audio de la llamada hasta mi agente? Hay dos caminos.
- Twilio Media Streams: el audio de la llamada se te reenvía en tiempo real por un WebSocket (una conexión bidireccional persistente sobre HTTP). Twilio maneja toda la telefonía; tú recibes paquetes de audio y devuelves paquetes de audio. Es el camino más simple para un agente de voz.
- SIP directo: tu servidor habla SIP y recibe el RTP por su cuenta. Más control y menos intermediario, pero cargas con la complejidad de la señalización, el NAT traversal y la negociación de códecs.
Ojo: SIP no lleva audio y WebRTC no toca la PSTN. Es el error de mapa más común. La señalización (SIP) y el transporte de voz (RTP) son dos flujos distintos, y una llamada desde un teléfono físico siempre pasa por la PSTN aunque tu agente sea 100% nube.
El castigo del canal telefónico
Aquí está el corazón del módulo. En el módulo 1 vimos que el audio de calidad para ASR se muestrea a 16 kHz. La telefonía te da la mitad. Cada degradación tiene un nombre, una causa y algo que puedes hacer al respecto.
8 kHz de sample rate. El canal telefónico muestrea a 8000 muestras por segundo. Por el teorema de muestreo, eso significa que solo puede representar frecuencias hasta ~4 kHz (la mitad del sample rate). La voz humana llega bastante más arriba: las consonantes fricativas — la /s/, la /f/, la /z/ — viven en los agudos, por encima de 4 kHz. La telefonía las pierde. Por eso por teléfono cuesta distinguir “seis” de “diez” o deletrear un apellido: la información que separa esos sonidos está en los agudos que el canal tiró. Tu ASR sufre exactamente lo mismo que sufre tu oído. Esto se llama audio de banda angosta (narrowband, 8 kHz) frente a banda ancha (wideband, 16 kHz).
Códecs con pérdida. El audio de voz se comprime para viajar por la red. El códec por defecto de la telefonía es G.711, también llamado μ-law (mu-law, la variante usada en Norteamérica y Japón; en Europa es A-law). G.711 es PCM a 8 kHz, 8 bits por muestra, 64 kbps — comprime poco y suena relativamente bien dentro de la banda angosta. El otro que verás es G.729: comprime muchísimo más (8 kbps) usando un modelo de la voz, pero es un códec con pérdida que degrada la señal, y si el audio se transcodifica varias veces (llamada que pasa por varios saltos) la degradación se acumula. Para tu agente, μ-law es el caso amable; G.729 es el que más castiga al ASR.
Ruido de fondo. La llamada real viene con el mundo detrás: tráfico, un local ruidoso, otra persona hablando, el viento en el celular. Tu demo no tenía nada de eso.
Eco. Si el audio que tu agente reproduce se cuela de vuelta por el micrófono del otro lado, tu propio speech vuelve a entrar. Sin cancelación de eco, el agente puede terminar “escuchándose a sí mismo” y cortándose el turno.
Recorte, pérdida de paquetes y jitter. La red no es perfecta: recorte (clipping, la señal satura y se aplana en los picos), pérdida de paquetes (packet loss, paquetes de audio que nunca llegan y dejan huecos) y jitter (variación en el tiempo de llegada de los paquetes, que obliga a un buffer y suma latencia). Nada de esto existe en tu laptop; todo existe en una llamada real.
¿Qué haces con todo esto? No hay magia, hay disciplina:
- Resamplear el audio de 8 kHz al sample rate que espera tu modelo, con conciencia de que no vas a recuperar los agudos perdidos — solo evitas que el modelo se atragante con el formato.
- Cancelación de eco y de ruido (echo cancellation, noise suppression) antes del ASR. Twilio y los CPaaS suelen ofrecerlo; si haces SIP directo, es tu problema.
- Modelos robustos: entrenados o afinados con audio telefónico, no solo con audio de estudio.
- Esperar peor WER (Word Error Rate, la tasa de error del ASR — cuántas palabras se equivoca de cada cien). El mismo modelo, sobre audio telefónico, tiene un WER más alto que sobre audio limpio, y eso hay que medirlo, no suponerlo (curso, módulo 11).
| Degradación | Causa | Qué hacer |
|---|---|---|
| Pérdida de agudos | 8 kHz corta sobre ~4 kHz | Resamplear; modelo robusto; asumir peor WER |
| Compresión con pérdida | Códec (μ-law, G.729) | Preferir μ-law; evitar transcodificaciones |
| Ruido de fondo | Entorno real del que llama | Supresión de ruido antes del ASR |
| Eco | Audio propio de vuelta | Cancelación de eco en el canal |
| Pérdida de paquetes / jitter | Red no controlada | Buffer de jitter; tolerancia a huecos |
DTMF: los tonos del teclado
DTMF (Dual-Tone Multi-Frequency, los tonos que suenan cuando marcas números en el teclado del teléfono). Sirve para capturar dígitos: el número de una tarjeta, la opción de un menú (“marque 1 para ventas”), un código. No intentes leerlos por el ASR — son tonos, no palabras, y el reconocedor de voz los va a interpretar mal. Se capturan como un evento aparte.
Hay un detalle técnico que importa: sobre G.711 los tonos DTMF viajan dentro del audio y sobreviven, pero sobre G.729 (que modela voz, no tonos puros) se destruyen. Por eso el estándar es transportarlos fuera de banda como eventos, mediante RFC 2833 / RFC 4733 (los tonos viajan como eventos RTP nombrados, no como audio). Los CPaaS te entregan el dígito ya como un evento limpio; tú solo lo recibes. La regla práctica: para datos estructurados y sensibles (una tarjeta, un RUT), prefiere DTMF sobre dictado por voz — es más confiable y no queda en la grabación de audio como número hablado.
Los detalles operativos que solo aparecen con llamadas reales
Estos no salen en ningún tutorial de “hola mundo”, pero son los que rompen tu agente en producción.
El saludo y la latencia inicial. Cuando la llamada conecta, hay un instante muerto mientras se establece el media stream. Si tu agente tarda dos segundos en decir la primera palabra, el usuario dice “¿aló?” y ya arruinaste el turno. El saludo inicial conviene tenerlo pre-generado o disparado apenas llega el evento de
start, no esperar a que el pipeline completo arranque.
Contestadoras y buzones de voz. En llamadas salientes (tu agente llama a alguien), muchas veces contesta un buzón de voz, no una persona. Un agente que le “conversa” a una contestadora es un desastre. La solución es AMD (Answering Machine Detection, detección de contestadora): en los primeros segundos se decide si contestó un humano o una máquina, para colgar o dejar un mensaje según corresponda. Los CPaaS lo ofrecen como servicio; no es perfecto, pero es indispensable en campañas salientes.
Transferencia a un humano. Ningún agente resuelve todo. Necesitas una salida limpia hacia un operador humano — transferir la llamada (vía SIP o la API del CPaaS) pasándole el contexto de lo conversado. Diseñar esa transferencia desde el día uno evita el peor final: el usuario atrapado en un loop con un agente que no entiende y sin forma de escapar.
Cumplimiento: grabación con consentimiento. Grabar una llamada es dato personal y en muchas jurisdicciones exige aviso y consentimiento (“esta llamada puede ser grabada”). El audio, las transcripciones y los datos capturados por DTMF son PII y se tratan como tal — esto engancha directo con datos, privacidad y PII. Súmale la regulación de los propios números: qué números puedes usar, en qué países, y las reglas anti-spam de llamadas salientes.
El camino de una llamada
Este es el recorrido completo, del teléfono al agente y de vuelta, marcando dónde el audio se degrada.
┌──────────┐ ┌──────────┐ ┌──────────┐
│ teléfono │ ──► │ PSTN │ ──► │ Twilio │
│ del user │ │ / SIP │ │ (CPaaS) │
└──────────┘ └──────────┘ └─────┬────┘
voz limpia 8 kHz + códec │ Media Stream
(se degrada aquí) │ WebSocket
▼
┌─────────────────┐
│ tu agente de │
│ voz │
│ decodifica μ-law│
│ ASR ─► LLM ─► │
│ TTS │
└────────┬────────┘
│ audio μ-law 8k
▼
de vuelta por el
mismo WebSocket ──► user
La lección del diagrama está en la segunda caja: el audio nace limpio en la boca del usuario y se degrada antes de llegar a tu código, en el salto por la PSTN y el códec. Cuando tu ASR falla, el instinto es tocar el modelo — pero el daño muchas veces ya venía hecho desde ese punto, y ahí no lo arreglas.
SIP vs WebRTC vs Media Streams: ¿cuál uso?
| Entra desde | Latencia | Complejidad | Cuándo | |
|---|---|---|---|---|
| SIP directo | PSTN / trunk de operadora | Baja | Alta (señalización, NAT, RTP) | Control total, volumen alto, ya tienes infra telefónica |
| WebRTC | Navegador / app | Baja | Media | El usuario habla desde tu web o app, sin número de teléfono |
| Twilio Media Streams | PSTN vía CPaaS | Media | Baja | Quieres un número real y que el proveedor cargue con la telefonía |
La regla: si el usuario llama desde su teléfono, quieres un número y el camino corto es Media Streams (o el equivalente de tu CPaaS). Si el usuario habla desde tu app o web, WebRTC. SIP directo solo si tienes volumen, equipo de telefonía y necesitas el control — no es por donde empiezas.
Recibir un Media Stream de Twilio por WebSocket
Twilio, cuando la llamada conecta, abre un WebSocket a tu servidor y te manda mensajes JSON. Los tipos son: connected (apenas se abre la conexión), start (metadatos del stream: streamSid, callSid, mediaFormat), media (el audio, en media.payload, base64 de μ-law 8 kHz), y stop (la llamada terminó). El mediaFormat reportado es {"encoding": "audio/x-mulaw", "sampleRate": 8000, "channels": 1}. Esto está verificado contra la doc de Twilio; el pipeline de más abajo es ilustrativo.
"""Esbozo ILUSTRATIVO: recibir un Media Stream de Twilio.
Twilio abre un WebSocket y envía mensajes JSON. El audio llega en
`media.payload` como base64 de μ-law a 8 kHz. Aquí lo decodificamos a
PCM lineal 16-bit y lo resampleamos para el pipeline del módulo 9.
La forma de los mensajes está verificada contra la doc de Twilio; el
resto (ASR/LLM/TTS y el reenvío) es esquemático.
"""
import asyncio
import audioop # μ-law -> PCM lineal. OJO: salió de la stdlib en Python 3.13;
# en 3.13+ instala el backport: pip install audioop-lts
import base64
import json
import websockets # servidor WebSocket
async def manejar_llamada(ws):
stream_sid = None
async for mensaje in ws:
datos = json.loads(mensaje)
evento = datos["event"]
if evento == "connected":
# Handshake inicial; aún no hay audio.
continue
if evento == "start":
# Metadatos: guarda el streamSid para poder responder.
stream_sid = datos["start"]["streamSid"]
fmt = datos["start"]["mediaFormat"]
assert fmt["encoding"] == "audio/x-mulaw" # μ-law 8 kHz
await enviar_saludo(ws, stream_sid) # dispara YA, sin esperar
elif evento == "media":
# 1) base64 -> bytes de μ-law
mulaw = base64.b64decode(datos["media"]["payload"])
# 2) μ-law -> PCM lineal 16-bit (2 = ancho de muestra en bytes)
pcm_8k = audioop.ulaw2lin(mulaw, 2)
# 3) resamplear 8 kHz -> 16 kHz para el ASR (módulo 1)
pcm_16k, _ = audioop.ratecv(pcm_8k, 2, 1, 8000, 16000, None)
# 4) al pipeline de voz del módulo 9 (ASR -> LLM -> TTS)
await alimentar_pipeline(pcm_16k)
elif evento == "stop":
break # la llamada terminó
async def responder_audio(ws, stream_sid, pcm_16k):
"""Camino inverso: PCM del TTS -> μ-law 8 kHz -> base64 -> Twilio.
El payload NO debe llevar cabeceras de archivo, solo audio crudo."""
pcm_8k, _ = audioop.ratecv(pcm_16k, 2, 1, 16000, 8000, None)
mulaw = audioop.lin2ulaw(pcm_8k, 2)
await ws.send(json.dumps({
"event": "media",
"streamSid": stream_sid,
"media": {"payload": base64.b64encode(mulaw).decode()},
}))
Tres cosas que este esbozo deja ver y que son reales: el audio entra como μ-law que hay que decodificar (no es PCM directo), el saludo se dispara en el evento start para matar la latencia inicial, y al responder tienes que volver a μ-law 8 kHz sin cabeceras de archivo — si mandas un WAV con su header, Twilio reproduce ruido. El resampleo con audioop.ratecv es correcto de forma pero básico; en producción se usa un resampler de mejor calidad. Y ojo con la versión de Python: audioop se eliminó de la biblioteca estándar en 3.13, así que en Python moderno se instala el backport audioop-lts (mismo import) o se decodifica con NumPy.
Errores comunes
- Probar solo en la laptop. El audio de estudio a 16 kHz esconde todos los problemas del canal. Un agente no está listo hasta que lo probaste sobre una llamada real, con su ruido y su códec.
- Tratar el DTMF como voz. Los tonos del teclado no son palabras; el ASR los destroza. Se capturan como evento (RFC 2833/4733), y para datos sensibles son más confiables que el dictado.
- Olvidar la latencia del saludo. Si el agente tarda en decir la primera palabra, el usuario dice “¿aló?” y el turno arranca roto. El saludo se dispara en el evento
start. - No detectar contestadoras en llamadas salientes. Un agente conversándole a un buzón de voz es tiempo y plata tirados. AMD no es opcional en campañas salientes.
- Reenviar audio a Twilio con cabecera de archivo. El
payloades audio crudo μ-law; un header de WAV suena como ruido. Es una de las fallas más frecuentes al empezar. - Sin salida a humano. El usuario atrapado en un loop con un agente que no entiende y sin escape es el peor final posible. La transferencia se diseña desde el día uno.
- Grabar sin consentimiento ni tratar el audio como PII. La grabación, la transcripción y los datos por DTMF son dato personal. El aviso y el consentimiento no son un detalle legal aparte: son parte del diseño.
La frase para llevarse
“El teléfono no le da a tu agente un micrófono peor: le da otro mundo. 8 kHz, un códec con pérdida y una red que no controlas degradan el audio antes de que tu modelo lo vea. Cuando el ASR falla en producción, mira primero el canal, no el modelo.”
Qué viene
Módulo 11: evaluar un sistema de voz. Llevamos diez módulos afirmando cosas — “el WER sube por teléfono”, “esta latencia se siente”, “este agente resiste el ruido” — sin un número que lo respalde. Vamos a medirlo de verdad: cómo se mide el WER de tu ASR sobre audio real y sobre audio telefónico, cómo se mide la latencia extremo a extremo de una conversación, cómo se evalúa la naturalidad del TTS y el manejo de turnos, y cómo montar un conjunto de llamadas de prueba que atrape una regresión antes de que la note un usuario. Sin evaluación, “mejoré el agente” es una opinión.
Material relacionado
Preguntas sobre este curso
Regístrate gratis para hacer preguntas y guardar tu progreso.
✉ Entérate de lo nuevo
Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.