Skip to content

Commit 818a1ce

Browse files
Calls: clarify voice vs screen-share audio controls
Add separate controls for participant voice and screen-share audio in group call member menus, and expose a dedicated screen-share mute action when screen audio is available.
1 parent 7296f85 commit 818a1ce

5 files changed

Lines changed: 258 additions & 7 deletions

File tree

Telegram/SourceFiles/calls/group/calls_group_call.cpp

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3570,6 +3570,24 @@ float64 GroupCall::singleSourceVolumeValue() const {
35703570
return _singleSourceVolume / float64(Group::kDefaultVolume);
35713571
}
35723572

3573+
float64 GroupCall::effectiveParticipantVolume(
3574+
const Data::GroupCallParticipant &participant) const {
3575+
return participant.mutedByMe
3576+
? 0.
3577+
: (participant.volume / float64(Group::kDefaultVolume));
3578+
}
3579+
3580+
float64 GroupCall::effectiveParticipantScreenVolume(
3581+
const Data::GroupCallParticipant &participant) const {
3582+
const auto i = _screenVolumesByPeer.find(participant.peer);
3583+
if (i != end(_screenVolumesByPeer)) {
3584+
return i->second.muted
3585+
? 0.
3586+
: (i->second.volume / float64(Group::kDefaultVolume));
3587+
}
3588+
return effectiveParticipantVolume(participant);
3589+
}
3590+
35733591
void GroupCall::updateInstanceVolumes() {
35743592
const auto real = lookupReal();
35753593
if (!real) {
@@ -3606,14 +3624,13 @@ void GroupCall::updateInstanceVolume(
36063624
&& (volumeChanged
36073625
|| (was && (GetAdditionalAudioSsrc(was->videoParams)
36083626
!= additionalSsrc)));
3609-
const auto localVolume = now.mutedByMe
3610-
? 0.
3611-
: (now.volume / float64(Group::kDefaultVolume));
3627+
const auto localVolume = effectiveParticipantVolume(now);
3628+
const auto localScreenVolume = effectiveParticipantScreenVolume(now);
36123629
if (set) {
36133630
_instance->setVolume(now.ssrc, localVolume);
36143631
}
36153632
if (additionalSet) {
3616-
_instance->setVolume(additionalSsrc, localVolume);
3633+
_instance->setVolume(additionalSsrc, localScreenVolume);
36173634
}
36183635
}
36193636

@@ -3996,6 +4013,42 @@ void GroupCall::changeVolume(const Group::VolumeRequest &data) {
39964013
}
39974014
}
39984015

4016+
void GroupCall::toggleScreenMute(const Group::MuteRequest &data) {
4017+
if (_rtmp || videoStream() || data.peer->isSelf()) {
4018+
return;
4019+
}
4020+
auto &state = _screenVolumesByPeer[data.peer];
4021+
state.muted = data.mute;
4022+
_otherParticipantScreenStateValue.fire(participantScreenState(data.peer));
4023+
applyScreenVolume(data.peer);
4024+
}
4025+
4026+
void GroupCall::changeScreenVolume(const Group::VolumeRequest &data) {
4027+
if (_rtmp || videoStream() || data.peer->isSelf()) {
4028+
return;
4029+
}
4030+
auto &state = _screenVolumesByPeer[data.peer];
4031+
state.volume = std::clamp(data.volume, 1, Group::kMaxVolume);
4032+
state.muted = false;
4033+
_otherParticipantScreenStateValue.fire(participantScreenState(data.peer));
4034+
applyScreenVolume(data.peer);
4035+
}
4036+
4037+
void GroupCall::applyScreenVolume(not_null<PeerData*> participantPeer) {
4038+
if (!_instance) {
4039+
return;
4040+
}
4041+
const auto participant = LookupParticipant(this, participantPeer);
4042+
if (!participant) {
4043+
return;
4044+
}
4045+
const auto ssrc = GetAdditionalAudioSsrc(participant->videoParams);
4046+
if (!ssrc) {
4047+
return;
4048+
}
4049+
_instance->setVolume(ssrc, effectiveParticipantScreenVolume(*participant));
4050+
}
4051+
39994052
void GroupCall::editParticipant(
40004053
not_null<PeerData*> participantPeer,
40014054
bool mute,
@@ -4222,6 +4275,40 @@ auto GroupCall::otherParticipantStateValue() const
42224275
return _otherParticipantStateValue.events();
42234276
}
42244277

4278+
auto GroupCall::otherParticipantScreenStateValue() const
4279+
-> rpl::producer<Group::ParticipantState> {
4280+
return _otherParticipantScreenStateValue.events();
4281+
}
4282+
4283+
bool GroupCall::hasScreenShareAudio(
4284+
not_null<PeerData*> participantPeer) {
4285+
const auto participant = LookupParticipant(this, participantPeer);
4286+
return participant && GetAdditionalAudioSsrc(participant->videoParams);
4287+
}
4288+
4289+
Group::ParticipantState GroupCall::participantScreenState(
4290+
not_null<PeerData*> participantPeer) {
4291+
const auto participant = LookupParticipant(this, participantPeer);
4292+
const auto i = _screenVolumesByPeer.find(participantPeer);
4293+
const auto fallbackVolume = participant
4294+
? participant->volume
4295+
: Group::kDefaultVolume;
4296+
const auto fallbackMuted = participant ? participant->mutedByMe : false;
4297+
return Group::ParticipantState{
4298+
.peer = participantPeer,
4299+
.volume = std::clamp(
4300+
(i != end(_screenVolumesByPeer))
4301+
? i->second.volume
4302+
: fallbackVolume,
4303+
1,
4304+
Group::kMaxVolume),
4305+
.mutedByMe = (i != end(_screenVolumesByPeer))
4306+
? i->second.muted
4307+
: fallbackMuted,
4308+
.locallyOnly = true,
4309+
};
4310+
}
4311+
42254312
MTPInputGroupCall GroupCall::inputCall() const {
42264313
Expects(_id != 0);
42274314

Telegram/SourceFiles/calls/group/calls_group_call.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ For license and copyright information please follow this link:
1010
#include "base/weak_ptr.h"
1111
#include "base/timer.h"
1212
#include "base/bytes.h"
13+
#include "calls/group/calls_group_common.h"
1314
#include "mtproto/sender.h"
1415
#include "mtproto/mtproto_auth_key.h"
1516
#include "webrtc/webrtc_device_common.h"
@@ -338,6 +339,12 @@ class GroupCall final
338339

339340
[[nodiscard]] auto otherParticipantStateValue() const
340341
-> rpl::producer<Group::ParticipantState>;
342+
[[nodiscard]] auto otherParticipantScreenStateValue() const
343+
-> rpl::producer<Group::ParticipantState>;
344+
[[nodiscard]] bool hasScreenShareAudio(
345+
not_null<PeerData*> participantPeer);
346+
[[nodiscard]] Group::ParticipantState participantScreenState(
347+
not_null<PeerData*> participantPeer);
341348

342349
enum State {
343350
Creating,
@@ -454,6 +461,8 @@ class GroupCall final
454461

455462
void toggleMute(const Group::MuteRequest &data);
456463
void changeVolume(const Group::VolumeRequest &data);
464+
void toggleScreenMute(const Group::MuteRequest &data);
465+
void changeScreenVolume(const Group::VolumeRequest &data);
457466

458467
void inviteUsers(
459468
const std::vector<InviteRequest> &requests,
@@ -594,6 +603,11 @@ class GroupCall final
594603
void updateInstanceVolume(
595604
const std::optional<Data::GroupCallParticipant> &was,
596605
const Data::GroupCallParticipant &now);
606+
[[nodiscard]] float64 effectiveParticipantVolume(
607+
const Data::GroupCallParticipant &participant) const;
608+
[[nodiscard]] float64 effectiveParticipantScreenVolume(
609+
const Data::GroupCallParticipant &participant) const;
610+
void applyScreenVolume(not_null<PeerData*> participantPeer);
597611
void applyMeInCallLocally();
598612
void startRejoin();
599613
void rejoin();
@@ -730,7 +744,13 @@ class GroupCall final
730744
bool _acceptFields = false;
731745

732746
rpl::event_stream<Group::ParticipantState> _otherParticipantStateValue;
747+
rpl::event_stream<Group::ParticipantState> _otherParticipantScreenStateValue;
733748
std::vector<MTPGroupCallParticipant> _queuedSelfUpdates;
749+
struct ScreenVolumeState {
750+
int volume = Group::kDefaultVolume;
751+
bool muted = false;
752+
};
753+
base::flat_map<not_null<PeerData*>, ScreenVolumeState> _screenVolumesByPeer;
734754

735755
CallId _id = 0;
736756
CallId _accessHash = 0;

Telegram/SourceFiles/calls/group/calls_group_members.cpp

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class Members::Controller final
8080
}
8181
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
8282
[[nodiscard]] rpl::producer<VolumeRequest> changeVolumeRequests() const;
83+
[[nodiscard]] rpl::producer<MuteRequest> toggleScreenMuteRequests() const;
84+
[[nodiscard]] rpl::producer<VolumeRequest> changeScreenVolumeRequests() const;
8385
[[nodiscard]] auto kickParticipantRequests() const
8486
-> rpl::producer<not_null<PeerData*>>;
8587

@@ -188,6 +190,8 @@ class Members::Controller final
188190

189191
rpl::event_stream<MuteRequest> _toggleMuteRequests;
190192
rpl::event_stream<VolumeRequest> _changeVolumeRequests;
193+
rpl::event_stream<MuteRequest> _toggleScreenMuteRequests;
194+
rpl::event_stream<VolumeRequest> _changeScreenVolumeRequests;
191195
rpl::event_stream<not_null<PeerData*>> _kickParticipantRequests;
192196
rpl::variable<int> _fullCount = 1;
193197

@@ -1047,6 +1051,16 @@ auto Members::Controller::changeVolumeRequests() const
10471051
return _changeVolumeRequests.events();
10481052
}
10491053

1054+
auto Members::Controller::toggleScreenMuteRequests() const
1055+
-> rpl::producer<MuteRequest> {
1056+
return _toggleScreenMuteRequests.events();
1057+
}
1058+
1059+
auto Members::Controller::changeScreenVolumeRequests() const
1060+
-> rpl::producer<VolumeRequest> {
1061+
return _changeScreenVolumeRequests.events();
1062+
}
1063+
10501064
bool Members::Controller::rowIsMe(not_null<PeerData*> participantPeer) {
10511065
return isMe(participantPeer);
10521066
}
@@ -1581,11 +1595,40 @@ void Members::Controller::addMuteActionsToContextMenu(
15811595
.locallyOnly = local,
15821596
});
15831597
});
1598+
const auto toggleScreenMute = crl::guard(this, [=](bool mute) {
1599+
_toggleScreenMuteRequests.fire(Group::MuteRequest{
1600+
.peer = participantPeer,
1601+
.mute = mute,
1602+
.locallyOnly = true,
1603+
});
1604+
});
1605+
const auto changeScreenVolume = crl::guard(this, [=](int volume) {
1606+
_changeScreenVolumeRequests.fire(Group::VolumeRequest{
1607+
.peer = participantPeer,
1608+
.volume = std::clamp(volume, 1, Group::kMaxVolume),
1609+
.locallyOnly = true,
1610+
});
1611+
});
1612+
const auto addSectionLabel = [=](const QString &text) {
1613+
const auto action = menu->addAction(text, [] {});
1614+
action->setEnabled(false);
1615+
};
1616+
const auto screenMuteActionText = [=](bool muted) {
1617+
return tr::lng_group_call_screen_share_audio(tr::now)
1618+
+ u": "_q
1619+
+ (muted
1620+
? tr::lng_call_unmute_audio(tr::now)
1621+
: tr::lng_call_mute_audio(tr::now));
1622+
};
15841623

