Audio Driver 架构

在WINCE中 Audio Driver 架构支持两种驱动模式

即独立型的unified audio model (UAM)驱动 和 分层式的MDD and PDD mode驱动,(不论是UAM或者MDD/PDD都是流接口驱动)。

其架构还支持的audio compression manager (ACM)驱动,例如codecs, converters, and filters等器件

1)         UAM

UAM支持标准波形驱动接口(standard wave driver interfaces),过去的波形驱动和采样驱动是由MDD和PDD模型组成。MDD模型执行了驱动的独立硬件部分以及输出到驱动接口的中间设备。PDD模型提供了驱动依赖硬件的执行部分

The following illustration shows the UAM stack.:

Using MDD and PDD, the previous model had the following limitations:

·            No support for multiple streams

·            No multiple devices on one driver

·            No reliable support for looping

·            Poor support for streaming

OEM商可以围绕这些限制来移植自己的MDD或者写入他们自己的完整驱动来输出到合适的接口到中间设备

UAM实现了对WAV和Microsoft DirectSound®音频API的高效支持。它还使得编写一个能有效支持WAV和DirectSound的驱动程序成为可能。

在我们的WM8753 音频Driver中即使用了UAM这种驱动模式,它也是一种流接口驱动,故只需编写驱动中WAVE和MIXER这两部分,然后使用流接口函数调用即可。

2).音频MDD和PDD

编写音频驱动我们可以选择UAM架构,或者直接执行流接口(stream interface),我们使用由微软提供的MDD库-Wavemdd.lib。这个库通过DDSI来执行流接口功能。如果使用了Wavemdd.lib,则必须一个PDD库来执行音频DDSI的功能。这个库被称为Wavepdd,lib, 这两个库编译连接后就形成了我们的音频驱动,通常被为Wavedev,dll。

在系统程序文件中可能缺少器件的功能导致音频器件的很多功能无法被使用,为了解决这个问题DeviceIOControl 就变得很重要了。DeviceIOControl是流接口的一部分,其允许任意功能能够通过WAV_IOControl功能来正确得操作硬件。例如:当命令器件准备录音时,中间设备会使用WAV_IOControl发送WIDM_PREPARE消息给音频驱动。

由于音频驱动完全依赖DeviceIOControl功能消息,所以执行剩余得流接口就相对简单了,

特别像WAV_Read, WAV_Seek, and WAV_Write功能仅仅是返回不变的值

下图显示了使用 MDD 库的音频驱动程序的交互

以下列表显示了音频驱动程序的 DDSI 函数

PDD_AudioDeinitialize
 This function turns off and disconnects the audio device.
 
PDD_AudioGetInterruptType
 This function determines the cause of the audio interrupt and returns the current device status.
 
PDD_AudioInitialize
 This function initializes the audio device for operation. 
 
PDD_AudioMessage
 This function sends messages from user applications to the audio driver's platform-dependent driver (PDD) layer.
 
PDD_AudioPowerHandler
 This function is responsible for managing the audio hardware during POWER_UP and POWER_DOWN notifications.
 
PDD_WaveProc
 This function sends messages to the audio driver's PDD layer.

PDD和MDD都依靠调用DDSI函数来实现相互通信,所以若采用分层式来编写驱动,只需找到微软提供的MDD,然后根据其DDSI来编写PDD层即可。

对于流驱动,×××_Open/×××_Close/×××_IoControl等就是ddi;如果不是流驱动,它的ddi不具有上述形式;

以我们的driver为例,在程序中,我们可以在C:/WINCE500/PLATFORM/C340/Src/Drivers/audio/IIS/wm8753/wavemain.cpp中找到以下对应点

Programming element

Description

WAV_IOControl

This function is the device I/O control routine for the WAV I/O device.

WAV_Init

This function initializes the WAV I/O device.

WAV_Deinit

This function deinitializes the WAV I/O device.

WAV_Open

This function opens the WAV I/O device.

WAV_Close

This function closes the WAV I/O device.

WAV_Read

This function is the read routine for the WAV I/O device driver.

WAV_Write

This function is the write routine for the WAV I/O device.

WAV_Seek

This function is the seek routine for the WAV I/O device.

WAV_PowerUp

This function notifies the WAV I/O device that the system is leaving the suspend state.

WAV_PowerDown

This function turns off the WAV I/O device

在注册表中还要建立驱动程序的入口点,这样设备管理器才能识别和管理这个驱动

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Audio]

"Prefix"="WAV"

"Dll"="s3c2440a_iis_wm8753.dll"

"Index"=dword:1

"Order"=dword:0

此外,注册表还能储存额外的信息,这些信息可以在驱动运行之后被使用到,DLL项是设备管理器在加载驱动时需要的DLL名称;Prefix代表了设备前缀;Order是驱动程序被加载的顺序

WIDM_GETDEVCAPS

This message is used to request a waveform input driver to return the capabilities of a specified device.

WIDM_GETNUMDEVS

This message is used to request a waveform input driver to return the number of devices that it supports.

WIDM_GETPOS

This message is used to request a stream input driver to return the current input position within a waveform. The input position is relative to the first recorded sample of the waveform.

WIDM_OPEN

This message is used to request a waveform input driver to open a stream of a specified device.

WIDM_PREPARE

This message is used to request a waveform input driver to prepare a system-exclusive data buffer for input.

WIDM_RESET

This message is used to request a waveform input driver to stop recording and return all buffers in the input queue to the caller.

WIDM_START

This message is used to request a waveform input driver to begin recording.

WIDM_STOP

This message is used to request a waveform input driver to stop recording.

WIDM_UNPREPARE

This message is used to request a waveform input driver to undo the buffer preparation that was performed in response to a WIDM_PREPARE message.

下表中列出了各个输出driver消息

Programming element

Description

WODM_BREAKLOOP

This message is used to request a waveform output driver to break an output loop that was created with a WODM_WRITE message.

WODM_CLOSE

This message is used to request a waveform output driver to close a specified stream that was previously opened with a WODM_OPEN message.

WODM_GETDEVCAPS

This message is used to request a waveform output driver to return the capabilities of a specified device.

WODM_GETNUMDEVS

This message is used to request a waveform output driver to return the number of device instances that it supports.

WODM_GETPITCH

This message is used to request a waveform output driver to return the specified device's current pitch multiplier value.

WODM_GETPLAYBACKRATE

This message is to request a waveform output driver to return the current playback rate multiplier value for the specified device.

WODM_GETPOS

This message is used to return the current position within a stream. The position is relative to the beginning of the waveform.

WODM_GETVOLUME

This message is used to request a waveform output driver to return the current volume level setting for the specified device or stream.

WODM_OPEN

This message is used to request a waveform output driver to open a stream on the specified device.

WODM_PAUSE

This message is used to request a waveform output driver to pause playback of a waveform.

WODM_PREPARE

This message is used to request a waveform output driver to prepare a system-exclusive data buffer for output.

WODM_RESET

This message is used to request a waveform output driver to stop sending output data and return all output buffers to the list.

WODM_RESTART

This message is used to request a waveform output driver to continue playback of a waveform after playback has been paused with WODM_PAUSE.

WODM_SETPITCH

This message is used to request a waveform output driver to set the specified device's pitch multiplier value.

WODM_SETPLAYBACKRATE

This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

WODM_SETVOLUME

This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

WODM_UNPREPARE

This message is used to request a waveform output driver to remove the buffer preparation performed in response to WODM_PREPARE.

WODM_WRITE

This message is used to request a waveform output driver to write a waveform data block to the specified device.

以我们的WM8753音频Driver 为例,整个驱动里包含了以下重要功能的子驱动:

Devctxt.cpp

器件关联——包含了音频流的创造,删除,打开,关闭,格式等功能

Hwctxt.cpp

硬件关联——包含了基本的硬件功能在各个状态的全局配置

I2citf.cpp

I2C传输配置

I2S.cpp

I2S传输配置

Input.cpp

负责输入音频流

Output.cpp

负责输出音频流

Midinote.cpp

负责输出MIDI

Midistrm.cpp

负责MIDI的开关以及控制

Mixerdrv.cpp

系统软件混音

RTcodecComm.cpp

Wm8753的所有功能配置,以及初始化设置

Strmctxt.cpp

负责所有音频流的增益,buffer请求等功能以及对Devctxt的控制

Wavemain.cpp

包含了所有的流接口函数

按照UAM的定义, wm8753的driver主要由mixer和wave两部分组成;

由于mixer只实现一些基本的混音功能,其主要由Mixerdrv.cpp承担,还包括Midistrm.cpp,Input.cpp,Output.cpp的部分功能。而其他基本都是wave功能

Wavemain.cpp基于整个驱动的最上层,其中,流接口函数做到了以下控制:

Wav_init ——> hwctxt    RTcodecComm

I2citf.,

I2S

Wav_deinit               devctxt

Wav_Powerup            hwctxt

Wav_powerdown          mixerdrv

strmctxt

Wav_IOControl——> Wav_open/close——> 所有

