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

# Descodificación de audio Opus de una sola secuencia con la API XAPU

> Información general sobre la descodificación de audio Opus de una sola secuencia mediante la API XAPU

En este tema, recorreremos el flujo de código esperado sobre cómo usar la descodificación acelerada por hardware de Opus en dispositivos XBOX Series X mediante uno de los ejemplos incluidos con el Microsoft Game Development Kit (GDK). Este ejemplo se denomina `DecodeOne.cpp` y cubre un escenario de descodificación de una sola secuencia con un cliente.

## Conexión con el hardware de audio e inicio

La descodificación comienza estableciendo una conexión con la unidad de aceleración de hardware mediante [XApuConnect](/reference/audio/xapu/functions/xapuconnect). El autor de la llamada establece los requisitos de la conexión mediante [XApuConnectInputParameters](/reference/audio/xapu/structs/xapuconnectinputparameters) para configurar lo siguiente:

1. El tipo de procesamiento (en este caso, [XApuProcessType::DecodeOpus](/reference/audio/xapu/enums/xapuprocesstype)).
2. El número de secuencias (en este caso, 1).
3. La memoria total necesaria para pasar y recuperar los datos de entrada y de salida; en este caso, 1024 para `MaxInputBufferLength` (debe ser igual o mayor que el paquete Opus más grande de la secuencia). El número también debe ser múltiplo de 16, y 7680. Esto corresponde a 20 ms de datos a 48 K, es decir, 960 × 2 × sizeof(float) = 7680 para `MaxOutputBufferLength`. La salida también debe ser múltiplo de 16.

Si esta llamada se realiza correctamente, el parámetro [XApuConnectOutputParameters::baseData](/reference/audio/xapu/structs/xapuconnectoutputparameters) apunta a una ubicación de memoria asignada por el sistema operativo de forma que la unidad de aceleración de hardware pueda acceder directamente sin serialización ni copia adicionales. El autor de la llamada debe usar esta memoria para pasar los datos de entrada y recuperar los datos de salida. El siguiente ejemplo de un administrador de memoria sencillo se puede usar para establecer [XApuConnectInputParameters](/reference/audio/xapu/structs/xapuconnectinputparameters) y particionar [XApuConnectOutputParameters::baseData](/reference/audio/xapu/structs/xapuconnectoutputparameters) en dos punteros: uno para los datos de entrada y otro para los datos de salida.

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

A continuación se muestra el ejemplo de código del primer paso para establecer una conexión.

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

## Activación y desactivación de secuencias

Una vez establecida la conexión con el dispositivo, el autor de la llamada debe enviar un comando de activación de secuencia para poner en marcha un único motor de descodificación. El autor de la llamada debe especificar el índice de la secuencia y el número de canales. Solo se permiten secuencias mono o estéreo.

El autor de la llamada debe llamar a [XApuDequeueResult](/reference/audio/xapu/functions/xapudequeueresult) para obtener el resultado de la activación. Como [XApuConnectInputParameters::maxQueuedCommandsPerStream](/reference/audio/xapu/structs/xapuconnectinputparameters) está establecido en 1 en este ejemplo, el autor de la llamada tiene que esperar cada resultado antes de enviar el siguiente comando. Esto incluye los comandos `Activate`, `Process` y `Deactivate` (para obtener más detalles, consulte [XApuCommandType](/reference/audio/xapu/enums/xapucommandtype)).

A continuación se muestra el código para activar una secuencia.

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

Después de recibir el resultado de la activación, el autor de la llamada puede empezar a enviar paquetes Opus para su descodificación. Esto debe hacerse mediante el comando [XApuCommandType::Process](/reference/audio/xapu/enums/xapucommandtype). Para cada comando `Process`, el autor de la llamada debe hacer lo siguiente:

1. Rellenar el búfer de entrada con exactamente un paquete Opus.
2. Especificar la longitud del paquete.
3. Proporcionar la ubicación del búfer de salida que la unidad de aceleración de hardware de audio rellenará con los datos descodificados.
4. Especificar la longitud máxima del búfer de salida.

Además, el autor de la llamada debe especificar los valores `streamIndex` y `frameCount`. Si es necesario copiar todos los datos descodificados en el búfer de salida, el valor `frameCount` se puede establecer en cualquier valor igual o mayor que el número de fotogramas codificados en el paquete (por ejemplo, para un paquete de 20 ms, `frameCount` se puede establecer entre 960 y 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);
```

A continuación, se debe llamar a [XApuDequeueResult](/reference/audio/xapu/functions/xapudequeueresult) para obtener la salida descodificada del paquete. Una vez recuperado correctamente [XApuResult](/reference/audio/xapu/structs/xapuresult), los datos de salida se almacenarán en `result.outputData`. Después de procesarlo, se debe enviar el siguiente paquete para su descodificación con una nueva llamada a [XApuEnqueueCommand](/reference/audio/xapu/functions/xapuenqueuecommand) con el comando [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);
```

Después de descodificar todos los paquetes de la secuencia, se debe enviar un comando [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);
```

## Finalización

Una vez recibido el resultado de la desactivación, el autor de la llamada debe llamar a [XApuDisconnect](/reference/audio/xapu/functions/xapudisconnect) para desconectarse de la unidad de aceleración de hardware de audio y liberar todos los recursos asignados.

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


## Related topics

- [Información general sobre XAPU](/es/build/console-features/audio/overviews/xapu-overview.md)
- [XApuProcessType](/es/reference/audio/xapu/enums/xapuprocesstype.md)
- [Aplicación de efectos de voz personalizados con manipulación de audio en tiempo real](/es/services/playfab/community/voice-communications/concepts-realtime-audio-manipulation.md)
- [Información general sobre el hardware de audio de XBOX Series X|S](/es/build/console-features/audio/overviews/scarlett-audio.md)
- [XApuCommandType](/es/reference/audio/xapu/enums/xapucommandtype.md)
