native webrtc支持切换音频采集设备和获取裸流
https://www.yuque.com/caokunchao/rtendq/oq8w3qgs3g59whru
前言
版本webrtc m96
1、修改webrtc m96代码,向外提供一个adm指针的接口出来
2、外部来获取指针进行设备的选择
3、外部获取音频裸流,麦克风或者扬声器的数据
修改webrtc代码
1、修改H:\webrtc\webrtc-checkout\webrtc\api\peer_connection_interface.h,PeerConnectionFactoryInterface类
添加接口
class AudioDeviceModule;
virtual rtc::scoped_refptr<AudioDeviceModule> GetAdmPtr() = 0;
2、修改H:\webrtc\webrtc-checkout\webrtc\pc\peer_connection_factory.h,
PeerConnectionFactory类,该类继承PeerConnectionFactoryInterface,实现GetAdmPtr()接口
#include "modules/audio_device/include/audio_device.h"
#include "media/base/media_engine.h"rtc::scoped_refptr<AudioDeviceModule> GetAdmPtr() override {return context_->channel_manager()->media_engine()->voice().GetAdm();}
3、修改代理,H:\webrtc\webrtc-checkout\webrtc\pc\peer_connection_factory_proxy.h
#include "modules/audio_device/include/audio_device.h"在 BEGIN_PROXY_MAP(PeerConnectionFactory) 下面添加代理方法
***
PROXY_METHOD0(rtc::scoped_refptr<AudioDeviceModule>,GetAdmPtr)
***
END_PROXY_MAP(PeerConnectionFactory)
4、修改H:\webrtc\webrtc-checkout\webrtc\media\base\media_engine.h,VoiceEngineInterface类
添加接口
virtual rtc::scoped_refptr <webrtc::AudioDeviceModule> GetAdm() = 0;
5、修改H:\webrtc\webrtc-checkout\webrtc\media\engine\webrtc_voice_engine.h,WebRtcVoiceEngine类
实现接口
rtc::scoped_refptr<webrtc::AudioDeviceModule> GetAdm() override { return adm_; }
外部切换设备
看我的krtcsdk源码
void MicImpl::Start() {RTC_LOG(LS_INFO) << "MicImpl Start call";KRTCGlobal::Instance()->worker_thread()->PostTask(webrtc::ToQueuedTask([=]() {RTC_LOG(LS_INFO) << "MicImpl Start PostTask";KRTCError err = KRTCError::kNoErr;do {// 1. 如果麦克风已经启动采集,直接停止if (has_start_) {RTC_LOG(LS_WARNING) << "mic already start, mic_id: " << mic_id_;break;}// 2. 直接从webrtc获取adm模块指针rtc::scoped_refptr<webrtc::AudioDeviceModule> audio_device =KRTCGlobal::Instance()->push_peer_connection_factory()->GetAdmPtr();// 3. 检查系统是否存在麦克风设备int total = audio_device->RecordingDevices();if (total <= 0) {RTC_LOG(LS_WARNING) << "no audio device";err = KRTCError::kNoAudioDeviceErr;break;}// 4. 检查关联的mic_id是否能够在系统设备中找到int device_index = -1;for (int i = 0; i < total; ++i) {char name[128];char guid[128];audio_device->RecordingDeviceName(i, name, guid);if (0 == strcmp(guid, mic_id_.c_str())) {device_index = i;break;}}if (device_index <= -1) {RTC_LOG(LS_WARNING) << "audio device not found, mic_id: " << mic_id_;err = KRTCError::kAudioNotFoundErr;break;}// 5. 设置启用的麦克风设备if (audio_device->SetRecordingDevice(device_index)) {RTC_LOG(LS_WARNING) << "SetRecordingDevice failed, mic_id: " << mic_id_;err = KRTCError::kAudioSetRecordingDeviceErr;break;}// 6. 设置为立体声采集audio_device->SetStereoRecording(true);// 7. 初始化麦克风if (audio_device->InitRecording() || !audio_device->RecordingIsInitialized()) {RTC_LOG(LS_WARNING) << "InitRecording failed, mic_id: " << mic_id_;err = KRTCError::kAudioInitRecordingErr;break;}bool ok = false;audio_device->PlayoutIsAvailable(&ok);if (!ok) {RTC_LOG(LS_WARNING) << "PlayoutIsAvailable failed, mic_id: " << mic_id_;err = KRTCError::kAudioInitRecordingErr;break;}int32_t ret = audio_device->InitPlayout();if (audio_device->StartPlayout()) {RTC_LOG(LS_WARNING) << "StartPlayout failed!!!";err = KRTCError::kAudioStartRecordingErr;break;}// 8. 启动麦克风采集if (audio_device->StartRecording()) {RTC_LOG(LS_WARNING) << "StartRecording failed, mic_id: " << mic_id_;err = KRTCError::kAudioStartRecordingErr;break;}has_start_ = true;} while (0);if (err == KRTCError::kNoErr) {if (KRTCGlobal::Instance()->engine_observer()) {KRTCGlobal::Instance()->engine_observer()->OnAudioSourceSuccess();}}else {if (KRTCGlobal::Instance()->engine_observer()) {KRTCGlobal::Instance()->engine_observer()->OnAudioSourceFailed(err);}}}));
}
这里音频audio_device->StartRecording之前,还必须加上audio_device->StartPlayout()否则会报错
(audio_device_core_win.cc:2351): Playout must be started before recording when using the built-in AEC
外部获取音频裸流
1、添加ADMDataObserver,继承自webrtc::AudioDeviceDataObserver
class ADMDataObserver : public webrtc::AudioDeviceDataObserver {
private:virtual void OnCaptureData(const void* audio_samples,const size_t num_samples,const size_t bytes_per_sample,const size_t num_channels,const uint32_t samples_per_sec) override {}virtual void OnRenderData(const void* audio_samples,const size_t num_samples,const size_t bytes_per_sample,const size_t num_channels,const uint32_t samples_per_sec) override {}};
OnCaptureData 音频采集麦克风数据,OnRenderData需要播放的扬声器数据。。
2、创建webrtc::AudioDeviceModule
rtc::scoped_refptr<webrtc::AudioDeviceModule> audio_device_;worker_thread_->Invoke<void>(RTC_FROM_HERE, [=]() {audio_device_ = webrtc::AudioDeviceModule::Create(webrtc::AudioDeviceModule::kPlatformDefaultAudio,task_queue_factory_.get());audio_device_ = webrtc::CreateAudioDeviceWithDataObserver(audio_device_, std::make_unique<ADMDataObserver>());audio_device_->Init();});
3、将audio_device_传入到webrtc::CreatePeerConnectionFactory即可。。
webrtc::CreatePeerConnectionFactory(network_thread_.get(), /* network_thread */worker_thread_.get(), /* worker_thread */signaling_thread_.get(), /* signaling_thread */audio_device_, /* default_adm */******
参考资料
https://blog.csdn.net/qq_22658119/article/details/117664188
https://blog.csdn.net/weixin_39343678/article/details/99948451
相关文章:
native webrtc支持切换音频采集设备和获取裸流
https://www.yuque.com/caokunchao/rtendq/oq8w3qgs3g59whru 前言 版本webrtc m96 1、修改webrtc m96代码,向外提供一个adm指针的接口出来 2、外部来获取指针进行设备的选择 3、外部获取音频裸流,麦克风或者扬声器的数据 修改webrtc代码 1、修改H:\w…...
HR怎么看待PMP证书呢?
在当今竞争激烈的职场环境中,拥有专业的证书已经成为了许多人提升职业竞争力的必要途径。PMP证书作为项目管理领域的国际认证,备受HR和企业的青睐。那么,HR在招聘和评估员工时,究竟是如何看待PMP证书的呢? 首先&#x…...

API接口:如何通过使用手机归属地查询
随着手机普及率的不断增加,手机号码的信息查询也成为了一个非常实用的功能。本文将介绍如何通过使用手机归属地查询API接口实现查询手机号码所在地的功能。 首先,我们需要一个可以查询手机号码所在地的API接口。目前市面上有很多免费或付费的API接口可供…...

小创业公司死亡剧本
感觉蛮真实的;很多小创业公司没有阿里华为的命,却得了阿里华为的病。小的创业公司要想活无非以下几点: 1 现金流,现金流,现金流; 2 产品,找痛点,不要搞伪需求; 3 根据公司…...

国产化的接口测试、接口自动化测试工具Apipost的介绍及使用
Apipost介绍: Apipost是 API 文档、API 调试、API Mock、API 自动化测试一体化的研发协作赋能平台,它的定位 Postman Swagger Mock JMeter。 Apipost 是接口管理、开发、测试全流程集成工具,能支撑整个研发技术团队同平台工作࿰…...

【MySQL】不允许你不知道如何插入数据
🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正࿰…...

Vue 渲染流程详解
在 Vue 里渲染一块内容,会有以下步骤及流程: 第一步,解析语法,生成AST 第二步,根据AST结果,完成data数据初始化 第三步,根据AST结果和DATA数据绑定情况,生成虚拟DOM 第四步&…...

10分钟内入门 ArcGIS Pro
本文来源:GIS荟 大家好,这篇文章大概会花费你10分钟的时间,带你入门 ArcGIS Pro 的使用,不过前提是你有 ArcMap 使用经验。 我将从工程文件组织方式、软件界面、常用功能、编辑器、制图这5个维度给大家介绍。 演示使用的 ArcGI…...

【ribbon】Ribbon的使用与原理
负载均衡介绍 负载均衡(Load Balance),其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同…...
axios封装到reques.js文件中
封装到js中,避免每次都import 然后写一大堆 import axios from axios /* 可复用的发 ajax 请求的函数: axios */ let baseURLhttp://localhost:3000/ export default function promiseAjax(url,methodget,datanull,params) {return new Promise((resolve, reject) …...

学好Elasticsearch系列-核心概念
本文已收录至Github,推荐阅读 👉 Java随想录 文章目录 节点角色master:候选节点data:数据节点Ingest:预处理节点ml:机器学习节点remote_ cluster_ client:候选客户端节点transform:…...

扩展点都不知道不要说你用了Spring Boot
文章目录 前言1.扩展点1.1. 应用程序生命周期扩展点1.1.1 SpringApplicationRunListener1.1.2 ApplicationEnvironmentPreparedEvent1.1.3 ApplicationPreparedEvent1.1.4 ApplicationStartedEvent1.1.5 ApplicationReadyEvent1.1.6 ApplicationFailedEvent 1.2. 容器扩展点1.2…...

LangChain大型语言模型(LLM)应用开发(五):评估
LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…...

Angular:动态依赖注入和静态依赖注入
问题描述: 自己写的服务依赖注入到组件时候是直接在构造器内初始化的。 直到看见代码中某大哥写的 private injector: Injector 动态依赖注入和静态依赖注入 在 Angular 中,使用构造函数注入的方式将服务注入到组件中是一种静态依赖注入的方式。这种方…...
Java前后端交互long类型溢出的解决方案
问题描述: 前端根据id发起请求查找对象的时候一直返回找不到对象,然后查看了请求报文,发现前端传给后台的数据id不对,原本的id是1435421253099634623,可前端传过来的id是 1435421253099634700,后三位变成了…...
Lua学习-1 基础数据类型
文章目录 基础数据类型分类nilbooleannumberstringfunctionuserDatathreadtable 如何判断类型(type)不同类型数据常见操作nilnumberstring(字符串)function普通函数匿名函数不定参数函数 table 基础数据类型分类 nil 表示无效值 boolean 只有 true 和…...
普通的计算机专业大学生如何学习才能找到好offer
2023年已经将近8月份了,回想到开始努力提高自己的时候还是在今年1月1号。开学就要大二了。 一、目标达成情况总结: 一月份,无意间在网上刷到鹏哥的C语言课程,在鸡汤实力课程已拿到大厂offer的同学喜报 ,让我萌发了学技…...

iOS私钥证书和证书profile文件的生成攻略
在使用uniapp打包ios app的时候,要求我们提供一个私钥证书和一个证书profile文件,私钥证书可以使用mac电脑的钥匙串访问程序来生成,也可以使用香蕉云编来生成。证书profile文件可以直接在苹果开发者中心生成。 有部分刚接触ios开发的同学们&…...

前端 | ( 十二)CSS3简介及基本语法(中)| 变换、过渡与动画 | 尚硅谷前端html+css零基础教程2023最新
学习来源:尚硅谷前端htmlcss零基础教程,2023最新前端开发html5css3视频 系列笔记: 【HTML4】(一)前端简介【HTML4】(二)各种各样的常用标签【HTML4】(三)表单及HTML4收尾…...

【BOOST程序库】时间日期库
基本概念这里不再浪费时间介绍了,这里给出时间日期库的常见使用方法: #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <boost/version.hpp> #include <boost/config.hpp>//时间库࿱…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...