若要移植一个音频驱动到另一个器件,一般只需更改Hwctxt.cpp,I2citf.cpp,I2S.cpp,RTcodecComm.cpp 即可

四.以下是WM8753的WAV_IOControl调用说明:

extern "C" BOOL WAV_IOControl(DWORD  dwOpenData,

DWORD  dwCode,

PBYTE  pBufIn,

DWORD  dwLenIn,

PBYTE  pBufOut,

DWORD  dwLenOut,

PDWORD pdwActualOut)

{

_try

{

switch (dwCode)

{

case IOCTL_MIX_MESSAGE:

return HandleMixerMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);//调用混音消息

case IOCTL_WAV_MESSAGE:

return HandleWaveMessage((PMMDRV_MESSAGE_PARAMS)pBufIn, (DWORD *)pBufOut);//调用音频消息

//以下为电源管理功能

case IOCTL_POWER_CAPABILITIES:

case IOCTL_POWER_SET:

case IOCTL_POWER_GET:

return g_pHWContext->IOControl

(dwOpenData, dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);

}

}

BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult) //管理音频消息

{

//  set the error code to be no error first

SetLastError(MMSYSERR_NOERROR);

UINT uMsg = pParams->uMsg;

UINT uDeviceId = pParams->uDeviceId;

DWORD dwParam1 = pParams->dwParam1;

DWORD dwParam2 = pParams->dwParam2;

DWORD dwUser   = pParams->dwUser;

StreamContext *pStreamContext = (StreamContext *)dwUser;

DWORD dwRet;

g_pHWContext->Lock();

// catch exceptions inside device lock, otherwise device will remain locked!

_try

{

switch (uMsg)

{

case WODM_GETNUMDEVS: //This message is used to request a waveform output driver to return the capabilities of a specified device.

{

dwRet = g_pHWContext->GetNumOutputDevices();

break;

}

case WIDM_GETNUMDEVS:// This message is used to request a waveform input driver to return the number of devices that it supports.

{

dwRet = g_pHWContext->GetNumInputDevices();

break;

}

case WODM_GETDEVCAPS:// This message is used to request a waveform output driver to return the capabilities of a specified device.

{

DeviceContext *pDeviceContext;

UINT NumDevs = g_pHWContext->GetNumOutputDevices();

if (pStreamContext)

{

pDeviceContext=pStreamContext->GetDeviceContext();

}

else

{

pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

}

dwRet = pDeviceContext->GetDevCaps((PVOID)dwParam1,dwParam2);

break;

}

case WIDM_GETDEVCAPS:// This message is used to request a waveform input driver to return the capabilities of a specified device.

{

DeviceContext *pDeviceContext;

http://www.bbfar.com/article/2e/590.html

UINT NumDevs = g_pHWContext->GetNumInputDevices();

if (pStreamContext)

{

pDeviceContext=pStreamContext->GetDeviceContext();

}

else

{

pDeviceContext = g_pHWContext->GetInputDeviceContext(uDeviceId);

}

dwRet = pDeviceContext->GetDevCaps((PVOID)dwParam1,dwParam2);

break;

}

case WODM_GETEXTDEVCAPS:

{

DeviceContext *pDeviceContext;

UINT NumDevs = g_pHWContext->GetNumOutputDevices();

if (pStreamContext)

{

pDeviceContext=pStreamContext->GetDeviceContext();

}

else

{

pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

}

dwRet = pDeviceContext->GetExtDevCaps((PVOID)dwParam1,dwParam2);

break;

}

case WODM_OPEN:// This message is used to request a waveform output driver to open a stream on the specified device.

{

// DEBUGMSG(1, (TEXT("WODM_OPEN/r/n"));

DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

dwRet = pDeviceContext->OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)dwUser);

break;

}

case WIDM_OPEN:// This message is used to request a waveform input driver to open a stream of a specified device.

{

// DEBUGMSG(1, (TEXT("WIDM_OPEN/r/n"));

DeviceContext *pDeviceContext = g_pHWContext->GetInputDeviceContext(uDeviceId);

dwRet = pDeviceContext->OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)dwUser);

break;

}

case WODM_CLOSE:

case WIDM_CLOSE:

{

// DEBUGMSG(1, (TEXT("WIDM_CLOSE/WODM_CLOSE/r/n"));

dwRet = pStreamContext->Close();

// Release stream context here, rather than inside StreamContext::Close, so that if someone

// (like CMidiStream) has subclassed Close there's no chance that the object will get released

// out from under them.

if (dwRet==MMSYSERR_NOERROR)

{

pStreamContext->Release();

}

break;

}

