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

# Manipulación de audio en tiempo real

> Tutorial para inspeccionar y aplicar efectos de audio en tiempo real a las secuencias de voz de Game Chat 2 mediante la canalización de manipulación de audio en su título del GDK de XBOX.

Este tema contiene un breve tutorial sobre el uso de la manipulación de audio en tiempo real.

Game Chat 2 le ofrece la opción de insertarse en la canalización de audio del chat para inspeccionar y manipular los datos de audio del chat de los usuarios.
Esto puede resultar útil para aplicar efectos de audio interesantes a las voces de los usuarios en el juego.

En Game Chat 2, se interactúa con la canalización de manipulación de audio a través de objetos de secuencia de audio que se pueden sondear para obtener datos de audio.
En lugar de usar devoluciones de llamada, puede usar este modelo para inspeccionar o manipular el audio en el subproceso de procesamiento que le resulte más conveniente.

## Inicialización de la canalización de manipulación de audio

De forma predeterminada, Game Chat 2 no habilita la manipulación de audio en tiempo real.
Para habilitarla, la aplicación debe especificar qué formas de manipulación de audio desea habilitar en [chat\_manager::initialize](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_initialize) estableciendo el parámetro `audioManipulationMode`.

Actualmente, se admiten las siguientes formas de manipulación de audio, que se encuentran en la enumeración [game\_chat\_audio\_manipulation\_mode\_flags](/reference/chat/gamechat2/enums/game_chat_audio_manipulation_mode_flags).

* `game_chat_audio_manipulation_mode_flags::none`: deshabilita la manipulación de audio. Esta es la configuración predeterminada. En este modo, el audio del chat fluye sin interrupciones.
* `game_chat_audio_manipulation_mode_flags::pre_encode_stream_manipulation`: habilita la manipulación de audio previa a la codificación. En este modo, todo el audio de chat generado por los usuarios locales se pasa por la canalización de manipulación de audio antes de codificarse. Aunque la aplicación solo inspeccione los datos de audio del chat y no los manipule, sigue siendo responsabilidad de la aplicación volver a enviar los búferes de audio sin modificar a Game Chat 2 para que se puedan codificar y transmitir.
* `game_chat_audio_manipulation_mode_flags::post_decode_stream_manipulation`: habilita la manipulación de audio posterior a la descodificación. En este modo, todo el audio de chat que se recibe de usuarios remotos se pasa por la canalización de manipulación de audio después de que el receptor lo descodifique, pero antes de que se represente. Aunque la aplicación solo inspeccione los datos de audio del chat y no los manipule, sigue siendo responsabilidad de la aplicación mezclar y volver a enviar los búferes de audio sin modificar a Game Chat 2 para que se puedan representar.

## Procesamiento de los cambios de estado de las secuencias de audio

Game Chat 2 proporciona actualizaciones del estado de las secuencias de audio mediante estructuras [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change).
Estas actualizaciones almacenan información sobre qué secuencia se ha actualizado y cómo se ha actualizado.

Estas actualizaciones se pueden sondear mediante llamadas al par de métodos [chat\_manager::start\_processing\_stream\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_start_processing_stream_state_changes) y [chat\_manager::finish\_processing\_stream\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_finish_processing_stream_state_changes). Proporcionan todas las últimas actualizaciones de estado de secuencia de audio en cola como una matriz de punteros a estructuras [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change). Las aplicaciones deben iterar por la matriz y controlar cada actualización de forma adecuada.

Una vez controladas todas las actualizaciones de [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) disponibles, esa matriz debe devolverse a Game Chat 2 mediante `chat_manager::finish_processing_stream_state_changes()`.
Esto se muestra en el ejemplo siguiente.

```cpp theme={null}
uint32_t streamStateChangeCount;
game_chat_stream_state_change_array streamStateChanges;
chat_manager::singleton_instance().start_processing_stream_state_changes(&streamStateChangeCount, &streamStateChanges);

for (uint32_t streamStateChangeIndex = 0; streamStateChangeIndex < streamStateChangeCount; ++streamStateChangeIndex)
{
    switch (streamStateChanges[streamStateChangeIndex]->state_change_type)
    {
        case game_chat_stream_state_change_type::pre_encode_audio_stream_created:
        {
            HandlePreEncodeAudioStreamCreated(streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream);
            break;
        }

        case Xs::game_chat_2::game_chat_stream_state_change_type::pre_encode_audio_stream_closed:
        {
            HandlePreEncodeAudioStreamClosed(streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream);
            break;
        }

        ...
    }
}
chat_manager::singleton_instance().finish_processing_stream_state_changes(streamStateChanges);
```

