Saltearse al contenido

Taller 10 - Parte 1: Central Telefónica Completa con IVR, Horarios y Colas

Construcción de una central profesional con menú IVR multinivel, validación de horarios y distribución de llamadas mediante colas

📞 Taller 10 - Parte 1: Central Telefónica Completa con IVR, Horarios y Colas

Sección titulada «📞 Taller 10 - Parte 1: Central Telefónica Completa con IVR, Horarios y Colas»

✅ Función de Horarios

Implementar validación reutilizable de horarios comerciales

✅ IVR Multinivel

Crear menú de opciones con navegación intuitiva

✅ Colas Profesionales

Configurar dos colas (ventas y soporte) con estrategias diferentes

✅ Gestión Dinámica

Login/logout automático de agentes en colas

✅ Música en Espera

Configurar MOH personalizada por departamento

✅ Grabación Automática

Integrar MixMonitor para todas las llamadas

✅ Integración CDR

Conectar con PostgreSQL para reportes avanzados

✅ Arquitectura Modular

Diseño escalable y mantenible para producción


🏢 10.1.- El Problema Real: Empresa TechSolutions

Sección titulada «🏢 10.1.- El Problema Real: Empresa TechSolutions»

La empresa TechSolutions necesita modernizar su atención telefónica. Actualmente tienen un número único donde todos contestan, generando caos y llamadas perdidas.

Horario de atención:

  • Lunes a Viernes: 9:00-18:00
  • Sábados: 9:00-13:00
  • Domingos: Cerrado

Menú IVR:

  • Opción 1: Ventas
  • Opción 2: Soporte Técnico
  • Opción 3: Administración
  • Opción 0: Operadora

Colas especializadas:

  • Cola de Ventas: 3 agentes, distribución equitativa
  • Cola de Soporte: 2 agentes, priorizar menos ocupado

Agentes asignados:

  • 1001, 1002, 1003 (Ventas)
  • 1004, 1005 (Soporte)

Requisitos adicionales:

  • Grabación: Todas las llamadas deben grabarse
  • Métricas: Integración con CDR para reportes
  • Escalabilidad: Preparado para crecimiento futuro

💾 10.2.- Preparación: Backup de Configuración

Sección titulada «💾 10.2.- Preparación: Backup de Configuración»

Antes de empezar, siempre hacemos backup. Esta es una práctica obligatoria en producción.

