XAudio2播放PCM

XAudio2

 

 

是一个跨平台的API,在Xbox 360及Windows中得到支持。在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中。在Windows上,XAudio2提供一个动态链接库(DLL)。以下例子只使用了其中的一部分功能,并不全面。详情请看微软技术页的XAudio2编程相关(英文)。 使用XAudio2来播放未压缩的PCM音频数据的过程并不复杂,主要有以下几个步骤:

1. 建立XAudio2 引擎

使用XAudio2Create函数,该函数的功能是创建一个XAudio2对象(IXAudio2接口)。

示例:XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR );

2. 使用第1步建立的引擎建立MasteringVoice

使用IXAudio2成员函数CreateMasteringVoice,该函数功能是创建并设置一个MasteringVoice 原型

示例:pXAudio2->CreateMasteringVoice(&pMasterVoice);

3. 使用第一步建立的引擎建立SourceVoice(或SubmixVoice,以下按SourceVoice举例) 使用IXAudio2成员函数CreateSourceVoice,该函数功能是创建并设置一个SourceVoice 原型

示例:

pXAudio2->CreateSourceVoice(&pSourceVoice,&format,0,XAUDIO2_DEFAULT_FREQ_RATIO,NULL,NULL,NULL);

 

 

其中format这样设置:(位数为bits,声道数为channels,采样率为hz)

WAVEFORMATEX format;

format.wFormatTag = WAVE_FORMAT_PCM;//PCM格式

format.wBitsPerSample = bits;//位数

format.nChannels = channels;//声道数

format.nSamplesPerSec = hz;//采样率

format.nBlockAlign = bits*channels/8;//数据块调整

format.nAvgBytesPerSec = format.nBlockAlign*hz;//平均传输速率

format.cbSize = 0;//附加信息

4. 呈交音频数据

使用IXAudio2SourceVoice的成员函数SubmitSourceBuffer,该函数功能是呈交一个XAUDIO2_BUFFER 原型

示例:pSourceVoice->SubmitSourceBuffer(&XAudio2Buffer,NULL);

 

其中XAudio2Buffer这样设置:

XAUDIO2_BUFFER XAudio2Buffer;

XAudio2Buffer.Flags = 0;//可以设为0或XAUDIO2_END_OF_STREAM,当设为后者时,将使

XAudio2播放完该数据块后自动停止,不再播放下一个数据块

XAudio2Buffer.AudioBytes = BufferSize;// 音频数据的长度,按字节算

XAudio2Buffer.pAudioData = pBuffer;//具体音频数据的地址,unsigned char pBuffer[]

XAudio2Buffer.PlayBegin = 0;//起始播放地址

XAudio2Buffer.PlayLength = 0;//播放长度,0为整数据块

XAudio2Buffer.LoopBegin = 0;//循环起始位置

XAudio2Buffer.LoopLength = 0;//循环长度,按字节算

XAudio2Buffer.LoopCount = 0;//循环次数,0为不循环,255为无限循环

XAudio2Buffer.pContext = NULL;//这里的pContext用来标识该数据块,供回调用,可以是NULL

5. 继续呈交数据和播放数据:

播放呈交的数据使用IXAudio2SourceVoice的成员函数Start,该函数功能是开始播放。

原型:HRESULT Start(

UINT32 Flags,//必须是0

UINT32 OperationSet = XAUDIO2_COMMIT_NOW//使用XAUDIO2_COMMIT_NOW将立即生效,

使用XAUDIO2_COMMIT_ALL将挂起,等待其它的数值的OperationSet的处理完

);

示例:pSourceVoice->Start(0, XAUDIO2_COMMIT_NOW);

第5步做完之后,XAudio2将一块接一块地播放呈交的数据块。我们只需不断重复第四步,就能不断地播放音频数据了。需要注意的是,在XAudio2播放完某个XAudio2Buffer之前,该XAudio2Buffer以及XAudio2Buffer.pAudioData所指向的内存不能被修改或删除,否则将发生错误。但是某个

XAudio2Buffer一旦被播放完,就能被修改了。为此,我们可以创建一个数组XAUDIO2_BUFFER []来循环呈交和更新数据。那怎么知道XAudio2到底播放了几个XAudio2Buffer呢,可以使用

IXAudio2SourceVoice的成员函数

