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>//时间库࿱…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
