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

# Uso de la API de C++ de Game Chat 2

> Tutorial de la API de C++ de Game Chat 2 en el GDK de XBOX, que abarca la inicialización, la adición de usuarios, la configuración de canales de chat y los patrones de control de errores.

Este tema proporciona un breve tutorial sobre el uso de la API de C++ de Game Chat 2 para agregar comunicación de voz y texto a su juego.

## Requisitos previos

Game Chat 2 requiere que su proyecto se haya configurado para el GDK. Para obtener más información sobre cómo configurarlo, consulte [Introducción al Microsoft Game Development Kit](https://learn.microsoft.com/gaming/gdk/docs/services/gdk-dev/get-started/get-started-home).

Para compilar Game Chat 2 es necesario incluir el encabezado principal *GameChat2.h*.
Para que la vinculación sea correcta, su proyecto también debe incluir *GameChat2Impl.h* en al menos una unidad de compilación (se recomienda un encabezado precompilado común, ya que estas implementaciones de funciones stub son pequeñas y fáciles de generar como "inline" para el compilador).

La interfaz de Game Chat 2 no requiere que un proyecto elija entre compilar con C++/CX o con C++ tradicional. Se puede usar con cualquiera de los dos. La implementación tampoco produce excepciones como medio de notificación de errores no irrecuperables. Puede consumirla fácilmente desde proyectos sin excepciones, si lo prefiere. Sin embargo, la implementación sí produce excepciones como medio de notificación de errores irrecuperables. (Para obtener más información, consulte la sección [Modelo de errores](/services/xbox-services/multiplayer/chat/game-chat2/using-game-chat-2#FAILURE_MODEL) más adelante en este tema).

## Inicialización

Empiece a interactuar con la biblioteca inicializando la instancia singleton de Game Chat 2 con parámetros que se aplican a la duración de la inicialización del singleton. La instancia singleton se inicializa llamando a [chat\_manager::initialize](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_initialize), como se muestra a continuación.

```cpp theme={null}
chat_manager::singleton_instance().initialize(...);
```

<Note>Debe registrarse para los eventos de suspensión y reanudación mediante `RegisterAppStateChangeNotification`. Al suspender, debe limpiar Game Chat 2 con [chat\_manager::cleanup()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_cleanup). Al reanudar, debe reinicializar Game Chat 2. Podría bloquearse si intenta usarlo a través de un ciclo de suspensión y reanudación.</Note>

<a id="configuring_users" />

## Configuración de usuarios

### Adición de usuarios a su título del Microsoft Game Development Kit (GDK)

Antes de agregar usuarios a la instancia de Game Chat 2, asegúrese de que se hayan agregado al título del GDK.
Esto se hace mediante la [API XUserAddAsync](/reference/system/xuser/functions/xuseraddasync). Para obtener más información sobre el uso de esta API, consulte [Identidad de usuario y XUser](/build/core-features/common/user/player-identity-xuser).

Después de tener el `XUserHandle` del usuario que desea agregar a Game Chat 2, debe obtener el identificador de usuario de XBOX (XUID) del usuario mediante la [API XUserGetId](/reference/system/xuser/functions/xusergetid).
El usuario debe estar en línea y debe contar con el consentimiento del usuario para este paso.

[XUserGetId](/reference/system/xuser/functions/xusergetid) proporciona el XUID como un `uint64_t`. Debe convertir el XUID en un `std::wstring` para usarlo con Game Chat 2.

A continuación se muestra un ejemplo de código que muestra cómo agregar un usuario a Game Chat 2 después de tener un `XUserHandle`.
<Note>Tenga en cuenta que llamar a [XUserResolveIssueWithUiAsync](/reference/system/xuser/functions/xuserresolveissuewithuiasync) muestra un cuadro de diálogo del sistema.</Note>

```cpp theme={null}
HRESULT
AddChatUserFromXUserHandle(
    _In_ XUserHandle user,
    _In_ XTaskQueueHandle queueHandle,
    _Outptr_result_maybenull_ Xs::game_chat_2::chat_user** chatUser
    )
{
    *chatUser = nullptr;
    uint64_t xuid;
    HRESULT hr = XUserGetId(user, &xuid);
    if (hr == E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED)
    {
        XAsyncBlock* asyncBlock = new (std::nothrow) XAsyncBlock;
        if (asyncBlock != nullptr)
        {
            ZeroMemory(asyncBlock, sizeof(*asyncBlock));
            asyncBlock->queue = queueHandle;
            hr = XUserResolveIssueWithUiAsync(user, nullptr, asyncBlock);
            if (SUCCEEDED(hr))
            {
                hr = XAsyncGetStatus(asyncBlock, true);
                if (SUCCEEDED(hr))
                {
                    hr = XUserGetId(user, &xuid);
                }
            }
            delete asyncBlock;
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if (SUCCEEDED(hr))
    {
        try
        {
            std::wstring xuidString = std::to_wstring(xuid);

            // If the user has already been added, this will return the existing user.
            *chatUser = Xs::game_chat_2::chat_manager::singleton_instance().add_local_user(xuidString.c_str());
        }
        catch (const std::bad_alloc&)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    return hr;
}
```

<a id="adding_users_to_game_chat_2" />

### Adición de usuarios a Game Chat 2

Una vez inicializada la instancia, debe agregar los usuarios locales a la instancia de Game Chat 2 mediante [chat\_manager::add\_local\_user](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_add_local_user). En este ejemplo, el usuario A representa un usuario local.

```cpp theme={null}
chat_user* chatUserA = chat_manager::singleton_instance().add_local_user(<user_a_xuid>);
```

A continuación, agregue los usuarios remotos y los identificadores que se usan para representar el "punto de conexión" remoto en el que se encuentra el usuario.
Un *punto de conexión* es una instancia de la aplicación que se ejecuta en un dispositivo remoto.

En este ejemplo, el usuario B está en el punto de conexión X. Los usuarios C y D están en el punto de conexión Y.
Al punto de conexión X se le asigna arbitrariamente el identificador "1". Al punto de conexión Y se le asigna arbitrariamente el identificador "2".

Informe a Game Chat 2 de los usuarios remotos con las siguientes llamadas.

```cpp theme={null}
chat_user* chatUserB = chat_manager::singleton_instance().add_remote_user(<user_b_xuid>, 1);
chat_user* chatUserC = chat_manager::singleton_instance().add_remote_user(<user_c_xuid>, 2);
chat_user* chatUserD = chat_manager::singleton_instance().add_remote_user(<user_d_xuid>, 2);
```

A continuación, configure la relación de comunicación entre cada usuario remoto y el usuario local.
En este ejemplo, suponga que el usuario A y el usuario B están en el mismo equipo. Se permite la comunicación bidireccional.
`c_communicationRelationshipSendAndReceiveAll` es una constante definida en *GameChat2.h* para representar la comunicación bidireccional.

Establezca la relación del usuario A con el usuario B mediante [chat\_user\_local::set\_communication\_relationship](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_set_communication_relationship).

```cpp theme={null}
chatUserA->local()->set_communication_relationship(chatUserB, c_communicationRelationshipSendAndReceiveAll);
```

Suponga que los usuarios C y D son "espectadores" y que se les debe permitir escuchar al usuario A, pero no hablar.
`c_communicationRelationshipSendAll` es una constante definida en *GameChat2.h* para representar esta comunicación unidireccional.

Establezca las relaciones de la manera siguiente.

```cpp theme={null}
chatUserA->local()->set_communication_relationship(chatUserC, c_communicationRelationshipSendAll);
chatUserA->local()->set_communication_relationship(chatUserD, c_communicationRelationshipSendAll);
```

Para ver ejemplos con la configuración de relaciones desde los cuatro usuarios locales, consulte la sección de [escenarios](/services/xbox-services/multiplayer/chat/game-chat2/using-game-chat-2#scenarios) más adelante en este tema.

Si en algún momento hay usuarios remotos que se hayan agregado a la instancia singleton pero que no se hayan configurado para comunicarse con ningún usuario local, no hay problema.
Esto es previsible en escenarios en los que los usuarios están determinando equipos o pueden cambiar arbitrariamente de canal de voz.

Game Chat 2 solo almacena en caché información (por ejemplo, relaciones de privacidad y reputación) de los usuarios que se han agregado a la instancia, por lo que resulta útil informar a Game Chat 2 de todos los usuarios posibles, aunque no puedan hablar con ningún usuario local en un momento determinado.

Por último, suponga que el usuario D ha abandonado el juego y debe quitarse de la instancia local de Game Chat 2.
Esto se puede hacer mediante [chat\_manager::remove\_user](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_remove_user), como se muestra a continuación.

```cpp theme={null}
chat_manager::singleton_instance().remove_user(chatUserD);
```

Llamar a `chat_manager::remove_user()` puede invalidar el objeto de usuario. Si usa la [manipulación de audio en tiempo real](/services/xbox-services/multiplayer/chat/game-chat2/real-time-audio-manipulation), consulte [Duración de los usuarios de chat](/services/xbox-services/multiplayer/chat/game-chat2/real-time-audio-manipulation#chat-user-lifetimes) para obtener más información. De lo contrario, el objeto de usuario se invalida inmediatamente cuando se llama a `chat_manager::remove_user()`. Una restricción sutil sobre cuándo se pueden quitar usuarios se detalla en la sección [Procesamiento de cambios de estado](#processing-state-changes) más adelante en este tema.

<a id="processing_data_frames" />

## Procesamiento de fotogramas de datos

Game Chat 2 no tiene su propia capa de transporte. La aplicación debe proporcionarla.
Este complemento se administra mediante las llamadas regulares y frecuentes de la aplicación al par de métodos [chat\_manager::start\_processing\_data\_frames()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_start_processing_data_frames) y [chat\_manager::finish\_processing\_data\_frames()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_finish_processing_data_frames). Estos métodos son la forma en que Game Chat 2 proporciona datos salientes a la aplicación.

Estos métodos están diseñados para funcionar con rapidez. Se pueden sondear con frecuencia en un subproceso de red dedicado.
Esto proporciona un lugar conveniente para recuperar todos los datos en cola sin preocuparse por la imprevisibilidad de los tiempos de la red ni por la complejidad de las devoluciones de llamada multiproceso.

Cuando se llama a `chat_manager::start_processing_data_frames()`, todos los datos en cola se notifican en una matriz de punteros a estructuras [game\_chat\_data\_frame](/reference/chat/gamechat2/structs/game_chat_data_frame).
Las aplicaciones deben iterar por la matriz, inspeccionar los puntos de conexión de destino y usar la capa de red de la aplicación para entregar los datos a las instancias remotas adecuadas de la aplicación.

Una vez que se haya terminado de usar la matriz con todas las estructuras [game\_chat\_data\_frame](/reference/chat/gamechat2/structs/game_chat_data_frame), la matriz debe devolverse a Game Chat 2 para liberar los recursos llamando a `chat_manager:finish_processing_data_frames()`.
Esto se muestra en el ejemplo siguiente.

```cpp theme={null}
uint32_t dataFrameCount;
game_chat_data_frame_array dataFrames;
chat_manager::singleton_instance().start_processing_data_frames(&dataFrameCount, &dataFrames);
for (uint32_t dataFrameIndex = 0; dataFrameIndex < dataFrameCount; ++dataFrameIndex)
{
    game_chat_data_frame const* dataFrame = dataFrames[dataFrameIndex];

    // Title-written function responsible for sending packet to remote instances of GameChat 2.
    HandleOutgoingDataFrame(
        dataFrame->packet_byte_count,
        dataFrame->packet_buffer,
        dataFrame->target_endpoint_identifier_count,
        dataFrame->target_endpoint_identifiers,
        dataFrame->transport_requirement
        );
}
chat_manager::singleton_instance().finish_processing_data_frames(dataFrames);
```

Cuanto mayor sea la frecuencia con que se procesen los fotogramas de datos, menor será la latencia de audio percibida por el usuario.
El audio se agrupa en fotogramas de datos de 40 ms. Este es el período de sondeo sugerido.

<a id="processing-state-changes" />

## Procesamiento de cambios de estado

Game Chat 2 proporciona actualizaciones a la aplicación, como los mensajes de texto recibidos, mediante las llamadas regulares y frecuentes de la aplicación al par de métodos [chat\_manager::start\_processing\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_start_processing_state_changes) y [chat\_manager::finish\_processing\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_finish_processing_state_changes).
Estos métodos funcionan con rapidez, por lo que se pueden llamar en cada fotograma gráfico de su bucle de representación de la interfaz de usuario.
Esto proporciona un lugar conveniente para recuperar todos los cambios en cola sin preocuparse por la imprevisibilidad de los tiempos de la red ni por la complejidad de las devoluciones de llamada multiproceso.

Cuando se llama a `chat_manager::start_processing_state_changes()`, todas las actualizaciones en cola se notifican en una matriz de punteros a estructuras [game\_chat\_state\_change](/reference/chat/gamechat2/structs/game_chat_state_change).
Las aplicaciones deben iterar por la matriz, inspeccionar la estructura base para conocer su tipo más específico, convertir la estructura base al tipo más detallado correspondiente y, a continuación, controlar esa actualización según corresponda.

Una vez que se haya terminado de usar la matriz con todos los objetos [game\_chat\_state\_change](/reference/chat/gamechat2/structs/game_chat_state_change) disponibles actualmente, la matriz debe devolverse a Game Chat 2 para liberar los recursos llamando a `chat_manager::finish_processing_state_changes()`.
Esto se muestra en el ejemplo siguiente.

```cpp theme={null}
uint32_t stateChangeCount;
game_chat_state_change_array gameChatStateChanges;
chat_manager::singleton_instance().start_processing_state_changes(&stateChangeCount, &gameChatStateChanges);

std::list<Xs::game_chat_2::chat_user*> usersWithPrivilegeIssues;
std::list<Xs::game_chat_2::chat_user*> usersWithPrivilegeCheckIssues;
for (uint32_t stateChangeIndex = 0; stateChangeIndex < stateChangeCount; ++stateChangeIndex)
{
    switch (gameChatStateChanges[stateChangeIndex]->state_change_type)
    {
        case game_chat_state_change_type::text_chat_received:
        {
            HandleTextChatReceived(static_cast<const game_chat_text_chat_received_state_change*>(gameChatStateChanges[stateChangeIndex]));
            break;
        }

        case Xs::game_chat_2::game_chat_state_change_type::transcribed_chat_received:
        {
            HandleTranscribedChatReceived(static_cast<const Xs::game_chat_2::game_chat_transcribed_chat_received_state_change*>(gameChatStateChanges[stateChangeIndex]));
            break;
        }
        case Xs::game_chat_2::game_chat_state_change_type::communication_relationship_adjuster_changed:
        {
            HandleAdjusterChangedStateReceived(static_cast<const Xs::game_chat_2::game_chat_communication_relationship_adjuster_changed_state_change*>(gameChatStateChanges[stateChangeIndex]), usersWithPrivilegeIssues, usersWithPrivilegeCheckIssues);
            break;
        }

        ...
    }
}
chat_manager::singleton_instance().finish_processing_state_changes(gameChatStateChanges);
```

Dado que `chat_manager::remove_user()` invalida inmediatamente la memoria asociada a un objeto de usuario, y los cambios de estado pueden contener punteros a objetos de usuario, no se debe llamar a `chat_manager::remove_user()` mientras se procesan cambios de estado.

## Chat de texto

Para enviar chat de texto, use [chat\_user::chat\_user\_local::send\_chat\_text()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_send_chat_text).
Esto se muestra en el ejemplo siguiente.

```cpp theme={null}
chatUserA->local()->send_chat_text(L"Hello");
```

Game Chat 2 genera un fotograma de datos que contiene este mensaje. Los puntos de conexión de destino del fotograma de datos son los asociados a los usuarios que se han configurado para recibir texto del usuario local.
Cuando los puntos de conexión remotos procesan los datos, el mensaje se expone mediante [game\_chat\_text\_chat\_received\_state\_change](/reference/chat/gamechat2/structs/game_chat_text_chat_received_state_change).

Al igual que con el chat de voz, las restricciones de privilegios y privacidad se respetan en el chat de texto.
Si un par de usuarios se ha configurado para permitir el chat de texto, pero las restricciones de privilegios o privacidad no permiten esa comunicación, el mensaje de texto se descarta.

## Accesibilidad

La accesibilidad requiere admitir la entrada y la visualización de chat de texto.

La entrada de texto es necesaria porque, incluso en plataformas o géneros de juego que históricamente no han tenido un uso generalizado del teclado físico, los usuarios pueden configurar el sistema para usar tecnologías de asistencia de texto a voz.

Del mismo modo, la visualización de texto es necesaria porque los usuarios pueden configurar el sistema para usar voz a texto.

Estas preferencias se pueden detectar en los usuarios locales llamando a los métodos [chat\_user::chat\_user\_local::text\_to\_speech\_conversion\_preference\_enabled()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_text_to_speech_conversion_preference_enabled) y [chat\_user::chat\_user\_local::speech\_to\_text\_conversion\_preference\_enabled()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_speech_to_text_conversion_preference_enabled), respectivamente. Se recomienda habilitar el texto de forma condicional, en función de las preferencias del usuario.

### Texto a voz

Cuando un usuario tiene habilitado el texto a voz, [chat\_user::chat\_user\_local::text\_to\_speech\_conversion\_preference\_enabled()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_text_to_speech_conversion_preference_enabled) devuelve `true`. Cuando se detecta este estado, la aplicación debe proporcionar un método de entrada de texto.

Después de obtener la entrada de texto proporcionada por un teclado real o virtual, pase la cadena al método [chat\_user::chat\_user\_local::synthesize\_text\_to\_speech()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_synthesize_text_to_speech). Game Chat 2 detecta y sintetiza datos de audio basados en la cadena y en la preferencia de voz de accesibilidad del usuario.
Esto se muestra en el ejemplo siguiente.

```cpp theme={null}
chat_userA->local()->synthesize_text_to_speech(L"Hello");
```

El audio que se sintetiza como parte de esta operación se transporta a todos los usuarios que se han configurado para recibir audio de este usuario local.
Si se llama a `chat_user::chat_user_local::synthesize_text_to_speech()` en un usuario que no tiene habilitado el texto a voz, Game Chat 2 no realiza ninguna acción.

### Voz a texto

Cuando un usuario tiene habilitada la conversión de voz a texto, [chat\_user::chat\_user\_local::speech\_to\_text\_conversion\_preference\_enabled()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_speech_to_text_conversion_preference_enabled) devuelve `true`. Cuando se detecta este estado, la aplicación debe estar preparada para proporcionar una interfaz de usuario asociada a los mensajes de chat transcritos. Game Chat 2 transcribe automáticamente el audio de cada usuario remoto y lo expone mediante una estructura [game\_chat\_transcribed\_chat\_received\_state\_change](/reference/chat/gamechat2/structs/game_chat_transcribed_chat_received_state_change).

### Consideraciones de rendimiento de la conversión de voz a texto

Cuando la conversión de voz a texto está habilitada, la instancia de Game Chat 2 de cada dispositivo remoto inicia una conexión WebSocket con el punto de conexión de los servicios de voz.
Cada cliente remoto de Game Chat 2 carga audio en el punto de conexión de los servicios de voz a través de este WebSocket. El punto de conexión de los servicios de voz devuelve ocasionalmente un mensaje de transcripción al dispositivo remoto.
A continuación, el dispositivo remoto envía el mensaje de transcripción (es decir, un mensaje de texto) al dispositivo local. Game Chat 2 entrega el mensaje transcrito a la aplicación para que lo represente.

Por lo tanto, el costo de rendimiento principal de la conversión de voz a texto es el uso de la red.
La mayor parte del tráfico de red es la carga de audio codificado.
El WebSocket carga audio que ya ha sido codificado por Game Chat 2 en la ruta "normal" del chat de voz. La aplicación tiene control sobre la velocidad de bits mediante [chat\_manager::set\_audio\_encoding\_bitrate](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_set_audio_encoding_bitrate).

<a id="ui" />

## Interfaz de usuario

Se recomienda que, en cualquier lugar donde se muestre una interfaz de usuario a los usuarios, especialmente en una lista de gamertags como un marcador, también se muestren iconos de silenciado o hablando como comentarios para el usuario.
Esto se hace llamando a [chat\_user::chat\_indicator()](/reference/chat/gamechat2/classes/chat_user/methods/chat_user_chat_indicator) para recuperar una enumeración [game\_chat\_user\_chat\_indicator](/reference/chat/gamechat2/enums/game_chat_user_chat_indicator) que representa el estado actual e instantáneo del chat de ese usuario. El siguiente ejemplo muestra cómo recuperar el valor del indicador de un objeto [chat\_user](/reference/chat/gamechat2/classes/chat_user/chat_user) al que apunta la variable `chatUserA` para determinar un valor constante de icono concreto que asignar a una variable `iconToShow`.

```cpp theme={null}
switch (chatUserA->chat_indicator())
{
   case game_chat_user_chat_indicator::silent:
   {
       iconToShow = Icon_InactiveSpeaker;
       break;
   }

   case game_chat_user_chat_indicator::talking:
   {
       iconToShow = Icon_ActiveSpeaker;
       break;
   }

   case game_chat_user_chat_indicator::local_microphone_muted:
   {
       iconToShow = Icon_MutedSpeaker;
       break;
   }
   ...
}
```

Se espera que el valor notificado por [chat\_user::chat\_indicator()](/reference/chat/gamechat2/classes/chat_user/methods/chat_user_chat_indicator) cambie con frecuencia, por ejemplo, a medida que los jugadores empiezan y dejan de hablar.
Por ello, está diseñado para permitir que las aplicaciones lo sondeen en cada fotograma de la interfaz de usuario.

## Silenciado

El método [chat\_user::chat\_user\_local::set\_microphone\_muted()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_set_microphone_muted) se puede usar para cambiar el estado de silencio del micrófono de un usuario local. Cuando el micrófono está silenciado, no se captura audio de ese micrófono. Si el usuario está en un dispositivo compartido, como Kinect, el estado de silencio se aplica a todos los usuarios.

El método [chat\_user::chat\_user\_local::microphone\_muted()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_microphone_muted) se puede usar para recuperar el estado de silencio del micrófono de un usuario local. Este método solo refleja si el micrófono del usuario local se ha silenciado por software mediante una llamada a `chat_user::chat_user_local::set_microphone_muted()`. Este método no refleja un silencio controlado por hardware, por ejemplo, mediante un botón de los auriculares del usuario.

No existe ningún método para recuperar el estado de silencio de hardware del dispositivo de audio de un usuario a través de Game Chat 2.

El método [chat\_user::chat\_user\_local::set\_remote\_user\_muted()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_set_remote_user_muted) se puede usar para cambiar el estado de silencio de un usuario remoto en relación con un usuario local concreto. Cuando el usuario remoto está silenciado, el usuario local no oirá ningún audio ni recibirá ningún mensaje de texto del usuario remoto.

## Silencio automático por mala reputación

Normalmente, los usuarios remotos comienzan sin silenciar.
Game Chat 2 inicia a los usuarios en estado silenciado cuando:

1. El usuario remoto no es amigo del usuario local.
2. El usuario remoto tiene una marca de mala reputación.

Cuando los usuarios están silenciados debido a esta operación, `chat_user::chat_indicator()` devuelve `game_chat_user_chat_indicator::reputation_restricted`.
Este estado se invalida con la primera llamada a `chat_user::chat_user_local::set_remote_user_muted()` que incluya al usuario remoto como usuario de destino.

## Privilegios y privacidad

Además de la relación de comunicación configurada por el juego, Game Chat 2 aplica restricciones de privilegios y privacidad.
Game Chat 2 realiza búsquedas de restricciones de privilegios y privacidad cuando se agrega un usuario por primera vez. El `chat_user::chat_indicator()` del usuario siempre devuelve `game_chat_user_chat_indicator::silent` hasta que se hayan completado esas operaciones.

Si la comunicación con un usuario se ve afectada por una restricción de privilegios o privacidad, el `chat_user::chat_indicator()` del usuario devuelve `game_chat_user_chat_indicator::platform_restricted`.
Las restricciones de comunicación de la plataforma se aplican tanto al chat de voz como al de texto. Nunca se dará el caso de que el chat de texto esté bloqueado por una restricción de plataforma pero el chat de voz no, ni viceversa.

[chat\_user::chat\_user\_local::get\_effective\_communication\_relationship()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_get_effective_communication_relationship) se puede usar para ayudar a distinguir cuándo los usuarios no pueden comunicarse debido a operaciones de privilegios y privacidad incompletas.
Devuelve la relación de comunicación aplicada por Game Chat 2 en forma de [game\_chat\_communication\_relationship\_flags](/reference/chat/gamechat2/enums/game_chat_communication_relationship_flags) y el motivo por el que la relación puede no ser igual a la relación configurada en forma de una enumeración [game\_chat\_communication\_relationship\_adjuster](/reference/chat/gamechat2/enums/game_chat_communication_relationship_adjuster).

Por ejemplo, si las operaciones de búsqueda siguen en curso, el [game\_chat\_communication\_relationship\_adjuster](/reference/chat/gamechat2/enums/game_chat_communication_relationship_adjuster) será `game_chat_communication_relationship_adjuster::initializing`.
Este método no debe usarse para influir en la interfaz de usuario. (Para obtener más información, consulte la sección [Interfaz de usuario](#ui) anteriormente en este tema).

Si Game Chat 2 encuentra un problema de privilegios, se notificará en el cambio de estado [communication\_relationship\_adjuster\_changed](/reference/chat/gamechat2/structs/game_chat_stream_state_change).

Si Game Chat 2 no puede recuperar el privilegio del usuario por un motivo irrecuperable, se notificará como un ajustador `game_chat_communication_relationship_adjuster::privilege_check_failure`.

Si Game Chat 2 no puede recuperar el privilegio del usuario por un motivo que el usuario podría resolver, se notificará como un ajustador `game_chat_communication_relationship_adjuster::resolve_user_issue`.

Si al usuario le faltan privilegios que podrían resolverse con la interfaz de usuario, se notificará como un ajustador `game_chat_communication_relationship_adjuster::privilege`.

En estos casos, la comunicación estará restringida.

A continuación se muestra un ejemplo de cómo comprobar si un usuario tiene uno de los siguientes problemas comunes.

1. Los usuarios deben dar su consentimiento a los servicios de XBOX para que Game Chat 2 compruebe los privilegios.
2. La cuenta del usuario está configurada para denegar privilegios (por ejemplo, por ser una cuenta infantil y, por tanto, no poder usar el chat).

```cpp theme={null}
void
HandleAdjusterChangedStateReceived (
    _In_ const Xs::game_chat_2::game_chat_communication_relationship_adjuster_changed_state_change* adjusterChange,
    _Inout_ std::list<Xs::game_chat_2::chat_user*>& usersWithPrivilegeIssues,
    _Inout_ std::list<Xs::game_chat_2::chat_user*>& usersWithPrivilegeCheckIssues
    )
{
    Xs::game_chat_2::game_chat_communication_relationship_flags communicationRelationship;
    Xs::game_chat_2::game_chat_communication_relationship_adjuster communicationRelationshipAdjuster;
    adjusterChange->local_user->local()->get_effective_communication_relationship(
        adjusterChange->target_user,
        &communicationRelationship,
        &communicationRelationshipAdjuster);

    if (communicationRelationshipAdjuster == Xs::game_chat_2::game_chat_communication_relationship_adjuster::privilege)
    {
        // The local user has privilege issues.
        usersWithPrivilegeIssues.push_back(adjusterChange->local_user);
    }
    else if (communicationRelationshipAdjuster == Xs::game_chat_2::game_chat_communication_relationship_adjuster::resolve_user_issue)
    {
        // The local user has an issue checking privileges.
        usersWithPrivilegeCheckIssues.push_back(adjusterChange->local_user);
    }
}
```

Para los problemas notificados con el ajustador `game_chat_communication_relationship_adjuster::privilege`, puede llamar a [XUserResolvePrivilegeWithUiAsync](/reference/system/xuser/functions/xuserresolveprivilegewithuiasync) con `XUserPrivilegeOptions::None` y `XUserPrivilege::Communications` para intentar resolver el problema.

Para los problemas notificados con el ajustador `game_chat_communication_relationship_adjuster::resolve_user_issue`, puede llamar a [XUserResolveIssueWithUiAsync](/reference/system/xuser/functions/xuserresolveissuewithuiasync) con `nullptr` como dirección URL para intentar resolver el problema.

Se recomienda mostrar una interfaz de usuario que indique que hay un problema de privilegios. Permita que el usuario decida si desea intentar resolver el problema, ya sea presionando un botón o mediante una opción de menú.

Es posible que el usuario no pueda o no quiera resolver el problema.
Si el usuario resuelve el problema, se aplicará la próxima vez que se agregue el usuario a Game Chat 2.

<Note>No se debe llamar a [chat\_manager::remove\_user()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_remove_user) mientras se procesan cambios de estado (es decir, después de llamar a [chat\_manager::start\_processing\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_start_processing_state_changes) y antes de la llamada correspondiente a [chat\_manager::finish\_processing\_state\_changes()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_finish_processing_state_changes)). Llamar a `chat_manager::remove_user()` mientras se procesan cambios de estado puede invalidar la memoria asociada al usuario quitado.
Si ve un ajustador `game_chat_communication_relationship_adjuster::privilege` y desea intentar resolver los privilegios del usuario, debe esperar hasta después de procesar los cambios de estado para intentarlo.</Note>

Para obtener el `XUserHandle` a partir de un XUID, que es necesario para llamar a `XUserResolvePrivilegeWithUiAsync`, puede usar la API [XUserFindUserById](/reference/system/xuser/functions/xuserfinduserbyid) para obtener un nuevo `XUserHandle`. Como alternativa, puede conservar el que adquirió con [XUserAddAsync](/reference/system/xuser/functions/xuseraddasync) y realizar un seguimiento de a qué XUID se asigna.

A continuación se muestra un ejemplo de cómo resolver estos problemas.

```cpp theme={null}
// If we got an Xs::game_chat_2::game_chat_communication_relationship_adjuster::resolve_user_issue,
// we need to try and fix our issue, if we haven't already, and then remove and re-add that user.
for (Xs::game_chat_2::chat_user* localUser : usersWithPrivilegeCheckIssues)
{
    auto asyncBlock = std::make_unique<XAsyncBlock>();
    ZeroMemory(asyncBlock.get(), sizeof(*asyncBlock));
    asyncBlock->queue = g_asyncQueue;

    XUserHandle userHandle;
    hr = XUserFindUserById(localUser->local()->xbox_user_id(), &userHandle);
    if (SUCCEEDED(hr))
    {
        hr = XUserResolveIssueWithUiAsync(
            userHandle,
            nullptr,
            asyncBlock.get());
        if (SUCCEEDED(hr))
        {
            hr = XAsyncGetStatus(asyncBlock.get(), true);
            if (SUCCEEDED(hr))
            {
                // Remove and re-add the user after fixing the privileges.
                // Users must not be removed while processing state changes.
            }
            asyncBlock.release();
        }
    }
}

// If we got an Xs::game_chat_2::game_chat_communication_relationship_adjuster::resolve_user_privilege,
// we need to try and resolve the privileges, if we haven't already, and then remove and re-add that user.
for (Xs::game_chat_2::chat_user* localUser : usersWithPrivilegeIssues)
{
    auto asyncBlock = std::make_unique<XAsyncBlock>();
    ZeroMemory(asyncBlock.get(), sizeof(*asyncBlock));
    asyncBlock->queue = g_asyncQueue;

    XUserHandle userHandle;
    hr = XUserFindUserById(localUser->local()->xbox_user_id(), &userHandle);
    if (SUCCEEDED(hr))
    {
        hr = XUserResolvePrivilegeWithUiAsync(
            userHandle,
            XUserPrivilegeOptions::None,
            XUserPrivilege::Communications,
            asyncBlock.get());
        if (SUCCEEDED(hr))
        {
            hr = XAsyncGetStatus(asyncBlock.get(), true);
            if (SUCCEEDED(hr))
            {
                // Remove and re-add the user after fixing the privileges.
                // Users must not be removed while processing state changes.
            }
            asyncBlock.release();
        }
    }
}
```

## Limpieza

Cuando la aplicación ya no necesite las comunicaciones a través de Game Chat 2, debe llamar a [chat\_manager::cleanup()](/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_cleanup).
Esto permite que Game Chat 2 recupere los recursos que se asignaron para administrar las comunicaciones.

<a id="FAILURE_MODEL" />

## Modelo de errores

La implementación de Game Chat 2 no produce excepciones como medio de notificación de errores no irrecuperables. Puede consumirla fácilmente desde proyectos sin excepciones, si lo prefiere.
Sin embargo, Game Chat 2 sí produce excepciones para informarle de errores irrecuperables.

Estos errores son el resultado de un uso incorrecto de la API, como agregar un usuario a la instancia de Game Chat antes de inicializar la instancia o acceder a un objeto de usuario después de que se haya quitado de la instancia de Game Chat 2.

Se espera que estos errores se detecten al principio del desarrollo y se puedan corregir modificando el patrón que se usa para interactuar con Game Chat 2.
Cuando se produce un error de este tipo, se imprime en el depurador una sugerencia sobre la causa del error antes de que se genere la excepción.

<a id="scenarios" />

## Cómo configurar escenarios populares

### Pulsar para hablar

La funcionalidad de pulsar para hablar debe implementarse con [chat\_user::chat\_user\_local::set\_microphone\_muted()](/reference/chat/gamechat2/classes/chat_user/chat_user_local/methods/chat_user_local_set_microphone_muted).
Llame a `set_microphone_muted(false)` para permitir la voz y a `set_microphone_muted(true)` para restringirla.
Este método proporciona la respuesta de menor latencia de Game Chat 2.

### Equipos

Suponga que el usuario A y el usuario B están en el equipo azul, y que el usuario C y el usuario D están en el equipo rojo.
Cada usuario está en una instancia única de la aplicación.

En el dispositivo del usuario A:

```cpp theme={null}
chatUserA->local()->set_communication_relationship(chatUserB, c_communicationRelationshipSendAndReceiveAll);
chatUserA->local()->set_communication_relationship(chatUserC, game_chat_communication_relationship_flags::none);
chatUserA->local()->set_communication_relationship(chatUserD, game_chat_communication_relationship_flags::none);
```

En el dispositivo del usuario B:

```cpp theme={null}
chatUserB->local()->set_communication_relationship(chatUserA, c_communicationRelationshipSendAndReceiveAll);
chatUserB->local()->set_communication_relationship(chatUserC, game_chat_communication_relationship_flags::none);
chatUserB->local()->set_communication_relationship(chatUserD, game_chat_communication_relationship_flags::none);
```

En el dispositivo del usuario C:

```cpp theme={null}
chatUserC->local()->set_communication_relationship(chatUserA, game_chat_communication_relationship_flags::none);
chatUserC->local()->set_communication_relationship(chatUserB, game_chat_communication_relationship_flags::none);
chatUserC->local()->set_communication_relationship(chatUserD, c_communicationRelationshipSendAndReceiveAll);
```

En el dispositivo del usuario D:

```cpp theme={null}
chatUserD->local()->set_communication_relationship(chatUserA, game_chat_communication_relationship_flags::none);
chatUserD->local()->set_communication_relationship(chatUserB, game_chat_communication_relationship_flags::none);
chatUserD->local()->set_communication_relationship(chatUserC, c_communicationRelationshipSendAndReceiveAll);
```

### Difusión

Suponga que el usuario A es el líder y da órdenes. Los usuarios B, C y D solo pueden escuchar.
Cada jugador está en un dispositivo único.

En el dispositivo del usuario A:

```cpp theme={null}
chatUserA->local()->set_communication_relationship(chatUserB, c_communicationRelationshipSendAll);
chatUserA->local()->set_communication_relationship(chatUserC, c_communicationRelationshipSendAll);
chatUserA->local()->set_communication_relationship(chatUserD, c_communicationRelationshipSendAll);
```

En el dispositivo del usuario B:

```cpp theme={null}
chatUserB->local()->set_communication_relationship(chatUserA, c_communicationRelationshipReceiveAll);
chatUserB->local()->set_communication_relationship(chatUserC, game_chat_communication_relationship_flags::none);
chatUserB->local()->set_communication_relationship(chatUserD, game_chat_communication_relationship_flags::none);
```

En el dispositivo del usuario C:

```cpp theme={null}
chatUserC->local()->set_communication_relationship(chatUserA, c_communicationRelationshipReceiveAll);
chatUserC->local()->set_communication_relationship(chatUserB, game_chat_communication_relationship_flags::none);
chatUserC->local()->set_communication_relationship(chatUserD, game_chat_communication_relationship_flags::none);
```

En el dispositivo del usuario D:

```cpp theme={null}
chatUserD->local()->set_communication_relationship(chatUserA, c_communicationRelationshipReceiveAll);
chatUserD->local()->set_communication_relationship(chatUserB, game_chat_communication_relationship_flags::none);
chatUserD->local()->set_communication_relationship(chatUserC, game_chat_communication_relationship_flags::none);
```

## Documentación de referencia de la API

* [Gamechat2 (contenido de la API)](/reference/chat/gamechat2/gamechat2_members)
  * Estructuras
    * [game\_chat\_data\_frame](/reference/chat/gamechat2/structs/game_chat_data_frame)
    * [game\_chat\_state\_change](/reference/chat/gamechat2/structs/game_chat_state_change)
    * [game\_chat\_text\_chat\_received\_state\_change](/reference/chat/gamechat2/structs/game_chat_text_chat_received_state_change)
    * [game\_chat\_transcribed\_chat\_received\_state\_change](/reference/chat/gamechat2/structs/game_chat_transcribed_chat_received_state_change)
    * [communication\_relationship\_adjuster\_changed](/reference/chat/gamechat2/structs/game_chat_stream_state_change)
* [xuser (contenido de la API)](/reference/system/xuser/xuser_members)
  * Funciones
    * [xuseraddasync](/reference/system/xuser/functions/xuseraddasync)
    * [xusergetid](/reference/system/xuser/functions/xusergetid)
    * [XUserResolveIssueWithUiAsync](/reference/system/xuser/functions/xuserresolveissuewithuiasync)
    * [XUserResolvePrivilegeWithUiAsync](/reference/system/xuser/functions/xuserresolveprivilegewithuiasync)
    * [XUserFindUserById](/reference/system/xuser/functions/xuserfinduserbyid)

## Consulte también

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

[Manipulación de audio en tiempo real](/services/xbox-services/multiplayer/chat/game-chat2/real-time-audio-manipulation)

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

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


## Related topics

- [Game chat2](/es/services/xbox-services/multiplayer/chat/game-chat2/index.md)
- [chat_manager::singleton_instance](/es/reference/chat/gamechat2/classes/chat_manager/methods/chat_manager_singleton_instance.md)
- [game_chat_audio_encoding_bitrate](/es/reference/chat/gamechat2/enums/game_chat_audio_encoding_bitrate.md)
- [game_chat_text_chat_received_state_change](/es/reference/chat/gamechat2/structs/game_chat_text_chat_received_state_change.md)
- [game_chat_transcribed_chat_received_state_change](/es/reference/chat/gamechat2/structs/game_chat_transcribed_chat_received_state_change.md)