原型:GetState(

XAUDIO2_VOICE_STATE *pVoiceState,// 这里返回结构体指针

[optional] UINT32 Flags//获取方式,可选,默认0.设为XAUDIO2_VOICE_NOSAMPLESPLAYED将

只获取挂起(包括正在播放)的XAudio2Buffer数量,速度较快。注意:DirectX SDK版本没有此参数 );

XAUDIO2_VOICE_STATE包含三个成员:

void * pCurrentBufferContext//对应XAUDIO2_BUFFER中的pContext

UINT32 BuffersQueued//挂起(包括正在播放)的XAudio2Buffer数量

UINT64 SamplesPlayed//已播放的样本数

示例: pSourceVoice->GetState(&state);

6. 暂停和停止播放

暂停播放使用IXAudio2SourceVoice的成员函数:Stop

原型:HRESULT Stop(

UINT32 Flags,// 设为0或XAUDIO2_PLAY_TAILS,后者代表等待音效放完

UINT32 OperationSet = XAUDIO2_COMMIT_NOW// XAUDIO2_COMMIT_NOW立即生效

);

如果设定XAUDIO2_PLAY_TAILS,应在音效输出完成后设定0,再Stop一次。

暂停后再次调用Start将在暂停的位置开始播放。

 

如果要完全停止,还需要使用IXAudio2SourceVoice的成员函数FlushSourceBuffers,该函数功能是清除挂起的XAudio2Buffer队列。

原型:HRESULT FlushSourceBuffers();

说明:该函数使用后要到XAudio2播放完一个XAudio2Buffer才生效,建议在回调中使用。使用该函数后,XAudio2Buffer队列计数将置0

7. IXAudio2SourceVoice的其他功能:设置声调使用SetFrequencyRatio函数

原型:HRESULT SetFrequencyRatio(

float Ratio,//1.0为正常声调,>1.0为高声调快放,<1.0为低声调慢放

UINT32 OperationSet = XAUDIO2_COMMIT_NOW

);

 

IXAudio2SourceVoice继承自,所以还有许多IXAudio2Voice的功能,比如设置音量用SetVolume等。

 

注意:以上IXAudio2SourceVoice的成员函数中, Stop、GetState、 FlushSourceBuffers可以在回调中使用 释放相关实例的顺序与创建他们的顺序相反。需要包含头文件Xaudio2.h和Objbase.h以及链接ole32.lib(而不是Microsoft网站上的Xaudio2.lib)

 

 

 

 

=============================================================================================================

以上摘抄

程序说明:

1、参考DirectX SDK 例程XAudio2BasicSound编写。

2、实现功能:验证XAduio2播放语音流程,实现播放二进制存储的PCM格式音频数据文件。

 

[cpp] view plain copy

 

  1.   

