A lua module to connect to a mumble server and interact with it
sudo apt-get install cmake pkgconf libluajit-5.1-dev protobuf-c-compiler libprotobuf-c-dev libssl-dev libopus-dev libuv1-dev libsndfile1-dev libsamplerate0-devNote: liblua5.1-0-dev can be substituted with libluajit-5.1-dev, liblua5.2-dev, or liblua5.3-dev depending on your needs.
sudo pacman -S cmake pkgconf luajit protobuf-c openssl libsndfile opus libuv libsamplerateNote: luajit can be substituted with lua5.1, lua5.2 or lua5.3 depending on your needs.
mkdir build
cd build
# Configure
cmake .. -DLUAVER=luajit -DLUALIB=/usr/local/lib/lua/5.1
# Build mumble.so
make
# Copies mumble.so to the provided LUALIB path
make install
# Removes mumble.so in the provided LUALIB path
make uninstallIf you want a debug build, add -DCMAKE_BUILD_TYPE=Debug to the cmake arguments
-- The mumble library is returned by a require calllocalmumble=require("mumble")
-- Create a new mumble client (Defaults to version 1.5.735 as defined in defines.h)mumble.client=mumble.client([Numberversion_major=1, Numberversion_minor=5, Numberversion_patch=735])
-- Main event loop that handles all events, ping, and audio processing-- This will block the script until SIGINT or mumble.stop(), so call this *after* you create your hooksmumble.loop()
-- Break out of the mumble.loop() callmumble.stop()
-- The client's user-- Is only available *after* "OnServerSync" is calledmumble.user=mumble.client.memumble.user=mumble.client:getMe()
mumble.user=mumble.client:getSelf()
-- A new timer object-- 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.-- Timers will keep the reference active until mumble.timer:stop() is called, or the timer stops on its own.-- Timers will dereference themselves if the timer is stopped after the callback funciton call.mumble.timer=mumble.timer()
-- A new buffer object-- Can be used to read/write raw binary data-- Can be initialized with data or a given sizemumble.buffer=mumble.buffer([NumbersizeorStringdata])
-- A new thread controller object-- The callback function will be ran in a separate thread.mumble.thread.controller=mumble.thread(StringfilenameorFunctioncallback(mumble.thread.workerworker))
-- A new voicetarget objectmumble.voicetarget=mumble.voicetarget()
-- A new opus encoder object-- Sample rate defaults to 48000-- Channels defaults to 2mumble.encoder=mumble.encoder(Numbersamplerate=48000, Numberchannels=2)
-- A new opus decoder object-- Sample rate defaults to 48000-- Channels defaults to 2mumble.decoder=mumble.decoder(Numbersamplerate=48000, Numberchannels=2)
-- A timestamp in millisecondsNumbertime=mumble.getTime()
-- A table of all currect clientsTableclients=mumble.getClients()
-- StructureTableclients= {
mumble.client,
mumble.client,
...
}-- Begins to connect to a mumble server.-- Returns true or false depending if we could start connecting or not.-- If connected is false, an error string will also be returned.-- Since this method is non-blocking, you can use the "OnConnect" hook to determine when the client has fully connected.Booleanconnecting, [ Stringerror ] =mumble.client:connect(Stringhost, Numberport, Stringcertificatefilepath, Stringkeyfilepath)
-- Authenticate as a user.-- Should be called inside an "OnConnect" hook.mumble.client:auth(Stringusername, [ Stringpassword, Tabletokens ])
-- Manually call a custom hook.-- Returns whatever the first hook that responded returned.Varargs...=mumble.client:call(Stringhook, ...)
-- Set the bots access tokensmumble.client:setTokens(Tabletokens)
-- Check if the client is connectedBooleanconnected=mumble.client:isConnected()
-- Check if the client has fully synced all users and channelsBooleansynced=mumble.client:isSynced()
-- Request the registered ban list from the server-- When server responds, it will call the 'OnBanList' hookmumble.client:requestBanList()
-- Request the registered user list from the server-- When server responds, it will call the 'OnUserList' hookmumble.client:requestUserList()
-- Disconnect from the connected servermumble.client:disconnect()
-- Transmit a plugin data packet-- User list can be a table of users or varargsmumble.client:sendPluginData(StringdataID, Stringplugindata, [Table {mumble.user..}, mumble.user..])
-- Transmit a raw, encoded, opus packet.-- Set speaking to false at the end of a stream.-- This should only be used if you don't plan on using mumble.client:openAudio() or mumble.client:createAudioBuffer(),-- since this will directly conflict with the internal output of this module.-- When audio data is streamed, it can trigger the following hooks: OnUserStartSpeaking, OnUserSpeak, OnUserStopSpeakingmumble.client:transmit(Numbercodec, Stringencoded_audio_packet, Booleanspeaking=true)
-- Open an audio file as an audio stream-- If audiostream = nil, it will pass along an error string as to why it couldn't open the file-- Allowed resample quality values: ["best", "medium", "fastest", "zero", "linear"]mumble.audiostreamaudiostream, [ Stringerror ] =mumble.client:openAudio(Stringaudiofilepath, StringresampleQuality="medium")
-- Creates a buffer that you can write raw, 32bit float, PCM data that will be output by the client as soon as it can.-- Creating multiple buffers will result in each buffer being mixed together during transmission, for simultaneous audio streaming.-- You should only ever use buffer:writeFloat(), but the other buffer methods are always available for whatever reason.-- When audio data is streamed, it can trigger the following hooks: OnUserStartSpeaking, OnUserSpeak, OnUserStopSpeakingmumble.bufferbuffer=mumble.client:createAudioBuffer([Numbersamplerate=48000, Numberchannels=2])
-- Gets a table of all currently playing audio streamsTableaudiostreams=mumble.client:getAudioStreams()
-- StructureTableaudiostreams= {
[1] =mumble.audiostream,
[2] =mumble.audiostream,
...
}
-- Sets the size of each audio packet played.-- The larger the packet size, the less chance of static.-- Larger = higher audio latency.-- Smaller = lower audio latency.Tablemumble.audio= {
["TINY"] =1,
["SMALL"] =2,
["MEDIUM"] =3,
["LARGE"] =4,
}
mumble.client:setAudioPacketSize(Numbersize= [TINY=1, SMALL=2, MEDIUM=3, LARGE=4])
-- Returns the current duration of each audio packet-- Default: mumble.audio.TINY = 1Numbersize=mumble.client:getAudioPacketSize()
-- Sets the global volume level-- Consider this the master volume levelmumble.client:setVolume(Numbervolume)
-- Gets the global volume levelNumbervolume=mumble.client:getVolume()
-- Returns if the client is tunneling UDP voice data through the TCP connection-- This will be true until the first "OnPongUDP" callBooleantunneludp=mumble.client:isTunnelingUDP()
-- Returns if the client is a legacy client or notBooleanisLegacy=mumble.client:isLegacy()
-- Attempts to change the bots commentmumble.client:setComment(Stringcomment)
-- Adds a callback for a specific event-- If no unique name is passed, it will default to "hook"mumble.client:hook(Stringhook, [ Stringuniquename="hook" ], Functioncallback(mumble.client))
-- Remove a callback for a specific event-- If no unique name is passed, it will default to "hook"mumble.client:unhook(Stringhook, [ Stringuniquename="hook" ])
-- Gets all registered callbacksTablehooks=mumble.client:getHooks()
-- StructureTablehooks= {
["OnServerSync"] = {
["hook"] =function: 0xffffffff,
["do stuff on connection"] =function: 0xffffffff,
},
["OnPingTCP"] = {
["hook"] =function: 0xffffffff,
["do stuff on ping"] =function: 0xffffffff,
},
...
}
-- Register a mumble.voicetarget to the server-- Accepts multiple mumble.voicetarget objects that will all be assigned to the given IDmumble.client:registerVoiceTarget(Numberid, mumble.voicetarget...)
-- Set the current voice target that mumble.client:play() will abide by-- Defaults to 0, the default voice targetmumble.client:setVoiceTarget(Numberid)
-- Get the current voice targetNumberid=mumble.client:getVoiceTarget()
-- Get the encoder object that the internal audio system uses to encode audio datamumble.encoderencoder=mumble.client:getEncoder()
-- Get the average ping of the clientNumberping=mumble.client:getPing()
-- Get the uptime of the current client in secondsNumbertime=mumble.client:getUpTime()
-- Returns a table of all mumble.usersTableusers=mumble.client:getUsers()
-- Structure-- Key: index-- Value: mumble.userTableusers= {
[1] =mumble.user,
[2] =mumble.user,
[3] =mumble.user,
...
}
-- Allows you to lookup a channel using a file path syntax.-- Will default to "." for the root channel.-- "." for current channel-- ".." for parent channel-- "/" for seperator-- "name" for channel name-- If the channel name doesn't exist, it will return nilmumble.channelchannel=mumble.client:getChannel([Stringpath="."])
-- Exampleslocalroot=mumble.client:getChannel()
localtesting=mumble.client:getChannel("Testing")
localroot=mumble.client:getChannel("Testing/..")
-- Returns a table of all mumble.channelsTablechannels=mumble.client:getChannels()
-- Structure-- Key: channel id-- Value: mumble.channelTablechannels= {
[id] =mumble.channel,
[id] =mumble.channel,
...
}
-- Request a users full texture data blob-- Server will respond with a "OnUserState" with the requested data filled outmumble.client:requestTextureBlob([Table {mumble.user, ...}, mumble.user..])
-- Request a users full comment data blob-- Server will respond with a "OnUserState" with the requested data filled out-- After the hook is called, mumble.user:getComment() will also return the full datamumble.client:requestCommentBlob([Table {mumble.user, ...}, mumble.user..])
-- Request a channels full description data blob-- Server will respond with a "OnChannelState" with the requested data filled out-- After the hook is called, mumble.channel:getDescription() will also return the full datamumble.client:requestDescriptionBlob(T[Table {mumble.channel, ...}, mumble.channel..])
-- Creates a channel-- Will be parented to the root channelmumble.client:createChannel(Stringname, [ Stringdescription="", Numberposition=0, Booleantemporary=false, Numbermax_users=0 ])-- Sends a text message to a usermumble.user:message(Stringhost)
-- Attempts to kick a user with an optional reason valuemumble.user:kick([ Stringreason ])
-- Attempts to ban a user with an optional reason valuemumble.user:ban([ Stringreason ])
-- Attempts to move a user to a different channelmumble.user:move(mumble.channelchannel)
-- Attempts to mute a user-- If no boolean is passed, it will default to muting the usermumble.user:setMuted([ Booleanmute=true ])
-- Attempts to deafen a user-- If no boolean is passed, it will default to deafening the usermumble.user:setDeaf([ Booleandeaf=true ])
-- Attempts to register the users name to the servermumble.user:register()
-- Requests the users information statistics from the server-- If no boolean is passed, it will default to requesting ALL statisticsmumble.user:requestStats([ Booleanstatsonly=false ])
-- Gets the current mumble.client this user is a part ofmumble.clientclient=mumble.user:getClient()
-- Gets the current session numberNumbersession=mumble.user:getSession()
-- Gets the name of the userStringname=mumble.user:getName()
-- Gets the channel of the usermumble.channelchannel=mumble.user:getChannel()
-- Gets the registered ID of the user-- Is 0 for unregistered usersNumberuserid=mumble.user:getId()
-- Returns if the user is registered or notBooleanregistered=mumble.user:isRegistered()
-- Returns if the user is muted or notBooleanmuted=mumble.user:isMuted()
-- Returns if the user is deaf or notBooleandeaf=mumble.user:isDeaf()
-- Returns if the user is muted or notBooleanmuted=mumble.user:isSelfMute()
-- Returns if the user is deaf or notBooleandeaf=mumble.user:isSelfDeaf()
-- Returns if the user is suppressed by the serverBooleansuppressed=mumble.user:isSuppressed()
-- Returns the comment string of the users commentStringcomment=mumble.user:getComment()
-- Returns the comments SHA1 hashStringhash=mumble.user:getCommentHash()
-- Returns if the user is speaking or notBooleanspeaking=mumble.user:isSpeaking()
-- Returns if the user is recording or notBooleanrecording=mumble.user:isRecording()
-- Returns if the user is a priority speaker or notBooleanpriority=mumble.user:isPrioritySpeaker()
-- Returns the users avatar as a string of bytesStringtexture=mumble.user:getTexture()
-- Returns the users avatar as a SHA1 hashStringhash=mumble.user:getTextureHash()
-- Returns the users username SHA1 hashStringhash=mumble.user:getHash()
-- Sets the users avatar image using a string of bytesmumble.user:setTexure(Stringbytes)
-- Adds a channel to the list of channels the user is listening to-- Channel list can be a table of channels or varargsmumble.user:listen([Table {mumble.channel..}, mumble.channel..])
-- Removes a channel from the list of channels the user is listening to-- Channel list can be a table of channels or varargsmumble.user:unlisten([Table {mumble.channel..}, mumble.channel..])
-- Returns if the user is listening to this channel or notBooleanisListening=mumble.user:isListening(mumble.channelchannel)
-- Returns a table of all channels the user is currently listening toTablelistens=mumble.user:getListens()
-- Structure-- Key: channel id-- Value: mumble.channelTablechannels= {
[id] =mumble.channel,
[id] =mumble.channel,
...
}
-- Transmit a plugin data packet to this usermumble.user:sendPluginData(StringdataID, Stringplugindata)
-- Request a users full texture data blob-- Server will respond with a "OnUserState" with the requested data filled out-- After the hook is called, mumble.user:getTexture() will also return the full datamumble.user:requestTextureBlob()
-- Request a users full comment data blob-- Server will respond with a "OnUserState" with the requested data filled out-- After the hook is called, mumble.user:getComment() will also return the full datamumble.user:requestCommentBlob()
-- Starts recording a users voice output to an ogg file.-- Will return nil and an error string if it failed to create the file.Booleansuccess, [Stringerror] =mumble.user:startRecord(StringoggFilePath)
-- Will return true if we successfully stopped recording.-- Will return false if the user wasn't being recorded.Booleansuccess=mumble.user:stopRecord()
-- Returns if the user is being recorded or not.BooleanisBeingRecorded=mumble.user:isBeingRecorded()-- Gets a channel relative to the currentmumble.channelchannel=mumble.channel(Stringpath)
mumble.channelparents_parent=mumble.channel("../..")
mumble.channelchild=mumble.channel("Child")
-- Sends a text message to the entire channelmumble.channel:message(Stringmessage)
-- Attempts to set the channels descriptionmumble.channel:setDescription(Stringdescription)
-- Attempts to remove the channelmumble.channel:remove()
-- Gets the current mumble.client this channel is a part ofmumble.clientclient=mumble.channel:getClient()
-- Gets the channels nameStringname=mumble.channel:getName()
-- Gets the channel IDNumberid=mumble.channel:getId()
-- Gets the parent channel-- Returns nil on root channelmumble.channelchannel=mumble.channel:getParent()
-- Returns the channels that are parented to the channelTablechildren=mumble.channel:getChildren()
-- Returns the users that are currently within the channelTableusers=mumble.channel:getUsers()
-- Structure-- Key: index-- Value: mumble.userTableusers= {
[1] =mumble.user,
[2] =mumble.user,
[3] =mumble.user,
...
}
-- Gets the channels descriptionStringdescription=mumble.channel:getDescription()
-- Gets the channels description SHA1 hashStringhash=mumble.channel:getDescriptionHash()
-- Returns if the channel is temporary or notBooleantemporary=mumble.channel:isTemporary()
-- Returns the channels positionNumberposition=mumble.channel:getPosition()
-- Gets the max number of users allowed in this channelNumbermax=mumble.channel:getMaxUsers()
-- Returns a table of all linked channelsNumberlinked=mumble.channel:getLinked()
-- Attempts to link channel(s)-- Channel list can be a table of channels or varargsmumble.channel:link([Table {mumble.channel..}, mumble.channel..])
-- Attempts to unlink channel(s)-- Channel list can be a table of channels or varargsmumble.channel:unlink([Table {mumble.channel..}, mumble.channel..])
-- Returns if the client is restricted from entering the channel-- NOTE: *Will only work in mumble version 1.4+*Booleanrestricted=mumble.channel:isEnterRestricted()
-- Returns if the client is able to enter the channel-- NOTE: *Will only work in mumble version 1.4+*Booleanenter=mumble.channel:canEnter()
-- Request ACL config for the channel-- When server responds, it will call the 'OnACL' hookmumble.channel:requestACL()
-- Request permissions for the channel-- When server responds, it will call the 'OnPermissionQuery' hookmumble.channel:requestPermissions()
-- Gets the permissions value for the channelNumberpermissions=mumble.channel:getPermissions()
-- Gets the permissions value for the channelBooleanpermission=mumble.channel:hasPermission(mumble.aclflag)
-- Request a users full texture data blob-- Server will respond with a "OnChannelState" with the requested data filled out-- After the hook is called, mumble.channel:getDescription() will also return the full datamumble.channel:requestTextureBlob()
-- Creates a channel-- Will be parented to the channel that this method was called frommumble.channel:create(Stringname, Stringdescription="", Numberposition=0, Booleantemporary=false, Numbermax_users=0)-- Run the timer with a given callback function.-- The callback function will first be called after the initial delay.-- If the timers repeat value is > 0, it will then repeat over using the repeat value as the delay.-- While the timer is running, the timer will not be garbage collected.-- It will only be garabage collected once the timer stops on its own, or mumble.timer:stop() is called.mumble.timer=mumble.timer:start(Functioncallback(mumble.timer), Numberafter=0, Numberrepeat=0)
-- Stops the timer and readies the timer for garabage collectionmumble.timer:stop()
-- Pauses the timer-- Will error out if the timer is not repeating or hasn't been started previously.mumble.timer:pause()
-- Restarts the timer and sets the iteration count back to 0-- Will error out if the timer is not repeating or hasn't been started previously.mumble.timer:again()
-- Resumes the timer-- Will error out if the timer is not repeating or hasn't been started previously.mumble.timer:resume()
-- Sets the timers delay and repeat valuesmumble.timer:set(Numberafter, [ Numberrepeat=0 ])
-- Gets the timers delay and repeat valuesNumberafter, Numberrepeat=mumble.timer:get()
-- Sets the timers delay valuemumble.timer:setDuration(Numberafter)
-- Gets the timers delay valueNumberafter=mumble.timer:getDuration()
-- Sets the timers repeat valuemumble.timer:setRepeat(Numberrepeat)
-- Gets the timers repeat valueNumberrepeat=mumble.timer:getRepeat()
-- Retruns if the timer is currently runningBooleanrunning=mumble.timer:isActive()
-- Get how many times the timer has loopedNumbercount=mumble.timer:getCount()
-- Get how many seconds remain until the callback is triggeredNumberremain=mumble.timer:getRemain()
mumble.timer=mumble.timer:set(Numberafter, Numberrepeat=0)
-- Returns if the timer is currently running or not.Booleanactive=mumble.timer:isActive()
-- Returns if the timer is currently paused or not.Booleanpaused=mumble.timer:isPaused()A buffer object used to read/write data from. It will dynamically adjust its capacity to fit all written data.
-- Packs the buffer, moving all remaining data that has not been read to the start.-- BEFORE PACK = [1234|5678|]-- Read head ^ ^ Write head-- AFTER PACK = [|5678|]-- Read head ^ ^ Write head-- If the read head and write head are in the same position, the buffer is cleared.buffer:pack()
-- Resets the buffer, setting the read head and write head to the start.-- Esentially empties the buffer, but the capacity will remain the same.buffer:reset()
-- Flips the buffer, preparing it for reading by setting the position to 0-- Does not alter the write head, so data can continue to be written to it.buffer:flip()
-- Get the length of the bufferNumberlength=buffer.lengthNumberlength=#buffer-- Get a byte from the buffer without readingStringbyte=buffer[Numberindex]
-- Returns the capacity of the buffer, which is the total amount of space allocatedNumbercapacity=buffer.capacity-- Returns if the buffer has no data available to be read.-- Works by checking if the read head position equals the write head position.BooleanisEmpty=buffer:isEmpty()
-- Returns the current read_head position in the bufferNumberread_head=buffer.read_head, sameasbuffer:seek("read")
-- Returns the current write_head position in the bufferNumberwrite_head=buffer.write_head, sameasbuffer:seek("write")
-- Will attempt to seek to a given position via offset numbers.-- See: https://www.lua.org/pil/21.3.html-- Returns the offset that it has seeked to.-- Mode defaults to "read"-- Whence defaults to "cur"-- Offset defaults to 0-- If the mode is set to "both" the read and write values will be returned.Numberposition=buffer:seek([Stringmode ["read", "write", "both"] ="read", Stringwhence ["set", "cur", "end"] ="cur", offset=0])
-- Write the given string to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:write(Stringdata)
-- Reads the specified number of bytes from the buffer and returns the data as a string-- Accepts multiple arguments, like buffer:read(4, 6, "*all")Stringdata=buffer:read([Numberlength, Stringformat, ..]
-- Write a single byte to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeByte(Numbervalue)
-- Reads a single byte from the buffer and returns itNumbervalue=buffer:readByte()
-- Write a short integer to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeShort(Numbervalue)
-- Reads a short integer from the buffer and returns itNumbervalue=buffer:readShort()
-- Write a 32-bit integer to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeInt(Numbervalue)
-- Reads a 32-bit integer from the buffer and returns itNumbervalue=buffer:readInt()
-- Write a variable-length integer to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeVarInt(Numbervalue)
-- Reads a variable-length integer from the buffer and returns itNumbervalue=buffer:readVarInt()
-- Write a float to the buffer-- Returns how many bytes were written to the bufferbufferNumberwritten=buffer:writeFloat(Numbervalue)
-- Reads a float from the buffer and returns itNumbervalue=buffer:readFloat()
-- Write a double to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeDouble(Numbervalue)
-- Reads a double from the buffer and returns itNumbervalue=buffer:readDouble()
-- Write a string to the buffer, including its length as a variable-length integer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeString(Stringvalue)
-- Reads a string from the buffer, using a variable-length integer to determine its sizeStringvalue=buffer:readString()
-- Write a boolean value (as 0 or 1) to the buffer-- Returns how many bytes were written to the bufferNumberwritten=buffer:writeBool(Booleanvalue)
-- Reads a boolean value from the buffer (returns true or false)Booleanvalue=buffer:readBool()-- Sets a callback function that will be called when the worker is joined back into the controller thread.mumble.thread.controller=mumble.thread.controller:onFinish(Functioncallback(mumble.thread.controller))
-- Sets a callback function that will be called when the controller receives a message from the worker.mumble.thread.controller=mumble.thread.controller:onMessage(Functioncallback(Stringmessage))
-- Sends a message to the worker thread.mumble.thread.controller=mumble.thread.controller:send([Stringmessage, mumble.buffermessage])
-- Blocks the main thread until the worker completes.mumble.thread.controller=mumble.thread.controller:join()-- Sleep the worker thread for however many milliseconds.mumble.thread.worker=mumble.thread.worker:sleep(Numbermilliseconds)
-- Keep the thread open until singnaled to close.-- Allows us to receive messages using mumble.worker.onMessage.mumble.thread.worker=mumble.thread.worker:loop()
-- Signals the thread to exit its loop.mumble.thread.worker=mumble.thread.worker:stop()
-- A new buffer object. (shortcut for mumble.buffer())-- Can be used to read/write raw binary data.-- Can be initialized with data or a given size.mumble.buffer=mumble.thread.worker:buffer([Numbersize, Stringdata])
-- Sets a callback function that will be called when the worker receives a message from the controller.mumble.thread.controller=mumble.thread.controller:onMessage(Functioncallback(Stringmessage))
-- Sends a message to the controller thread.mumble.thread.controller=mumble.thread.controller:send([Stringmessage, mumble.buffermessage])--local thread = mumble.thread("thread.lua")localoutsideValue="outside scope"localthread=mumble.thread(function(worker)
-- This function is ran in a separate thread and will not block.-- The scope of this function starts here and can not access upvalues from the outer scope.print("outsideValue", outsideValue) -- outsideValue is nil here.worker:send("my work has begun")
fori=1,3doworker:sleep(1000)
worker:send("hello " ..i)
endworker:send("my work has completed")
end):onMessage(function(t, msg)
-- Use this to receive data from the worker thread.print("worker: " ..msg)
end):onFinish(function(t)
-- Thread was joined back into our main thread.print("thread finished", t)
end)Output
outsideValue nil
worker: my work has begun
worker: hello 1
worker: hello 2
thread finished mumble.thread.controller: 0x7ffff7b7bc70
worker: hello 3
worker: my work has completed
thread.lua
-- When running a file in a thread, the worker will be passed in as arg[1]localworker=...-- This function is ran in a separate thread and will not block.-- The scope of this function starts here and can not access upvalues from the outer scope.worker:send("my work has begun")
fori=1,3doworker:sleep(1000)
worker:send("hello " ..i)
endworker:send("my work has completed")-- Add a user to whisper tomumble.voicetarget:addUser(mumble.useruser)
-- Return a table of all the users currently in the voicetargetTableusers=mumble.voicetarget:getUsers()
-- Structure-- Key: index-- Value: Number sessionTablechannels= {
Numbersession,
Numbersession,
...
}
-- Sets the channel that is be shouted tomumble.voicetarget:setChannel(mumble.channelchannel)
-- Gets the channel that is shouted tomumble.voicetarget:getChannel()
-- Sets the specific user group to whisper tomumble.voicetarget:setGroup(Stringgroup)
-- Gets the group name we are whispering toStringgroup=mumble.voicetarget:getGroup()
-- Shout to the linked channels of the set channelmumble.voicetarget:setLinks(Booleanfollowlinks)
-- Returns if we are currently shouting to linked channels of the set channelBooleanlinks=mumble.voicetarget:getLinks()
-- Shout to the children of the set channelmumble.voicetarget:setChildren(Booleanfollowchildren)
-- Returns if we are currently shouting to children of the set channelBooleanchildren=mumble.voicetarget:getChildren()-- Equivalent to OPUS_GET_FINAL_RANGENumberrange=mumble.encoder:getFinalRange()
-- Equivalent to OPUS_GET_PITCHNumberpitch=mumble.encoder:getPitch()
-- Equivalent to OPUS_GET_BANDWIDTHNumberbandwidth=mumble.encoder:getBandwidth()
-- Equivalent to OPUS_GET_SAMPLE_RATENumbersamplerate=mumble.encoder:getSamplerate()
-- Equivalent to OPUS_GET_PHASE_INVERSION_DISABLEDBooleninversion=mumble.encoder:getPhaseInversionDisabled()
-- Equivalent to OPUS_SET_PHASE_INVERSION_DISABLEDmumble.encoder:setPhaseInversionDisabled(Booleaninversion)
-- Equivalent to OPUS_GET_IN_DTXBoolenindtx=mumble.encoder:getInDTX()
-- Equivalent to OPUS_GET_COMPLEXITYNumberbitrate=mumble.encoder:getComplexity()
-- Equivalent to OPUS_SET_COMPLEXITYmumble.encoder:setComplexity(Numbercomplexity)
-- Equivalent to OPUS_GET_BITRATENumberbitrate=mumble.encoder:getBitRate()
-- Equivalent to OPUS_SET_BITRATEmumble.encoder:setBitRate(Numberbitrate)
-- Encode X number of pcm 16 bit short frames into an opus audio packetStringencoded=mumble.encoder:encode(Numberframes, Stringpcm)
-- Encode X number of pcm 32 bit float frames into an opus audio packetStringencoded=mumble.encoder:encodeFloat(Numberframes, Stringpcm)-- Equivalent to OPUS_RESET_STATEmumble.decoder:reset()
-- Equivalent to OPUS_GET_FINAL_RANGENumberrange=mumble.decoder:getFinalRange()
-- Equivalent to OPUS_GET_PITCHNumberpitch=mumble.decoder:getPitch()
-- Equivalent to OPUS_GET_BANDWIDTHNumberbandwidth=mumble.decoder:getBandwidth()
-- Equivalent to OPUS_GET_SAMPLE_RATENumbersamplerate=mumble.decoder:getSamplerate()
-- Equivalent to OPUS_GET_PHASE_INVERSION_DISABLEDBooleninversion=mumble.decoder:getPhaseInversionDisabled()
-- Equivalent to OPUS_SET_PHASE_INVERSION_DISABLEDmumble.decoder:setPhaseInversionDisabled(Booleaninversion)
-- Equivalent to OPUS_GET_IN_DTXBoolenindtx=mumble.decoder:getInDTX()
-- Decode an opus audio packet into raw PCM dataStringdecoded=mumble.decoder:decode(Stringencoded)
-- Decode an opus audio packet into raw PCM float dataStringdecoded=mumble.decoder:decodeFloat(Stringencoded)Click here for a list of supported audio formats
All audio will be resampled to 48000 Hz and remixed to stereo.
-- Returns if this audio stream is currently playing or notBooleanisplaying=mumble.audiostream:isPlaying()
-- Sets the volume of the audio stream-- Returns itself so you can stack calls-- example: client:openOgg("file.ogg"):setVolume(0.5):setLooping(true):play()mumble.audiostream=mumble.audiostream:setVolume(Numbervolume)
-- Gets the volume of the audio streamNumbervolume=mumble.audiostream:getVolume()
-- Pause the audiomumble.audiostream:pause()
-- Resume playing the audiomumble.audiostream:play()
-- Pauses the audio AND resets playback to the beginning-- Will remove the stream from the mumble.client:getAudioStreams() tablemumble.audiostream:stop()
-- Fade the volume to the specified volume over the duration.mumble.audiostream:fadeTo(Numbervolume, Numberduration=1)
-- Fade the volume to 0 over the duration and stop playing.mumble.audiostream:fadeOut(Numberduration=1)
-- Will attempt to seek to a given position via sample numbers.-- See: https://www.lua.org/pil/21.3.html-- Returns the offset that it has seeked to.-- Mode defaults to "read"-- Whence defaults to "cur"-- Offset defaults to 0Numbersamples=mumble.audiostream:seek(Stringwhence ["set", "cur", "end"] ="cur", Numberoffset=0)
-- Returns the duration of the stream given the unit typeNumbersamples/seconds=mumble.audiostream:getLength(Stringunits ["seconds", "samples"])
-- Returns a table of information about the audio file.Tableinfo=mumble.audiostream:getInfo()
-- Structure-- Key: String-- Value: NumberTableinfo= {
["channels"] =Numberchannels,
["sample_rate"] =Numbersample_rate,
["setup_memory_required"] =Numbersetup_memory_required,
["setup_temp_memory_required"] =Numbersetup_temp_memory_required,
["temp_memory_required"] =Numbertemp_memory_required,
["max_frame_size"] =Numbermax_frame_size
}
-- Returns the title of the file.-- Will return nil if not available.Stringtitle=mumble.audiostream:getTitle()
-- Returns the artist of the file.-- Will return nil if not available.Stringartist=mumble.audiostream:getArtist()
-- Returns the copyright of the file.-- Will return nil if not available.Stringtitle=mumble.audiostream:getCopyright()
-- Returns the software the file was created in.-- Will return nil if not available.Stringtitle=mumble.audiostream:getSoftware()
-- Returns the comments of the file.-- Will return nil if not available.Stringcomments=mumble.audiostream:getComments()
-- Enables the audio stream to loop to the beginning when reaching the end.-- Boolean = true will cause it to loop forever.-- Number = Will loop X amount of times before eventually stopping.-- Returns itself so you can stack calls.-- example: client:openOgg("file.ogg"):setVolume(0.5):setLooping(true):play()mumble.audiostream=mumble.audiostream:setLooping([Booleanloop, Numberloop_count])
-- Returns if the stream is looping or notBooleanlooping=mumble.audiostream:isLooping()
-- Retuns how many more times the stream will loop before stopping.-- If you used setLooping(true), this will return math.huge (inf)Numbercount=mumble.audiostream:getLoopCount()Tablemumble.acl= {
NONE=0x0,
WRITE=0x1,
TRAVERSE=0x2,
ENTER=0x4,
SPEAK=0x8,
MUTE_DEAFEN=0x10,
MOVE=0x20,
MAKE_CHANNEL=0x40,
LINK_CHANNEL=0x80,
WHISPER=0x100,
TEXT_MESSAGE=0x200,
MAKE_TEMP_CHANNEL=0x400,
LISTEN=0x800,
-- Root channel onlyKICK=0x10000,
BAN=0x20000,
REGISTER=0x40000,
SELF_REGISTER=0x80000,
RESET_USER_CONTENT=0x100000,
CACHED=0x8000000,
ALL=WRITE+TRAVERSE+ENTER+SPEAK+MUTE_DEAFEN+MOVE+MAKE_CHANNEL+LINK_CHANNEL+WHISPER+TEXT_MESSAGE+MAKE_TEMP_CHANNEL+LISTEN+KICK+BAN+REGISTER+SELF_REGISTER+RESET_USER_CONTENT,
}Tablemumble.reject= {
[0] ="None",
[1] ="WrongVersion",
[2] ="InvalidUsername",
[3] ="WrongUserPW",
[4] ="WrongServerPW",
[5] ="UsernameInUse",
[6] ="ServerFull",
[7] ="NoCertificate",
[8] ="AuthenticatorFail",
}Tablemumble.deny= {
[0] ="Text",
[1] ="Permission",
[2] ="SuperUser",
[3] ="ChannelName",
[4] ="TextTooLong",
[5] ="H9K",
[6] ="TemporaryChannel",
[7] ="MissingCertificate",
[8] ="UserName",
[9] ="ChannelFull",
[10] ="NestingLimit",
[11] ="ChannelCountLimit",
}Called when the connection to the server is fully established.
Called when the connection to the server is disconnected for any reason.
Called when the server version information is recieved.
Tableevent= {
["version"] =Numberversion,
["release"] =Stringrelease,
["os"] =Stringos,
["os_version"] =Stringos_version,
}Called when the server sends a responce to a TCP ping request.
Tableevent= {
["ping"] =Numberping,
["timestamp"] =Numbertimestamp,
["good"] =Numbergood,
["late"] =Numberlate,
["lost"] =Numberlost,
["resync"] =Numberresync,
["udp_packets"] =Numberudp_packets,
["tcp_packets"] =Numbertcp_packets,
["udp_ping_avg"] =Numberudp_ping_avg,
["udp_ping_var"] =Numberudp_ping_var,
["tcp_ping_avg"] =Numbertcp_ping_avg,
["tcp_ping_var"] =Numbertcp_ping_var,
}Called when the server sends a responce to a UDP ping request.
Tableevent= {
["ping"] =Numberping,
["timestamp"] =Numbertimestamp,
}Called when you are rejected from connecting to the server.
Tableevent= {
["type"] =mumble.rejecttype,
["reason"] =Stringreason,
}Called after the bot has recieved all the mumble.user and mumble.channel states.
Tableevent= {
["user"] =mumble.useruser,
["max_bandwidth"] =Numbermax_bandwidth,
["welcome_text"] =Stringwelcome_text,
["permissions"] =Numberpermissions,
}Called when a mumble.channel is removed.
Called when a mumble.channel state has changed.. Like updating the name, description, position, comment, etc.. Not every value will always be set. Only the fields that are currently changing will be set!
Tableevent= {
["channel"] =mumble.channelchannel,
["parent"] =mumble.channelparent,
["channel_id"] =Numberchannel_id,
["position"] =Numberposition,
["max_users"] =Numbermax_users,
["name"] =Stringname,
["description"] =Stringdescription,
["description_hash"] =Stringdescription_hash,
["temporary"] =Booleantemporary,
["is_enter_restricted"] =Booleanis_enter_restricted,
["can_enter"] =Booleancan_enter,
["links"] = {
[1] =mumble.channelchannel,
...
},
["links_add"] = {
[1] =mumble.channelchannel,
...
},
["links_remove"] = {
[1] =mumble.channelchannel,
...
}
}Called when a mumble.user changes their channel
Tableevent= {
["user"] =mumble.useruser,
["actor"] =mumble.useractor,
["from"] =mumble.channelfrom,
["to"] =mumble.channelto,
}Called when a mumble.user disconnects or is kicked from the server
Tableevent= {
["user"] =mumble.useruser,
["actor"] =mumble.useractor,
["reason"] =Stringreason,
["ban"] =Booleanban,
}Called when a mumble.user has connected to the server
Tableevent= {
["user"] =mumble.useruser,
...
}Called when a mumble.user state has changed.. Like updating their comment, moving channels, muted, deafened, etc.. Not every value will always be set. Only the fields that are currently changing will be set!
Tableevent= {
["user_id"] =Numberuser_id,
["session"] =Numbersession,
["actor"] =mumble.useractor,
["user"] =mumble.useruser,
["channel"] =mumble.channelchannel,
["mute"] =Booleanmute,
["deaf"] =Booleandeaf,
["self_mute"] =Booleanself_mute,
["self_deaf"] =Booleanself_deaf,
["suppress"] =Booleansuppress,
["recording"] =Booleanrecording,
["priority_speaker"] =Booleanpriority_speaker,
["name"] =Stringname,
["comment"] =Stringcomment,
["texture"] =Stringtexture,
["hash"] =Stringhash,
["comment_hash"] =Stringcomment_hash,
["texture_hash"] =Stringtexture_hash,
}Called when a user starts to transmit voice data.
Called when a user stops transmitting voice data.
Called when a user starts to transmit voice data.
Tableevent= {
["user"] =mumble.useruser,
["codec"] =Numbercodec,
["target"] =Numbertarget,
["sequence"] =Numbersequence,
["data"] =Stringencoded_opus_packet, -- Raw encoded audio data
["frame_header"] =Numberframe_header, -- The frame header usually contains a length and terminator bit
["speaking"] =Booleanspeaking, -- Is false when this is the last audio packet for the speaking user.
["channels"] =Numberchannels, -- How many channels were detected in this opus packet.
["bandwidth"] =Numberbandwidth, -- How much bandwidth this opus packet uses.
["samples_per_frame"] =Numbersamples_per_frame, -- How many samples per frame this opus packet has.
}Audio loopback example
localdecoder=mumble.decoder()
localechoinglocaloption=1client:hook("OnUserSpeak", function(client, event)
ifclient.me==event.userthenreturnend-- We have two ways to echo voice data backifoption==1then-- Create an audio buffer for this user-- This allows multiple people to be echoed at onceifnotevent.user.audiobufferthenevent.user.audiobuffer=client:createAudioBuffer()
end-- Option 1-- Decode the audio data and write it to our audiostream.-- This will be properly mixed with any audio streams that are playing. (via client:openAudio("sound.mp3"):play())localdecoded=decoder:decodeFloat(event.data)
event.user.audiobuffer:write(decoded)
elseifoption==2andnotechoingthen-- Option 2-- Transmit the encoded data back directly.-- This will not sound right if any audio streams are playing. (via client:openAudio("sound.mp3"):play())client:transmit(event.codec, event.data, event.speaking)
-- Keep echoing until the user stops speakingechoing=speakingandevent.userornilendend)Called on response to a mumble.client:requestBanList() call
Tablebanlist= {
[1] = {
["address"] = {
["string"] =Stringipaddress,
["ipv4"] =Booleanisipv4,
["ipv6"] =Booleanisipv6,
["data"] =Tableraw,
},
["mask"] =Numberip_mask,
["name"] =Stringname,
["hash"] =Stringhash,
["reason"] =Stringreason,
["start"] =Stringstart,
["duration"] =Numberduration
},
...
}Called when the bot receives a text message
Tableevent= {
["actor"] =mumble.useractor,
["message"] =Stringmessage,
["users"] =Tableusers,
["channels"] =Tablechannels, -- will be nil when receiving a direct message
["direct"] =Booleandirect
}Called when an action is performed that you don't have permission to do
Tableevent= {
["type"] =Numbertype,
["permission"] =Numberpermission,
["channel"] =mumble.channelchannel,
["user"] =mumble.useruser,
["reason"] =Stringreason,
["name"] =Stringname,
}Called when ACL data is received from a mumble.channel:requestACL() request
Tableacl= {
["channel"] =mumble.channelchannel,
["inherit_acls"] =Booleaninherit_acls,
["groups"] = {
[1] = {
["name"] =Stringgroup_name,
["inherited"] =Booleaninherited,
["inheritable"] =Booleaninheritable,
["add"] = {
[1] =Numberuser_id,
...
},
["remove"] = {
[1] =Numberuser_id,
...
},
["inherited_members"] = {
[1] =Numberuser_id,
...
}
},
...
},
["acls"] = {
[1] = {
["apply_here"] =Booleanapply_here,
["apply_subs"] =Booleanapply_subs,
["inherited"] =Booleaninherited,
["user_id"] =Numberuser_id,
["group"] =Stringgroup,
["grant"] =Numbergrant, -- This number is a flag that determines what this group is allowed to do
["deny"] =Numberdeny, -- This number is a flag that determines what this group is NOT allowed to do
},
...
},
}Called when the server sends UDP encryption keys to the client.
Tableevent= {
["valid"] =Booleanvalid,
["key"] =Stringkey,
["client_nonce"] =Stringclient_nonce,
["server_nonce"] =Stringserver_nonce,
}Called on response to a mumble.client:requestUsers() call
Tableuserlist= {
[1] = {
["user_id"] =Numberuser_id,
["name"] =Stringname,
["last_seen"] =Stringlast_seen,
["last_channel"] =mumble.channellast_channel,
},
...
}Called when the bot recieves permissions for a channel.
Tableevent= {
["channel"] =mumble.channelchannel,
["permissions"] =Numberpermissions,
["flush"] =Booleanflush,
}Called when the bot recieves the codec info from the server.
Tableevent= {
["alpha"] =Numberalpha,
["beta"] =Numberbeta,
["prefer_alpha"] =Booleanprefer_alpha,
["opus"] =Booleanopus,
}Called when the mumble.user's detailed statistics are received from the server. Only sent if mumble.user:requestStats() is called.
Tableevent= {
["user"] =mumble.useractor,
["stats_only"] =Booleanstats_only,
["certificates"] =Tablecertificates,
["from_client"] = {
["good"] =Numbergood,
["late"] =Numberlate,
["lost"] =Numberlost,
["resync"] =Numberresync,
},
["from_server"] = {
["good"] =Numbergood,
["late"] =Numberlate,
["lost"] =Numberlost,
["resync"] =Numberresync,
},
["udp_packets"] =Numberudp_packets,
["tcp_packets"] =Numbertcp_packets,
["udp_ping_avg"] =Numberudp_ping_avg,
["udp_ping_var"] =Numberudp_ping_var,
["tcp_ping_avg"] =Numbertcp_ping_avg,
["tcp_ping_var"] =Numbertcp_ping_var,
["version"] =Numberversion,
["release"] =Stringrelease,
["os"] =Stringos,
["os_version"] =Stringos_version,
["certificates"] =Tablecelt_versions,
["address"] = {
["string"] =Stringipaddress,
["ipv4"] =Booleanisipv4,
["ipv6"] =Booleanisipv6,
["data"] =Tableraw,
},
["bandwidth"] =Numberbandwidth,
["onlinesecs"] =Numberonlinesecs,
["idlesecs"] =Numberidlesecs,
["strong_certificate"] =Booleanstrong_certificate,
["opus"] =Booleanopus,
}Called when the servers settings are received. Usually called after OnServerSync
Tableevent= {
["max_bandwidth"] =Numbermax_bandwidth,
["welcome_text"] =Stringwelcome_text,
["allow_html"] =Booleanallow_html,
["message_length"] =Numbermessage_length,
["image_message_length"] =Numberimage_message_length,
["max_users"] =Numbermax_users,
}Called when the servers suggest the client to use specific settings.
Tableevent= {
["version"] =Numberversion,
["positional"] =Booleanpositional,
["push_to_talk"] =Booleanpush_to_talk,
}Called when the client receives plugin data from the server.
Tableevent= {
["sender"] =mumble.usersender, -- Who sent this data packet
["id"] =Numberid, -- The data ID of this packet
["data"] =Stringdata, -- The data sent (can be binary data)
["receivers"] = { -- A table of who is receiving this data
[1] =mumble.user,
...
},
}Called when an error occurs inside a hook. WARNING: Erroring within this hook will cause an error on the line where mumble.loop() is called, causing the script to exit
Called just before a TCP ping is sent to the server. This updates the users statistics found on their information panel. The mumble.client will automatically ping the server every 30 seconds within mumble.loop()
Tableevent= {
["timestamp"] =Numbertimestamp,
["good"] =Numbergood,
["late"] =Numberlate,
["lost"] =Numberlost,
["resync"] =Numberresync,
["udp_packets"] =Numberudp_packets,
["tcp_packets"] =Numbertcp_packets,
["udp_ping_avg"] =Numberudp_ping_avg,
["udp_ping_var"] =Numberudp_ping_var,
["tcp_ping_avg"] =Numbertcp_ping_avg,
["tcp_ping_var"] =Numbertcp_ping_var,
}Called just before a UDP ping is sent to the server. The mumble.client will automatically ping the server every 30 seconds within mumble.loop()
Tableevent= {
["timestamp"] =Numbertimestamp,
}Called just before any playing audio streams are encoded and transmitted.
Sinwave tone example
localsamples=0localtime=0localaudiostream=client:createAudioBuffer()
client:hook("OnAudioStream", function(client, samplerate, channels, frames)
-- The client is about to encode and stream x amount of frames-- Samplerate will always be 48000-- Channels will always be 2-- Frames will be based off the audio packet sizefori=1,framesdosamples=samples+1time=samples/samplerateforc=1,channelsdo-- Write a 600hz tone to both channels for this frame-- Whatever is written to the output buffer will be mixed with any playing mumble.audiostreamaudiostream:writeFloat(math.sin(2*math.pi*600*time))
endendend)Called when a sound file has finished playing. Passes the the audio stream that finished.