Last active
October 14, 2023 14:28
-
-
Save happyj2me/b0132384712dafab031d6b19d8e2ed77 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1.linux平台, webrtc抽取出来静态库和头文件,先用ninja编译完webrtc,然后进入src/out/linux目录(假设src目录下是webrtc相关的代码) | |
1.1 提取所有的.o生成libwebrtc_full.a | |
.ninja_log 里面可以找到所有的.a ; .ninja_deps里面可以找到所有的.o, 但建议用.a去构建最终的静态库 | |
cat libwebrtc_full.ar | |
CREATE libwebrtc_full.a | |
ADDLIB obj/third_party/boringssl/libboringssl.a | |
ADDLIB obj/third_party/protobuf/libprotobuf_full.a | |
ADDLIB obj/libwebrtc.a | |
SAVE | |
END | |
ar -M < libwebrtc.ar | |
ranlib libwebrtc_full.a | |
1.2 提取所有的头文件放入out/linxu/lib目录下 | |
find . -path './third_party' -prune -o -type f -name '*.h' -print | xargs -I '{}' cp --parents '{}' out/linux/lib/ | |
find . -name '*.h' -o -name README -o -name LICENSE -o -name COPYING | grep './third_party' | \ | |
grep -E 'boringssl|expat/files|jsoncpp/source/json|libjpeg|libjpeg_turbo|libsrtp|libyuv|libvpx|opus|protobuf|usrsctp/usrsctpout/usrsctpout' | \ | |
xargs -I '{}' cp --parents '{}' out/linux/lib/ | |
1.3 有了上面的头文件和库,我们就可以引入到其他的工程里面去使用了,这是集成webrtc能力到其他项目中的一种很自然的方法 | |
下面思考一个问题,很多时候我们希望不但可以集成webrtc到其他工程,更重要的是希望集成后,可以单步调测webrtc里面的代码,比如在vscode这个IDE里面 | |
具体应该怎么做才最方便呢,很多时候我们要改动webrtc的代码,我们希望改动后直接编译好webrtc就可以生效了,不想再去打包,拷贝头文件到其他工程 | |
因为这些头文件很多,libwebrtc_full.a 有200多M,如果稍微修改下webrtc代码就需要去这么拷贝,太麻烦了,请看下面1.4所用的方法,就是把工程建立到 | |
webrtc/src/目录下,通过工程相关的配置去规避改动webrtc就需要拷贝的问题,同时,最重要的一点,如果希望能顺利调测,生成的可执行程序必须 | |
放到webrtc/src/out/linux目录下,这个目录同时也是我们通过ninja -C src/out/linux xxx 去编译webrtc的时候的输出目录 | |
1.4 假设新建一个transfer实时转码程序,它依赖webrtc库提供的一些能力,我们用vscode这个linux平台的IDE进行开发 | |
首先我们需要考虑transfer这个实时转码程序需要依赖的能力,具体分析如下: | |
它需要webrtc的能力,因为我们希望合并多路音视频流到一路,webrtc里面有合音的代码可以利用,另外,webrtc代码提供了很多类似线程,网络方面的封装,都是可以利用的 | |
它需要http+json的能力,因为我们转码服务器需要一些配置,比如多路画面如何布局等等,这些都可以通过http+json的配置方式解决(transfer接收http配置请求) | |
它需要一套信令传输系统,和其他部件进行交互,可以考虑http或者websocket,如果是http,那么它需要http client+ http server的能力 | |
基于以上的考虑,我们集成一下基础开源能力部件,考虑到webrtc代码过于庞大,我们的目的主要是需要调测webrtc代码,所以我们把这些能力集成到webrtc的third_party目录下: | |
nlohmann_json: 提供json的能力,它的代码放入third_party/json子目录下(libsourcey使用了它提供json的能力) | |
restclient-cpp: 提供http client的能力,它的库和头文件放入third_party/restclieng-cpp子目录下 | |
webrtc: 提供webrtc端的能力 | |
libsourcy: 它提供了很多基础能力,比如网络,线程,事件分发,还能把这些能力和webrtc结合起来提供视频录制,视频分析等功能,它的库和文件放入third_party/libsourcey子目录下 | |
多提一句,libsourcy的代码结构以及编译系统组织的很好,可以拿出来单独几个模块使用,transfer里面利用它的base,json,webrtc三个模块,具体编译方法查看官网介绍 | |
如果想依赖外部的ffmepg,可以查看libsourcey/cmake/FindFFmpeg.cmake的内容,修改ffmpeg_root的位置 | |
1.4.1 VSCODE-transfer工程目录结构的设计,以webrtc为主: | |
/home/kevin/webrtc/linux/src -----> webrtc-linux平台下的源码(适用于android以及linux两个平台下的开发) | |
/home/kevin/webrtc/linux/src/out/linux/compile.sh -----> 如果改动了webrtc相关代码,可以用来重新编译webrtc,打成libwebrtc_full.a | |
/home/kevin/webrtc/linux/CMakeLists.txt -----> 它调用transfer下的CMakeList.txt | |
/home/kevin/webrtc/linux/transfer | |
/home/kevin/webrtc/linux/transfer/CMakeLists.txt -----> 完成transfer相关代码的编译以及连接 | |
/home/kevin/webrtc/linux/transfer/src -----> transfer的源码 | |
/home/kevin/webrtc/linux/transfer/lib -----> transfer依赖的第三方库 | |
/home/kevin/webrtc/linux/transfer/bin -----> 编译后的可执行程序存放目录 | |
/home/kevin/webrtc/linux/src/out/linux/compile.sh: | |
#!/bin/bash | |
# $1: The platform | |
# $2: The list of object file paths to be combined | |
# $3: The output library name | |
function combine::static() { | |
local platform="$1" | |
local outputdir="$2" | |
local libname="$3" | |
echo $libname | |
pushd $outputdir >/dev/null | |
rm -f $libname.* | |
# Find only the libraries we need | |
if [ $platform = 'win' ]; then | |
local whitelist="boringssl.dll.lib|protobuf_lite.dll.lib|webrtc\.lib|field_trial_default.lib|metrics_default.lib" | |
else | |
local whitelist="boringssl\.a|protobuf_full\.a|webrtc\.a|field_trial_default\.a|metrics_default\.a" | |
fi | |
cat .ninja_log | tr '\t' '\n' | grep -E $whitelist | sort -u >$libname.list | |
# Combine all objects into one static library | |
case $platform in | |
win) | |
# TODO: Support VS 2017 | |
"$VS140COMNTOOLS../../VC/bin/lib" /OUT:$libname.lib @$libname.list | |
;; | |
*) | |
# Combine *.a static libraries | |
echo "CREATE $libname.a" >$libname.ar | |
while read a; do | |
echo "ADDLIB $a" >>$libname.ar | |
done <$libname.list | |
echo "SAVE" >>$libname.ar | |
echo "END" >>$libname.ar | |
ar -M < $libname.ar | |
ranlib $libname.a | |
rm $libname.list | |
rm $libname.ar | |
;; | |
esac | |
popd >/dev/null | |
} | |
ninja -C . webrtc | |
combine::static "linux" "./" libwebrtc_full | |
/home/kevin/webrtc/linux/CMakeLists.txt: | |
cmake_minimum_required(VERSION 3.5.1) | |
add_subdirectory(src/transfer ${CMAKE_CURRENT_SOURCE_DIR}/transfer/build) | |
/home/kevin/webrtc/linux/transfer/CMakeLists.txt: | |
cmake_minimum_required(VERSION 3.5.1) | |
project(transfer) | |
# Typically you don't care so much for a third party library's tests to be | |
# run from your own project's code. | |
set(JSON_BuildTests OFF CACHE INTERNAL "") | |
# If you only include this third party in PRIVATE source files, you do not | |
# need to install it when your main project gets installed. | |
set(JSON_Install OFF CACHE INTERNAL "") | |
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it | |
# unintended consequences that will break the build. It's generally | |
# discouraged (although not necessarily well documented as such) to use | |
# include(...) for pulling in other CMake projects anyways. | |
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../src/third_party/json json) | |
#add_library(foo ...) | |
#target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) | |
set(CMAKE_VERBOSE_MAKEFILE on) | |
set(CMAKE_CXX_COMPILER "clang++") | |
set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ -fno-rtti ${CMAKE_CXX_FLAGS}") | |
add_definitions(-DWEBRTC_POSIX) | |
add_definitions(-DWEBRTC_LINUX) | |
set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../src/third_party/libsourcey/lib/pkgconfig") | |
find_package(PkgConfig REQUIRED) | |
pkg_search_module(PKG_SCY REQUIRED libsourcey) | |
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) | |
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/third_party/abseil-cpp) | |
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/third_party/restclient-cpp/include) | |
include_directories(${PKG_SCY_INCLUDE_DIRS}) | |
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/out/linux) | |
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/third_party/restclient-cpp/lib) | |
add_executable(transfer src/main.cpp) | |
target_link_libraries(transfer nlohmann_json::nlohmann_json | |
restclient-cpp | |
${PKG_SCY_LDFLAGS} | |
webrtc_full | |
pthread) | |
set_target_properties(transfer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../src/out/linux) | |
1.4.2 /home/kevin/webrtc/linux/.vscode目录下的相关配置文件及其内容 | |
c_cpp_properties.json -----> 这个文件主要用来告诉vscode头文件到哪里去查找 | |
{ | |
"configurations": [ | |
{ | |
"name": "Linux", | |
"includePath": [ | |
"${workspaceFolder}/**", | |
"${workspaceFolder}/src/third_party/abseil-cpp", | |
"${workspaceFolder}/src/third_party/json/single_include", | |
"${workspaceFolder}/src/third_party/libsourcey/include", | |
"${workspaceFolder}/src/third_party/restclient-cpp/include" | |
], | |
"defines": [], | |
"compilerPath": "/usr/bin/clang", | |
"cStandard": "c11", | |
"cppStandard": "c++17", | |
"intelliSenseMode": "clang-x64", | |
"compileCommands": "${workspaceFolder}/src/transfer/build/compile_commands.json" | |
} | |
], | |
"version": 4 | |
} | |
settings.json -----> 相关的配置,这些配置的范围可以是项目级别,也可以是用户级别,这里配置项目级别: | |
告诉vscode不要去管这些目录的变化情况,因为里面的文件太多了,超过了vscode的关注能力 | |
如果想扩大这个能力,修改/etc/sysctl.conf,在文件最后加一行 | |
fs.inotify.max_user_watches=524288,然后sudo sysctl -p | |
{ | |
"search.exclude": { | |
"**/src/examples": true, | |
"**/src/out": true, | |
"**/src/third_party": true, | |
"**/transfer/build": true, | |
"**/transfer/lib": true | |
} | |
} | |
launch.json -----> 告诉vscode如何运行我们编译好的程序 | |
{ | |
// Use IntelliSense to learn about possible attributes. | |
// Hover to view descriptions of existing attributes. | |
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | |
"version": "0.2.0", | |
"configurations": [ | |
{ | |
"name": "(gdb) Launch", | |
"type": "cppdbg", | |
"request": "launch", | |
"program": "${workspaceFolder}/src/out/linux/transfer", | |
"args": [], | |
"stopAtEntry": false, | |
"cwd": "${workspaceFolder}", | |
"environment": [], | |
"externalConsole": false, | |
"MIMode": "gdb", | |
"setupCommands": [ | |
{ | |
"description": "Enable pretty-printing for gdb", | |
"text": "-enable-pretty-printing", | |
"ignoreFailures": true | |
} | |
] | |
} | |
] | |
} | |
tasks.json ----->告诉vscode如何去编译我们的程序,因为额外在vscode里面安装了一个cmake插件,所以其实这个文件没有用到 | |
编译的时候是用的cmake插件,但是其实配置下tasks.json一样可以达到编译CMakeLists.txt的目的,待研究 | |
{ | |
"tasks": [ | |
{ | |
"type": "shell", | |
"label": "clang++-3.8 build active file", | |
"command": "/usr/bin/clang++-3.8", | |
"args": [ | |
"-g", | |
"${file}", | |
"-o", | |
"${fileDirname}/${fileBasenameNoExtension}" | |
], | |
"options": { | |
"cwd": "/usr/bin" | |
} | |
} | |
], | |
"version": "2.0.0" | |
} | |
1.4.3 用vscode open /home/kevin/webrtc/linux 这个目录,就可以查看,编译,单步调测相关源码了(包括webrtc) | |
1.4.4 编译的时候,需要注意,默认webrtc使用libc++标准库,所以先sudo apt-get install libc++-dev,否则会提示说list找不到; | |
另外,CMakeLists.txt中指定编译选项 -stdlib=libc++ 用clang++去编译,否则会报一堆的symbol undefined错误 | |
其他注意的地方: | |
1. libsourcey最低要求c++14去编译 | |
2. 所有cpp编写的第三方库的编译使用clang++完成,和webrtc对齐 | |
3. 服务器对显示界面方面没有要求,webrtc要想办法要去掉x11相关的库依赖,附上一份不需要x11的arm64机器上的args.gn | |
target_cpu = "arm64" | |
target_os = "linux" | |
rtc_use_fake_ui=true | |
rtc_use_sdk_mode=true | |
rtc_use_external_capturer=true | |
rtc_use_h264=true | |
rtc_use_x264=false | |
rtc_use_uws=true | |
rtc_build_ssl=false | |
rtc_ssl_version="arm64" | |
is_clang=false | |
use_sysroot=false | |
linux_use_bundled_binutils=false | |
use_custom_libcxx=false | |
use_custom_libcxx_for_host=false | |
rtc_use_x11=false | |
rtc_include_internal_audio_device=false | |
rtc_libvpx_build_vp9=false | |
rtc_use_new_stat_api=false | |
treat_warnings_as_errors=false | |
5. 如果需要x11,那么需要安装 | |
sudo apt-get install libalsa-ocaml-dev libpulse-dev libxcomposite-dev libxrender-dev libxext-dev libxdamage-dev libcairo2-dev | |
webrtc依赖的c++标准库在 src/build/config/android/BUILD.gn中定义 | |
标准库的位置:third_party/android_tools/ndk/sources/cxx-stl --- 该目录下有很多标准库,webrtc默认使用llvm的libc++_shared.so | |
交叉编译ARM-LINUX平台(host是ubuntu16.04): | |
sudo apt get install binutils-aarch64-linux-gnu binutils-arm-linux-gnueabihf --- 分别安装64以及32的交叉编译环境 | |
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu | |
这些工具的名字记录位置: src/build/toolchain/linux/BUILD.gn 里面 | |
然后: | |
gn gen out/arm64 --args='target_cpu="arm64" target_os="linux"' | |
ninja -C out/arm64 peerconnection_client | |
依赖库脚本安装: src/build/linux/sysroot_scripts/install-sysroot.py --arch=arm64 | |
clang编译webrtc静态库 | |
ninja -C out/linux | |
得到libwebrtc.a,这个静态库包括webrtc全部的o文件. | |
直接-lwebrtc, -I${webrtc}/src目录,就可以用native api开发了. | |
由于webrtc编译时,采用clang进行的编译,所以如果二次开发环境是gcc,会遇到一些库的不兼容 | |
例如: | |
undefined reference:string<char, char_traits<char>, allocator<char> >::~basic_string() | |
解决方法: | |
把webrtc的clang环境,引入到二次开发的工程中,步骤如下. | |
(1)在${webrtc}/src/out/linux/obj/buildtools/third_party中,找到.o文件,分别打包. | |
ar -crv libc++.a *.o | |
ar -crv libc++abi.a *.o | |
(2)在二次开发的工程中,引入这两个a文件,-lc++,-lc++abi | |
(3)把g++和gcc替换成clang++和clang,可执行文件在${webrtc}src/third_party/llvm-build/Release+Asserts/bin下面 | |
(4)包含头文件位置: | |
${webrtc}/src/buildtools/third_party/libc++/trunk/include | |
${webrtc}/src/third_party/llvm-build/Release+Asserts/lib/clang/6.0.0/include | |
(5)为防止clang与gcc的标准库冲突,在编译时指定选项,-nostdinc++,表示不要搜索标准系统头文件目录 | |
(6)预定义WEBRTC_POSIX和WEBRTC_LINUX | |
(7)webrtc关闭了 rtti机制,以减小应用程序大小,所以在继承webrtc的类时,需要在g++中添加 -fno-rtti选项. | |
总结,用webrtc或者chromium的二次开发,不仅需要引入.a的静态库文件,同时需要引入相应的c++编译环境,包括clang的依赖库,bin和头文件. | |
openssl vs boringssl | |
rtc_build_ssl = false && rtc_ssl_root = //third_party/openssl/include , 这样就可以切换到openssl了,注意一下几点: | |
1. third_party 里面 usrsctp 以及 libsrtp 依赖 boringssl, 就是没有注意修改这两个地方,导致编译进去openssl以后, | |
DTLSV1_get_timeout函数表现异常,挂掉 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment