Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT(client, server): Implement loopback while still sending to others #6445

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

davidebeatrici
Copy link
Member

No description provided.

…the data

The function that already existed took the index instead of the data,
making it susceptible to errors because the data could be passed instead of the index.

Also, with this new iteration of loadComboBox() we can reorder the items shown to the user as desired.
@davidebeatrici davidebeatrici force-pushed the server-loopback-sending-to-others branch from 2e47e0f to 1730f39 Compare June 1, 2024 22:42
@davidebeatrici davidebeatrici changed the title FEAT(client, server): Implement server loopback while still sending to others FEAT(client, server): Implement loopback while still sending to others Jun 1, 2024
@davidebeatrici davidebeatrici force-pushed the server-loopback-sending-to-others branch from 1730f39 to d4dd9c2 Compare June 1, 2024 23:03
@@ -992,7 +992,8 @@ void AudioInput::encodeAudioFrame(AudioChunk chunk) {

ClientUser *p = ClientUser::get(Global::get().uiSession);
bool bTalkingWhenMuted = false;
if (Global::get().s.bMute || ((Global::get().s.lmLoopMode != Settings::Local) && p && (p->bMute || p->bSuppress))
if (Global::get().s.bMute
|| ((Global::get().s.lmLoopMode != Settings::LocalOnly) && p && (p->bMute || p->bSuppress))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this if now even harder to comprehend. Let's maybe create some bools before the if and compare that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

break;
case Settings::LocalRegular:
LoopUser::lpLoopy.addFrame(audioData);
[[fallthrough]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[[fallthrough]] is apparently a C++17 thing and therefore the Windows and OSX CI build fails (?)

src/MumbleProtocol.h Show resolved Hide resolved
}
} else if (u->qmTargets.contains(static_cast< int >(audioData.targetOrContext))) { // Whisper/Shout
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when clients implementing this feature are connected to old servers? When they are using "server (send to others)" their packets will be dropped entirely, correct? Or will they be whisper/shout to some channel or user?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are requesting the audio to be sent to a non-registered whisper-target, which should lead to the packet just being dropped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new loopback mode should probably only be used/offered to the user whilst connected to a server that actually supports this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about only showing the option in the combobox when available (i.e. the server supports it), but the idea implies that:

  1. It would not appear when not connected to a server.
  2. It would be confusing as the user may think their client version doesn't provide the feature.

I think we should show a warning in the log box explaining that the selected loopback method is not supported due to the server not implementing it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think hiding the option if the server doesn't support it makes sense. Only issue would be that it'd be confusing for users who configure loopback while disconnected and once they connect their chosen option is gone.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure hiding would be a good UX. Either change the text of the combobox entries to add (unsupported by server) or use the log

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log will be overlooked in like 90% of cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but hiding will create us a dozen bug reports xD

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True :)
We could make use of the mute-cue in cases where the user has selected loopback+broadcast but the server doesn't support it - because as far as other clients are concerned, you are muted (more or less). So maybe mute-cue + indicating in the settings window that the server doesn't support the selected loopback+broadcast would be an idea?

constexpr unsigned int REGULAR_SPEECH = 0;
constexpr unsigned int SERVER_LOOPBACK = 31;
constexpr unsigned int REGULAR_SPEECH = 0;
constexpr unsigned int SERVER_LOOPBACK_REGULAR = 30;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the naming "regular" is not very helpful in this case. Maybe SERVER_LOOPBACK_ADDITIONAL or something in that direction makes things a bit more expressive? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SERVER_LOOPBACK_BROADCAST?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SERVER_LOOPBACK_AND_BROADCAST <- that would nicely describe what's going on

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually thought about using "broadcast", but ended up with "regular" because shorter. I agree that the former would be clearer.

Comment on lines +643 to +646
qcbLoopback->addItem(tr("Local (don't send to others)"), Settings::LocalOnly);
qcbLoopback->addItem(tr("Local (send to others)"), Settings::LocalRegular);
qcbLoopback->addItem(tr("Server (don't send to others)"), Settings::ServerOnly);
qcbLoopback->addItem(tr("Server (send to others)"), Settings::ServerRegular);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
qcbLoopback->addItem(tr("Local (don't send to others)"), Settings::LocalOnly);
qcbLoopback->addItem(tr("Local (send to others)"), Settings::LocalRegular);
qcbLoopback->addItem(tr("Server (don't send to others)"), Settings::ServerOnly);
qcbLoopback->addItem(tr("Server (send to others)"), Settings::ServerRegular);
qcbLoopback->addItem(tr("Local only"), Settings::LocalOnly);
qcbLoopback->addItem(tr("Local + Broadcast"), Settings::LocalRegular);
qcbLoopback->addItem(tr("Server only"), Settings::ServerOnly);
qcbLoopback->addItem(tr("Server + Broadcast"), Settings::ServerRegular);

I feel like my suggestion can still be improved upon 🤔

Either way, I think we need tooltips for all of these that explain in more detail what is meant by that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, absolutely.

Comment on lines +1185 to +1186
default:
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not include default cases when switching over enums as that will prevent compiler warnings once new enum values are added.

case Settings::LocalRegular:
LoopUser::lpLoopy.addFrame(audioData);
[[fallthrough]];
default: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

if (c->currentIndex() != index) {
c->setCurrentIndex(index);
} else {
connect(this, SIGNAL(intSignal(int)), c, SIGNAL(currentIndexChanged(int)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old signal/slot syntax should no longer be used - prefer the version with explicit function pointers where the compiler can actually do type-checking for us.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only did this for consistency with the rest of the file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think consistency is important for this 🤷

@@ -188,7 +188,7 @@ struct OverlaySettings {
struct Settings {
enum AudioTransmit { Continuous, VAD, PushToTalk };
enum VADSource { Amplitude, SignalToNoise };
enum LoopMode { None, Local, Server };
enum LoopMode { None, LocalOnly, ServerOnly, LocalRegular, ServerRegular };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before, I don't think "regular" is descriptive - should be adapted in unison with the special whisper target.

break;
case Mumble::Protocol::ReservedTargetIDs::SERVER_LOOPBACK_REGULAR:
buffer.forceAddReceiver(*u, Mumble::Protocol::AudioContext::NORMAL, audioData.containsPositionalData);
[[fallthrough]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another C++17 usage

cachedListeners = cache.listeningTargets;
} else {
ZoneScopedN(TracyConstants::AUDIO_WHISPER_CACHE_CREATE);
default:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No default-cases in enum switches

Copy link
Member

@Hartmnt Hartmnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized another important thing: We will have to take echo cancellation into account. Because we might effectively cancel the user speech entirely, if not careful.

@Hartmnt
Copy link
Member

Hartmnt commented Jun 2, 2024

BTW, you are effectively implementing #3408

@Krzmbrzl
Copy link
Member

Krzmbrzl commented Jun 2, 2024

We will have to take echo cancellation into account. Because we might effectively cancel the user speech entirely, if not careful.

I would assume this isn't an issue as the loopback variants already exist and work - the only changes of this PR are not visible to the local client.

@davidebeatrici
Copy link
Member Author

Correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants