当前位置: 首页 > news >正文

绍兴网站制作套餐百度免费安装

绍兴网站制作套餐,百度免费安装,网站开发 前端 外包,物流专线网站建设Waveform Audio 驱动(Wavedev2)之#xff1a;WAV 驱动解析 上篇文章中#xff0c;我们模拟了WAV API。现在进入我们正在要解析的Wave 驱动的架构。我们了解一个驱动的时候#xff0c;先不去看具体跟硬件操作相关的东西#xff0c;而是从流程入手#xff0c;把整个流程搞清…Waveform Audio 驱动(Wavedev2)之WAV 驱动解析 上篇文章中我们模拟了WAV API。现在进入我们正在要解析的Wave 驱动的架构。我们了解一个驱动的时候先不去看具体跟硬件操作相关的东西而是从流程入手把整个流程搞清楚了调试起来就非常的容易了。我们着重看 hwctxt.cpp,hwctxt.Hdevctxt.cpp,devctxt.H,strmctxt.cpp,strmctxt.H这几个源文件。 其中hwctxt是类HardwareContext代码文件devctxt是DeviceContext代码文件strmctxt是 StreamContext代码文件。这几个类的其他一些功能还在其他一些文件中实现如output.Cppmidistrm.Cpp等。 现在我们来看下StreamContext的类图StreamContext是管理音频流的对象包括播放、暂停、停止、设置音量、获取播放位置等。从 下面的StreamContext的类图中我们可以看到它派生了WaveStreamContext和MidiStream。然后 WaveStreamContext又派生了Input和Output类型的Stream。不用说也可以知道InputStreamContext是针对 于像麦克这种输入设备流的。 StreamContext类图 其中OutputStreamContext派生了六个类M代表单音道S代表的是立体音8/16是8/16比特采样了。 SPDIFSONY/PHILIPS DIGITAL INTERFACE是一种最新的音频传输格式它通过光纤进行数字音频信号传输以取代传统的模拟信号传输方式因此可以取得更高质量的音质效果。 StreamContext是一个管理音频数据流的对象像智能手机中可能存在用media player播放音乐同时又开着FM突然又来电。从上篇文章中我们知道要想调用wave驱动的播放功能每个应用都有一份 StreamContext对象上面提到的状况就会有三个StreamContext对象被创建。 在硬件只要一个的条件下那么这三个StreamContext是如果协同工作的呢而DeviceContext正是管理StreamContext对 象的。 如下是DeviceContext类图 DeviceContext类图 DeviceContext派生出InputDeviceContext和OutputDeviceContext他们分别管理 InputStreamContext和OutputStreamContext。在DeviceContext内部维护了一个双向链表来管理 StreamContext。 HardwareContext是具体操作硬件相关的类其内部包含InputDeviceContext和OutputDeviceContext对象下面这种图就是三个类的关系图一看就知道他们的对应关系了。 DeivceContext和StreamContext关系图 对于HardwareContext是具体操作硬件的东西不具有代码性只要仔细看看代码就行了。现在我们主要分析下DeviceContext和StreamContext的关系。 DeviceContext的作用是管理StreamContext可以分为几套函数,见Devctxt.h, Devctxt.cpp 音量增益管理下面这个函数主要是设置设备的整个音量增益设置了设备音量增益后对流音量的增益起了限制做用的。 音量函数如下 view plain copy to clipboard print ? DWORD  GetGain();   DWORD  SetGain( DWORD  dwGain);   DWORD  GetDefaultStreamGain();   DWORD  SetDefaultStreamGain( DWORD  dwGain);   DWORD  GetSecondaryGainLimit( DWORD  GainClass);   DWORD  SetSecondaryGainLimit( DWORD  GainClass,  DWORD  Limit);   DWORD GetGain(); DWORD SetGain(DWORD dwGain); DWORD GetDefaultStreamGain(); DWORD SetDefaultStreamGain(DWORD dwGain); DWORD GetSecondaryGainLimit(DWORD GainClass); DWORD SetSecondaryGainLimit(DWORD GainClass, DWORD Limit); 先来讲下设备音量增益(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分支我在代码中去掉了不重要的部分可以看得更清晰些。 view plain copy to clipboard print ? case  WODM_SETVOLUME:   {       StreamContext *pStreamContext;       pStreamContext  (StreamContext *) dwUser;          LONG  dwGain  dwParam1;       if  (pStreamContext)       {           dwRet  pStreamContext-SetGain(dwGain);       }       else        {           DeviceContext *pDeviceContext  g_pHWContext-GetOutputDeviceContext(uDeviceId);           dwRet  pDeviceContext-SetGain(dwGain);       }   }   case WODM_SETVOLUME: { StreamContext *pStreamContext; pStreamContext (StreamContext *) dwUser; LONG dwGain 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函数代码如下 view plain copy to clipboard print ? DWORD  SetGain( DWORD  dwGain)       {           m_dwGain  dwGain;           RecalcAllGains();           return  MMSYSERR_NOERROR;       }   DWORD SetGain(DWORD dwGain) { m_dwGain dwGain; RecalcAllGains(); return MMSYSERR_NOERROR; } 用m_dwGain保存设备音量然后调用RecalcAllGains来重新计算所有StreamContext的音量增益。 在Devctxt.cpp中的RecalcAllGains的实现如下 view plain copy to clipboard print ? void  DeviceContext::RecalcAllGains()   {       PLIST_ENTRY pListEntry;       StreamContext *pStreamContext;          for  (pListEntry  m_StreamList.Flink;           pListEntry ! m_StreamList;           pListEntry  pListEntry-Flink)       {           pStreamContext  CONTAINING_RECORD(pListEntry,StreamContext,m_Link);           pStreamContext-GainChange();       }       return ;   }   void DeviceContext::RecalcAllGains() { PLIST_ENTRY pListEntry; 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的实现 view plain copy to clipboard print ? void  GainChange()      {          m_fxpGain  MapGain(m_dwGain);   }   DWORD  StreamContext::MapGain( DWORD  Gain)   {       DWORD  TotalGain  Gain  0xFFFF;       DWORD  SecondaryGain  m_pDeviceContext-GetSecondaryGainLimit(m_SecondaryGainClass)  0xFFFF;       if  (m_SecondaryGainClass  SECONDARYDEVICEGAINCLASSMAX)       {           // Apply device gain            DWORD  DeviceGain  m_pDeviceContext-GetGain()  0xFFFF;           TotalGain * DeviceGain;           TotalGain  0xFFFF;  // Round up            TotalGain  16;     // Shift to lowest 16 bits        }          // Apply secondary gain        TotalGain * SecondaryGain;       TotalGain  0xFFFF;  // Round up        TotalGain  16;     // Shift to lowest 16 bits           // Special case 0 as totally muted        if  (TotalGain0)       {           return  0;       }          // Convert to index into table        DWORD  Index  63 - (TotalGain10);       return  GainMap[Index];   }   void GainChange() { m_fxpGain MapGain(m_dwGain); } DWORD StreamContext::MapGain(DWORD Gain) { DWORD TotalGain Gain 0xFFFF; DWORD SecondaryGain m_pDeviceContext-GetSecondaryGainLimit(m_SecondaryGainClass) 0xFFFF; if (m_SecondaryGainClass SECONDARYDEVICEGAINCLASSMAX) { // Apply device gain DWORD DeviceGain m_pDeviceContext-GetGain() 0xFFFF; TotalGain * DeviceGain; TotalGain 0xFFFF; // Round up TotalGain 16; // Shift to lowest 16 bits } // Apply secondary gain TotalGain * SecondaryGain; TotalGain 0xFFFF; // Round up TotalGain 16; // Shift to lowest 16 bits // Special case 0 as totally muted if (TotalGain0) { return 0; } // Convert to index into table DWORD Index 63 - (TotalGain10); return GainMap[Index]; } 音量在系统中用一个DWORD值来表示其高低两个字节分别来表示左右声道一般情况下左声道和右声道的音量大小是一样的所以只取其低两个字节DWORD TotalGain Gain 0xFFFF; TotalGain是DeviceGain和m_dwGain的乘机然后再左移16位得到的。其实就是 TotalGainDeviceGain*m_dwGain/最高音量如果把DeviceGain/最高音量用百分比来算的话就很更容易理解了 那么最后的公式就变成TotalGainDeviceGain*系统音量百分比。那么这里就解释了系统音量是如何限制流音量的疑问。 我们设置好音量增益后最终会再哪里体现呢首先看一下Output.cpp文件WaveStreamContext::Render之后的数据 就是直接发送到外部声音芯片的数据他根据参数以及标志位选择OutputStreamContextXXX::Render2XXX表示双声道S单声 道Mbit位是8位还是16位。以双声道OutputStreamContextS16::Render2为例BSP里面的代码如下 view plain copy to clipboard print ? PBYTE  OutputStreamContextS16::Render2( PBYTE  pBuffer,  PBYTE  pBufferEnd,  PBYTE  pBufferLast)   {       LONG  CurrT  m_CurrT;       LONG  DeltaT  m_DeltaT;       LONG  CurrSamp0  m_CurrSamp[0];       LONG  PrevSamp0  m_PrevSamp[0];       PBYTE  pCurrData  m_lpCurrData;       PBYTE  pCurrDataEnd  m_lpCurrDataEnd;       LONG  fxpGain  m_fxpGain;       LONG  OutSamp0;          __try        {           while  (pBuffer  pBufferEnd)           {               while  (CurrT  0x100)               {                   if  (pCurrDatapCurrDataEnd)                   {                       goto  Exit;                   }                   CurrT - 0x100;                   PrevSamp0  CurrSamp0;                   PPCM_SAMPLE pSampleSrc  (PPCM_SAMPLE)pCurrData;                   CurrSamp0   (LONG )pSampleSrc-s16.sample_left;                   CurrSamp0  (LONG )pSampleSrc-s16.sample_right;                   CurrSamp0  CurrSamp01;                   pCurrData4;               }               OutSamp0  PrevSamp0  (((CurrSamp0 - PrevSamp0) * CurrT)  8);               // 设置增益                OutSamp0  (OutSamp0 * fxpGain)  VOLSHIFT;               CurrT  DeltaT;                      if  (pBuffer  pBufferLast)               {                   OutSamp0  *(HWSAMPLE *)pBuffer;               }               *(HWSAMPLE *)pBuffer  (HWSAMPLE)OutSamp0;               pBuffer  sizeof (HWSAMPLE);              }       }//end the __try block        __except (EXCEPTION_EXECUTE_HANDLER)       {           RETAILMSG(1, (TEXT(InputStreamContext::Render2!/r/n )));           m_lpCurrData  m_lpCurrDataEnd  NULL;             return  NULL;       }   Exit:       m_dwByteCount  (pCurrData - m_lpCurrData);       m_lpCurrData  pCurrData;       m_CurrT  CurrT;       m_PrevSamp[0]  PrevSamp0;       m_CurrSamp[0]  CurrSamp0;       return  pBuffer;       }   PBYTE OutputStreamContextS16::Render2(PBYTE pBuffer, PBYTE pBufferEnd, PBYTE pBufferLast) { LONG CurrT m_CurrT; LONG DeltaT m_DeltaT; LONG CurrSamp0 m_CurrSamp[0]; LONG PrevSamp0 m_PrevSamp[0]; PBYTE pCurrData m_lpCurrData; PBYTE pCurrDataEnd m_lpCurrDataEnd; LONG fxpGain m_fxpGain; LONG OutSamp0; __try { while (pBuffer pBufferEnd) { while (CurrT 0x100) { if (pCurrDatapCurrDataEnd) { goto Exit; } CurrT - 0x100; PrevSamp0 CurrSamp0; PPCM_SAMPLE pSampleSrc (PPCM_SAMPLE)pCurrData; CurrSamp0 (LONG)pSampleSrc-s16.sample_left; CurrSamp0 (LONG)pSampleSrc-s16.sample_right; CurrSamp0 CurrSamp01; pCurrData4; } OutSamp0 PrevSamp0 (((CurrSamp0 - PrevSamp0) * CurrT) 8); // 设置增益 OutSamp0 (OutSamp0 * fxpGain) VOLSHIFT; CurrT DeltaT; if (pBuffer pBufferLast) { OutSamp0 *(HWSAMPLE *)pBuffer; } *(HWSAMPLE *)pBuffer (HWSAMPLE)OutSamp0; pBuffer sizeof(HWSAMPLE); } }//end the __try block __except (EXCEPTION_EXECUTE_HANDLER) { RETAILMSG(1, (TEXT(InputStreamContext::Render2!/r/n))); m_lpCurrData m_lpCurrDataEnd NULL; return NULL; } Exit: m_dwByteCount (pCurrData - m_lpCurrData); m_lpCurrData pCurrData; m_CurrT CurrT; m_PrevSamp[0] PrevSamp0; m_CurrSamp[0] CurrSamp0; return pBuffer; } 从上面看到是与采样数据相乘然后在左移16位。跟上面提到的系统音量影响流音量是一样的。 上面讲了DeviceContext的音量增益管理现在来看下它的流管理。 StreamContext流管理主要来管理StreamContext的创建、删除、渲染、传输等功能。 主要有如下几个函数 view plain copy to clipboard print ? StreamContext *CreateStream(LPWAVEOPENDESC lpWOD);   DWORD  OpenStream(LPWAVEOPENDESC lpWOD,  DWORD  dwFlags, StreamContext **ppStreamContext);   HRESULT  Open(DeviceContext *pDeviceContext, LPWAVEOPENDESC lpWOD,  DWORD  dwFlags);   void  NewStream(StreamContext *pStreamContext);   void  DeleteStream(StreamContext *pStreamContext);   void  StreamReadyToRender(StreamContext *pStreamContext);   PBYTE  TransferBuffer( PBYTE  pBuffer,  PBYTE  pBufferEnd,  DWORD  *pNumStreams,  BOOL  bMuteFlag);   StreamContext *CreateStream(LPWAVEOPENDESC lpWOD); DWORD OpenStream(LPWAVEOPENDESC lpWOD, DWORD dwFlags, StreamContext **ppStreamContext); HRESULT Open(DeviceContext *pDeviceContext, LPWAVEOPENDESC lpWOD, DWORD dwFlags); void NewStream(StreamContext *pStreamContext); void DeleteStream(StreamContext *pStreamContext); void StreamReadyToRender(StreamContext *pStreamContext); PBYTE TransferBuffer(PBYTE pBuffer, PBYTE pBufferEnd, DWORD *pNumStreams, BOOL bMuteFlag); 在DeviceContext中有个m_StreamList的双向链表(LIST_ENTRY), m_StreamList用来指向链表的头。在StreamConext中也存在一个m_Link(LIST_ENTRY)。StreamContext 是调用DeviceContext的OpenStream来创建的然后把StreamContext对象加入到DeviceContext的 m_StreamList中。我们从代码中去直接分析 上层调用waveoutOpen在wavedev2中会调用WODM_OPEN这个分支。在WODM_OPEN中的代码如下 view plain copy to clipboard print ? case  WODM_OPEN:   {       StreamContext *pStreamContext;       pStreamContext  (StreamContext *) dwUser;       dwRet  pDeviceContext-OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)pStreamContext);       break ;   }   case WODM_OPEN: { StreamContext *pStreamContext; pStreamContext (StreamContext *) dwUser; dwRet pDeviceContext-OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)pStreamContext); break; } OpenStream的其流程图如下 StreamContext 初始化流程 CreateStream是根据WAVEFORMATEX这个结构体来判断具体要创建StreamContext的哪个派生类下面是CreateStream的流程图不可不提还是流程图清晰。 OutputDeviceContext:: CreateStream流程图 上面讲了上层通过WODM_OPEN创建一个StreamContext的过程那么音频流被打开之后接下来就是给StreamContext传 入音频数据开始播放音乐。Wavedev2提供了WODM_WRITE来向音频设置写入数据。我们先看下WODM_WRITE分支的代码 view plain copy to clipboard print ? case  WODM_WRITE:   {       StreamContext *pStreamContext;       pStreamContext  (StreamContext *) dwUser;       dwRet  pStreamContext-QueueBuffer((LPWAVEHDR)dwParam1);       break ;   }   case WODM_WRITE: { StreamContext *pStreamContext; pStreamContext (StreamContext *) dwUser; dwRet pStreamContext-QueueBuffer((LPWAVEHDR)dwParam1); break; } 这里调用了StreamContext中的QueueBufferQueueBuffer的作用就是把WAVEHDR中的数据加入到StreamContext的队列中等待播放。下面是QueueBuffer的流程图 QueueBuffer流程图 在QueueBuffer中调用DeviceContext中的StreamReadyToReander通知可以开始渲染了流程图中的箭头方向 是StreamReadyToReander调用流程最终调用SetEvent(hOutputIntEvent)来通知线程数据已经准备好得到通 知后就开始播放了。该线程在HardwareContext中的OutputInterruptThread函数中 OutputInterruptThread流程如下 结尾时想起大学教育的一个问题居然不学语文了。见别人写的文章文采飞扬而我的确是很僵硬风趣和文采都不足。 还是老话本人才疏学浅有错误之处请更正。
http://www.pierceye.com/news/936539/