## Manipulación de datos de audio de chat previos a la codificación

Game Chat 2 proporciona acceso a los datos de audio de chat previos a la codificación de los usuarios locales mediante la clase [pre\_encode\_audio\_stream](/reference/chat/gamechat2/classes/pre_encode_audio_stream/pre_encode_audio_stream).

### Duración de la secuencia

Cuando una nueva instancia de [pre\_encode\_audio\_stream](/reference/chat/gamechat2/classes/pre_encode_audio_stream/pre_encode_audio_stream) está lista para que la use la aplicación, se entrega mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::pre_encode_audio_stream_created`.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la secuencia de audio queda disponible para la manipulación de audio previa a la codificación.

Cuando una [pre\_encode\_audio\_stream](/reference/chat/gamechat2/classes/pre_encode_audio_stream/pre_encode_audio_stream) existente deja de estar disponible para la manipulación de audio, se notifica a la aplicación mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::pre_encode_audio_stream_closed`.
Esta es la oportunidad de la aplicación para empezar a limpiar los recursos asociados a esta secuencia de audio.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la secuencia de audio deja de estar disponible para la manipulación de audio previa a la codificación.

Cuando una [pre\_encode\_audio\_stream](/reference/chat/gamechat2/classes/pre_encode_audio_stream/pre_encode_audio_stream) cerrada tiene todos sus recursos devueltos, la secuencia se destruye y se notifica a la aplicación mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::pre_encode_audio_stream_destroyed`.
Debe limpiarse cualquier referencia o puntero a esta secuencia.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la memoria de la secuencia de audio pasa a ser no válida.

### Usuarios de la secuencia

La lista de usuarios asociados a una secuencia se puede inspeccionar mediante [pre\_encode\_audio\_stream::get\_users()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_get_users).

### Formatos de audio

El formato de audio de los búferes que la aplicación recupera de Game Chat 2 se puede inspeccionar mediante [pre\_encode\_audio\_stream::get\_pre\_processed\_format()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_get_pre_processed_format). El formato de audio preprocesado es mono.
La aplicación debe estar preparada para controlar datos representados como valores float de 32 bits, enteros de 16 bits y enteros de 32 bits.

La aplicación debe informar a Game Chat 2 del formato de audio de los búferes manipulados que se le envían para su codificación y transmisión mediante [pre\_encode\_audio\_stream::set\_processed\_format()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_set_processed_format). Los formatos procesados de las secuencias de audio previas a la codificación deben cumplir las siguientes condiciones previas.

* El formato debe ser mono.
* El formato debe ser PCM (contador del Monitor de rendimiento) float de 32 bits, PCM de enteros de 32 bits o PCM de enteros de 16 bits.
* La frecuencia de muestreo del formato debe cumplir las condiciones previas según su plataforma. XBOX One ERA y XBOX Series X|S admiten frecuencias de muestreo de 8 KHz, 12 KHz, 16 KHz y 24 KHz. La Plataforma universal de Windows (UWP) para XBOX One y PC con Windows admite frecuencias de muestreo de 8 KHz, 12 KHz, 16 KHz, 24 KHz, 32 KHz, 44,1 KHz y 48 KHz.

### Recuperación y envío de audio previo a la codificación

Las aplicaciones pueden consultar en las secuencias de audio previas a la codificación el número de búferes disponibles para procesar mediante [pre\_encode\_audio\_stream::get\_available\_buffer\_count()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_get_available_buffer_count). Esta información se puede usar si la aplicación desea retrasar el procesamiento de audio hasta que haya disponible un número mínimo de búferes.

Solo se pondrán en cola 10 búferes en cada secuencia de audio previa a la codificación, y los retrasos de audio introducirán latencia en la canalización de audio. Se recomienda que las aplicaciones vacíen sus secuencias de audio previas a la codificación antes de poner en cola más de 4 búferes.

#### Recuperación de búferes de audio con get\_next\_buffer()

Las aplicaciones pueden recuperar búferes de audio de una secuencia de audio previa a la codificación mediante [pre\_encode\_audio\_stream::get\_next\_buffer()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_get_next_buffer).
Los nuevos búferes de audio están disponibles, en promedio, una vez cada 40 ms.

Los búferes devueltos por este método deben liberarse en [pre\_encode\_audio\_stream::return\_buffer()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_return_buffer) cuando se termine de usarlos.

Puede existir un máximo de 10 búferes en cola o sin devolver en un momento dado para una secuencia de audio previa a la codificación.
Una vez alcanzado este límite, los nuevos búferes capturados del origen de audio del usuario se descartan hasta que se devuelvan algunos de los búferes pendientes.

#### Envío de búferes de audio con submit\_buffer()

Las aplicaciones pueden volver a enviar a Game Chat 2 los búferes de audio inspeccionados y manipulados para su codificación y transmisión mediante [pre\_encode\_audio\_stream::submit\_buffer()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_submit_buffer). Game Chat 2 admite la manipulación de audio en contexto (in-place) y fuera de contexto (out-of-place). Los búferes enviados a `pre_encode_audio_stream::submit_buffer()` no tienen que ser necesariamente los mismos búferes que se recuperaron de `pre_encode_audio_stream::get_next_buffer()`.

La privacidad y los privilegios de estos búferes enviados se aplican en función de los usuarios asociados a esta secuencia.
Cada 40 ms, se codifican y transmiten los siguientes 40 ms de audio de esta secuencia.

Para evitar interrupciones de audio, los búferes del audio que deba escucharse de forma continua deben enviarse a esta secuencia a un ritmo constante.

### Contextos de secuencia

Las aplicaciones pueden administrar valores de contexto personalizados del tamaño de un puntero en las secuencias de audio previas a la codificación mediante [pre\_encode\_audio\_stream::set\_custom\_stream\_context()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_set_custom_stream_context) y [pre\_encode\_audio\_stream::custom\_stream\_context()](/reference/chat/gamechat2/classes/pre_encode_audio_stream/methods/pre_encode_audio_stream_custom_stream_context). Estos contextos de secuencia personalizados resultan útiles para crear asignaciones entre las secuencias de audio de Game Chat 2 y datos auxiliares. Por ejemplo, metadatos de la secuencia y el estado del juego.

### Ejemplo

A continuación se muestra un ejemplo simplificado de un extremo a otro de cómo usar secuencias de audio previas a la codificación en un fotograma de procesamiento de audio.

```cpp theme={null}
uint32_t streamStateChangeCount;
game_chat_stream_state_change_array streamStateChanges;
chat_manager::singleton_instance().start_processing_stream_state_changes(&streamStateChangeCount, &streamStateChanges);

for (uint32_t streamStateChangeIndex = 0; streamStateChangeIndex < streamStateChangeCount; ++streamStateChangeIndex)
{
    switch (streamStateChanges[streamStateChangeIndex]->state_change_type)
    {
        case game_chat_stream_state_change_type::pre_encode_audio_stream_created:
        {
            pre_encode_audio_stream* stream = streamStateChanges[streamStateChangeIndex]->pre_encode_audio_stream;
            stream->set_processed_audio_format(...);
            stream->set_custom_stream_context(...);
            HandlePreEncodeAudioStreamCreated(stream);
            break;
        }

        case game_chat_2::game_chat_stream_state_change_type::pre_encode_audio_stream_closed:
        {
            HandlePreEncodeAudioStreamClosed(streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream);
            break;
        }

        case game_chat_2::game_chat_stream_state_change_type::pre_encode_audio_stream_destroyed:
        {
            HandlePreEncodeAudioStreamDestroyed(streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream);
            break;
        }

        ...
    }
}
chat_manager::singleton_instance().finish_processing_stream_state_changes(streamStateChanges);

uint32_t preEncodeAudioStreamCount;
pre_encode_audio_stream_array preEncodeAudioStreams;
chat_manager::singleton_instance().get_pre_encode_audio_streams(&preEncodeAudioStreamCount, &preEncodeAudioStreams);
for (uint32_t preEncodeAudioStreamIndex = 0; preEncodeAudioStreamIndex < preEncodeAudioStreamCount; ++preEncodeAudioStreamIndex)
{
    pre_encode_audio_stream* stream = preEncodeAudioStreams[preEncodeAudioStreamIndex];
    StreamContext* context = reinterpret_cast<StreamContext*>(stream->custom_stream_context());

    game_chat_audio_format audio_format = stream->get_pre_processed_format();

    uint32_t preProcessedBufferByteCount;
    void* preProcessedBuffer;
    stream->get_next_buffer(&preProcessedBufferByteCount, &preProcessedBuffer);

    while (preProcessedBuffer != nullptr)
    {
        void* processedBuffer = nullptr;
        switch (audio_format.bits_per_sample)
        {
            case 16:
            {
                assert (audio_format.sample_type == game_chat_sample_type::integer);
                processedBuffer = ManipulateChatBuffer<int16_t>(preProcessedBufferByteCount, preProcessedBuffer, context);
                break;
            }

            case 32:
            {
                switch (audio_format.sample_type)
                {
                    case game_chat_sample_type::integer:
                    {
                        processedBuffer = ManipulateChatBuffer<int32_t>(preProcessedBufferByteCount, preProcessedBuffer, context);
                        break;
                    }

                    case game_chat_sample_type::ieee_float:
                    {
                        processedBuffer = ManipulateChatBuffer<float>(preProcessedBufferByteCount, preProcessedBuffer, context);
                        break;
                    }

                    default:
                    {
                        assert(false);
                        break;
                    }
                }
                break;
            }

            default:
            {
                assert(false);
                break;
            }
        }
        // processedBuffer can be the same as preProcessedBuffer (in-place manipulation) or it can be a buffer of
        // memory not managed by Game Chat 2 (out-of-place manipulation).
        stream->submit_buffer(processedBuffer);
        // Only return buffers retrieved from Game Chat 2. Don't return foreign memory to return_buffer.
        stream->return_buffer(preProcessedBuffer);
        stream->get_next_buffer(&preProcessedBufferByteCount, &preProcessedBuffer);
    }
}

