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

相关推荐
MediaTea6 小时前
Pr 视频过渡:沉浸式视频 - VR 色度泄漏
音视频·vr
LNTON羚通6 小时前
算法定制LiteAIServer摄像机实时接入分析平台烟火检测算法的主要功能
音视频·视频监控
EasyCVR12 小时前
EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?
人工智能·算法·ffmpeg·音视频·webrtc·监控视频接入
冷凝女子14 小时前
【QT】海康视频及openCv抓拍正脸接口
qt·opencv·音视频·海康
安步当歌15 小时前
【WebRTC】视频编码链路中各个类的简单分析——VideoStreamEncoder
音视频·webrtc·视频编解码·video-codec
顾北川_野15 小时前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
顶呱呱程序15 小时前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
EasyCVR16 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
runing_an_min16 小时前
ffmpeg 视频滤镜:屏蔽边框杂色- fillborders
ffmpeg·音视频·fillborders
我喜欢就喜欢1 天前
基于qt vs下的视频播放
开发语言·qt·音视频