解析的Wave 驱动的构架。我们知道一个驱动的之后,先不去看详细跟软件操作相关的东西,而是从步骤入手,把整个流程搞清楚了,调试出来就比较的容易了。我们着重看hwctxt.cpp,hwctxt.H,devctxt.cpp,devctxt.H,strmctxt.cpp,strmctxt.H这几个源文件。其中hwctxt是类HardwareContext代码文件,devctxt是DeviceContext代码文件,strmctxt是StreamContext代码文件。这几个类的其他一些用途,还在其他一些文件中推动,如output.Cpp,midistrm.Cpp等。
现在我们来看下StreamContext的类图,StreamContext是管理音频流的对象,包括播放、暂停、停止、设置音量、获取播放位置等。从下边的StreamContext的类图中,我们可以提到它派生了WaveStreamContext和MidiStream。然后WaveStreamContext又派生了Input和Output类型的Stream。不用说也可以明白InputStreamContext是针对于像麦克这种输入设备流的。
![wps_clip_image-597[4]](http://hi.csdn.net/attachment/201004/25/0_1272211051ua4V.gif)
StreamContext类图
其中OutputStreamContext派生了六个类,M代表单音道,S代表的是立体音,8/16是8/16比特采样了。 SPDIF(SONY/PHILIPS DIGITAL INTERFACE)是一种最新的音频存储格式,它借助光纤进行数字音频信号存储以替代传统的模拟信号传输方法,因此可以取得更高质量的性能效果。
StreamContext是一个管理音频数据流的对象,像智能电脑中可能存在用media player播放音乐,同时又开着FM,突然又来电。从前言文章中我们明白,要想读取wave驱动的播放功能,每个应用都有一份StreamContext对象,上面讲到的情况,就会有三个StreamContext对象被建立。 在硬件只要一个的条件下,那么这三个StreamContext是如若协同工作的呢?而DeviceContext正是管理StreamContext对象的。
如下是DeviceContext类图:
![wps_clip_image-1047[4]](http://hi.csdn.net/attachment/201004/25/0_1272211051ZRaT.gif)
DeviceContext类图
DeviceContext派生出InputDeviceContext和OutputDeviceContext,他们分别管理InputStreamContext和OutputStreamContext。在DeviceContext内部维护了一个双向链表来管控StreamContext。
HardwareContext是详细操作软件相关的类,其外部包括InputDeviceContext和OutputDeviceContext对象wince6.0 音乐播放器,下面这种图,就是三个类的关系图,一看就明白人们的对应关系了。
![wps_clip_image-1339[4]](http://hi.csdn.net/attachment/201004/25/0_1272211052h220.gif)
DeivceContext和StreamContext关系图
对于HardwareContext是详细操作软件的东西,不具备代码性,只要认真说说代码就行了。现在我们主要剖析下DeviceContext和StreamContext的关系。
DeviceContext的作用是管理StreamContext,可以分为几套函数,见Devctxt.h, Devctxt.cpp
音量增益管理:下面这个变量主要是设定设备的整个音量增益,设置了设施音量增益后,对流音量的增益起了限制做用的。
音量函数如下
DWORDGetGain();DWORDSetGain(DWORDdwGain);DWORDGetDefaultStreamGain();DWORDSetDefaultStreamGain(DWORDdwGain);DWORDGetSecondaryGainLimit(DWORDGainClass);DWORDSetSecondaryGainLimit(DWORDGainClass,DWORDLimit);
先来讲下设备噪音增益(Device Gain)和流音量增益(Stream Gain)的关系。我们从微软Media Player中,很容易就听到了设备噪音和流音量的关系。设备音量时借助音量键来控制平台的音量,从而改变整个输出设备的音量的,但是在Media Player中,还是有一个单独的亮度控制按键,它能调节Media Player的噪音(不要问我在哪里,自己找),但是安装它是受限制于平台音量,是能否限制,请看下边讲解。
我们今天看下设定系统音量和更改流音量的整个步骤,来知道整个音量控制的过程。用户设定时,会读取waveOutSetVolume
MMRESULT waveOutSetVolume(
HWAVEOUT hwo,
DWORD dwVolume
);
当HWAVEOUT传入为空时,设置的就是设备音量,当HWAVEOUT是借助读取waveOutOpen返回的键值是,设置的就是流音量。
好,我们步入到驱动中区看看,waveOutSetVolume会调用到来看wavemain.Cpp中HandleWaveMessage的WODM_SETVOLUME分支,我在代码中除去了不重要的个别,可以看得更清晰些。
caseWODM_SETVOLUME:{StreamContext*pStreamContext;pStreamContext=(StreamContext*)dwUser;LONGdwGain=dwParam1;if(pStreamContext){dwRet=pStreamContext->SetGain(dwGain);}else{DeviceContext*pDeviceContext=g_pHWContext->GetOutputDeviceContext(uDeviceId);dwRet=pDeviceContext->SetGain(dwGain);}}
dwUser 指向的是StreamContext对象(在前文中已经讲过),如果pStreamContext为空,那么就读取DeviceContext的SetGain函数,否则调用StreamContext的SetGain函数。调用StreamContext的Gain只对当前的StreamContext的音量起作用,不妨碍其他的Stream音量。但是对DeviceContext设置音量增益是对DeviceContext管理的所有StreamContext起了控制作用,但是确切是能否影响的,还是依照代码来剖析:

在Devctxt.h中的SetGain函数代码如下
DWORDSetGain(DWORDdwGain){m_dwGain=dwGain;RecalcAllGains();returnMMSYSERR_NOERROR;}
用m_dwGain保存设备音量,然后读取RecalcAllGains来重新计算所有StreamContext的亮度增益。
在Devctxt.cpp中的RecalcAllGains的实现如下
voidDeviceContext::RecalcAllGains(){PLIST_ENTRYpListEntry;StreamContext*pStreamContext;for(pListEntry=m_StreamList.Flink;pListEntry!=&m_StreamList;pListEntry=pListEntry->Flink){pStreamContext=CONTAINING_RECORD(pListEntry,StreamContext,m_Link);pStreamContext->GainChange();}return;}
它便利所有的StreamContext,并调用pStreamContext->GainChange()来改变StreamContext对象的音量。接着看StreamContext类中的GainChange的实现
voidGainChange(){m_fxpGain=MapGain(m_dwGain);}DWORDStreamContext::MapGain(DWORDGain){DWORDTotalGain=Gain&0xFFFF;DWORDSecondaryGain=m_pDeviceContext->GetSecondaryGainLimit(m_SecondaryGainClass)&0xFFFF;if(m_SecondaryGainClass<SECONDARYDEVICEGAINCLASSMAX){//ApplydevicegainDWORDDeviceGain=m_pDeviceContext->GetGain()&0xFFFF;TotalGain*=DeviceGain;TotalGain+=0xFFFF;//RoundupTotalGain>>=16;//Shifttolowest16bits}//ApplysecondarygainTotalGain*=SecondaryGain;TotalGain+=0xFFFF;//RoundupTotalGain>>=16;//Shifttolowest16bits//Specialcase0astotallymutedif(TotalGain==0){return0;}//ConverttoindexintotableDWORDIndex=63-(TotalGain>>10);returnGainMap[Index];}
音量在系统中用一个DWORD值来表示,其高低两个字节分别来表示左右声道,一般状况下左声道和右声道的音量大小是一样的,所以只取其低两个字节,DWORD TotalGain = Gain & 0xFFFF;
TotalGain是DeviceGain和m_dwGain的乘机,然后再左移16位得到的。其实就是TotalGain=DeviceGain*m_dwGain/最高音量,如果把DeviceGain/最高音量,用百分比来算的话,就很更容易理解了,那么最终的推导就变成TotalGain=DeviceGain*系统音量百分比。那么这里就解释了平台音量是能否限制流音量的问题。
我们设定好音量增益后,最终会再哪里表现呢:首先看一下Output.cpp文件,WaveStreamContext::Render之后的数据就是直接发送到内部声音芯片的数据,他依据参数以及标志位选择OutputStreamContextXXX::Render2,XXX表示双声道S单声道M,bit位是8位还是16位。以双声道OutputStreamContextS16::Render2为例,BSP里面的代码如下:
PBYTEOutputStreamContextS16::Render2(PBYTEpBuffer,PBYTEpBufferEnd,PBYTEpBufferLast){LONGCurrT=m_CurrT;LONGDeltaT=m_DeltaT;LONGCurrSamp0=m_CurrSamp[0];LONGPrevSamp0=m_PrevSamp[0];PBYTEpCurrData=m_lpCurrData;PBYTEpCurrDataEnd=m_lpCurrDataEnd;LONGfxpGain=m_fxpGain;LONGOutSamp0;__try{while(pBuffer<pBufferEnd){while(CurrT>=0x100){if(pCurrData>=pCurrDataEnd){gotoExit;}CurrT-=0x100;PrevSamp0=CurrSamp0;PPCM_SAMPLEpSampleSrc=(PPCM_SAMPLE)pCurrData;CurrSamp0=(LONG)pSampleSrc->s16。sample_left;CurrSamp0+=(LONG)pSampleSrc->s16。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-120037-1.html
有实战意义