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

# Aplicar efeitos de voz personalizados com manipulação de áudio em tempo real

> Use os fluxos de manipulação de áudio em tempo real do PlayFab Party para interceptar buffers de chat de voz e aplicar efeitos personalizados, como áudio espacial e filtros de voz.

O PlayFab Party é uma solução de rede e chat de voz em tempo real. Quando configurado para chat de voz, o PlayFab Party transmite o áudio do microfone e o reproduz sem modificações. Alguns jogos precisam de acesso aos buffers de áudio do chat de voz para implementar efeitos de áudio personalizados, como áudio espacial ou filtros de voz. Este documento fornece um passo a passo de como usar o recurso de manipulação de áudio em tempo real para interceptar e modificar o áudio do chat de voz no PlayFab Party.

## Pré-requisitos

Este passo a passo pressupõe que você tenha familiaridade básica com o [chat de voz no PlayFab Party](/pt-BR/services/playfab/community/voice-communications/concepts-chat).

## Suporte a plataformas

A manipulação de áudio em tempo real não está disponível em todas as plataformas. Embora os métodos associados à manipulação de áudio em tempo real estejam presentes no cabeçalho unificado e multiplataforma, no momento eles são implementados somente para Windows, XBOX e PlayStation® 5. Os métodos retornarão erros em outras plataformas.

## Fluxos de áudio

A manipulação de áudio em tempo real introduz o conceito de fluxos de áudio para recuperar áudio da biblioteca ou enviar áudio a ela. Há dois tipos de fluxos de áudio. O primeiro é o **fluxo de origem**. Um fluxo de origem é usado para recuperar áudio de um controle de chat. Cada controle de chat pode ter apenas um único fluxo de origem, chamado de **fluxo de voz**. Para um controle de chat local, ele é usado para recuperar a entrada do microfone; para um controle de chat remoto, ele é usado para recuperar o áudio de voz recebido. Se o fluxo de voz existir para um controle de chat, a biblioteca redirecionará o áudio de origem desse controle de chat para o fluxo de voz em vez de processar o áudio automaticamente. Para um controle de chat local, isso significa redirecionar o áudio do microfone para o fluxo de voz em vez de codificá-lo e transmiti-lo automaticamente; para um controle de chat remoto, isso significa redirecionar o áudio de voz recebido para o fluxo de voz em vez de enviá-lo automaticamente a cada controle de chat local para ser reproduzido. Os fluxos de origem são representados por [`PartyAudioManipulationSourceStream`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/partyaudiomanipulationsourcestream).

O segundo tipo de fluxo é o **fluxo de coletor**. Um fluxo de coletor é usado para enviar áudio a um controle de chat. Somente controles de chat locais podem ter fluxos de coletor, e cada um pode ter dois. Eles são chamados de **fluxo de captura** e **fluxo de renderização**. Se o fluxo de captura existir para um controle de chat, a biblioteca obterá o áudio do fluxo de captura para codificar e transmitir a outros controles de chat em vez do microfone. Se o fluxo de renderização existir para um controle de chat, a biblioteca obterá o áudio do fluxo de renderização e o reproduzirá *além do* áudio do chat de voz que é reproduzido automaticamente a partir de controles de chat remotos. O áudio enviado ao fluxo de captura é usado como a entrada de microfone do controle de chat local; o áudio enviado ao fluxo de renderização é reproduzido ou "renderizado" no dispositivo de saída de áudio do controle de chat local. Os fluxos de coletor são representados por [`PartyAudioManipulationSinkStream`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSinkStream/partyaudiomanipulationsinkstream).

### Configurando fluxos de áudio

Por padrão, a biblioteca cuida da recuperação, do transporte e da reprodução do áudio. Portanto, os controles de chat são criados sem nenhum fluxo de áudio. Você pode criar um ou mais fluxos para um controle de chat por meio dos métodos de configuração de fluxo - [`PartyLocalChatControl::ConfigureAudioManipulationCaptureStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_configureaudiomanipulationcapturestream), [`PartyLocalChatControl::ConfigureAudioManipulationRenderStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_configureaudiomanipulationrenderstream) e [`PartyChatControl::ConfigureAudioManipulationVoiceStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyChatControl/methods/partychatcontrol_configureaudiomanipulationvoicestream). Depois de configurado, um fluxo pode ser recuperado posteriormente por meio de [`PartyLocalChatControl::GetAudioManipulationCaptureStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_getaudiomanipulationcapturestream), [`PartyLocalChatControl::GetAudioManipulationRenderStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyLocalChatControl/methods/partylocalchatcontrol_getaudiomanipulationrenderstream) e [`PartyChatControl::GetAudioManipulationVoiceStream()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyChatControl/methods/partychatcontrol_getaudiomanipulationvoicestream)

Cada método de configuração de fluxo permite especificar o formato do áudio que você recuperará do fluxo ou enviará a ele. Para obter mais informações sobre os formatos com suporte, consulte a documentação de referência de cada método de configuração de fluxo.

### Recuperando áudio de um fluxo de origem

Você pode recuperar áudio de um fluxo de origem por meio de [`PartyAudioManipulationSourceStream::GetNextBuffer()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_getnextbuffer). Quando uma atividade de voz é detectada, um novo buffer fica disponível aproximadamente a cada 40 ms. Se nenhum buffer estiver disponível, a chamada será bem-sucedida e fornecerá um buffer de comprimento zero. O número total de buffers disponíveis instantaneamente pode ser recuperado por meio de [`PartyAudioManipulationSourceStream::GetAvailableBufferCount()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_getavailablebuffercount).

