Skip to content
Permalink
Browse files

Fix client freeze due to deadlock (#1167)

See issue for deadlock cause. Removed need for ClientUser::get
call causing the c_qrwlUsers read lock in audio output thread
by moving feature implementation into GUI thread analog to how
application attenuation is handled. Now a global flag signals to
the audio output thread if priority speaker should be triggered
even though none of the outputs are priority speaker.

Also fixed asymmetric behavior between local and remote priority
speaker handling in the feature. Now also whisper and shouts trigger
the local priority speaker feature.

Minor refactoring in places that had to be touched to improve
readability. Removed some now superfluous comments.
  • Loading branch information...
hacst committed Feb 23, 2014
1 parent 00392d1 commit 12eac3c6725bc138f1ee9caf9e5ad3b475a5bf35
Showing with 51 additions and 33 deletions.
  1. +21 −17 src/mumble/AudioOutput.cpp
  2. +1 −0 src/mumble/Global.cpp
  3. +3 −0 src/mumble/Global.h
  4. +26 −16 src/mumble/MainWindow.cpp
@@ -374,30 +374,32 @@ bool AudioOutput::mix(void *outbuff, unsigned int nsamp) {
const unsigned int nchan = iChannels;
ServerHandlerPtr sh = g.sh;
VoiceRecorderPtr recorder;
if (sh)
if (sh) {
recorder = g.sh->recorder;
}

qrwlOutputs.lockForRead();
bool needAdjustment = false;

bool prioritySpeakerActive = false;

QMultiHash<const ClientUser *, AudioOutputUser *>::const_iterator it = qmOutputs.constBegin();
while (it != qmOutputs.constEnd()) {
AudioOutputUser *aop = it.value();
if (! aop->needSamples(nsamp)) {
qlDel.append(aop);
} else {
qlMix.append(aop);
// Set a flag if there is a priority speaker
if (it.key() && it.key()->bPrioritySpeaker)
needAdjustment = true;

const ClientUser *user = it.key();
if (user && user->bPrioritySpeaker) {
prioritySpeakerActive = true;
}
}
++it;
}

if (!needAdjustment && g.s.bAttenuateUsersOnPrioritySpeak) {
const ClientUser *p = ClientUser::get(g.uiSession);
if (p && p->tsState == Settings::Talking && p->bPrioritySpeaker) {
needAdjustment = true;
}
if (g.prioritySpeakerActiveOverride) {
prioritySpeakerActive = true;
}

if (! qlMix.isEmpty()) {
@@ -489,14 +491,16 @@ bool AudioOutput::mix(void *outbuff, unsigned int nsamp) {
const float * RESTRICT pfBuffer = aop->pfBuffer;
float volumeAdjustment = 1;

// We have at least one priority speaker
if (needAdjustment) {
AudioOutputSpeech *aos = qobject_cast<AudioOutputSpeech *>(aop);
// Exclude whispering people
if (aos && (aos->p->tsState == Settings::Talking || aos->p->tsState == Settings::Shouting)) {
// Adjust all non-priority speakers
if (!aos->p->bPrioritySpeaker)
if (prioritySpeakerActive) {
AudioOutputSpeech *speech = qobject_cast<AudioOutputSpeech *>(aop);
if (speech) {
const ClientUser* user = speech->p;

if (user->tsState != Settings::Whispering
&& !user->bPrioritySpeaker) {

volumeAdjustment = adjustFactor;
}
}
}

@@ -92,6 +92,7 @@ Global::Global() {
#endif

bAttenuateOthers = false;
prioritySpeakerActiveOverride = false;

bAllowHTML = true;
uiMessageLength = 5000;
@@ -97,6 +97,9 @@ struct Global {
bool bPreferAlpha;
bool bOpus;
bool bAttenuateOthers;
/// If set the AudioOutput::mix will forcefully adjust the volume of all
/// non-priority speakers.
bool prioritySpeakerActiveOverride;
bool bAllowHTML;
unsigned int uiMessageLength;
unsigned int uiImageLength;
@@ -1898,25 +1898,35 @@ void MainWindow::updateMenuPermissions() {
}

void MainWindow::talkingChanged() {
ClientUser *p = ClientUser::get(g.uiSession);
if (p && g.s.bAttenuateOthersOnTalk) {
switch (p->tsState) {
case Settings::Talking:
case Settings::Whispering:
case Settings::Shouting:
g.bAttenuateOthers = true;
break;
case Settings::Passive:
default:
g.bAttenuateOthers = false;
break;
}
} else {
if (g.s.bStateInTray) {
updateTrayIcon();
}

ClientUser *user = ClientUser::get(g.uiSession);
if (user == NULL) {
g.bAttenuateOthers = false;
g.prioritySpeakerActiveOverride = false;

return;
}

if (g.s.bStateInTray)
updateTrayIcon();
switch (user->tsState) {
case Settings::Talking:
case Settings::Whispering:
case Settings::Shouting:
g.bAttenuateOthers = g.s.bAttenuateOthersOnTalk;

g.prioritySpeakerActiveOverride =
g.s.bAttenuateUsersOnPrioritySpeak
&& user->bPrioritySpeaker;

break;
case Settings::Passive:
default:
g.bAttenuateOthers = false;
g.prioritySpeakerActiveOverride = false;
break;
}
}

void MainWindow::on_qaAudioReset_triggered() {

0 comments on commit 12eac3c

Please sign in to comment.
You can’t perform that action at this time.