wince7下音频驱动学习(以DM3730为例,主要是数据的输出控制流程)
1、音频硬件连接如下所示:
McBsp是DM3730上的一个多通道缓冲串行端口,这里音频驱动使用了其中的模块2。音频数据从McBsp2输出,TPS659XX将其解码后输出模拟信号到喇叭。
在wince下音频驱动有3种模式:1.MDD/PDD模式.2.Wavedev2模式.3.UAM模式。我的代码中音频驱动是分为两层的,一层是与硬件无关的驱动tps659xx_wave.dll(WAV层),另一层是与硬件相关的驱动omap_mcbsp.dll(MCP),这两个驱动都是标准的流接口驱动。
2、tps659xx_wave.dll的流接口函数在Wavemain.cpp中,如下所示:
这几个函数名是微软统一的音频驱动接口,wince系统通过这几个函数来实现音频的各种功能。其中最重要的是WAV_IOControl(),系统调用WAV_IOControl()并通过PMMDRV_MESSAGE_PARAMS结构体的uMsg成员传入各种命令来控制音频驱动,所以驱动中需要实现这些命令各自对应的功能。
对于音频输出的命令主要有(并没有全部列出,在vs2008的help文档可看到全部命令的详解)
WODM_OPEN:请求音频驱动创建一个指定设备的实例
WODM_CLOSE:关闭由WODM_OPEN所创建的指定设备的实例
WODM_PAUSE:暂停音频输出
WODM_RESTART:继续音频输出
WODM_WRITE:向指定设备写入波形数据块
WODM_SETVOLUME:设置音量
WODM_GETPOS:获取当前音频播放位置
以下是加载tps659xx_wave.dll驱动,并发出一次触摸屏声音时所打印的信息。
加载dll时打印的信息
PID:00400002 TID:01F7000EWAV:WIDM_GETNUMDEVS
PID:00400002 TID:01F7000E WAV:WIDM_SETPROP
PID:00400002 TID:01F7000EWAV:WODM_GETNUMDEVS
PID:00400002 TID:01F7000EWAV:WODM_GETEXTDEVCAPS
PID:00400002 TID:01F7000E WAV:WODM_SETPROP
PID:00400002 TID:01F7000EWAV:WODM_SETVOLUME
PID:00400002 TID:01F7000EWAV:+process_MixerMessage()
PID:00400002 TID:01F7000EWAV:MXDM_GETNUMDEVS
PID:00400002 TID:01F7000EWAV:-process_MixerMessage()
点击screen一次打印的信息
PID:00400002 TID:074A3C5A WAV:WODM_OPEN
PID:00400002 TID:074A3C5A WAV:WODM_PAUSE
PID:00400002 TID:074A3C5A WAV:WODM_WRITE
PID:00400002 TID:074A3C5A WAV:WODM_WRITE
PID:00400002 TID:074A3C5A WAV:WODM_WRITE
PID:00400002 TID:074A3C5A WAV:WODM_WRITE
PID:00400002 TID:074A3C5A WAV:WODM_RESTART
PID:00400002 TID:0769001A WAV:WODM_WRITE
PID:00400002 TID:0769001A WAV:WODM_WRITE
PID:00400002 TID:0769001A WAV:WODM_WRITE
PID:00400002 TID:0769001A WAV:WODM_WRITE
PID:00400002 TID:0769001A WAV:WODM_WRITE
PID:00400002 TID:0769001A WAV:WODM_PAUSE
PID:00400002 TID:0769001A WAV: WODM_CLOSE
每次发出一段声音时,流程都与此类似,唯有WODM_WRITE次数不一样(声音数据大小有关)。
3、omap_mcbsp.dll驱动主要是对McBsp模块直接进行初始化和操作,接口函数为:
CopyTransferInfo():在这个函数中会相互交换MCP驱动和WAV驱动的一些接口函数指针,这样这两个驱动就能通过这些函数指针调用对方的接口函数了。
TxCommand():当系统给WAV层传入WODM_RESTART和WODM_PAUSE命令时,WAV层就会调用这个函数,并通过这个函数来调用StartTransmit()和StopTransmit()来开启或者关闭MCP层的DMA音频数据传输。
StartTransmit():用于开启MCP层的第一次DMA数据传输,
ST_TxDMA():与StartTransmit()函数一样,用于开启MCP层的DMA数据传输。不同的是IST_TxDMA()是线程函数,这个线程在MCP_Init()中被创建,它会等待DMA数据传输完成中断,然后开启下一次DMA传输。这就解释了,为什么只要发送一次WODM_RESTART命令(只执行一次StartTransmit()函数),音频数据就能一段一段的被McBsp2发送出去。
4、音频数据的输出传递
我们知道系统通过WODM_WRITE命令将音频数据一段一段的传输到WAV层,WAV层再将这些音频数据传输到MCP层,MCP层将这些数据通过McBsp2发送给解码器。那么音频数据具体是怎么存储怎么传递的呢?实际上音频数据采用的是先进先出的队列(单链表结构)存储方式,数据由WAV层入队,由MCP层出队。
在WAV层使用了3个指针来管理这个链表:m_lpWaveHdrHead、m_lpWaveHdrCureent、m_lpWaveHdrTail,分别指向了链表头单元、当前单元、链表尾单元。假设当前系统将data5数据块传输到WAV层,WAV层就会将这个data5插入队尾,此时m_lpWaveHdrTail就会指向这个data5数据块。当MCP层需要获取音频数据时(执行StartTransmit和ST_TxDMA这两个函数时),就会调用WAV层的接口函数(在CopyTransferInfo()函数中获取的)从这个队列的头部获取数据块,然后m_lpWaveHdrHead和m_lpWaveHdrCureent指针会指向队列中的下一个数据块。