FreeSWITCH 1.10.10 简单图形化界面13 - 使用Python-ESL获取FreeSWITCH事件

本文主要是介绍FreeSWITCH 1.10.10 简单图形化界面13 - 使用Python-ESL获取FreeSWITCH事件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

FreeSWITCH 1.10.10 简单图形化界面13 - Python-ESL

  • 0、 界面预览
  • 1、简介
  • 2、安装python-esl
  • 3、简单使用
  • 4、示例


FreeSWITCH界面安装参考:https://blog.csdn.net/jia198810/article/details/132479324

0、 界面预览

http://myfs.f3322.net:8020/
用户名:admin,密码:admin

FreeSWITCH界面安装参考:https://blog.csdn.net/jia198810/article/details/132479324

1、简介

Python ESL 模块提供了与 FreeSWITCH 之间的本地交互,通过事件套接字接口实现。它允许发送命令、接收输出,并从 FreeSWITCH 服务器发送和接收事件及交互。

2、安装python-esl

当前python版本:

Python 3.10.13 (main, Oct 21 2023, 22:46:22) [GCC 8.5.0 20210514 (Red
Hat 8.5.0-18)] on linux

yum install swig 
pip3 install python-ESL

安装后,当前ESL版本:

root@localhost ~# /usr/local/python310/bin/pip3 list |grep ESL
python-ESL                     1.4.18

3、简单使用

# test.py
# 导入esl
import ESL
# 连接mod_event_socket
con = ESL.ESLconnection("127.0.0.1", "8021", "ClueCon")
# 接收事件
con.recvEvent()
# 执行fs api
con.api("status")
# 执行拨号应用
con.execute("anster")

详细方法和属性可参考此链接

4、示例

使用python-ESL 连接mod_event_socket,获取分机注册、通话、离线及会议状态并推送到mqtt。

