mirror of
https://github.com/mumble-voip/mumble.git
synced 2026-03-03 00:46:56 -05:00
Inconsistent playback of mic push/release sounds. #2912
Labels
No labels
GlobalShortcuts
Hacktoberfest
accessibility
acl
asio
audio
bonjour
bsd
bug
build
certificate
ci
client
code
documentation
external-bug
feature-request
gRPC
github
good first issue
help wanted
help-needed
ice
installer
linux
macOS
needs-ckeck-with-latest-version
needs-more-input
overlay
positional audio
priority/P0 - Blocker
priority/P1 - Critical
priority/P2 - Important
priority/P3 - Somewhat important
priority/P4 - Low
public-server-registration
qt
recording
release-management
server
stale-no-response
stale-support
support
task
test
theme
translation
triage
ui
windows
wontfix
x64
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/mumble-mumble-voip#2912
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @bmmcginty on GitHub (Oct 21, 2024).
Description
I have sounds enabled for key down and key up of my mic. If you press and release the PTT key, waiting even as much as 1 second between press/release and release/re-press, the key up/key down sound will eventually "miss a beat", or fail to sound. This can happen multiple times consecutively, and can take up to 30 seconds to show up. It can also happen when keying or unkeying, which can make it difficult to know when I'm transmitting for certain.
I amusing the default mic up/down sounds that are provided with the client (on.ogg and off.ogg).
I am using the PTT lock setting, threshold 300 MS. This issue occurs regardless of that lock setting, though, and i have tested same. Possibly related to #6359.
Steps to reproduce
Press the PTT key, hold for 1/4 second, and release. Wait 1/4 second, and repeat.
Mumble version
1.5.634
Mumble component
Client
OS
Windows
Reproducible?
Yes
Additional information
No response
Relevant log output
No response
Screenshots
No response
@Hartmnt commented on GitHub (Oct 21, 2024):
This sounds exactly like #6359 Are your sound cue files
.wavfiles? If so, try to convert it to another format e.g..ogg@bmmcginty commented on GitHub (Oct 21, 2024):
These _are .ogg files; they are the default files provided upon install.
@Hartmnt commented on GitHub (Oct 21, 2024):
Oof, well then solving this is going to be difficult, because I can not reproduce this with the default sounds.
@tspivey commented on GitHub (Oct 23, 2024):
I also have this issue.
I might've found it. I'm not too familiar with QT or C++, so could be missing something.
Starting from
AudioInput::encodeAudioFrame:AudioOutput::handleInvalidatedBuffer.AudioInput::encodeAudioFramecallsao->removeToken(m_activeAudioCue);.AudioOutput::removeBufferon the buffer, which emitsbufferInvalidated.AudioInput::encodeAudioFrameand added to the playback queue.bufferInvalidatedruns, and if the new sample gets the address of the old one, removes it.@Hartmnt commented on GitHub (Oct 23, 2024):
Oh good lord... So we have two
handleInvalidateBuffercalls with the same address racing against the system specific memory allocator which is re-allocating the address after the first but before the second call tohandleInvalidateBuffer? That sounds possible but extremely hard to trigger. Especially since OP stated you could have a delay of up to a second and still trigger the problem sometimes. I would imagine the queued calles tohandleInvalidateBufferwould finish relatively quickly.But this is at least a possible lead.
@tspivey commented on GitHub (Oct 23, 2024):
This isn't hard to trigger at all. I added some debugging and got it on the first try.
And this one after a few tries (the first line is when on.ogg fininshes playing):
Looking at the addresses and timestamps, this seems to be what's happening.
@Hartmnt commented on GitHub (Oct 23, 2024):
@tspivey Nice work confirming this!
Indeed, it makes sense now. The time between the calls is irrelevant because we keep the pointer in
AudioInput::m_activeAudioCue. This also perfectly explains, why I can not reproduce this: It entirely depends on the system memory allocator reusing the same address in consecutive calls and Linux (or the specific std implementation I am using) seems to be unaffected by this.So now we just have to figure out how to fix this 🥲
@Hartmnt commented on GitHub (Oct 24, 2024):
@tspivey I have come up with something that should reduce the number of times this problem occurs:
github.com/hartmnt/mumble@c460e8ca4fHowever, this will still race against a sample that is just finishing playing after the check was performed. So I don't consider this a proper fix for this problem. But I wanted to share this anyway for now.
@Krzmbrzl commented on GitHub (Jan 12, 2025):
Conceptually, the fix is simple: Instead of storing a raw pointer in
m_activeCue, we store astd::weak_ptr<AudioOutputBuffer>. In order for this to be possible,qmOutputsmust also the buffers asstd::shared_ptr<AudioOutputBuffer>. Then,m_activeCuecould check whether the referenced object has been deleted already or not (that's whatweak_ptrallows you to do). Insert this check into the current logic of when to stop audio buffers and you're mostly good.The final puzzle piece is that the
invalidateBuffersignal must also passweak_ptrs instead of raw pointers sohandleInvalidatedBuffercan do the same kind of checking.The problem is: This would require introducing smart pointers into the audio processing code. While I would consider this to be a good thing in general, this will likely require a non-trivial refactoring effort. And all that because of the audio cue handling (afaict no other part of the code ever takes and stores a pointer to an audio output buffer). That seems excessive.
On the other hand, I can't come up with another mechanism that would allow us to get to know whether a given sample has finished playing or not. My first thought was to emit an event, but this would again be asynchronous, so we still have a race condition as stopping the supposedly still running sample and the event telling you it already stopped are in no way synchronized and can therefore happen in any order. 🤔