Sleep(audioProcessingPeriodInMilliseconds);
```

## Manipulación de datos de audio de chat posteriores a la descodificación

Game Chat 2 proporciona acceso a los datos de audio de chat posteriores a la descodificación mediante las clases [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) y [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream). Esto significa que los usuarios pueden manipular el audio de los usuarios remotos de forma única para cada receptor local del audio del chat.

### Orígenes y receptores

A diferencia de la canalización previa a la codificación, el modelo para trabajar con datos de audio posteriores a la descodificación se divide en dos clases: [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) y [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream).

El audio descodificado de los usuarios remotos se puede recuperar de los objetos [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream), manipular y enviar a los objetos [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream) para su representación.
Esto permite la integración entre la canalización de procesamiento de audio posterior a la descodificación de Game Chat 2 y middleware de audio útil.

### Duración de la secuencia

Cuando una nueva instancia de [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) o [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream) está lista para que la use la aplicación, se entrega mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::post_decode_audio_source_stream_created` o `game_chat_stream_state_change_type::post_decode_audio_sink_stream_created`, respectivamente.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la secuencia de audio queda disponible para la manipulación de audio posterior a la descodificación.

Cuando una [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) o [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream) existente deja de estar disponible para la manipulación de audio, se notifica a la aplicación mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::post_decode_audio_source_stream_closed` o `game_chat_stream_state_change_type::post_decode_audio_sink_stream`, respectivamente.
Esta es la oportunidad de la aplicación para empezar a limpiar los recursos asociados a esta secuencia de audio.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la secuencia de audio deja de estar disponible para la manipulación de audio posterior a la descodificación.
En el caso de las secuencias de origen, esto significa que no se pondrán más búferes en cola para su manipulación.
En el caso de las secuencias de receptor, esto significa que los búferes enviados ya no se representarán.

Cuando una [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) o [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream) cerrada tiene todos sus recursos devueltos, la secuencia se destruye y se notifica a la aplicación mediante una estructura [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change) con su campo `state_change_type` establecido en `game_chat_stream_state_change_type::post_decode_audio_source_stream_destroyed` o `game_chat_stream_state_change_type::post_decode_audio_sink_stream_destroyed`, respectivamente.
Debe limpiarse cualquier referencia o puntero a esta secuencia.
Después de devolver este cambio de estado de secuencia a Game Chat 2, la memoria de la secuencia de audio pasa a ser no válida.

### Usuarios de la secuencia

La lista de usuarios remotos asociados a una secuencia de origen posterior a la descodificación se puede inspeccionar mediante [post\_decode\_audio\_source\_stream::get\_users()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_get_users).

La lista de usuarios locales asociados a una secuencia de receptor posterior a la descodificación se puede inspeccionar mediante [post\_decode\_audio\_sink\_stream::get\_users()](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/methods/post_decode_audio_sink_stream_get_users).

### Formatos de audio

El formato de audio de los búferes que la aplicación recupera de Game Chat 2 se puede inspeccionar mediante [post\_decode\_audio\_source\_stream::get\_pre\_processed\_format()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_get_pre_processed_format). El formato de audio preprocesado es siempre PCM mono de enteros de 16 bits.

La aplicación debe informar a Game Chat 2 del formato de audio de los búferes manipulados que se le envían para su representación mediante [post\_decode\_audio\_sink\_stream::set\_processed\_format()](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/methods/post_decode_audio_sink_stream_set_processed_format). Los formatos procesados de las secuencias de receptor de audio posteriores a la descodificación deben cumplir las siguientes condiciones previas.

* El formato debe tener menos de 64 canales.
* El formato debe ser PCM de enteros de 16 bits (óptimo), PCM de enteros de 20 bits (en un contenedor de 24 bits), PCM de enteros de 24 bits, PCM de enteros de 32 bits o PCM float de 32 bits (formato preferido después del PCM de enteros de 16 bits).
* La frecuencia de muestreo del formato debe estar entre 1000 y 200 000 muestras por segundo.

### Recuperación y envío de audio posterior a la codificación

Las aplicaciones pueden consultar en las secuencias de origen de audio posteriores a la descodificación el número de búferes disponibles para procesar mediante [post\_decode\_audio\_source\_stream::get\_available\_buffer\_count()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_get_available_buffer_count).
Esta información se puede usar si la aplicación desea retrasar el procesamiento de audio hasta que haya disponible un número mínimo de búferes.
Solo se ponen en cola 10 búferes en cada secuencia de origen de audio posterior a la descodificación, y los retrasos de audio introducen latencia en la canalización de audio. Se recomienda que las aplicaciones vacíen sus secuencias de audio posteriores a la descodificación antes de poner en cola más de 4 búferes.

#### Recuperación de búferes de audio con get\_next\_buffer()

Las aplicaciones pueden recuperar búferes de audio de una secuencia de origen de audio posterior a la descodificación mediante [post\_decode\_audio\_source\_stream::get\_next\_buffer()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_get_next_buffer). Los nuevos búferes de audio están disponibles, en promedio, una vez cada 40 ms.

Los búferes devueltos por este método deben liberarse en [post\_decode\_audio\_source\_stream::return\_buffer()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_return_buffer) cuando se termine de usarlos.

Puede existir un máximo de 10 búferes en cola o sin devolver en un momento dado para una secuencia de origen de audio posterior a la descodificación.
Una vez alcanzado este límite, los nuevos búferes descodificados del usuario remoto se descartan hasta que se devuelvan algunos de los búferes pendientes.

#### Envío de búferes de audio con submit\_buffer()

Las aplicaciones pueden volver a enviar a Game Chat 2 los búferes inspeccionados y manipulados a través de las secuencias de receptor de audio posteriores a la descodificación para su representación mediante [post\_decode\_audio\_sink\_stream::submit\_mixed\_buffer()](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/methods/post_decode_audio_sink_stream_submit_mixed_buffer).
Game Chat 2 admite la manipulación de audio en contexto (in-place) y fuera de contexto (out-of-place). Los búferes enviados a `post_decode_audio_sink_stream::submit_mixed_buffer()` no tienen que ser necesariamente los mismos búferes que se recuperaron de [post\_decode\_audio\_source\_stream::get\_next\_buffer()](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_get_next_buffer).

Cada 40 ms, se representan los siguientes 40 ms de audio de esta secuencia.
Para evitar interrupciones de audio, los búferes del audio que deba escucharse de forma continua deben enviarse a esta secuencia a un ritmo constante.

### Privacidad y mezcla

Debido al modelo de origen-receptor de la canalización posterior a la descodificación, es responsabilidad de la aplicación mezclar los búferes recuperados de los objetos [post\_decode\_audio\_source\_stream](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/post_decode_audio_source_stream) y enviar los búferes mezclados a los objetos [post\_decode\_audio\_sink\_stream](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/post_decode_audio_sink_stream) para su representación. Esto también significa que es responsabilidad de la aplicación realizar la mezcla aplicando correctamente la privacidad y los privilegios.
Game Chat 2 proporciona [post\_decode\_audio\_sink\_stream::can\_receive\_audio\_from\_source\_stream()](/reference/chat/gamechat2/classes/post_decode_audio_sink_stream/methods/post_decode_audio_sink_stream_can_receive_audio_from_source_stream) para que la consulta de esta información sea sencilla y eficiente.

### Indicadores de chat

La manipulación de audio posterior a la descodificación no afecta al estado del indicador de chat de cada usuario.
Por ejemplo, cuando un usuario remoto está silenciado, el audio se proporciona a la aplicación. Sin embargo, el indicador de chat de ese usuario remoto sigue indicando que está silenciado.

Cuando un usuario remoto está hablando, se proporciona su audio. Sin embargo, el indicador de chat indica que está hablando, independientemente de si la aplicación proporciona una mezcla de audio que contenga audio de ese usuario.
Para obtener más información sobre la interfaz de usuario y el indicador de chat, consulte [Uso de Game Chat 2](/services/xbox-services/multiplayer/chat/game-chat2/using-game-chat-2#ui).

Si se usan restricciones adicionales específicas de la aplicación para determinar qué usuarios están presentes en una mezcla de audio, es responsabilidad de la aplicación tener en cuenta esas mismas restricciones al leer los indicadores de chat que proporciona Game Chat 2.

### Contextos de secuencia

Las aplicaciones pueden administrar valores de contexto personalizados del tamaño de un puntero en las secuencias de audio posteriores a la descodificación mediante los métodos [post\_decode\_audio\_source\_stream::set\_custom\_stream\_context](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_set_custom_stream_context) y [post\_decode\_audio\_source\_stream::custom\_stream\_context](/reference/chat/gamechat2/classes/post_decode_audio_source_stream/methods/post_decode_audio_source_stream_custom_stream_context).
Estos contextos de secuencia personalizados resultan útiles para crear asignaciones entre las secuencias de audio de Game Chat 2 y datos auxiliares. Por ejemplo, metadatos de la secuencia y el estado del juego.

### Ejemplo

A continuación se muestra un ejemplo simplificado de un extremo a otro de cómo usar secuencias de audio posteriores a la descodificación en un fotograma de procesamiento de audio.

```cpp theme={null}
uint32_t streamStateChangeCount;
game_chat_stream_state_change_array streamStateChanges;
chat_manager::singleton_instance().start_processing_stream_state_changes(&streamStateChangeCount, &streamStateChanges);

for (uint32_t streamStateChangeIndex = 0; streamStateChangeIndex < streamStateChangeCount; ++streamStateChangeIndex)
{
    switch (streamStateChanges[streamStateChangeIndex]->state_change_type)
    {
        case game_chat_stream_state_change_type::post_decode_audio_source_stream_created:
        {
            post_decode_audio_source_stream* stream = streamStateChanges[streamStateChangeIndex]->post_decode_audio_source_stream;
            stream->set_custom_stream_context(...);
            HandlePostDecodeAudioSourceStreamCreated(stream);
            break;
        }

        case game_chat_stream_state_change_type::post_decode_audio_source_stream_closed:
        {
            HandlePostDecodeAudioSourceStreamClosed(stream);
            break;
        }

        case game_chat_stream_state_change_type::post_decode_audio_source_stream_destroyed:
        {
            HandlePostDecodeAudioSourceStreamDestroyed(stream);
            break;
        }

        case game_chat_stream_state_change_type::post_decode_audio_sink_stream_created:
        {
            post_decode_audio_sink_stream* stream = streamStateChanges[streamStateChangeIndex]->post_decode_audio_sink_stream;
            stream->set_custom_stream_context(...);
            stream->set_processed_format(...);
            HandlePostDecodeAudioSinkStreamCreated(stream);
            break;
        }

        case game_chat_stream_state_change_type::post_decode_audio_sink_stream_closed:
        {
            HandlePostDecodeAudioSinkStreamClosed(stream);
            break;
        }

        case game_chat_stream_state_change_type::post_decode_audio_sink_stream_destroyed:
        {
            HandlePostDecodeAudioSinkStreamDestroyed(stream);
            break;
        }

        ...
    }
}

