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

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::