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

炽乐清网站建设广州推广优化

炽乐清网站建设,广州推广优化,昆山网站建设公司,wordpress优惠券发放插件Waveform Audio 驱动(Wavedev2)之#xff1a;WAV API模拟 Waveform 驱动对Windows Mobile来说是一个非常重要的驱动#xff0c;控制着所有有关声音的操作#xff0c;包括喇叭、耳机、麦克、听筒等。 要 想对驱动的整个架构和流程都非常的了解#xff0c;我们必须从…Waveform Audio  驱动(Wavedev2)之WAV API模拟 Waveform 驱动对Windows Mobile来说是一个非常重要的驱动控制着所有有关声音的操作包括喇叭、耳机、麦克、听筒等。     要 想对驱动的整个架构和流程都非常的了解我们必须从上层来入手需要知道上层的API是如何调用到驱动的其数据结构是如何封装的。由于微软不提供中间层 的代码只能只是自己去猜测。这篇文章就是去模仿WAV API的实现方法的。顺便提及下之前几个开发人员还讨论过微软的半开放模式和Android的 完全开源模式哪个更好。先做个总结。 完全开源优点: 1.  添 加新功能容易比如做Android双卡双待就比Windows Mobile容易的多之前做Windows Mobile双卡的项目时那真是非常的 痛苦微软没有接口只能自己想尽一起方法往微软原有的程序中去插入新的功能想COM接口Dll注入窗口Hook等等能用的变态方法都用上了。花 的时间的很大部分都是在寻找插入功能的方法上而不是实现另一张卡的功能上。而Android就十分简单了直接在原有的代码上增加代码就行。 2.  开发人员很容易了解整个架构和流程 微软的半开放模式优点 1.  易 维护: 由于微软的中间层都是以dll形式封装好的开发人员不能去修改只能按照微软的接口去做当微软从Windows Mobile 5.0升级到 Windows Mobile 6.0的时候BSP不需要做任何修改就可以在新的系统上用软件也是如此。而Android的完全开源模式开发人员会 去修改中间层Android的版本号从1.5,1.6,2.0再到2.1不断的进行升级其中间层也在改变中添加了某些功能优化了某些部分。像我 们公司做Android的从1.5升级到1.6就花了很长的时间。不仅驱动要修改应用也都需要做修改。 先不谈这个回到正题。 微软上层的WAV API分为waveOut和waveIn两套表一中我只列了部分的wave out API。由于wave In相对于wave Out比较简单wave In就不做讲解了。 waveOutGetNumDevs   Retrieves the number of waveform output devices present in the system. waveOutGetPitch   Queries the current pitch setting of a waveform output device. waveOutGetPlaybackRate   Queries the current playback rate setting of a waveform output device. waveOutGetPosition   Retrieves the current playback position of the specified waveform output device. waveOutGetProperty   Queries the value of a specific property in a property set for waveform audio output. waveOutGetVolume   Queries the current volume setting of a waveform output device. waveOutMessage   Sends messages to the waveform output device drivers. waveOutOpen   Opens a specified waveform output device for playback. 表一WaveOut部分函数 W ave Out API是如何调用的驱动部分的呢现在就来一步步的模拟来实现wave Out API。先看下waveOutOpen的函数参数 view plain copy to clipboard print ? MMRESULT waveOutOpen(     LPHWAVEOUT phwo,     UINT  uDeviceID,     LPWAVEFORMATEX pwfx,     DWORD  dwCallback,     DWORD  dwInstance,     DWORD  fdwOpen      );   MMRESULT waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen ); 其中phwo是我们要返回的WAVEOUT对象的句柄 uDeviceID 指设置的ID号一般情况下设置为0就可以pwfx是声音格式的描述dwCallback的通知可以是回调函数也可以是事件或者窗体消息主要通过fdwOpen来指定其类型。具体看waveOutOpen的SDK帮助文档。 在WaveApi中的工作就是把waveOutOpen中的参数封装起来然后发到Wave驱动中想要的结构下面是waveOutOpen的调用流程。 1.  W ave Api中封装结构 2.  调用Wavedev2的  WAV_IOControl 函数调用 IOCTL_WAV_MESSAGE 分支。 3.  调用 HandleWaveMessage 的 WODM_OPEN 分支 HandleWaveMessage 需要传入两个参数其中一个是 PMMDRV_MESSAGE_PARAMS 另一个是函数执行的结果pdwResult,见 HandleWaveMessage 原型和 MMDRV_MESSAGE_PARAMS 结构体定义。 BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult) view plain copy to clipboard print ? BOOL  HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams,  DWORD  *pdwResult)   typedef   struct  {       UINT  uDeviceId;       UINT  uMsg;       DWORD  dwUser;       DWORD  dwParam1;       DWORD  dwParam2;   } MMDRV_MESSAGE_PARAMS, *PMMDRV_MESSAGE_PARAMS;   MMRESULT waveOutMessage(     HWAVEOUT hwo,      UINT  uMsg,      DWORD  dw1,      DWORD  dw2    );    BOOL HandleWaveMessage(PMMDRV_MESSAGE_PARAMS pParams, DWORD *pdwResult) typedef struct { UINT uDeviceId; UINT uMsg; DWORD dwUser; DWORD dwParam1; DWORD dwParam2; } MMDRV_MESSAGE_PARAMS, *PMMDRV_MESSAGE_PARAMS; MMRESULT waveOutMessage( HWAVEOUT hwo, UINT uMsg, DWORD dw1, DWORD dw2 ); 其 中参数dwUser指向Wavedev2驱动的StreamContext对象指针如果调用的是waveOutOpen则dwUser做出传出参数 来保存StreamContext对象否则就是作为传入参数。waveOutMessage的uMsg会传入驱动变成 MDRV_MESSAGE_PARAMS 中的uMsg, 同样的dw1变dwParam1dw2变dwParam2所以的上层调用都是调用 waveOutMessage 这个函数实现的。 好了现在我们来开始显示吧。 HWAVEOUT 要么直接指向对象要么是对象的在数组中的索引。我们只是模拟所以把 HWAVEOUT 直接指向对象。 先定义一个 CWAVEOut 对象来保存必要的数据其他几个参数就不做解释了我们看m_hWave和m_pStreamm_hWave是来保存打开Wave驱动CreateFile返回的句柄而m_pStream是保存创建的StreamContext对象的。 view plain copy to clipboard print ? class  CWAVEOut   {   public :       MMRESULT open();      private :       DWORD  m_dwCallback;       DWORD  m_dwInstance;       UINT  m_uDeviceID;       DWORD  m_fdwOpen;       WAVEFORMATEX m_wfx;       HANDLE  m_hWave;       LPVOID   m_pStream;   };   class CWAVEOut { public: MMRESULT open(); private: DWORD m_dwCallback; DWORD m_dwInstance; UINT m_uDeviceID; DWORD m_fdwOpen; WAVEFORMATEX m_wfx; HANDLE m_hWave; LPVOID m_pStream; }; 好现在我们来模拟 waveOutOpen 的实现。在waveOutOpen中只是新建一个CWAVEOut对象然后把外部传入的数据保存到这个对象中最后调用open来打开音频设备。代码如下 view plain copy to clipboard print ? MMRESULT waveOutOpen(                        LPHWAVEOUT phwo,                        UINT  uDeviceID,                        LPWAVEFORMATEX pwfx,                        DWORD  dwCallback,                        DWORD  dwInstance,                        DWORD  fdwOpen                        )   {       CWAVEOut pWaveOut  new  CWAVEOut;       pWaveOut-m_dwCallback  dwCallback;       pWaveOut-m_fdwOpen  fdwOpen;       pWaveOut-m_wfx  *pwfx;              *pwfx  pWaveOut;              phwo  (LPHWAVEOUT)pWaveOut;       return  pWaveOut-open();   }   MMRESULT waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen ) { CWAVEOut pWaveOut new CWAVEOut; pWaveOut-m_dwCallback dwCallback; pWaveOut-m_fdwOpen fdwOpen; pWaveOut-m_wfx *pwfx; *pwfx pWaveOut; phwo (LPHWAVEOUT)pWaveOut; return pWaveOut-open(); } O pen函数封装 WAVEOPENDESC 作为waveOutMessage的第一个传入参数第二个参数是m_fdwOpen。 view plain copy to clipboard print ? MMRESULT CWAVEOut::open()   {       MMRESULT mmResult;       m_hWave  CreateFile(LWAV1: , GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,            NULL, OPEN_EXISTING, 0, NULL);              WAVEOPENDESC waveOpenDesc;       waveOpenDesc.hWave  HWAVE(this );       waveOpenDesc.lpFormat  m_wfx;       waveOpenDesc.dwInstance  m_dwInstance;       waveOpenDesc.uMappedDeviceID  0;       waveOpenDesc.dwCallback  m_dwCallback;          return  waveOutMessage((HWAVEOUT) this , WODM_OPEN, waveOpenDesc, m_fdwOpen);   }   MMRESULT CWAVEOut::open() { MMRESULT mmResult; m_hWave CreateFile(LWAV1:, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); WAVEOPENDESC waveOpenDesc; waveOpenDesc.hWave HWAVE(this); waveOpenDesc.lpFormat m_wfx; waveOpenDesc.dwInstance m_dwInstance; waveOpenDesc.uMappedDeviceID 0; waveOpenDesc.dwCallback m_dwCallback; return waveOutMessage((HWAVEOUT)this, WODM_OPEN, waveOpenDesc, m_fdwOpen); } waveOutMessage的工作就是只要把uMsg,dw1,dw2封装到 MMDRV_MESSAGE_PARAMS 结构体然后调用 DeviceIoControl 调用驱动的IO Control。这里有一点需要注意如果uMsg是WODM_OPEN也就是打开音频流的操作的时候把 pWaveOut - m_pStream 作为参数传入因为在底层通过调用 OpenStream 传入指针的指针来保存对象的。 pDeviceContext-OpenStream((LPWAVEOPENDESC)dwParam1, dwParam2, (StreamContext **)dwUser); view plain copy to clipboard print ? MMRESULT waveOutMessage(                           HWAVEOUT hwo,                            UINT  uMsg,                            DWORD  dw1,                            DWORD  dw2                            )   {       CWAVEOut * pWaveOut  (CWAVEOut *)hwo;       MMDRV_MESSAGE_PARAMS paramInput;       paramInput.dwParam1  dw1;       paramInput.dwParam2  dw2;              if (WODM_OPEN  uMsg)           paramInput.dwUser  (DWORD )pWaveOut-m_pStream;       else            paramInput.dwUser  (DWORD )pWaveOut-m_pStream;              paramInput.uMsg  uMsg;          MMRESULT    dwOutput  0;              if (!DeviceIoControl(pWaveOut-m_hWave, IOCTL_WAV_MESSAGE, ¶mInput,  sizeof (paramInput), dwOutput,  sizeof (dwOutput), NULL, NULL))       {           return  MMSYSERR_ERROR;       }              return  dwOutput;   }   MMRESULT waveOutMessage( HWAVEOUT hwo, UINT uMsg, DWORD dw1, DWORD dw2 ) { CWAVEOut * pWaveOut (CWAVEOut *)hwo; MMDRV_MESSAGE_PARAMS paramInput; paramInput.dwParam1 dw1; paramInput.dwParam2 dw2; if(WODM_OPEN uMsg) paramInput.dwUser (DWORD)pWaveOut-m_pStream; else paramInput.dwUser (DWORD)pWaveOut-m_pStream; paramInput.uMsg uMsg; MMRESULT dwOutput 0; if(!DeviceIoControl(pWaveOut-m_hWave, IOCTL_WAV_MESSAGE, ¶mInput, sizeof(paramInput), dwOutput, sizeof(dwOutput), NULL, NULL)) { return MMSYSERR_ERROR; } return dwOutput; } 我们现在模拟实现了waveOutMessage,那么其他一些函数的实现要比waveOutOpen更加的简单。如WaveOutReset和 waveOutSetVolume 只要调用下 waveOutMessage 就可以了。 view plain copy to clipboard print ? MMRESULT waveOutReset(                         HWAVEOUT hwo                          )   {       return  waveOutMessage(hwo, WODM_RESET, 0, 0);   }      MMRESULT waveOutSetVolume(                             HWAVEOUT hwo,                              DWORD  dwVolume                              )   {       return  waveOutMessage(hwo, WODM_SETVOLUME, dwVolume, 0);   }   MMRESULT waveOutReset( HWAVEOUT hwo ) { return waveOutMessage(hwo, WODM_RESET, 0, 0); } MMRESULT waveOutSetVolume( HWAVEOUT hwo, DWORD dwVolume ) { return waveOutMessage(hwo, WODM_SETVOLUME, dwVolume, 0); } 对于上层来说只是简单的进行了下封装。当然我的封装里面还没有考虑到具体的一些东西如callback函数是怎么返回的如函数调用是hwo为空是怎么样的也没有对错误进行处理。 下面是播放一个wave声音的函数从代码中去解析 view plain copy to clipboard print ? MMRESULT   PlayFile(LPCTSTR  pszFilename)   { MMRESULT mr;     DWORD  dwBufferSize;     PBYTE  pBufferBits  NULL;     PWAVEFORMATEX pwfx  NULL;     DWORD  dwSlop;     DWORD  dwWait;     DWORD  dwDuration;          HANDLE  hevDone  CreateEvent(NULL, FALSE, FALSE, NULL);       if  (hevDone  NULL) {           return  MMSYSERR_NOMEM;       }          mr  ReadWaveFile(pszFilename,pwfx,dwBufferSize,pBufferBits);       MRCHECK(mr, ReadWaveFile, ERROR_READ);          // Note: Cast to UINT64 below is to avoid potential DWORD overflow for large (~4MB) files.        dwDuration  (DWORD )((( UINT64 )dwBufferSize) * 1000 / pwfx-nAvgBytesPerSec);          HWAVEOUT hwo;       mr  waveOutOpen(hwo, WAVE_MAPPER, pwfx, (DWORD ) hevDone, NULL, CALLBACK_EVENT);       MRCHECK(mr, waveOutOpen, ERROR_OPEN);          WAVEHDR hdr;       memset(hdr, 0, sizeof (hdr));       hdr.dwBufferLength  dwBufferSize;       hdr.lpData  (char  *) pBufferBits;          mr  waveOutPrepareHeader(hwo, hdr, sizeof (hdr));       MRCHECK(mr, waveOutPrepareHeader, ERROR_PLAY);          mr  waveOutWrite(hwo, hdr, sizeof (hdr));       MRCHECK(mr, waveOutWrite, ERROR_PLAY);          // wait for play  1 second slop        dwSlop  1000;       dwWait  WaitForSingleObject(hevDone, dwDuration  dwSlop);       if  (dwWait ! WAIT_OBJECT_0) {           // not much to here, other than issue a warning            RETAILMSG(1, (TEXT(Timeout waiting for playback to complete/r/n )));       }          mr  waveOutUnprepareHeader(hwo, hdr, sizeof (hdr));       MRCHECK(mr, waveOutUnprepareHeader, ERROR_PLAY);      ERROR_PLAY:       mr  waveOutClose(hwo);       MRCHECK(mr, waveOutClose, ERROR_OPEN);      ERROR_OPEN:       delete  [] pBufferBits;       delete  [] pwfx;      ERROR_READ:       CloseHandle(hevDone);       return  mr;   }   MMRESULT PlayFile(LPCTSTR pszFilename) { MMRESULT mr; DWORD dwBufferSize; PBYTE pBufferBits NULL; PWAVEFORMATEX pwfx NULL; DWORD dwSlop; DWORD dwWait; DWORD dwDuration; HANDLE hevDone CreateEvent(NULL, FALSE, FALSE, NULL); if (hevDone NULL) { return MMSYSERR_NOMEM; } mr ReadWaveFile(pszFilename,pwfx,dwBufferSize,pBufferBits); MRCHECK(mr, ReadWaveFile, ERROR_READ); // Note: Cast to UINT64 below is to avoid potential DWORD overflow for large (~4MB) files. dwDuration (DWORD)(((UINT64)dwBufferSize) * 1000 / pwfx-nAvgBytesPerSec); HWAVEOUT hwo; mr waveOutOpen(hwo, WAVE_MAPPER, pwfx, (DWORD) hevDone, NULL, CALLBACK_EVENT); MRCHECK(mr, waveOutOpen, ERROR_OPEN); WAVEHDR hdr; memset(hdr, 0, sizeof(hdr)); hdr.dwBufferLength dwBufferSize; hdr.lpData (char *) pBufferBits; mr waveOutPrepareHeader(hwo, hdr, sizeof(hdr)); MRCHECK(mr, waveOutPrepareHeader, ERROR_PLAY); mr waveOutWrite(hwo, hdr, sizeof(hdr)); MRCHECK(mr, waveOutWrite, ERROR_PLAY); // wait for play 1 second slop dwSlop 1000; dwWait WaitForSingleObject(hevDone, dwDuration dwSlop); if (dwWait ! WAIT_OBJECT_0) { // not much to here, other than issue a warning RETAILMSG(1, (TEXT(Timeout waiting for playback to complete/r/n))); } mr waveOutUnprepareHeader(hwo, hdr, sizeof(hdr)); MRCHECK(mr, waveOutUnprepareHeader, ERROR_PLAY); ERROR_PLAY: mr waveOutClose(hwo); MRCHECK(mr, waveOutClose, ERROR_OPEN); ERROR_OPEN: delete [] pBufferBits; delete [] pwfx; ERROR_READ: CloseHandle(hevDone); return mr; } 先调用waveOutOpen初始化音频流。在调用waveOutPrepareHeader准备好数据头告诉驱动要播放多大的数据在驱动中 waveOutPrepareHeader   调用 WODM_PREPARE 分支一般情况下驱动没有去实现 WODM_PREPARE 直接返回 MMSYSERR_NOTSUPPORTED 。准备好Header后调用waveOutWrite写出buffer。 好了就写到这里如有错误之处请更正。
http://www.yutouwan.com/news/444323/

