操作说明:对磁盘中的声音进行流式处理
注意
此内容仅适用于桌面应用(并且需要修订才能在 UWP 应用中运行)。 请参阅 CreateFile2、CreateEventEx、WaitForSingleObjectEx、SetFilePointerEx 和 GetOverlappedResultEx 的文档。 请参阅现已存档的 Windows SDK 示例库中的 XAudio2 音频流效果 Windows 8 示例应用。
可以通过创建一个单独的线程在 XAudio2 中流式传输音频数据,并在流式线程中执行音频数据的缓冲区读取,然后使用回调来控制该线程。
在流式处理线程中执行缓冲区读取
若要在流式处理线程中执行缓冲区读取,请执行以下步骤:
创建读取缓冲区数组。
#define STREAMING_BUFFER_SIZE 65536 #define MAX_BUFFER_COUNT 3 BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
初始化 OVERLAPPED 结构。
该结构用于检查异步磁盘读取完成的时间。
OVERLAPPED Overlapped = {0}; Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
-
hr = pSourceVoice->Start( 0, 0 );
在当前读取位置未传递到音频文件的末尾时循环。
CurrentDiskReadBuffer = 0; CurrentPosition = 0; while ( CurrentPosition < cbWaveSize ) { ... }
在循环中,执行以下操作:
将磁盘上的数据块读取到当前的读取缓冲区中。
DWORD dwRead; if( SUCCEEDED(hr) && 0 == ReadFile( hFile, pData, dwDataSize, &dwRead, pOverlapped ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); DWORD cbValid = min( STREAMING_BUFFER_SIZE, cbWaveSize - CurrentPosition ); DWORD dwRead; if( 0 == ReadFile( hFile, buffers[CurrentDiskReadBuffer], STREAMING_BUFFER_SIZE, &dwRead, &Overlapped ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); Overlapped.Offset += cbValid; //update the file position to where it will be once the read finishes CurrentPosition += cbValid;
使用 GetOverlappedResult 函数等待指示读取已完成的事件。
DWORD NumberBytesTransferred; ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
等待源语音上排队的缓冲区数量小于读取缓冲区的数量。
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1) { WaitForSingleObject( Context.hBufferEndEvent, INFINITE ); }
使用 SubmitSourceBuffer 函数将当前读取缓冲区提交到源语音。
XAUDIO2_BUFFER buf = {0}; buf.AudioBytes = cbValid; buf.pAudioData = buffers[CurrentDiskReadBuffer]; if( CurrentPosition >= cbWaveSize ) { buf.Flags = XAUDIO2_END_OF_STREAM; } pSourceVoice->SubmitSourceBuffer( &buf );
将当前读取缓冲区索引设置为下一个缓冲区。
CurrentDiskReadBuffer++; CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
循环完成后,等待剩余的排队缓冲区完成播放。
当剩余的缓冲区播放完毕后,声音将停止,线程可以退出或重新用于流式传输另一个声音。
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 ) { WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE ); }
创建回调类
若要创建回调类,请创建继承自 IXAudio2VoiceCallback 接口类。
该类应在其 OnBufferEnd 方法中设置事件。 这允许流式处理线程将自身置于睡眠状态,直到事件发出 XAudio2 已完成从音频缓冲区读取的信号。 有关将回调与 XAudio2 配合使用的详细信息,请参阅操作指南:使用源语音回调。
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
HANDLE hBufferEndEvent;
StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
...
};
相关主题