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


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com