由於新版本的webrtc工程太過於龐大,有一千讀個工程,對於理解源碼很不方便,所以以後都採用老版本的webrtc,以方便理解,這個版本有一百多個工程,相對於最新的工程要小很多
webrtc源碼 下載 鏈接:
https://pan.baidu.com/s/14ECsWNgQ4ZxrxG0tO22E0w
提取碼:ups7
這個版本中webrtc 音頻核心爲
webrtc::VoiceEngine* ptrVoEngine_; //核心引擎類,下面的四個類的都是基於引擎創建的
webrtc::VoEBase* ptrVoEBase_;
webrtc::VoEVolumeControl* ptrVoEVolumeControl_;//聲音控制類,設置麥克風與聲卡的聲音等
webrtc::VoEFile* ptrVoEFile_;//音頻文件管理,播放文件,保存文件等
webrtc::VoEHardware* ptrVoEHardware_;//設備相關,可以獲取設備,打開設備,播放等
1.核心類的創建
bool videoCap::InitVoiceEnginee()
{
ptrVoEngine_ = webrtc::VoiceEngine::Create(); //通過全局方法創建引擎
//通過引擎創建其他類
ptrVoEBase_ = webrtc::VoEBase::GetInterface(ptrVoEngine_);
ptrVoEHardware_ = webrtc::VoEHardware::GetInterface(ptrVoEngine_);
ptrVoEFile_ = webrtc::VoEFile::GetInterface(ptrVoEngine_);
ptrVoEVolumeControl_ = webrtc::VoEVolumeControl::GetInterface(ptrVoEngine_);
int errCode = ptrVoEBase_->Init();
if (errCode != 0)
{
return false;
}
//註冊錯誤回調
errCode = ptrVoEBase_->RegisterVoiceEngineObserver(voeObserver_);
if (errCode != 0)
{
return false;
}
return true;
}
2 獲取音頻設備列表(麥克風與音響設備)
void videoCap::setDevice()
{
int recoder_device_num{ 0 };
int play_device_num{ 0 };
//獲取所有錄製設備信息(麥克風等)
int errCode = ptrVoEHardware_->GetNumOfRecordingDevices(recoder_device_num);
if (errCode != 0)
{
return;
}
//獲取所以播放設備信息(耳麥音響等)
errCode = ptrVoEHardware_->GetNumOfPlayoutDevices(play_device_num);
if (errCode != 0)
{
return;
}
//獲取錄製設備詳細信息
for (int i = 0; i < recoder_device_num; ++i)
{
char devName[256]{ 0 };
char guidName[256]{ 0 };
ptrVoEHardware_->GetRecordingDeviceName(i, devName, guidName);
ui.m_cbRecoderDev->addItem(devName, i);
}
//獲取播放設備詳細信息
for (int i = 0; i < recoder_device_num; ++i)
{
char devName[256]{ 0 };
char guidName[256]{ 0 };
ptrVoEHardware_->GetPlayoutDeviceName(i, devName, guidName);
ui.m_cbPlayerDev->addItem(devName,i);
}
//創建channel,以後所有的操作都是基於這個audio_channel_
audio_channel_ = ptrVoEBase_->CreateChannel();
if (audio_channel_ < 0)
{
qDebug() << "ERROR in VoEBase::CreateChannel";
}
errCode = ptrVoEBase_->StartPlayout(audio_channel_);
if (errCode != 0)
{
qDebug() << "ERROR in VoEBase::StartPlayout";
}
}
3 開始/結束錄製
void videoCap::OnOpenPbClicked()
{
if (ui.m_pbOpen->text() == QString::fromLocal8Bit("打開"))
{
//開始錄製
ptrVoEFile_->StartRecordingMicrophone(VIDEO_FILE);
ui.m_pbOpen->setText(QString::fromLocal8Bit("關閉"));
}
else
{
//結束錄製
ptrVoEFile_->StopRecordingMicrophone();
ui.m_pbOpen->setText(QString::fromLocal8Bit("打開"));
}
}
4播放/停止
void videoCap::OnPlayPbClicked()
{
if (ui.m_pbPlayer->text() == QString::fromLocal8Bit("播放"))
{
//播放
ptrVoEFile_->StartPlayingFileLocally(audio_channel_, VIDEO_FILE);
ui.m_pbPlayer->setText(QString::fromLocal8Bit("停止"));
}
else
{
//停止
ptrVoEFile_->StopPlayingFileLocally(audio_channel_);
ui.m_pbPlayer->setText(QString::fromLocal8Bit("播放"));
}
}
5音量控制
//獲取麥克風當前音量
int videoCap::GetMicroVolume()
{
unsigned int n{ 0 };
ptrVoEVolumeControl_->GetMicVolume(n);
ui.m_slider_Speaker->setValue(n);
return n;
}
//設置麥克風音量
void videoCap::SetMicroVolume(int n)
{
int errCode = ptrVoEVolumeControl_->SetMicVolume(n);
if (errCode != 0)
{
qDebug() << "set volume failed";
}
}
//獲取音響音量
int videoCap::GetSpeakVolume()
{
unsigned int n{ 0 };
ptrVoEVolumeControl_->GetSpeakerVolume(n);
ui.m_slider_Micro->setValue(n);
return n;
}
//設置音響音量
void videoCap::SetSpeakVolume(int n)
{
int errCode = ptrVoEVolumeControl_->SetSpeakerVolume(n);
if (errCode != 0)
{
qDebug() << "set volume failed";
}
}
6 資源銷燬
void videoCap::UnInitVoiceEnginee()
{
if (ptrVoEFile_->IsPlayingFileLocally(audio_channel_))
{
ptrVoEFile_->StopPlayingFileLocally(audio_channel_);
}
ptrVoEFile_->StopRecordingMicrophone();
ptrVoEBase_->StopPlayout(audio_channel_);
ptrVoEFile_->Release();
ptrVoEHardware_->Release();
ptrVoEVolumeControl_->Release();
ptrVoEBase_->Release();
webrtc::VoiceEngine::Delete(ptrVoEngine_);
}
7完整代碼
//.h文件
#pragma once
#include <QWidget>
#include <QDebug>
#include <mutex>
#include "video_capture/video_capture_factory.h"
#include "base/device.h"
#include "engine/webrtcvideocapturer.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
#include "ui_videoCap.h"
//audio
#include "webrtc/voice_engine/include/voe_hardware.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/voice_engine_defines.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
#include "webrtc/voice_engine/include/voe_file.h"
#include "webrtc/voice_engine/voice_engine_impl.h"
class VoiceObserver :public webrtc::VoiceEngineObserver
{
public:
virtual void CallbackOnError(int channel, int errCode) override
{
qDebug() << "channel id = " << channel << "errCode = " << errCode;
}
};
class videoCap:public QWidget
{
public:
explicit videoCap(QWidget *parent = nullptr);
~videoCap();
protected:
virtual void paintEvent(QPaintEvent *event) override;
private:
void OnOpenPbClicked();
void OnPlayPbClicked();
bool InitVoiceEnginee();
void UnInitVoiceEnginee();
void setDevice();
int GetMicroVolume();
void SetMicroVolume(int n);
int GetSpeakVolume();
void SetSpeakVolume(int n);
private:
Ui::Form ui;
webrtc::VoiceEngine* ptrVoEngine_;
webrtc::VoEBase* ptrVoEBase_;
webrtc::VoEVolumeControl* ptrVoEVolumeControl_;
webrtc::VoEFile* ptrVoEFile_;
webrtc::VoEHardware* ptrVoEHardware_;
VoiceObserver voeObserver_;
int audio_channel_;
};
.cpp文件
#include "videoCap.h"
#include <QPainter>
#include "libyuv/include/libyuv.h"
#define VIDEO_FILE "1234.pcm"
videoCap::videoCap(QWidget *parent)
:QWidget(parent)
,ptrVoEBase_(nullptr)
,ptrVoEFile_(nullptr)
,ptrVoEngine_(nullptr)
,ptrVoEHardware_(nullptr)
,ptrVoEVolumeControl_(nullptr)
{
ui.setupUi(this);
if (!InitVoiceEnginee())
return;
setDevice();
QObject::connect(ui.m_pbOpen,&QPushButton::clicked,this,&videoCap::OnOpenPbClicked);
QObject::connect(ui.m_pbPlayer,&QPushButton::clicked,this,&videoCap::OnPlayPbClicked);
ui.m_pbOpen->setText(QString::fromLocal8Bit("打開"));
ui.m_pbPlayer->setText(QString::fromLocal8Bit("播放"));
connect(ui.m_slider_Speaker,&QSlider::valueChanged,this,&videoCap::SetSpeakVolume);
connect(ui.m_slider_Micro, &QSlider::valueChanged, this, &videoCap::SetMicroVolume);
GetMicroVolume();
GetSpeakVolume();
}
bool videoCap::InitVoiceEnginee()
{
ptrVoEngine_ = webrtc::VoiceEngine::Create();
ptrVoEBase_ = webrtc::VoEBase::GetInterface(ptrVoEngine_);
ptrVoEHardware_ = webrtc::VoEHardware::GetInterface(ptrVoEngine_);
ptrVoEFile_ = webrtc::VoEFile::GetInterface(ptrVoEngine_);
ptrVoEVolumeControl_ = webrtc::VoEVolumeControl::GetInterface(ptrVoEngine_);
int errCode = ptrVoEBase_->Init();
if (errCode != 0)
{
return false;
}
errCode = ptrVoEBase_->RegisterVoiceEngineObserver(voeObserver_);
if (errCode != 0)
{
return false;
}
return true;
}
void videoCap::UnInitVoiceEnginee()
{
if (ptrVoEFile_->IsPlayingFileLocally(audio_channel_))
{
ptrVoEFile_->StopPlayingFileLocally(audio_channel_);
}
ptrVoEFile_->StopRecordingMicrophone();
ptrVoEBase_->StopPlayout(audio_channel_);
ptrVoEFile_->Release();
ptrVoEHardware_->Release();
ptrVoEVolumeControl_->Release();
ptrVoEBase_->Release();
webrtc::VoiceEngine::Delete(ptrVoEngine_);
}
videoCap::~videoCap()
{
UnInitVoiceEnginee();
}
void videoCap::OnOpenPbClicked()
{
if (ui.m_pbOpen->text() == QString::fromLocal8Bit("打開"))
{
ptrVoEFile_->StartRecordingMicrophone(VIDEO_FILE);
ui.m_pbOpen->setText(QString::fromLocal8Bit("關閉"));
}
else
{
ptrVoEFile_->StopRecordingMicrophone();
ui.m_pbOpen->setText(QString::fromLocal8Bit("打開"));
}
}
void videoCap::OnPlayPbClicked()
{
if (ui.m_pbPlayer->text() == QString::fromLocal8Bit("播放"))
{
ptrVoEFile_->StartPlayingFileLocally(audio_channel_, VIDEO_FILE);
ui.m_pbPlayer->setText(QString::fromLocal8Bit("停止"));
}
else
{
ptrVoEFile_->StopPlayingFileLocally(audio_channel_);
ui.m_pbPlayer->setText(QString::fromLocal8Bit("播放"));
}
}
void videoCap::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
}
void videoCap::setDevice()
{
int recoder_device_num{ 0 };
int play_device_num{ 0 };
int errCode = ptrVoEHardware_->GetNumOfRecordingDevices(recoder_device_num);
if (errCode != 0)
{
return;
}
errCode = ptrVoEHardware_->GetNumOfPlayoutDevices(play_device_num);
if (errCode != 0)
{
return;
}
for (int i = 0; i < recoder_device_num; ++i)
{
char devName[256]{ 0 };
char guidName[256]{ 0 };
ptrVoEHardware_->GetRecordingDeviceName(i, devName, guidName);
ui.m_cbRecoderDev->addItem(devName, i);
}
for (int i = 0; i < recoder_device_num; ++i)
{
char devName[256]{ 0 };
char guidName[256]{ 0 };
ptrVoEHardware_->GetPlayoutDeviceName(i, devName, guidName);
ui.m_cbPlayerDev->addItem(devName,i);
}
audio_channel_ = ptrVoEBase_->CreateChannel();
if (audio_channel_ < 0)
{
qDebug() << "ERROR in VoEBase::CreateChannel";
}
errCode = ptrVoEBase_->StartPlayout(audio_channel_);
if (errCode != 0)
{
qDebug() << "ERROR in VoEBase::StartPlayout";
}
}
int videoCap::GetMicroVolume()
{
unsigned int n{ 0 };
ptrVoEVolumeControl_->GetMicVolume(n);
ui.m_slider_Speaker->setValue(n);
return n;
}
void videoCap::SetMicroVolume(int n)
{
int errCode = ptrVoEVolumeControl_->SetMicVolume(n);
if (errCode != 0)
{
qDebug() << "set volume failed";
}
}
int videoCap::GetSpeakVolume()
{
unsigned int n{ 0 };
ptrVoEVolumeControl_->GetSpeakerVolume(n);
ui.m_slider_Micro->setValue(n);
return n;
}
void videoCap::SetSpeakVolume(int n)
{
int errCode = ptrVoEVolumeControl_->SetSpeakerVolume(n);
if (errCode != 0)
{
qDebug() << "set volume failed";
}
}
8編譯錯誤,音頻需要依賴的模塊
video_capture_module.lib
video_capture_module_internal_impl.lib
common_video.lib
rtc_base.lib
rtc_media.lib
voice_engine.lib
rtc_base_approved.lib
rtc_event_log_proto.lib
rtc_event_log.lib
protobuf_full_do_not_use.lib
protobuf_lite.lib
protoc_lib.lib
system_wrappers.lib
directshow_baseclasses.lib
webrtc_i420.lib
libyuv.lib
Winmm.lib
libjpeg.lib
audio_device.lib
audio_decoder_interface.lib
audio_processing.lib
audio_processing_sse2.lib
audio_coding_module.lib
audio_encoder_interface.lib
audio_decoder_factory_interface.lib
rtp_rtcp.lib
rent_a_codec.lib
isac.lib
audio_conference_mixer.lib
webrtc_utility.lib
webrtc_common.lib
common_audio.lib
openmax_dl.lib
common_audio_sse2.lib
media_file.lib
red.lib
builtin_audio_decoder_factory.lib
isac_common.lib
pcm16b.lib
cng.lib
g711.lib
webrtc_opus.lib
opus.lib
ilbc.lib
g722.lib
neteq.lib
metrics_default.lib
audioproc_debug_proto.lib
paced_sender.lib
msdmo.lib
wmcodecdspuuid.lib
dmoguids.lib
最後三個是directShow的依賴,不是webrtc源碼編譯出來的,
還有些預處理需要添加
WEBRTC_WIN
QT_NO_KEYWORDS
_DEBUG
NOMINMAX
否則會編譯失敗
參考燦哥哥的博客