Para maior eficiência, `GetNextBuffer()` fornece um buffer que aponta para a memória da biblioteca em vez de copiar o buffer inteiro. Opcionalmente, ele pode ser modificado no local. Quando terminar de processar um buffer, você deverá liberá-lo por meio de [`PartyAudioManipulationSourceStream::ReturnBuffer()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSourceStream/methods/partyaudiomanipulationsourcestream_returnbuffer) para que a biblioteca possa recuperar sua memória. Vários buffers podem ser recuperados antes que qualquer um seja devolvido, e os buffers não precisam ser devolvidos na ordem em que foram recuperados.

### Enviar áudio para um fluxo de coletor

Você pode enviar áudio para um fluxo de coletor por meio de [`PartyAudioManipulationSinkStream::SubmitBuffer()`](/pt-BR/services/playfab/multiplayer/networking/reference/classes/PartyAudioManipulationSinkStream/methods/partyaudiomanipulationsinkstream_submitbuffer). O buffer é copiado pela biblioteca e pode ser liberado imediatamente após a conclusão da chamada.

A cada 40 ms, a biblioteca consome 40 ms do áudio que foi enviado ao fluxo de coletor. Para evitar falhas no áudio, o áudio deve ser enviado a uma taxa constante.

## Cenários

### Manipulação do áudio do microfone, também conhecida como manipulação de buffer pré-codificação

A manipulação do áudio do microfone é o ato de interceptar e alterar o áudio do microfone antes que ele seja transmitido a outros controles de chat. Às vezes, isso é chamado de "manipulação de buffer pré-codificação", porque o áudio do microfone é modificado antes de ser codificado e transmitido a outros controles de chat. Se você quiser implementar esse cenário para um controle de chat local, primeiro configure um fluxo de voz e um fluxo de captura para o controle de chat local. Depois de configurados, uma função chamada a cada tique de um thread de áudio dedicado para processar o áudio do microfone desse único controle de chat pode ser semelhante à seguinte.

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

### Manipulação de áudio remoto, também conhecida como manipulação de buffer pós-decodificação

A manipulação de áudio remoto é o ato de interceptar e alterar o áudio recebido antes que ele seja renderizado para cada controle de chat local. Às vezes, isso é chamado de "manipulação de buffer pós-decodificação", porque o áudio recebido é modificado depois de ser decodificado, mas antes de ser renderizado. Se você quiser implementar esse cenário, primeiro configure o fluxo de voz para cada controle de chat remoto e o fluxo de renderização para cada controle de chat local. Em seguida, a cada tique, seu thread de áudio deve obter o áudio de cada fluxo de voz, mixar o áudio em um único fluxo enquanto aplica efeitos opcionalmente e enviar o buffer mixado para cada fluxo de renderização. Dependendo do cenário do seu jogo, talvez seja necessário mixar os buffers em fluxos diferentes para cada controle de chat local. Uma função chamada a cada tique de um thread de áudio dedicado para processar o áudio de voz recebido pode ser semelhante à seguinte.

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

#### Considerações sobre privacidade e mixagem

A biblioteca fornecerá áudio por meio do fluxo de voz de um controle de chat remoto desde que o controle de chat remoto esteja gerando áudio e as configurações de [permissão de chat](/pt-BR/services/playfab/community/voice-communications/concepts-chat-permissions-and-muting#chat-permissions) e de [mudo](/pt-BR/services/playfab/community/voice-communications/concepts-chat-permissions-and-muting#muting) permitam que o áudio seja reproduzido por pelo menos um controle de chat local. Se o áudio tiver de ser reproduzido para um controle de chat local, mas não para outro, você deverá omiti-lo da mixagem de áudio desse último controle de chat.

#### Considerações sobre o indicador de chat

Configurar um fluxo de voz para um controle de chat remoto não afetará seu [indicador de chat](/pt-BR/services/playfab/community/voice-communications/concepts-audio-troubleshooting#check-the-chat-indicators). Talvez seja necessário implementar uma lógica para conciliar as diferenças entre o indicador de chat e sua lógica de mixagem a fim de escolher o indicador de interface do usuário correto. Por exemplo, o indicador de chat pode indicar que o controle de chat está falando, mas uma lógica de mixagem personalizada pode optar por descartar o áudio.

### Cenários mistos

Em alguns cenários, talvez você queira habilitar a manipulação de áudio para alguns controles de chat, mas não para outros. Por exemplo, talvez você queira aplicar efeitos aos jogadores adversários encontrados durante uma partida, mas não aos jogadores da mesma equipe. Nesse cenário, você pode seguir as etapas descritas anteriormente para a manipulação de áudio remoto, configurando um fluxo de voz somente para os controles de chat aos quais deseja aplicar efeitos de áudio. O áudio dos controles de chat remotos restantes será renderizado automaticamente para os controles de chat locais, desde que as configurações de mudo e de permissão permitam.


## Related topics

- [Notas de versão do PlayFab Party](/pt-BR/services/playfab/multiplayer/networking/release-notes.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)
- [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)
- [Visão geral de acessibilidade no GDK](/pt-BR/build/game-principles/accessibility/accessibility-overview.md)
