修改拨号计划 修改freeswitch/conf/dialplan/default.xml

修改拨号计划

修改freeswitch/conf/dialplan/default.xml
修改如下内容,好让所有的拨号通过以下的条件

<extension name="Local_Extension">
<!--<condition field="destination_number" expression="^(10[01][0-9])$">-->
<condition field="destination_number" expression="^(.*)$">
<think>我们有一个FreeSWITCHDialplan配置片段,它位于conf/dialplan/default.xml中。 该配置片段定义了一个名为"Dialplan Controller Default"的extension(扩展)。 在condition(条件)标签内,只有一个action(动作),即调用"socket"应用。 解释: 1. `extension name="Dialplan Controller Default"`:定义了一个扩展,名为"Dialplan Controller Default"。 2. `condition`:条件标签,这里没有指定具体的匹配条件(如destination_number等),所以这个条件总是匹配的。这意味着每次呼叫进入Dialplan时,都会执行这个扩展。 注意:在实际使用中,我们通常会给condition指定匹配条件(如被叫号码),否则可能会影响所有呼叫。这里没有条件,所以它会匹配所有呼叫。 3. `action application="socket" data="127.0.0.1:22444 async full"`:当匹配到这个条件时,执行socket应用。 - socket应用:用于将呼叫控制权通过Socket连接转移到外部程序(如ESL脚本)。 - data参数:指定了Socket连接的地址和选项。 * "127.0.0.1:22444":表示连接到本地的22444端口。 * "async":表示异步模式,即FreeSWITCH不会等待外部程序的响应,而是继续执行后续动作(如果有的话)。但是,由于这里只有一个action,且没有后续动作,所以呼叫控制权会完全交给外部程序。 * "full":表示使用完整的事件模式,即外部程序可以接收和发送所有事件。 整个扩展的作用: 当呼叫进入Dialplan时,无条件地将呼叫控制权通过Socket连接转移到本地22444端口上运行的ESL脚本(或任何可以处理Socket连接的程序)。外部程序将接管呼叫,并负责后续的控制(如播放声音、收集按键等)。 注意:由于这个扩展没有匹配条件,它会匹配所有呼叫。因此,在实际部署中,我们通常会将这个扩展放在特定的上下文中,或者添加匹配条件(如被叫号码)来限制其影响范围。 示例:假设我们有一个ESL脚本在本地22444端口监听,那么当有呼叫进入时,FreeSWITCH会通过Socket连接将事件发送给该脚本,然后由脚本控制呼叫流程。 代码示例(Python ESL脚本监听22444端口): 以下是一个简单的ESL服务器示例,它接收来自FreeSWITCH的Socket连接,然后播放一个声音文件。 ```python import socket import sys # 创建TCP服务器 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('127.0.0.1', 22444)) server.listen(5) print("Listening on port 22444...") while True: client_socket, addr = server.accept() print(f"Accepted connection from {addr}") # 接收FreeSWITCH发送的初始信息(包括事件内容) data = client_socket.recv(4096) print(f"Received data: {data}") # 解析事件(这里简化处理,实际需要解析事件获取Channel UUID等信息) # 假设我们从中提取出了Channel UUID # 实际应用中,我们需要解析事件,获取Caller-Destination-Number等,以便做不同处理 # 发送命令给FreeSWITCH # 注意:实际应用中,我们需要根据事件内容构造正确的命令 # 命令格式:每个命令以'\n\n'结尾 # 第一步:设置回复(需要先回复一个connect事件) # 我们假设已经解析出事件的UUID,这里用变量channel_uuid代替 # 如果初始事件中没有,我们可以用其他方式获取(比如在事件中查找) # 假设我们解析出事件中有一个Unique-ID头 # 这里我们简化处理,假设已经知道Unique-ID # 如果无法解析,我们可以使用以下方法:先回复一个"connect"消息,然后使用其他API获取 # 回复一个connect消息,表示连接成功 connect_response = "connect\n\n" client_socket.send(connect_response.encode('utf-8')) # 然后发送命令:播放声音文件 # 注意:命令必须以事件的形式发送,并且需要指定应用和参数 play_command = "sendmsg\n" play_command += "call-command: execute\n" play_command += "execute-app-name: playback\n" play_command += "execute-app-arg: /usr/local/freeswitch/sounds/en/us/callie/ivr/8000/ivr-welcome_to_freeswitch.wav\n" play_command += "\n" # 两个换行表示结束 client_socket.send(play_command.encode('utf-8')) # 然后发送退出命令(可选,也可以等待外部程序继续控制) # 这里我们播放完就挂断 # 注意:播放是异步的,所以我们需要等待播放完成再挂断?或者使用其他机制。 # 实际上,我们可以发送一个hangup命令,但这样会立即挂断,而不会等待播放完成。 # 更好的做法是:使用playback_done事件来检测播放完成,然后挂断。但这里为了简单,我们使用同步方式(使用event lock)等待播放完成。 # 但是,在socket应用中,我们通常使用异步方式,所以这里我们只播放然后挂断(不考虑播放完成事件)是不合适的。 # 因此,我们改为使用同步执行(使用sync标志)来等待播放完成。 # 修改上面的命令: play_command = "sendmsg\n" play_command += "call-command: execute\n" play_command += "execute-app-name: playback\n" play_command += "execute-app-arg: /usr/local/freeswitch/sounds/en/us/callie/ivr/8000/ivr-welcome_to_freeswitch.wav\n" play_command += "event-lock: true\n" # 同步执行,等待播放完成 play_command += "\n" client_socket.send(play_command.encode('utf-8')) # 然后挂断 hangup_command = "sendmsg\n" hangup_command += "call-command: execute\n" hangup_command += "execute-app-name: hangup\n" hangup_command += "execute-app-arg: NORMAL_CLEARING\n" hangup_command += "\n" client_socket.send(hangup_command.encode('utf-8')) # 关闭连接 client_socket.close() ``` 注意:上面的脚本只是一个非常简化的示例,实际应用中需要处理多个连接、解析事件、错误处理等。 另外,在FreeSWITCHDialplan配置中,使用`socket`应用时,如果外部程序没有响应,呼叫可能会被挂起。因此,建议在外部程序中进行完善的错误处理。 相关优化: 1. 使用多线程或异步IO处理多个同时的呼叫。 2. 解析FreeSWITCH发送的事件(事件内容以纯文本形式发送,格式为键值对,由换行分隔,以两个换行结束)。 3. 根据事件内容(如被叫号码)执行不同的业务逻辑。 §§相关问题§§: 1. 如何为FreeSWITCH的socket应用添加安全认证机制? 2. 在外部程序处理呼叫时,如何捕获DTMF按键事件? 3. 当外部程序崩溃时,如何确保FreeSWITCH中的呼叫不会挂起? 4. 如何使用ESL库(如Python的ESL)简化外部控制程序的开发?</think>### 解释 Dialplan 配置片段 ```xml <extension name="Dialplan Controller Default"> <condition> <action application="socket" data="127.0.0.1:22444 async full"/> </condition> </extension> ``` 这个配置片段位于 FreeSWITCH拨号计划 (`conf/dialplan/default.xml`) 中,用于控制呼叫路由行为。以下是详细解释: #### 1. 组件解析 | 组件 | 说明 | |------|------| | `<extension>` | 定义呼叫路由规则的基本单元 | | `name="Dialplan Controller Default"` | 扩展规则的名称标识 | | `<condition>` | 定义规则匹配条件(此处为空,表示无条件匹配) | | `<action>` | 匹配条件后执行的操作 | | `application="socket"` | 使用 socket 应用程序 | | `data="127.0.0.1:22444 async full"` | socket 应用的参数配置 | #### 2. 功能详解 这个配置实现了以下功能: 1. **无条件匹配**:由于 `<condition>` 标签内没有指定匹配条件(如被叫号码),此规则会对所有呼叫生效 2. **Socket 应用调用**:使用 `socket` 应用将呼叫控制权转交给外部程序 3. **参数解析**: - `127.0.0.1:22444`:连接本地 22444 端口 - `async`:异步模式(非阻塞) - `full`:完整事件模式(发送所有事件) #### 3. 工作流程 当呼叫进入 FreeSWITCH: 1. 系统匹配拨号计划规则 2. 找到此无条件匹配的扩展 3. 执行 `socket` 应用: - 建立到 `127.0.0.1:22444` 的 TCP 连接 - 发送呼叫相关事件(如 CHANNEL_CREATE) 4. 外部程序(如 ESL 脚本)接管呼叫控制 5. FreeSWITCH 等待外部指令 #### 4. 完整调用示例 外部 Python 程序监听 22444 端口处理呼叫: ```python import socket import threading def handle_call(client_socket): """处理单个呼叫连接""" # 接收FreeSWITCH发送的初始事件 initial_data = client_socket.recv(4096).decode('utf-8') print(f"收到呼叫事件:\n{initial_data}") # 解析关键信息 (简化版) call_uuid = None for line in initial_data.split('\n'): if line.startswith('Unique-ID:'): call_uuid = line.split(':')[1].strip() if not call_uuid: print("未找到呼叫UUID") return # 发送控制命令 commands = [ "connect", # 确认连接 f"sendmsg {call_uuid}", "call-command: execute", "execute-app-name: answer", "", f"sendmsg {call_uuid}", "call-command: execute", "execute-app-name: playback", f"execute-app-arg: /usr/local/freeswitch/sounds/en/us/callie/ivr/8000/ivr-welcome.wav", "" ] # 发送命令序列 for cmd in commands: client_socket.send(f"{cmd}\n".encode('utf-8')) print(f"发送命令: {cmd}") # 保持连接直到呼叫结束 while True: data = client_socket.recv(1024) if not data: break print(f"收到事件: {data.decode('utf-8')}") print("呼叫结束") client_socket.close() def start_server(): """启动Socket服务器""" server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('127.0.0.1', 22444)) server.listen(5) print("Socket服务器监听 127.0.0.1:22444...") while True: client, addr = server.accept() print(f"接受来自 {addr} 的连接") threading.Thread(target=handle_call, args=(client,)).start() if __name__ == "__main__": start_server() ``` #### 5. 参数配置详解 | 参数 | 值 | 说明 | |------|----|------| | IP | 127.0.0.1 | 本地回环地址 | | 端口 | 22444 | 自定义监听端口 | | 模式 | async | 异步非阻塞模式 | | 事件 | full | 发送完整事件集 | | 超时 | (未指定) | 默认超时时间 | | 协议 | (未指定) | 默认TCP协议 | #### 6. 实际应用场景 1. **呼叫中心系统**:外部CTI服务器控制呼叫流程 2. **AI语音交互**:对接语音识别和TTS引擎 3. **自定义路由**:基于数据库的复杂路由逻辑 4. **呼叫监控**:实时获取呼叫事件和统计 5. **集成测试**:自动化呼叫流程测试 #### 7. 最佳实践建议 1. **添加匹配条件**:避免影响所有呼叫 ```xml <condition field="destination_number" expression="^1234$"> ``` 2. **安全加固**:添加防火墙规则 ```bash iptables -A INPUT -p tcp --dport 22444 -s 127.0.0.1 -j ACCEPT iptables -A INPUT -p tcp --dport 22444 -j DROP ``` 3. **错误处理**:添加超时和重试机制 ```xml <action application="socket" data="127.0.0.1:22444 async full 5000"/> ``` 4. **负载均衡**:支持多实例 ```xml <!-- 主连接 --> <action application="socket" data="127.0.0.1:22444 async full"/> <!-- 备用连接 --> <action application="socket" data="127.0.0.1:22445 async full"/> ``` #### 8. 高级调试技巧 1. 查看Socket连接状态: ```bash fs_cli -x "show channels" | grep socket ``` 2. 捕获Socket通信: ```bash tcpdump -i lo -nn -X port 22444 ``` 3. 模拟Socket客户端: ```python import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 8021)) s.send(b"api originate user/1000 &socket(127.0.0.1:22444 async full)\n") print(s.recv(4096).decode()) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值