#!/usr/local/python310/bin/python
import threading
import queue
import multiprocessing
import requests
import logging
from pathlib import Path
import re
import ESL
import json
import atexit
import os
from mqtt import mqtt_client,phone_status_topic,conference_status_topic,all_status_topic
from time import sleep# 日志开始
log_file = Path(Path(__file__).parent.parent.as_posix(), "log/events.log").as_posix()
print(log_file)
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
header = logging.FileHandler(log_file)
header.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
header.setFormatter(formatter)
logger.addHandler(header)
# 日志结束# 连接fscli
esl_con = ESL.ESLconnection('127.0.0.1', '8021', 'fs8021')
esl_con_connected = False
# process 事件控制
process_event = threading.Event()
# PID文件
pidfile = Path("/var/run/fsevent.pid")# 消息队列
event_queue =  queue.Queue() # 通道存储,存储多路通话状态,一路结束,恢复到上一个状态,并不会真正的删除通话
channel_list = []# 添加通道
def add_channel(uuid,caller_number,callee_number):channels = [channel for channel in channel_list if channel["uuid"] == uuid]if not channels:channel_list.append(dict(uuid=uuid,caller_number=caller_number,callee_number=callee_number))print("当前通道数量:",channel_list)# 删除通道
def del_channel(uuid):print("删除uuid:",uuid)for channel in channel_list:if (channel["uuid"] == uuid):channel_list.remove(channel)print("删除后的通道列表:",channel_list)# 删除所有通道
def del_all_channels():for channel in channel_list:channel_list.remove(channel)# 获取通道
def get_channel_by_caller_number(number):channels = [channel for channel in channel_list if channel["caller_number"] == number]return channels[0] if channels else Nonedef get_channel_by_callee_number(number):channels = [channel for channel in channel_list if channel["callee_number"] == number]return channels[0] if channels else None# 为分机状态获取主叫号码
def get_phone_status_caller_number(e):caller_number=None# 第一次获取主叫if e.getHeader("Caller-ANI"):result = re.search(r'(\d+)',e.getHeader("Caller-ANI"))if result:caller_number = result.group(1)# 第二次获取主叫if not caller_number and e.getHeader("Caller-Caller-ID-Number"):result = re.search(r'(\d+)',e.getHeader("Caller-Caller-ID-Number"))if result:caller_number = result.group(1)if not caller_number:del_all_channels()print("分机状态:主叫号码获取异常Caller-ANI Caller-Caller-ID-Number,数据:",e.serialize("json"))return caller_number# 为分机状态获取被叫号码
def get_phone_status_callee_number(e):callee_number= None# 第一次获取被叫if e.getHeader("Caller-Destination-Number"):result = re.search(r'(\d+)',e.getHeader("Caller-Destination-Number"))if result:callee_number = result.group(1) # 第二次获取被叫if not callee_number and  e.getHeader("Caller-Callee-ID-Number"):result = re.search(r'(\d+)',e.getHeader("Caller-Callee-ID-Number"))if result:callee_number = result.group(1)if not callee_number :del_all_channels()print("分机状态:被叫号码获取异常Caller-Destination-Number Caller-Callee-ID-Number,数据:",e.serialize("json"))return callee_number# 为会议状态获取主叫号码
def get_conference_status_caller_number(e):caller_number = Noneif e.getHeader("Caller-ANI"):result = re.search(r'(\d+)$',e.getHeader("Caller-ANI"))if result:caller_number = result.group(1)if not caller_number:del_all_channels()print("会议状态:主叫号码获取异常Caller-ANI,数据:",e.serialize("json"))return caller_number# 为会议状态获取被叫号码
def get_conference_status_callee_number(e):callee_number = Noneif e.getHeader("Caller-RDNIS"):result = re.search(r'(\d+)$', e.getHeader("Caller-RDNIS"))if result:callee_number = result.group(1)if not callee_number :del_all_channels()print("会议状态:被叫号码获取异常Caller-RDNIS,数据:",e.serialize("json"))return callee_numberdef handle_event(e):#print(e.serialize("json"))name = e.getHeader("Event-Name")subclass = e.getHeader("Event-Subclass")datetime=e.getHeader("Event-Date-Local")seq=e.getHeader("Event-Sequence")# 分机状态初默认值phone_status_dict = dict(type="phone_status",datetime=datetime,seq=seq)# 会议室状态默认值conference_status_dict = dict(type="conference_status",datetime=datetime,seq=seq)# 分机注销if subclass == "sofia::unregister":phone_status_dict.update(number=e.getHeader("username").split('-')[0] if e.getHeader("username") else e.getHeader("from-user").split('-')[0],status=0,description="离线")event_queue.put(phone_status_dict)# 分机注册elif subclass == "sofia::register":number=e.getHeader("username").split('-')[0]phone_status_dict.update(number=number,status=1,description="空闲")# 如果分机即没有呼叫,也没有被呼叫,则发布状态if not get_channel_by_caller_number(number) and not get_channel_by_callee_number(number):event_queue.put(phone_status_dict)# 分机振铃elif name == "CHANNEL_PROGRESS": #print(e.serialize("json"))caller_number = get_phone_status_caller_number(e)callee_number = get_phone_status_callee_number(e)uuid = e.getHeader("Channel-Call-UUID")add_channel(uuid,caller_number,callee_number)if e.getHeader("Call-Direction") == "outbound": # 主叫分机状态phone_status_dict.update(number=caller_number,direction="OUTBOUND",caller_number=caller_number,callee_number=callee_number,status=10,description=f"正在呼叫{callee_number}")event_queue.put(phone_status_dict)elif e.getHeader("Call-Direction") == "inbound":# 被叫分机状态phone_status_dict.update(number=callee_number,direction="INBOUND",caller_number=caller_number,callee_number=callee_number,status=11,description=f"等待接听{caller_number}的来电")event_queue.put(phone_status_dict)# 分机应答elif name == "CHANNEL_ANSWER":#print(e.serialize("json"))caller_number = get_phone_status_caller_number(e)callee_number = get_phone_status_callee_number(e)# 有的分机没有PROCESS,同样需要加到通道存储中uuid = e.getHeader("Channel-Call-UUID")add_channel(uuid,caller_number,callee_number)if e.getHeader("Call-Direction") == "outbound":# 主叫分机状态phone_status_dict.update(number=caller_number,direction="OUTBOUND",caller_number=caller_number,callee_number=callee_number,status=20,description=f"和{callee_number}通话中")event_queue.put(phone_status_dict)elif e.getHeader("Call-Direction") == "inbound":# 被叫分机状态phone_status_dict.update(number=callee_number,direction="INBOUND",caller_number=caller_number,callee_number=callee_number,status=21,description=f"和{caller_number}通话中")event_queue.put(phone_status_dict)# # 分机挂断elif name == "CHANNEL_HANGUP_COMPLETE" :caller_number = get_phone_status_caller_number(e)callee_number = get_phone_status_callee_number(e)uuid = e.getHeader("Channel-Call-UUID")# 先删除本次的uuid,如果还有通话则恢复状态del_channel(uuid)if e.getHeader("Call-Direction") == "outbound":# 主叫分机状态phone_status_dict.update(number=caller_number,status=1,description="空闲")event_queue.put(phone_status_dict)# 主叫挂机后,如果还有通话,则恢复到上一次的通话状态other_channel = get_channel_by_caller_number(caller_number)print(f"OUT剩余通道中主叫是{caller_number}的通道",other_channel)if other_channel:# 主叫分机状态phone_status_dict.update(number=caller_number,direction="OUTBOUND",caller_number=caller_number,callee_number=other_channel["callee_number"],status=20,description=f"和{other_channel['callee_number']}通话中")event_queue.put(phone_status_dict)other_channel = get_channel_by_callee_number(caller_number)print(f"OUT剩余通道中被叫是{caller_number}的通道",other_channel)if other_channel:# 主叫分机状态phone_status_dict.update(number=caller_number,direction="OUTBOUND",caller_number=caller_number,callee_number=other_channel["callee_number"],status=20,description=f"和{other_channel['callee_number']}通话中")event_queue.put(phone_status_dict)elif e.getHeader("Call-Direction") == "inbound":# 被叫分机状态# 如果呼叫ivr,可能获取不到号码# print(e.serialize("json"))phone_status_dict.update(number=callee_number,status=1,description="空闲")event_queue.put(phone_status_dict)# 被叫挂机后,如果还有通话,则恢复到上一次的通话状态other_channel = get_channel_by_caller_number(callee_number)print(f"IN剩余通道中主叫是{callee_number}的通道",other_channel)if other_channel:# 主叫分机状态phone_status_dict.update(number=callee_number,direction="OUTBOUND",caller_number=callee_number,callee_number=other_channel["callee_number"],status=20,description=f"和{other_channel['callee_number']}通话中")event_queue.put(phone_status_dict)other_channel = get_channel_by_callee_number(callee_number)print(f"IN剩余通道中被叫是{callee_number}的通道",other_channel)if other_channel:# 主叫分机状态phone_status_dict.update(number=callee_number,direction="INBOUND",caller_number=other_channel["caller_number"],callee_number=callee_number,status=20,description=f"和{other_channel['caller_number']}通话中")event_queue.put(phone_status_dict)# 分机状态结束# 会议开始elif subclass == "conference::maintenance":#print(e.serialize("json"))action = e.getHeader("Action")number=e.getHeader("Conference-Name")count=int(e.getHeader("Conference-Size"))conference_status_dict.update(number=number,count=count,action=action)# 开始会议if action == "conference-create":conference_status_dict.update(status=1,description="会议室开始")event_queue.put(conference_status_dict)# 结束会议elif action == "conference-destroy":# 如果还有通话继续删除uuid = e.getHeader("Channel-Call-UUID")del_channel(uuid)conference_status_dict.update(status=0,description="会议室结束")event_queue.put(conference_status_dict)# 布局改变elif action == "floor-change" or action == "video-floor-change":conference_status_dict.update(old_id=None if e.getHeader("Old-ID") == "none" else int(e.getHeader("Old-ID")),new_id=None if e.getHeader("New-ID") == "none" else int(e.getHeader("New-ID")),description="会议室改变布局")event_queue.put(conference_status_dict)# 添加成员elif action == "add-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)print(f"会议号码{caller_number},成员号码是:{callee_number}")state = e.getHeader("Answer-State")if state == "answered" or state == "early":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室增加成员")event_queue.put(conference_status_dict)phone_status_dict.update(number=callee_number,direction="INBOUND",caller_number=caller_number,callee_number=callee_number,status=3,description=f"在会议室{caller_number}中")event_queue.put(phone_status_dict)# 禁止发言elif action == "mute-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员禁止发言")event_queue.put(conference_status_dict)# 允许发言elif action == "unmute-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员允许发言"),event_queue.put(conference_status_dict)# 关闭视频elif action == "vmute-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员关闭视频")event_queue.put(conference_status_dict)# 开启视频elif action == "unvmute-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员开启视频"),event_queue.put(conference_status_dict)# 开启禁音elif action == "deaf-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员开启禁音")event_queue.put(conference_status_dict)# 关闭禁音elif action == "undeaf-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员关闭禁音"),event_queue.put(conference_status_dict)# 踢出成员elif action == "kick-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室踢出成员")event_queue.put(conference_status_dict)# 删除成员elif action == "del-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室删除成员")event_queue.put(conference_status_dict)phone_status_dict.update(number=callee_number,direction="INBOUND",caller_number=caller_number,callee_number=callee_number,status=1,description=f"空闲")event_queue.put(phone_status_dict)# 挂断成员elif action == "hup-member":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室挂断成员")event_queue.put(conference_status_dict)# 邀请成员elif action == "bgdial-result":state = e.getHeader("Answer-State")conference_status_dict.update(result=e.getHeader("Result"),description="会议室邀请成员结果",)event_queue.put(conference_status_dict)# 正在发言就会触发此事件elif action == "start-talking":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员正在发言")event_queue.put(conference_status_dict)# 发言完毕后触发elif action == "stop-talking":caller_number = get_conference_status_caller_number(e)callee_number = get_conference_status_callee_number(e)state = e.getHeader("Answer-State")if state == "answered":conference_status_dict.update(member_number=callee_number,member_status=dict(member_id = int(e.getHeader("Member-ID")),member_type = e.getHeader("Member-Type"),video = True if e.getHeader("Video") == "true" else False,hear = True if e.getHeader("Hear") == "true" else False,see =  True if e.getHeader("See") == "true" else False,speak = True if e.getHeader("Speak") == "true" else False,talking = True if e.getHeader("Talking") == "true" else False,mute = True if e.getHeader("Mute-Detect") == "true" else False,),description="会议室成员发言完毕")event_queue.put(conference_status_dict)# 开始录音/录像# start-recordingelif action == "start-recording":conference_status_dict.update(path=e.getHeader("Path"),error=e.getHeader("Error"),description="会议室开始录音/录像")event_queue.put(conference_status_dict)# 暂停录音/录像elif action == "pause-recording":conference_status_dict.update(path=e.getHeader("Path"),description="会议室暂停录音/录像")event_queue.put(conference_status_dict)# 暂停录音/录像elif action == "resume-recording":conference_status_dict.update(path=e.getHeader("Path"),description="会议室恢复录音/录像")event_queue.put(conference_status_dict)# 结束录音/录像elif action == "stop-recording":conference_status_dict.update(path=e.getHeader("Path"),description="会议室结束录音/录像")event_queue.put(conference_status_dict)# 锁定会议室elif action == "lock":conference_status_dict.update(description="会议室锁定")event_queue.put(conference_status_dict)# 解锁定会议室elif action == "unlock":conference_status_dict.update(description="会议室解锁")event_queue.put(conference_status_dict)# 播放文件elif action == "play-file":conference_status_dict.update(file=e.getHeader("File"),sync = True if e.getHeader("Async") == "true" else False,description="会议室播放文件开始")event_queue.put(conference_status_dict)# 结束文件elif action == "play-file-done":conference_status_dict.update(file=e.getHeader("File"),description="会议室播放文件完毕")event_queue.put(conference_status_dict)# 会议状态结束# 提交状态到其他目的
def status_to_post(status_data):url = "https://example.com/submit-status"# 替换为您要提交状态的目标URLprint("POST提交到URL:",status_data)try:response = requests.post(url, json=status_data,timeout=10)if response.status_code == 200:print("提交成功")else:print("提交失败:", response.status_code)except requests.exceptions.RequestException as e:print("其他错误",e)pass# 推送事件到mqtt
def status_to_mqtt(status_data):print("推送到MQTT:",status_data)logger.info(status_data)payload=json.dumps(status_data)# 推送分机状态if status_data["type"] == "phone_status":mqtt_client.publish(topic=phone_status_topic,payload=payload,qos=2)# 推送会议状态elif status_data["type"] == "conference_status":mqtt_client.publish(topic=conference_status_topic,payload=payload,qos=2)# 推送所有状态mqtt_client.publish(topic=all_status_topic,payload=payload,qos=2)# 接收freeswitch事件
def recv_event():global esl_con,esl_con_connected, process_eventwhile True:while process_event.wait():esl_con.events('json', 'all')event = esl_con.recvEvent()if event.getHeader("Event-Name") == "SERVER_DISCONNECTED":print("FreeSWITCH已断开,停止发送和接收")process_event.clear()if event:handle_event(event)sleep(5)# 发送freeswitch事件
def send_event():while True:print("发送",process_event.is_set())while process_event.wait():event_data = event_queue.get()status_to_mqtt(event_data)#status_to_post(event_data)event_queue.task_done()sleep(5)# 连接FreeSWITCH ESL
def connect_esl():global esl_con,esl_con_connected, process_eventwhile True:if esl_con.connected():process_event.set()print("心跳:FreeSWITCH ESL连接中,正在发送和接收")sleep(10)else: print("连接FreeSWITCH ESL失败,停止发送和接收")print("连接FreeSWITCH ESL失败,重新连接中")process_event.clear()esl_con = ESL.ESLconnection('127.0.0.1', '8021', 'fs8021')if esl_con.connected():print("连接FreeSWITCH ESL成功")print("连接FreeSWITCH ESL成功,开始发送和接收")process_event.set()sleep(30)# 主进程
def main():# 创建连接ESL的进程connect_process = threading.Thread(target=connect_esl)connect_process.start()# 创建接收freeswitch事件的进程recv_process = threading.Thread(target=recv_event)recv_process.start()# 创建发送freeswitch事件的进程send_process = threading.Thread(target=send_event)send_process.start()# 结束进程时处理atexit.register(on_exit)# 创建PID文件pid = str(os.getpid())pidfile.write_text(pid)print("mqtt开始循环")mqtt_client.loop_forever()# 清理相关线程
def on_exit():# 结束mqttmqtt_client.disconnect()# 删除PIDif pidfile.exists():pidfile.unlink()if __name__ == "__main__":main()

这篇关于FreeSWITCH 1.10.10 简单图形化界面13 - 使用Python-ESL获取FreeSWITCH事件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658211

相关文章

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC