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

# Aplicación de efectos de voz personalizados con manipulación de audio en tiempo real

> Use las secuencias de manipulación de audio en tiempo real de PlayFab Party para interceptar los búferes del chat de voz y aplicar efectos personalizados, como audio espacial y filtros de voz.

PlayFab Party es una solución de redes y chat de voz en tiempo real. Cuando se configura para el chat de voz, PlayFab Party transmite el audio del micrófono y lo reproduce sin modificar. Algunos juegos necesitan acceso a los búferes de audio del chat de voz para implementar efectos de audio personalizados, como audio espacial o filtros de voz. Este documento proporciona un tutorial de cómo usar la característica de manipulación de audio en tiempo real para interceptar y modificar el audio del chat de voz en PlayFab Party.

## Requisitos previos

Este tutorial supone que está básicamente familiarizado con el [chat de voz en PlayFab Party](/services/playfab/community/voice-communications/concepts-chat).

## Compatibilidad con plataformas

La manipulación de audio en tiempo real no está disponible en todas las plataformas. Aunque los métodos asociados con la manipulación de audio en tiempo real están presentes en el encabezado unificado multiplataforma, actualmente solo están implementados para Windows, XBOX y PlayStation® 5. Los métodos devolverán errores en otras plataformas.

## Secuencias de audio

La manipulación de audio en tiempo real introduce el concepto de secuencias de audio para recuperar audio de la biblioteca o enviarle audio. Hay dos tipos de secuencias de audio. El primero es la **secuencia de origen**. Una secuencia de origen se usa para recuperar audio de un control de chat. Cada control de chat solo puede tener una única secuencia de origen, denominada **secuencia de voz**. Para un control de chat local, se usa para recuperar la entrada del micrófono; para un control de chat remoto, se usa para recuperar el audio de voz entrante. Si la secuencia de voz existe para un control de chat, la biblioteca redirigirá el audio de origen de ese control de chat a su secuencia de voz en lugar de gestionar el audio automáticamente. Para un control de chat local, esto significa redirigir el audio del micrófono a la secuencia de voz en lugar de codificarlo y transmitirlo automáticamente; para un control de chat remoto, esto significa redirigir el audio de voz entrante a la secuencia de voz en lugar de enviarlo automáticamente a cada control de chat local para su reproducción. Las secuencias de origen se representan mediante [`PartyAudioManipulationSourceStream`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/partyaudiomanipulationsourcestream).

El segundo tipo de secuencia es la **secuencia de receptor**. Una secuencia de receptor se usa para enviar audio a un control de chat. Solo los controles de chat locales pueden tener secuencias de receptor, y cada uno puede tener dos. Se denominan **secuencia de captura** y **secuencia de representación**. Si la secuencia de captura existe para un control de chat, la biblioteca extraerá el audio de la secuencia de captura para codificarlo y transmitirlo a otros controles de chat en lugar del micrófono. Si la secuencia de representación existe para un control de chat, la biblioteca extraerá el audio de la secuencia de representación y lo reproducirá *además* del audio del chat de voz que se reproduce automáticamente desde los controles de chat remotos. El audio enviado a la secuencia de captura se usa como entrada de micrófono del control de chat local; el audio enviado a la secuencia de representación se reproduce o "representa" en el dispositivo de salida de audio del control de chat local. Las secuencias de receptor se representan mediante [`PartyAudioManipulationSinkStream`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSinkStream/partyaudiomanipulationsinkstream).

### Configuración de secuencias de audio

De forma predeterminada, la biblioteca se encarga de la recuperación, el transporte y la reproducción del audio. Por lo tanto, los controles de chat se crean sin ninguna secuencia de audio. Puede crear una o varias secuencias para un control de chat mediante los métodos de configuración de secuencias: [`PartyLocalChatControl::ConfigureAudioManipulationCaptureStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_configureaudiomanipulationcapturestream), [`PartyLocalChatControl::ConfigureAudioManipulationRenderStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_configureaudiomanipulationrenderstream) y [`PartyChatControl::ConfigureAudioManipulationVoiceStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyChatControl/methods/partychatcontrol_configureaudiomanipulationvoicestream). Una vez configurada, una secuencia puede recuperarse posteriormente mediante [`PartyLocalChatControl::GetAudioManipulationCaptureStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_getaudiomanipulationcapturestream), [`PartyLocalChatControl::GetAudioManipulationRenderStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_getaudiomanipulationrenderstream) y [`PartyChatControl::GetAudioManipulationVoiceStream()`](/services/playfab/multiplayer/networking/reference/classes/PartyChatControl/methods/partychatcontrol_getaudiomanipulationvoicestream)

Cada método de configuración de secuencias le permite especificar el formato del audio que recuperará de la secuencia o que le enviará. Para obtener más información sobre los formatos admitidos, consulte la documentación de referencia de cada método de configuración de secuencias.

### Recuperación de audio de una secuencia de origen

Puede recuperar audio de una secuencia de origen mediante [`PartyAudioManipulationSourceStream::GetNextBuffer()`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_getnextbuffer). Cuando se detecta actividad de voz, habrá un nuevo búfer disponible aproximadamente cada 40 ms. Si no hay búferes disponibles, la llamada se realizará correctamente y proporcionará un búfer de longitud cero. El número total de búferes disponibles en un instante dado se puede recuperar mediante [`PartyAudioManipulationSourceStream::GetAvailableBufferCount()`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_getavailablebuffercount).

Por eficiencia, `GetNextBuffer()` proporciona un búfer que apunta a la memoria de la biblioteca en lugar de copiar todo el búfer. Opcionalmente, se puede modificar en su lugar. Cuando haya terminado de procesar un búfer, debe liberarlo mediante [`PartyAudioManipulationSourceStream::ReturnBuffer()`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_returnbuffer) para que la biblioteca pueda reclamar su memoria. Se pueden recuperar varios búferes antes de devolver alguno, y los búferes no tienen que devolverse en el orden en que se recuperaron.

### Envío de audio a una secuencia de receptor

Puede enviar audio a una secuencia de receptor mediante [`PartyAudioManipulationSinkStream::SubmitBuffer()`](/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSinkStream/methods/partyaudiomanipulationsinkstream_submitbuffer). La biblioteca copia el búfer, que se puede liberar inmediatamente después de completarse la llamada.

Cada 40 ms, la biblioteca consume 40 ms del audio que se ha enviado a la secuencia de receptor. Para evitar interrupciones de audio, el audio debe enviarse a un ritmo constante.

## Escenarios

### Manipulación del audio del micrófono, también conocida como manipulación del búfer antes de la codificación

La manipulación del audio del micrófono es el acto de interceptar y cambiar el audio del micrófono antes de que se transmita a otros controles de chat. A veces se denomina "manipulación del búfer antes de la codificación" porque el audio del micrófono se modifica antes de codificarse y transmitirse a otros controles de chat. Si desea implementar este escenario para un control de chat local, configure primero una secuencia de voz y una secuencia de captura para el control de chat local. Una vez configuradas, una función llamada en cada ciclo de un subproceso de audio dedicado para procesar el audio del micrófono de ese único control de chat podría tener el aspecto siguiente.

```cpp theme={null}
// An app-defined function that takes a microphone buffer and generates a new
// buffer that should be transmitted to other chat controls.
std::vector<uint8_t>
ProcessLocalVoiceBuffer(
    PartyMutableDataBuffer* inputBuffer
    );

void
ProcessLocalMicrophoneAudioForSingleChatControl(
    PartyLocalChatControl* chatControl
    )
{
    // Get the voice stream from which we want to retrieve audio. This provides
    // the audio generated by the chat control's input device.
    PartyAudioManipulationSourceStream* voiceStream;
    RETURN_VOID_IF_FAILED(chatControl->GetAudioManipulationVoiceStream(&voiceStream));

    // Get the capture stream to which we want to submit audio. This is used to
    // submit audio that will be transmitted to other chat controls.
    PartyAudioManipulationSinkStream* captureStream;
    RETURN_VOID_IF_FAILED(chatControl->GetAudioManipulationCaptureStream(&captureStream));

    // Get the next audio buffer from the voice stream.
    PartyMutableDataBuffer buffer;
    RETURN_VOID_IF_FAILED(voiceStream->GetNextBuffer(&buffer));

    // If we retrieved a buffer, process it.
    if (buffer.bufferByteCount > 0)
    {
        // Use the buffer we retrieved to generate a new buffer that will be
        // treated as the "real" capture input and transmitted to other chat
        // controls.
        std::vector<uint8_t> processedBuffer = ProcessLocalVoiceBuffer(&buffer);

        // Convert the buffer to a Party type.
        PartyDataBuffer partyBuffer;
        partyBuffer.bufferByteCount = static_cast<uint32_t>(processedBuffer.size());
        partyBuffer.buffer = processedBuffer.data();

        // Submit the processed buffer to the capture stream.
        PartyError error = captureStream->SubmitBuffer(&partyBuffer);
        if (PARTY_FAILED(error))
        {
            printf("Failed to submit buffer to sink stream! error = 0x%08x", error);
        }

        // Return the original buffer back to the voice stream.
        error = voiceStream->ReturnBuffer(buffer.buffer);
        if (PARTY_FAILED(error))
        {
            printf("Failed to return buffer to source stream! error = 0x%08x", error);
        }
    }
}
```

### Manipulación del audio remoto, también conocida como manipulación del búfer después de la descodificación

La manipulación del audio remoto es el acto de interceptar y cambiar el audio entrante antes de que se represente en cada control de chat local. A veces se denomina "manipulación del búfer después de la descodificación" porque el audio entrante se modifica después de descodificarse pero antes de representarse. Si desea implementar este escenario, configure primero la secuencia de voz para cada control de chat remoto y la secuencia de representación para cada control de chat local. Después, en cada ciclo de su subproceso de audio se debe extraer el audio de cada secuencia de voz, mezclar el audio en una sola secuencia aplicando opcionalmente efectos, y enviar el búfer mezclado a cada secuencia de representación. Según el escenario de su juego, es posible que deba mezclar los búferes en secuencias distintas para cada control de chat local. Una función llamada en cada ciclo de un subproceso de audio dedicado para procesar el audio de voz entrante podría tener el aspecto siguiente.

```cpp theme={null}
// This is an app-defined function that takes a local chat control and list of remote voice buffers and generates
// a single mixed buffer to submit to the local chat control's audio output.
std::vector<uint8_t>
GetOutputMixBuffer(
    PartyLocalChatControl& localChatControl,
    const std::map<PartyAudioManipulationSourceStream*, PartyMutableDataBuffer>& remoteVoiceBuffers
    );

void
ProcessRemoteVoiceAudio(
    const std::vector<PartyChatControl*>& remoteChatControls,
    const std::vector<PartyLocalChatControl*>& localChatControls
    )
{
    std::map<PartyAudioManipulationSourceStream*, PartyMutableDataBuffer> remoteVoiceBuffers;

    // Acquire voice buffers from each remote chat control.
    for (auto remoteChatControl : remoteChatControls)
    {
        // Get the voice stream for this chat control from which we will retrieve audio.
        PartyAudioManipulationSourceStream* voiceStream;
        PartyError error = remoteChatControl->GetAudioManipulationVoiceStream(&voiceStream);
        if (PARTY_FAILED(error))
        {
            printf("Failed to get voice stream! error = 0x%08x", error);
            continue;
        }

        // Get the next audio buffer from the voice stream.
        PartyMutableDataBuffer buffer;
        error = voiceStream->GetNextBuffer(&buffer);
        if (PARTY_FAILED(error))
        {
            printf("Failed to get next buffer! error = 0x%08x", error);
            continue;
        }

        // If we retrieved a buffer, cache it in the map for mixing.
        if (buffer.bufferByteCount > 0)
        {
            remoteVoiceBuffers[voiceStream] = buffer;
        }
    }

    // If we didn't acquire any source buffers, we don't have anything to mix.
    if (remoteVoiceBuffers.empty())
    {
        return;
    }

    // Mix the voice buffers and submit to each render stream.
    for (auto localChatControl : localChatControls)
    {
        // Get the render stream for this chat control to which we will submit audio.
        PartyAudioManipulationSinkStream* renderStream;
        PartyError error = localChatControl->GetAudioManipulationRenderStream(&renderStream);
        if (PARTY_FAILED(error))
        {
            printf("Failed to get render stream! error = 0x%08x", error);
            continue;
        }

        // Mix the buffers the buffers to generate a new, mixed buffer.
        std::vector<uint8_t> mixedBuffer = GetOutputMixBuffer(*localChatControl, remoteVoiceBuffers);

        // Convert the buffer to a party type.
        PartyDataBuffer partyBuffer;
        partyBuffer.bufferByteCount = static_cast<uint32_t>(mixedBuffer.size());
        partyBuffer.buffer = mixedBuffer.data();

        // Submit the mixed buffer to the render stream.
        error = renderStream->SubmitBuffer(&partyBuffer);
        if (PARTY_FAILED(error))
        {
            printf("Failed to submit buffer to render stream! error = 0x%08x", error);
        }
    }

    // Release the voice buffers.
    for (auto voiceBuffer : remoteVoiceBuffers)
    {
        // Return the voice buffer that we had cached from this voice stream.
        PartyError error = voiceBuffer.first->ReturnBuffer(voiceBuffer.second.buffer);
        if (PARTY_FAILED(error))
        {
            printf("Failed to return buffer! error = 0x%08x", error);
        }
    }
}
```

#### Consideraciones sobre privacidad y mezcla

La biblioteca proporcionará audio a través de la secuencia de voz de un control de chat remoto siempre que el control de chat remoto genere audio y las configuraciones de [permisos de chat](/services/playfab/community/voice-communications/concepts-chat-permissions-and-muting#chat-permissions) y [silencio](/services/playfab/community/voice-communications/concepts-chat-permissions-and-muting#muting) permitan que el audio lo reproduzca al menos un control de chat local. Si el audio debe reproducirse para un control de chat local pero no para otro, debe omitirlo de la mezcla de audio del segundo control de chat.

#### Consideraciones sobre los indicadores de chat

Configurar una secuencia de voz para un control de chat remoto no afectará a su [indicador de chat](/services/playfab/community/voice-communications/concepts-audio-troubleshooting#check-the-chat-indicators). Es posible que deba implementar lógica para conciliar las diferencias entre el indicador de chat y su lógica de mezcla, a fin de elegir el indicador de interfaz de usuario correcto. Por ejemplo, el indicador de chat podría indicar que el control de chat está hablando, pero la lógica de mezcla personalizada podría optar por descartar el audio.

### Escenarios mixtos

En algunos escenarios, podría querer habilitar la manipulación de audio para algunos controles de chat pero no para otros. Por ejemplo, quizá quiera aplicar efectos a los jugadores rivales encontrados durante una partida, pero no a los jugadores del mismo equipo. En tal escenario, puede seguir los pasos descritos anteriormente para la manipulación del audio remoto configurando una secuencia de voz solo para los controles de chat a los que quiera aplicar efectos de audio. El audio de los demás controles de chat remotos se representará automáticamente en los controles de chat locales, siempre que las configuraciones de silencio y permisos lo permitan.


## Related topics

- [Manipulación de audio en tiempo real](/es/services/xbox-services/multiplayer/chat/game-chat2/real-time-audio-manipulation.md)
- [Notas de la versión de PlayFab Party](/es/services/playfab/multiplayer/networking/release-notes.md)
- [Características de PlayFab Party](/es/services/playfab/multiplayer/networking/party-features.md)
- [Game chat2](/es/services/xbox-services/multiplayer/chat/game-chat2/index.md)
- [Información general sobre Game Chat 2](/es/services/xbox-services/multiplayer/chat/game-chat2/game-chat-2-overview.md)
