2024年6月6日,QQ For Linux 3.2.9 正式支持了音视频通话功能,这是 QQ Linux 版本的又一个里程碑事件。 2024 年,QQ 音视频正式推出 NTRTC,全平台(iOS/Android/MacOS/Windows/Linux)的支持是 NTRTC 的重要特性之一,本次 Linux 平台的适配也是这次升级过程中重要的一环。
本文详细记录了新版QQ音视频通话在 Linux 平台适配开发过程中的技术方案与实现细节,希望能帮助大家理解在 Linux 平台从 0 到 1 实现音视频通话能力的过程。
/usr/bin/ld: ../../../qav_rtc_sdk/av_engine/android_ios_mac/Lib/Linux/x86_64/libTcH264Enc.a(cabac-a.asm.o): relocation R_X86_64_PC32 against symbol `g_kuiCabacRangeLps' can not be used when making a shared object; recompile with -fPIC
这个错误时机上是 ar 提取文件时,复制到待合并文件夹时环节出现的,是不同的静态库有相同命名的 .o 文件,通过重命名,还比较好解决;
2)同一个静态库,相同命名的 .o:
解决了 .o 覆盖的问题,再次 link,还是缺失符号,通过排查还是丢了对应的符号,再次排查哪一步丢的,我们发现一个静态库内出现相同命名的 .o 符号段,两个符号段在不同位置,ar x 提取时,会优先命中第一个搜索到的 .o 段,后面遇到的都会忽略,这就棘手了,是工具提取环节出现的丢失,排查了一些 ar 选项没有解决;
解决方法:通过修改该静态库内相同源文件命名解决。
3)Demo Link & Demo Run:
经过上面2个方面的适配,解决一系列link问题后,较顺利的输出了 x64 版本的 qav_rtc_sdk.a。
我们通过之前提到的 qt_demo, 进行 link 验证,也没有问题,自回环的逻辑也正常跑起来,基于 QT 开发环境也可以正常调试,此时音频、视频能力可以先开始验证。
4)AVSDKPlugin & electron demo:
我们输出了 x64 版本的 AVSDKPlugin.so,搭建了一个 electron demo,用于验证我们的动态库是否可以正常运行;
这里需要在 Linux 安装 electron 环境,具体看 Electron Quick Start。
然后我们遇到了第一个问题:动态库拉不起来!
错误信息:182204.991288: ERROR:ppapi_thread.cc(269) Failed to load Pepper module from ~/robert/AVSDKPluginDemo/app/avsdk/libAVSDKPlugin.so(error cannot open shared object file: Operation not permitted)。
通过错误信息,我们大致能看出来是权限问题,首先通过确认,排除了 so 文件路径错误的问题,那就是权限问题。
GLIBC,全称 GNU C Library,是 GNU 项目的 C 标准库的实现,为系统和应用程序提供了系统调用的封装和许多基本的程序接口。这包括输入输出(I/O)、字符串处理、文件操作、内存管理、数学计算等。GLIBC 是大多数基于 Linux 的系统的标准 C 库,并且是编译大多数 C 程序的必要组件。
AVSDKPlugin.so 放到不同 Linux 版本上运行时,比如 Ubuntu 18、Fedora 23、Qlin 等系统上,发现音视频拉不起来?
通过ldd AVSDKPlugin.so 我们发现出现一些依赖库 no found, 或者 GLIBC need 2.29等错误信息。
这个是 Ubuntu 18(x64)的报错:
robert@ubuntu:~/.config/QQ/global/ext_lib/avsdk$ ldd libAVSDKPlugin.so
./libAVSDKPlugin.so: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by ./libAVSDKPlugin.so)
./libAVSDKPlugin.so: /lib/x86_64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.13' not found (required by ./libAVSDKPlugin.so)
xplatform-ng/xpng/task/coroutine/task.h:31:30: fatal error: use of undeclared identifier 'experimental'
using coroutine_handle = experimental::coroutine_handle<T>;
Warning: vkCreateInstance: Found no drivers!
Warning: vkCreateInstance failed with VK_ERROR_INCOMPATIBLE_DRIVER
at CheckVkSuccessImpl (../../third_party/dawn/src/dawn/native/vulkan/VulkanError.cpp:101)
此时我们通过启动 qq 时增加:
qq --enable-logging=stderr --v=1
又多出一些信息:
[9364:0415/181411.892176:ERROR:gl_utils.cc(412)] [.WebGL-0x200029f800]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels
[9364:0415/181411.949701:ERROR:gl_utils.cc(412)] [.WebGL-0x200029f800]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels
[9364:0415/181411.976514:ERROR:gl_utils.cc(412)] [.WebGL-0x200029f800]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels
[9364:0415/181412.027489:ERROR:gl_utils.cc(412)] [.WebGL-0x200029f800]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels (this message will no longer repeat)
#if BUILDFLAG(IS_ANDROID)
if (browser_cmd.HasSwitch(switches::kDisableGpuCompositing)) {
renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing);
}
#elif !BUILDFLAG(IS_CHROMEOS_ASH)
// If gpu compositing is not being used, tell the renderer at startup. This
// is inherently racey, as it may change while the renderer is being
// launched, but the renderer will hear about the correct state eventually.
// This optimizes the common case to avoid wasted work.
if (GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled())
renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing);
#endif // BUILDFLAG(IS_ANDROID)
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #3 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #27 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #28 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #29 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #50 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #134 in gpu_blocklist.
VERBOSE1:gpu_control_list.cc(296)] Control list match for rule #176 in gpu_blocklist.