Terminal window
# Crear directorio de backup con timestamp
mkdir -p /root/backups/taller10
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Backup de archivos que modificaremos
cp /etc/asterisk/extensions.conf /root/backups/taller10/extensions.conf.$TIMESTAMP
cp /etc/asterisk/queues.conf /root/backups/taller10/queues.conf.$TIMESTAMP
cp /etc/asterisk/musiconhold.conf /root/backups/taller10/musiconhold.conf.$TIMESTAMP
cp /etc/asterisk/pjsip.conf /root/backups/taller10/pjsip.conf.$TIMESTAMP
# Verificar backups
ls -lh /root/backups/taller10/
Terminal window
# Crear script de restauración rápida
nano /root/backups/restore-taller10.sh
#!/bin/bash
# Script de restauración rápida
BACKUP_DIR="/root/backups/taller10"
TIMESTAMP=$1
if [ -z "$TIMESTAMP" ]; then
echo "Uso: $0 TIMESTAMP"
echo "Timestamps disponibles:"
ls -1 $BACKUP_DIR/*.conf.* | sed 's/.*\.\([0-9_]*\)/\1/' | sort -u
exit 1
fi
cp $BACKUP_DIR/extensions.conf.$TIMESTAMP /etc/asterisk/extensions.conf
cp $BACKUP_DIR/queues.conf.$TIMESTAMP /etc/asterisk/queues.conf
cp $BACKUP_DIR/musiconhold.conf.$TIMESTAMP /etc/asterisk/musiconhold.conf
cp $BACKUP_DIR/pjsip.conf.$TIMESTAMP /etc/asterisk/pjsip.conf
asterisk -rx "core reload"
echo "Restauración completada con backup: $TIMESTAMP"
Terminal window
chmod +x /root/backups/restore-taller10.sh

📱 10.3.- Configuración de Extensiones PJSIP con Wizard

Sección titulada «📱 10.3.- Configuración de Extensiones PJSIP con Wizard»

Necesitamos 5 extensiones para nuestros agentes. Usaremos PJSIP Wizard para una configuración limpia, escalable y profesional.

Terminal window
asterisk -rx "pjsip show endpoints" | grep -E "1001|1002|1003|1004|1005"

10.3.2.- Configurar pjsip.conf (Solo Global y Transport)

Sección titulada «10.3.2.- Configurar pjsip.conf (Solo Global y Transport)»

Primero, aseguramos que pjsip.conf solo tenga configuración global y de transporte:

Terminal window
nano /etc/asterisk/pjsip.conf

Verifica que contenga (o agrégalo si falta):

[global]
type=global
user_agent=TechSolutions-CallCenter
default_realm=techsolutions.local
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
local_net=192.168.1.0/24 ; Ajusta a tu red local
external_media_address=TU_IP_PUBLICA
external_signaling_address=TU_IP_PUBLICA

10.3.3.- Crear Plantilla de Agentes en pjsip_wizard.conf

Sección titulada «10.3.3.- Crear Plantilla de Agentes en pjsip_wizard.conf»

Ahora creamos la configuración de agentes usando el Wizard:

Terminal window
nano /etc/asterisk/pjsip_wizard.conf

Agregar al final (o crear el archivo si no existe):

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; AGENTES CALL CENTER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[phone-template](!)
type=wizard ; Declara una plantilla reutilizable
transport=transport-udp ; Hereda el transporte definido en pjsip.conf
accepts_auth=yes ; Genera objeto auth para autenticación
accepts_registrations=yes ; Permite que los softphones se registren
endpoint/allow=!all,ulaw,alaw,opus ; Códecs habilitados (orden de prioridad)
endpoint/context=internal ; Contexto de dialplan para agentes
endpoint/dtmf_mode=rfc4733 ; Tonos DTMF confiables para IVR
endpoint/rtp_symmetric=yes ; Solución para NAT en RTP
endpoint/force_rport=yes ; Reescribe puerto para clientes NAT
endpoint/rewrite_contact=yes ; Asegura Contact correcto
endpoint/direct_media=no ; Mantén audio en Asterisk (para grabación)
aor/max_contacts=1 ; Un dispositivo por extensión
aor/qualify_frequency=30 ; Verifica disponibilidad cada 30s
; === AGENTES DE VENTAS ===
[1001](phone-template)
endpoint/context=cat1 ; Contexto para agentes de ventas
endpoint/mailboxes=1001@default
endpoint/callerid="Juan Pérez - Ventas <1001>"
inbound_auth/username=1001
inbound_auth/password=Ventas1001!
[1002](phone-template)
endpoint/context=cat2
endpoint/mailboxes=1002@default
endpoint/callerid="María García - Ventas <1002>"
inbound_auth/username=1002
inbound_auth/password=Ventas1002!
[1003](phone-template)
endpoint/context=cat3
endpoint/mailboxes=1003@default
endpoint/callerid="Carlos López - Ventas <1003>"
inbound_auth/username=1003
inbound_auth/password=Ventas1003!
; === AGENTES DE SOPORTE ===
[1004](phone-template)
endpoint/context=cat3 ; Contexto para agentes de soporte
endpoint/mailboxes=1004@default
endpoint/callerid="Ana Martínez - Soporte <1004>"
inbound_auth/username=1004
inbound_auth/password=Soporte1004!
[1005](phone-template)
endpoint/context=cat3
endpoint/mailboxes=1005@default
endpoint/callerid="Luis Rodríguez - Soporte <1005>"
inbound_auth/username=1005
inbound_auth/password=Soporte1005!
Terminal window
asterisk -rx "pjsip reload"

El Wizard generó automáticamente los objetos. Verifica uno por uno:

1. Verificar endpoint:

Terminal window
asterisk -rx "pjsip show endpoint 1001"

Salida esperada:

Endpoint: 1001/1001 Not in use 0 of inf
OutAuth: 1001-oauth/1001
Aor: 1001 1
Transport: transport-udp udp 0 0 0.0.0.0:5060
Identify: 1001/1001

2. Verificar auth:

Terminal window
asterisk -rx "pjsip show auth 1001-iauth"

3. Verificar aor:

Terminal window
asterisk -rx "pjsip show aor 1001"

4. Verificar todos los endpoints:

Terminal window
asterisk -rx "pjsip show endpoints" | grep -E "1001|1002|1003|1004|1005"

Salida esperada:

1001/1001 Not in use 0 of inf
1002/1002 Not in use 0 of inf
1003/1003 Not in use 0 of inf
1004/1004 Not in use 0 of inf
1005/1005 Not in use 0 of inf

Configura al menos 2 softphones (Zoiper, Linphone, etc.) con estas credenciales:

Agente 1001 (Ventas):

  • Usuario: 1001
  • Contraseña: Ventas1001!
  • Servidor: IP_DE_TU_ASTERISK
  • Puerto: 5060

Agente 1004 (Soporte):

  • Usuario: 1004
  • Contraseña: Soporte1004!
  • Servidor: IP_DE_TU_ASTERISK
  • Puerto: 5060

Verificar registro exitoso:

Terminal window
asterisk -rx "pjsip show contacts"

Deberías ver:

Contact: 1001/sip:1001@192.168.1.100:5060 Avail 3.456
Contact: 1004/sip:1004@192.168.1.101:5060 Avail 2.123

🎵 10.4.- Configuración de Música en Espera (MOH)

Sección titulada «🎵 10.4.- Configuración de Música en Espera (MOH)»

Las colas necesitan música mientras los llamantes esperan. Configuraremos MOH con archivos del sistema.

Asterisk incluye archivos de audio por defecto:

Terminal window
ls -lh /var/lib/asterisk/moh/

Deberías ver archivos como:

  • macroform-cold_day.wav
  • macroform-robot_dity.wav
  • macroform-the_simplicity.wav

Si instalamos con otro usuario, debemos cambiar los permisos, en caso de root no es necesario

Terminal window
# chown -R asterisk:asterisk /var/lib/asterisk/moh/
# chmod -R 644 /var/lib/asterisk/moh/*.wav

Editar /etc/asterisk/musiconhold.conf:

Terminal window
nano /etc/asterisk/musiconhold.conf

Reemplazar todo el contenido con:

; /etc/asterisk/musiconhold.conf
; Configuración de Música en Espera para Call Center
[general]
; === CLASE DEFAULT (Para todas las colas) ===
[default]
mode=files
directory=/var/lib/asterisk/moh
sort=random ; Reproduce las pistas en orden aleatorio
sort=alpha
; === CLASE PARA VENTAS (Música más energética) ===
[ventas]
mode=files
directory=/var/lib/asterisk/moh
sort=random ; Reproduce las pistas en orden aleatorio
sort=alpha
; === CLASE PARA SOPORTE (Música más relajante) ===
[soporte]
mode=files
directory=/var/lib/asterisk/moh
sort=random ; Reproduce las pistas en orden aleatorio
sort=alpha
Terminal window
asterisk -rx "moh reload"
asterisk -rx "moh show classes"

Salida esperada:

Class: default
Mode: files
Directory: /var/lib/asterisk/moh
Class: ventas
Mode: files
Directory: /var/lib/asterisk/moh
Class: soporte
Mode: files
Directory: /var/lib/asterisk/moh

Ahora sí podemos probar la música en espera. El comando llamará al anexo 1001 y reproducirá MOH:

Terminal window
# Probar música llamando al anexo 1001
asterisk -rx "originate PJSIP/1001 application MusicOnHold default"

Probar otras clases de MOH:

Terminal window
# Probar clase "ventas"
asterisk -rx "originate PJSIP/1001 application MusicOnHold ventas"
# Probar clase "soporte"
asterisk -rx "originate PJSIP/1001 application MusicOnHold soporte"

🏢 10.5.- Configuración de Colas (queues.conf)

Sección titulada «🏢 10.5.- Configuración de Colas (queues.conf)»

Ahora configuramos las dos colas: cola-ventas y cola-soporte.

Editar /etc/asterisk/queues.conf:

Terminal window
nano /etc/asterisk/queues.conf

Reemplazar todo el contenido con:

; /etc/asterisk/queues.conf
; Configuración de Colas para TechSolutions Call Center
[general]
; === CONFIGURACIÓN GLOBAL ===
; Guardar miembros dinámicos en AstDB (persisten al reiniciar)
persistentmembers = yes
; Distribuir llamadas en paralelo (no serial)
autofill = yes
; Tipo de grabación (usaremos MixMonitor)
monitor-type = MixMonitor
; Compartir lastcall entre colas (para wrapuptime)
shared_lastcall = yes
; === PLANTILLA REUTILIZABLE ===
[plantilla-cola](!)
; Timeout para contestar (20 segundos)
timeout = 20
; Retry en X segundos si no contesta
retry = 5
; Wrapuptime: segundos después de colgar antes de nueva llamada
wrapuptime = 15
; Autopause: pausar agente si no contesta
; yes = solo en esta cola, all = en todas las colas
autopause = yes
; Autopausedelay: esperar X segundos antes de autopausar
autopausedelay = 60
; Ringinuse: NO llamar a agentes que ya están en llamada
ringinuse = no
; Joinempty: permitir entrar a cola aunque no haya agentes
joinempty = yes
; Leavewhenempty: NO sacar al llamante si todos se desloguean
leavewhenempty = no
; Timeoutpriority: priorizar timeout de config sobre dialplan
timeoutpriority = conf
; Anuncios periódicos
announce-frequency = 30
announce-holdtime = yes
announce-position = yes
periodic-announce-frequency = 60
; Service Level: llamadas atendidas en X segundos
servicelevel = 60
; Máximo de llamadas en espera
maxlen = 20
; Variables en canal
setinterfacevar = yes
setqueueentryvar = yes
setqueuevar = yes
; === COLA DE VENTAS ===
[cola-ventas](plantilla-cola)
; Estrategia: Round Robin con memoria (distribución equitativa)
strategy = rrmemory
; Música específica para ventas
musicclass = ventas
; Anuncio de bienvenida (se reproduce al entrar)
;announce = custom/bienvenida-ventas
; Máximo de llamadas en espera
maxlen = 25
; Wrapuptime más corto para ventas (ritmo rápido)
wrapuptime = 10
; === COLA DE SOPORTE ===
[cola-soporte](plantilla-cola)
; Estrategia: Fewest Calls (menos llamadas atendidas)
strategy = fewestcalls
; Música específica para soporte
musicclass = soporte
; Anuncio de bienvenida
;announce = custom/bienvenida-soporte
; Máximo de llamadas en espera
maxlen = 15
; Wrapuptime más largo para soporte (casos complejos)
wrapuptime = 20

💡 Diferencias entre las Colas

cola-ventas:

  • strategy = rrmemory → Distribución equitativa entre agentes
  • wrapuptime = 10 → Ritmo rápido, ventas son más cortas
  • maxlen = 25 → Más capacidad (ventas suelen tener más volumen)

cola-soporte:

  • strategy = fewestcalls → Prioriza al agente con menos carga
  • wrapuptime = 20 → Más tiempo para documentar casos técnicos
  • maxlen = 15 → Menos capacidad (soporte es más especializado)
Terminal window
asterisk -rx "module reload app_queue.so"
asterisk -rx "queue show"

Salida esperada:

cola-ventas has 0 calls (max 25) in 'rrmemory' strategy (0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0% within 60s
No Members
No Callers
cola-soporte has 0 calls (max 15) in 'fewestcalls' strategy (0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0% within 60s
No Members
No Callers

Crearemos funciones reutilizables en un archivo modular siguiendo las buenas prácticas del Taller 7.

10.6.1.- Concepto de la Función de Horarios

Sección titulada «10.6.1.- Concepto de la Función de Horarios»

Horarios de TechSolutions:

  • Lunes a Viernes: 9:00 - 18:00
  • Sábados: 9:00 - 13:00
  • Domingos: Cerrado

La función func-apply-open-hours retornará:

  • OPEN si estamos en horario
  • CLOSED si estamos fuera de horario

Crear el archivo de funciones auxiliares:

Terminal window
nano /etc/asterisk/extensions_functions.conf

Contenido completo:

; ============================================================================
; FUNCIÓN: Validación de Horarios de Atención (Versión con GotoIfTime)
; ============================================================================
; Esta función verifica si estamos en horario de atención
; Retorna: OPEN o CLOSED en la variable HORARIO_STATUS
; Uso: Gosub(func-apply-open-hours,s,1)
[func-apply-open-hours]
exten => s,1,NoOp(=== Validando Horario de Atención ===)
same => n,Set(HORARIO_STATUS=CLOSED) ; Por defecto: cerrado
; Verificar horarios con GotoIfTime (más simple y legible)
; Formato: GotoIfTime(horas,días_semana,días_mes,meses?etiqueta)
; Lunes a Viernes (mon-fri): 9:00 - 18:00
same => n,GotoIfTime(09:00-17:59,mon-fri,*,*?open)
; Sábado (sat): 9:00 - 13:00
same => n,GotoIfTime(09:00-12:59,sat,*,*?open)
; Si no coincide con ningún horario, queda CLOSED
same => n,Goto(closed)
same => n(open),Set(HORARIO_STATUS=OPEN)
same => n,NoOp(Resultado: ABIERTO)
same => n,Return()
same => n(closed),NoOp(Resultado: CERRADO)
same => n,Return()
; ============================================================================
; FUNCIÓN ALTERNATIVA: Validación con STRFTIME (Más control manual)
; ============================================================================
; Misma funcionalidad pero con lógica manual usando variables
; Útil si necesitas lógica más compleja o debugging detallado
[func-apply-open-hours-manual]
exten => s,1,NoOp(=== Validando Horario (Versión Manual) ===)
same => n,Set(HORARIO_STATUS=CLOSED)
same => n,Set(DIA_SEMANA=${STRFTIME(${EPOCH},,%u)}) ; 1=Lun, 7=Dom
same => n,Set(HORA_ACTUAL=${STRFTIME(${EPOCH},,%H%M)}) ; Formato: HHMM
same => n,NoOp(Día: ${DIA_SEMANA}, Hora: ${HORA_ACTUAL})
; === LUNES A VIERNES (1-5): 9:00 - 18:00 ===
same => n,GotoIf($[${DIA_SEMANA} >= 1 & ${DIA_SEMANA} <= 5]?check_weekday:check_saturday)
same => n(check_weekday),NoOp(Verificando horario de Lunes a Viernes)
same => n,GotoIf($[${HORA_ACTUAL} >= 0900 & ${HORA_ACTUAL} < 1800]?open:closed)
; === SÁBADO (6): 9:00 - 13:00 ===
same => n(check_saturday),GotoIf($[${DIA_SEMANA} = 6]?check_saturday_hours:closed)
same => n(check_saturday_hours),NoOp(Verificando horario de Sábado)
same => n,GotoIf($[${HORA_ACTUAL} >= 0900 & ${HORA_ACTUAL} < 1300]?open:closed)
; === DOMINGO (7): CERRADO ===
same => n(closed),NoOp(Resultado: CERRADO)
same => n,Return()
same => n(open),Set(HORARIO_STATUS=OPEN)
same => n,NoOp(Resultado: ABIERTO)
same => n,Return()

10.6.3.- Incluir el Archivo en extensions.conf

Sección titulada «10.6.3.- Incluir el Archivo en extensions.conf»

Editar /etc/asterisk/extensions.conf:

Terminal window
nano /etc/asterisk/extensions.conf

Verificar que tenga esta estructura (agregar lo que falte):

[general]
static=yes ; Si es 'yes', Asterisk no sobrescribe este archivo
writeprotect=no ; Ajusta a 'yes' si deseas impedir cambios desde CLI
autofallthrough=yes ; Evita que la llamada quede colgada si una extensión termina sin Hangup
clearglobalvars=no ; Mantiene las variables globales entre recargas de dialplan
priorityjumping=no ; Recomendado: evita saltos implícitos de prioridad
[globals]
IDTRUNK=TU_NUMERO_DID ; Valor que reutilizaremos como CallerID de la troncal
CONTEXT_ENTRADAS=from-trunk ; Contexto centralizado para llamadas entrantes
CONTEXT_CALLCENTER=internal ; Contexto para agentes del call center
#include extensions_anexos.conf
#include extensions_salidas.conf
#include extensions_funciones.conf
#include extensions_categorias.conf
#include extensions_entradas.conf

Crea el archivo /etc/asterisk/extensions_entradas.conf:

Terminal window
touch /etc/asterisk/extensions_entradas.conf
Terminal window
asterisk -rx "dialplan reload"
asterisk -rx "dialplan show func-apply-open-hours"

🎙️ 10.7.- Sistema de Grabación de Audios para IVR

Sección titulada «🎙️ 10.7.- Sistema de Grabación de Audios para IVR»

Antes de crear el IVR, necesitamos grabar los audios personalizados. Usaremos un método simple y efectivo que permite grabar desde cualquier extensión.

10.7.1.- ¿Por qué Grabar Audios Personalizados?

Sección titulada «10.7.1.- ¿Por qué Grabar Audios Personalizados?»

Un IVR profesional requiere mensajes claros y personalizados:

  • Bienvenida corporativa con el nombre de la empresa
  • Menú de opciones específico del negocio
  • Mensajes de horarios adaptados a tu organización

10.7.2.- Agregar Función de Grabación al Dialplan

Sección titulada «10.7.2.- Agregar Función de Grabación al Dialplan»

Editar /etc/asterisk/extensions_functions.conf y agregar al final:

; ============================================================================
; SISTEMA DE GRABACIÓN DE AUDIOS PARA IVR
; ============================================================================
; Permite grabar audios personalizados desde cualquier extensión
[func-grabar-audios]
; === GRABACIÓN DE AUDIOS (*6500) ===
exten => *6500,1,NoOp(=== Sistema de Grabación de Audios IVR ===)
same => n,Answer()
same => n,Wait(1)
same => n,Playback(beep)
same => n,Record(custom/audio%d.wav,3,30,k) ; Presionar # para finalizar
same => n,Wait(1)
same => n,Playback(beep)
same => n,Playback(${RECORDED_FILE}) ; Reproduce lo grabado
same => n,NoOp(Audio grabado: ${RECORDED_FILE})
same => n,Wait(1)
same => n,Hangup()
; === ESCUCHAR AUDIOS GRABADOS ===
; Para audios de 1 dígito: *01, *02, *03, etc.
exten => _*0X,1,NoOp(=== Reproducir Audio ${EXTEN:2} ===)
same => n,Answer()
same => n,Playback(custom/audio${EXTEN:2})
same => n,Wait(1)
same => n,Hangup()
; Para audios de 2 dígitos: *11, *12, *20, etc.
exten => _*[12]X,1,NoOp(=== Reproducir Audio ${EXTEN:1} ===)
same => n,Answer()
same => n,Playback(custom/audio${EXTEN:1})
same => n,Wait(1)
same => n,Hangup()

Editar /etc/asterisk/extensions_categorias.conf y asegurar que se incluyan las nuevas categorías

; En extensions_categorias.conf - MANTENER estructura existente
[cat1] ; Categoría con todos los permisos
include => anexos-internos ; Ya existe desde talleres previos
include => funciones-voicemail ; Ya existe desde Taller 6
include => salidas-celular ; Ya existe desde Taller 5
include => salidas-fijo
include => salidas-ldn
include => salidas-ldi
[cat2] ; Categoría solo con permisos internos y colas
include => anexos-internos
include => funciones-voicemail
include => salidas-fijo
include => salidas-celular
[cat3] ; Categoría básica
include => anexos-internos
include => funciones-voicemail
include => salidas-celular

10.7.4.- Crear Directorio para Audios Personalizados

Sección titulada «10.7.4.- Crear Directorio para Audios Personalizados»
Terminal window
# Crear directorio para audios personalizados
mkdir -p /var/lib/asterisk/sounds/custom
# Dar permisos correctos (si es necesario)
# chown -R asterisk:asterisk /var/lib/asterisk/sounds/custom
# chmod 755 /var/lib/asterisk/sounds/custom
Terminal window
# Recargar dialplan
asterisk -rx "dialplan reload"
# Verificar que la extensión existe
asterisk -rx "dialplan show func-grabar-audios"

Paso 1: Preparar el guión

Antes de grabar, escribe el texto que dirás:

AudioCódigoContenido Sugerido
audio0*00”Bienvenido a TechSolutions. Presione 1 para ventas, 2 para soporte técnico, 3 para administración, o 0 para hablar con la operadora”
audio1*01”Por favor espere, lo estamos comunicando con el departamento de ventas”
audio2*02”Por favor espere, lo estamos comunicando con soporte técnico”
audio3*03”Nuestro horario de atención es de lunes a viernes de 9 de la mañana a 6 de la tarde, y sábados de 9 de la mañana a la una de la tarde. Por favor llame en ese horario”

Paso 2: Grabar cada audio

Terminal window
# Desde tu softphone (ej: extensión 1001)
# 1. Marca *6500
# 2. Escucha el tono (beep)
# 3. Habla claramente el mensaje
# 4. Presiona # cuando termines
# 5. Escucha la reproducción para verificar
# 6. Anota el número de audio asignado

Paso 3: Verificar grabaciones

Terminal window
# Listar audios grabados
ls -lh /var/lib/asterisk/sounds/custom/
# Reproducir desde CLI (requiere sox)
apt install sox -y
play /var/lib/asterisk/sounds/custom/audio0.wav

Paso 4: Probar desde teléfono

Terminal window
# Marca *00 para escuchar audio0
# Marca *01 para escuchar audio1
# Marca *02 para escuchar audio2
# etc.

10.7.7.- Audios Recomendados para TechSolutions

Sección titulada «10.7.7.- Audios Recomendados para TechSolutions»

Para este taller, graba al menos estos 4 audios:

audio0 (*00): Mensaje de bienvenida y menú principal
audio1 (*01): "Comunicando con ventas"
audio2 (*02): "Comunicando con soporte"
audio3 (*03): Mensaje de horario cerrado

📞 10.8.- Dialplan: IVR Profesional con Background

Sección titulada «📞 10.8.- Dialplan: IVR Profesional con Background»

Ahora creamos el menú IVR usando los audios que grabamos y aprovechando Background() para respuesta inmediata.

Crear el archivo para el IVR y manejo de llamadas:

Terminal window
nano /etc/asterisk/extensions_entradas.conf

Contenido completo:

; ============================================================================
; CONTEXTO: IVR Principal con Background Profesional
; ============================================================================
; Menú de opciones con respuesta inmediata durante reproducción
; Opciones: 1=Ventas, 2=Soporte, 3=Administración, 0=Operadora
[ivr-principal]
exten => s,1,NoOp(=== IVR Principal - Caller: ${CALLERID(all)} ===)
same => n,Answer()
same => n,Wait(1)
; Configurar timeouts para mejor experiencia
same => n,Set(TIMEOUT(digit)=3) ; 3 segundos entre dígitos
same => n,Set(TIMEOUT(response)=5) ; 5 segundos para empezar a marcar
same => n,Set(IVR_RETRIES=0)
same => n,Goto(ivr-menu)
; === MENÚ PRINCIPAL ===
same => n(ivr-menu),Set(IVR_RETRIES=$[${IVR_RETRIES} + 1])
same => n,GotoIf($[${IVR_RETRIES} > 3]?ivr-timeout)
; Background permite entrada DTMF durante reproducción
same => n,Background(custom/audio0) ; Audio grabado: menú principal
same => n,WaitExten(5)
; Si no presiona nada, repetir
same => n,Playback(invalid)
same => n,Wait(1)
same => n,Goto(ivr-menu)
; === OPCIÓN 1: VENTAS ===
exten => 1,1,NoOp(=== Opción 1: Ventas ===)
same => n,Playback(custom/audio1) ; "Comunicando con ventas"
same => n,Gosub(func-apply-open-hours,s,1)
same => n,GotoIf($["${HORARIO_STATUS}" = "OPEN"]?open:closed)
same => n(open),Set(__QUEUE_NAME=cola-ventas)
same => n,Set(__QUEUE_DEPT=Ventas)
same => n,Queue(${QUEUE_NAME},tT,,,300)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
same => n(closed),Playback(custom/audio3) ; Mensaje fuera de horario
same => n,Hangup()
; === OPCIÓN 2: SOPORTE ===
exten => 2,1,NoOp(=== Opción 2: Soporte Técnico ===)
same => n,Playback(custom/audio2) ; "Comunicando con soporte"
same => n,Gosub(func-apply-open-hours,s,1)
same => n,GotoIf($["${HORARIO_STATUS}" = "OPEN"]?open:closed)
same => n(open),Set(__QUEUE_NAME=cola-soporte)
same => n,Set(__QUEUE_DEPT=Soporte)
same => n,Queue(${QUEUE_NAME},tT,,,300)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
same => n(closed),Playback(custom/audio3) ; Mensaje fuera de horario
same => n,Hangup()
; === OPCIÓN 3: ADMINISTRACIÓN ===
exten => 3,1,NoOp(=== Opción 3: Administración ===)
same => n,Playback(pls-wait)
same => n,Dial(PJSIP/1001,30,tT) ; Llamar directamente
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
; === OPCIÓN 0: OPERADORA ===
exten => 0,1,NoOp(=== Opción 0: Operadora ===)
same => n,Playback(pls-wait)
same => n,Dial(PJSIP/1001,30,tT) ; Llamar a operadora
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
; === MANEJO DE ERRORES PROFESIONAL ===
exten => t,1,NoOp(=== Timeout en IVR ===)
same => n,Goto(s,ivr-menu)
exten => i,1,NoOp(=== Opción Inválida ===)
same => n,Playback(invalid)
same => n,Wait(1)
same => n,Goto(s,ivr-menu)
exten => s-timeout,n(ivr-timeout),NoOp(=== Demasiados Intentos ===)
same => n,Playback(vm-nobodyavail)
same => n,Playback(goodbye)
same => n,Hangup()
; === MARCACIÓN DIRECTA DE EXTENSIONES ===
; Permite marcar extensiones directamente desde el IVR
exten => _1XXX,1,NoOp(=== Marcación Directa: ${EXTEN} ===)
same => n,Dial(PJSIP/${EXTEN},20,tT)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
Terminal window
asterisk -rx "dialplan reload"
asterisk -rx "dialplan show ivr-principal"
asterisk -rx "dialplan show func-apply-open-hours"
asterisk -rx "dialplan show func-grabar-audios"

  • Backup creado y script de restauración listo
  • 5 extensiones PJSIP (1001-1005) registradas correctamente
  • MOH configurado con 3 clases (default, ventas, soporte)
  • 2 colas creadas (cola-ventas, cola-soporte) sin miembros
  • Función de horarios implementada y funcional
  • Sistema de grabación de audios (*6500) operativo
  • 4 audios IVR grabados (audio0-audio3) y verificados
  • IVR con Background() respondiendo inmediatamente
  • Contexto internal usado consistentemente
  • Dialplan recargado sin errores
Terminal window
# Verificar extensiones
asterisk -rx "pjsip show endpoints" | wc -l
# Verificar MOH
asterisk -rx "moh show classes" | grep "Class:"
# Verificar colas
asterisk -rx "queue show" | grep "has 0 calls"
# Verificar dialplan
asterisk -rx "dialplan show ivr-principal" | head -5
asterisk -rx "dialplan show func-apply-open-hours" | head -5

🔧 Infraestructura Base

5 extensiones PJSIP con contexto internal consistente

🎵 Sistema de Audio

MOH especializada + Sistema de grabación de audios IVR

🏢 Colas Profesionales

2 colas con estrategias optimizadas (rrmemory y fewestcalls)

⏰ Validación de Horarios

Función reutilizable con GotoIfTime (método moderno)

📞 IVR con Background()

Respuesta inmediata durante reproducción + manejo de errores robusto

🎙️ Grabación de Audios

Sistema simple (*6500) para audios personalizados del IVR

💾 Backup System

Sistema de respaldos y restauración para producción

🔗 Arquitectura Modular

Archivos separados siguiendo convenciones de talleres previos

  • /etc/asterisk/pjsip_wizard.conf → 5 extensiones con plantilla reutilizable
  • /etc/asterisk/musiconhold.conf → 3 clases de MOH
  • /etc/asterisk/queues.conf → Colas ventas y soporte
  • /etc/asterisk/extensions_functions.conf → Horarios + Grabación de audios
  • /etc/asterisk/extensions_entradas.conf → IVR profesional
  • /etc/asterisk/extensions.conf → Configuración principal e includes

Contexto internal consistente (corregido de call-center)
Background() en lugar de Playback() para respuesta inmediata
Timeouts configurados para mejor experiencia de usuario
Validación de horarios integrada en cada opción del IVR
Sistema de grabación interno sin software externo
Manejo de errores profesional con máximo de intentos
Marcación directa de extensiones desde el IVR


🎓 Parte 2 del Taller

En la Parte 2 completaremos el sistema con:

  • Contexto de ruta entrante que simula llamadas externas
  • Handler de colas con grabación automática
  • Sistema de login/logout para agentes (*71-*76)
  • Pruebas exhaustivas del flujo completo
  • Monitoreo y métricas en tiempo real

👉 Continuar con Taller 10 Parte 2



¡Fundación de Call Center Completada!

¡Continúa con la Parte 2 para completar tu central telefónica! 🚀