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