網站首頁 編程語言 正文
- webrtc版本5841-m110
時間又過去了一年,再分析一下底層有什么改進,依然從video_loopback開始。
我想先不去看信令及協商的過程,只看媒體層有什么變化。所以從這個demo開始
video_loopback
項目路徑 src/video/video_loopback
在video_loopback_main.cc 中就一個函數main,進入webrtc::RunLoopbackTest
video_loopback_lib
這個文件里面主要是測試功能的一些配置,列出我測試修改的幾個
//修改編碼用h264
// Flags common with screenshare loopback, with equal default values.
ABSL_FLAG(std::string, codec, "H264" /*"VP8"*/, "Video codec to use.");
//修改起音頻測試
ABSL_FLAG(bool, audio, true, "Add audio stream");
//修改啟用真實音頻采集
ABSL_FLAG(bool,
use_real_adm,
true,/* false,*/
"Use real ADM instead of fake (no effect if audio is false)");
通過修改參數配置 我們可以跟蹤調試,接下來跟蹤webrtc::test::RunTest(webrtc::Loopback);
- Loopback() 這個函數就是初始化參數,我們簡單看一下初始化的值是不是我們想要的,
- 進入 fixture->RunWithRenderers(params);
video_quality_test
主要的流程在video_quality_test.cc 里面
跟蹤試試,運行就崩潰,和之前版本一樣的問題,解決方法參考之前的文章
https://newrtc.blog.csdn.net/article/details/118379956
運行起來了,不過沒有聲音,哪里出了問題么,這demo越來越不負責了。我們先找找音頻的問題再分析代碼。
代碼在video_quality_tesy.cc
先解決沒有聲音的問題,查看代碼是使用了新的音頻采集模塊,不知道為什么沒有聲音,等有時間先去看看為什么要替換原來的coreaudio,莫非真的要刷kpi么。
上代碼
rtc::scoped_refptr<AudioDeviceModule> VideoQualityTest::CreateAudioDevice() {
//增加這句,初始化的是原來的coreaudio采集方式
return AudioDeviceModule::Create(AudioDeviceModule::kPlatformDefaultAudio,
task_queue_factory_.get());
//這是新版的測試代碼,大概跟蹤了一下
#ifdef WEBRTC_WIN
RTC_LOG(LS_INFO) << "Using latest version of ADM on Windows";
// We must initialize the COM library on a thread before we calling any of
// the library functions. All COM functions in the ADM will return
// CO_E_NOTINITIALIZED otherwise. The legacy ADM for Windows used internal
// COM initialization but the new ADM requires COM to be initialized
// externally.
com_initializer_ =
std::make_unique<ScopedCOMInitializer>(ScopedCOMInitializer::kMTA);
RTC_CHECK(com_initializer_->Succeeded());
RTC_CHECK(webrtc_win::core_audio_utility::IsSupported());
RTC_CHECK(webrtc_win::core_audio_utility::IsMMCSSSupported());
return CreateWindowsCoreAudioAudioDeviceModule(task_queue_factory_.get());
#else
//這是原來的方式,可以正常使用
// Use legacy factory method on all platforms except Windows.
return AudioDeviceModule::Create(AudioDeviceModule::kPlatformDefaultAudio,
task_queue_factory_.get());
#endif
}
到此,demo的音視頻都能夠測試通過了,接下來開始代碼流程
初始化過程
我們只看幾個重要的函數
void VideoQualityTest::RunWithRenderers(const Params& params) {
//發送和接收的transport,繼承自Transport,實現SendRtp,SendRtcp接口
std::unique_ptr<test::LayerFilteringTransport> send_transport;
std::unique_ptr<test::DirectTransport> recv_transport;
//渲染采集到的數據和解碼后的數據yuv420p
std::unique_ptr<test::VideoRenderer> local_preview;
std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
//初始化音頻模塊,這里創建了send call 和recv call兩個call,其實可以創建一個
InitializeAudioDevice(&send_call_config, &recv_call_config,
params_.audio.use_real_adm);
//創建發送call 接收call
CreateCalls(send_call_config, recv_call_config);
//創建transport
send_transport = CreateSendTransport();
recv_transport = CreateReceiveTransport();
// TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
// least share as much code as possible. That way this test would also match
// the full stack tests better.
//設置transport的receiver,模擬網絡接收的rtp,rtcp傳遞給call
send_transport->SetReceiver(receiver_call_->Receiver());
recv_transport->SetReceiver(sender_call_->Receiver());
//設置視頻相關,設置一些配置。后續仔細分析
SetupVideo(send_transport.get(), recv_transport.get());
//創建視頻流
CreateVideoStreams();
//創建視頻采集
CreateCapturers();
//將采集關聯到視頻流
ConnectVideoSourcesToStreams();
//音頻設置及創建音頻流
SetupAudio(send_transport.get());
//開始測試
Start();
}
重要函數分析
先看音頻的接收發送流程吧,視頻的類似
1、音頻設備初始化,在call 創建之前,
調用入口
InitializeAudioDevice(&send_call_config, &recv_call_config,
params_.audio.use_real_adm);
void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config,
Call::Config* recv_call_config,
bool use_real_adm) {
rtc::scoped_refptr<AudioDeviceModule> audio_device;
if (use_real_adm) {
// Run test with real ADM (using default audio devices) if user has
// explicitly set the --audio and --use_real_adm command-line flags.
//我們測試參數設置用實際的音頻設備,在此初始化
audio_device = CreateAudioDevice();
} else {
// By default, create a test ADM which fakes audio.
audio_device = TestAudioDeviceModule::Create(
task_queue_factory_.get(),
TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
}
RTC_CHECK(audio_device);
AudioState::Config audio_state_config;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = AudioProcessingBuilder().Create();
audio_state_config.audio_device_module = audio_device;
//把device設置為創建call的參數,多個call可以共用一個device
send_call_config->audio_state = AudioState::Create(audio_state_config);
recv_call_config->audio_state = AudioState::Create(audio_state_config);
if (use_real_adm) {
// The real ADM requires extra initialization: setting default devices,
// setting up number of channels etc. Helper class also calls
// AudioDeviceModule::Init().
//這里面是初始化設置,選取音頻采集,播放設備
webrtc::adm_helpers::Init(audio_device.get());
} else {
audio_device->Init();
}
// Always initialize the ADM before injecting a valid audio transport.
RTC_CHECK(audio_device->RegisterAudioCallback(
send_call_config->audio_state->audio_transport()) == 0);
}
在CreateAudioDevice()中,調用AudioDeviceModule創建device
rtc::scoped_refptr<AudioDeviceModule> VideoQualityTest::CreateAudioDevice() {
return AudioDeviceModule::Create(AudioDeviceModule::kPlatformDefaultAudio,
task_queue_factory_.get());
}
調用webrtc::adm_helpers::Init(audio_device.get()); 設置音頻設備
void Init(AudioDeviceModule* adm) {
RTC_DCHECK(adm);
RTC_CHECK_EQ(0, adm->Init()) << "Failed to initialize the ADM.";
// Playout device.
{
//設置播放設備ID,adm可以遍歷有哪些設備的
if (adm->SetPlayoutDevice(AUDIO_DEVICE_ID) != 0) {
RTC_LOG(LS_ERROR) << "Unable to set playout device.";
return;
}
//初始化音頻播放設備
if (adm->InitSpeaker() != 0) {
RTC_LOG(LS_ERROR) << "Unable to access speaker.";
}
// Set number of channels
bool available = false;
//雙聲道支持
if (adm->StereoPlayoutIsAvailable(&available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to query stereo playout.";
}
if (adm->SetStereoPlayout(available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to set stereo playout mode.";
}
}
// Recording device.
{
//設置麥克風id,同樣adm可以設置ID
if (adm->SetRecordingDevice(AUDIO_DEVICE_ID) != 0) {
RTC_LOG(LS_ERROR) << "Unable to set recording device.";
return;
}
//初始化
if (adm->InitMicrophone() != 0) {
RTC_LOG(LS_ERROR) << "Unable to access microphone.";
}
// Set number of channels
bool available = false;
if (adm->StereoRecordingIsAvailable(&available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to query stereo recording.";
}
if (adm->SetStereoRecording(available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to set stereo recording mode.";
}
}
2、創建call
CreateCalls
void CallTest::CreateSenderCall(const Call::Config& config) {
auto sender_config = config;
sender_config.task_queue_factory = task_queue_factory_.get();
sender_config.network_state_predictor_factory =
network_state_predictor_factory_.get();
sender_config.network_controller_factory = network_controller_factory_.get();
sender_config.trials = &field_trials_;
sender_call_.reset(Call::Create(sender_config));
}
void CallTest::CreateReceiverCall(const Call::Config& config) {
auto receiver_config = config;
receiver_config.task_queue_factory = task_queue_factory_.get();
receiver_config.trials = &field_trials_;
receiver_call_.reset(Call::Create(receiver_config));
}
3、音頻編碼器設置
void VideoQualityTest::SetupAudio(Transport* transport) {
AudioSendStream::Config audio_send_config(transport);
audio_send_config.rtp.ssrc = kAudioSendSsrc;
// Add extension to enable audio send side BWE, and allow audio bit rate
// adaptation.
audio_send_config.rtp.extensions.clear();
//采用opus48k 雙聲道
audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec(
kAudioSendPayloadType,
{"OPUS",
48000,
2,
{{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}});
if (params_.call.send_side_bwe) {
audio_send_config.rtp.extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri,
kTransportSequenceNumberExtensionId));
audio_send_config.min_bitrate_bps = kOpusMinBitrateBps;
audio_send_config.max_bitrate_bps = kOpusBitrateFbBps;
audio_send_config.send_codec_spec->transport_cc_enabled = true;
// Only allow ANA when send-side BWE is enabled.
audio_send_config.audio_network_adaptor_config = params_.audio.ana_config;
}
audio_send_config.encoder_factory = audio_encoder_factory_;
SetAudioConfig(audio_send_config);
std::string sync_group;
if (params_.video[0].enabled && params_.audio.sync_video)
sync_group = kSyncGroup;
CreateMatchingAudioConfigs(transport, sync_group);
CreateAudioStreams();
}
4 創建音頻stream
void CallTest::CreateAudioStreams() {
RTC_DCHECK(audio_send_stream_ == nullptr);
RTC_DCHECK(audio_receive_streams_.empty());
//通過call創建音頻發送stream
audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_);
for (size_t i = 0; i < audio_receive_configs_.size(); ++i) {
audio_receive_streams_.push_back(
//通過call創建音頻接收stream
receiver_call_->CreateAudioReceiveStream(audio_receive_configs_[i]));
}
}
5 start音視頻
void CallTest::Start() {
StartVideoStreams();
if (audio_send_stream_) {
//開始音頻發送
audio_send_stream_->Start();
}
for (AudioReceiveStreamInterface* audio_recv_stream : audio_receive_streams_)
//開始音頻接收
audio_recv_stream->Start();
}
原文鏈接:https://newrtc.blog.csdn.net/article/details/130601730
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-09-08 pytorch中Tensor.to(device)和model.to(device)的區別及說明_p
- 2022-05-23 詳解Rust中的workspace_相關技巧
- 2023-12-14 Excel如何把兩列互換
- 2022-12-04 pyecharts如何實現顯示數據為百分比的柱狀圖_python
- 2022-09-03 docker鏡像管理命令詳解_docker
- 2022-11-23 python人工智能使用RepVgg實現圖像分類示例詳解_python
- 2022-10-30 移動web開發技能之touch事件詳解_IOS
- 2022-03-26 C++的缺省參數你了解嘛_C 語言
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支