chat_manager::singleton_instance().finish_processing_stream_state_changes(streamStateChanges);

uint32_t sourceStreamCount;
post_decode_audio_source_stream_array sourceStreams;
chatManager::singleton_instance().get_post_decode_audio_source_streams(&sourceStreamCount, &sourceStreams);

uint32_t sinkStreamCount;
post_decode_audio_sink_stream_array sinkStreams;
chatManager::singleton_instance().get_post_decode_audio_sink_streams(&sinkStreamCount, &sinkStreams);

//
// MixBuffer is a custom type defined as:
// struct MixBuffer
// {
//     uint32_t bufferByteCount;
//     void* buffer;
// };
//
std::vector<std::pair<post_decode_audio_source_stream*, MixBuffer>> cachedSourceBuffers;

for (uint32_t sourceStreamIndex = 0; sourceStreamIndex < sourceStreamCount; ++sourceStreamIndex)
{
    post_decode_audio_source_stream* sourceStream = sourceStreams[sourceStreamIndex];

    MixBuffer mixBuffer;
    sourceStream->get_next_buffer(&mixBuffer.bufferByteCount, &mixBuffer.buffer);
    if (buffer != nullptr)
    {
        // Stash the buffer to return after we're done with mixing. If this program was using audio middleware, now
        // would be an appropriate time to plumb the buffer through the middleware.
        cachedSourceBuffer.push_back(std::pair<post_decode_audio_source_stream*, MixBuffer>{sourceStream, mixBuffer});
    }
}

