Unity SDK

Get VoicePatrol up and running seamlessly in Unity

Installation & Setup

Prerequisites

  • Unity 2020.3 LTS or newer
  • Target platforms: Android API 23+, Windows 10+, macOS 10.15+
  • Microphone permissions on target platforms
  • Internet access

Installation Steps

  1. Download the Package
    - Download the VoicePatrol Unity package from your dashboard at dashboard.voicepatrol.dev
  2. Import the Package
    - Right-click in Unity Assets folder → Import
    - Package → Custom Package...
    - Select the VoicePatrol Unity package
  3. Add to Scene
    - Drag the VoicePatrol prefab into your main/startup scene
    - The prefab includes all necessary components and will persist across scenes
  4. Configure Settings
    - Select the VoicePatrol prefab in your scene
    - In the Inspector, enter your API key from the VoicePatrol dashboard
    - Configure optional features (Voice BI, Age Verification, Debug Logs)

Core Concepts

SDK Lifecycle

The VoicePatrol SDK follows a specific lifecycle pattern.

  1. Initialization: SDK starts and establishes server connections
  2. Muted State: SDK begins in muted state (no processing)
  3. Active State: SDK processes audio when unmuted
  4. Room Management: Optional room joining/leaving for context
  5. Shutdown: Proper cleanup when application closes

Audio Processing Pipeline

Microphone Input → Stream to Server → Audio Analysis → Violation Detection → Callback Events

Key Components

VoicePatrolWrapper: Main interface for all SDK operations

  • Static methods for easy access from anywhere in your code
  • Thread-safe event system for violation callbacks
  • Automatic permission handling on Android

AudioCaptureProxy: Captures game audio for analysis

  • Automatically attached to AudioListener components
  • Captures mixed audio output for comprehensive monitoring
  • Required for player reporting features

Permission Manager: Handles microphone permissions

  • Automatic permission requests on Android
  • Graceful degradation when permissions denied
  • Platform-specific implementation

Install Guide

Video Guide (2 minutes)

Basic Integration (5 minutes)

1. Add the VoicePatrol prefab to your scene

2. Initialize in your game manager:

using VoicePatrol.Scripts;

public class GameManager : MonoBehaviour
{
    [SerializeField] private string apiKey = "your-api-key-here";
    
    void Start()
    {
        // Start VoicePatrol with basic settings
        string result = VoicePatrolWrapper.StartVoicePatrol(token: apiKey);        
        Debug.Log($"VoicePatrol: {result}");
    }
}

3. Handle muting based on your voice chat state:

void Start()
{
    // Check voice chat state every second instead of every frame
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    // Example: Mute VoicePatrol when not in voice chat
    bool shouldMute = !IsInVoiceChat() || IsVoiceChatMuted();
    VoicePatrolWrapper.SetMuted(shouldMute);
}

4. Listen for violations:

void OnEnable()
{
    VoicePatrolWrapper.OnViolationDetected += HandleViolation;
}

void OnDisable()
{
    VoicePatrolWrapper.OnViolationDetected -= HandleViolation;
}

private void HandleViolation(VoicePatrolWrapper.ViolationEventData violation)
{
    Debug.Log($"Violation detected for {violation.UniqueId}: {violation.Priority}");
    
    // Take action based on violation
    switch (violation.Priority.ToLower())
    {
        case "severe":
            // Immediate action required
            MutePlayer(violation.UniqueId);
            break;
        case "high":
            // Warning or temporary action
            WarnPlayer(violation.UniqueId);
            break;
        case "medium":
            // Log for review
            LogViolation(violation);
            break;
    }
}

Room Management

// When joining a multiplayer room
void OnJoinedRoom(string roomId)
{
    VoicePatrolWrapper.OnJoinedRoom(roomId);
}

// When leaving a room
void OnLeftRoom()
{
    VoicePatrolWrapper.OnLeftRoom();
}

API Reference

VoicePatrolWrapper Static Methods

StartVoicePatrol

Initializes the VoicePatrol SDK

public static string StartVoicePatrol(
    string token,
    string uniqueID = null,
    bool voiceBI = false,
    bool ageVerification = false,
    bool debugLogs = false
)

Parameters:

  • token: Your VoicePatrol API key from the dashboard
  • uniqueID: Optional custom user identifier (null = device ID)
  • voiceBI: Optional flag to enable Business Intelligence tool
  • ageVerification: Optional flag to enable age verification feature
  • debugLogs: Optional flag to enable detailed debug logging

Returns: Status message indicating initialization result

IsSdkRunning

Checks if the VoicePatrol SDK is currently running

public static string IsSdkRunning()

Returns: True if SDK is running, false otherwise

OnJoinedRoom

Notifies the SDK when joining a multiplayer room

