webrtc 编译 - housekeeper-software/tech GitHub Wiki
最好在买个云主机,位置在美国、新加坡、香港等地,最好是亚马逊的美国服务器,下载不要太快。
https://webrtc.googlesource.com/src.git/+log/refs/branch-heads/4324
如果在同一台机器编译,每个平台都新建一个目录,互相不干扰
比如:
/build/rv1109
/build/linux
/build/android
需要编译debug/release,debug用于开发
源码可以从上述链接下载,但是需要将编译环境中的 src/third_party/abseil-cpp拷贝出来,放在源码的 third_party目录下。
因为源码头文件中也引用了absl头文件。
每个平台编译出来的都是 libwebrtc.a,此库包含所有用到的目标文件,并没有其他依赖。
通过下述方式编译的库,可以提供neteq, audioprocess,等模块的调用。但是一般去掉了audio device,因为我们使用外部的audio device
简单说,就是把以下两个线程中的锁全部注释掉
bool AudioDeviceLinuxALSA::PlayThreadProcess() {
if (!_playing)
return false;
int err;
snd_pcm_sframes_t frames;
snd_pcm_sframes_t avail_frames;
// Lock();
// return a positive number of frames ready otherwise a negative error code
avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout);
if (avail_frames < 0) {
RTC_LOG(LS_ERROR) << "playout snd_pcm_avail_update error: "
<< LATE(snd_strerror)(avail_frames);
ErrorRecovery(avail_frames, _handlePlayout);
// UnLock();
return true;
} else if (avail_frames == 0) {
// UnLock();
// maximum tixe in milliseconds to wait, a negative value means infinity
err = LATE(snd_pcm_wait)(_handlePlayout, 2);
if (err == 0) { // timeout occured
RTC_LOG(LS_VERBOSE) << "playout snd_pcm_wait timeout";
}
return true;
}
if (_playoutFramesLeft <= 0) {
// UnLock();
_ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
// Lock();
_playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
assert(_playoutFramesLeft == _playoutFramesIn10MS);
}
if (static_cast<uint32_t>(avail_frames) > _playoutFramesLeft)
avail_frames = _playoutFramesLeft;
int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout, _playoutFramesLeft);
frames = LATE(snd_pcm_writei)(
_handlePlayout, &_playoutBuffer[_playoutBufferSizeIn10MS - size],
avail_frames);
if (frames < 0) {
RTC_LOG(LS_VERBOSE) << "playout snd_pcm_writei error: "
<< LATE(snd_strerror)(frames);
_playoutFramesLeft = 0;
ErrorRecovery(frames, _handlePlayout);
// UnLock();
return true;
} else {
assert(frames == avail_frames);
_playoutFramesLeft -= frames;
}
// UnLock();
return true;
}
bool AudioDeviceLinuxALSA::RecThreadProcess() {
if (!_recording)
return false;
int err;
snd_pcm_sframes_t frames;
snd_pcm_sframes_t avail_frames;
int8_t buffer[_recordingBufferSizeIn10MS];
//Lock();
// return a positive number of frames ready otherwise a negative error code
avail_frames = LATE(snd_pcm_avail_update)(_handleRecord);
if (avail_frames < 0) {
RTC_LOG(LS_ERROR) << "capture snd_pcm_avail_update error: "
<< LATE(snd_strerror)(avail_frames);
ErrorRecovery(avail_frames, _handleRecord);
// UnLock();
return true;
} else if (avail_frames == 0) { // no frame is available now
// UnLock();
// maximum time in milliseconds to wait, a negative value means infinity
err = LATE(snd_pcm_wait)(_handleRecord, ALSA_CAPTURE_WAIT_TIMEOUT);
if (err == 0) // timeout occured
RTC_LOG(LS_VERBOSE) << "capture snd_pcm_wait timeout";
return true;
}
if (static_cast<uint32_t>(avail_frames) > _recordingFramesLeft)
avail_frames = _recordingFramesLeft;
frames = LATE(snd_pcm_readi)(_handleRecord, buffer,
avail_frames); // frames to be written
if (frames < 0) {
RTC_LOG(LS_ERROR) << "capture snd_pcm_readi error: "
<< LATE(snd_strerror)(frames);
ErrorRecovery(frames, _handleRecord);
// UnLock();
return true;
} else if (frames > 0) {
assert(frames == avail_frames);
int left_size =
LATE(snd_pcm_frames_to_bytes)(_handleRecord, _recordingFramesLeft);
int size = LATE(snd_pcm_frames_to_bytes)(_handleRecord, frames);
memcpy(&_recordingBuffer[_recordingBufferSizeIn10MS - left_size], buffer,
size);
_recordingFramesLeft -= frames;
if (!_recordingFramesLeft) { // buf is full
_recordingFramesLeft = _recordingFramesIn10MS;
// store the recorded buffer (no action will be taken if the
// #recorded samples is not a full buffer)
_ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
_recordingFramesIn10MS);
// calculate delay
_playoutDelay = 0;
_recordingDelay = 0;
if (_handlePlayout) {
err = LATE(snd_pcm_delay)(_handlePlayout,
&_playoutDelay); // returned delay in frames
if (err < 0) {
// TODO(xians): Shall we call ErrorRecovery() here?
_playoutDelay = 0;
RTC_LOG(LS_ERROR)
<< "playout snd_pcm_delay: " << LATE(snd_strerror)(err);
}
}
err = LATE(snd_pcm_delay)(_handleRecord,
&_recordingDelay); // returned delay in frames
if (err < 0) {
// TODO(xians): Shall we call ErrorRecovery() here?
_recordingDelay = 0;
RTC_LOG(LS_ERROR) << "capture snd_pcm_delay: "
<< LATE(snd_strerror)(err);
}
// TODO(xians): Shall we add 10ms buffer delay to the record delay?
_ptrAudioBuffer->SetVQEData(_playoutDelay * 1000 / _playoutFreq,
_recordingDelay * 1000 / _recordingFreq);
_ptrAudioBuffer->SetTypingStatus(KeyPressed());
// Deliver recorded samples at specified sample rate, mic level etc.
// to the observer using callback.
//UnLock();
_ptrAudioBuffer->DeliverRecordedData();
//Lock();
}
}
//UnLock();
return true;
}
修改 src目录下的 BUILD.GN
if (!build_with_chromium) {
# Target to build all the WebRTC production code.
rtc_static_library("webrtc") {
# Only the root target and the test should depend on this.
visibility = [
"//:default",
"//:webrtc_lib_link_test",
]
sources = []
complete_static_lib = true
suppressed_configs += [ "//build/config/compiler:thin_archive" ]
defines = []
deps = [
"api:create_peerconnection_factory",
"api:libjingle_peerconnection_api",
"api:rtc_error",
"api:transport_api",
"api/crypto",
"api/rtc_event_log:rtc_event_log_factory",
"api/task_queue",
"api/task_queue:default_task_queue_factory",
"api/voip:voip_api", #!!!
"api/voip:voip_engine_factory",#!!!
"rtc_base:rtc_json", #为了编译jsoncpp
"third_party/abseil-cpp/absl/flags:flag",
"third_party/abseil-cpp/absl/flags:parse", #可能用到absl 命令行解析
mkdir webrtc
cd webrtc
fetch --nohooks webrtc
gclient sync
cd src
git checkout branch-heads/4324
gclient sync
通过 gn gen 之后,生成编译脚本
执行 ninja -C out/Debug or ninja -C out/Release即可
libwebrtc.a 位于 out/Debug/gen/obj目录下
查看包含的符号:
nm -C libwebrtc.a | grep xxxx
mkdir webrtc
cd webrtc
fetch --nohooks webrtc_android
gclient sync
cd src
git checkout branch-heads/4324
gclient sync
rv1109不支持clang编译,所以,我们要禁止clang。
判断arm_float_abi 是soft,hard,根据工具链判断:gnueabihf 有h的就是hard
libjpeg-turbo 在gcc上编译出错,我们用内置的libjpeg,因为我们不会用到这块
rv1109也不用支持H264编解码器,我们用rkmpp
把third_party/abseil-cpp/absl/base/config.h中得 ABSL_TLS等等注释
// ABSL_HAVE_THREAD_LOCAL
//
// Checks whether C++11's `thread_local` storage duration specifier is
// supported.
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__)
// Notes:
// * Xcode's clang did not support `thread_local` until version 8, and
// even then not for all iOS < 9.0.
// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
// targeting iOS 9.x.
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
// making ABSL_HAVE_FEATURE unreliable there.
//
#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
#undef ABSL_HAVE_TLS
#undef ABSL_HAVE_THREAD_LOCAL //#define ABSL_HAVE_THREAD_LOCAL 1
#endif
如果无法禁止pulse_audio ,则需要修改/module/audio_deivce/BUILD.gn
defines += [ "WEBRTC_ENABLE_LINUX_ALSA" ]
libs = [ "dl" ]
if (rtc_use_x11) {
libs += [ "X11" ]
defines += [ "WEBRTC_USE_X11" ]
}
if (rtc_include_pulse_audio) {
defines += [ "WEBRTC_ENABLE_LINUX_PULSE" ]
}
if (rtc_include_pulse_audio) { #添加这个条件
sources += [
"linux/audio_device_pulse_linux.cc",
"linux/audio_device_pulse_linux.h",
"linux/audio_mixer_manager_pulse_linux.cc",
"linux/audio_mixer_manager_pulse_linux.h",
"linux/pulseaudiosymboltable_linux.cc",
"linux/pulseaudiosymboltable_linux.h",
]
}
gn gen out/Debug --args='target_os="linux" target_cpu="arm" arm_arch="armv7-a"
arm_tune="cortex-a7"
arm_version=7
arm_optionally_use_neon=true
arm_use_neon=true
arm_fpu="neon-vfpv4"
is_clang=false
is_debug=true
is_nacl_glibc=false
libyuv_use_neon=true
rtc_build_with_neon=true
rtc_use_gtk=false
strip_debug_info=false
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_internal_audio_device=true
rtc_include_builtin_video_codecs=true
rtc_include_pulse_audio=false
use_glib=false
use_x11=false
rtc_use_x11=false
arm_float_abi="hard"
rtc_use_pipewire=false
use_custom_libcxx=false
use_custom_libcxx_for_host=false
rtc_use_h264=false
rtc_enable_protobuf=false
use_rtti=true
rtc_build_json=true
rtc_enable_libevent=true
is_component_build=false
use_libjpeg_turbo=false
use_system_libjpeg=true
target_sysroot="/opt/qt-5.9.4-arm/host/arm-buildroot-linux-gnueabihf/sysroot"'
gn gen out/Release --args='target_os="linux" target_cpu="arm" arm_arch="armv7-a"
arm_tune="cortex-a7"
arm_version=7
arm_optionally_use_neon=true
arm_use_neon=true
arm_fpu="neon-vfpv4"
is_clang=false
is_debug=false
is_nacl_glibc=false
libyuv_use_neon=true
rtc_build_with_neon=true
rtc_include_pulse_audio=false
rtc_use_gtk=false
strip_debug_info=true
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_internal_audio_device=true
rtc_include_builtin_video_codecs=true
use_glib=false
rtc_use_x11=false
arm_float_abi="hard"
rtc_use_pipewire=false
use_custom_libcxx=false
use_custom_libcxx_for_host=false
rtc_use_h264=false
rtc_enable_protobuf=false
use_rtti=true
rtc_build_json=true
rtc_enable_libevent=true
is_component_build=false
use_libjpeg_turbo=false
use_system_libjpeg=true
target_sysroot="/opt/qt-5.9.4-arm/host/arm-buildroot-linux-gnueabihf/sysroot"'
rtc_enable_avx2=false 是在下电脑比较老,不支持avx2,一般情况下不需要禁止
我这里使用clang 编译,如果需要gcc编译,is_clang=false 即可
我们不用内置的h264 编解码器
linux使能 rtc_include_pulse_audio,这个工作的比alsa好,特别对vmware
gn gen out/Debug --args='target_os="linux"
target_cpu="x64"
is_clang=false
is_debug=true
is_nacl_glibc=false
rtc_use_gtk=false
strip_debug_info=false
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_builtin_video_codecs=true
rtc_include_pulse_audio=true
use_glib=false
rtc_use_x11=false
rtc_use_pipewire=false
use_custom_libcxx=false
use_custom_libcxx_for_host=false
rtc_use_h264=true
ffmpeg_branding="Chrome"
proprietary_codecs=true
rtc_enable_protobuf=false
rtc_enable_libevent=true
use_rtti=true
rtc_build_json=true
is_component_build=false
rtc_enable_avx2=false
rtc_include_internal_audio_device=true'
gn gen out/Release --args='target_os="linux"
target_cpu="x64"
is_clang=false
is_debug=false
is_nacl_glibc=false
rtc_use_gtk=false
strip_debug_info=true
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_builtin_video_codecs=true
rtc_include_pulse_audio=true
use_glib=false
rtc_use_x11=false
rtc_use_pipewire=false
use_custom_libcxx=false
use_custom_libcxx_for_host=false
rtc_use_h264=true
ffmpeg_branding="Chrome"
proprietary_codecs=true
rtc_enable_protobuf=false
rtc_enable_libevent=true
use_rtti=true
rtc_build_json=true
is_component_build=false
rtc_enable_avx2=false
rtc_include_internal_audio_device=true'
Android中我们禁止: use_custom_libcxx=false use_custom_libcxx_for_host=false 原因是我们主程序要使用android NDK中的c++库,不然会出现C++库不一致的情况。
gn gen out/Debug --args='target_os="android" target_cpu="arm64"
is_debug=true
is_clang=true
arm_optionally_use_neon=true
arm_use_neon=true
strip_debug_info=false
android_full_debug=true
use_custom_libcxx=false
use_custom_libcxx_for_host=false
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_builtin_video_codecs=true
rtc_use_h264=false
proprietary_codecs=true
rtc_enable_protobuf=false
rtc_enable_libevent=false
use_rtti=true
rtc_build_json=true
is_component_build=false
rtc_enable_android_aaudio=true
rtc_include_internal_audio_device=true'
gn gen out/Release --args='target_os="android" target_cpu="arm64"
is_debug=false
is_clang=true
arm_optionally_use_neon=true
arm_use_neon=true
strip_debug_info=true
use_custom_libcxx=false
use_custom_libcxx_for_host=false
treat_warnings_as_errors=false
use_aura=false
use_dbus=false
use_gold=true
use_goma=false
use_lld=false
use_ozone=false
use_udev=false
rtc_build_examples=false
rtc_build_tools=false
rtc_include_tests=false
rtc_include_builtin_audio_codecs=true
rtc_include_builtin_video_codecs=true
rtc_use_h264=false
proprietary_codecs=true
rtc_enable_protobuf=false
rtc_enable_libevent=false
use_rtti=true
rtc_build_json=true
is_component_build=false
rtc_enable_android_aaudio=true
rtc_include_internal_audio_device=true'
具体参考:https://www.jianshu.com/p/9456f45e9f91
debug版本:
arm64: gn gen out/Debug --args='target_os="android" target_cpu="arm64" is_debug=true rtc_use_h264=true ffmpeg_branding="Chrome" proprietary_codecs=true'
armv7: gn gen out/Debug --args='target_os="android" target_cpu="arm" is_debug=true rtc_use_h264=true ffmpeg_branding="Chrome" proprietary_codecs=true arm_optionally_use_neon=true
arm_use_neon=true '
release:
arm64: gn gen out/Release--args='target_os="android" target_cpu="arm64" is_debug=false strip_debug_info=true
rtc_use_h264=true ffmpeg_branding="Chrome" proprietary_codecs=true'
armv7: gn gen out/Release --args='target_os="android" target_cpu="arm" is_debug=false strip_debug_info=true rtc_use_h264=true ffmpeg_branding="Chrome" proprietary_codecs=true arm_use_neon=true '
https://blog.jianchihu.net/webrtc-android-native-code-build-error.html
注意,还有一个ffmpeg openh264 license的问题要解决
得切到WebRTC源码/src目录下执行
build_aar.py 位于: \src\tools_webrtc\android
./tools_webrtc/android/build_aar.py --output "libwebrtc-m88.aar" --build-dir out --arch "armeabi-v7a" "arm64-v8a" --extra-gn-args 'is_debug=false strip_debug_info=true rtc_use_h264=true ffmpeg_branding="Chrome" proprietary_codecs=true treat_warnings_as_errors=false'