// Loop over each sink stream, perform mixing, and submit.
for (uint32_t sinkStreamIndex = 0; sinkStreamIndex < sinkStreamCount; ++sinkStreamIndex)
{
    post_decode_audio_sink_stream* sinkStream = sinkStreams[sinkStreamIndex];

    if (sinkStream->is_open())
    {
        std::vector<std::pair<MixBuffer, float>> buffersToMixForThisStream;

        for (const std::pair<post_decode_audio_source_stream, MixBuffer>& sourceBufferPair : cachedSourceBuffers)
        {
            float volume;
            if (sinkStream->can_receive_audio_from_source_stream(sourceBufferPair.first, &volume))
            {
                buffersToMixForThisStream.push_back(std::pair<MixBuffer, float>{sourceBufferPair.second, volume});
            }
        }

        if (buffersToMixForThisStream.size() > 0)
        {
            uint32_t mixedBufferByteCount;
            uint8_t* mixedBuffer;
            MixPostDecodeBuffers(buffersToMixForThisStream, &mixedBufferByteCount, &mixedBuffer);
            sinkStream->submit_mixed_buffer(mixedBufferByteCount, mixedBuffer);
        }
    }
}

// Return buffers after mix and submission.
for (const std::pair<post_decode_audio_source_stream*, MixBuffer>& cachedSourceBuffer : cachedSourceBuffers)
{
    post_decode_audio_source_stream* sourceStream = cachedSourceBuffer.first;
    void* bufferToReturn = cachedSourceBuffer.second.buffer;
    sourceStream->return_buffer(bufferToReturn);
}

