Skip to content
RustPluginGenerator

OnPlayerVoice

OnPlayerVoice is called on the server for every incoming voice packet before the audio is delivered to the rest of the server. Returning a non-null value drops that voice frame instead of passing it to BasePlayer.OnReceivedVoice.

Signature
object OnPlayerVoice(BasePlayer player, ArraySegment<byte> voiceData)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who sent the voice packet, resolved by the server from the network connection. It is never null at the hook call site.
voiceDataArraySegment<byte>The raw voice payload as an ArraySegment<byte> with the packet header already stripped. Its Count is the byte length of this voice frame.

Return value

Returning null passes the voice frame on to BasePlayer.OnReceivedVoice, which delivers it to listeners. Returning any non-null object (a bool, a string, anything) skips that delivery and the frame is dropped; the returned value itself is not used.

How it works

The hook fires inside ServerMgr.OnPlayerVoice after the server has read the sender from the network packet and sliced the voice payload into an ArraySegment<byte>. It runs for each voice frame a client uploads, so it can fire many times per second for an active speaker. player is the sender; voiceData holds the encoded audio bytes (the frame is capped by the server's maxpacketsize_voicedata convar before the hook is reached, so oversized frames never call it).

Declaring player as a more specific type is not useful here because only BasePlayer is passed, and narrowing it to a subclass would simply stop the hook from ever running. To drop a frame, return any non-null object; returning null lets the frame continue to the normal voice broadcast. Because this runs on the hot path of voice traffic, keep the body cheap: no allocations, no logging, no data file writes. Counting, muting or rate-limiting based on the sender are the practical uses.

Example plugin: Voice mute for players with a permission

VoiceMute.cs
using System.Collections.Generic;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("VoiceMute", "RustPluginGenerator", "1.0.0")]
    [Description("Grants admins a permission-driven server-side voice mute for players.")]
    public class VoiceMute : RustPlugin
    {
        private const string PermUse = "voicemute.use";
        private const string PermMuted = "voicemute.muted";

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
            permission.RegisterPermission(PermMuted, this);
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Muted"] = "{0} is now voice muted.",
                ["Unmuted"] = "{0} can speak again.",
                ["NoPermission"] = "You do not have permission to use this command.",
                ["NotFound"] = "No player found with that name or id.",
                ["Usage"] = "Usage: /voicemute <name or steamid>"
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args)
            => string.Format(lang.GetMessage(key, this, userId), args);

        private object OnPlayerVoice(BasePlayer player, System.ArraySegment<byte> voiceData)
        {
            if (player == null || voiceData.Count == 0) return null;
            if (!permission.UserHasPermission(player.UserIDString, PermMuted)) return null;
            return false;
        }

        [ChatCommand("voicemute")]
        private void CmdVoiceMute(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }

            if (args == null || args.Length < 1)
            {
                player.ChatMessage(Msg("Usage", player.UserIDString));
                return;
            }

            BasePlayer target = BasePlayer.FindAwakeOrSleeping(args[0]);
            if (target == null)
            {
                player.ChatMessage(Msg("NotFound", player.UserIDString));
                return;
            }

            if (permission.UserHasPermission(target.UserIDString, PermMuted))
            {
                permission.RevokeUserPermission(target.UserIDString, PermMuted);
                player.ChatMessage(Msg("Unmuted", player.UserIDString, target.displayName));
            }
            else
            {
                permission.GrantUserPermission(target.UserIDString, PermMuted, this);
                player.ChatMessage(Msg("Muted", player.UserIDString, target.displayName));
            }
        }
    }
}

The plugin registers a voicemute.muted permission that admins grant to silence a player. OnPlayerVoice checks whether the sender holds that permission and, if so, returns false so the frame never reaches OnReceivedVoice. Muted players can still hear others; only their outgoing audio is discarded. A chat command toggles the permission for a target player, and LoadDefaultMessages keeps the feedback text in the language files. No state is cached, so the mute takes effect on the very next voice frame and the body stays allocation-free on the voice hot path.

Common use cases

  • Permission-based voice mute

    Silence outgoing audio for specific players by checking a permission inside the hook and returning a non-null value. Toggled from chat without touching config data.

  • Team-only comms

    Drop voice frames from players who are not in a team, or restrict incoming audio by comparing player.currentTeam against the listener's team in your own relay logic.

  • Rate limiting and abuse handling

    Track per-player frame counts in a dictionary and return non-null once a player exceeds a reasonable voice frequency, reducing spam audio without kicking.

Pitfalls

  • No listener information in the hook

    The hook only tells you who spoke, not who will hear it. You cannot selectively mute one recipient here; you can only block the whole frame, which affects all listeners.

  • Hot path, keep it cheap

    This fires per voice frame, so avoid allocating, iterating player lists or writing data. Cache permission results only if you have a cheap invalidation path, otherwise a single permission lookup is fine.

  • Muting is server-side only

    Players who muted someone via the game client already stop hearing them; returning non-null here stops the frame from ever being broadcast, but does not change the client mute state.

Build a plugin with OnPlayerVoice

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Permission-based voice mute using the OnPlayerVoice hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnPlayerVoice

Generate