El archivo features.conf es uno de los componentes fundamentales en la configuración de Asterisk PBX, ya que define las funcionalidades de llamada que los usuarios pueden activar mediante secuencias DTMF durante una conversación activa. Estas características incluyen transferencias, grabación y otras funciones avanzadas que enriquecen la experiencia telefónica.
El archivo features.conf controla las funcionalidades en llamada (in-call features) que permiten a los usuarios manipular llamadas activas sin necesidad de colgar. Las principales funcionalidades que gestiona son:
Transferencias de llamadas: Permite transferir una llamada a otra extensión, ya sea de forma ciega (blind transfer) o atendida (attended transfer).
Grabación de llamadas: Activa o desactiva la grabación de conversaciones durante la llamada mediante códigos DTMF.
Desconexión de llamadas: Permite a cualquiera de las partes finalizar la llamada mediante una secuencia específica.
Características personalizadas: Define funcionalidades adicionales mediante aplicaciones dialplan que se activan con códigos DTMF.
Pickup de llamadas: Permite contestar llamadas que están sonando en otras extensiones.
Configuración del archivo features.conf
El archivo features.conf se estructura en varias secciones principales. A continuación se detalla cada una con ejemplos prácticos:
Sección [general]
Esta sección contiene parámetros globales que afectan al comportamiento general de las características:
[general]
transferdigittimeout = 3
atxfernoanswertimeout = 15
atxferdropcall = no
atxferloopdelay = 10
atxfercallbackretries = 2
courtesytone = beep
xfersound = beep
xferfailsound = beeperr
pickupexten = *8
pickupsound = beep
pickupfailsound = beeperr
featuredigittimeout = 2000
transferdialattempts = 3
transferretrysound = beep
transferinvalidsound = beeperr
transferdigittimeout: Tiempo en segundos para ingresar dígitos durante una transferencia (por defecto 3 segundos). Si el usuario no completa la marcación de la extensión destino en este tiempo, la operación se cancela.
atxfernoanswertimeout: Tiempo de espera en segundos cuando no se contesta una transferencia atendida (por defecto 15 segundos). Si el destino no contesta, la llamada puede regresar al origen.
atxferdropcall: Define si se cuelga la llamada original cuando falla una transferencia atendida. Valores: yes/no (por defecto: no).
atxferloopdelay: Retraso en segundos antes de reintentar una transferencia fallida.
atxfercallbackretries: Número de intentos para devolver la llamada al origen cuando falla una transferencia atendida.
courtesytone: Tono que se reproduce a ambas partes antes de reconectar después de una transferencia atendida. Puede ser "beep", un archivo de sonido personalizado, o estar vacío.
xfersound: Tono que se reproduce al iniciar una transferencia exitosa.
xferfailsound: Tono que se reproduce cuando una transferencia falla.
pickupexten: Código para contestar llamadas de otras extensiones (call pickup). El valor por defecto es *8.
pickupsound: Tono que se reproduce al realizar un pickup exitoso.
pickupfailsound: Tono que se reproduce cuando el pickup falla.
featuredigittimeout: Tiempo en milisegundos para esperar entre dígitos al activar una característica (por defecto 2000ms). Este parámetro es crítico para la detección correcta de códigos DTMF.
transferdialattempts: Número de intentos permitidos para marcar el destino durante una transferencia.
transferretrysound: Tono reproducido cuando se puede reintentar la transferencia.
transferinvalidsound: Tono reproducido cuando se marca una extensión inválida durante la transferencia.
Sección [featuremap]
Define los códigos DTMF para activar cada funcionalidad. Esta es la sección más importante del archivo:
[featuremap]
blindxfer => *1
atxfer => *2
disconnect => *0
automon => *3
automixmon => *4
blindxfer: Código para transferencia ciega (blind transfer). El usuario marca el código, introduce la extensión destino y la llamada se transfiere inmediatamente sin hablar con el destino. El formato es: durante la llamada, presionar *1, marcar extensión destino, la transferencia se completa automáticamente.
atxfer: Código para transferencia atendida (attended transfer). El usuario marca el código, habla con el destino antes de completar la transferencia y puede cancelarla si es necesario. El proceso es: presionar *2, marcar extensión, hablar con el destino, colgar para completar o presionar * para cancelar.
disconnect: Permite colgar la llamada desde cualquiera de los extremos. Útil cuando los endpoints no tienen un botón de colgar confiable o en conferencias.
automon: Activa la grabación de la llamada usando la aplicación Monitor. Graba los canales por separado (entrada y salida en archivos diferentes).
automixmon: Activa la grabación usando MixMonitor, que mezcla ambos canales en un solo archivo. Este es el método preferido en versiones modernas de Asterisk.
Códigos adicionales disponibles:
- disconnect: Desconecta la llamada
- parkcall: Estaciona la llamada (requiere configuración adicional de parking)
- atxferthreeway: Crea conferencia de tres vías durante transferencia atendida
Sección [applicationmap]
Permite crear funcionalidades personalizadas que ejecutan aplicaciones del dialplan. Esta sección es extremadamente poderosa para extender las capacidades de Asterisk:
[applicationmap]
pauseagent => *5,self/caller,Pause()
unpauseagent => *6,self/caller,Unpause()
togglehold => *7,self,Macro(toggle-hold)
conference => *9,peer,ConfBridge(${EXTEN})
La sintaxis es: nombre => código,activador,aplicación(argumentos)
Parámetros de activador:
- caller: Solo el que llama puede activar la característica
- callee: Solo el que recibe puede activar la característica
- both: Cualquiera de las dos partes puede activarla
- self: La característica afecta al canal que la activa
- peer: La característica afecta al canal de la otra parte
- self/caller: Combinación que especifica que afecta a quien llama si es el caller
Ejemplos prácticos:
[applicationmap]
; Pausar/despausar agente en cola
pauseagent => *5,self,PauseQueueMember(,Local/${CALLERID(num)}@from-internal)
unpauseagent => *6,self,UnpauseQueueMember(,Local/${CALLERID(num)}@from-internal)
; Enviar llamada a buzón de voz
sendtovm => *8,self,VoiceMail(${EXTEN}@default,s)
; Agregar la llamada a una conferencia existente
addtoconf => *9,both,ConfBridge(sala1)
; Activar/desactivar spy en otro canal
startspy => #1,self,ChanSpy(PJSIP,q)
; Ejecutar una macro personalizada
customaction => **1,caller,Macro(custom-action,${EXTEN})
; Activar/desactivar grabación con MixMonitor
togglerecord => *3,both,System(/usr/local/bin/toggle-recording.sh ${CHANNEL})
Variables de canal importantes
Durante la ejecución de características personalizadas, Asterisk proporciona variables especiales:
- ${DYNAMIC_FEATURES}: Lista de características dinámicas habilitadas para el canal
- ${DYNAMIC_WHO_ACTIVATED}: Quién activó la característica (caller/callee)
- ${CHANNEL}: Canal actual
- ${BRIDGEPEER}: Canal del peer conectado
Sección [featuregroups]
Permite agrupar características en conjuntos reutilizables:
[featuregroups]
agentfeatures => pauseagent,unpauseagent,togglerecord
managerfeatures => #startspy,#addtoconf,#togglerecord
customerfeatures => #blindxfer
Para activar un grupo de características en un canal, se usa:
; En el dialplan
same => n,Set(DYNAMIC_FEATURES=agentfeatures)
same => n,Dial(PJSIP/${EXTEN})
Integración con pjsip.conf
La integración de features.conf con los endpoints definidos en pjsip.conf es crucial para que las funcionalidades DTMF operen correctamente. Hay varios parámetros que deben configurarse adecuadamente.
Parámetros críticos en pjsip.conf
Para que un endpoint pueda utilizar las características definidas en features.conf, debe configurarse con los siguientes parámetros:
[6001](basic-endpoint)
type = endpoint
context = internal
disallow = all
allow = ulaw
allow = alaw
aors = 6001
auth = 6001
direct_media = no
dtmf_mode = rfc4733
one_touch_recording = yes
allow_transfer = yes
dtmf_mode: Este es el parámetro más importante. Define cómo se transmiten los tonos DTMF:
-
rfc4733 (recomendado): Envía DTMF como eventos RTP fuera de banda. Es el método más confiable, consume menos ancho de banda y no se degrada por códecs de audio. Este es el valor que debes usar.
-
inband: DTMF se envía como tonos audibles dentro del flujo de audio. Puede degradarse con códecs comprimidos y es menos confiable. Solo usar si los dispositivos no soportan RFC4733.
-
info: DTMF se envía mediante mensajes SIP INFO. Menos común y puede tener problemas de compatibilidad.
-
auto: Asterisk intenta detectar automáticamente el método. No recomendado para producción.
-
auto_info: Combinación de auto e info.
direct_media: Debe estar configurado en "no" para que Asterisk permanezca en el path del media y pueda detectar los códigos DTMF de características. Si está en "yes", el audio (RTP) fluye directamente entre endpoints y Asterisk no puede interceptar las secuencias DTMF. Esta es la razón número uno por la que las características no funcionan.
one_touch_recording: Habilita la grabación mediante código DTMF definido en featuremap (normalmente *3 para automon o *4 para automixmon).
allow_transfer: Permite transferencias de llamada para este endpoint. Si está en "no", los códigos de transferencia no funcionarán.
Configuración de direct_media y media_address
En escenarios más complejos, puedes necesitar:
[6001](basic-endpoint)
type = endpoint
; ... otras opciones ...
direct_media = no
media_address = 192.168.1.10
rtp_symmetric = yes
force_rport = yes
rewrite_contact = yes
media_address: IP que Asterisk anuncia en SDP. Útil cuando Asterisk está detrás de NAT.
rtp_symmetric: Envía RTP a la dirección origen en lugar de la anunciada en SDP.
force_rport: Fuerza el uso del puerto remoto real.
rewrite_contact: Reescribe el contacto SIP basándose en la IP/puerto de origen.
Habilitar características específicas por canal
Puedes habilitar características dinámicamente en el dialplan:
[internal]
exten => _6XXX,1,NoOp(Llamando a extensión ${EXTEN})
same => n,Set(DYNAMIC_FEATURES=blindxfer#atxfer#automon)
same => n,Set(__DYNAMIC_FEATURES=${DYNAMIC_FEATURES})
same => n,Dial(PJSIP/${EXTEN},30)
same => n,Hangup()
La variable DYNAMIC_FEATURES contiene una lista separada por # de las características que estarán disponibles durante la llamada. El doble guión bajo (__) hace que la variable se herede a los canales bridged.
features.conf completo
[general]
; Configuración de temporización
transferdigittimeout = 3
atxfernoanswertimeout = 15
atxferdropcall = no
atxferloopdelay = 10
atxfercallbackretries = 2
featuredigittimeout = 2000
transferdialattempts = 3
; Tonos y sonidos
courtesytone = beep
xfersound = beep
xferfailsound = beeperr
transferretrysound = beep
transferinvalidsound = beeperr
; Pickup de llamadas
pickupexten = *8
pickupsound = beep
pickupfailsound = beeperr
[featuremap]
; Códigos DTMF para características estándar
blindxfer => *1 ; Transferencia ciega
atxfer => *2 ; Transferencia atendida
disconnect => *0 ; Desconectar llamada
automon => *3 ; Grabar con Monitor (dos archivos)
automixmon => *4 ; Grabar con MixMonitor (un archivo)
[applicationmap]
; Características personalizadas
pauseagent => *5,self,Macro(pause-agent)
unpauseagent => *6,self,Macro(unpause-agent)
togglehold => *7,self,Macro(toggle-hold)
addconf => *9,both,ConfBridge(sala_${CALLERID(num)})
sendtovm => **1,self,VoiceMail(${EXTEN}@default,s)
emergency => ***911,caller,Dial(PJSIP/emergency-line)
[featuregroups]
; Grupos de características
agentfeatures => pauseagent,unpauseagent,automixmon
supervisorfeatures => pauseagent,unpauseagent,automixmon,addconf
basicfeatures => blindxfer,atxfer,automixmon
pjsip.conf correspondiente
; ============================================
; TRANSPORTE
; ============================================
[transport-udp]
type = transport
protocol = udp
bind = 0.0.0.0:5060
external_media_address = TU.IP.PUBLICA.AQUI
external_signaling_address = TU.IP.PUBLICA.AQUI
local_net = 192.168.1.0/24
; ============================================
; PLANTILLA BASE PARA ENDPOINTS
; ============================================
[basic-endpoint](!)
type = endpoint
context = internal
disallow = all
allow = ulaw
allow = alaw
allow = g722
; CRUCIAL: Parámetros para que funcionen las características
direct_media = no ; Asterisk debe ver el RTP
dtmf_mode = rfc4733 ; Método DTMF recomendado
allow_transfer = yes ; Habilitar transferencias
one_touch_recording = yes ; Habilitar grabación DTMF
; Parámetros NAT (ajustar según necesidad)
rtp_symmetric = yes
force_rport = yes
rewrite_contact = yes
; Otros parámetros útiles
trust_id_inbound = yes
send_pai = yes
callerid = "Extension ${EXTEN}" <${EXTEN}>
; ============================================
; ENDPOINTS ESPECÍFICOS
; ============================================
; Agente de call center con características extendidas
[6001](basic-endpoint)
auth = auth6001
aors = 6001
callerid = "Agente 1" <6001>
[auth6001]
type = auth
auth_type = userpass
username = 6001
password = agentePass123!
[6001]
type = aor
max_contacts = 1
remove_existing = yes
; Usuario básico con características limitadas
[6002](basic-endpoint)
auth = auth6002
aors = 6002
callerid = "Usuario 2" <6002>
[auth6002]
type = auth
auth_type = userpass
username = 6002
password = userPass456!
[6002]
type = aor
max_contacts = 1
; Supervisor con todas las características
[6003](basic-endpoint)
auth = auth6003
aors = 6003
callerid = "Supervisor" <6003>
[auth6003]
type = auth
auth_type = userpass
username = 6003
password = superPass789!
[6003]
type = aor
max_contacts = 2
remove_existing = yes
; ============================================
; TRUNK SIP (ejemplo)
; ============================================
[trunk-proveedor](!)
type = endpoint
context = from-trunk
disallow = all
allow = ulaw
allow = alaw
direct_media = no
dtmf_mode = rfc4733
[proveedor-sip](trunk-proveedor)
auth = auth-proveedor
aors = proveedor-sip
outbound_auth = auth-proveedor
[auth-proveedor]
type = auth
auth_type = userpass
username = tu_usuario_trunk
password = tu_password_trunk
[proveedor-sip]
type = aor
contact = sip:tu_proveedor.com:5060
[proveedor-sip]
type = identify
endpoint = proveedor-sip
match = IP.DEL.PROVEEDOR
extensions.conf (dialplan) integrado
[general]
static = yes
writeprotect = no
[globals]
RECORDING_DIR = /var/spool/asterisk/monitor
; ============================================
; CONTEXTO PARA EXTENSIONES INTERNAS
; ============================================
[internal]
; Extensiones de agentes con características completas
exten => _600[1-5],1,NoOp(=== Llamada a Agente ${EXTEN} ===)
same => n,Set(__DYNAMIC_FEATURES=agentfeatures)
same => n,Set(CHANNEL(language)=es)
same => n,Dial(PJSIP/${EXTEN},30,tTkK)
same => n,Goto(no-answer,1)
; Extensiones de supervisores con características extendidas
exten => _600[6-9],1,NoOp(=== Llamada a Supervisor ${EXTEN} ===)
same => n,Set(__DYNAMIC_FEATURES=supervisorfeatures)
same => n,Set(CHANNEL(language)=es)
same => n,Dial(PJSIP/${EXTEN},30,tTkK)
same => n,Goto(no-answer,1)
; Usuarios básicos
exten => _61XX,1,NoOp(=== Llamada a Usuario ${EXTEN} ===)
same => n,Set(__DYNAMIC_FEATURES=basicfeatures)
same => n,Set(CHANNEL(language)=es)
same => n,Dial(PJSIP/${EXTEN},20,tTkK)
same => n,Goto(no-answer,1)
; Manejo de no respuesta
exten => no-answer,1,NoOp(No hubo respuesta de ${EXTEN})
same => n,VoiceMail(${EXTEN}@default,su)
same => n,Hangup()
; Acceso a buzón de voz
exten => *97,1,NoOp(=== Acceso a Buzón de Voz ===)
same => n,VoiceMailMain(${CALLERID(num)}@default)
same => n,Hangup()
; Pickup de llamadas
exten => *8,1,NoOp(=== Call Pickup ===)
same => n,Pickup()
same => n,Hangup()
; Pickup de grupo
exten => **8,1,NoOp(=== Group Pickup ===)
same => n,PickupChan(PJSIP/${EXTEN})
same => n,Hangup()
; Sala de conferencia
exten => 9000,1,NoOp(=== Conferencia Principal ===)
same => n,Answer()
same => n,ConfBridge(sala1)
same => n,Hangup()
; Eco test
exten => 9999,1,NoOp(=== Echo Test ===)
same => n,Answer()
same => n,Echo()
same => n,Hangup()
; ============================================
; MACROS PARA CARACTERÍSTICAS PERSONALIZADAS
; ============================================
[macro-pause-agent]
exten => s,1,NoOp(=== Pausando Agente ===)
same => n,PauseQueueMember(,Local/${CALLERID(num)}@from-internal)
same => n,Playback(agent-paused)
same => n,MacroExit()
[macro-unpause-agent]
exten => s,1,NoOp(=== Despausando Agente ===)
same => n,UnpauseQueueMember(,Local/${CALLERID(num)}@from-internal)
same => n,Playback(agent-unpaused)
same => n,MacroExit()
[macro-toggle-hold]
exten => s,1,NoOp(=== Toggle Hold ===)
same => n,Set(HOLD_STATUS=${DB(hold/${CHANNEL})})
same => n,GotoIf($["${HOLD_STATUS}" = "1"]?unhold:hold)
same => n(hold),Set(DB(hold/${CHANNEL})=1)
same => n,MusicOnHold()
same => n,MacroExit()
same => n(unhold),Set(DB(hold/${CHANNEL})=0)
same => n,StopMusicOnHold()
same => n,MacroExit()
; ============================================
; CONTEXTO DESDE TRUNK
; ============================================
[from-trunk]
exten => _X.,1,NoOp(=== Llamada entrante desde trunk: ${CALLERID(num)} ===)
same => n,Set(CHANNEL(language)=es)
same => n,Goto(internal,${EXTEN},1)
exten => _6XXX,1,NoOp(=== DID a extensión ${EXTEN} ===)
same => n,Goto(internal,${EXTEN},1)
En el dialplan, la aplicación Dial() acepta flags que interactúan con features.conf:
Dial(PJSIP/extension,timeout,options)
Opciones importantes:
- t: Permite a quien llama usar características de transferencia
- T: Permite a quien recibe usar características de transferencia
- k: Permite a quien llama usar características de parking
- K: Permite a quien recibe usar características de parking
- w: Permite a quien llama usar características de automon
- W: Permite a quien recibe usar características de automon
Ejemplo combinado:
same => n,Dial(PJSIP/${EXTEN},30,tTkKwW)
Esto habilita todas las características para ambas partes.
Verificar configuración
Desde la CLI de Asterisk:
# Ver configuración actual de features
asterisk -rx "features show"
# Ver características mapeadas
asterisk -rx "core show config features.conf"
# Verificar endpoints PJSIP
asterisk -rx "pjsip show endpoints"
# Ver detalles de un endpoint específico
asterisk -rx "pjsip show endpoint 6001"
Activar logs detallados
# En la consola de Asterisk
asterisk -rvvvv
# O aumentar verbosidad
core set verbose 5
core set debug 5
# Logs específicos de DTMF
core set debug 3
Problemas comunes y soluciones
Las características DTMF no funcionan:
Solución 1: Verificar que direct_media = no en pjsip.conf
Solución 2: Confirmar que dtmf_mode = rfc4733 tanto en endpoint como que el dispositivo lo soporte
Solución 3: Revisar que los códigos en [featuremap] no conflictúan con códigos de extensiones
Transferencias no se completan:
Solución 1: Verificar allow_transfer = yes en el endpoint
Solución 2: Aumentar transferdigittimeout si el usuario tarda en marcar
Solución 3: Revisar que el contexto tenga acceso a la extensión destino
Grabación DTMF no inicia:
Solución 1: Confirmar one_touch_recording = yes en endpoint
Solución 2: Verificar permisos de escritura en directorio de grabaciones
Solución 3: Revisar que MixMonitor esté disponible: asterisk -rx "core show application MixMonitor"
DTMF se escucha como audio:
Problema: El modo es inband en lugar de rfc4733
Solución: Cambiar dtmf_mode = rfc4733 y reiniciar el endpoint
Timeout muy corto para marcar:
Solución: Aumentar featuredigittimeout en [general] a 3000 o más
Logs útiles
# Ver logs en tiempo real
tail -f /var/log/asterisk/full
# Filtrar solo DTMF
tail -f /var/log/asterisk/full | grep -i dtmf
# Filtrar transferencias
tail -f /var/log/asterisk/full | grep -i transfer
# Filtrar features
tail -f /var/log/asterisk/full | grep -i feature
Simplicidad en códigos: Usa códigos DTMF cortos y memorables. Evita secuencias largas o complejas.
Documentación: Mantén un documento con todos los códigos y compártelo con usuarios.
Testing progresivo: Prueba cada característica individualmente antes de habilitar todas.
Grupos de características: Usa [featuregroups] para asignar características según roles (agentes, supervisores, usuarios).
Monitoreo: Implementa logging adecuado para auditar uso de características.
Capacitación: Asegúrate que usuarios conozcan los códigos y cómo usarlos correctamente.
Respaldo: Siempre respalda configuraciones antes de cambios importantes.
Consistencia: Mantén los mismos códigos DTMF en todos los sistemas de la organización.
SEGURIDAD:
Prevención de abuso: Limita características sensibles (como transferencias externas) mediante contextos restrictivos.
Auditoría: Registra todas las transferencias y grabaciones para compliance.
Permisos: Asigna características según necesidad real, no des acceso universal.
Códigos seguros: Evita códigos DTMF obvios o predecibles para funciones críticas.
Validación: En applicationmap, valida siempre las entradas antes de ejecutar acciones.
Conclusión
El archivo features.conf proporciona funcionalidades esenciales que transforman Asterisk de una simple centralita en un sistema telefónico completo y profesional. Su correcta integración con pjsip.conf requiere atención especial a parámetros como direct_media y dtmf_mode para garantizar que todas las características funcionen según lo esperado.
La clave del éxito está en:
- Mantener
direct_media = no para que Asterisk pueda interceptar DTMF
- Usar
dtmf_mode = rfc4733 para máxima confiabilidad
- Configurar los flags apropiados en la aplicación Dial()
- Documentar y capacitar a usuarios en el uso de códigos DTMF
- Monitorear y depurar sistemáticamente
Con la configuración adecuada, los usuarios pueden disfrutar de transferencias fluidas, grabación bajo demanda y características personalizadas, mejorando significativamente la productividad y experiencia telefónica en cualquier implementación de Asterisk PBX.