WINCE声音驱动模型概述

来源:互联网 发布:一起游手游专营店淘宝 编辑:程序博客网 时间:2024/05/17 03:27

1.1 WINCE的声音模型

标准的WINDOWS CE下的声音处理模型。

1)  声音应用在使用WAVE接口函数的时候被COREDLL模块分了类:如果是简单的PCM数据,则直接进入ADM模块,进行SoftWare Mixer或者连Mixer也省了,直接调用Driver放音;如果是压缩模式的数据则进入ACM模块进行解压处理后(比如:GSM/G7XX等等…)再次进入ADM模块。 此外,如果DRIVER支持硬件的Mixer,则应用层直接Bypass掉ACM和ADM,直接进入到驱动进行软件或者硬件进行混音和放音。

 

2)  ACM、Software Mixer都是可选配单元,可以通过注册表或者CE内核配置参数添加或者删除。

1.2 WINCE的声音驱动模型
l         分层模型

 

 这是一个标准的分层 MDD-PDD 流式接口模型。 应用层的WAVEAPI都使用WaveAPI Manager(WaveApi.DLL)通过DeviceIOControl映射成为WAV_IOControl函数进行处理。

 MDD层是微软的标准实现,通过DDSI (device driver service-provider interface )和PDD层实现进行连接。MDD通过消息来通知PDD层(PDD_WaveProc处理)

 

MDD层接口函数

·                 WAV_Close

·                 WAV_Deinit

·                 WAV_Init

·                 WAV_IOControl

·                 WAV_Open

·                 WAV_PowerDown

·                 WAV_PowerUp

·                 WAV_Read

·                 WAV_Seek

·                 WAV_Write

DDSI接口函数

·                 PDD_AudioDeinitialize

·                 PDD_AudioGetInterruptType

·                 PDD_AudioInitialize

·                 PDD_AudioMessage

·                 PDD_AudioPowerHandler

·                 PDD_WaveProc

 

但是分层模型也有一定的限制

·                 只支持一个设备

·                 不支持多个流

·                 对循环支持的不好

·                 对多个流数据支持的不是很好

 

l         单片模型

 

 

对于单片模型,WINCE是希望过渡到这个方案上的。该模型下,驱动的移植

还是很简单的。同时,该模型也客服了以前只能通过内核的MIXER来支持多个流的局限,在驱动层面即支持输入和输出多个流的混音操作。

 

l         分层模型的基本运转

分层模型支持同时放音和录音操作。MDD层管理着一个中断处理程序和多个

DMA BUFFERS,一般放音和录音都使用双DMA 缓冲。

比如,放音的时候,应用通过WAVEAPI传递过来一些数据,MDD层通过 PDD_WaveProc 函数发送 WPDM_START消息给PDD,PDD层将数据拷贝到DMA缓冲,并启动硬件放音。当DMA完成一个BUFFER的数据传送后,会产生一个硬件中断,PDD层会设定一个 AUDIO_STATE_OUT_PLAYING标志 。如果MDD发现有更多的数据要传送就会通过WPDM_CONTINUE.消息让PDD层继续负责填充DMA缓冲,否则就发送一个WPDM_ENDOFDATA.消息让PDD层停止DMA。

WINCE WAVE接口模型详解
1、标准的WAVE流式驱动程序接口

WAVE的驱动程序提供标准的流式接口给高层,但真正产生关键作用的是

WAV_IOControl这个函数。该函数的以下两个参数最重要:

dwCode

具体的IO控制命令,包括:

IOCTL_WAV_MESSAGE  (处理放音和录音相关的所有操作)

IOCTL_DSDVR_MESSAGE (DirectSound 动作处理)

IOCTL_MIX_MESSAGE.   (MIXER的操作)

pBufIn

指向了MMDRV_MESSAGE_PARAMS结构,该结构如下:

      Struct {

             UINT uDeviceId;

       UINT uMsg;

       DWORD dwUser;

       DWORD dwParam1;

       DWORD dwParam2;

}MMDRV_MESSAGE_PARAMS;

                    

                     uDeviceId: 0,1,2 。。。 如果是0代表全局或者缺省的设备

                     uMsg :用作(WIDM_*),(WODM_*), (MXDM_*)三种消息

                     dwUser:实例的具体标识

  

       通过这个函数传递的高层命令,最终导致驱动的具体动作,放音、录音或者混音。

 

2、关键的数据结构

        WAVE OPEN时候使用的数据结构:

              WAVEFORMATEX{

                     WORD  wFormatTag;

                     WORD  wChannels;

                     DWORD       nSamplesPerSec;

                     DWORD  nAvgBytesPerSec;

                     WORD  nBlockAlign;

                     WORD  nBitsPerSample;

                     WORD  cbSize;

}

该数据结构定义了一个Audio Stream所需要的大部分信息,当做WAVE OPEN的时候可能应用可能会首先尝试打开,这个时候WAVE_IO_CONTROL 就会传递一个WAVE_FORMAT_QUERY 给驱动,而驱动只是简单的检查是否真正的支持请求的格式,而不真正打开设备。

 

每次应用添加声音数据的时候会使用如下数据结构:

Struct {

LPSTR lpData;

DWORD dwBufferLength;

DWORD dwBytesRecorded;

DWORD dwUser;

DWORD dwFlags;

DWORD dwLoops;

Struct wavehdr_tag *lpNext;

DWORD Reserved;
}

其中dwFlags定义了几个标志:

              WHDR_BEGINLOOP :指明这个BUFFER是否要求被自动重放 (APP设)

              WHDR_DONE          :指明这个BUFFER已经处理完毕(驱动设)

              WHDR_ENDLOOP :指明这个BUFFER是否结束重放(APP设)

              WHDR_INQUEUE :指明这个BUFFER入队列(驱动设)

              WHDR_PREPARED:指明这个BUFFER的确准备好(APP或驱动设)