case WODM_RESTART:

case WIDM_START:

{

dwRet = pStreamContext->Run();

break;

}

case WODM_PAUSE:

case WIDM_STOP:

{

dwRet = pStreamContext->Stop();

break;

}

case WODM_GETPOS:

case WIDM_GETPOS:

{

dwRet = pStreamContext->GetPos((PMMTIME)dwParam1);

break;

}

case WODM_RESET:

case WIDM_RESET:

{

dwRet = pStreamContext->Reset();

break;

}

case WODM_WRITE:

case WIDM_ADDBUFFER:

{

// DEBUGMSG(1, (TEXT("WODM_WRITE/WIDM_ADDBUFFER, Buffer=0x%x/r/n"),dwParam1);

dwRet = pStreamContext->QueueBuffer((LPWAVEHDR)dwParam1);

break;

}

case WODM_GETVOLUME:// This message is used to request a waveform output driver to return the current volume level setting for the specified device or stream.

{

PULONG pdwGain = (PULONG)dwParam1;

if (pStreamContext)

{

*pdwGain = pStreamContext->GetGain();

}

else

{

#ifdef USE_HW_GAIN_WODM_SETGETVOLUME

// Handle device gain in hardware

*pdwGain = g_pHWContext->GetOutputGain();

#else

// Handle device gain in software

DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

*pdwGain = pDeviceContext->GetGain();

#endif

}

dwRet = MMSYSERR_NOERROR;

break;

}

case WODM_SETVOLUME:// This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.

{

LONG dwGain = dwParam1;

if (pStreamContext)

{

dwRet = pStreamContext->SetGain(dwGain);

}

else

{

#ifdef USE_HW_GAIN_WODM_SETGETVOLUME

// Handle device gain in hardware

dwRet = g_pHWContext->SetOutputGain(dwGain);

#else

// Handle device gain in software

DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

dwRet = pDeviceContext->SetGain(dwGain);

#endif

}

break;

}

case WODM_BREAKLOOP:// This message is used to request a waveform output driver to break an output loop that was created with a WODM_WRITE message.

{

dwRet = pStreamContext->BreakLoop();

break;

}

case WODM_SETPLAYBACKRATE:// This message is used to request a waveform output driver to set the playback rate multiplier value for the specified device.         {

WaveStreamContext *pWaveStream = (WaveStreamContext *)dwUser;

dwRet = pWaveStream->SetRate(dwParam1);

break;

}

case WODM_GETPLAYBACKRATE:// This message is to request a waveform output driver to return the current playback rate multiplier value for the specified device.

{

WaveStreamContext *pWaveStream = (WaveStreamContext *)dwUser;

dwRet = pWaveStream->GetRate((DWORD *)dwParam1);

break;

}

case MM_WOM_SETSECONDARYGAINCLASS:

{

dwRet = pStreamContext->SetSecondaryGainClass(dwParam1);

break;

}

case MM_WOM_SETSECONDARYGAINLIMIT:

{

DeviceContext *pDeviceContext;

if (pStreamContext)

{

pDeviceContext = pStreamContext->GetDeviceContext();

}

else

{

pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);

}

dwRet = pDeviceContext->SetSecondaryGainLimit(dwParam1,dwParam2);

break;

}

case MM_MOM_MIDIMESSAGE:

{

CMidiStream *pMidiStream = (CMidiStream *)dwUser;

dwRet = pMidiStream->MidiMessage(dwParam1);

break;

}

// For Debug Register

case WPDM_PRIVATE_WRITE_CODEC:

case WPDM_PRIVATE_READ_CODEC:

//{

//    dwRet=g_pHWContext->Private_AudioMessage(pParams->uMsg, pParams->dwParam1, pParams->dwParam2);

//     break;

//}

// unsupported messages

case WODM_GETPITCH:

case WODM_SETPITCH:

case WODM_PREPARE:

case WODM_UNPREPARE:

case WIDM_PREPARE:

case WIDM_UNPREPARE:

default:

dwRet  = MMSYSERR_NOTSUPPORTED;

break;

}

}

_except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)

{

ERRORMSG(1, (TEXT("Access violation in HandleWaveMessage!!!!/r/n")));

SetLastError(E_FAIL);

}

g_pHWContext->Unlock();

// Pass the return code back via pBufOut

if (pdwResult)

{

*pdwResult = dwRet;

}

return(TRUE);

}

