Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 91 additions & 4 deletions Telegram/SourceFiles/calls/group/calls_group_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3570,6 +3570,24 @@ float64 GroupCall::singleSourceVolumeValue() const {
return _singleSourceVolume / float64(Group::kDefaultVolume);
}

float64 GroupCall::effectiveParticipantVolume(
const Data::GroupCallParticipant &participant) const {
return participant.mutedByMe
? 0.
: (participant.volume / float64(Group::kDefaultVolume));
}

float64 GroupCall::effectiveParticipantScreenVolume(
const Data::GroupCallParticipant &participant) const {
const auto i = _screenVolumesByPeer.find(participant.peer);
if (i != end(_screenVolumesByPeer)) {
return i->second.muted
? 0.
: (i->second.volume / float64(Group::kDefaultVolume));
}
return effectiveParticipantVolume(participant);
}

void GroupCall::updateInstanceVolumes() {
const auto real = lookupReal();
if (!real) {
Expand Down Expand Up @@ -3606,14 +3624,13 @@ void GroupCall::updateInstanceVolume(
&& (volumeChanged
|| (was && (GetAdditionalAudioSsrc(was->videoParams)
!= additionalSsrc)));
const auto localVolume = now.mutedByMe
? 0.
: (now.volume / float64(Group::kDefaultVolume));
const auto localVolume = effectiveParticipantVolume(now);
const auto localScreenVolume = effectiveParticipantScreenVolume(now);
if (set) {
_instance->setVolume(now.ssrc, localVolume);
}
if (additionalSet) {
_instance->setVolume(additionalSsrc, localVolume);
_instance->setVolume(additionalSsrc, localScreenVolume);
}
}

Expand Down Expand Up @@ -3996,6 +4013,42 @@ void GroupCall::changeVolume(const Group::VolumeRequest &data) {
}
}

void GroupCall::toggleScreenMute(const Group::MuteRequest &data) {
if (_rtmp || videoStream() || data.peer->isSelf()) {
return;
}
auto &state = _screenVolumesByPeer[data.peer];
state.muted = data.mute;
_otherParticipantScreenStateValue.fire(participantScreenState(data.peer));
applyScreenVolume(data.peer);
}

void GroupCall::changeScreenVolume(const Group::VolumeRequest &data) {
if (_rtmp || videoStream() || data.peer->isSelf()) {
return;
}
auto &state = _screenVolumesByPeer[data.peer];
state.volume = std::clamp(data.volume, 1, Group::kMaxVolume);
state.muted = false;
_otherParticipantScreenStateValue.fire(participantScreenState(data.peer));
applyScreenVolume(data.peer);
}

void GroupCall::applyScreenVolume(not_null<PeerData*> participantPeer) {
if (!_instance) {
return;
}
const auto participant = LookupParticipant(this, participantPeer);
if (!participant) {
return;
}
const auto ssrc = GetAdditionalAudioSsrc(participant->videoParams);
if (!ssrc) {
return;
}
_instance->setVolume(ssrc, effectiveParticipantScreenVolume(*participant));
}

void GroupCall::editParticipant(
not_null<PeerData*> participantPeer,
bool mute,
Expand Down Expand Up @@ -4222,6 +4275,40 @@ auto GroupCall::otherParticipantStateValue() const
return _otherParticipantStateValue.events();
}

auto GroupCall::otherParticipantScreenStateValue() const
-> rpl::producer<Group::ParticipantState> {
return _otherParticipantScreenStateValue.events();
}

bool GroupCall::hasScreenShareAudio(
not_null<PeerData*> participantPeer) {
const auto participant = LookupParticipant(this, participantPeer);
return participant && GetAdditionalAudioSsrc(participant->videoParams);
}

Group::ParticipantState GroupCall::participantScreenState(
not_null<PeerData*> participantPeer) {
const auto participant = LookupParticipant(this, participantPeer);
const auto i = _screenVolumesByPeer.find(participantPeer);
const auto fallbackVolume = participant
? participant->volume
: Group::kDefaultVolume;
const auto fallbackMuted = participant ? participant->mutedByMe : false;
return Group::ParticipantState{
.peer = participantPeer,
.volume = std::clamp(
(i != end(_screenVolumesByPeer))
? i->second.volume
: fallbackVolume,
1,
Group::kMaxVolume),
.mutedByMe = (i != end(_screenVolumesByPeer))
? i->second.muted
: fallbackMuted,
.locallyOnly = true,
};
}

MTPInputGroupCall GroupCall::inputCall() const {
Expects(_id != 0);

Expand Down
20 changes: 20 additions & 0 deletions Telegram/SourceFiles/calls/group/calls_group_call.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ For license and copyright information please follow this link:
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "base/bytes.h"
#include "calls/group/calls_group_common.h"
#include "mtproto/sender.h"
#include "mtproto/mtproto_auth_key.h"
#include "webrtc/webrtc_device_common.h"
Expand Down Expand Up @@ -338,6 +339,12 @@ class GroupCall final

[[nodiscard]] auto otherParticipantStateValue() const
-> rpl::producer<Group::ParticipantState>;
[[nodiscard]] auto otherParticipantScreenStateValue() const
-> rpl::producer<Group::ParticipantState>;
[[nodiscard]] bool hasScreenShareAudio(
not_null<PeerData*> participantPeer);
[[nodiscard]] Group::ParticipantState participantScreenState(
not_null<PeerData*> participantPeer);

enum State {
Creating,
Expand Down Expand Up @@ -454,6 +461,8 @@ class GroupCall final

void toggleMute(const Group::MuteRequest &data);
void changeVolume(const Group::VolumeRequest &data);
void toggleScreenMute(const Group::MuteRequest &data);
void changeScreenVolume(const Group::VolumeRequest &data);

void inviteUsers(
const std::vector<InviteRequest> &requests,
Expand Down Expand Up @@ -594,6 +603,11 @@ class GroupCall final
void updateInstanceVolume(
const std::optional<Data::GroupCallParticipant> &was,
const Data::GroupCallParticipant &now);
[[nodiscard]] float64 effectiveParticipantVolume(
const Data::GroupCallParticipant &participant) const;
[[nodiscard]] float64 effectiveParticipantScreenVolume(
const Data::GroupCallParticipant &participant) const;
void applyScreenVolume(not_null<PeerData*> participantPeer);
void applyMeInCallLocally();
void startRejoin();
void rejoin();
Expand Down Expand Up @@ -730,7 +744,13 @@ class GroupCall final
bool _acceptFields = false;

rpl::event_stream<Group::ParticipantState> _otherParticipantStateValue;
rpl::event_stream<Group::ParticipantState> _otherParticipantScreenStateValue;
std::vector<MTPGroupCallParticipant> _queuedSelfUpdates;
struct ScreenVolumeState {
int volume = Group::kDefaultVolume;
bool muted = false;
};
base::flat_map<not_null<PeerData*>, ScreenVolumeState> _screenVolumesByPeer;

CallId _id = 0;
CallId _accessHash = 0;
Expand Down
136 changes: 133 additions & 3 deletions Telegram/SourceFiles/calls/group/calls_group_members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class Members::Controller final
}
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
[[nodiscard]] rpl::producer<VolumeRequest> changeVolumeRequests() const;
[[nodiscard]] rpl::producer<MuteRequest> toggleScreenMuteRequests() const;
[[nodiscard]] rpl::producer<VolumeRequest> changeScreenVolumeRequests() const;
[[nodiscard]] auto kickParticipantRequests() const
-> rpl::producer<not_null<PeerData*>>;

Expand Down Expand Up @@ -188,6 +190,8 @@ class Members::Controller final

rpl::event_stream<MuteRequest> _toggleMuteRequests;
rpl::event_stream<VolumeRequest> _changeVolumeRequests;
rpl::event_stream<MuteRequest> _toggleScreenMuteRequests;
rpl::event_stream<VolumeRequest> _changeScreenVolumeRequests;
rpl::event_stream<not_null<PeerData*>> _kickParticipantRequests;
rpl::variable<int> _fullCount = 1;

Expand Down Expand Up @@ -1047,6 +1051,16 @@ auto Members::Controller::changeVolumeRequests() const
return _changeVolumeRequests.events();
}

auto Members::Controller::toggleScreenMuteRequests() const
-> rpl::producer<MuteRequest> {
return _toggleScreenMuteRequests.events();
}

auto Members::Controller::changeScreenVolumeRequests() const
-> rpl::producer<VolumeRequest> {
return _changeScreenVolumeRequests.events();
}

bool Members::Controller::rowIsMe(not_null<PeerData*> participantPeer) {
return isMe(participantPeer);
}
Expand Down Expand Up @@ -1581,11 +1595,40 @@ void Members::Controller::addMuteActionsToContextMenu(
.locallyOnly = local,
});
});
const auto toggleScreenMute = crl::guard(this, [=](bool mute) {
_toggleScreenMuteRequests.fire(Group::MuteRequest{
.peer = participantPeer,
.mute = mute,
.locallyOnly = true,
});
});
const auto changeScreenVolume = crl::guard(this, [=](int volume) {
_changeScreenVolumeRequests.fire(Group::VolumeRequest{
.peer = participantPeer,
.volume = std::clamp(volume, 1, Group::kMaxVolume),
.locallyOnly = true,
});
});
const auto addSectionLabel = [=](const QString &text) {
const auto action = menu->addAction(text, [] {});
action->setEnabled(false);
};
const auto screenMuteActionText = [=](bool muted) {
return tr::lng_group_call_screen_share_audio(tr::now)
+ u": "_q
+ (muted
? tr::lng_call_unmute_audio(tr::now)
: tr::lng_call_mute_audio(tr::now));
};

