bkacjios / lua-mumble

A lua module to connect to a mumble server and interact with it
MIT License
23 stars 4 forks source link

Played samples not audible after some time (client:transmit) #19

Closed hbeni closed 3 years ago

hbeni commented 3 years ago

Hello, i have a playback bot (https://github.com/hbeni/fgcom-mumble/blob/master/server/fgcom-radio-playback.bot.lua) that plays back samples previously recorded.

This works fine. Until it doesn't. My log at the terminal still shows samples that are processed and put into the client:transmit function. From the mumble client perspective it looks like the bot is not speaking.

What i can see is, when activating the debug output of the sample data, that the printed binary blob changes at the moment when the transmission stops working. The samples to be played are fetched from a lua buffer variable, that gets filled if its empty.

It somehow looks like the content of the buffer is overwritten with "garbage/random not-sample-data" at a random point in time - possible memory corruption?

hbeni commented 3 years ago

It somehow looks like the content of the buffer is overwritten with "garbage/random not-sample-data" at a random point in time - possible memory corruption?

Rechecked it, i think it's not the buffer now. It more looks like the data is somehow not relayed to murmur anymore, or not relayed to my client...

hbeni commented 3 years ago

Looking at the buffer replayed, it looks like the data is passed "ok" to the lua-mumble API, but there it vanishes somewhere...

hbeni commented 3 years ago

Hi there, I recently added OGG support to my bot, to see if there is a problem with my raw PCM sample playing method. It turns out that the problem persists even with that.

For better investigation, I narrowed down the Problem to a very simple looped bot code. I use LuaJIT 2.1.0-beta3 on debian/testing to call it: luajit looptest-ogg.lua --cert=playbot.pem --key=playbot.key --sample=testsample.ogg

It died here shortly after the second looping:

elapsed time: 325.00 (playing: true)
elapsed time: 325.00 (playing: true)
elapsed time: 326.00 (playing: false)
Sample casualties_of_war.ogg not playing: starting
elapsed time: 326.00 (playing: true)
elapsed time: 327.00 (playing: true)
elapsed time: 327.00 (playing: true)
elapsed time: 328.00 (playing: true)
elapsed time: 328.00 (playing: true)
elapsed time: 329.00 (playing: true)
elapsed time: 329.00 (playing: true)
------ COMMENT INSERTED: HERE IT GOT SILENT -------
elapsed time: 330.00 (playing: true)
elapsed time: 330.00 (playing: true)
elapsed time: 331.00 (playing: true)
elapsed time: 331.00 (playing: true)
elapsed time: 332.00 (playing: true)

looptest-ogg.lua:

--[[  This is a simple loop bot. He will just play an OGG file in a loop. ]]

mumble = require("mumble")  -- get the mumble API

--[[
   It is nice if the bot can be called with parameters from the outside:
   lua echobot.lua --host=someHost --cert=mycert.pem --key=mykey.key

   The cert and key can be generated with openssl like this:
     $> openssl genrsa -out bot.key 2048 2> /dev/null
     $> openssl req -new -sha256 -key bot.key -out bot.csr -subj "/"
     $> openssl x509 -req -in bot.csr -signkey bot.key -out bot.pem 2> /dev/null
]]

-- define defaults
local botname = "loopbot"
local host    = "localhost"
local port    = 64738      -- standard mumble port
local cert    = "bot.pem"
local key     = "bot.key"
local sample  = "testsample.ogg"

-- Parse cmdline args
if arg[1] then
    if arg[1]=="-h" or arg[1]=="--help" then
        print(botname)
        print("usage: "..arg[0].." [opt=val ...]")
        print("  opts:")
        print("    --host=    host to coennct to")
        print("    --port=    port to connect to")
        print("    --cert=    path to PEM encoded cert")
        print("    --key=     path to the certs key")
        print("    --sample=  path to the sample.ogg")
        os.exit(0)
    end

    for _, opt in ipairs(arg) do
        _, _, k, v = string.find(opt, "--(%w+)=(.+)")
        print("KEY='"..k.."'; VAL='"..v.."'")
        if k=="host" then host=v end
        if k=="port" then port=v end
        if k=="cert" then cert=v end
        if k=="key" then  key=v end
        if k=="sample" then  sample=v end
    end

end

-- Connect to server, so we get the API
print(botname..": connecting to "..host.." on port "..port.." (cert: "..cert.."; key: "..key..")")
local client = assert(mumble.connect(host, port, cert, key))
client:auth(botname)
print("connect and bind: OK")

--[[
  Playback loop: we use a mumble timer for this. The timer loops in
  the playback-rate and looks if there are samples buffered. If so,
  he fetches them and plays them, one packet per timer tick.
]]
local loopTimer = mumble.timer()
local x = os.time()
client:hook("OnServerSync", function(client, event)
    print("Sync done; server greeted with: ", event.welcome_text)
    loopTimer:start(function(t)
        print(string.format("elapsed time: %.2f (playing: %s)", os.time() - x, client:isPlaying()))

        if not client:isPlaying() then
            print("Sample "..sample.." not playing: starting")
            local f=io.open(sample,"r") if f~=nil then  io.close(f) else print("error opening "..sample..": no such file") os.exit(1) end

            client:play(sample)
        end

    end, 0.00, 0.5)
end)

-- Done with setup, lets enter the bots main loop
mumble.loop()
print("Bot finished")
print(string.format("elapsed time: %.2f\n", os.time() - x))
bkacjios commented 3 years ago

So it plays the entire file fine once, then when you play it again it goes silent a few seconds into it?

hbeni commented 3 years ago

Basicly, however:

For me it looks somehow like this is somewhat elapsed-time dependent.

I just also retested with a loop timer of 5 seconds, bu this does not change anything.

bkacjios commented 3 years ago

If it is truly time dependant, the only thing I could think of is it being this line here..

https://github.com/bkacjios/lua-mumble/blob/855048c653926339a8a7ed611512b9d0bcfb2b25/audio.c#L251

You could try lowing the % 100000 to something more reasonable, like say, 1000, and see if it works. I think what might be happening is this value gets too big for my util_set_varint function to handle.

hbeni commented 3 years ago

Will try. If it matters: the tried sample was https://github.com/wesnoth/wesnoth/blob/master/data/core/music/casualties_of_war.ogg

bkacjios commented 3 years ago

After looking into it and pushing that last mentioned commit, I think this was definitely the cause of the problem. Before, the util_set_varint function was capped out at 0x4000 or 16384. Seeing how I set the audio_sequence cap at 100000 it was certainly going over the limit and causing an incorrect audio packet header, since it didn't know how to handle it. I pushed some more code to support larger varint's, but just lowering that value by one 0 should honestly do the trick as well.

hbeni commented 3 years ago

I just currently am testing with client->audio_sequence = (client->audio_sequence + 1) % 1000; and so far it works great (I'm in the fourth loop or something)

I let it play on and see how it goes. So far its promising :) <3

bkacjios commented 3 years ago

Pretty much confirms it as fixed for me.

hbeni commented 3 years ago

Did you skip the proposed line on purpose? :) https://github.com/bkacjios/lua-mumble/commit/ff421ab41bfdbc8b4211b2d97d20f9465cdc57d6#commitcomment-51241195

hbeni commented 3 years ago

Great, thank you very much!!!

hbeni commented 3 years ago

Pretty much confirms it as fixed for me.

Bot still running strong :grin: (fix=your version)