15851624
const auto muteState = row->state();
15861625
const auto muted = (muteState == Row::State::Muted)
15871626
|| (muteState == Row::State::RaisedHand);
15881627
const auto mutedByMe = row->mutedByMe();
1628+
const auto addScreenVolumeItem = !_call->rtmp()
1629+
&& !_call->videoStream()
1630+
&& !isMe(participantPeer)
1631+
&& _call->hasScreenShareAudio(participantPeer);
15891632

15901633
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased;
15911634

@@ -1643,16 +1686,70 @@ void Members::Controller::addMuteActionsToContextMenu(
16431686
if (menu->actions().size() > 1) { // First - cover.
16441687
menu->addSeparator();
16451688
}
1689+
if (addScreenVolumeItem) {
1690+
addSectionLabel(tr::lng_group_call_microphone(tr::now));
1691+
}
16461692

16471693
menu->addAction(std::move(volumeItem));
16481694

1649-
if (!_call->rtmp()
1650-
&& !_call->videoStream()
1651-
&& !isMe(participantPeer)) {
1695+
if (!addScreenVolumeItem && !isMe(participantPeer)) {
16521696
menu->addSeparator();
16531697
}
16541698
};
16551699

1700+
if (addScreenVolumeItem) {
1701+
auto otherParticipantScreenStateValue = rpl::merge(
1702+
_call->otherParticipantScreenStateValue(
1703+
) | rpl::filter([=](const Group::ParticipantState &data) {
1704+
return data.peer == participantPeer;
1705+
}),
1706+
_call->otherParticipantStateValue(
1707+
) | rpl::filter([=](const Group::ParticipantState &data) {
1708+
return data.peer == participantPeer;
1709+
}) | rpl::map([=](const Group::ParticipantState &) {
1710+
return _call->participantScreenState(participantPeer);
1711+
}));
1712+
1713+
const auto state = _call->participantScreenState(participantPeer);
1714+
auto volumeItem = base::make_unique_q<MenuVolumeItem>(
1715+
menu->menu(),
1716+
st::groupCallPopupVolumeMenu,
1717+
st::groupCallMenuVolumeSlider,
1718+
std::move(otherParticipantScreenStateValue),
1719+
state.volume.value_or(Group::kDefaultVolume),
1720+
Group::kMaxVolume,
1721+
state.mutedByMe,
1722+
st::groupCallMenuVolumePadding);
1723+
1724+
volumeItem->toggleMuteRequests(
1725+
) | rpl::on_next([=](bool muted) {
1726+
toggleScreenMute(muted);
1727+
}, volumeItem->lifetime());
1728+
1729+
volumeItem->toggleMuteLocallyRequests(
1730+
) | rpl::on_next([=](bool muted) {
1731+
toggleScreenMute(muted);
1732+
}, volumeItem->lifetime());
1733+
1734+
volumeItem->changeVolumeRequests(
1735+
) | rpl::on_next([=](int volume) {
1736+
changeScreenVolume(volume);
1737+
}, volumeItem->lifetime());
1738+
1739+
volumeItem->changeVolumeLocallyRequests(
1740+
) | rpl::on_next([=](int volume) {
1741+
changeScreenVolume(volume);
1742+
}, volumeItem->lifetime());
1743+
1744+
if (menu->actions().size() > 1) {
1745+
menu->addSeparator();
1746+
}
1747+
addSectionLabel(tr::lng_group_call_screen_share_audio(tr::now));
1748+
1749+
menu->addAction(std::move(volumeItem));
1750+
menu->addSeparator();
1751+
}
1752+
16561753
const auto muteAction = [&]() -> QAction* {
16571754
if (muteState == Row::State::Invited
16581755
|| muteState == Row::State::Calling
@@ -1696,6 +1793,29 @@ void Members::Controller::addMuteActionsToContextMenu(
16961793
muteAction->setText(muteUnmuteString(muted, mutedByMe));
16971794
}, menu->lifetime());
16981795
}
1796+
if (addScreenVolumeItem) {
1797+
const auto initial = _call->participantScreenState(participantPeer);
1798+
const auto screenMuteAction = menu->addAction(
1799+
screenMuteActionText(initial.mutedByMe),
1800+
[=] {
1801+
const auto state = _call->participantScreenState(participantPeer);
1802+
toggleScreenMute(!state.mutedByMe);
1803+
});
1804+
rpl::merge(
1805+
_call->otherParticipantScreenStateValue(
1806+
) | rpl::filter([=](const Group::ParticipantState &data) {
1807+
return data.peer == participantPeer;
1808+
}),
1809+
_call->otherParticipantStateValue(
1810+
) | rpl::filter([=](const Group::ParticipantState &data) {
1811+
return data.peer == participantPeer;
1812+
}) | rpl::map([=](const Group::ParticipantState &) {
1813+
return _call->participantScreenState(participantPeer);
1814+
})
1815+
) | rpl::on_next([=](const Group::ParticipantState &state) {
1816+
screenMuteAction->setText(screenMuteActionText(state.mutedByMe));
1817+
}, menu->lifetime());
1818+
}
16991819
}
17001820

