返回

PJSUA2 Python 视频通话错误: 问题分析与解决

windows

PJSUA2 Python 视频通话支持问题分析与解决

使用 Python 的 PJSUA2 库进行视频通话时,可能遇到 Assertion failed: call->opt.vid_cnt == 0, file ../src/pjsua-lib/pjsua_call.c, line 682. 这样的错误。此错误表明在初始化通话时,视频通道设置存在问题。通常,即使 PJSIP 官方的 pjsua-x86_64-w64-mingw32.exe 可正常进行视频通话,通过 SWIG 生成的 Python 扩展也可能出现此问题。此情况多与构建和配置过程有关,需要细致分析并逐一排除。

问题分析

此断言错误在 PJSUA 库中指出,尝试进行视频通话时 call->opt.vid_cnt 预期应为 0, 但实际并非如此。这说明通过 SWIG 生成的 Python 接口虽然启用了视频支持,但实际上没有正确传递或应用视频通话参数,导致视频通道设置异常。可能存在以下几个主要原因:

  1. SWIG 生成接口配置不当: SWIG 在生成 Python 接口时,可能没有正确映射 PJSUA2 C++ API 中涉及视频功能的结构体和选项。某些枚举值,或结构体成员没有被正确的包装导出。

  2. 编译配置错误: 编译 PJSIP 库时,视频支持相关的选项可能没有被正确启用,即便代码中设置了相应的标志。尤其当使用了第三方库(如视频编解码库),则配置错误可能会影响最终生成的库。

  3. 参数传递问题: 在 Python 代码中,尽管设置了 param.opt.videoCount = 1,但这个参数可能没有以正确的形式传递到 PJSUA2 核心库,或者库没有正确读取这些配置,依旧将其识别为禁用状态。

  4. 底层依赖问题: 运行环境中缺失某些必要的视频编解码库,导致 PJSIP 在尝试初始化视频通道时失败。即使编译时配置了视频支持,如果运行环境不支持,仍然会出问题。

解决方案

基于上述分析,下面介绍针对此问题的几种解决方案:

解决方案一:检查并修改 SWIG 接口文件

SWIG 使用 .i 接口文件定义如何从 C/C++ 代码生成包装。检查 pjsua2.i 文件,确认与视频通话相关的结构体、枚举类型、函数定义已正确导出。特别是pjsua_call_option 中的 vid_cntvideoCount 确保被正确定义为可访问属性,而不是被错误的隐藏或省略。检查其参数的包装类型,确保参数类型映射的正确性。

如果发现缺失或错误定义,修改.i文件并重新生成扩展模块。修改 pjsua2.i 文件时,应特别注意enumstruct的定义,比如:

 %include "pjsua.h"
 // 如果结构体需要被操作,那么也要将其进行包装,方便进行取值赋值操作。
%include <windows.i>

 %inline %{
     // enum 和结构体,应该进行正确的包装导出
     typedef struct pjmedia_vid_dev_info pjmedia_vid_dev_info;
     typedef struct pjmedia_vid_codec_param  pjmedia_vid_codec_param;
     typedef struct pjsua_vid_preview_param pjsua_vid_preview_param;
     typedef struct pjsua_call_media_config pjsua_call_media_config;
     typedef struct pjsua_call_option  pjsua_call_option;

     // 添加如下代码可以测试结构体的传递,以及确保包装类型是可访问和可用的。
     pjsua_call_option* testCallOpt() {
          pjsua_call_option * opt =  new pjsua_call_option();
          opt->audio_cnt = 0;
          opt->video_cnt = 1;
          return opt;
    }

 %}

 class pjsua_call_option {

 };

 class CallOpParam {

    // 一些属性定义,参考pjsua.i中的定义。

      public:
          pjsua_call_option opt;

      // ...
 };
 // ... 其他相关的包装代码 ...

执行 swig -python -c++ pjsua2.i,重新生成接口,随后需要进行编译并安装新生成的模块。

操作步骤:

  1. 修改 pjsua2.i 文件。
  2. 执行 SWIG 命令:swig -python -c++ pjsua2.i
  3. 重新编译生成 Python 模块。
  4. 安装或更新 Python 模块。

解决方案二: 确认编译配置及第三方依赖

检查 PJSIP 编译配置,确认 PJMEDIA_HAS_VIDEO 以及所用的视频编解码器支持已启用。如果使用特定视频编解码器,确保正确链接对应的库。可以使用 CMake 检查构建选项,并在编译过程中加入必要支持,比如:

cmake  -DPJMEDIA_HAS_VIDEO=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./output ..

同时也要确保运行时环境已安装相应的视频编解码库,比如如果使用 H.264 编码,运行环境需要有相应的 H.264 解码库,没有则会造成无法调用。可以使用 ldd 或者 dependency walker 等工具检查可执行文件或者动态链接库的依赖情况。

操作步骤:

  1. 检查 CMake 配置:确保视频支持和必要编解码器选项已开启。
  2. 执行 CMake 命令生成构建文件: cmake ...
  3. 执行构建编译命令:如 make install 或者 ninja install 等等。
  4. 检查依赖库情况:通过工具验证 PJSIP 动态链接库所依赖的视频解码库是否缺失。

解决方案三:详细检查参数传递方式

某些情况下,Python 可能因为类型转换或内存管理问题无法正确传递结构体到 C++ 代码。考虑手动创建一个 pjsua_call_option对象并设置相应的参数,使用 SWIG 生成的方法将其传递给 PJSUA2 函数。

使用上文提及的代码片段中的 testCallOpt() 函数对传递的 pjsua_call_option对象做个测试,观察是否正确的创建和返回了预期参数,以排查是否是因为pjsua_call_option这个类型传递存在问题。 如果依然有问题,排查内存释放、类型传递转换等其他相关的问题。确保 pjsua2.i中的类型和代码的对应传递是正确有效的。

操作步骤:

  1. 修改 pjsua2.i 加入测试函数。
  2. 执行SWIG 和编译, 生成新库,并使用新的扩展库执行代码。
  3. 确认代码逻辑正常传递和运行后,修改或编写相应的python 测试脚本。

其他建议

  • 测试环境隔离: 使用虚拟环境,确保库的版本和依赖管理清晰。
  • 详细日志: 设置 PJSUA2 更高的日志级别以获得更详细的信息。 增加代码中日志输出可以协助定位问题。
  • 官方文档: 参考 PJSUA2 的官方文档以及相关 SWIG 使用文档,获取更多指导信息。
  • 小步迭代: 进行修改后,小步测试,确认是某个环节出了问题,切勿一次改动很多。
  • 安全: 在调试期间需要测试环境隔离,以免污染系统环境,同时也要保护测试环境信息,避免安全问题。

解决此问题需要仔细检查构建流程,并对代码的每一环节进行测试和确认。 通过以上步骤,一般能够找出问题,并且最终成功启用 PJSUA2 的视频通话功能。