相关文章:

  • 可信网站认证哪里有网站建设分金手指排名一
  • 十大品牌网站建设专业网站的利弊
  • 如何查看网站域名360seo
  • 苏州网站设计kgwl手机网站全屏代码
  • 网站开发工程师就业前景免费企业网站模板
  • 网站建设额企业建设网站对客户的好处
  • 济南网站制作设计公司WordPress文章相册修改
  • 购物网站建设思维导构图电商平台建设方案
  • 一个网站一年的费用多少惠州网站制作哪里好
  • 网站界面设计材料收集国内外包网站
  • 自如网站做的好 服务网站开发实训
  • 档案网站建设的意义网页制作工具可以分为
  • 网站建设价格是哪些方面决定的wordpress32m
  • 建设公司网站哪家好网站建设 中企动力洛阳分公司
  • 如何做自己的大淘客网站开公司建网站
  • 在线网站设计工具腾讯做的电子商务网站
  • 重庆建设工程证照查询网站东莞松山湖
  • 唐山市政建设总公司网站南阳网站推广招聘
  • wordpress搭建网站网站建立网络优化
  • 杭州住房和城乡建设部网站东莞常平粤海水务
  • 网站设计方案案例yw55516can优物入口
  • 重庆有哪些做网站公司好丹东 建设集团 招聘信息网站
  • 深圳高端网站建设建设凡科网站
  • 类似织梦的建站cms百度广州分公司待遇
  • 仿qq商城版淘宝客网站源码模板+带程序后台文章dede织梦企业程序上海专业制作网页
  • 网站建设服务8合肥网红打卡地
  • 网站按关键词显示广告图片如何在本地搭建网站
  • 安徽网站建设认准-晨飞网络域名和网站建设
  • 上海人才网最新招聘信息官方网站互联网软件
  • 网站备案审核流程图长治专业做网站