{"id":27213225,"url":"https://github.com/bkacjios/lua-mumble","last_synced_at":"2025-04-10T02:04:11.756Z","repository":{"id":97528561,"uuid":"64512100","full_name":"bkacjios/lua-mumble","owner":"bkacjios","description":"A lua module to create a mumble bot client. Supports audio playback with automatic buffering, resampling, and even recording. Uses libuv for an efficient and easy event loop.","archived":false,"fork":false,"pushed_at":"2025-03-22T17:41:50.000Z","size":534,"stargazers_count":24,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-22T18:25:01.579Z","etag":null,"topics":["lua","mumble","mumble-client"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bkacjios.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-29T21:42:15.000Z","updated_at":"2025-03-22T17:41:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"61214837-68ed-421b-8cec-beed81bddbc4","html_url":"https://github.com/bkacjios/lua-mumble","commit_stats":null,"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkacjios%2Flua-mumble","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkacjios%2Flua-mumble/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkacjios%2Flua-mumble/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkacjios%2Flua-mumble/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bkacjios","download_url":"https://codeload.github.com/bkacjios/lua-mumble/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248142946,"owners_count":21054671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","mumble","mumble-client"],"created_at":"2025-04-10T02:03:32.845Z","updated_at":"2025-04-10T02:04:11.732Z","avatar_url":"https://github.com/bkacjios.png","language":"C","readme":"# lua-mumble\n\nA lua module to connect to a mumble server and interact with it\n\n## Build requirements\n\n### Ubuntu\n```bash\nsudo apt-get install cmake pkgconf libluajit-5.1-dev protobuf-c-compiler libprotobuf-c-dev libssl-dev libopus-dev libuv1-dev libsndfile1-dev libsamplerate0-dev\n```\n\nNote: `liblua5.1-0-dev` can be substituted with `libluajit-5.1-dev`, `liblua5.2-dev`, or `liblua5.3-dev` depending on your needs.\n\n### Arch Linux\n```bash\nsudo pacman -S cmake pkgconf luajit protobuf-c openssl libsndfile opus libuv libsamplerate\n```\n\nNote: `luajit` can be substituted with `lua5.1`, `lua5.2` or `lua5.3` depending on your needs.\n\n## Make usage\n\n```bash\nmkdir build\n\ncd build\n\n# Configure\ncmake .. -DLUAVER=luajit -DLUALIB=/usr/local/lib/lua/5.1\n\n# Build mumble.so\nmake\n\n# Copies mumble.so to the provided LUALIB path\nmake install\n\n# Removes mumble.so in the provided LUALIB path\nmake uninstall\n```\n\nIf you want a debug build, add `-DCMAKE_BUILD_TYPE=Debug` to the cmake arguments\n\n## Scripting documentation\n\n### mumble\n\n``` lua\n-- The mumble library is returned by a require call\nlocal mumble = require(\"mumble\")\n\n-- Create a new mumble client\nmumble.client = mumble.client()\n\n-- Main event loop that handles all events, ping, and audio processing\n-- This will block the script until SIGINT or mumble.stop(), so call this *after* you create your hooks\nmumble.loop()\n\n-- Break out of the mumble.loop() call\nmumble.stop()\n\n-- The client's user\n-- Is only available *after* \"OnServerSync\" is called\nmumble.user = mumble.client.me\nmumble.user = mumble.client:getMe()\nmumble.user = mumble.client:getSelf()\n\n-- A new timer object\n-- The timer itself will do a best-effort at avoiding drift, that is, if you configure a timer to trigger every 10 seconds, then it will normally trigger at exactly 10 second intervals. If, however, your program cannot keep up with the timer (because it takes longer than those 10 seconds to do stuff) the timer will not fire more than once per event loop iteration.\n-- Timers will keep the reference active until mumble.timer:stop() is called, or the timer stops on its own.\n-- Timers will dereference themselves if the timer is stopped after the callback funciton call.\nmumble.timer = mumble.timer()\n\n-- A new buffer object\n-- Can be used to read/write raw binary data\n-- Can be initialized with data or a given size\nmumble.buffer = mumble.buffer([Number size or String data])\n\n-- A new thread controller object\n-- The callback function will be ran in a separate thread.\nmumble.thread.controller = mumble.thread(String filename or Function callback(mumble.thread.worker worker))\n\n-- A new voicetarget object\nmumble.voicetarget = mumble.voicetarget()\n\n-- A new opus encoder object\n-- Sample rate defaults to 48000\n-- Channels defaults to 2\nmumble.encoder = mumble.encoder(Number samplerate = 48000, Number channels = 2)\n\n-- A new opus decoder object\n-- Sample rate defaults to 48000\n-- Channels defaults to 2\nmumble.decoder = mumble.decoder(Number samplerate = 48000, Number channels = 2)\n\n-- A timestamp in milliseconds\nNumber time = mumble.getTime()\n\n-- A table of all currect clients\nTable clients = mumble.getClients()\n\n-- Structure\nTable clients = {\n\tmumble.client,\n\tmumble.client,\n\t...\n}\n```\n\n### mumble.client\n\n``` lua\n-- Begins to connect to a mumble server.\n-- Returns true or false depending if we could start connecting or not.\n-- If connected is false, an error string will also be returned.\n-- Since this method is non-blocking, you can use the \"OnConnect\" hook to determine when the client has fully connected.\nBoolean connecting, [ String error ] = mumble.client:connect(String host, Number port, String certificate file path, String key file path)\n\n-- Authenticate as a user.\n-- Should be called inside an \"OnConnect\" hook.\nmumble.client:auth(String username, [ String password, Table tokens ])\n\n-- Manually call a custom hook.\n-- Returns whatever the first hook that responded returned.\nVarargs ... = mumble.client:call(String hook, ...)\n\n-- Set the bots access tokens\nmumble.client:setTokens(Table tokens)\n\n-- Check if the client is connected\nBoolean connected = mumble.client:isConnected()\n\n-- Check if the client has fully synced all users and channels\nBoolean synced = mumble.client:isSynced()\n\n-- Request the registered ban list from the server\n-- When server responds, it will call the 'OnBanList' hook\nmumble.client:requestBanList()\n\n-- Request the registered user list from the server\n-- When server responds, it will call the 'OnUserList' hook\nmumble.client:requestUserList()\n\n-- Disconnect from the connected server\nmumble.client:disconnect()\n\n-- Transmit a plugin data packet\n-- User list can be a table of users or varargs\nmumble.client:sendPluginData(String dataID, String plugindata, [Table {mumble.user ..}, mumble.user ..])\n\n-- Transmit a raw, encoded, opus packet.\n-- Set speaking to false at the end of a stream.\n-- This should only be used if you don't plan on using mumble.client:openAudio() or mumble.client:createAudioBuffer(),\n-- since this will directly conflict with the internal output of this module.\n-- When audio data is streamed, it can trigger the following hooks: OnUserStartSpeaking, OnUserSpeak, OnUserStopSpeaking\nmumble.client:transmit(Number codec, String encoded_audio_packet, Boolean speaking = true)\n\n-- Open an audio file as an audio stream\n-- If audiostream = nil, it will pass along an error string as to why it couldn't open the file\nmumble.audiostream audiostream, [ String error ] = mumble.client:openAudio(String audio file path, Number volume = 1.0)\n\n-- Creates a buffer that you can write raw, 32bit float, PCM data that will be output by the client as soon as it can.\n-- Creating multiple buffers will result in each buffer being mixed together during transmission, for simultaneous audio streaming.\n-- You should only ever use buffer:writeFloat(), but the other buffer methods are always available for whatever reason.\n-- When audio data is streamed, it can trigger the following hooks: OnUserStartSpeaking, OnUserSpeak, OnUserStopSpeaking\nmumble.buffer buffer = mumble.client:createAudioBuffer([Number samplerate = 48000, Number channels = 2])\n\n-- Gets a table of all currently playing audio streams\nTable audiostreams = mumble.client:getAudioStreams()\n\n-- Structure\nTable audiostreams = {\n\t[1]\t= mumble.audiostream,\n\t[2]\t= mumble.audiostream,\n\t...\n}\n\n-- Sets the size of each audio packet played.\n-- The larger the packet size, the less chance of static.\n-- Larger  = higher audio latency.\n-- Smaller = lower audio latency.\n\nTable mumble.audio = {\n\t[\"TINY\"]\t= 1,\n\t[\"SMALL\"]\t= 2,\n\t[\"MEDIUM\"]\t= 3,\n\t[\"LARGE\"]\t= 4,\n}\n\nmumble.client:setAudioPacketSize(Number size = [TINY = 1, SMALL = 2, MEDIUM = 3, LARGE = 4])\n\n-- Returns the current duration of each audio packet\n-- Default: mumble.audio.TINY = 1\nNumber size = mumble.client:getAudioPacketSize()\n\n-- Sets the global volume level\n-- Consider this the master volume level\nmumble.client:setVolume(Number volume)\n\n-- Gets the global volume level\nNumber volume = mumble.client:getVolume()\n\n-- Returns if the client is tunneling UDP voice data through the TCP connection\n-- This will be true until the first \"OnPongUDP\" call\nBoolean tunneludp = mumble.client:isTunnelingUDP()\n\n-- Attempts to change the bots comment\nmumble.client:setComment(String comment)\n\n-- Adds a callback for a specific event\n-- If no unique name is passed, it will default to \"hook\"\nmumble.client:hook(String hook, [ String unique name = \"hook\" ], Function callback(mumble.client))\n\n-- Remove a callback for a specific event\n-- If no unique name is passed, it will default to \"hook\"\nmumble.client:unhook(String hook, [ String unique name = \"hook\" ])\n\n-- Gets all registered callbacks\nTable hooks = mumble.client:getHooks()\n\n-- Structure\nTable hooks = {\n\t[\"OnServerSync\"] = {\n\t\t[\"hook\"] = function: 0xffffffff,\n\t\t[\"do stuff on connection\"] = function: 0xffffffff,\n\t},\n\t[\"OnPingTCP\"] = {\n\t\t[\"hook\"] = function: 0xffffffff,\n\t\t[\"do stuff on ping\"] = function: 0xffffffff,\n\t},\n\t...\n}\n\n-- Register a mumble.voicetarget to the server\n-- Accepts multiple mumble.voicetarget objects that will all be assigned to the given ID\nmumble.client:registerVoiceTarget(Number id, mumble.voicetarget ...)\n\n-- Set the current voice target that mumble.client:play() will abide by\n-- Defaults to 0, the default voice target\nmumble.client:setVoiceTarget(Number id)\n\n-- Get the current voice target\nNumber id = mumble.client:getVoiceTarget()\n\n-- Get the encoder object that the internal audio system uses to encode audio data\nmumble.encoder encoder = mumble.client:getEncoder()\n\n-- Get the average ping of the client\nNumber ping = mumble.client:getPing()\n\n-- Get the uptime of the current client in seconds\nNumber time = mumble.client:getUpTime()\n\n-- Returns a table of all mumble.users\nTable users = mumble.client:getUsers()\n\n-- Structure\n-- Key:\t\tindex\n-- Value:\tmumble.user\nTable users = {\n\t[1] = mumble.user,\n\t[2] = mumble.user,\n\t[3] = mumble.user,\n\t...\n}\n\n-- Allows you to lookup a channel using a file path syntax.\n-- Will default to \".\" for the root channel.\n-- \".\" for current channel\n-- \"..\" for parent channel\n-- \"/\" for seperator\n-- \"name\" for channel name\n-- If the channel name doesn't exist, it will return nil\nmumble.channel channel = mumble.client:getChannel([String path = \".\"])\n\n-- Examples\nlocal root = mumble.client:getChannel()\nlocal testing = mumble.client:getChannel(\"Testing\")\nlocal root = mumble.client:getChannel(\"Testing/..\")\n\n-- Returns a table of all mumble.channels\nTable channels = mumble.client:getChannels()\n\n-- Structure\n-- Key:\t\tchannel id\n-- Value:\tmumble.channel\nTable channels = {\n\t[id] = mumble.channel,\n\t[id] = mumble.channel,\n\t...\n}\n\n-- Request a users full texture data blob\n-- Server will respond with a \"OnUserState\" with the requested data filled out\nmumble.client:requestTextureBlob([Table {mumble.user, ...}, mumble.user ..])\n\n-- Request a users full comment data blob\n-- Server will respond with a \"OnUserState\" with the requested data filled out\n-- After the hook is called, mumble.user:getComment() will also return the full data\nmumble.client:requestCommentBlob([Table {mumble.user, ...}, mumble.user ..])\n\n-- Request a channels full description data blob\n-- Server will respond with a \"OnChannelState\" with the requested data filled out\n-- After the hook is called, mumble.channel:getDescription() will also return the full data\nmumble.client:requestDescriptionBlob(T[Table {mumble.channel, ...}, mumble.channel ..])\n\n-- Creates a channel\n-- Will be parented to the root channel\nmumble.client:createChannel(String name, [ String description = \"\", Number position = 0, Boolean temporary = false, Number max_users = 0 ])\n```\n\n### mumble.user\n\n``` lua\n-- Sends a text message to a user\nmumble.user:message(String host)\n\n-- Attempts to kick a user with an optional reason value\nmumble.user:kick([ String reason ])\n\n-- Attempts to ban a user with an optional reason value\nmumble.user:ban([ String reason ])\n\n-- Attempts to move a user to a different channel\nmumble.user:move(mumble.channel channel)\n\n-- Attempts to mute a user\n-- If no boolean is passed, it will default to muting the user\nmumble.user:setMuted([ Boolean mute = true ])\n\n-- Attempts to deafen a user\n-- If no boolean is passed, it will default to deafening the user\nmumble.user:setDeaf([ Boolean deaf = true ])\n\n-- Attempts to register the users name to the server\nmumble.user:register()\n\n-- Requests the users information statistics from the server\n-- If no boolean is passed, it will default to requesting ALL statistics\nmumble.user:requestStats([ Boolean statsonly = false ])\n\n-- Gets the current mumble.client this user is a part of\nmumble.client client = mumble.user:getClient()\n\n-- Gets the current session number\nNumber session = mumble.user:getSession()\n\n-- Gets the name of the user\nString name = mumble.user:getName()\n\n-- Gets the channel of the user\nmumble.channel channel = mumble.user:getChannel()\n\n-- Gets the registered ID of the user\n-- Is 0 for unregistered users\nNumber userid = mumble.user:getId()\n\n-- Returns if the user is registered or not\nBoolean registered = mumble.user:isRegistered()\n\n-- Returns if the user is muted or not\nBoolean muted = mumble.user:isMuted()\n\n-- Returns if the user is deaf or not\nBoolean deaf = mumble.user:isDeaf()\n\n-- Returns if the user is muted or not\nBoolean muted = mumble.user:isSelfMute()\n\n-- Returns if the user is deaf or not\nBoolean deaf = mumble.user:isSelfDeaf()\n\n-- Returns if the user is suppressed by the server\nBoolean suppressed = mumble.user:isSuppressed()\n\n-- Returns the comment string of the users comment\nString comment = mumble.user:getComment()\n\n-- Returns the comments SHA1 hash\nString hash = mumble.user:getCommentHash()\n\n-- Returns if the user is speaking or not\nBoolean speaking = mumble.user:isSpeaking()\n\n-- Returns if the user is recording or not\nBoolean recording = mumble.user:isRecording()\n\n-- Returns if the user is a priority speaker or not\nBoolean priority = mumble.user:isPrioritySpeaker()\n\n-- Returns the users avatar as a string of bytes\nString texture = mumble.user:getTexture()\n\n-- Returns the users avatar as a SHA1 hash\nString hash = mumble.user:getTextureHash()\n\n-- Returns the users username SHA1 hash\nString hash = mumble.user:getHash()\n\n-- Sets the users avatar image using a string of bytes\nmumble.user:setTexure(String bytes)\n\n-- Adds a channel to the list of channels the user is listening to\n-- Channel list can be a table of channels or varargs\nmumble.user:listen([Table {mumble.channel ..}, mumble.channel ..])\n\n-- Removes a channel from the list of channels the user is listening to\n-- Channel list can be a table of channels or varargs\nmumble.user:unlisten([Table {mumble.channel ..}, mumble.channel ..])\n\n-- Returns if the user is listening to this channel or not\nBoolean isListening = mumble.user:isListening(mumble.channel channel)\n\n-- Returns a table of all channels the user is currently listening to\nTable listens = mumble.user:getListens()\n\n-- Structure\n-- Key:\t\tchannel id\n-- Value:\tmumble.channel\nTable channels = {\n\t[id] = mumble.channel,\n\t[id] = mumble.channel,\n\t...\n}\n\n-- Transmit a plugin data packet to this user\nmumble.user:sendPluginData(String dataID, String plugindata)\n\n-- Request a users full texture data blob\n-- Server will respond with a \"OnUserState\" with the requested data filled out\n-- After the hook is called, mumble.user:getTexture() will also return the full data\nmumble.user:requestTextureBlob()\n\n-- Request a users full comment data blob\n-- Server will respond with a \"OnUserState\" with the requested data filled out\n-- After the hook is called, mumble.user:getComment() will also return the full data\nmumble.user:requestCommentBlob()\n\n-- Starts recording a users voice output to an ogg file.\n-- Will return nil and an error string if it failed to create the file.\nBoolean success, [String error] = mumble.user:startRecord(String oggFilePath)\n\n-- Will return true if we successfully stopped recording.\n-- Will return false if the user wasn't being recorded.\nBoolean success = mumble.user:stopRecord()\n\n-- Returns if the user is being recorded or not.\nBoolean isBeingRecorded = mumble.user:isBeingRecorded()\n```\n\n### mumble.channel\n\n``` lua\n-- Gets a channel relative to the current\nmumble.channel channel = mumble.channel(String path)\nmumble.channel parents_parent = mumble.channel(\"../..\")\nmumble.channel child = mumble.channel(\"Child\")\n\n-- Sends a text message to the entire channel\nmumble.channel:message(String message)\n\n-- Attempts to set the channels description\nmumble.channel:setDescription(String description)\n\n-- Attempts to remove the channel\nmumble.channel:remove()\n\n-- Gets the current mumble.client this channel is a part of\nmumble.client client = mumble.channel:getClient()\n\n-- Gets the channels name\nString name = mumble.channel:getName()\n\n-- Gets the channel ID\nNumber id = mumble.channel:getId()\n\n-- Gets the parent channel\n-- Returns nil on root channel\nmumble.channel channel = mumble.channel:getParent()\n\n-- Returns the channels that are parented to the channel\nTable children = mumble.channel:getChildren()\n\n-- Returns the users that are currently within the channel\nTable users = mumble.channel:getUsers()\n\n-- Structure\n-- Key:\t\tindex\n-- Value:\tmumble.user\nTable users = {\n\t[1] = mumble.user,\n\t[2] = mumble.user,\n\t[3] = mumble.user,\n\t...\n}\n\n-- Gets the channels description\nString description = mumble.channel:getDescription()\n\n-- Gets the channels description SHA1 hash\nString hash = mumble.channel:getDescriptionHash()\n\n-- Returns if the channel is temporary or not\nBoolean temporary = mumble.channel:isTemporary()\n\n-- Returns the channels position\nNumber position = mumble.channel:getPosition()\n\n-- Gets the max number of users allowed in this channel\nNumber max = mumble.channel:getMaxUsers()\n\n-- Returns a table of all linked channels\nNumber linked = mumble.channel:getLinked()\n\n-- Attempts to link channel(s)\n-- Channel list can be a table of channels or varargs\nmumble.channel:link([Table {mumble.channel ..}, mumble.channel ..])\n\n-- Attempts to unlink channel(s)\n-- Channel list can be a table of channels or varargs\nmumble.channel:unlink([Table {mumble.channel ..}, mumble.channel ..])\n\n-- Returns if the client is restricted from entering the channel\n-- NOTE: *Will only work in mumble version 1.4+*\nBoolean restricted = mumble.channel:isEnterRestricted()\n\n-- Returns if the client is able to enter the channel\n-- NOTE: *Will only work in mumble version 1.4+*\nBoolean enter = mumble.channel:canEnter()\n\n-- Request ACL config for the channel\n-- When server responds, it will call the 'OnACL' hook\nmumble.channel:requestACL()\n\n-- Request permissions for the channel\n-- When server responds, it will call the 'OnPermissionQuery' hook\nmumble.channel:requestPermissions()\n\n-- Gets the permissions value for the channel\nNumber permissions = mumble.channel:getPermissions()\n\n-- Gets the permissions value for the channel\nBoolean permission = mumble.channel:hasPermission(mumble.acl flag)\n\n-- Request a users full texture data blob\n-- Server will respond with a \"OnChannelState\" with the requested data filled out\n-- After the hook is called, mumble.channel:getDescription() will also return the full data\nmumble.channel:requestTextureBlob()\n\n-- Creates a channel\n-- Will be parented to the channel that this method was called from\nmumble.channel:create(String name, String description = \"\", Number position = 0, Boolean temporary = false, Number max_users = 0)\n```\n\n### mumble.timer\n\n``` lua\n-- Run the timer with a given callback function.\n-- The callback function will first be called after the initial delay.\n-- If the timers repeat value is \u003e 0, it will then repeat over using the repeat value as the delay.\n-- While the timer is running, the timer will not be garbage collected.\n-- It will only be garabage collected once the timer stops on its own, or mumble.timer:stop() is called.\nmumble.timer = mumble.timer:start(Function callback(mumble.timer), Number after = 0, Number repeat = 0)\n\n-- Stops the timer and readies the timer for garabage collection\nmumble.timer:stop()\n\n-- Pauses the timer\n-- Will error out if the timer is not repeating or hasn't been started previously.\nmumble.timer:pause()\n\n-- Restarts the timer and sets the iteration count back to 0\n-- Will error out if the timer is not repeating or hasn't been started previously.\nmumble.timer:again()\n\n-- Resumes the timer\n-- Will error out if the timer is not repeating or hasn't been started previously.\nmumble.timer:resume()\n\n-- Sets the timers delay and repeat values\nmumble.timer:set(Number after, [ Number repeat = 0 ])\n\n-- Gets the timers delay and repeat values\nNumber after, Number repeat = mumble.timer:get()\n\n-- Sets the timers delay value\nmumble.timer:setDuration(Number after)\n\n-- Gets the timers delay value\nNumber after = mumble.timer:getDuration()\n\n-- Sets the timers repeat value\nmumble.timer:setRepeat(Number repeat)\n\n-- Gets the timers repeat value\nNumber repeat = mumble.timer:getRepeat()\n\n-- Retruns if the timer is currently running\nBoolean running = mumble.timer:isActive()\n\n-- Get how many times the timer has looped\nNumber count = mumble.timer:getCount()\n\n-- Get how many seconds remain until the callback is triggered\nNumber remain = mumble.timer:getRemain()\n\nmumble.timer = mumble.timer:set(Number after, Number repeat = 0)\n\n-- Returns if the timer is currently running or not.\nBoolean active = mumble.timer:isActive()\n\n-- Returns if the timer is currently paused or not.\nBoolean paused = mumble.timer:isPaused()\n```\n\n### mumble.buffer\n\nA buffer object used to read/write data from. It will dynamically adjust its capacity to fit all written data.\n\n``` lua\n-- Packs the buffer, moving all remaining data that has not been read to the start.\n-- BEFORE PACK = [1234|5678|]\n--          Read head ^    ^ Write head\n-- AFTER PACK = [|5678|]\n--     Read head ^    ^ Write head\n-- If the read head and write head are in the same position, the buffer is cleared.\nbuffer:pack()\n\n-- Resets the buffer, setting the read head and write head to the start.\n-- Esentially empties the buffer, but the capacity will remain the same.\nbuffer:reset()\n\n-- Flips the buffer, preparing it for reading by setting the position to 0\n-- Does not alter the write head, so data can continue to be written to it.\nbuffer:flip()\n\n-- Get the length of the buffer\nNumber length = buffer.length\nNumber length = #buffer\n\n-- Get a byte from the buffer without reading\nString byte = buffer[Number index]\n\n-- Returns the capacity of the buffer, which is the total amount of space allocated\nNumber capacity = buffer.capacity\n\n-- Returns if the buffer has no data available to be read.\n-- Works by checking if the read head position equals the write head position.\nBoolean isEmpty = buffer:isEmpty()\n\n-- Returns the current read_head position in the buffer\nNumber read_head = buffer.read_head, same as buffer:seek(\"read\")\n\n-- Returns the current write_head position in the buffer\nNumber write_head = buffer.write_head, same as buffer:seek(\"write\")\n\n-- Will attempt to seek to a given position via offset numbers.\n-- See: https://www.lua.org/pil/21.3.html\n-- Returns the offset that it has seeked to.\n-- Mode defaults to \"read\"\n-- Whence defaults to \"cur\"\n-- Offset defaults to 0\n-- If the mode is set to \"both\" the read and write values will be returned.\nNumber position = buffer:seek([String mode [\"read\", \"write\", \"both\"] = \"read\", String whence [\"set\", \"cur\", \"end\"] = \"cur\", offset = 0])\n\n-- Write the given string to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:write(String data)\n\n-- Reads the specified number of bytes from the buffer and returns the data as a string\n-- Accepts multiple arguments, like buffer:read(4, 6, \"*all\")\nString data = buffer:read([Number length, String format, ..]\n\n-- Write a single byte to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeByte(Number value)\n\n-- Reads a single byte from the buffer and returns it\nNumber value = buffer:readByte()\n\n-- Write a short integer to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeShort(Number value)\n\n-- Reads a short integer from the buffer and returns it\nNumber value = buffer:readShort()\n\n-- Write a 32-bit integer to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeInt(Number value)\n\n-- Reads a 32-bit integer from the buffer and returns it\nNumber value = buffer:readInt()\n\n-- Write a variable-length integer to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeVarInt(Number value)\n\n-- Reads a variable-length integer from the buffer and returns it\nNumber value = buffer:readVarInt()\n\n-- Write a float to the buffer\n-- Returns how many bytes were written to the bufferbuffer\nNumber written = buffer:writeFloat(Number value)\n\n-- Reads a float from the buffer and returns it\nNumber value = buffer:readFloat()\n\n-- Write a double to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeDouble(Number value)\n\n-- Reads a double from the buffer and returns it\nNumber value = buffer:readDouble()\n\n-- Write a string to the buffer, including its length as a variable-length integer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeString(String value)\n\n-- Reads a string from the buffer, using a variable-length integer to determine its size\nString value = buffer:readString()\n\n-- Write a boolean value (as 0 or 1) to the buffer\n-- Returns how many bytes were written to the buffer\nNumber written = buffer:writeBool(Boolean value)\n\n-- Reads a boolean value from the buffer (returns true or false)\nBoolean value = buffer:readBool()\n```\n\n### mumble.thread.controller\n\n```lua\n-- Sets a callback function that will be called when the worker is joined back into the controller thread.\nmumble.thread.controller = mumble.thread.controller:onFinish(Function callback(mumble.thread.controller))\n\n-- Sets a callback function that will be called when the controller receives a message from the worker.\nmumble.thread.controller = mumble.thread.controller:onMessage(Function callback(String message))\n\n-- Sends a message to the worker thread.\nmumble.thread.controller = mumble.thread.controller:send([String message, mumble.buffer message])\n\n-- Blocks the main thread until the worker completes.\nmumble.thread.controller = mumble.thread.controller:join()\n```\n\n### mumble.thread.worker\n\n```lua\n-- Sleep the worker thread for however many milliseconds.\nmumble.thread.worker = mumble.thread.worker:sleep(Number milliseconds)\n\n-- Keep the thread open until singnaled to close.\n-- Allows us to receive messages using mumble.worker.onMessage.\nmumble.thread.worker = mumble.thread.worker:loop()\n\n-- Signals the thread to exit its loop.\nmumble.thread.worker = mumble.thread.worker:stop()\n\n-- A new buffer object. (shortcut for mumble.buffer())\n-- Can be used to read/write raw binary data.\n-- Can be initialized with data or a given size.\nmumble.buffer = mumble.thread.worker:buffer([Number size, String data])\n\n-- Sets a callback function that will be called when the worker receives a message from the controller.\nmumble.thread.controller = mumble.thread.controller:onMessage(Function callback(String message))\n\n-- Sends a message to the controller thread.\nmumble.thread.controller = mumble.thread.controller:send([String message, mumble.buffer message])\n```\n\n#### Thread examples\n\n```lua\n--local thread = mumble.thread(\"thread.lua\")\n\nlocal outsideValue = \"outside scope\"\n\nlocal thread = mumble.thread(function(worker)\n\t-- This function is ran in a separate thread and will not block.\n\t-- The scope of this function starts here and can not access upvalues from the outer scope.\n\tprint(\"outsideValue\", outsideValue) -- outsideValue is nil here.\n\tworker:send(\"my work has begun\")\n\tfor i=1,3 do\n\t\tworker:sleep(1000)\n\t\tworker:send(\"hello \" .. i)\n\tend\n\tworker:send(\"my work has completed\")\nend):onMessage(function(t, msg)\n\t-- Use this to receive data from the worker thread.\n\tprint(\"worker: \" ..  msg)\nend):onFinish(function(t)\n\t-- Thread was joined back into our main thread.\n\tprint(\"thread finished\", t)\nend)\n```\n\nOutput\n\n```\noutsideValue    nil\nworker: my work has begun\nworker: hello 1\nworker: hello 2\nthread finished mumble.thread.controller: 0x7ffff7b7bc70\nworker: hello 3\nworker: my work has completed\n```\n\nthread.lua\n```lua\n-- When running a file in a thread, the worker will be passed in as arg[1]\nlocal worker = ...\n\n-- This function is ran in a separate thread and will not block.\n-- The scope of this function starts here and can not access upvalues from the outer scope.\nworker:send(\"my work has begun\")\nfor i=1,3 do\n\tworker:sleep(1000)\n\tworker:send(\"hello \" .. i)\nend\nworker:send(\"my work has completed\")\n```\n\n### mumble.voicetarget\n\n``` lua\n-- Add a user to whisper to\nmumble.voicetarget:addUser(mumble.user user)\n\n-- Return a table of all the users currently in the voicetarget\nTable users = mumble.voicetarget:getUsers()\n\n-- Structure\n-- Key:\t\tindex\n-- Value:\tNumber session\nTable channels = {\n\tNumber session,\n\tNumber session,\n\t...\n}\n\n-- Sets the channel that is be shouted to\nmumble.voicetarget:setChannel(mumble.channel channel)\n\n-- Gets the channel that is shouted to\nmumble.voicetarget:getChannel()\n\n-- Sets the specific user group to whisper to\nmumble.voicetarget:setGroup(String group)\n\n-- Gets the group name we are whispering to\nString group = mumble.voicetarget:getGroup()\n\n-- Shout to the linked channels of the set channel\nmumble.voicetarget:setLinks(Boolean followlinks)\n\n-- Returns if we are currently shouting to linked channels of the set channel\nBoolean links = mumble.voicetarget:getLinks()\n\n-- Shout to the children of the set channel\nmumble.voicetarget:setChildren(Boolean followchildren)\n\n-- Returns if we are currently shouting to children of the set channel\nBoolean children = mumble.voicetarget:getChildren()\n```\n\n### mumble.encoder\n\n``` lua\n-- Equivalent to OPUS_GET_FINAL_RANGE\nNumber range = mumble.encoder:getFinalRange()\n\n-- Equivalent to OPUS_GET_PITCH\nNumber pitch = mumble.encoder:getPitch()\n\n-- Equivalent to OPUS_GET_BANDWIDTH\nNumber bandwidth = mumble.encoder:getBandwidth()\n\n-- Equivalent to OPUS_GET_SAMPLE_RATE\nNumber samplerate = mumble.encoder:getSamplerate()\n\n-- Equivalent to OPUS_GET_PHASE_INVERSION_DISABLED\nBoolen inversion = mumble.encoder:getPhaseInversionDisabled()\n\n-- Equivalent to OPUS_SET_PHASE_INVERSION_DISABLED\nmumble.encoder:setPhaseInversionDisabled(Boolean inversion)\n\n-- Equivalent to OPUS_GET_IN_DTX\nBoolen indtx = mumble.encoder:getInDTX()\n\n-- Equivalent to OPUS_GET_COMPLEXITY\nNumber bitrate = mumble.encoder:getComplexity()\n\n-- Equivalent to OPUS_SET_COMPLEXITY\nmumble.encoder:setComplexity(Number complexity)\n\n-- Equivalent to OPUS_GET_BITRATE\nNumber bitrate = mumble.encoder:getBitRate()\n\n-- Equivalent to OPUS_SET_BITRATE\nmumble.encoder:setBitRate(Number bitrate)\n\n-- Encode X number of pcm 16 bit short frames into an opus audio packet\nString encoded = mumble.encoder:encode(Number frames, String pcm)\n\n-- Encode X number of pcm 32 bit float frames into an opus audio packet\nString encoded = mumble.encoder:encodeFloat(Number frames, String pcm)\n```\n\n### mumble.decoder\n\n``` lua\n-- Equivalent to OPUS_RESET_STATE\nmumble.decoder:reset()\n\n-- Equivalent to OPUS_GET_FINAL_RANGE\nNumber range = mumble.decoder:getFinalRange()\n\n-- Equivalent to OPUS_GET_PITCH\nNumber pitch = mumble.decoder:getPitch()\n\n-- Equivalent to OPUS_GET_BANDWIDTH\nNumber bandwidth = mumble.decoder:getBandwidth()\n\n-- Equivalent to OPUS_GET_SAMPLE_RATE\nNumber samplerate = mumble.decoder:getSamplerate()\n\n-- Equivalent to OPUS_GET_PHASE_INVERSION_DISABLED\nBoolen inversion = mumble.decoder:getPhaseInversionDisabled()\n\n-- Equivalent to OPUS_SET_PHASE_INVERSION_DISABLED\nmumble.decoder:setPhaseInversionDisabled(Boolean inversion)\n\n-- Equivalent to OPUS_GET_IN_DTX\nBoolen indtx = mumble.decoder:getInDTX()\n\n-- Decode an opus audio packet into raw PCM data\nString decoded = mumble.decoder:decode(String encoded)\n\n-- Decode an opus audio packet into raw PCM float data\nString decoded = mumble.decoder:decodeFloat(String encoded)\n```\n\n### mumble.audiostream\n\n[Click here for a list of supported audio formats](https://libsndfile.github.io/libsndfile/formats.html)\n\nAll audio will be resampled to 48000 Hz and remixed to stereo.\n\n``` lua\n-- Returns if this audio stream is currently playing or not\nBoolean isplaying = mumble.audiostream:isPlaying()\n\n-- Sets the volume of the audio stream\n-- Returns itself so you can stack calls\n-- example: client:openOgg(\"file.ogg\"):setVolume(0.5):setLooping(true):play()\nmumble.audiostream = mumble.audiostream:setVolume(Number volume)\n\n-- Gets the volume of the audio stream\nNumber volume = mumble.audiostream:getVolume()\n\n-- Pause the audio\nmumble.audiostream:pause()\n\n-- Resume playing the audio\nmumble.audiostream:play()\n\n-- Pauses the audio AND resets playback to the beginning\n-- Will remove the stream from the mumble.client:getAudioStreams() table\nmumble.audiostream:stop()\n\n-- Fade the volume to the specified volume over the duration.\nmumble.audiostream:fadeTo(Number volume, Number duration = 1)\n\n-- Fade the volume to 0 over the duration and stop playing.\nmumble.audiostream:fadeOut(Number duration = 1)\n\n-- Will attempt to seek to a given position via sample numbers.\n-- See: https://www.lua.org/pil/21.3.html\n-- Returns the offset that it has seeked to.\n-- Mode defaults to \"read\"\n-- Whence defaults to \"cur\"\n-- Offset defaults to 0\nNumber samples = mumble.audiostream:seek(String whence [\"set\", \"cur\", \"end\"] = \"cur\", Number offset = 0)\n\n-- Returns the duration of the stream given the unit type\nNumber samples/seconds = mumble.audiostream:getLength(String units [\"seconds\", \"samples\"])\n\n-- Returns a table of information about the audio file.\nTable info = mumble.audiostream:getInfo()\n\n-- Structure\n-- Key:\t\tString\n-- Value:\tNumber\nTable info = {\n\t[\"channels\"] = Number channels,\n\t[\"sample_rate\"] = Number sample_rate,\n\t[\"setup_memory_required\"] = Number setup_memory_required,\n\t[\"setup_temp_memory_required\"] = Number setup_temp_memory_required,\n\t[\"temp_memory_required\"] = Number temp_memory_required,\n\t[\"max_frame_size\"] = Number max_frame_size\n}\n\n-- Returns the title of the file.\n-- Will return nil if not available.\nString title = mumble.audiostream:getTitle()\n\n-- Returns the artist of the file.\n-- Will return nil if not available.\nString artist = mumble.audiostream:getArtist()\n\n-- Returns the copyright of the file.\n-- Will return nil if not available.\nString title = mumble.audiostream:getCopyright()\n\n-- Returns the software the file was created in.\n-- Will return nil if not available.\nString title = mumble.audiostream:getSoftware()\n\n-- Returns the comments of the file.\n-- Will return nil if not available.\nString comments = mumble.audiostream:getComments()\n\n-- Enables the audio stream to loop to the beginning when reaching the end.\n-- Boolean = true will cause it to loop forever.\n-- Number = Will loop X amount of times before eventually stopping.\n-- Returns itself so you can stack calls.\n-- example: client:openOgg(\"file.ogg\"):setVolume(0.5):setLooping(true):play()\nmumble.audiostream = mumble.audiostream:setLooping([Boolean loop, Number loop_count])\n\n-- Returns if the stream is looping or not\nBoolean looping = mumble.audiostream:isLooping()\n\n-- Retuns how many more times the stream will loop before stopping.\n-- If you used setLooping(true), this will return math.huge (inf)\nNumber count = mumble.audiostream:getLoopCount()\n```\n\n### mumble.acl\n\n```lua\nTable mumble.acl = {\n\tNONE = 0x0,\n\tWRITE = 0x1,\n\tTRAVERSE = 0x2,\n\tENTER = 0x4,\n\tSPEAK = 0x8,\n\tMUTE_DEAFEN = 0x10,\n\tMOVE = 0x20,\n\tMAKE_CHANNEL = 0x40,\n\tLINK_CHANNEL = 0x80,\n\tWHISPER = 0x100,\n\tTEXT_MESSAGE = 0x200,\n\tMAKE_TEMP_CHANNEL = 0x400,\n\tLISTEN = 0x800,\n\n\t-- Root channel only\n\tKICK = 0x10000,\n\tBAN = 0x20000,\n\tREGISTER = 0x40000,\n\tSELF_REGISTER = 0x80000,\n\tRESET_USER_CONTENT = 0x100000,\n\n\tCACHED = 0x8000000,\n\tALL = WRITE + TRAVERSE + ENTER + SPEAK + MUTE_DEAFEN + MOVE\n\t\t\t+ MAKE_CHANNEL + LINK_CHANNEL + WHISPER + TEXT_MESSAGE + MAKE_TEMP_CHANNEL + LISTEN\n\t\t\t+ KICK + BAN + REGISTER + SELF_REGISTER + RESET_USER_CONTENT,\n}\n```\n\n### mumble.reject\n\n```lua\nTable mumble.reject = {\n\t[0] = \"None\",\n\t[1] = \"WrongVersion\",\n\t[2] = \"InvalidUsername\",\n\t[3] = \"WrongUserPW\",\n\t[4] = \"WrongServerPW\",\n\t[5] = \"UsernameInUse\",\n\t[6] = \"ServerFull\",\n\t[7] = \"NoCertificate\",\n\t[8] = \"AuthenticatorFail\",\n}\n```\n\n### mumble.deny\n\n```lua\nTable mumble.deny = {\n\t[0]  = \"Text\",\n\t[1]  = \"Permission\",\n\t[2]  = \"SuperUser\",\n\t[3]  = \"ChannelName\",\n\t[4]  = \"TextTooLong\",\n\t[5]  = \"H9K\",\n\t[6]  = \"TemporaryChannel\",\n\t[7]  = \"MissingCertificate\",\n\t[8]  = \"UserName\",\n\t[9]  = \"ChannelFull\",\n\t[10] = \"NestingLimit\",\n\t[11] = \"ChannelCountLimit\",\n}\n```\n\n## hooks\n\n### `OnConnect (mumble.client client)`\n\nCalled when the connection to the server is fully established.\n\n### `OnDisconnect (mumble.client client, String reason)`\n\nCalled when the connection to the server is disconnected for any reason.\n\n### `OnServerVersion (mumble.client client, Table event)`\n\nCalled when the server version information is recieved.\n\n``` lua\nTable event = {\n\t[\"version\"]\t\t= Number version,\n\t[\"release\"]\t\t= String release,\n\t[\"os\"]\t\t\t= String os,\n\t[\"os_version\"]\t= String os_version,\n}\n```\n___\n\n### `OnPongTCP (mumble.client client, Table event)`\n\nCalled when the server sends a responce to a TCP ping request.\n\n``` lua\nTable event = {\n\t[\"ping\"]\t\t\t= Number ping,\n\t[\"timestamp\"]\t\t= Number timestamp,\n\t[\"good\"]\t\t\t= Number good,\n\t[\"late\"]\t\t\t= Number late,\n\t[\"lost\"]\t\t\t= Number lost,\n\t[\"resync\"]\t\t\t= Number resync,\n\t[\"udp_packets\"]\t\t= Number udp_packets,\n\t[\"tcp_packets\"]\t\t= Number tcp_packets,\n\t[\"udp_ping_avg\"]\t= Number udp_ping_avg,\n\t[\"udp_ping_var\"]\t= Number udp_ping_var,\n\t[\"tcp_ping_avg\"]\t= Number tcp_ping_avg,\n\t[\"tcp_ping_var\"]\t= Number tcp_ping_var,\n}\n```\n___\n\n### `OnPongUDP (mumble.client client, Table event)`\n\nCalled when the server sends a responce to a UDP ping request.\n\n``` lua\nTable event = {\n\t[\"ping\"]\t\t\t= Number ping,\n\t[\"timestamp\"]\t\t= Number timestamp,\n}\n```\n___\n\n### `OnServerReject (mumble.client client, Table event)`\n\nCalled when you are rejected from connecting to the server.\n\n``` lua\nTable event = {\n\t[\"type\"]\t= mumble.reject type,\n\t[\"reason\"]\t= String reason,\n}\n```\n___\n\n### `OnServerSync (mumble.client client, Table event)`\n\nCalled after the bot has recieved all the mumble.user and mumble.channel states.\n\n``` lua\nTable event = {\n\t[\"user\"]\t\t\t= mumble.user user,\n\t[\"max_bandwidth\"]\t= Number max_bandwidth,\n\t[\"welcome_text\"]\t= String welcome_text,\n\t[\"permissions\"]\t\t= Number permissions,\n}\n```\n___\n\n### `OnChannelRemove (mumble.client client, mumble.channel channel)`\n\nCalled when a mumble.channel is removed.\n___\n\n### `OnChannelState (mumble.client client, Table event)`\n\nCalled when a mumble.channel state has changed.. Like updating the name, description, position, comment, etc..\nNot every value will always be set. Only the fields that are currently changing will be set!\n\n``` lua\nTable event = {\n\t[\"channel\"]\t\t\t\t= mumble.channel channel,\n\t[\"parent\"]\t\t\t\t= mumble.channel parent,\n\t[\"channel_id\"]\t\t\t= Number channel_id,\n\t[\"position\"]\t\t\t= Number position,\n\t[\"max_users\"]\t\t\t= Number max_users,\n\t[\"name\"]\t\t\t\t= String name,\n\t[\"description\"]\t\t\t= String description,\n\t[\"description_hash\"]\t= String description_hash,\n\t[\"temporary\"]\t\t\t= Boolean temporary,\n\t[\"is_enter_restricted\"]\t= Boolean is_enter_restricted,\n\t[\"can_enter\"]\t\t\t= Boolean can_enter,\n\t[\"links\"]\t\t\t\t= {\n\t\t[1] = mumble.channel channel,\n\t\t...\n\t},\n\t[\"links_add\"]\t\t\t= {\n\t\t[1] = mumble.channel channel,\n\t\t...\n\t},\n\t[\"links_remove\"]\t\t= {\n\t\t[1] = mumble.channel channel,\n\t\t...\n\t}\n}\n```\n___\n\n### `OnUserChannel (mumble.client client, Table event)`\n\nCalled when a mumble.user changes their channel\n\n``` lua\nTable event = {\n\t[\"user\"]\t= mumble.user user,\n\t[\"actor\"]\t= mumble.user actor,\n\t[\"from\"]\t= mumble.channel from,\n\t[\"to\"]\t\t= mumble.channel to,\n}\n```\n\n### `OnUserRemove (mumble.client client, Table event)`\n\nCalled when a mumble.user disconnects or is kicked from the server\n\n``` lua\nTable event = {\n\t[\"user\"]\t= mumble.user user,\n\t[\"actor\"]\t= mumble.user actor,\n\t[\"reason\"]\t= String reason,\n\t[\"ban\"]\t\t= Boolean ban,\n}\n```\n___\n\n### `OnUserConnect (mumble.client client, Table event)`\n\nCalled when a mumble.user has connected to the server\n\n``` lua\nTable event = {\n\t[\"user\"]\t= mumble.user user,\n\t...\n}\n```\n___\n\n### `OnUserState (mumble.client client, Table event)`\n\nCalled when a mumble.user state has changed.. Like updating their comment, moving channels, muted, deafened, etc..\nNot every value will always be set. Only the fields that are currently changing will be set!\n\n``` lua\nTable event = {\n\t[\"user_id\"]\t\t\t\t= Number user_id,\n\t[\"session\"]\t\t\t\t= Number session,\n\t[\"actor\"]\t\t\t\t= mumble.user actor,\n\t[\"user\"]\t\t\t\t= mumble.user user,\n\t[\"channel\"]\t\t\t\t= mumble.channel channel,\n\t[\"mute\"]\t\t\t\t= Boolean mute,\n\t[\"deaf\"]\t\t\t\t= Boolean deaf,\n\t[\"self_mute\"]\t\t\t= Boolean self_mute,\n\t[\"self_deaf\"]\t\t\t= Boolean self_deaf,\n\t[\"suppress\"]\t\t\t= Boolean suppress,\n\t[\"recording\"]\t\t\t= Boolean recording,\n\t[\"priority_speaker\"]\t= Boolean priority_speaker,\n\t[\"name\"]\t\t\t\t= String name,\n\t[\"comment\"]\t\t\t\t= String comment,\n\t[\"texture\"]\t\t\t\t= String texture,\n\t[\"hash\"]\t\t\t\t= String hash,\n\t[\"comment_hash\"]\t\t= String comment_hash,\n\t[\"texture_hash\"]\t\t= String texture_hash,\n}\n```\n___\n\n### `OnUserStartSpeaking (mumble.client client, mumble.user)`\n\nCalled when a user starts to transmit voice data.\n___\n\n### `OnUserStopSpeaking (mumble.client client, mumble.user)`\n\nCalled when a user stops transmitting voice data.\n___\n\n### `OnUserSpeak (mumble.client client, Table event)`\n\nCalled when a user starts to transmit voice data.\n\n``` lua\nTable event = {\n\t[\"user\"]\t\t\t= mumble.user user,\n\t[\"codec\"]\t\t\t= Number codec,\n\t[\"target\"]\t\t\t= Number target,\n\t[\"sequence\"]\t\t= Number sequence,\n\t[\"data\"]\t\t\t= String encoded_opus_packet,\t-- Raw encoded audio data\n\t[\"frame_header\"]\t= Number frame_header,\t\t\t-- The frame header usually contains a length and terminator bit\n\t[\"speaking\"]\t\t= Boolean speaking,\t\t\t\t-- Is false when this is the last audio packet for the speaking user.\n\t[\"channels\"]\t\t= Number channels,\t\t\t\t-- How many channels were detected in this opus packet.\n\t[\"bandwidth\"]\t\t= Number bandwidth,\t\t\t\t-- How much bandwidth this opus packet uses.\n\t[\"samples_per_frame\"] = Number samples_per_frame,\t-- How many samples per frame this opus packet has.\n}\n```\n\nAudio loopback example\n\n```lua\nlocal decoder = mumble.decoder()\nlocal echoing\nlocal option = 1\n\nclient:hook(\"OnUserSpeak\", function(client, event)\n\tif client.me == event.user then return end\n\n\t-- We have two ways to echo voice data back\n\n\tif option == 1 then\n\n\t\t-- Create an audio buffer for this user\n\t\t-- This allows multiple people to be echoed at once\n\t\tif not event.user.audiobuffer then\n\t\t\tevent.user.audiobuffer = client:createAudioBuffer()\n\t\tend\n\n\t\t-- Option 1\n\t\t-- Decode the audio data and write it to our audiostream.\n\t\t-- This will be properly mixed with any audio streams that are playing. (via client:openAudio(\"sound.mp3\"):play())\n\t\tlocal decoded = decoder:decodeFloat(event.data)\n\n\t\tevent.user.audiobuffer:write(decoded)\n\n\telseif option == 2 and not echoing then\n\n\t\t-- Option 2\n\t\t-- Transmit the encoded data back directly.\n\t\t-- This will not sound right if any audio streams are playing. (via client:openAudio(\"sound.mp3\"):play())\n\t\tclient:transmit(event.codec, event.data, event.speaking)\n\n\t\t-- Keep echoing until the user stops speaking\n\t\techoing = speaking and event.user or nil\n\n\tend\nend)\n```\n\n___\n\n### `OnBanList (mumble.client client, Table banlist)`\n\nCalled on response to a `mumble.client:requestBanList()` call\n\n```lua\nTable banlist = {\n\t[1] = {\n\t\t[\"address\"] = {\n\t\t\t[\"string\"]\t= String ipaddress,\n\t\t\t[\"ipv4\"]\t= Boolean isipv4,\n\t\t\t[\"ipv6\"]\t= Boolean isipv6,\n\t\t\t[\"data\"]\t= Table raw,\n\t\t},\n\t\t[\"mask\"]\t\t= Number ip_mask,\n\t\t[\"name\"]\t\t= String name,\n\t\t[\"hash\"]\t\t= String hash,\n\t\t[\"reason\"]\t\t= String reason,\n\t\t[\"start\"]\t\t= String start,\n\t\t[\"duration\"]\t= Number duration\n\t},\n\t...\n}\n```\n___\n\n### `OnMessage (mumble.client client, Table event)`\n\nCalled when the bot receives a text message\n\n``` lua\nTable event = {\n\t[\"actor\"]\t\t= mumble.user actor,\n\t[\"message\"]\t\t= String message,\n\t[\"users\"]\t\t= Table users,\n\t[\"channels\"]\t= Table channels, -- will be nil when receiving a direct message\n\t[\"direct\"]\t\t= Boolean direct\n}\n```\n___\n\n### `OnPermissionDenied (mumble.client client, Table event)`\n\nCalled when an action is performed that you don't have permission to do\n\n``` lua\nTable event = {\n\t[\"type\"]\t\t= Number type,\n\t[\"permission\"]\t= Number permission,\n\t[\"channel\"]\t\t= mumble.channel channel,\n\t[\"user\"]\t\t= mumble.user user,\n\t[\"reason\"]\t\t= String reason,\n\t[\"name\"]\t\t= String name,\n}\n```\n___\n\n### `OnACL (mumble.client client, Table acl)`\n\nCalled when ACL data is received from a `mumble.channel:requestACL()` request\n\n```lua\nTable acl = {\n\t[\"channel\"]      = mumble.channel channel,\n\t[\"inherit_acls\"] = Boolean inherit_acls,\n\t[\"groups\"]       = {\n\t\t[1] = {\n\t\t\t[\"name\"]        = String group_name,\n\t\t\t[\"inherited\"]   = Boolean inherited,\n\t\t\t[\"inheritable\"] = Boolean inheritable,\n\t\t\t[\"add\"] = {\n\t\t\t\t[1] = Number user_id,\n\t\t\t\t...\n\t\t\t},\n\t\t\t[\"remove\"] = {\n\t\t\t\t[1] = Number user_id,\n\t\t\t\t...\n\t\t\t},\n\t\t\t[\"inherited_members\"] = {\n\t\t\t\t[1] = Number user_id,\n\t\t\t\t...\n\t\t\t}\n\t\t},\n\t\t...\n\t},\n\t[\"acls\"]       = {\n\t\t[1] = {\n\t\t\t[\"apply_here\"]  = Boolean apply_here,\n\t\t\t[\"apply_subs\"]  = Boolean apply_subs,\n\t\t\t[\"inherited\"]   = Boolean inherited,\n\t\t\t[\"user_id\"]     = Number user_id,\n\t\t\t[\"group\"]       = String group,\n\t\t\t[\"grant\"]       = Number grant, -- This number is a flag that determines what this group is allowed to do\n\t\t\t[\"deny\"]        = Number deny,  -- This number is a flag that determines what this group is NOT allowed to do\n\t\t},\n\t\t...\n\t},\n}\n```\n___\n\n### `OnCryptSetup (mumble.client client, Table event)`\n\nCalled when the server sends UDP encryption keys to the client.\n\n``` lua\nTable event = {\n\t[\"valid\"]\t\t\t= Boolean valid,\n\t[\"key\"]\t\t\t\t= String key,\n\t[\"client_nonce\"]\t= String client_nonce,\n\t[\"server_nonce\"]\t= String server_nonce,\n}\n```\n___\n\n### `OnUserList (mumble.client client, Table userlist)`\n\nCalled on response to a `mumble.client:requestUsers()` call\n\n```lua\nTable userlist = {\n\t[1] = {\n\t\t[\"user_id\"]\t\t\t= Number user_id,\n\t\t[\"name\"]\t\t\t= String name,\n\t\t[\"last_seen\"]\t\t= String last_seen,\n\t\t[\"last_channel\"]\t= mumble.channel last_channel,\n\t},\n\t...\n}\n```\n___\n\n### `OnPermissionQuery (mumble.client client, Table event)`\n\nCalled when the bot recieves permissions for a channel.\n\n``` lua\nTable event = {\n\t[\"channel\"]\t\t\t= mumble.channel channel,\n\t[\"permissions\"]\t\t= Number permissions,\n\t[\"flush\"]\t\t\t= Boolean flush,\n}\n```\n___\n\n### `OnCodecVersion (mumble.client client, Table event)`\n\nCalled when the bot recieves the codec info from the server.\n\n``` lua\nTable event = {\n\t[\"alpha\"]\t\t\t= Number alpha,\n\t[\"beta\"]\t\t\t= Number beta,\n\t[\"prefer_alpha\"]\t= Boolean prefer_alpha,\n\t[\"opus\"]\t\t\t= Boolean opus,\n}\n```\n___\n\n### `OnUserStats (mumble.client client, Table event)`\n\nCalled when the mumble.user's detailed statistics are received from the server.\nOnly sent if mumble.user:requestStats() is called.\n\n``` lua\nTable event = {\n\t[\"user\"]\t\t\t\t= mumble.user actor,\n\t[\"stats_only\"]\t\t\t= Boolean stats_only,\n\t[\"certificates\"]\t\t= Table certificates,\n\t[\"from_client\"]\t\t\t= {\n\t\t[\"good\"]\t= Number good,\n\t\t[\"late\"]\t= Number late,\n\t\t[\"lost\"]\t= Number lost,\n\t\t[\"resync\"]\t= Number resync,\n\t},\n\t[\"from_server\"]\t\t\t= {\n\t\t[\"good\"]\t= Number good,\n\t\t[\"late\"]\t= Number late,\n\t\t[\"lost\"]\t= Number lost,\n\t\t[\"resync\"]\t= Number resync,\n\t},\n\t[\"udp_packets\"]\t\t\t= Number udp_packets,\n\t[\"tcp_packets\"]\t\t\t= Number tcp_packets,\n\t[\"udp_ping_avg\"]\t\t= Number udp_ping_avg,\n\t[\"udp_ping_var\"]\t\t= Number udp_ping_var,\n\t[\"tcp_ping_avg\"]\t\t= Number tcp_ping_avg,\n\t[\"tcp_ping_var\"]\t\t= Number tcp_ping_var,\n\t[\"version\"]\t\t\t\t= Number version,\n\t[\"release\"]\t\t\t\t= String release,\n\t[\"os\"]\t\t\t\t\t= String os,\n\t[\"os_version\"]\t\t\t= String os_version,\n\t[\"certificates\"]\t\t= Table celt_versions,\n\t[\"address\"]\t\t\t\t= {\n\t\t[\"string\"]\t= String ipaddress,\n\t\t[\"ipv4\"]\t= Boolean isipv4,\n\t\t[\"ipv6\"]\t= Boolean isipv6,\n\t\t[\"data\"]\t= Table raw,\n\t},\n\t[\"bandwidth\"]\t\t\t= Number bandwidth,\n\t[\"onlinesecs\"]\t\t\t= Number onlinesecs,\n\t[\"idlesecs\"]\t\t\t= Number idlesecs,\n\t[\"strong_certificate\"]\t= Boolean strong_certificate,\n\t[\"opus\"]\t\t\t\t= Boolean opus,\n}\n```\n___\n\n### `OnServerConfig (mumble.client client, Table event)`\n\nCalled when the servers settings are received.\nUsually called after OnServerSync\n\n``` lua\nTable event = {\n\t[\"max_bandwidth\"]\t\t\t= Number max_bandwidth,\n\t[\"welcome_text\"]\t\t\t= String welcome_text,\n\t[\"allow_html\"]\t\t\t\t= Boolean allow_html,\n\t[\"message_length\"]\t\t\t= Number message_length,\n\t[\"image_message_length\"]\t= Number image_message_length,\n\t[\"max_users\"]\t\t\t\t= Number max_users,\n}\n```\n___\n\n### `OnSuggestConfig (mumble.client client, Table event)`\n\nCalled when the servers suggest the client to use specific settings.\n\n``` lua\nTable event = {\n\t[\"version\"]\t\t\t\t\t= Number version,\n\t[\"positional\"]\t\t\t\t= Boolean positional,\n\t[\"push_to_talk\"]\t\t\t= Boolean push_to_talk,\n}\n```\n___\n\n### `OnPluginData (mumble.client client, Table event)`\n\nCalled when the client receives plugin data from the server.\n\n``` lua\nTable event = {\n\t[\"sender\"] = mumble.user sender, -- Who sent this data packet\n\t[\"id\"]     = Number id,          -- The data ID of this packet\n\t[\"data\"]   = String data,        -- The data sent (can be binary data)\n\t[\"receivers\"]\t\t\t\t= {  -- A table of who is receiving this data\n\t\t[1] = mumble.user,\n\t\t...\n\t},\n}\n```\n___\n\n### `OnError (mumble.client client, String error)`\n\nCalled when an error occurs inside a hook.\nWARNING: Erroring within this hook will cause an error on the line where mumble.loop() is called, causing the script to exit\n___\n\n### `OnPingTCP (mumble.client client, Table event)`\n\nCalled just before a TCP ping is sent to the server.\nThis updates the users statistics found on their information panel.\nThe mumble.client will automatically ping the server every 30 seconds within mumble.loop()\n\n``` lua\nTable event = {\n\t[\"timestamp\"]\t\t= Number timestamp,\n\t[\"good\"]\t\t\t= Number good,\n\t[\"late\"]\t\t\t= Number late,\n\t[\"lost\"]\t\t\t= Number lost,\n\t[\"resync\"]\t\t\t= Number resync,\n\t[\"udp_packets\"]\t\t= Number udp_packets,\n\t[\"tcp_packets\"]\t\t= Number tcp_packets,\n\t[\"udp_ping_avg\"]\t= Number udp_ping_avg,\n\t[\"udp_ping_var\"]\t= Number udp_ping_var,\n\t[\"tcp_ping_avg\"]\t= Number tcp_ping_avg,\n\t[\"tcp_ping_var\"]\t= Number tcp_ping_var,\n}\n```\n___\n\n### `OnPingUDP (mumble.client client, Table event)`\n\nCalled just before a UDP ping is sent to the server.\nThe mumble.client will automatically ping the server every 30 seconds within mumble.loop()\n\n``` lua\nTable event = {\n\t[\"timestamp\"]\t\t= Number timestamp,\n}\n```\n\n___\n\n### `OnAudioStream (mumble.client client, Number samplerate, Number channels, Number frames)`\n\nCalled just before any playing audio streams are encoded and transmitted.\n\nSinwave tone example\n\n```lua\nlocal samples = 0\nlocal time = 0\nlocal audiostream = client:createAudioBuffer()\n\nclient:hook(\"OnAudioStream\", function(client, samplerate, channels, frames)\n\t-- The client is about to encode and stream x amount of frames\n\t-- Samplerate will always be 48000\n\t-- Channels will always be 2\n\t-- Frames will be based off the audio packet size\n\tfor i=1,frames do\n\t\tsamples = samples + 1\n\t\ttime = samples / samplerate\n\t\tfor c=1,channels do\n\t\t\t-- Write a 600hz tone to both channels for this frame\n\t\t\t-- Whatever is written to the output buffer will be mixed with any playing mumble.audiostream\n\t\t\taudiostream:writeFloat(math.sin(2 * math.pi * 600 * time))\n\t\tend\n\tend\nend)\n```\n___\n\n### `OnAudioStreamEnd (mumble.client client, mumble.audiostream stream)`\n\nCalled when a sound file has finished playing.\nPasses the the audio stream that finished.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkacjios%2Flua-mumble","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbkacjios%2Flua-mumble","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkacjios%2Flua-mumble/lists"}