public static string OnJoinedRoom(string roomId)

Parameters:

  • roomId: The unique identifier for the room

Returns: Status message indicating room join result

OnLeftRoom

Notifies the SDK when leaving a multiplayer room

public static string OnLeftRoom()

Returns: Status message indicating room leave result

StopVoicePatrol

Stops the VoicePatrol SDK and releases resources

public static string StopVoicePatrol()

Returns: Status message indicating shutdown result

Do not call this unless explicitly required - instead, use SetMuted to control the state of VoicePatrol.

SetMuted

Toggles voice analysis and usage time incrementation

public static string SetMuted(bool value)

Parameters:

  • value: True to mute, false to unmute

Returns: Status message indicating mute state change result

Setting the muted state is not computationally expensive - it simply sets an internal boolean flag that causes early returns in audio processing functions. You can call SetMuted() frequently without performance concerns.

IsMuted

Checks if VoicePatrol is currently muted

public static bool IsMuted()

Returns: True if muted, false otherwise

ProcessAudioFile

Process a pre-recorded audio clip for testing or analysis

public static string ProcessAudioFile(AudioClip audioClip)

Parameters:

  • audioClip: The audio clip to process

Returns: Status message indicating processing result

Audio clip must be uncompressed or load type set to Decompress On Load.

SubmitPlayerReport

Submit the last 60 seconds of game audio as evidence for manual review

public static string SubmitPlayerReport(string reportedUniqueID)

Parameters:

  • reportedUniqueID: The unique identifier of the player being reported

Returns: Status message indicating whether the report submission started successfully

SetMetadata

Attach custom JSON-serializable metadata (max 200 bytes) to audio submissions

public static string SetMetadata(T metadata)

Parameters:

  • metadata: The JSON-serializable data

Returns: Status message indicating setting result

Example:

var metadata = new {
    playerLevel = 42,
    gameMode = "Competitive",
    mapName = "Dust2",
    teamSize = 5
};
VoicePatrolWrapper.SetMetadata(metadata);

Event System

Violation Detection

public static event Action OnViolationDetected;

public struct ViolationEventData
{
    public string UniqueId;      // Player identifier
    public string Priority;      // "medium", "high", "severe"
    public Label[] Labels;       // Specific violation labels
}

Age Verification

public static event Action OnAgeVerified;

public struct AgeVerificationData
{
    public string UniqueId;      // Player identifier
    public uint MinAge;          // Estimated minimum age
    public uint MaxAge;          // Estimated maximum age
}

Violation Labels

public enum Label
{
    Hate = 1,
    Hate_Threatening = 2,
    Harassment = 3,
    Harassment_Threatening = 4,
    Self_Harm = 5,
    Self_Harm_Intent = 6,
    Self_Harm_Instructions = 7,
    Sexual = 8,
    Sexual_Minors = 9,
    Violence = 10,
    Violence_Graphic = 11,
    Discrimination_Sexism = 12,
    Discrimination_Racism = 13,
    Discrimination_Homophobia = 14,
    Discrimination_Other = 15
}

Voice Engine Integration

VoicePatrol works alongside your existing voice chat solution. The recommended approach is to check your voice engine's muted state once per second rather than every frame. Here are integration examples:

Vivox Integration
void Start()
{
    // Check Vivox state every second
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    bool isMuted = Unity.Services.Vivox.VivoxService.Instance == null ||
                   Unity.Services.Vivox.VivoxService.Instance.ActiveChannels.Count == 0 ||
                   Unity.Services.Vivox.VivoxService.Instance.IsInputDeviceMuted;
    
    VoicePatrolWrapper.SetMuted(isMuted);
}
Photon Voice Integration
void Start()
{
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    bool isMuted = PhotonVoiceNetwork.Instance == null ||
                   PhotonVoiceNetwork.Instance.ClientState != ClientState.Joined ||
                   !PhotonVoiceNetwork.Instance.PrimaryRecorder.IsRecording;
    
    VoicePatrolWrapper.SetMuted(isMuted);
}
Dissonance Integration
private DissonanceComms _dissonanceComms;

void Start()
{
    _dissonanceComms = FindObjectOfType();
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    bool isMuted = _dissonanceComms == null || _dissonanceComms.IsMuted;
    VoicePatrolWrapper.SetMuted(isMuted);
}
Custom Voice Engine
void Start()
{
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    bool isMuted = !MyVoiceEngine.IsConnected() || 
                   !MyVoiceEngine.IsMicrophoneActive() ||
                   MyVoiceEngine.IsLocalPlayerMuted();
    
    VoicePatrolWrapper.SetMuted(isMuted);
}

Advanced Features

Age Verification

