Voice Moderation with Photon Voice
Introduction
If your application uses integrated voice chat, you may need to add moderation to meet local privacy and compliance requirements. While Photon does not provide a built-in moderation service, it supports secure server-to-server integrations with trusted providers:
A server-to-server integration offers the following advantages compared to client-side solutions:
- Increased security: Prevents client-side manipulation of moderation features.
- Optimized bandwidth usage: Eliminates redundant client-to-service streams and avoids transmitting muted streams from the server to clients.
To enable external moderation, configure the service credentials in the Photon Dashboard. Photon Cloud will automatically forward the voice streams to the selected provider’s API endpoint.
Keep in mind:
- You need a paid account with the moderation provider.
- Bandwidth usage of your app on Photon Cloud will increase depending on your voice quality settings.
- All streams are sent securely via HTTPS directly to the provider. Photon does not log or store any audio data.
How to setup Voice Moderation for your Photon Voice app
Note: A paid Photon Cloud plan greater 100 CCU is required to activate voice moderation forwarding
Step 1: Create an account and subscribe to the voice moderation service of your choice. Make sure you’ll have all required information at hand (see config details below).
Step 2: Contact us via email to [email protected] and ask to unlock the voice moderation feature.
Step 3: Go to dashboard.photonengine.com, “YOUR > APPS > Premium Cloud” and click on “Manage” in your Voice application box.
Step 4: In the Plugins section, activate either the ToxMod or GGWP config by clicking on the “Create [...] Plugin” button and enter all required information to the config
Although ToxMod and GGWP configuration and features are similar, there are some differences.
ToxMod
ApiKey
The API key used to authenticate within the voice moderation service
AccountId
Name of the account used to authenticate with ToxMod API
IsActive
Can be used to temporarily disable the service without removing the plugin setup.
SingleTenantPrefix
This value is provided by Modulate.AI to be used as additional information within their API. Usually it is empty.
GGWP
ApiKey
The API key used to authenticate within the voice moderation service
IsActive
Can be used to temporarily disable the service without removing the plugin setup.
Additional options for Enterprise Customers
The Photon Voice Moderation integration is based on the battle-tested Photon Server Plugin-architecture (doc.photonengine.com/server/current/plugins/manual). It offers a valuable set of additional features for Enterprise customers in their Private Cloud environment. If you are interested in operating your own plugin, please contact us via mail: [email protected].
Overview
Server-to-Server integration and additional features using the Enterprise custom plugin
ForwardPercentage
Percentage of rooms that are forwarded to the voice moderation service. GGWP expects to use lower numbers for testing purposes. ToxMod does expect to always have 100%.
UseAnonIDs
Indicates whether anonymized UserIDs and SessionIDs are used when forwarding to voice moderation service. Works currently for GGWP only. ToxMod requires to use UUID values, so it is always anonymized (using a method designed by them)
MutePollInterval
Interval in milliseconds, how often to ask HTTP service for a list of muted users. 5000 is the default value.
MutePollUrl
URL of the HTTP service that provides a list of muted users (customer's backend)
The mute poll configuration expects a HTTP service that provides a list of players who are globally muted (this can be used for moderation). Each request is a POST request with application/json content in format:
{users:[
—-Comma separated list of UserIDs of currently active users—-
]}
And the response would again be a application/json array of UserIDs, that are muted:
[user1,user2,...]
Enterprise Client Features
Clients can provide muting and proximity data to the plugin. It uses RaiseEvent operation, with a s system command event code - 220. The expected data is an object array with 3 fields.
- First field is a byte value indicating the subcode of the operation
- 2 = UpdateMute
- 3 = UpdateProximity
- Second field is an integer or string array - a list of players (ActorNrs or UserIds)
- Third optional field is an operation type,
- 0 or not set means Set operation - the list of players is set as a value for muted players or players in proximity,
- 1 is Remove - players from the list are removed from muted players or players in proximity
- 2 is Add - players from the list are added to muted players or players in proximity
Here is a code snippet for PhotonTransport.cs of PhotonVoice SDK, to simplify the client-server communication regarding muting and proximity.
C#
#if USE_VOICE_PLUGIN
public void AddToProximity(IEnumerable<int> playersInProximity)
{
this.UpdateProximity(playersInProximity, CommandEventMethod.Add);
}
public void RemoveFromProximity(IEnumerable<int> playersInProximity)
{
this.UpdateProximity(playersInProximity, CommandEventMethod.Remove);
}
public void SetProximity(IEnumerable<int> playersInProximity)
{
this.UpdateProximity(playersInProximity, CommandEventMethod.Set);
}
private void UpdateProximity(IEnumerable<int> playersInProximity, CommandEventMethod method)
{
PluginCommand(CommandEventSubcode.UpdateProximity, playersInProximity, method);
}
public void AddMuted(IEnumerable<int> playersMuted)
{
this.UpdateMuted(playersMuted, CommandEventMethod.Add);
}
public void RemoveMuted(IEnumerable<int> playersMuted)
{
this.UpdateMuted(playersMuted, CommandEventMethod.Remove);
}
public void SetMuted(IEnumerable<int> playersMuted)
{
this.UpdateMuted(playersMuted, CommandEventMethod.Set);
}
private void UpdateMuted(IEnumerable<int> playersMuted, CommandEventMethod method)
{
PluginCommand(CommandEventSubcode.UpdateMute, playersMuted, method);
}
private void PluginCommand(CommandEventSubcode subCode, IEnumerable<int> players, CommandEventMethod method)
{
var data = new object[3];
data[0] = (byte)subCode;
data[1] = players.ToArray();
data[2] = (byte)method;
this.OpRaiseEvent(220, data, RaiseEventOptions.Default, SendOptions.SendReliable);
}
#endif
Back to top