webrtc 测试video_loopback

news2024/11/28 11:40:50
  • 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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/528648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

openssh原理

目录 一、openssh是什么 二、安装openssh 三、ssh协议 四、客户端登录过程 &#xff08;1&#xff09;远程登录——采用“密码身份验证方式” &#xff08;1&#xff09;远程登录——采用“密钥身份验证&#xff08;免密登录&#xff09;方式” 五、openssh配置文件 &a…

从零开始写一个Vue3+Element Plus的后台管理系统

写在开始之前 接触Vue3也有一年的时间了&#xff0c;除了刚开始用Vue3做了一个小小的项目&#xff0c;其后一直没有机会在项目中真正使用Vue3&#xff0c;反而一直维护Vue2的老项目。作为一个有追求&#xff08;wuliao&#xff09;的前端&#xff0c;那就自己开一个git仓库练手…

RAM内存,ROM,CACHE缓存

RAM&#xff08;Random Access Memory&#xff09;&#xff1a;&#xff08;redis是在这一层做的  随机存储器&#xff0c;俗称内存&#xff0c;我们常说的电脑内存8g&#xff0c;指的就是这个(也不完全正确)。RAM要求每时每刻都不断地供电&#xff0c;否则数据会丢失。它由半…

抖音无需代码连接飞书自建的方法

抖音用户使用场景&#xff1a; 公司短视频运营人员每天需要监管企业抖音视频的评论并及时处理&#xff0c;日常工作流程为&#xff1a;每当抖音上发布的视频有新增评论时&#xff0c;运营人员需要将评论内容发送到企业飞书群中通知相关人员及时跟进。整个流程看似比较简单&…

分页存储管理方式

目录 一、分页存储管理的基本方法 1.1页面与物理块 &#xff08;1&#xff09;页面 &#xff08;2&#xff09;页面大小 1.2地址结构 1.3页表 二、地址变换机构 2.1基本的地址变换机构 2.2具有快表的地址变换机构 三、访问内存的有效时间 案例习题: 1.二进制 2.基本…

ElasticSearch数据备份还原

ElasticSearch数据备份还原 使用Elasticsearch的API导出数据 Elasticsearch并没有内置的数据导出工具&#xff0c;但是可以使用多种方法来导出数据&#xff0c;包括使用Elasticsearch的API或者使用外部工具。这是一个使用Elasticsearch的API进行数据导出的基本步骤&#xff1…

OpenCV中的图像处理3.9(六)轮廓线特征与属性

目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线&#xff1a;入门目标什么是轮廓线&#xff1f;如何绘制轮廓线&#xff1f;轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮…

Springboot +Flowable,流程表单应用之外置表单(JSON形式)(二)

一.简介 整体上来说&#xff0c;我们可以将Flowable 的表单分为三种不同的类型&#xff1a; 动态表单 这种表单定义方式我们可以配置表单中每一个字段的可读性、可写性、是否必填等信息&#xff0c;不过不能定义完整的表单页面。外置表单 外置表单我们只需要定义一下表单的 k…

前端实现可拖拽课程表【纯HTML、CSS、JS】

前言 hello&#xff0c;今天实现点小动画&#xff0c;帮助学习理解Web api的拖拽效果&#xff0c;这里实现的是可拖拽的课程表&#xff01;# 效果图 附&#xff1a;作者没钱去除水印&#xff0c;就这样看一下简单的看一下效果吧&#xff01; 实现前言知识 这里我使用事件委…

轻量化Verilog开发环境搭建

轻量化Verilog学习环境搭建 本文记录基于vscode、iverilog搭建轻量化Verilog学习环境的方法。 ref: VSCode Verilog工具链、linux下搭建轻量易用的verilog仿真环境 环境搭建 &#xff08;1&#xff09;安装iverilog&#xff0c;这是一个轻量化的开源verilog编译器&#xff0…

4月更新 | Visual Studio Code Python

