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格式音频数据文件。
- // XAudio2_test.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include <Windows.h>
- #include "XAudio2.h"
- //--------------------------------------------------------------------------------------
- // Helper macros
- //--------------------------------------------------------------------------------------
- #ifndef SAFE_DELETE_ARRAY
- #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
- #endif
- #ifndef SAFE_RELEASE
- #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
- #endif
- int main()
- {
- IXAudio2 *pXAudio2;//这里返回XAudio2对象的指针
- CoInitializeEx(NULL, COINIT_MULTITHREADED);
- HRESULT hr;
- if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
- {
- wprintf(L"Failed to init XAudio2 engine: %#X\n", hr);
- CoUninitialize();
- return 0;
- }
- //
- // Create a mastering voice
- //
- IXAudio2MasteringVoice* pMasteringVoice = NULL;
- if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice)))
- {
- wprintf(L"Failed creating mastering voice: %#X\n", hr);
- SAFE_RELEASE(pXAudio2);
- CoUninitialize();
- return 0;
- }
- WAVEFORMATEX pwfx;
- pwfx.wFormatTag = WAVE_FORMAT_PCM; //PCM格式
- pwfx.wBitsPerSample = 16; //位数
- pwfx.nChannels = 1; //声道数
- pwfx.nSamplesPerSec = 8000; //采样率
- pwfx.nBlockAlign = 16*1 / 8; //数据块调整
- pwfx.nAvgBytesPerSec = pwfx.nBlockAlign * 8000; //平均传输速率
- pwfx.cbSize = 0; //附加信息
- //
- // Play the wave using a XAudio2SourceVoice
- //
- // Create the source voice
- IXAudio2SourceVoice* pSourceVoice;
- if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, &pwfx)))
- {
- wprintf(L"Error %#X creating source voice\n", hr);
- return hr;
- }
- FILE *fp;
- //SPEECHDECODE文件说明: 该文件为保存的二进制音频数据,格式:16位,采样率8K.
- int re = fopen_s(&fp, "SPEECHDECODE", "rb");
- XAUDIO2_BUFFER XBuffer[4];
- BYTE *pRBuffer[4];
- int i = 0;
- for (i = 0; i < 4; i++)
- {
- pRBuffer[i] = (BYTE *)malloc(640);
- fread(pRBuffer[i], 640, 1, fp);
- XBuffer[i].AudioBytes = 640;
- XBuffer[i].Flags = 0;
- XBuffer[i].LoopBegin = 0;
- XBuffer[i].LoopCount = 0;
- XBuffer[i].LoopLength = 0;
- XBuffer[i].pAudioData = pRBuffer[i];
- XBuffer[i].pContext = (void*)new int[1];
- XBuffer[i].PlayBegin = 0;
- XBuffer[i].PlayLength = 0;
- if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))
- {
- wprintf(L"Error %#X submitting source buffer\n", hr);
- pSourceVoice->DestroyVoice();
- return hr;
- }
- }
- hr = pSourceVoice->Start(0);
- BOOL isRunning = TRUE;
- i = 0;
- while (SUCCEEDED(hr) && isRunning)
- {
- XAUDIO2_VOICE_STATE state;
- //检查播放缓存区缓冲块数量,当缓存块数量不足时,则新加入
- pSourceVoice->GetState(&state);
- isRunning = (state.BuffersQueued > 0) != 0;
- // Wait till the escape key is pressed
- if (GetAsyncKeyState(VK_ESCAPE)) //Esc键退出
- break;
- printf("state.BuffersQueued = %d\n", state.BuffersQueued);
- if (state.BuffersQueued <= 2)
- {
- if (fread(pRBuffer[i], 640, 1, fp) <= 0) break;
- XBuffer[i].pAudioData = pRBuffer[i];
- if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&XBuffer[i])))
- {
- wprintf(L"Error %#X submitting source buffer\n", hr);
- pSourceVoice->DestroyVoice();
- return hr;
- }
- i = (i + 1) % 4;
- }
- Sleep(10);
- }
- END:
- hr = pSourceVoice->Stop(0);
- pSourceVoice->DestroyVoice();
- for (i = 0; i < 4; i++)
- {
- if (pRBuffer[i]) free(pRBuffer[i]);
- }
- if (pXAudio2) {
- pXAudio2->Release();
- pXAudio2 = NULL;
- }
- CoUninitialize();
- return 0;
- }
XAudio2播放PCM的更多相关文章
- 最简单的视音频播放示例8:DirectSound播放PCM
本文记录DirectSound播放音频的技术.DirectSound是Windows下最常见的音频播放技术.目前大部分的音频播放应用都是通过DirectSound来播放的.本文记录一个使用Direct ...
- 最简单的视音频播放演示样例8:DirectSound播放PCM
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
- 通过WinAPI播放PCM声音
在Windows平台上,播放PCM声音使用的API通常有如下两种. waveOut and waveIn:传统的音频MMEAPI,也是使用的最多的 xAudio2:C++/COM API,主要针对游戏 ...
- ffplay代码播放pcm数据
摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...
- DirectSound播放PCM(可播放实时采集的音频数据)
前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...
- 最简单的视音频播放示例9:SDL2播放PCM
本文记录SDL播放音频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...
- 使用AudioTrack播放PCM音频数据(android)
众所周知,Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的.MediaPl ...
- Android 音视频深入 二 AudioTrack播放pcm(附源码下载)
本篇项目地址,名字是录音和播放PCM,求starhttps://github.com/979451341/Audio-and-video-learning-materials 1.AudioTrack ...
- OpenAL播放pcm或wav数据流-windows/ios/android(一)
OpenAL播放pcm或wav数据流-windows/iOS/Android(一) 最近在研究渲染问题,本文采用openal做pcm和wav数据流播放,并非本地文件,demo是windows的,i ...
随机推荐
- Hadoop2.8.0 源码编译
一.下载源码并解压 二.检查以下几项 必须有网络!!! JDK 1.7+ 安装方法 java -version Maven 3.0 or later 安装方法 mvn -version Findbug ...
- mysql in和exists性能比较和使用【转】
exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当 exists里的条件语句能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,返回当前loop到的这条记录, ...
- Python的类(一)
类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外. ...
- 安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(二)
本文导航 -7. 安装 PHP0 -8. 安装 MariaDB 数据库 -9. 安装和配置 SSH 服务器 -10. 安装 GCC (GNU 编译器集) -11. 安装 Java 7. 安装 PHP ...
- laravel5.5授权系统
目录 1. Gates 1.1 一个简单的使用Gates的例子 1.2 编写Gates 1.3 授权动作 2. policy策略 2.1 还是先看个例子 2.2 编写策略 2.3 授权策略 2.3.1 ...
- Hyper-V中的Linux无法配置网络地址的解决办法
一周碰到2次在Hyper-V 2012中安装了Linux,也安装了IC 3.4.但是却无法配置IP地址的问题.因此造成很多不便,因此找机会把这个原因和解决办法进行了尝试. 这过程中感谢同事的提示,让我 ...
- 平时收集的一些有关UED的团队和个人博客
平时收集的一些有关UED的团队和个人博客 前端团队阿里巴巴 UED -- 我们设计的界面,并没有几十亿的流量,但每天来自上百个国家的百万商人在使用着.阿里巴巴中国站UED -- 阿里巴巴中国站UED成 ...
- unity2D技术学习与整理
目前有关unity2D的教程以及原理几乎都是国外的.我在这方面也是新手,看了一些例子有很多不懂的地方. 这个网站提供的教程很有参考价值 http://brackeys.com/ 还有这个 http:/ ...
- python中subprocess.Popen执行命令并持续获取返回值
先举一个Android查询连接设备的命令来看看Python中subprocess.Popen怎么样的写法.用到的命令为 adb devices. import subprocess order='ad ...
- Go的HttpClient实现
Go作为相对java更新的语言,本身的http模块就有客户端请求的实现,继上一章Java的实现,这里记录Go的实现,接下来还有python的实现 注(go版本1.6) package main imp ...