const auto muteState = row->state();
const auto muted = (muteState == Row::State::Muted)
|| (muteState == Row::State::RaisedHand);
const auto mutedByMe = row->mutedByMe();
const auto addScreenVolumeItem = !_call->rtmp()
&& !_call->videoStream()
&& !isMe(participantPeer)
&& _call->hasScreenShareAudio(participantPeer);

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

Expand Down Expand Up @@ -1643,16 +1686,70 @@ void Members::Controller::addMuteActionsToContextMenu(
if (menu->actions().size() > 1) { // First - cover.
menu->addSeparator();
}
if (addScreenVolumeItem) {
addSectionLabel(tr::lng_group_call_microphone(tr::now));
}

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

if (!_call->rtmp()
&& !_call->videoStream()
&& !isMe(participantPeer)) {
if (!addScreenVolumeItem && !isMe(participantPeer)) {
menu->addSeparator();
}
};

if (addScreenVolumeItem) {
auto otherParticipantScreenStateValue = rpl::merge(
_call->otherParticipantScreenStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) {
return data.peer == participantPeer;
}),
_call->otherParticipantStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) {
return data.peer == participantPeer;
}) | rpl::map([=](const Group::ParticipantState &) {
return _call->participantScreenState(participantPeer);
}));

const auto state = _call->participantScreenState(participantPeer);
auto volumeItem = base::make_unique_q<MenuVolumeItem>(
menu->menu(),
st::groupCallPopupVolumeMenu,
st::groupCallMenuVolumeSlider,
std::move(otherParticipantScreenStateValue),
state.volume.value_or(Group::kDefaultVolume),
Group::kMaxVolume,
state.mutedByMe,
st::groupCallMenuVolumePadding);

