XAudio2学习之IXAudio2VoiceCallback回调

使用IXAudio2VoiceCallback回调的好处是,在音频数据播放完的时候,可以通知外部程序进行其他操作。

使用IXAudio2VoiceCallback需要继承此接口,然后重新实现,因为内部所有函数都是纯虚函数。所有函数中使用比较多的是OnStreamEnd函数,当音频数据播放完成的时候,OnStreamEnd会触发一个事件。

继承实现IXAudio2VoiceCallback接口:

class VoiceCallback : public IXAudio2VoiceCallback
{
public:
    HANDLE hBufferEndEvent;
    VoiceCallback(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
    ~VoiceCallback(){ CloseHandle( hBufferEndEvent ); }

    //Called when the voice has just finished playing a contiguous audio stream.
    void OnStreamEnd() { SetEvent( hBufferEndEvent ); }

    //Unused methods are stubs
    void OnVoiceProcessingPassEnd() { }
    void OnVoiceProcessingPassStart(UINT32 SamplesRequired) {    }
    void OnBufferEnd(void * pBufferContext)    { }
    void OnBufferStart(void * pBufferContext) {    }
    void OnLoopEnd(void * pBufferContext) {    }
    void OnVoiceError(void * pBufferContext, HRESULT Error) { }
};

怎么使用回调呢?

IXAudio2VoiceCallback是创建IXAudio2SourceVoice对象的时候给CreateSourceVoice使用的,第五个参数就是IXAudio2VoiceCallback对象的指针或者地址。

VoiceCallback pCallBack;
 	IXAudio2SourceVoice *pSourceVoice = NULL;
	hr = pEngine->CreateSourceVoice(&pSourceVoice, waveFormat, 0, 1.0f, &pCallBack);//创建源声音,用来提交数据
 	if (FAILED(hr))
 		return 0;
然后提交音频数据,调用IXAudio2SourceVoice的Start启动播放。使用WaitForSingleObject来等待此次提交的音频数据播放完成:第一参数是回调的事件句柄,当此次提交的音频数据播放完时,回调会触发OnStreamEnd设置一个事件给hBufferEndEvent,那么WaitForSingleObject就会返回;第二个参数是等待的时长,INFINITE表示无限等待,直到句柄返回。也可以依据自己提交的数据的时长,设置一个合适的值,比如20,注意单位是ms。
WaitForSingleObject(pCallBack.hBufferEndEvent, INFINITE);
如果需要多次提交数据,那么就需要很频繁的调用SubmitSourceBuffer,但是IXAudio2SourceVoice等待播放的音频数据队列最大不能超过XAUDIO2_MAX_QUEUED_BUFFERS也就是64个,否则就会导致崩溃。那么这种情况下可以如下操作:
XAUDIO2_VOICE_STATE state;
	pSourceVoice->GetState(&state);//获取状态
	while (state.BuffersQueued > XAUDIO2_MAX_QUEUED_BUFFERS - 1)
	{
		WaitForSingleObject(pCallBack.hBufferEndEvent, INFINITE);
		pSourceVoice->GetState(&state);
	}
当待播放队列超过63时,那么就进入等待,直到当前播放的buff播放完成,否则就一直阻塞。

注意:IXAudio2SourceVoice待播放队列中的数据要一直保持有效,直到播放完成,否则会崩溃。

测试代码(WaveFile.h/WaveFile.cpp见前面文章:XAudio2学习四之wave文件格式):

#pragma once
#include "WaveFile.h"
#include "XAudio2.h"

class VoiceCallback : public IXAudio2VoiceCallback
{
public:
	HANDLE hBufferEndEvent;
	VoiceCallback() : hBufferEndEvent(CreateEvent(NULL, FALSE, FALSE, NULL)){}
	~VoiceCallback(){ CloseHandle(hBufferEndEvent); }

	//Called when the voice has just finished playing a contiguous audio stream.
	void OnStreamEnd() { SetEvent(hBufferEndEvent); }

	//Unused methods are stubs
	void OnVoiceProcessingPassEnd() { }
	void OnVoiceProcessingPassStart(UINT32 SamplesRequired) {    }
	void OnBufferEnd(void * pBufferContext)    { }
	void OnBufferStart(void * pBufferContext) {    }
	void OnLoopEnd(void * pBufferContext) {    }
	void OnVoiceError(void * pBufferContext, HRESULT Error) { }
};

 int main(int argc, char *argv[])
 {
	 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);;//com初始化
 	if (FAILED(hr))
 		return 0;
 
 	IXAudio2 *pEngine = NULL;
 	hr = XAudio2Create(&pEngine);//创建引擎
 	if (FAILED(hr))
 		return 0;
 
 	IXAudio2MasteringVoice *pMasterVoice = NULL;
 	hr = pEngine->CreateMasteringVoice(&pMasterVoice);//创建主声音,默认是输出当前扬声器
 	if (FAILED(hr))
 		return 0;
 
 	CWaveFile waveFile;
 	hr = waveFile.Open(L"F:\\桌面\\24bit-48khz.wav", NULL, WAVEFILE_READ);//加载文件
 	if (FAILED(hr))
 		return 0;
 
 	WAVEFORMATEX *waveFormat = waveFile.GetFormat();//获取文件格式

	VoiceCallback pCallBack;
 	IXAudio2SourceVoice *pSourceVoice = NULL;
	hr = pEngine->CreateSourceVoice(&pSourceVoice, waveFormat, 0, 1.0f, &pCallBack);//创建源声音,用来提交数据
 	if (FAILED(hr))
 		return 0;
 
 	DWORD size = waveFile.GetSize();//获取文件的大小
 	BYTE *pData = new BYTE[size];//申请内存空间,用于保存数据
 	hr = waveFile.Read(pData, size, &size);//读取文件内容
 	if (FAILED(hr))
 		return 0;
 
	XAUDIO2_BUFFER buffer = {0};//将读取的文件数据,赋值XAUDIO2_BUFFER
 	buffer.AudioBytes = size;
 	buffer.pAudioData = pData;
	buffer.Flags = XAUDIO2_END_OF_STREAM;
 
 	hr = pSourceVoice->SubmitSourceBuffer(&buffer);//提交内存数据
 	if (FAILED(hr))
 		return 0;
 
 	hr = pSourceVoice->Start(0);//启动源声音
 	if (FAILED(hr))
 		return 0;
 
	XAUDIO2_VOICE_STATE state;
	pSourceVoice->GetState(&state);//获取状态
	while (state.BuffersQueued > XAUDIO2_MAX_QUEUED_BUFFERS - 1)
	{
		WaitForSingleObject(pCallBack.hBufferEndEvent, INFINITE);
		pSourceVoice->GetState(&state);
	}
 
 	pMasterVoice->DestroyVoice();//释放资源
 	pSourceVoice->DestroyVoice();//释放资源
 	pEngine->Release();//释放资源
 	CoUninitialize();//释放资源

	delete []pData;//释放资源
	pData = NULL;

 	return 0;
 }
交流QQ:1245178753
本文地址:http://blog.csdn.net/u011417605/article/details/50970574

源码下载:http://download.csdn.net/detail/u011417605/9471383

你可能感兴趣的:(XAudio2)