如果你正在Windows平台上开发一个支持音视频通话的SIP客户端,PJSIP绝对是一个绕不开的开源库。作为一个集成了SIP、媒体和NAT穿透功能的强大工具链,PJSIP已经被广泛应用于VoIP、视频会议等实时通信场景。我在实际项目中多次使用PJSIP开发企业级通信系统,发现它在处理音视频编解码、网络传输和跨平台兼容性方面表现尤为出色。
相比其他SIP协议栈,PJSIP最大的优势在于它完整实现了SIP协议栈的同时,还内置了媒体处理能力。这意味着你不需要再额外集成其他媒体库,就能实现音视频通话的核心功能。特别是在Windows平台上,PJSIP可以与DirectShow、SDL2等本地API无缝集成,大大简化了摄像头采集和视频渲染的开发难度。
我最近接手的一个项目就是基于MicroSip客户端进行二次开发,需要增加视频通话功能。经过技术调研,最终选择了PJSIP作为底层支撑。整个过程虽然遇到不少坑,但最终效果令人满意。下面我就把完整的配置和编译过程分享出来,希望能帮你少走弯路。
在开始编译PJSIP之前,我们需要先准备好Windows开发环境。我推荐使用Visual Studio 2019作为开发工具,因为它对C++11标准的支持比较完善,而且社区版完全免费。安装VS2019时,记得勾选"使用C++的桌面开发"工作负载,这会自动安装必要的编译工具链。
另一个关键组件是Windows SDK。我建议选择较新的版本(如10.0.19041.0),这样可以确保对最新硬件设备的支持。在VS安装器中,你可以很方便地选择安装特定版本的Windows SDK。安装完成后,记得在VS的项目属性中检查平台工具集和Windows SDK版本是否匹配,这是后续编译成功的关键。
PJSIP的源码可以从官网直接下载。我使用的是2.11.1版本,这个版本稳定性较好,社区支持也比较完善。下载后解压到一个不含中文和空格的路径下,比如D:\Dev\pjsip-2.11.1。
除了PJSIP本身,我们还需要准备几个关键的依赖库:
FFmpeg:用于音视频编解码处理。建议下载官方预编译的Windows版本,解压后放在D:\Dev\ffmpeg这样的路径下。
SDL2:用于视频渲染和音频播放。同样下载预编译版本,解压到D:\Dev\SDL2-2.0.18。
OpenH264:这是调用本地摄像头必须的编解码器。需要从Cisco官网下载Windows版本的动态库,放在D:\Dev\openh264。
这些依赖库的路径后面在配置PJSIP时会用到,所以建议提前规划好目录结构。我习惯把所有第三方库都放在一个统一的Dev目录下,这样管理起来比较方便。
PJSIP的编译配置主要通过config_site.h文件实现。这个文件需要手动创建在pjlib/include/pj/目录下。最简单的方法是复制同目录下的config_site_simple.h并重命名。
下面是我在实际项目中使用的配置,特别针对音视频功能做了优化:
c复制/* 视频支持配置 */
#define PJMEDIA_HAS_VIDEO 1
#define PJMEDIA_HAS_OPENH264_CODEC 1
#define PJMEDIA_HAS_LIBYUV 1
#define PJMEDIA_VIDEO_DEV_HAS_SDL 1
#define PJMEDIA_VIDEO_DEV_HAS_DSHOW 1
/* FFmpeg支持 */
#define PJMEDIA_HAS_FFMPEG 1
/* 编解码器配置 */
#define PJMEDIA_HAS_OPENH264_CODEC 1
#define PJMEDIA_HAS_VPX_CODEC 1
#define PJMEDIA_HAS_VPX_CODEC_VP9 1
/* 其他优化配置 */
#define PJSUA_MAX_VIDEO_INSTANCES 4
#define PJMEDIA_VIDEO_STREAM_MAX_WIDTH 1920
#define PJMEDIA_VIDEO_STREAM_MAX_HEIGHT 1080
这个配置中,有几个关键点需要注意:
PJMEDIA_HAS_VIDEO必须设为1,否则视频功能会被完全禁用PJMEDIA_HAS_OPENH264_CODEC是调用摄像头必须的,很多教程会忽略这一点打开PJSIP源码目录下的pjproject-vs14.sln解决方案文件(VS2019可以完美兼容)。首先需要调整解决方案的平台工具集和Windows SDK版本,确保与你安装的环境一致。
接下来是最关键的依赖库配置。右键点击解决方案中的pjsua项目,选择"属性",在"VC++目录"中添加包含目录和库目录:
包含目录添加:
code复制D:\Dev\ffmpeg\include
D:\Dev\SDL2-2.0.18\include
D:\Dev\openh264\include
库目录添加:
code复制D:\Dev\ffmpeg\lib
D:\Dev\SDL2-2.0.18\lib\x86
D:\Dev\openh264\lib
然后在"链接器->输入"中添加额外的依赖项:
code复制avcodec.lib
avformat.lib
avutil.lib
swresample.lib
swscale.lib
SDL2.lib
openh264.lib
这些配置需要应用到所有需要编译的项目上,特别是pjsua、pjsip和pjmedia等核心项目。如果遇到链接错误,很可能是某些库的路径没有配置正确。
在编译过程中,最常见的问题就是依赖库的版本不匹配。特别是FFmpeg和SDL2,不同版本的API可能会有细微差别。我建议严格按照PJSIP官方文档推荐的版本进行下载。如果遇到函数未定义的错误,可以检查是否使用了不兼容的库版本。
另一个常见陷阱是32位和64位库混用。PJSIP默认会编译32位版本,所以所有依赖库也必须使用32位版本。如果你下载的是64位库,需要在VS中切换解决方案平台,或者重新下载32位版本的依赖库。
PJSIP解决方案中包含了一些测试项目,如pjsystest、pjsip_test等。这些项目经常会因为找不到依赖库而编译失败。实际上,这些测试项目对我们的主要开发目标没有影响,最简单的解决方法是在解决方案中直接排除这些项目。
如果确实需要编译测试项目,可以单独为它们配置依赖库路径。不过根据我的经验,除非你要修改PJSIP核心代码,否则没有必要在这些测试项目上花费太多时间。
OpenH264是一个比较特殊的依赖项,因为它通常以动态库形式提供。在运行时,你需要确保openh264.dll位于可执行文件的搜索路径中。我建议将dll文件复制到输出目录,或者在系统PATH环境变量中添加OpenH264的路径。
如果遇到"无法找到OpenH264编解码器"的错误,很可能是PJMEDIA_HAS_OPENH264_CODEC没有正确定义,或者动态库加载失败。可以检查config_site.h中的定义,并确认dll文件的版本与头文件匹配。
编译成功后,你可以在pjsip-apps\bin目录下找到生成的可执行文件。最简单的测试方法是打开两个命令行窗口,分别运行:
bash复制pjsua-x86_64-vc14-Debug.exe --local-port=5060
pjsua-x86_64-vc14-Debug.exe --local-port=5061
这样你就有了两个SIP客户端实例,可以在它们之间进行通话测试。基本的音频通话只需要输入对方的SIP URI(如sip:127.0.0.1:5061)即可建立连接。
要测试视频功能,需要在通话前进行一些额外配置。在pjsua命令行中输入以下命令:
bash复制vid enable # 启用视频功能
vid acc autotx on # 自动发送视频流
vid acc autorx on # 自动接收并播放视频流
建立通话后,还需要在接听方输入:
bash复制vid call tx on 1 # 启用视频发送
这样双方就能看到来自对方摄像头的视频流了。在我的测试中,使用OpenH264编解码器时,720p视频的延迟可以控制在200ms以内,完全满足一般视频通话的需求。
在实际应用中,你可能需要根据网络条件和硬件性能调整视频参数。以下是一些实用的优化命令:
bash复制# 设置视频分辨率
media vid set codec H264/90000 pt 100
media vid set param 1280 720 15 800000
# 调整编码质量
media vid set codec H264/90000 pt 100
media vid set codec-param 100 profile-level-id=42e01f
这些参数需要根据实际场景进行调整。在我的项目中,发现将关键帧间隔设置为2秒(keyint=50)可以在流畅性和画质之间取得较好的平衡。