volumeItem->toggleMuteRequests(
) | rpl::on_next([=](bool muted) {
toggleScreenMute(muted);
}, volumeItem->lifetime());

volumeItem->toggleMuteLocallyRequests(
) | rpl::on_next([=](bool muted) {
toggleScreenMute(muted);
}, volumeItem->lifetime());

volumeItem->changeVolumeRequests(
) | rpl::on_next([=](int volume) {
changeScreenVolume(volume);
}, volumeItem->lifetime());

volumeItem->changeVolumeLocallyRequests(
) | rpl::on_next([=](int volume) {
changeScreenVolume(volume);
}, volumeItem->lifetime());

if (menu->actions().size() > 1) {
menu->addSeparator();
}
addSectionLabel(tr::lng_group_call_screen_share_audio(tr::now));

menu->addAction(std::move(volumeItem));
menu->addSeparator();
}

const auto muteAction = [&]() -> QAction* {
if (muteState == Row::State::Invited
|| muteState == Row::State::Calling
Expand Down Expand Up @@ -1696,6 +1793,29 @@ void Members::Controller::addMuteActionsToContextMenu(
muteAction->setText(muteUnmuteString(muted, mutedByMe));
}, menu->lifetime());
}
if (addScreenVolumeItem) {
const auto initial = _call->participantScreenState(participantPeer);
const auto screenMuteAction = menu->addAction(
screenMuteActionText(initial.mutedByMe),
[=] {
const auto state = _call->participantScreenState(participantPeer);
toggleScreenMute(!state.mutedByMe);
});
rpl::merge(
_call->otherParticipantScreenStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) {
return data.peer == participantPeer;
}),
_call->otherParticipantStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) {
return data.peer == participantPeer;
}) | rpl::map([=](const Group::ParticipantState &) {
return _call->participantScreenState(participantPeer);
})
) | rpl::on_next([=](const Group::ParticipantState &state) {
screenMuteAction->setText(screenMuteActionText(state.mutedByMe));
}, menu->lifetime());
}
}

std::unique_ptr<Row> Members::Controller::createRowForMe() {
Expand Down Expand Up @@ -1782,6 +1902,16 @@ auto Members::changeVolumeRequests() const
return _listController->changeVolumeRequests();
}

auto Members::toggleScreenMuteRequests() const
-> rpl::producer<Group::MuteRequest> {
return _listController->toggleScreenMuteRequests();
}

auto Members::changeScreenVolumeRequests() const
-> rpl::producer<Group::VolumeRequest> {
return _listController->changeScreenVolumeRequests();
}

auto Members::kickParticipantRequests() const
-> rpl::producer<not_null<PeerData*>> {
return _listController->kickParticipantRequests();
Expand Down
4 changes: 4 additions & 0 deletions Telegram/SourceFiles/calls/group/calls_group_members.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class Members final
-> rpl::producer<Group::MuteRequest>;
[[nodiscard]] auto changeVolumeRequests() const
-> rpl::producer<Group::VolumeRequest>;
[[nodiscard]] auto toggleScreenMuteRequests() const
-> rpl::producer<Group::MuteRequest>;
[[nodiscard]] auto changeScreenVolumeRequests() const
-> rpl::producer<Group::VolumeRequest>;
[[nodiscard]] auto kickParticipantRequests() const
-> rpl::producer<not_null<PeerData*>>;
[[nodiscard]] rpl::producer<> addMembersRequests() const {
Expand Down
Loading