0

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

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

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

4

1 回答 1

1

XAudio2 示例代码使用“异步”而不是“阻塞”I/O 的原因是最佳实践。它在“工作线程”中完成的原因主要是为了简单,因为在游戏中音频通常由它自己的线程处理以避免故障并保持渲染/更新循环不同。

您可以将异步/提交作为Update循环的一部分来处理,但前提是您确定它总是能够足够快地得到处理以避免出现故障。这实际上是我在GitHub 上使用最新的旧版 DirectX SDK 版本的 XAudio2 流式传输示例所采用的方法

可以使用更好的实现ReadFileEx,但工作线程方法更简单。此外,由于在 Windows 8 中如何实现 API 分区的一些怪癖,ReadFileEx在 Windows Store 平台/Windows phone 8/UWP 上不受支持,因此教程/示例避免使用它来避免指向不适用的方向适用于所有 Microsoft 平台。FWIW,ReadFileExWriteFileEx在 Windows 10 周年更新 (14393) 中重新添加到 UWP。

ERROR_IO_PENDING请注意,在如何处理场景时,在等待重叠 I/O 的事件中有一些怪癖。此功能在 Windows 8 或更高版本中得到改进和简化GetOverlappedResultEx。对于DirectX Tool Kit for Audio中的波形库阅读器,我使用此模式为旧平台和新平台构建:

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() );
}
于 2018-01-07T19:47:55.737 回答