> ## 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.

# 使用 XAPU API 进行单流 Opus 音频解码

> 使用 XAPU API 进行单流 Opus 音频解码概述

在本主题中，我们将通过 Microsoft Game Development Kit (GDK) 附带的一个示例，逐步介绍在 XBOX Series X 设备上使用 Opus 硬件加速解码时的预期代码流程。该示例名为 `DecodeOne.cpp`，涵盖了一个客户端下的单流解码场景。

## 音频硬件连接与启动

解码从通过 [XApuConnect](/reference/audio/xapu/functions/xapuconnect) 建立与硬件加速单元的连接开始。调用者使用 [XApuConnectInputParameters](/reference/audio/xapu/structs/xapuconnectinputparameters) 设置连接的要求，具体包括：

1. 处理类型（此处为 [XApuProcessType::DecodeOpus](/reference/audio/xapu/enums/xapuprocesstype)）。
2. 流的数量（此处为 1）。
3. 用于传入和取出输入/输出数据所需的总内存。这里 `MaxInputBufferLength` 为 1024（必须大于或等于流中最大的 Opus 数据包，且必须是 16 的倍数）；`MaxOutputBufferLength` 为 7680，即 48 K 下 20 ms 的数据，960 × 2 × sizeof(float) = 7680，输出也需要是 16 的倍数。

如果该调用成功，[XApuConnectOutputParameters::baseData](/reference/audio/xapu/structs/xapuconnectoutputparameters) 参数将指向操作系统分配的一块内存，硬件加速单元可以直接访问，无需额外的整理或复制。调用者应使用该内存来传入输入数据并取出输出数据。以下是一个简单内存管理器示例，可用于设置 [XApuConnectInputParameters](/reference/audio/xapu/structs/xapuconnectinputparameters) 并把 [XApuConnectOutputParameters::baseData](/reference/audio/xapu/structs/xapuconnectoutputparameters) 划分为两个指针：一个用于输入数据，另一个用于输出数据。

```cpp theme={null}
class DecodeOneSimpleMemoryManager
{
public:
    static const uint32_t MaxStreamCount = 1;
    const uint32_t MaxInputBufferLength = 1024; // Must be equal to or greater than the largest Opus packet in the stream. The number must also be a multiple of 16.
    const uint32_t MaxOutputBufferLength = 7680; // This is 20 ms of data at 48 K, which is 960 x 2 x sizeof(float) = 7680 for MaxOutputBufferLength. The output also needs to be multiple of 16.

private:
    XApuConnectInputParameters _inParam = {
        XApuProcessType::DecodeOpus,
        MaxStreamCount,
        1,
        MaxStreamCount * (MaxInputBufferLength + MaxOutputBufferLength),
        0,
        XApuConnectOptions::None };

    XApuConnectOutputParameters _outParam = {};

public:
    XApuConnectInputParameters * const GetConnectParametersRef() {
        return &_inputParam;
    }

    XApuConnectOutputParameters * const GetConnectionDataRef() {
        return &_outParam;
    }

    uint8_t* GetRawInputBuffer(uint32_t& maxByteCount) {
        maxByteCount = MaxInputBufferLength;
        return reinterpret_cast<uint8_t*>(_outParam.baseData);
    }

    uint8_t* GetRawOutputBuffer(uint32_t& maxByteCount) {
        maxByteCount = MaxOutputBufferLength;
        return reinterpret_cast<uint8_t*>(_outParam.baseData) + MaxInputBufferLength;
    }
};
```

以下是建立连接第一步的代码示例。

```cpp theme={null}
XApuConnectInputParameters * const connectParameters = memoryManager.GetConnectParametersRef();
XApuConnectOutputParameters * const connectionData = memoryManager.GetConnectionDataRef();
hr = XApuConnect(connectParameters, connectionData, &xapuHandle);
```

## 流的激活与停用

在与设备建立连接后，调用者应发送一个流激活命令来启用一个解码引擎。调用者必须指定流索引和声道数。只允许单声道或立体声流。

调用者应调用 [XApuDequeueResult](/reference/audio/xapu/functions/xapudequeueresult) 获取激活结果。因为在本示例中 [XApuConnectInputParameters::maxQueuedCommandsPerStream](/reference/audio/xapu/structs/xapuconnectinputparameters) 设置为 1，所以调用者必须等到每个结果返回后再提交下一个命令。这包括 `Activate`、`Process` 和 `Deactivate` 命令（详情见 [XApuCommandType](/reference/audio/xapu/enums/xapucommandtype)）。

以下是激活一个流的代码。

```cpp theme={null}
XApuDecodeConvertActivateCommand command = {};
command.id.type = XApuCommandType::Activate;
command.id.streamIndex = 0;
command.id.sequence = 0;
command.channelCount = channelCount;

hr = XApuEnqueueCommand(xapuHandle, &command.id, nullptr);
XApuResult result = {};

do {
    hr = XApuDequeueResult(handle, &result);
} while (hr == XAPU_E_PENDING_RESULTS);
```

激活结果收到后，调用者即可开始提交 Opus 数据包进行解码。这应通过 [XApuCommandType::Process](/reference/audio/xapu/enums/xapucommandtype) 命令完成。对于每个 `Process` 命令，调用者必须完成以下工作：

1. 用恰好一个 Opus 数据包填充输入缓冲区。
2. 指定数据包的长度。
3. 提供输出缓冲区的位置，音频硬件加速单元将把解码数据写入其中。
4. 指定输出缓冲区的最大长度。

此外，调用者必须指定 `streamIndex` 和 `frameCount` 值。如果需要把所有解码数据都拷贝到输出缓冲区，则可将 `frameCount` 值设为大于或等于数据包中编码帧数的任意值（例如，对于一个 20 ms 的数据包，`frameCount` 可以在 960 到 0xFFFFFFFF 之间取任意值）。

```cpp theme={null}
XApuDecodeConvertCommand command = {};
command.id.streamIndex = 0;
command.id.type = XApuCommandType::Process;
command.id.sequence = packetIndex;
command.frameCount = 0xFFFFFFFF;
command.inputData = memoryManager.GetRawInputBuffer(inputMaxByteCount);
command.inputDataLength = packetLength;
command.outputData = memoryManager.GetRawOutputBuffer(outputMaxByteCount);
command.maxOutputDataLength = outputMaxByteCount;

hr = XApuEnqueueCommand(xapuHandle, &command.id, nullptr);
```

接下来，应调用 [XApuDequeueResult](/reference/audio/xapu/functions/xapudequeueresult) 获取该数据包的解码输出。成功取回 [XApuResult](/reference/audio/xapu/structs/xapuresult) 后，输出数据会存放在 `result.outputData` 中。处理完后，应通过新的一次 [XApuEnqueueCommand](/reference/audio/xapu/functions/xapuenqueuecommand) 调用（携带 [XApuCommandType::Process](/reference/audio/xapu/enums/xapucommandtype) 命令）提交下一个数据包进行解码。

```cpp theme={null}
XApuResult result = {};

do {
    hr = XApuDequeueResult(handle, &result);
    if (SUCCEEDED(hr))
    {
         if (result.id.type == XApuCommandType::Process)
         {
              fwrite(result.outputData, 1, result.outputDataLength, fileOutput);
         }
    }
    
} while (hr == XAPU_E_PENDING_RESULTS);
```

当流中所有数据包都解码完成后，应提交一个 [XApuCommandType::Deactivate](/reference/audio/xapu/enums/xapucommandtype) 命令。

```cpp theme={null}
XApuCommandId id;
id.type = XApuCommandType::Deactivate;
id.streamIndex = 0;
id.sequence = 0;

hr = XApuEnqueueCommand(xapuHandle, &id, nullptr);

do {
    hr = XApuDequeueResult(handle, &result);
} while (hr == XAPU_E_PENDING_RESULTS);
```

## 终止

收到停用结果后，调用者必须调用 [XApuDisconnect](/reference/audio/xapu/functions/xapudisconnect) 与音频硬件加速单元断开连接，以释放所有已分配的资源。

```cpp theme={null}
hr = XApuDisconnect(xapuHandle);
```


## Related topics

- [XBOX Series X|S 音频硬件概述](/zh-CN/build/console-features/audio/overviews/scarlett-audio.md)
- [XAPU 概述](/zh-CN/build/console-features/audio/overviews/xapu-overview.md)
- [使用 XDSP API 进行单流 FFT/IFFT 概述](/zh-CN/build/console-features/audio/overviews/xdsp-overview-single-stream-fft-ifft.md)
- [使用 XDSP API 进行单流卷积概述](/zh-CN/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution.md)
- [概述](/zh-CN/build/console-features/audio/overviews/index.md)