[cpp] view plain copy

 

  1. // XAudio2_test.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <Windows.h>  
  6. #include "XAudio2.h"  
  7.   
  8. //--------------------------------------------------------------------------------------  
  9. // Helper macros  
  10. //--------------------------------------------------------------------------------------  
  11. #ifndef SAFE_DELETE_ARRAY  
  12. #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }  
  13. #endif  
  14. #ifndef SAFE_RELEASE  
  15. #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }  
  16. #endif  
  17. int main()  
  18. {  
  19.     IXAudio2 *pXAudio2;//这里返回XAudio2对象的指针  
  20.     CoInitializeEx(NULL, COINIT_MULTITHREADED);  
  21.     HRESULT hr;  
  22.     if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))  
  23.     {  
  24.         wprintf(L"Failed to init XAudio2 engine: %#X\n", hr);  
  25.         CoUninitialize();  
  26.         return 0;  
  27.     }  
  28.     //  
  29.     // Create a mastering voice  
  30.     //  
  31.     IXAudio2MasteringVoice* pMasteringVoice = NULL;  
  32.     if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice)))  
  33.     {  
  34.         wprintf(L"Failed creating mastering voice: %#X\n", hr);  
  35.         SAFE_RELEASE(pXAudio2);  
  36.         CoUninitialize();  
  37.         return 0;  
  38.     }  
  39.     WAVEFORMATEX pwfx;  
  40.     pwfx.wFormatTag         = WAVE_FORMAT_PCM;  //PCM格式  
  41.     pwfx.wBitsPerSample     = 16;               //位数  
  42.     pwfx.nChannels          = 1;                //声道数  
  43.     pwfx.nSamplesPerSec     = 8000;             //采样率  
  44.     pwfx.nBlockAlign        = 16*1 / 8;         //数据块调整  
  45.     pwfx.nAvgBytesPerSec    = pwfx.nBlockAlign * 8000;      //平均传输速率  
  46.     pwfx.cbSize             = 0;                //附加信息  
  47.     //  
  48.     // Play the wave using a XAudio2SourceVoice  
  49.     //  
  50.     // Create the source voice  
  51.     IXAudio2SourceVoice* pSourceVoice;  
  52.     if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, &pwfx)))  
  53.     {  
  54.         wprintf(L"Error %#X creating source voice\n", hr);  
  55.         return hr;  
  56.     }  
  57.   
  58.     FILE *fp;  
  59.     //SPEECHDECODE文件说明: 该文件为保存的二进制音频数据,格式:16位,采样率8K.  
  60.     int re = fopen_s(&fp, "SPEECHDECODE", "rb");  
  61.     XAUDIO2_BUFFER XBuffer[4];  
  62.     BYTE *pRBuffer[4];  
  63.     int i = 0;  
  64.     for (i = 0; i < 4; i++)  
  65.     {  
  66.         pRBuffer[i] = (BYTE *)malloc(640);  
  67.         fread(pRBuffer[i], 640, 1, fp);  
  68.         XBuffer[i].AudioBytes = 640;  
  69.         XBuffer[i].Flags = 0;  
  70.         XBuffer[i].LoopBegin = 0;  
  71.         XBuffer[i].LoopCount = 0;  
  72.         XBuffer[i].LoopLength = 0;  
  73.         XBuffer[i].pAudioData = pRBuffer[i];  
  74.         XBuffer[i].pContext = (void*)new int[1];  
  75.         XBuffer[i].PlayBegin = 0;  
  76.         XBuffer[i].PlayLength = 0;  
  77.         if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))  
  78.         {  
  79.             wprintf(L"Error %#X submitting source buffer\n", hr);  
  80.             pSourceVoice->DestroyVoice();  
  81.             return hr;  
  82.         }  
  83.     }  
  84.   
  85.     hr = pSourceVoice->Start(0);  
  86.     BOOL isRunning = TRUE;  
  87.     i = 0;  
  88.     while (SUCCEEDED(hr) && isRunning)  
  89.     {  
  90.         XAUDIO2_VOICE_STATE state;  
  91.         //检查播放缓存区缓冲块数量,当缓存块数量不足时,则新加入  
  92.         pSourceVoice->GetState(&state);        
  93.         isRunning = (state.BuffersQueued > 0) != 0;  
  94.         // Wait till the escape key is pressed  
  95.         if (GetAsyncKeyState(VK_ESCAPE))    //Esc键退出  
  96.             break;  
  97.         printf("state.BuffersQueued = %d\n", state.BuffersQueued);  
  98.         if (state.BuffersQueued <= 2)  
  99.         {  
  100.             if (fread(pRBuffer[i], 640, 1, fp) <= 0) break;  
  101.             XBuffer[i].pAudioData = pRBuffer[i];  
  102.             if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))  
  103.             {  
  104.                 wprintf(L"Error %#X submitting source buffer\n", hr);  
  105.                 pSourceVoice->DestroyVoice();  
  106.                 return hr;  
  107.             }  
  108.             i = (i + 1) % 4;  
  109.         }  
  110.         Sleep(10);  
  111.     }  
  112. END:  
  113.     hr = pSourceVoice->Stop(0);  
  114.     pSourceVoice->DestroyVoice();  
  115.     for (i = 0; i < 4; i++)  
  116.     {  
  117.         if (pRBuffer[i]) free(pRBuffer[i]);  
  118.     }  
  119.     if (pXAudio2) {  
  120.         pXAudio2->Release();   
  121.         pXAudio2 = NULL;  
  122.     }  
  123.     CoUninitialize();  
  124.     return 0;  
  125. }  

 

时间: 2024-08-01 13:34:03

XAudio2播放PCM的相关文章

最简单的视音频播放示例8:DirectSound播放PCM

本文记录DirectSound播放音频的技术.DirectSound是Windows下最常见的音频播放技术.目前大部分的音频播放应用都是通过DirectSound来播放的.本文记录一个使用DirectSound播放PCM的例子.注:一位仁兄已经提醒我DirectSound已经计划被XAudio2取代了.后来考证了一下发现确有此事.因此在下次更新中考虑加入XAudio2播放PCM的例子.本文仍然记录一下DirectSound这位"元老".   DirectSound简介 DirectSo

