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

# Decodificação de áudio Opus de fluxo único com a API XAPU

> Visão geral da decodificação de áudio Opus de fluxo único usando a API XAPU

Neste tópico, vamos percorrer o fluxo de código esperado sobre como usar a decodificação Opus acelerada por hardware em dispositivos XBOX Series X usando um dos exemplos incluídos no Microsoft Game Development Kit (GDK). Esse exemplo se chama `DecodeOne.cpp` e aborda um cenário de decodificação de fluxo único com um cliente.

## Conexão e inicialização do hardware de áudio

A decodificação começa com o estabelecimento de uma conexão com a unidade de aceleração de hardware por meio de [XApuConnect](/pt-BR/reference/audio/xapu/functions/xapuconnect). O chamador define os requisitos da conexão usando [XApuConnectInputParameters](/pt-BR/reference/audio/xapu/structs/xapuconnectinputparameters) para configurar o seguinte:

1. O tipo de processamento (neste caso, [XApuProcessType::DecodeOpus](/pt-BR/reference/audio/xapu/enums/xapuprocesstype)).
2. O número de fluxos (neste caso, 1).
3. A memória total necessária para passar e recuperar os dados de entrada e de saída; neste caso, 1024 para `MaxInputBufferLength` (deve ser igual ou maior que o maior pacote Opus no fluxo). O número também deve ser múltiplo de 16, e 7680. Isso corresponde a 20 ms de dados a 48 K, ou seja, 960 × 2 × sizeof(float) = 7680 para `MaxOutputBufferLength`. A saída também precisa ser múltipla de 16.

Se essa chamada for bem-sucedida, o parâmetro [XApuConnectOutputParameters::baseData](/pt-BR/reference/audio/xapu/structs/xapuconnectoutputparameters) apontará para um local de memória alocado pelo sistema operacional de forma que a unidade de aceleração de hardware possa acessá-lo diretamente, sem marshaling ou cópia adicionais. Essa memória deve ser usada pelo chamador para passar os dados de entrada e recuperar os dados de saída. O exemplo a seguir de um gerenciador de memória simples pode ser usado para definir [XApuConnectInputParameters](/pt-BR/reference/audio/xapu/structs/xapuconnectinputparameters) e particionar [XApuConnectOutputParameters::baseData](/pt-BR/reference/audio/xapu/structs/xapuconnectoutputparameters) em dois ponteiros: um para os dados de entrada e outro para os dados de saída.

```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;
    }
};
```

Veja a seguir o exemplo de código da primeira etapa para estabelecer uma conexão.

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

## Ativação e desativação de fluxos

Depois que a conexão com o dispositivo for estabelecida, o chamador deverá enviar um comando de ativação de fluxo para acionar um único mecanismo de decodificação. O chamador deve especificar o índice do fluxo e a contagem de canais. Somente fluxos mono ou estéreo são permitidos.

O chamador deve chamar [XApuDequeueResult](/pt-BR/reference/audio/xapu/functions/xapudequeueresult) para obter o resultado da ativação. Como [XApuConnectInputParameters::maxQueuedCommandsPerStream](/pt-BR/reference/audio/xapu/structs/xapuconnectinputparameters) está definido como 1 neste exemplo, o chamador precisa aguardar cada resultado antes de enviar o próximo comando. Isso inclui os comandos `Activate`, `Process` e `Deactivate` (para obter detalhes, confira [XApuCommandType](/pt-BR/reference/audio/xapu/enums/xapucommandtype)).

Veja a seguir o código para ativar um fluxo.

```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);
```

Depois que o resultado da ativação for recebido, o chamador poderá começar a enviar pacotes Opus para decodificação. Isso deve ser feito usando o comando [XApuCommandType::Process](/pt-BR/reference/audio/xapu/enums/xapucommandtype). Para cada comando `Process`, o chamador deve fazer o seguinte:

1. Preencher o buffer de entrada com exatamente um pacote Opus.
2. Especificar o tamanho do pacote.
3. Fornecer o local do buffer de saída que será preenchido com os dados decodificados pela unidade de aceleração de hardware de áudio.
4. Especificar o tamanho máximo do buffer de saída.

Além disso, o chamador deve especificar os valores `streamIndex` e `frameCount`. Se for necessário copiar todos os dados decodificados para o buffer de saída, o valor `frameCount` poderá ser definido como qualquer valor igual ou maior que o número de quadros codificados no pacote (por exemplo, para um pacote de 20 ms, `frameCount` pode ser definido entre 960 e 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);
```

Em seguida, [XApuDequeueResult](/pt-BR/reference/audio/xapu/functions/xapudequeueresult) deve ser chamado para obter a saída decodificada do pacote. Depois que [XApuResult](/pt-BR/reference/audio/xapu/structs/xapuresult) for recuperado com êxito, os dados de saída serão armazenados em `result.outputData`. Depois que eles forem processados, o próximo pacote deverá ser enviado para decodificação com uma nova chamada para [XApuEnqueueCommand](/pt-BR/reference/audio/xapu/functions/xapuenqueuecommand) com o comando [XApuCommandType::Process](/pt-BR/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);
```

Depois que todos os pacotes do fluxo forem decodificados, um comando [XApuCommandType::Deactivate](/pt-BR/reference/audio/xapu/enums/xapucommandtype) deverá ser enviado.

```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);
```

## Encerramento

Depois que o resultado da desativação for recebido, o chamador deverá chamar [XApuDisconnect](/pt-BR/reference/audio/xapu/functions/xapudisconnect) para se desconectar da unidade de aceleração de hardware de áudio e liberar todos os recursos alocados.

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


## Related topics

- [Convolução de fluxo único com envelope usando a API XDSP](/pt-BR/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution-with-envelope.md)
- [Visão geral da XAPU](/pt-BR/build/console-features/audio/overviews/xapu-overview.md)
- [XApuProcessType](/pt-BR/reference/audio/xapu/enums/xapuprocesstype.md)
- [Visão geral do hardware de áudio do XBOX Series X|S](/pt-BR/build/console-features/audio/overviews/scarlett-audio.md)
- [XApuCommandType](/pt-BR/reference/audio/xapu/enums/xapucommandtype.md)