Audio Driver 架构相关推荐

  1. 安装Realtek HD Audio Driver 失败 就是安装不上怎么办

    之前重装系统一直好好的,前几天重装完,安装声卡驱动时,一直提示 安装realtek hd audio driver 失败 [error code:0x0000FF] 网上的办法都用了,系统再次重装都没 ...

  2. dwc3 linux usb3.0 driver架构

    dwc3 linux usb3.0 driver架构: 1. DRD driver DRD驱动在usb/dwc3 1.1 dts dwc3@44000000 {/* Compatible ID use ...

  3. usb3.0驱动linux,dwc3 linux usb3.0 driver架构

    dwc3 linux usb3.0 driver架构: 1. DRD driver DRD驱动在usb/dwc3 1.1 dts dwc3@44000000 { /* Compatible ID us ...

  4. [Linux Audio Driver] Qualcomm平台音频GMS认证器件要求

    从GMS测试常见的fail项来明确其器件要求,常见的fail测试项主要是以下三个: 后面是分析,要看结论的话直接拉到文末: 一:Audio Frequency Speaker Test 此测试使用外部 ...

  5. 笔记本电脑外放没声音,或外放有声音/插耳机没声音———Realtek High Definition Audio Driver安装

    情况1:之前自己的电脑插入圆孔有线耳机,耳机没声音,当时直接在realtek官网下载64位,Windows10适配的Realtek High Definition Audio Driver,安装后耳机 ...

  6. [Linux Audio Driver] SM6350平台音频bring up ( 一 )

    0. 背景 这个是高通5G平台,音频的内容改的比较多,比较直接的是platform.c就直接移动到vendor了:目前 高通那边的趋势还是把音频逐渐从kernel剥离,android 7/androi ...

  7. 瑞昱Realtek(Realtek HD Audio Driver)音频声卡驱动R2.49 for Win7_Vista

    不管是在高端系列主板上,还是在低端系列主板上,我们都能看到Realtek瑞昱的身影,Realtek HD Audio Driver能够支持所有的Realtek HD Audio音频驱动.Realtek ...

  8. Wave Driver介绍-5(Waveform Audio Driver Test测试Case描述)

    http://blog.csdn.net/daydayupfromnowon/article/details/6003500 因为要对Audio Driver做CETK测试,所以今天了解了一下CETK ...

  9. Realtek HD Audio Driver安装失败的解决方法

    公司ACER4710笔记本电脑安装winxp系统,安装若干遍声音驱动都提示"安装Realtek HD Audio Driver失败": 解决的处理过程:  1,进入安全模式(否则相 ...

  10. [Linux Audio Driver] Android 10 machine driver probe函数分析

    0. 背景 平台:Qualcomm 5G SM6350.android10.kernel version: msm-4.19. 本文重点分析machine driver里面的msm_asoc_mach ...

最新文章

  1. Java接地气日常编码技巧
  2. PaddlePaddle yolov3
  3. Spring MVC 接收请求参数所有方式总结!
  4. 面向过程之骑士飞行棋
  5. mybatis出现 Parameter '__frch_excelModel_0' not found.
  6. RM格式转换成VCD
  7. 从Java视角理解CPU缓存(CPU Cache)
  8. 《蓝色协议BLUE PROTOCOL》技术分享解读
  9. 伪元素::before与::after的用法
  10. 王道操作系统考研笔记——1.1.6 系统调用
  11. href=“javascript:void(0);”和href=void(change_code(this));
  12. spring boot全局日期格式化配置
  13. 扫描仪 无线 打印服务器,自带扫描仪、还能无线打印,Find X2 Pro实用功能分享...
  14. 一文道尽Flutter最新最全的学习资料
  15. 登录账号提示服务器出错怎么办,教育平台号和密码都正确,就是显示用户名和或密码错误,登不上怎么办呀?...
  16. 水晶报表相关官方软件下载
  17. 全国区号省份mysql_中国各个省份的区号
  18. plc顺序控制设计法是什么?
  19. 华为p40支持鸿蒙,华为P40来袭,支持鸿蒙系统,花粉直呼惊喜
  20. 【机器学习实战】KNN

热门文章

  1. 云呐|固定资产盘点管理办法
  2. Java使用ODBC连接Access数据库
  3. 程序设计导引及在线实践——练习记录
  4. Java爬虫需要的包_java爬虫需要的jar包
  5. unix linux性能对比,各有所长!对比LINUX和UNIX系统优势
  6. 13个不容错过的Java项目
  7. 浅谈SQL注入攻击与防御(适用于小白观看)
  8. LINUX系统使用锐捷客户端认证校园网(华中科技大学)
  9. 用Python实现简单的Web Server
  10. java利用sigar获取电脑cpu 内存 硬盘使用率等信息