XAudio2 教程 - 分离线程和异步读取?

XAudio2 tutorial - Seperate thread and asynchronous reads?

我过去曾使用过此 XAudio2 流式传输教程,并成功地创建了一个程序来流式传输和播放磁盘中的音频 (https://msdn.microsoft.com/en-us/library/windows/desktop/ee415791(v=vs.85).aspx)。

现在我正在修改代码,我发现了一些奇怪的事情。他们创建一个单独的线程来从文件中读取小块的音频数据,并将这些块提交到语音缓冲区。太好了,现在主线程可以在播放音频时做任何它需要做的事情了,但是为什么还要在流线程中使用异步文件读取呢?据我所知,每次循环迭代都会执行文件读取,线程会立即等待,直到块被完全读取,然后再将其提交到语音缓冲区。

他们正在做的事情有优势还是没有必要?

XAudio2 示例代码使用 'asynchronous' 而不是 'blocking' I/O 的原因是最佳实践。它在 'worker thread' 中完成的原因主要是为了简单起见,因为在游戏中,音频通常由它自己的线程处理,以避免出现故障并保持 render/update 循环不同。

您可以将 async/submit 作为 Update 循环的一部分来处理,但前提是您确定它的处理速度总是足够快以避免出现故障。这实际上是我在 GitHub

上使用 XAudio2 流媒体示例的最新遗留 DirectX SDK 版本的方法

A fancier implementation could have used ReadFileEx, but the worker-thread approach was simpler. Also due to some quirks of how API partitioning was implemented back in Windows 8, ReadFileEx was not supported on the Windows Store platform / Windows phone 8 / UWP so the tutorials/samples avoided it to keep from pointing you in a direction that wasn't applicable to all the Microsoft platforms. FWIW, ReadFileEx and WriteFileEx got added back to UWP in the Windows 10 Anniversary Update (14393).

请注意,在 ERROR_IO_PENDING 场景的处理方式中,等待重叠 I/O 的事件存在一些怪癖。 GetOverlappedResultEx 函数在 Windows 8 或更高版本中对此进行了改进和简化。对于 DirectX Tool Kit for Audio 中的波库 reader,我使用此模式为旧平台和新平台构建:

bool wait = false;
if( !ReadFile( hFile.get(), &m_data, sizeof( m_data ), nullptr, &request ) )
{
    DWORD error = GetLastError();

    if ( error != ERROR_IO_PENDING )
        return HRESULT_FROM_WIN32( error );

    wait = true;
}

#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
result = GetOverlappedResultEx( hFile.get(), &request, &bytes, INFINITE, FALSE );
#else
if ( wait )
    (void)WaitForSingleObject( m_event.get(), INFINITE );

result = GetOverlappedResult( hFile.get(), &request, &bytes, FALSE );
#endif

if ( !result || ( bytes != sizeof( m_data ) ) )
{
    return HRESULT_FROM_WIN32( GetLastError() );
}