> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 XAudio2 播放声音

> 使用 XAudio2 播放声音

在 XBOX One 上使用 `XAudio2` 加载并播放 .wav 文件。

以下各节介绍如何在 XBOX One 开发工具包上使用 `XAudio2` 加载并播放声音。

* [重要的 XAudio2 数据类型](#ID4ELB)
* [初始化 XAudio2](#ID4EXC)
* [加载 .wav 文件](#ID4E1D)
* [设置 .wav 文件的路径](#ID4E2H)
* [播放 .wav 文件](#ID4EAF)
* [结束 .wav 文件的播放](#ID4E2F)

要获取可运行的 `XAudio2` 示例，请从 Microsoft Game Development Kit (GDK) 示例中下载 SimplePlaySound 示例。

<a id="ID4ELB" />

## 重要的 XAudio2 数据类型

`XAudio2` 提供了多种数据类型，用于帮助你在 XBOX One 上播放音效。若要播放 .wav 文件，至少需要以下数据类型。

* `IXAudio2`：这是 `XAudio2` 对象的接口，负责管理音频引擎的所有状态、音频处理线程、声音图等。

* `IXAudio2SourceVoice`：使用源语音向 `XAudio2` 处理管线提交音频数据。要被听到，语音数据必须被送入母带语音。

* `IXAudio2MasteringVoice`：使用该数据类型代表音频输出设备。数据缓冲区不能直接提交给母带语音。但发送给其他类型语音的数据要被听到，必须被引导到母带语音。

此外，以下数据类型也可能有用。

* `PlaySoundVoiceContext`：用于在处理后释放音频缓冲区。

* `IXAudio2VoiceCallback`：包含一些方法，用于在某个 `IXAudio2SourceVoice` 中发生特定事件时通知客户端。

<a id="ID4EXC" />

## 初始化 XAudio2

`CoInitializeEx()` 初始化组件对象模型 (COM) 供当前线程使用。将第一个参数设为 `NULL`；第二个参数设为 `COINIT_MULTITHREADED`。

`XAudio2Create()` 创建一个新的 `XAudio2` 对象，并返回指向其 `IXAudio2` 接口的指针。请确保 `XAUDIO2_PROCESSOR` 被设置为有效值。建议使用 `XAUDIO2_USE_DEFAULT_PROCESSOR`，让操作系统根据硬件平台选择理想的处理器。

`IXAudio2::CreateMasteringVoice()` 会创建并配置一个母带语音，并通过用户提供的指针指向它。

#### C++

```cpp theme={null}
CoInitializeEx( NULL, COINIT_MULTITHREADED );

// Create an XAudio2 device.
DX::ThrowIfFailed( XAudio2Create( &m_pXAudio2, 0, XAUDIO2_USE_DEFAULT_PROCESSOR, NULL ) );

// Create an XAudio2 mastering voice, and store the result.
DX::ThrowIfFailed( m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice ) );  
```

<a id="ID4E1D" />

## 加载 .wav 文件

要访问音频文件，请使用 `WaveFile` 类的一个实例。

* 要打开 .wav 文件并读取其头部中的一些信息，请调用 `WaveFile::Open(LPCWSTR strFileName)`。
* 要确定 .wav 文件的格式，请调用 `WaveFile::GetFormat()`。
* 要确定 .wav 文件中的字节数和采样数，请调用 `WaveFile::GetDuration()`。
* 要将采样数据读入内存，请调用 `WaveFile::ReadSample()`。

#### C++

```cpp theme={null}
// Read the .wav file.
WaveFile WaveFile;

// Append the file name and location to the end of the installation location.
WCHAR FilenameAndLocation[ 1024 ];
_snwprintf_s( FilenameAndLocation, _countof( FilenameAndLocation ), _TRUNCATE, L"%s%s", g_strCommonFileRoot, szFilename );

DX::ThrowIfFailed( WaveFile.Open( FilenameAndLocation ) );

// Read the format header.
BYTE header[64];
WAVEFORMATEX* pbWfx = reinterpret_cast<WAVEFORMATEX*>(header);

DX::ThrowIfFailed( WaveFile.GetFormat( pbWfx, sizeof(header) ) );

// Calculate the number of bytes and samples in the .wav file. 
DWORD cbWaveSize = WaveFile.GetDuration();

// Read the sample data into memory.
BYTE* pbWaveData = new BYTE[ cbWaveSize ];
DX::ThrowIfFailed( WaveFile.ReadSample( 0, pbWaveData, cbWaveSize, &cbWaveSize ) );  
```

<a id="ID4E2H" />

## 设置 .wav 文件的路径

若要加载并使用音频文件，请使用以下代码在本地设备上查找项目的安装位置，并将其存储到字符串中。然后将音频文件的相对位置追加到安装位置字符串末尾。

#### C++

```cpp theme={null}
std::wstring installFolder = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();  
```

<a id="ID4EAF" />

## 播放 .wav 文件

创建一个 `IXAudio2::CreateSourceVoice()` 类，并用它向 `XAudio2` 处理管线提交音频数据。语音数据要被听到，必须直接或通过中间的子混音语音送入母带语音。要保存音频文件的详细信息，请创建一个 `XAUDIO2_BUFFER`。

在创建并初始化好 `XAudio2` 缓冲区和源语音之后，调用 `IXAudio2SourceVoice::SubmitSourceBuffer()` 将音频缓冲区加入语音输入队列。请注意，`XAUDIO2_BUFFER::pAudioData` 指向的音频数据必须一直保持有效，直到 `XAudio2` 播放完缓冲区中的内容。

在语音输入队列被填充后，调用 `IXAudio2SourceVoice::Start()` 播放队列中的下一个声音。

#### C++

```cpp theme={null}
// Play the .wav file by using a new XAudio2SourceVoice.
// Create the source voice.
DX::ThrowIfFailed( pXaudio2->CreateSourceVoice( &m_pSourceVoice, pbWfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &m_VoiceContext ) );

// Submit the .wav sample data by using an XAUDIO2_BUFFER structure.
XAUDIO2_BUFFER buffer = {0};
buffer.pAudioData     = pbWaveData;
buffer.Flags          = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes     = cbWaveSize;
buffer.pContext       = pbWaveData;

// Add the audio buffer to the voice input queue.
DX::ThrowIfFailed( m_pSourceVoice->SubmitSourceBuffer( &buffer ) );

// Play the next audio buffer in the queue.
DX::ThrowIfFailed( m_pSourceVoice->Start( 0 ) );  
```

<a id="ID4E2F" />

## 结束 .wav 文件的播放

要判断某个 .wav 文件是否已播放完毕，需要获取源语音的当前状态。创建一个 `XAUDIO2_VOICE_STATE` 结构，然后调用 `IXAudio2SourceVoice::GetState()`。如果音频已播放完毕，则调用 `IXAudio2SourceVoice::DestroyVoice()`。

#### C++

```cpp theme={null}
// Determine whether the sound effect has been played to completion, and handle an appropriate termination.
XAUDIO2_VOICE_STATE state;
m_pSourceVoice->GetState( &state, XAUDIO2_VOICE_NOSAMPLESPLAYED );
if( state.BuffersQueued == 0 )
{
  // Destroy the current sound effect.
  m_pSourceVoice->DestroyVoice();
}  
```

## 另请参阅

[XAudio2 概述](/build/console-features/audio/overviews/xaudio2-overview)
[ADPCM 概述](/build/console-features/audio/overviews/adpcm-overview)
[ADPCM 命令行编码器](/build/console-features/audio/tools/adpcmencoder-tools)
