调用 Endpoint.utilAddPendingJob(job) 时遇到问题

Posted

技术标签:

【中文标题】调用 Endpoint.utilAddPendingJob(job) 时遇到问题【英文标题】:Having trouble with calling Endpoint.utilAddPendingJob(job) 【发布时间】:2019-06-28 20:35:20 【问题描述】:

我正在尝试从 Python 调用 PJSUA2 库,它工作正常,但我在尝试调用时遇到了障碍

void utilAddPendingJob(PendingJob *job)

导致以下错误

TypeError:在方法“Endpoint_utilAddPendingJob”中,类型为“pj::PendingJob *”的参数 2

Python代码如下:

import pjsua2 as pj

class MyJob(pj.PendingJob):
    def __init__(self, text):
        self.text = text

    def execute(self, is_pending = False):
        print(text)

<<SNIP>>

job = MyJob("test")
pj.Endpoint.instance().utilAddPendingJob(job)

我看到的唯一区别是这个函数在 C++ 端采用指针而不是引用。但是,查看 SWIG 手册,这并不重要。

编辑: 这是 PendingJob SWIG 生成的 Python 类:

class PendingJob(_object):
    __swig_setmethods__ = 
    __setattr__ = lambda self, name, value: _swig_setattr(self, PendingJob, name, value)
    __swig_getmethods__ = 
    __getattr__ = lambda self, name: _swig_getattr(self, PendingJob, name)

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined - class is abstract")
    __repr__ = _swig_repr

    def execute(self, is_pending):
        return _pjsua2.PendingJob_execute(self, is_pending)
    __swig_destroy__ = _pjsua2.delete_PendingJob
    __del__ = lambda self: None
PendingJob_swigregister = _pjsua2.PendingJob_swigregister
PendingJob_swigregister(PendingJob)

还有方法签名,再次 SWIG 生成 Python 代码:

    def utilAddPendingJob(self, job):
        return _pjsua2.Endpoint_utilAddPendingJob(self, job)

【问题讨论】:

您已经展示了一个名为 AudioJob 的类,但随后创建了一个名为 MyJob 的类的实例。鉴于我认为问题在于你定义的类,你能澄清发生了什么吗? 你完全正确,这是一个错字。马上更新,谢谢! 【参考方案1】:

看起来这里有一个简单的错误,导致 SWIG 无法意识到您正在创建的对象实际上是 pj.PendingJob 的一个实例 - 您没有调用超类的 __init__ 函数。

像这样添加:

class MyJob(pj.PendingJob):
    def __init__(self, text):
        self.text = text
        super().__init__() # Python3 niceness, alternatives available for Python2

我认为你会重新开始营业。

(超类构造函数在 SWIG 中始终很重要,它创建了一个真正的 C++ 实例来实现你的虚函数)。

然而,在这种情况下,您使用的包装器似乎尚未设置为允许 pj.PendingJob 类上的跨语言多态性。如果你签出 pjsip 然后运行这个:

find . -iname '*.i' -execdir cat  \; | grep 'director'

那么在任何地方都没有对PendingJob 的引用(也没有隐藏它的宏)。

为了便于理解,让我们通过实验来验证这一点:

%module(directors="1") test

%director Test2;

%inline %
struct Test1 
  virtual ~Test1() 
  virtual void blah() = 0;
;
%

%inline %
struct Test2 
  virtual ~Test2() 
  virtual void blah() = 0;
;
%

当我们通过 SWIG 运行它时,我们看到为两个类生成的 __init__ 不同。对于具有%director 指令(即Test2)的类,它是可调用的,并且为跨语言多态性做好了准备工作。对于Test1,我们看到与您在构造函数中报告的__init__ 相同,即它只是引发异常,因为类型是抽象的。 (作为参考,它并非完全没用,因为您可以从 C++ 接收该类型的具体实例,只是您无法在 Python 中创建或扩展它们。

【讨论】:

不幸的是,这不起作用。对象是抽象的,所以调用 super 会抛出异常。 如果它是抽象的,你就不能创建它的实例。您必须实现纯虚拟方法。在 SWIG 手册中有一个例子:swig.org/Doc3.0/Python.html#Python_nn33 我想我已经做到了。我用相关的 SWIG 生成的 Python 代码更新了问题 看起来很可能该类没有为它打开导演,这意味着没有跨语言多态性。稍后我会进行更多调查并正确确认。 @Rob 在这种情况下看起来是不可能的,因为他们没有为这个类启用跨语言多态性。我认为他们可能应该快速扫描源代码,值得为 pjsip-apps/src/swig/pjsua2.i 添加一个补丁,其中添加了%feature("director") PendingJob。 (实际上,您可以使用 Python 中的可调用对象和 Java 中的可运行对象来做一些非常简洁的事情。

以上是关于调用 Endpoint.utilAddPendingJob(job) 时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

java三种调用方式(同步调用/回调/异步调用)

LINUX系统调用

引用调用 vs 复制调用调用

RPC 调用和 HTTP 调用的区别

js方法调用

深入理解Java虚拟机——方法调用(解析调用)