When enabled, VoicePatrol analyzes the first 60 seconds of clear speech to estimate player age. The model returns specific age ranges: 0-5, 6-6, 7-7, 8-8, 9-11, 11-12, 13-15, 16-100.

void OnEnable()
{
    VoicePatrolWrapper.OnAgeVerified += HandleAgeVerification;
}

private void HandleAgeVerification(VoicePatrolWrapper.AgeVerificationData data)
{
    Debug.Log($"Player {data.UniqueId} estimated age range: {data.MinAge}-{data.MaxAge}");
    
    // Apply age-appropriate restrictions based on specific ranges
    if (data.MaxAge <= 12)
    {
        // Child safety measures (0-5, 6-6, 7-7, 8-8, 9-11, 11-12)
        EnableChildSafetyMode();
        RestrictChatFeatures();
        RequireParentalSupervision();
    }
    else if (data.MaxAge <= 15)
    {
        // Teen safety features (13-15)
        EnableTeenSafetyFeatures();
        EnableContentFiltering();
    }
    else
    {
        // Adult content allowed (16-100)
        EnableFullFeatures();
    }
}

Player Reporting System

Implement an evidence based reporting system:

public class PlayerReportingSystem : MonoBehaviour
{    
    public void ReportPlayer(string playerId)
    {
        // Submit audio evidence
        string result = VoicePatrolWrapper.SubmitPlayerReport(playerId);
        Debug.Log($"VoicePatrol: {result}");
    }
}

How Player Reporting Works:

VoicePatrol continuously captures a rolling 60-second window of your game's mixed audio output - everything the player actually hears through their speakers or headphones. When SubmitPlayerReport() is called, it immediately uploads the last 60 seconds of captured audio as evidence.

This approach ensures reliable evidence collection because:

  • No audio loss: Evidence is already captured before the report is made
  • Complete context: Captures all audio the player heard, regardless of voice chat complexity
  • Works with any setup: Proximity chat, team channels, spatial audio - if the player heard it, it's captured

The submitted audio file is tagged with the reported player's ID and sent for human moderation review in your dashboard.

Voice Business Intelligence

Track voice communication patterns and player sentiment:

// Enable Voice BI during SDK initialization
VoicePatrolWrapper.StartVoicePatrol(
    token: apiKey,
    voiceBI: true  // Enable BI features
);

Best Practices

Performance Optimization

Muting Logic - Check Voice Engine State Periodically

Setting the muted state is not computationally expensive - it simply sets an internal boolean flag that causes early returns in processing functions. Check your voice engine's muted state once per second rather than every frame:

void Start()
{
    // Check voice engine muted state every second
    InvokeRepeating(nameof(UpdateVoicePatrolMutedState), 1f, 1f);
}

private void UpdateVoicePatrolMutedState()
{
    bool shouldMute = !IsInVoiceChat() || IsVoiceChatMuted();
    VoicePatrolWrapper.SetMuted(shouldMute);
}

// Example voice engine state checking
private bool IsInVoiceChat()
{
    // Replace with your voice engine's connection check
    return MyVoiceEngine.IsConnectedToChannel();
}

private bool IsVoiceChatMuted()
{
    // Replace with your voice engine's muted state
    return MyVoiceEngine.IsMicrophoneMuted();
}

Memory Management

void OnDestroy()
{
    // Always clean up event subscriptions
    VoicePatrolWrapper.OnViolationDetected -= HandleViolation;
    VoicePatrolWrapper.OnAgeVerified -= HandleAgeVerification;
}

void OnApplicationPause(bool pauseStatus)
{
    if (pauseStatus)
    {
        // Mute when app is backgrounded
        VoicePatrolWrapper.SetMuted(true);
    }
}

Troubleshooting

Common Issues

Audio Clip Processing Fails.

// Ensure audio clip is properly configured
if (audioClip.loadType != AudioClipLoadType.DecompressOnLoad)
{
    Debug.LogError("Audio clip must be set to 'Decompress On Load' for processing");
    return;
}

Debug Information

Debug logs will show SDK initialization progress, audio device detection, age verification buffer status, player report uploads, and authentication issues. This information is essential for diagnosing microphone access problems, API key issues, and feature-specific troubleshooting.

// Start with debug logs enabled
VoicePatrolWrapper.StartVoicePatrol(
    token: apiKey,
    debugLogs: true
);

Platform-Specific Notes

Android

  • Requires API level 23 (Android 6.0) minimum
  • Microphone permission automatically requested
  • Supports ARM64 architecture
  • Tested on various Android versions and devices

Windows/Mac/Linux

  • No special permissions required
  • Supports x64 architecture
  • Tested with various audio drivers and hardware

Build Settings

#if UNITY_ANDROID
    // Android-specific code
#elif UNITY_STANDALONE
    // Desktop-specific code
#endif