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

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


0、 界面预览

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

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

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
# 2024年4月26日,更新此博客
#直接yum安装swig最新版本后,在安装python-ESL时,可能会出现报错(和swig相关的报错),可以卸载掉swig,安装旧版本的swig。
wget https://jaist.dl.sourceforge.net/project/swig/swig/swig-3.0.12/swig-3.0.12.tar.gz 
tar zxvf swig-3.0.12.tar.gz
./configure
make
make install

# 再次安装python-ESL
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 None

def 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 = 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:
        del_all_channels()
        print("会议状态:主叫号码获取异常Caller-ANI,数据:",e.serialize("json"))
    return caller_number

# 为会议状态获取被叫号码
def get_conference_status_callee_number(e):
    callee_number = None
    if 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_number

def 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-recording
        elif 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"
    # 替换为您要提交状态的目标URL
    print("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_event
    while 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_event

    while 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():
    # 结束mqtt
    mqtt_client.disconnect()
    # 删除PID
    if pidfile.exists():
        pidfile.unlink()

if __name__ == "__main__":
    main()
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: Freeswitch是一种开放源代码的语音和通信软件,提供语音、视频和多媒体通信能力。为了方便用户操作和管理,开发者为Freeswitch开发了简单图形化界面Freeswitch图形化界面基于Web技术实现,并采用Bootstrap框架和React.js技术。它具有简洁、易用的界面和友好的用户体验。用户只需在浏览器中输入相关的IP地址和端口号即可进入图形化界面。在界面中,用户可以登录、配置路由、管理通话、监控系统状态等操作。 图形化界面默认包含一些基本配置,例如:用户、呼入路由、呼出路由,用户可以根据自己的需求进行修改或者新增配置。用户也可以在界面中管理通话,例如:发起呼叫、挂断电话、进行转移等等。此外,Freeswitch图形化界面还提供系统日志、性能监控等功能,方便用户进行系统维护和管理。 总体来看,Freeswitch 1.10.7图形化界面为用户提供了方便、高效的使用体验,并提高了系统管理的可视化程度,这对于语音和通信行业的从业者及其管理者来说具有很大的意义。 ### 回答2: FreeSWITCH是一款强大的开源电话系统,其中1.10.7版本是最新的稳定版本。它支持Voice over IP(VoIP)和其他通信技术,如电话、传真和视频。同时,这款软件也支持多种协议,例如SIP、H.323和WebRTC,可以在 Linux、Windows 和 macOS 等不同平台上运行。 不过,对于一些初学者来说,命令行界面较为复杂,很难驾驭,因此出现了一些可以在图形界面下进行FreeSWITCH的配置和管理的工具。其中一些工具功能繁多,但使用起来相对复杂,很难快速掌握。而在这些工具中,Sangoma的FreePBX可能是比较著名的一个,但它需要安装在 FreeSWITCH 系统之外。 这里介绍一个能够在 FreeSWITCH 系统内完成图形化界面配置的工具,它是由FreeSWITCH的社区成员开发的。这个工具名为FreeSWITCH Desktop GUI (FSgui),目前已经实现了基础的系统配置以及呼叫中心方面的功能。 关于FSgui的使用,它提供了可视化的配置界面,在功能区中可以快捷地调整相关配置。例如,在呼叫中心方面,可以通过可视化配置,添加、编辑和删除IVR,管理呼叫、管理坐席分机等功能,缩短了用户配置的时间,从而提高效率。此外,其还支持SIP Trunks的管理,可以方便地配置多个SIP Trunks,以便于用户同时使用多种语音服务提供商。 总之,FreeSWITCH Desktop GUI 是一款简单易用的图形化工具,它为用户提供了快捷的配置方式,能够帮助使用者快速完成系统的配置与调整。同时,它是开源软件,可以在 GitHub 上进行下载。 ### 回答3: freeswitch是一款功能强大的开源电话交换机软件,但对于一些非技术人员来说,其操作和配置可能会比较复杂。为了能够更简单、更直观地使用freeswitch,一些第三方开发者开发了一些针对freeswitch图形化界面,使得用户只需要通过鼠标点击和填写一些基本信息就可以完成freeswitch的配置和操作。 针对freeswitch 1.10.7,开发者已经开发出了一些好用的图形化界面,比如“FusionPBX”和“FreeSWITCH-GUI”。这些界面的主要特点是简单、易用、可扩展,可用于管理用户、呼叫路由、语音信箱等等freeswitch的相关服务。 以“FusionPBX”为例,其界面设计比较简洁,主要分为左侧的菜单栏和右侧的内容展示区。通过菜单栏的操作,用户可以完成一些相应的功能,比如添加、删除用户,配置呼叫路由,设置CallCenter等等。同时,FusionPBX也提供了一些实用的功能,比如在线音频播放和录制,呼叫会议等等。 值得注意的是,图形化界面只是对freeswitch的操作和配置进行了简化和优化,并不代表可以完全替代命令行操作。因此,对于freeswitch使用者,仍需掌握一些基本的命令行操作和配置知识,以便更好地利用图形化界面完成自己的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾宝玉的玉宝贾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值