Sleep(audioProcessingPeriodInMilliseconds);
```

<a id="chat-user-lifetimes" />

## Duración de los usuarios de chat

Habilitar la manipulación de audio en tiempo real afecta a la duración de los usuarios de chat.
Si se llama a [chat\_manager::remove\_user(chatUserX)](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_remove_user), el objeto [chat\_user](/reference/chat/gamechat2/classes/chat_user/chat_user) al que apunta `chatUserX` sigue siendo válido hasta que se hayan destruido todas las secuencias de audio que hagan referencia a `chatUserX`.

Considere el escenario siguiente.

```cpp theme={null}
// At some point, a chat user, chatUserX, leaves the game session.
chat_manager::singleton_instance().remove_user(chatUserX);

// chatUserX is still valid, but to avoid further synchronization, prevent non-audio-stream use of chatUserX.
chatUserX = nullptr;

// On the audio processing thread...
uint32_t streamStateChangeCount;
game_chat_stream_state_change_array streamStateChanges;
chat_manager::singleton_instance().start_processing_stream_state_changes(&streamStateChangeCount, &streamStateChanges);
for (uint32_t streamStateChangeIndex = 0; streamStateChangeIndex < streamStateChangeCount; ++streamStateChangeIndex)
{
    switch (streamStateChanges[streamStateChangeIndex]->state_change_type)
    {
        ...

        // All the streams that are associated with chatUserX will close.
        case Xs::game_chat_2::game_chat_stream_state_change_type::pre_encode_audio_stream_closed:
        {
            CleanupPreEncodeAudioStreamResources(streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream);
            break;
        }

        ...
    }
}
chat_manager::singleton_instance().finish_processing_stream_state_changes(streamStateChanges);

// The next time the app processes stream state changes...
uint32_t streamStateChangeCount;
game_chat_stream_state_change_array streamStateChanges;
chat_manager::singleton_instance().start_processing_stream_state_changes(&streamStateChangeCount, &streamStateChanges);
for (uint32_t streamStateChangeIndex = 0; streamStateChangeIndex < streamStateChangeCount; ++streamStateChangeIndex)
{
    switch (streamStateChanges[streamStateChangeIndex]->state_change_type)
    {
        ...

        case Xs::game_chat_2::game_chat_stream_state_change_type::pre_encode_audio_stream_destroyed:
        {
            uint32_t chatUserCount;
            Xs::game_chat_2::chat_user_array chatUsers;
            streamStateChanges[streamStateChangeIndex].pre_encode_audio_stream->get_users(&chatUserCount, &chatUsers);
            assert(chatUserCount != 0);
            for (uint32_t chatUserIndex = 0; chatUserIndex < chatUserCount; ++chatUserIndex)
            {
                // chat_user objects such as chatUserX will still be valid while the destroyed state change is being processed.
                Log(chatUsers[chatUserIndex]->xbox_user_id());
            }
            break;
        }

        ...
    }
}
chat_manager::singleton_instance().finish_processing_stream_state_changes(streamStateChanges);
// After the all destroyed state changes have been processed for all streams associated with chatUserX, its memory will be invalidated.
// Don't call methods on chatUserX. For example, chatUserX->xbox_user_id()
```

## Documentación de referencia de la API

* [Gamechat2 (contenido de la API)](/reference/chat/gamechat2/gamechat2_members)
  * Estructuras
    * [game\_chat\_stream\_state\_change](/reference/chat/gamechat2/structs/game_chat_stream_state_change)

## Consulte también

[Introducción a Game Chat 2](/services/xbox-services/multiplayer/chat/game-chat2/game-chat-2-intro)

[Uso de la API de C++ de Game Chat 2](/services/xbox-services/multiplayer/chat/game-chat2/using-game-chat-2)

[Contenido de la API (GameChat2)](/reference/chat/gamechat2/gamechat2_members)

[Microsoft Game Development Kit](/services/playfab/sdks/platforms/gdk)


## Related topics

- [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)
- [game_chat_sample_type](/es/reference/chat/gamechat2/enums/game_chat_sample_type.md)
- [Uso de la API de C++ de Game Chat 2](/es/services/xbox-services/multiplayer/chat/game-chat2/using-game-chat-2.md)
- [game_chat_audio_manipulation_mode_flags](/es/reference/chat/gamechat2/enums/game_chat_audio_manipulation_mode_flags.md)
- [Notas de la versión de PlayFab Party](/es/services/playfab/multiplayer/networking/release-notes.md)
