在 Python 中,当尝试创建同时支持 SimpleXMLRPC 和 DBusGMainLoop 的服务时,会遇到服务无法响应 DBus 调用事件(例如 on_call_state_changed 函数未被调用)的问题。
2. 解决方案
为了解决这个问题,我们完成了以下步骤:
- 首先,我们需要创建一个 SlfPhoneConnector 类,该类将处理所有与 SflPhone(DBus 服务)相关的操作,包括监听各种信号和发出方法调用。
- 然后,我们需要启动 DBusGMainLoop 以启用 DBus 事件循环。
- 接下来,我们需要创建一个 SimpleXMLRPCServer 对象并注册 SlfPhoneConnector 实例。
- 最后,我们需要在单独的线程中启动 SimpleXMLRPCServer,以防止它阻塞 DBus 事件循环。
以下是一段示例代码:
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gobject
from gobject import GObject
from SimpleXMLRPCServer import SimpleXMLRPCServer
import thread
from os import path
class SlfPhoneConnector :
def __init__(self) :
self.activeCalls = {}
account = {
"username" : "1111",
"Account.type" : "SIP",
"hostname" : "192.168.1.109",
"Account.alias" : "1111",
"password":"1111",
"Account.enable" : "TRUE"
}
session = dbus.SessionBus()
conf_obj = session.get_object("org.sflphone.SFLphone", "/org/sflphone/SFLphone/ConfigurationManager")
self.conf_mgr = dbus.Interface(conf_obj ,"org.sflphone.SFLphone.ConfigurationManager")
call_obj = session.get_object("org.sflphone.SFLphone", "/org/sflphone/SFLphone/CallManager")
self.call_mgr = dbus.Interface(call_obj ,"org.sflphone.SFLphone.CallManager")
self.call_mgr.connect_to_signal('incomingCall', self.on_incoming_call)
self.call_mgr.connect_to_signal('callStateChanged', self.on_call_state_changed)
self.account_id = self.conf_mgr.addAccount(account)
self.conf_mgr.sendRegister(self.account_id, 1)
#self.call_mgr.placeCall(self.account_id, self.account_id, "2222" )
def on_incoming_call(self, account, callid, to):
print "Incoming call: " + account + ", " + callid + ", " + to
self.activeCalls[callid] = {'Account': account, 'To': to, 'State': '' }
self.call_mgr.accept(callid)
# On call state changed event, set the values for new calls,
# or delete the call from the list of active calls
def on_call_state_changed(self, callid, state):
print "Call state changed: " + callid + ", " + state
if state == "HUNGUP":
try:
del self.activeCalls[callid]
except KeyError:
print "Call " + callid + " didn't exist. Cannot delete."
elif state in [ "RINGING", "CURRENT", "INCOMING", "HOLD" ]:
try:
self.activeCalls[callid]['State'] = state
except KeyError, e:
print "This call didn't exist!: " + callid + ". Adding it to the list."
callDetails = self.getCallDetails(callid)
self.activeCalls[callid] = {'Account': callDetails['ACCOUNTID'], 'To': callDetails['PEER_NUMBER'], 'State': state }
elif state in [ "BUSY", "FAILURE" ]:
try:
del self.activeCalls[callid]
except KeyError, e:
print "This call didn't exist!: " + callid
def getCallDetails(self, callid):
"""Return informations on this call if exists"""
return self.call_mgr.getCallDetails(callid)
def place_call(self, callid):
self.call_mgr.placeCall(self.account_id, self.account_id, callid)
def hangup(self) :
call0 = self.activeCalls.keys()[0]
self.call_mgr.hangUp(call0)
def start_server(obj):
server = SimpleXMLRPCServer( ("localhost", 9988), allow_none= True)
server.register_instance(obj)
print "server start @localhost 9988 forever ..."
server.serve_forever()
if __name__ == "__main__" :
DBusGMainLoop(set_as_default=True)
s = SlfPhoneConnector()
thread.start_new_thread(start_server(s,))
... {{ another code here }}
#loop = gobject.MainLoop()
#loop.run()
通过遵循这些步骤,我们可以让 SimpleXMLRPC 和 DBusGMainLoop 同时运行,而不会影响 DBus 事件循环。