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>//时间库࿱…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...
【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...
【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验
2024年初,人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目(一款融合大型语言模型能力的云端AI编程IDE)时,技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力,TRAE在WayToAGI等…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...