我们很高兴地宣布2023年4月版 Visual Studio Code 的 Python 和 Jupyter 扩展现已推出&#xff01; 此版本包括以下改进&#xff1a; Data Wrangler 可供 Visual Studio Code Insiders 使用移动符号重构Create Environment 按钮嵌入依赖文件扩展作者的环境 APIPython 环境的内…

Foxit PDF Reader及Editor任意代码执行漏洞复现(CVE-2023-27363)

0x01 产品简介 Foxit PDF Reader是一套用来阅读PDF格式文件的软件&#xff0c;由福建福昕软件所研发&#xff0c;主要运行在Windows操作系统上。 0x02 漏洞概述 Foxit PDF Reader及Editor中存在任意代码执行漏洞&#xff0c;由于Foxit PDF Reader/Editor未验证exportXFAData方…

【C++】3. 类和对象 - 类的六大默认成员函数

专栏导读 &#x1f341;作者简介&#xff1a;余悸&#xff0c;在读本科生一枚&#xff0c;致力于 C方向学习。 &#x1f341;收录于 C专栏&#xff0c;本专栏主要内容为 C初阶、 C 进阶、STL 详解等&#xff0c;持续更新中&#xff01; &#x1f341;相关专栏推荐&#xff1a; …

定薪17K*15,阿里测试岗上岸经验分享.....

先简单介绍一下我自己吧&#xff0c;等会大家以为我是什么学历狂人&#xff0c;技术大牛&#xff0c;我毕业于广东一个普通本科院校&#xff0c;绝对不是什么双一流大学&#xff0c;大家不要有距离感&#xff0c;这也是我为什么来分享的原因&#xff0c;因为我觉得我这段经验还…

Agisoft Metashape 空三导入Photomod

Agisoft Metashape 空三导入Photomod 文章目录 Agisoft Metashape 空三导入Photomod前言一、Metashape空三成果导出1.1导出PAT-B空三格式1.2. 导出相机文件二、Photomod空三成果导入2.1导入PAT-B空三格式2.2导入相机文件前言 本文讲解将Agisoft Metashape的空三成果导入Photom…

uniapp - 微信小程序接入腾讯视频播放器功能插件,uniapp开发微信小程序端调用引入并使用腾讯视频播放组件完整全流程(详细示例源码,一键复制开箱即用)

效果图 在uniapp 微信小程序项目中,集成腾讯视频功能插件,实现播放腾讯视频效果,附带详细示例源码及注释, 你可以跟着步骤一步步来,保证几分钟就能快速在uniapp小程序项目中植入腾讯视频功能! 一、开通插件 首先使用腾讯视频的话

【数据结构】链表的增删改查| 组件化封装

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;专栏汇总&#xff1a;全部文章专栏汇总 &#x1f525; 给大…

BSN-DDC基础网络详解(十一):官方门户OpenAPI说明及开发资料汇总

01 官方门户OpenAPI说明 官方门户OpenAPI是BSN联盟面向算力中心方和平台方开放的一套官方门户业务管理服务接口。“业务开通”和“资金账户充值/提现”操作&#xff0c;需通过官方门户手工执行&#xff0c;官方门户内的其它功能&#xff0c;都建议算力中心方和平台方按照官方…

Mongo集合操作

2、创建切换数据库 2.1 默认数据库 mongo数据库和其他类型的数据库一样&#xff0c;可以创建数据库&#xff0c;且可以创建多个数据库。 mongo数据库默认会有四个数据库&#xff0c;分别是 admin&#xff1a;主要存储MongoDB的用户、角色等信息 config&#xff1a;主要存储…

数据泄露、数据爬取......金融机构要如何保护催收场景下的数据安全?

金融企业的贷后催收是指向借款人发送催收通知和采取其他措施&#xff0c;以确保借款人按时还款并追回逾期贷款的过程。这通常包括电话催收、信函催收、上门访问等方式。贷后催收通常由金融机构内部的专业团队或第三方专业催收公司承担。 由于催收业务会涉及到很多个人信息&…