17011821
std::unique_ptr<Row> Members::Controller::createRowForMe() {
@@ -1782,6 +1902,16 @@ auto Members::changeVolumeRequests() const
17821902
return _listController->changeVolumeRequests();
17831903
}
17841904

1905+
auto Members::toggleScreenMuteRequests() const
1906+
-> rpl::producer<Group::MuteRequest> {
1907+
return _listController->toggleScreenMuteRequests();
1908+
}
1909+
1910+
auto Members::changeScreenVolumeRequests() const
1911+
-> rpl::producer<Group::VolumeRequest> {
1912+
return _listController->changeScreenVolumeRequests();
1913+
}
1914+
17851915
auto Members::kickParticipantRequests() const
17861916
-> rpl::producer<not_null<PeerData*>> {
17871917
return _listController->kickParticipantRequests();

Telegram/SourceFiles/calls/group/calls_group_members.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class Members final
5555
-> rpl::producer<Group::MuteRequest>;
5656
[[nodiscard]] auto changeVolumeRequests() const
5757
-> rpl::producer<Group::VolumeRequest>;
58+
[[nodiscard]] auto toggleScreenMuteRequests() const
59+
-> rpl::producer<Group::MuteRequest>;
60+
[[nodiscard]] auto changeScreenVolumeRequests() const
61+
-> rpl::producer<Group::VolumeRequest>;
5862
[[nodiscard]] auto kickParticipantRequests() const
5963
-> rpl::producer<not_null<PeerData*>>;
6064
[[nodiscard]] rpl::producer<> addMembersRequests() const {

0 commit comments

Comments
 (0)