我正在使用Python和PJSUA2创建一个SIP客户端。 我正在用运行在同一主机上的SIP服务器进行测试。 当我调用makeCall()时,Wireshark显示了以下内容。
我的客户端从来没有ACK过200-OK消息。 应该是自动完成还是我需要配置一些东西来让它ACK?
import time
import pjsua2 as pj
class MyCall(pj.Call):
def onCallState(self, prm):
print("***OnCallState: ")
call_info = self.getInfo()
print("current state is " + str(call_info.state) + " " + call_info.stateText)
print("last status code: " + str(call_info.lastStatusCode))
ep = pj.Endpoint()
ep_cfg = pj.EpConfig()
ep_cfg.uaConfig.threadCnt = 0
ep.libCreate()
ep.libInit(ep_cfg)
sipTpConfig = pj.TransportConfig()
ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sipTpConfig)
ep.libStart()
# Create the account information
acfg = pj.AccountConfig()
acfg.idUri = "sip:[email protected]";
acfg.regConfig.registrarUri = "sip:pjsip.org";
cred = pj.AuthCredInfo("digest", "*", "test", 0, "pwtest");
acfg.sipConfig.authCreds.append( cred );
acc = pj.Account()
acc.create(acfg)
call = MyCall(acc, pj.PJSUA_INVALID_ID)
prm = pj.CallOpParam(True)
call.makeCall("sip:[email protected]", prm)
time.sleep(5)
ep.libDestroy()
del ep
难道你不需要一个回调的账户吗?我有一个helper文件,在那里我对来电进行回调。我不知道是不是这个问题,我也是来这里寻求智慧的... ...
import sys
import pjsua as pj
import threading
import time
current_call=None
# Callback to receive events from Account
class MyAccountCallback(pj.AccountCallback):
sem = None
def __init__(self, account):
pj.AccountCallback.__init__(self, account)
def wait(self):
self.sem = threading.Semaphore(0)
self.sem.acquire()
#Notification when account registration state has changed
def on_reg_state(self):
if self.sem:
if self.account.info().reg_status >= 200:
self.sem.release()
# Notification on incoming call
def on_incoming_call(self, call):
global current_call
if current_call:
call.answer(486, "Busy")
return
print "Incoming call from ", call.info().remote_uri
current_call = call
call_cb = MyCallCallback(current_call)
current_call.set_callback(call_cb)
current_call.answer(180)
time.sleep(0.1)
current_call.answer(200)
# Callback to receive events from Call
class MyCallCallback(pj.CallCallback):
def __init__(self, call=None):
pj.CallCallback.__init__(self, call)
# Notification when call state has changed
def on_state(self):
global current_call
print "Call is ", self.call.info().state_text,
print "last code =", self.call.info().last_code,
print "(" + self.call.info().last_reason + ")"
if self.call.info().state == pj.CallState.DISCONNECTED:
current_call = None
print 'Current call is', current_call
# Notification when call's media state has changed.
def on_media_state(self):
if (self.call.info().media_state == pj.MediaState.ACTIVE):
# Connect the call to sound device
call_slot = self.call.info().conf_slot
pj.Lib.instance().conf_connect(call_slot, 0)
pj.Lib.instance().conf_connect(0, call_slot)
print "\nMEDIA IS ACTIVE\n"
else:
print "\n\MEDIA IS *NOT* ACTIVE\n"
我终于想明白了。 我把它贴在这里,以防别人遇到同样的问题。 我需要告诉端点处理事件。
while True:
ep.libHandleEvents(10)
从... https:/www.pjsip.orgdocsbook-latesthtmlendpoint.html#starting-the-library
int libHandleEvents(unsigned msec_timeout)轮询pjsua是否有事件发生,如果有必要,会在指定的最大时间间隔(以毫秒为单位)内阻塞调用者线程。
如果应用程序在pjsua_config结构中配置了工作线程(thread_cnt字段),通常不需要调用这个函数,因为轮询将由这些工作线程来完成。
如果EpConfig::UaConfig::mainThreadOnly被启用,并且这个函数被主线程调用(默认情况下,主线程是调用libCreate()的线程),那么这个函数也会扫描并运行列表中的任何待处理作业。