这几个标志是应用和驱动通信的关键,也是对队列操作的关键。应用和驱动通过设定这些标志位,让数据不断在驱动和应用之间流动,从而完成录放的各种操作。当然,这个过程还要配合一些WAVE 消息。

 

 

放音的消息解析

WINCE的声音驱动模型在放音的工作中定义了21个消息(懒了,不再列举了),但在具体实现中并不是每个消息都必须实现。

消息很多,特别是在具体实现中需要和DMA操作模型配合使用,因此理解消息的用途和推敲它们之间的关系就显得格外重要了!

通过仔细推敲它们之间的关系,我们可以将放音的整个过程规划成如下一些状态,并用状态迁移图来理解消息的使用,整个过程的操作就非常简单了。

 

 

混音的处理

       如果要WINDOWS CE的声音驱动模型支持混音,则要考虑如下问题:

1)  声音设备是否支持硬件混音

2)  声音设备需要工作在同一种采样频率下

3)  声音设备要能够同时支持录音和放音操作

 

而声音的驱动要负责完成声音采集的混音和声音放音的混音。其基本原理如下:

1)  将声音设备设定在一个频率下,比如:44.1KHZ,16BIT

2)  驱动允许打开多个音频流,每个音频流可以允许不同的采样率,比如: (A:8KHZ,8BIT    B: 44.1KHZ,16BIT)

3)  放音的混音在最后的数据准备阶段(即放入到DMA前),用合成算法将所有的流进行数学运算,得出声音设备采样频率下(44.1KHZ,16BIT)的数据。数据通过DMA发送到CODEC中。

4)  录音的混音操作,都是从声音设备采样频率下(44.1KHZ,16BIT)下得到采样的基本数据,然后通过数学运算分配到不同的频率下的音频流上。

5)  要注意的就是合成的时候要注意数据不溢出;分开的时候要注意数据速率的匹配和数据宽度的匹配。

 


中断和DMA驱动模型
声音系统一般都使用DMA作为数据传输的基本手段,因此DMA的操作模型对于

声音子系统的处理有着特别关键的作用。DMA的声音操作一般都是用双BUFFER作为

数据缓冲(录和放)都如此,一个BUFFER在被DMA占用的时候,另一个BUFFER

就可以被CPU占用,从而提高效率。显而易见,声音子系统的硬件操作是一个典型的
生产者消费者模式,因此,对共享资源的控制就特别重要。

DMA的硬件实现,不同的CPU略有不同。有的嵌入式芯片做的简单,不支持DMA地址的链式连接,有的则支持,但不影响具体实现。他们相同的点是:

l         一般一个DMA有N个子CHANNEL

l         每一个CHANNEL都可以互不干扰的独立运转或者停机,自有一个状态机

l         DMA使用一个总的DMA 中断通知CPU,然后由软件负责查找具体某个CHANNEL。

 

如果一个系统中很多驱动都需要用到DMA,那么就需要一个DMA ENGINE来总

协调DMA的运作,否则就会出现驱动争用DMA的问题。如果只有一个驱动使用DMA系统,则实现起来的障碍会小不少。

双声道系统中的声音驱动,DMA运作都是采用两个通道独立完成录、放的操作,并且每个通道都采用双BUFFER的策略,来保证DMA和CPU可以近乎同时的工作,互不影响。而且,一个在高层支持多个流的声音驱动也要注意对DMA这个硬件设备的操作要保持互斥。

在实际驱动的实现过程中,这种双通道、双BUFFER的驱动有很多细节要注意,要注意处理好几大类关系:

1)  硬件 DMA和硬件CODEC之间的关系

在整个放音声音数据传输系统中有:

       APP buffer ßà DMA buffer ßà I2S(AC97) FIFO ßà CODEC

APP负责提供数据,DMA负责数据传输,其实就是要把数据搬运到类似I2S或者AC97间的FIFO中,I2S负责成帧传递数据,最后由CODEC还原。录音则反之。

一般来讲,I2S和CODEC要在DMA启动前准备好,而启动DMA和I2S的顺序,往往会导致一些数据的丢失,这是关注的一点。

 

2)  DMA与APP  buffer之间的关系

还原处理时: APP 往往提供很大的数据包,比如16K,而DMA由于设计的需要,一般取到4K,就比较大了。

启动DMA开始工作的条件是:

---填充完毕两个DMA BUFFER

---I2S准备好

 

当DMA完成搬运后,会产生DMA的中断,而在中断处理中,要注意一下问题:

---启动第二个BUFFER,继续让DMA工作,如果不能启动就要DMA停机了。

---CPU负责检查是否还有足够的数据给DMA,如果有,够填充几个DMA BUFFER

 

DMA停机的条件是:

---没有更多的BUFFER可供搬运

---强制停机

 

在实践过程中,要拿捏好DMA启动和停机的条件,因为驱动一般都是多线程运转的,一定要注意对DMA操作时的互斥,防止出现异常或者死锁。

 

另外,DMA BUFFER的大小,直接关系到采样的频率,对于一些实时应用很重要。比如:VOIP中需要20ms 的打包周期,就需要限制DMA BUFFER的大小,从而控制中断时间,及时为VOIP提供周期打包数据。

 

3)  DMA多CHANNEL之间的关系

如果同时启动录音和放音CHANNEL,那么在DMA的中断处理中要注意区分是谁的数据,并且要及时启动各自CHANNEL的第二个BUFFER,防止采集数据丢失或者放音停顿。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cnhighway/archive/2009/05/15/4188016.aspx

 

原创粉丝点击