最简单的视音频播放示例9:SDL2播放PCM

本文记录SDL播放音频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API用于播放视频:封装了DirectSound这类的API用于播放音频.因为SDL的编写目的就是简化视音频播放的开发难度,所以使用SDL播放视频(YUV/RGB)和音频(PCM)数据非常的容易. SDL简介 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,

linux alsa下实现同时录制、播放pcm???

问题描述 linux alsa下实现同时录制.播放pcm??? 大神们: 目的:在linux平台上实现同时录制.播放声音,要求播放的声音和录制的声音之间的延时小于5ms. 要实现这个要求的话,硬件上需要声卡支持全双工吗?软件上有无设计建议?linux系统延时能达到上述要求吗? 谢谢! 平台:linux 音频结构:alsa 解决方案 linux alsa pcm 播放声音基于alsa驱动架构的pcm播放

使用WindowsAPI实现播放PCM音频的方法_C 语言

本文介绍了使用WindowsAPI实现播放PCM音频的方法,同前面一篇使用WindowsAPI获取录音音频的方法原理具有相似之处,这里就不再详细介绍具体的函数与结构体的参数,相同的部分加以省略,只介绍主要的功能部分代码.如下所示: 1. waveOutGetNumDevs 2. waveOutGetDevCaps 3. waveOutOpen 回调函数: void CALLBACK PlayCallback(HWAVEOUT hwaveout, UINT uMsg, DWORD dwInstan

使用WindowsAPI实现播放PCM音频的方法

这篇文章主要介绍了使用WindowsAPI实现播放PCM音频的方法,很实用的一个功能,需要的朋友可以参考下 本文介绍了使用WindowsAPI实现播放PCM音频的方法,同前面一篇使用WindowsAPI获取录音音频的方法原理具有相似之处,这里就不再详细介绍具体的函数与结构体的参数,相同的部分加以省略,只介绍主要的功能部分代码.如下所示: 1. waveOutGetNumDevs 2. waveOutGetDevCaps 3. waveOutOpen 回调函数: ? 1 void CALLBACK

OpenAL播放pcm或wav数据流-windows/ios/android(一)

OpenAL播放pcm或wav数据流-windows/iOS/Android(一)   最近在研究渲染问题,本文采用openal做pcm和wav数据流播放,并非本地文件,demo是windows的,ios通用.网上都是ios的,ios需要引用OpenAl.framework框架, Android平台需要做openal的jni,android的openal库可以参考 http://blog.csdn.NET/matrix_laboratory/article/details/53319735这篇文

Windows基础-使用XAudio2播放音频(本质是WASAPI)

对于常见的音频播放,使用XAudio2足够了. 时间是把杀猪刀,滑稽的是我成了猪 早在Windows Vista中,M$推出了新的音频架构UAA,其中的CoreAudio接替了DSound.WaveXxx.MediaFundation,通过Core Audio APIs,Windows的音频性能可以与MacOS X相媲美(手动偷笑). Universal Audio Architecture (UAA) CoreAudio属于UAA,只在用户层进行一系列音频处理,而系统内核只负责递交缓冲数据给音

11.3、Libgdx的音频之播放PCM音频

(官网:www.libgdx.cn) audio模块可以提供对音频硬件的直接访问. 音频硬件是通过AudioDevice接口进行的抽象. 以下创建一个新的AudioDevice实例: AudioDevice device = Gdx.audio.newAudioDevice(44100, true); 如果设备无法创建,将返回一个GdxRuntimeException异常. 需要注意的是:在所有的Android设备中延时都非常高,许多设备达到400毫秒的延时. 销毁通过如下代码实现: devic

PCM音频设备的操作函数

对音频设备的操作主要是初始化音频设备以及往音频设备发送 PCM(Pulse Code Modulation)数据.为了方便,本文使用 ALSA(Advanced Linux Sound Architecture)提供的库和驱动.在编译和运行本文中的 MP3 流媒体播放器的时候,必须先安装 ALSA 相关的文件. 本文用到的主要对 PCM 设备操作的函数分为 PCM 设备初始化的函数以及 PCM 接口的一些操作函数. PCM 硬件设备参数设置和初始化的函数有: int snd_pcm_hw_par