微信订阅号二维码
本栏目热门内容
  • 全格式自动改名器 Ver 4.0...
  • mp3的无损版本:mp3HD已经...
  • Ogg Theora 1.0 发布
  • 继Opera之后,Firefox(Ge...
  • Linux 音频 API 指南
  • Module音乐大全
  • 常见疑问(FAQ)
  • WaveCN 教程
  • 发现一个德国人做的音频网...
  • Rockbox Utility介绍及Roc...
  • 基于WaveX低级音频函数的...
  • 最流行的无损压缩格式FLAC...
  • 安装使用WaveCN
  • 音频制作与编辑初级教程节...
  • 如何用WaveCN录制自己的音...
  • Rockbox系列三:关于 Rock...
  • MPEG-4 音频无损编码:MPE...
  • Rockbox 3.0 释出。
  • Rockbox系列一:开源的Roc...
  • 音频文件格式全介绍
  • 音频术语中常见的“采样频...
  • WaveCN 运行截图
  • Windows 播放音频文件音量...
  • 最流行的无损压缩格式FLAC...
  • 来自俄罗斯的无损音频压缩...
  • Graph Editor 教程
  • LA - LosslessAudio 无损...
  • 最流行的无损压缩格式FLAC...
  • Rockbox系列二:Rockbox具...
  • 更多...

    基于WaveX低级音频函数的实时语音通信
    作者:Sender  来源:WaveCN.com  发布日期:2007-04-03  最后修改日期:2008-02-14

    编者注:

      虽然现在Microsoft说Windows低级音频函数已经obsoleted,DirectSound也已经大行其道,但其相对易用的特点还是值 得学习的。本文的另一个特点是作者结合了局域网实时音频传输的课题给出了这些API函数的使用实例,使得全文不仅仅是单纯的API函数使用介绍,从而具有 相当的实用价值。

    未经作者许可,请勿转载!

    1 摘要

    2 背景介绍

    3 相关数据结构

    4 参数设置

    5 基本操作流程

    6 消息及处理

    7 程序结构

    8 网络拥塞控制策略

    9 系统测试

    10 结束语

    附录A  WaveX API

    1 摘要

      本文介绍了基于WaveX低级音频API采集音频及实时播放的技术。并对音频实时性和连 续性作了比较深入的分析。利用双/多缓冲技术和网络拥塞控制策略可很好的控制音频的实时性和连续性。

    2 背景介绍

      WINDOWS下音频的采集,播放有三种模式:

      1)通过高级音频函数、媒体控制接口MCI[12]设备驱 动程序;

      2)低级音频函数MIDI Mapper、低级音频设备驱动(WaveX API);

      3)利用DirectX中的DirectSound

      使用MCI的方法极其简便,灵活性较差;使用低级音频函数的方法相对来说难一点,但是能够对音频数据进行灵活的操 控;而采用DirectSound的方法,控制声音数据灵活,效果比前二者都好,但实现起来是三者中最难的。

      低层音频服务及重要的数据结构低级音频服务控制着不同的音频设备,这些设备包括 WAVE,MIDI和辅助音频设 备。低级音频服务包括如下内容:

      (1)查询音频设备;

      (2)打开和关闭设备驱动程序;

      (3)分配和准备音频数据块;

      (4)管理音频数据块;

      (5)应用MMTIME结构;

      (6)处理错误。

      WaveX低级音频函数的相关声明和定义在mmsystem.h头文件和Winmm.lib库 中。所以如果程序中用到这些函数,必须包含mmsystem.h这个头文件,同时导进Winmm.lib库。 如下:

    #include "mmsystem.h"

    #pragma comment(lib,"Winmm.lib")

      双/多缓冲技术可以很好的实现声音的快速连续采集和实时顺畅播放。采集声音时,缓冲满了会有一个消息,程序在响应这 个消息需要几毫秒~几十毫秒甚至更多的时间,假设为Xms,如果只使用一个缓冲,程序必须在响应完该消息才再次采集声音,那么 在这Xms的时间里,没有采集到任何声音;声音的播放也是一样的道理,这样声音就会不连续。因此双缓冲或多缓冲技术是必要的, 让输入和输出设备可以循环使用这些缓冲,当程序在响应某块缓冲数据已满或播放完毕消息时,声卡可以继续往下一块缓冲添加数据或播放下一块缓冲的数据,如此 循环保障声音的连续性。

    3 相关数据结构

      声音在采集(录音)和播放的时需要有一些统一的格式,包括音频格式类型,声道,采样率等信息。下面的数据结构具体描述了该格式:

    typedef struct tWAVEFORMATEX

    {

        WORD        wFormatTag;

        WORD        nChannels;

        DWORD       nSamplesPerSec;

        DWORD       nAvgBytesPerSec;

        WORD        nBlockAlign;

        WORD        wBitsPerSample;

        WORD        cbSize;

    } WAVEFORMATEX, *PWAVEFORMATEX,

      NEAR *NPWAVEFORMATEX, FAR *LPWAVEFORMATEX;

      其中,wFormatTag是音频格式类型,nChannels是声道数,nSamplesPerSec是 采样频率,nAvgBytesPerSec是每秒钟的字节数,nBlockAlign是每个样本的 字节数,wBitsPerSample是每个样本的量化位数,cbSize是附加信息的字节大小。

      在打开声卡输入和输出设备之前,必须对音频的相关参数进行设置。在后面章节中将给出WAVE_FORMAT_PCM格 式音频的详细参数设置。

      音频数据块有一个头结构,这个结构包含了音频数据缓冲的地址,大小,已录音数据大小等信息和其他各种控制标志。这个结构适用于音频的输入(录 音)和输出(播放)缓冲中。下面是该结构的详细信息:

    typedef struct wavehdr_tag

    {

        LPSTR       lpData;

        DWORD       dwBufferLength;

        DWORD       dwBytesRecorded;

        DWORD       dwUser;

        DWORD       dwFlags;

        DWORD       dwLoops;

        struct      wavehdr_tag FAR *lpNext;

        DWORD       reserved;

    } WAVEHDR, *PWAVEHDR, NEAR *NPWAVEHDR, FAR *LPWAVEHDR;

      其中,lpData是指定的缓冲块地址,dwBufferLength是指定的缓冲块大 小,dwBytesRecorded是已录音数据大小,dwUser是用户数据,dwFlags是 控制标志,表明缓冲的使用状态,dwLoops是音频输出时缓冲数据块循环的次数,lpNextreserved是 系统保留数据。在程序实现时,通过设置或修改这个结构的相关参数来实现对音频输入和输出缓冲区的控制。

      程序中定义了一个队列结构,用来存储网络中接收到的音频数据,其结构如下:

    struct CAudioOutData

    {

        short *lpdata;

        DWORD dwLength;

    };

    struct CAudioOutData m_AudioDataOut[50];

      其中,lpdata是数据块地址,dwLength是数据块大小。通过调整m_AudioDataOut下 标实现队列的循环过程。

    4 参数设置

      声卡输入和输出的音频属性可定义如下:

    m_waveformt.wFormatTag        =  WAVE_FORMAT_PCM;

    m_waveformt.nChannels         =  1;

    m_waveformt.nSamplesPerSec    =  8000;

    m_waveformt.wBitsPerSample    =  16;

    m_waveformt.cbSize            =  0;

    m_waveformt.nBlockAlign       =  2;

    m_waveformt.nAvgBytesPerSec   = 16000;

      设置的音频格式类型是PCM格式,单通道,8000HZ的采样率,每秒采集的数据大小为16000bytes.其 中,存在着下面的关系:

    nBlockAlign       =  nChannels * wBitsPerSample / 8 ;  

    nAvgBytesPerSec   =  nSamplesPerSec * nBlockAlign ;

      音频数据块头结构可定义如下:

    pWaveHdr->lpData            = 指定缓冲的地址;

    pWaveHdr->dwBufferLength    = 指定缓冲的大小;

    pWaveHdr->dwBytesRecorded   = 0 ;

    pWaveHdr->dwUser            = 0 ;

    pWaveHdr->dwFlags           = 0 ;

    pWaveHdr->dwLoops           = 1 ;

    pWaveHdr->lpNext            = NULL;

    pWaveHdr->reserved          = 0;

    m_waveformt.nAvgBytesPerSec = 16000;

      每次为输入或输出设备准备缓存的时候,都需要设置缓存数据块的头结构。

    5 基本操作流程

      调用WaveX 低级音频函数API启动声卡录音的基本操作步骤如下图所示:

                   打 开录音设备: waveInOpen

                              

            为录音设备准备缓存: waveInPrepareHeader

                              

              为输入设备增加缓存: waveInAddBuffer

                              

                     启动录音: waveInStart

                              

                清除缓存: waveInUnprepareHeader

                              

                     停 止录音: waveInReset

                              

                   关 闭录音设备: waveInClose

    3.1    录音流程

      在这个过程中,会产生很多WM_WIM_***格式的WINDOWS消息。程序通过捕获 这些消息对缓存,数据和设备进行处理,具体可见后面章节。录音设备打开时,可以指定消息的响应方式:回掉函数,线程IDWINDOWS窗 口句柄或事件句柄等。

    MMRESULT waveInOpen(

        LPHWAVEIN phwi,         //输入设备句柄

        UINT uDeviceID,         //输入设备ID

        LPWAVEFORMATEX pwfx,    //录音格式指针

        DWORD dwCallback,       //处理消息的回调函数或窗口句柄, 线程ID

        DWORD dwCallbackInstance,   //通常为0

        DWORD fdwOpen           //处理消息方式的符 号位

    );

      调用WaveX 低级音频函数API启动声卡输出的基本操作步骤如下图所示:

                     打开输出设备: waveOutOpen

                                 

              为输出设备准备缓存: waveOutPrepareHeader

                                 

                 写数据导输出设备缓存: waveOutWrite

                                 

                清除输出缓存: waveOutUnprepareHeader

                                 

                       停止输出: waveOutReset

                                 

                     关闭输出设备: waveOutClose

    3.2    播放流程

      同录音一样,在音频输出过程中也有一系列的消息,程序通过捕获这些消息对缓存,数据和设备进行处理。具体操作见后面章节。

    6 消息及处理

      WINDOWS下提供消息映射实现事件的处理。低级音频函数处理声音数据块也正要归功于WINDOW的 消息映射机制。

      图6.1 6.2分别描述了声卡录音和播放过程中产生的消息:

            WM_WIM_OPEN

                    

                      音频输入 设备打开消息

               

            WM_WIM_DATA

                    

                       缓冲录满或停止录音消息

               

            WM_WIM_CLOSE

                     

                        音频输入 设备关闭消息

    6.1   录 音过程消息

            WM_WOM_OPEN

                    

                      音频输出 设备打开消息

               

            WM_WOM_DONE

                    

                      缓冲播放完或停止输出消息

               

            WM_WOM_CLOSE

                     

                        音频输出 设备关闭消息

    6.2   播 放过程消息

      在打开音频输入或输出设备消息处理中,可对一些变量进行初始化;在WM_WIM_CLOSE消息的处理中主要是调用WaveInUnprepareHeader释 放输入设备对应的缓存和其他资源;在WOM_CLOSE消息的处理中主要是调用WaveOutUnprepareHeader释 放输出设备对应的缓存和其他资源;在WM_WIM_DATA消息处理中,处理完录入的数据后需要重新为输入设备添加缓冲;在WM_WIM_DATA消 息处理中,首先清空已经播放的数据,调整循环队列中接收音频指针和播放音频指针,然后从该队列中拷贝数据到输出缓存中。

    7 程序结构

      系统的功能是实现在局域网内的点对点实时音频通信。音频的网络传输采用UDP方式。

      程序中为输入设备准备了两块缓冲,输出设备的缓冲块数可以通过修改宏进行调整,但至少是两块。程序使用多线程技术实现声音的采集发送和接收播 放。总体结构如下所示:

                                  程序启动

                                    

                                设置音频属性

                                    

                                    

                           启动录音     启动音频包接收

                                           

                          发送音频包       启动播放

    7.1   总 体结构图

      程序总体结构很简单,大体可以分为两部分:一是录音和发送,二是接收和播放。

    (一) 录音发送部分的流程如下:

                            打 开音频输入设备(录音)

                                     

                             为 输入设备准备两块缓存

                                      

                                   启 动录音

                                     

        ┌─────────────→│

                                  ↙  ↘

           捕捉到消息:WM_WIM_DATA      捕捉到消息:WM_WIM_CLOSE

                                                 

           对已录数据进行G721编码        释放输入设备所有缓存

                                                 

                发送 编码后数据           关 闭音频输入设备,结束

                     

           为输入设备重新指定缓存

                     

        └───────┘

    7.2   录 音及发送流程图

      部分源码:

    1)打开音频输入设备源码为:

    waveInOpen(&hWaveIn,

        WAVE_MAPPER,

        &m_waveformin,

        (DWORD)waveInProc,

        NULL,

        CALLBACK_FUNCTION);

      其中,hWaveIn为音频输入句柄,WAVE_MAPPER表示让系统选择录音的声 卡,m_waveformin是音频格式,waveInProc是消息处理函数名,CALLBACK_FUNCTION表 示以函数调用的方式处理响应录音过程中的消息。

    2)为输入设备添加缓冲的源码为:

    // 为音频输入准备两个缓存:pBuffer1,pBuffer2, 大小为BUFFER_SIZE

    // hWaveIn为音频输入句柄

    pWaveHdr1->lpData           = (LPTSTR)pBuffer1;

    pWaveHdr1->dwBufferLength   = BUFFER_SIZE;

    pWaveHdr1->dwBytesRecorded  = 0;

    pWaveHdr1->dwUser           = 0;

    pWaveHdr1->dwFlags          = 0;

    pWaveHdr1->dwLoops          = 1;

    pWaveHdr1->lpNext           = NULL;

    pWaveHdr1->reserved         = 0;

    // 准备头结构

    waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR)) );

    pWaveHdr2->lpData           = (LPTSTR)pBuffer2;

    pWaveHdr2->dwBufferLength   = BUFFER_SIZE;

    pWaveHdr2->dwBytesRecorded  = 0;

    pWaveHdr2->dwUser           = 0;

    pWaveHdr2->dwFlags          = 0;

    pWaveHdr2->dwLoops          = 1;

    pWaveHdr2->lpNext           = NULL;

    pWaveHdr2->reserved         = 0;

    // 准备头结构

    waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR)) );

    // 添加缓存

    waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR));

    waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR));

    3WM_WIM_DATA消息处理中为输入设备添加缓存源码为:

    // dwParam1为消息处理函数参数

    waveInPrepareHeader (hWaveIn, (PWAVEHDR)dwParam1, sizeof (WAVEHDR));

    waveInAddBuffer (hWaveIn, (PWAVEHDR)dwParam1, sizeof (WAVEHDR));

      WM_WIM_CLOSE消息处理中释放缓存源码为:

    waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR));

    waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR));

    (二)音频接收播放流程如下所示:

                 打开音频输 出设备(播放)

                            ↓

              为输出设备准备n块缓存 (n >= 2)

                            

                          ↙  ↘

                      ↙          ↘

                 ↙                    ↘

                ↓                         ↓←────┐

             启动网络               循 环队列中音频     

             音频数据                接 收指针位置      

             接收线程                 是 否大于1   ──┘

                                                 N

        ┌──                         Y

              ↓                         ↓

           接收数据      ┌─────启动播放

           丢包处理                   

                                   ↙   ↘

                               ↙           ↘

              ↓               ↓               ↓

        │调用G721对接收   │  捕捉到消息:    捕捉到消息:

        │的数据进行解码     WM_WIM_DATA     WM_WIM_CLOSE

                             ↓               ↓

              ↓         │调整音频播放指针  释放所有音频

        │ 将解码后数据    │在循环队列中位置  输 出设备缓存

        │ 拷进循环队列          ↓               ↓

                       │从循环队列中拷贝  关闭音频输出

        └───┘         │ 数据到输出缓存    设备,结束

                                 ↓

                           └───┘

    7.3   音 频接收及播放播放流程图

      部分源码:

      打开音频输出设备:

    waveOutOpen(&hWaveOut,

        WAVE_MAPPER,

        &m_waveformout,

        (DWORD)waveOutProc,

        NULL,

        CALLBACK_FUNCTION);

      hWaveOut是输出设备句柄;WAVE_MAPPER表示让系统选择播放声卡;m_waveformout表 示输出音频格式;waveOutProc是音频输出消息处理函数名;CALLBACK_FUNCTION表 示以回掉函数的方式响应音频输出过程的消息。

      为音频输出准备缓冲并启动音频输出源码:

    for( int i=0;i<BufferNum;i++)     // BufferNum 为输出 缓冲块数

    {   // outBuffer[i]是每一块缓冲区的 首地址,为short类型

      pWaveHdrOut[i]->lpData            = (LPTSTR)outBuffer[i];

      pWaveHdrOut[i]->dwBufferLength    = OUTSIZE*sizeof(short);

      pWaveHdrOut[i]->dwBytesRecorded   = 0 ;

      pWaveHdr->lpNext                  = NULL ;

      pWaveHdr->reserved                = 0 ;

      m_waveformt.nAvgBytesPerSec  = 16000 ;

      pWaveHdrOut[i]->dwUser         = 0 ;

      pWaveHdrOut[i]->dwFlags         = 0 ;

      pWaveHdrOut[i]->dwLoops        = 1 ; 

      pWaveHdrOut[i]->lpNext          = NULL ;

      pWaveHdrOut[i]->reserved        = 0 ;

    }

    while(1)

    { // nReceive 是网络音频接收指针在循环队列中的位置

      if( nReceive > 1 )   // 当接收到的数据大于1帧时才启动声卡输出

      {

        for(int i=0;i<BufferNum;i++)

        { // 启动音频输出所有缓冲区块

          waveOutPrepareHeader(hWaveOut,pWaveHdrOut[i],sizeof(WAVEHDR)) ;

          waveOutWrite(hWaveOut,pWaveHdrOut[i],sizeof(WAVEHDR));

        }

        break ;

      }

      Sleep(100) ;

    }

      WM_WOM_DONE消息处理中为播放缓冲准备数据源码为:

    // dwParam1为消息处理函数参数;m_AudioDataOut是 音频接收循环队列首地址

    // nAudioOut为音频播放指针在循环队列中位置

    memcpy(

        ((PWAVEHDR)dwParam1)->lpData,

        (char )m_AudioDataOut[nAudioOut].lpdata,

        m_AudioDataOut[nAudioOut].dwLength*sizeof(short)

    );

    waveOutWrite(hWaveOut,(PWAVEHDR)dwParam1,sizeof(WAVEHDR));

      WM_WOM_CLOSE消息处理释放资源源码为:

    for(int i=0;i<BufferNum;i++)  // 释 放资源

    {

      //释放输出头缓冲

      waveOutUnprepareHeader(hWaveOut,pWaveHdrOut[i],sizeof(WAVEHDR));

      if( pWaveHdrOut[i] )

      {

        free(pWaveHdrOut[i]) ;

        pWaveHdrOut[i] = NULL ;

      }

      if( outBuffer[i] )  // 释 放输出缓冲

      {

        free(outBuffer[i]) ;

        outBuffer[i] = NULL ;

      }

    }

    8 网络拥塞控制策略

      从网络中接收到的音频数据解码后存放在循环队列中,队列中缓存块数为50,每块大小为400Bytes(网 络音频数据一帧为100B,解码后为400B);声卡播放音频需要从循环队列中取数据,令接收指针 在循环队列中的位置为nR,播放指针为nP,两者之间的关系如图8.1所 示:

    8.1   循 环队列结构

      nP nR指向的位置一开始都是0。如果同时启动网络接 收和音频播放的话就会造成同一块内存的读写冲突,导致程序崩溃,所以程序中当nR>1时才启动音频播放。

      nRnP的移动是异步的。当接收到一帧网络音频数据时nR (nR+1)%50;而nP的移动需要视网络状态好坏而定。通过协调两者的移动步伐达到网络拥塞控制的目的。具 体如下:

      1)网络正常,即nRnP的差距在28之 间,包括28,则nP = (nP+1)%50;

      2)网络繁忙,即nR指针移动过满,导致nR-nP < 2, nP保持不动,下一次播放的数据为空数据;

      3)网络较好,且因某些原因声卡输出慢了,即nR-nP > 8,则 np = (nP+abs(nR-nP)%50-5)%50 ;通过丢弃一些数据帧以保证声音的实时性,否则会造成声音延时过大,而且随着 时间推移会越来越大。

    9 系统测试

      语音通信主要测试以下几个方面:

      1)实时性:话音是否有延时;

      2)连续性:话音是否连续,中间是否会断续;

      3)稳定性:话音是否会丢失,若会,丢失的是否严重;

      程序中某些参数是固定的:音频每次采集的大小为400B,编码后为100B;接收音频循 环队列块数为50。可调整的是循环队列每块缓存大小,声卡输出缓冲大小(两者的大小是一样的),以及声卡输出缓冲数目。假设缓 存大小为BUFFER,缓存块数为BUFFERNUM,通过测试有以下结果:

    BUFFER(Bytes)

    BUFFERNUM

    话音效果

    实时性

    连续

    稳定

    400

    2

    不连续

    稳定

    400

    4

    有点不连续

    稳定

    400

    8

    一般

    稳定

    400

    16

    稳定

    800

    2

    有点连续

    稳定

    800

    4

    一般

    稳定

    800

    8

    稳定

    800

    16

    稳定

    2000

    2

    有点延迟

    稳定

    2000

    4

    延迟大

    稳定

    2000

    8

    延迟较大

    稳定

    2000

    16

    延迟很大

    稳定

    4000

    2

    延迟大

    稳定

    4000

    4

    延迟较大

    稳定

    4000

    8

    延迟很大

    稳定

    4000

    16

    很差

    稳定

      根据之前分析及上面测试结果,不难发现在局域网中,网络比较稳定,话音基本上不丢失。

      当缓冲区较小时,必须增大缓冲块数以保障话音的连续性;当缓冲较大时,必须减少缓冲块数以保证话音实时性。音频在网络拥塞控制时,如果nR移 动速度比nP快,则他们之间最大差距可能是8,若每块大小为4000B,则 就有4000×832000B数据的延迟。

      所以在实际应用中,可将缓冲大小和缓冲块数设置比较合适的值,例如:40016;或8008; 也可以调整网络拥塞控制策略优化话音效果,例如可将nRnP的差值幅度调小作为网络正常的情况。

    10 结束语

      网络拥塞控制策略和双/多缓冲技术是实现实时连续话音通信的关键技术。在实际应用中建立两个UDP套 接字:一个用于发送音频数据,一个用于接收音频数据,利用WaveX音频函数采集播放声音,可以很好的实现音频的实时通信

    附录A  WaveX API

    waveInGetNumDevs 返回系统中存在的波形输入设备的数量
    waveInAddBuffer 向波形输入设备添加一个输入缓冲区
    waveInGetDevCaps 查询指定的波形输入设备以确定其性能
    waveInGetErrorText 检取由指定的错误代码标识的文本说明
    waveInGetID 获取指定的波形输入设备的标识符
    waveInGetPosition 检取指定波形输入设备的当前位置
    waveInMessage 发送一条消息给波形输入设备的驱动器
    waveInOpen 为录音而打开一个波形输入设备
    waveInPrepareHeader 为波形输入准备一个输入缓冲区
    waveInStart 启动在指定的波形输入设备的输入
    waveInReset 停止给定的波形输入设备的输入,且将当前位置清零
    waveInStop 停止在指定的波形输入设备上的输入
    waveInUnprepareHeader 清除由waveInPrepareHeader函 数实现的准备
    WaveInClose 关闭指定的波形输入设置
    waveOutBreakLoop 中断给定的波形输出设备上一个循环,并允许 播放驱动取列表中的下一个块
    waveOutClose 关闭指定的波形输出设备
    waveOutGetDevCaps 查询一个指定的波形输出设备以确定其性能
    waveOutGetErrorText 检取由指定的错误代码标识的文本说明
    waveOutGetID 检取指定的波形输出设备的标识符
    waveOutGetNumDevs 检取系统中存在的波形输出设备的数量
    waveOutGetPitch 查询一个波形输出设备的当前音调设置
    waveOutGetPlaybackRate 查询一个波形输出设备当前播放的速度
    waveOutGetPosition 检取指定波形输出设备的当前播放位置
    waveOutGetVolume 查询指定波形输出设备的当前音量设置
    waveOutMessage 发送一条消息给一个波形输出设备的驱动器
    waveOutOpen 为播放打开一个波形输出设备
    waveOutPause 暂停指定波形输出设备上的播放
    waveOutPrepareHeader 为播放准备一个波形缓冲区
    waveOutRestart 重新启动一个被暂停的波形输出设备
    waveOutSetPitch 设置一个波形输出设备的音调
    waveOutSetPlaybackRate 设置指定波形输出设备的速度
    waveOutSetVolume 设置指定的波形输出设备的音量
    waveOutUnprepareHeader 清除由waveOutPrepareHeader函 数实现的准备
    waveOutWrite 向指定的波形输出设备发送一个数据块

    - END -


    本文已获作者(林文焕)本人许可转载,其他转载请直接联系作者:linpder AT 163.com。

    本栏目相关
  •  2008-11-10 Linux 音频 API 指南
  •  2007-04-03 基于WaveX低级音频函数的实时语音通信
  •  2001-09-13 Graph Editor 教程
  •  2001-09-20 Ogg Vorbis测试报告
  •  2005-11-26 MPEG 1 Layer-2+SBR对比MPEG 1 Layer-2
  •  2005-11-27 Parametric Stereo/参量立体声简介
  •  2005-12-16 Fraunhofer IIS 音频水印技术
  •  2006-05-03 什么是ABX盲听测试
  •  1999-08-03 The Truth About Vocal Eliminators