WebRTC源码之音频设备播放流程源码分析
WebRTC源码之音频设备播放流程源码分析
WebRTC专题开嗨鸭 !!!
一、 WebRTC 线程模型
2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用
二、 WebRTC媒体协商
三、 WebRTC 音频数据采集
四、 WebRTC 音频引擎(编解码和3A算法)
五、 WebRTC 视频数据采集
六、 WebRTC 视频引擎( 编解码)
七、 WebRTC 网络传输
2、WebRTC的ICE之Dtls/SSL/TLSv1.x协议详解
八、 WebRTC服务质量(Qos)
3、WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传
九、 NetEQ
十、 Simulcast与SVC
前言
WebRTC音频引擎启动基本流程图
ADM
一、 ADM的作用即创建
1、Audio Device Module 类关系图
2、创建ADM的时机
3、创建ADM的过程
二、 WIndows Audio Core 基本概念
1、从Window Vista开始提供了 Core Audio API
2、 其运行在用户空间的
3、Core Audio 是DirectSound和WaveXxx的基础
4、Win7 对Core Audio API做了增强的
5、Core Audio 的特性
①、低延迟
②、提高了可靠性,API从内核层移到了用户层
③、安全性更高
等等…
6、Core Audio关系图
MMDevice API
WAS API
DeviceTopology API
EndpointVolume API
Core Audio 有两种模式: 同享模式和独享模式
7、音频设备种类
- 音频终端设备,指外设
- 音频适配器设备,一般集成在主板上,接供PCI/PNP插口
8、音频终端设备
- 扬声器
- 麦克风
- 辅助输入设备(耳机)
9、音频适配设备
- 不行输出设备(数模转换器)
- 输出控制设备(音量和静音控件)
- 波输入设备(模数转换器)
- 输入控制设备(输入音量控制器,多数复用器)
三、 Audio Core API
分下面四种API
1、MMDevice API,最常用到的接口
①、MMDevice API 的作用
- 获得音频终端设备得Client
- 决定音频终端设备的能力
- 能为音频终端设备创建驱动实例
②、MMDevice API的组成
- IMMDevice,代表一个音频设备
- IMMDeviceCollection,音频设备集
- IMMDeviceEnumerator,用于枚举音频设备
- IMMEndpoint,代表一个音频终端设备
③、IMMDeviceEnumerator接口
- 它是IMMDevice API种最关键的接口
- 通过它可以获得IMMDevice接口
- 通过它可以获取IMMDeviceCollection接口
④、创建IMMDeviceEnumerator接口
⑤、COM组件
- 它是一个小的,可单独运行的程序;使用时类似一个API
- 应用程序可以通过多个COM组件的构成
- COM组件有可复用、动态更新、灵活等优点
-
两个COM对象能实现相同的接口
通过CLSID找到组件
通过IID找到COM组件种的接口
-
每个COM组件对象可以实现多个接口
⑥、IMMDeviceEnumerator支持的方法
- GateDefaultAudioEndpoint获取默认设备
- EnumAudioEndpoint枚举音频设备
等等
2、Windows Audio Session API (WASAPI)
3、Device Topology API(更高级的API)
4、EndpointVolume API( 修改主声音或独享方式使用)
四、ADM的初始化与设备管理
五、AudioState 的作用
六、音频播放设备的初始化
七、音频播放设备任何工作
八、音频采集设备的初始化
九、音频采集设备任何工作
十、采集后的数据交给谁?
十一、播放设置从哪儿获取数据?
InitPlay基础知识
一、几个主要的状态值
状态 | 默认值 | 作用 |
---|---|---|
_playing | false | 是否处于播放状态 |
_playIsinitialized | false | 是否对播放参数进行了设置 |
_buildInAecEnabled | false | 是否启用了硬件AEC功能 |
_recIsInitiaized | false | 是否对录录制参数进行了设备 |
_recording | false | 是否处理录制状态 |
_speakerIsInitialized | false | 是否对扬声器进行了初始化 |
_microphoneIsIntialized | false | 是否对microphone进行了初始化 |
二、音频的数据结构
/* general extended waveform format structure
Use this for all NON PCM formats
(information common to all formats)
*/
#ifndef _WAVEFORMATEX_
#define _WAVEFORMATEX_
typedef struct tWAVEFORMATEX
{
WORD wFormatTag; /* 设置声音格式类型 PCM format type */
WORD nChannels; /* 设置通道数 number of channels (i.e. mono, stereo...) */
DWORD nSamplesPerSec; /* 设置采样率 sample rate */
DWORD nAvgBytesPerSec; /* 设置每秒平均字节数 for buffer estimation */
WORD nBlockAlign; /* 设置对齐字节数 block size of data */
WORD wBitsPerSample; /*设置每个采样的大小(位深) Number of bits per sample of mono data */
WORD cbSize; /* 额外消息大小 The count in bytes of the size of
extra information (after cbSize) */
} WAVEFORMATEX;
typedef WAVEFORMATEX *PWAVEFORMATEX;
typedef WAVEFORMATEX NEAR *NPWAVEFORMATEX;
typedef WAVEFORMATEX FAR *LPWAVEFORMATEX;
#endif /* _WAVEFORMATEX_ */
#ifdef GUID_DEFINED
三、 音频接口 IAudioClient 接口
- 该接口属于WASAPI
- 该接口能够再音频应用程序和音频引擎之间采集音频流
- 也能再应用程序和设备的硬件缓冲区之间创建音频流
- 采集客户端
- 扬声器客户端
MIDL_INTERFACE("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2")
IAudioClient : public IUnknown
{
public:
// TODO@chensong 2022-07-24 初始化音频流
///
/**
* @param AUDCLNT_SHAREMODE : 共享模式/独占模式
* @param DWORD : 控制流创建的flag
* @param REFERENCE_TIME : 请求缓冲区的大小
* @param REFERENCE_TIME : 周期时间
* @param WAVEFORMATEX : 数据格式
* @param LPCGUID : Audio Session 的 GUID
* @return
*/
/
// StreamFlags 参数类型解释:
// AUDCLNT_STREAMFLAGS_LOOPBACK :
// AUDCLNT_STREAMFLAGS_EVENTCALLBACK :
// ...
virtual HRESULT STDMETHODCALLTYPE Initialize(
/* [annotation][in] */
_In_ AUDCLNT_SHAREMODE ShareMode,
/* [annotation][in] */
_In_ DWORD StreamFlags,
/* [annotation][in] */
_In_ REFERENCE_TIME hnsBufferDuration,
/* [annotation][in] */
_In_ REFERENCE_TIME hnsPeriodicity,
/* [annotation][in] */
_In_ const WAVEFORMATEX *pFormat,
/* [annotation][in] */
_In_opt_ LPCGUID AudioSessionGuid) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBufferSize(
/* [annotation][out] */
_Out_ UINT32 *pNumBufferFrames) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStreamLatency(
/* [annotation][out] */
_Out_ REFERENCE_TIME *phnsLatency) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCurrentPadding(
/* [annotation][out] */
_Out_ UINT32 *pNumPaddingFrames) = 0;
virtual HRESULT STDMETHODCALLTYPE IsFormatSupported(
/* [annotation][in] */
_In_ AUDCLNT_SHAREMODE ShareMode,
/* [annotation][in] */
_In_ const WAVEFORMATEX *pFormat,
/* [unique][annotation][out] */
_Out_opt_ WAVEFORMATEX **ppClosestMatch) = 0;
virtual HRESULT STDMETHODCALLTYPE GetMixFormat(
/* [annotation][out] */
_Out_ WAVEFORMATEX **ppDeviceFormat) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDevicePeriod(
/* [annotation][out] */
_Out_opt_ REFERENCE_TIME *phnsDefaultDevicePeriod,
/* [annotation][out] */
_Out_opt_ REFERENCE_TIME *phnsMinimumDevicePeriod) = 0;
virtual HRESULT STDMETHODCALLTYPE Start( void) = 0;
virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
virtual HRESULT STDMETHODCALLTYPE SetEventHandle(
/* [in] */ HANDLE eventHandle) = 0;
/
// TODO@chensong 2022-07-24 GetService 方法解释
/**
*
* @param rrid : 接口ID
* @param ppv : 输出的接口对象
* return STDMETHODCALLTYPE
*/
virtual HRESULT STDMETHODCALLTYPE GetService(
/* [annotation][in] */
_In_ REFIID riid,
/* [annotation][iid_is][out] */
_Out_ void **ppv) = 0;
};
音频流的访问方式
1、IAuidoClient的几个重要方法
- Initialize (模式[共享,独享] …)
- GetBufferSize
- SetEventHandle
- GetService
①、初始化音频流
...
// TODO@chensong 2022-07-24 初始化音频流
///
/**
* @param AUDCLNT_SHAREMODE : 共享模式/独占模式
* @param DWORD : 控制流创建的flag
* @param REFERENCE_TIME : 请求缓冲区的大小 [是与时间有关系的哈]
* @param REFERENCE_TIME : 周期时间 [10ms采集一次、 20ms采集一次]
* @param WAVEFORMATEX : 数据格式
* @param LPCGUID : Audio Session 的 GUID
* @return
*/
/
// StreamFlags 参数类型解释:
// AUDCLNT_STREAMFLAGS_LOOPBACK :
// AUDCLNT_STREAMFLAGS_EVENTCALLBACK :
// ...
hr = _ptrClientOut->Initialize(
AUDCLNT_SHAREMODE_SHARED, // share Audio Engine with other applications
AUDCLNT_STREAMFLAGS_EVENTCALLBACK, // processing of the audio buffer by
// the client will be event driven
hnsBufferDuration, // requested buffer capacity as a time value (in
// 100-nanosecond units)
0, // periodicity
&Wfx, // selected wave format
NULL); // session GUID
if (FAILED(hr)) {
RTC_LOG(LS_ERROR) << "IAudioClient::Initialize() failed:";
}
...
②、GetService方法
- 它是IAudioClient中的方法
- 用于获取IAudioRenderClient接口
- 用于下写数据到渲染终端的buffer
...
/
// TODO@chensong 2022-07-24 GetService 方法解释
/**
*
* @param rrid : 接口ID
* @param ppv : 输出的接口对象
* return STDMETHODCALLTYPE
*/
// Get an IAudioRenderClient interface.
SAFE_RELEASE(_ptrRenderClient);
hr = _ptrClientOut->GetService(__uuidof(IAudioRenderClient),
(void**)&_ptrRenderClient);
EXIT_ON_ERROR(hr);
...