相关文章:

  • 网站大全免费入口有专门做面包的网站么
  • 我想做个百度网站怎么做的wordpress有没有linux
  • jsp网站开发实例教学网站开发与技术维护
  • wpf做的网站网站怎么添加手机版
  • 关于水果的网站开发天津建设协会网站
  • 网站seo合同图片制作器app
  • 网站建设与 维护实训报告范文wordpress视频弹幕
  • 晚上网站推广软件免费版饿了吗外卖网站怎么做
  • 宁波做网站制作自己做网站需要收费吗
  • 蓝天网站建设营销网站模版
  • 网站开发常用技术东莞最新防控通知
  • 网站建设功能说明书前程无忧网杭州网站建设类岗位
  • 香橼做空机构网站网站的广度
  • 产品型网站案例河南省的网页制作
  • 有企业邮箱案例的网站wordpress非插件幻灯
  • 洱源名师工作室网站建设招代理
  • 优化企业网站公司网站注销
  • 三网合一网站建设费用wordpress七牛加速
  • 网站视频下载软件如何建造网站
  • 创建一个网站的最常用的方法是先建立一个文件夹jsp网站怎么做
  • 在哪些网站上发外链好官网搭建 杭州
  • 销售人员报销网站开发费郑州做网站琴
  • 微信朋友圈做网站推广赚钱吗江苏无锡今天的最新发布消息
  • 网站设计应遵循的原则山西省诚信建设网站
  • 侠客推 网站建设棋牌软件开发多少钱
  • 去哪个网站找题目给孩子做网站建设的比较合理的流程
  • 上海手机网站建设报价网站优化建设山东
  • 企业电器网站建设方案免费软件的定义
  • 十堰网站建设电话搜索引擎优化方案案例
  • 成都建设网站那家好电子商务网站建设预算