diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index 9f34964cca..319c7223ca 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -53,13 +53,14 @@ GroupCall::GroupCall( , _api(&_channel->session().mtp()) , _lastSpokeCheckTimer([=] { checkLastSpoke(); }) , _checkJoinedTimer([=] { checkJoined(); }) { - _muted.changes( - ) | rpl::start_with_next([=](MuteState state) { + _muted.value( + ) | rpl::combine_previous( + ) | rpl::start_with_next([=](MuteState previous, MuteState state) { if (_instance) { - _instance->setIsMuted(state != MuteState::Active); + updateInstanceMuteState(); } - if (_mySsrc && state != MuteState::ForceMuted) { - sendMutedUpdate(); + if (_mySsrc) { + maybeSendMutedUpdate(previous); } }, _lifetime); @@ -200,9 +201,9 @@ void GroupCall::rejoin() { const auto json = QJsonDocument(root).toJson( QJsonDocument::Compact); - const auto muted = _muted.current(); + const auto wasMuteState = muted(); _api.request(MTPphone_JoinGroupCall( - MTP_flags((muted != MuteState::Active) + MTP_flags((wasMuteState != MuteState::Active) ? MTPphone_JoinGroupCall::Flag::f_muted : MTPphone_JoinGroupCall::Flag(0)), inputCall(), @@ -213,11 +214,7 @@ void GroupCall::rejoin() { ? State::Joined : State::Connecting); applySelfInCallLocally(); - - if (_muted.current() != muted) { - sendMutedUpdate(); - } - + maybeSendMutedUpdate(wasMuteState); _channel->session().api().applyUpdates(updates); }).fail([=](const RPCError &error) { LOG(("Call Error: Could not join, error: %1" @@ -251,12 +248,11 @@ void GroupCall::applySelfInCallLocally() { const auto lastActive = (i != end(participants)) ? i->lastActive : TimeId(0); - const auto muted = (_muted.current() != MuteState::Active); - const auto cantSelfUnmute = (_muted.current() == MuteState::ForceMuted); - const auto flags = (cantSelfUnmute ? Flag(0) : Flag::f_can_self_unmute) + const auto canSelfUnmute = (muted() != MuteState::ForceMuted); + const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0)) | (lastActive ? Flag::f_active_date : Flag(0)) | (_mySsrc ? Flag(0) : Flag::f_left) - | (muted ? Flag::f_muted : Flag(0)); + | ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)); call->applyUpdateChecked( MTP_updateGroupCallParticipants( inputCall(), @@ -488,11 +484,19 @@ void GroupCall::createAndStartController() { LOG(("Call Info: Creating group instance")); _instance = std::make_unique( std::move(descriptor)); - _instance->setIsMuted(_muted.current() != MuteState::Active); + updateInstanceMuteState(); //raw->setAudioOutputDuckingEnabled(settings.callAudioDuckingEnabled()); } +void GroupCall::updateInstanceMuteState() { + Expects(_instance != nullptr); + + const auto state = muted(); + _instance->setIsMuted(state != MuteState::Active + && state != MuteState::PushToTalk); +} + void GroupCall::handleLevelsUpdated( gsl::span> data) { Expects(!data.empty()); @@ -609,10 +613,23 @@ void GroupCall::setInstanceConnected(bool connected) { } } +void GroupCall::maybeSendMutedUpdate(MuteState previous) { + // Send only Active <-> !Active changes. + const auto now = muted(); + const auto wasActive = (previous == MuteState::Active); + const auto nowActive = (now == MuteState::Active); + if (now == MuteState::ForceMuted + || previous == MuteState::ForceMuted + || (nowActive == wasActive)) { + return; + } + sendMutedUpdate(); +} + void GroupCall::sendMutedUpdate() { _api.request(_updateMuteRequestId).cancel(); _updateMuteRequestId = _api.request(MTPphone_EditGroupCallMember( - MTP_flags((_muted.current() != MuteState::Active) + MTP_flags((muted() != MuteState::Active) ? MTPphone_EditGroupCallMember::Flag::f_muted : MTPphone_EditGroupCallMember::Flag(0)), inputCall(), @@ -758,8 +775,9 @@ void GroupCall::applyGlobalShortcutChanges() { } _pushToTalk = shortcut; _shortcutManager->startWatching(_pushToTalk, [=](bool pressed) { - if (_muted.current() != MuteState::ForceMuted) { - setMuted(pressed ? MuteState::Active : MuteState::Muted); + if (muted() != MuteState::ForceMuted + && muted() != MuteState::Active) { + setMuted(pressed ? MuteState::PushToTalk : MuteState::Muted); } }); } diff --git a/Telegram/SourceFiles/calls/calls_group_call.h b/Telegram/SourceFiles/calls/calls_group_call.h index 739b6295be..eab1f503a2 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.h +++ b/Telegram/SourceFiles/calls/calls_group_call.h @@ -28,10 +28,17 @@ namespace Calls { enum class MuteState { Active, + PushToTalk, Muted, ForceMuted, }; +[[nodiscard]] inline auto MapPushToTalkToActive() { + return rpl::map([=](MuteState state) { + return (state == MuteState::PushToTalk) ? MuteState::Active : state; + }); +} + struct LevelUpdate { uint32 ssrc = 0; float value = 0.; @@ -132,7 +139,9 @@ private: void setState(State state); void finish(FinishType type); + void maybeSendMutedUpdate(MuteState previous); void sendMutedUpdate(); + void updateInstanceMuteState(); void applySelfInCallLocally(); void rejoin(); diff --git a/Telegram/SourceFiles/calls/calls_group_panel.cpp b/Telegram/SourceFiles/calls/calls_group_panel.cpp index 6e66af6c00..fab99d7b60 100644 --- a/Telegram/SourceFiles/calls/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_group_panel.cpp @@ -317,13 +317,13 @@ void GroupPanel::hangup(bool discardCallChecked) { void GroupPanel::initControls() { _mute->clicks( ) | rpl::filter([=](Qt::MouseButton button) { - return (button == Qt::LeftButton); + return (button == Qt::LeftButton) + && _call + && (_call->muted() != MuteState::ForceMuted); }) | rpl::start_with_next([=] { - if (_call && _call->muted() != MuteState::ForceMuted) { - _call->setMuted((_call->muted() == MuteState::Active) - ? MuteState::Muted - : MuteState::Active); - } + _call->setMuted((_call->muted() == MuteState::Muted) + ? MuteState::Active + : MuteState::Muted); }, _mute->lifetime()); _hangup->setClickedCallback([=] { hangup(false); }); @@ -381,19 +381,20 @@ void GroupPanel::initWithCall(GroupCall *call) { using namespace rpl::mappers; rpl::combine( - _call->mutedValue(), + _call->mutedValue() | MapPushToTalkToActive(), _call->stateValue() | rpl::map( _1 == State::Creating || _1 == State::Joining || _1 == State::Connecting ) + ) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](MuteState mute, bool connecting) { _mute->setState(Ui::CallMuteButtonState{ .text = (connecting ? tr::lng_group_call_connecting(tr::now) : mute == MuteState::ForceMuted ? tr::lng_group_call_force_muted(tr::now) - : mute != MuteState::Active + : mute == MuteState::Muted ? tr::lng_group_call_unmute(tr::now) : tr::lng_group_call_you_are_live(tr::now)), .type = (connecting diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index 9b48078ef0..a54c94d69c 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -198,9 +198,9 @@ void TopBar::initControls() { call->setMuted(!call->muted()); } else if (const auto group = _groupCall.get()) { if (group->muted() != MuteState::ForceMuted) { - group->setMuted((group->muted() == MuteState::Active) - ? MuteState::Muted - : MuteState::Active); + group->setMuted((group->muted() == MuteState::Muted) + ? MuteState::Active + : MuteState::Muted); } } }); @@ -212,7 +212,9 @@ void TopBar::initControls() { _call ? mapToState(_call->muted()) : _groupCall->muted()); auto muted = _call ? _call->mutedValue() | rpl::map(mapToState) - : _groupCall->mutedValue(); + : (_groupCall->mutedValue() + | MapPushToTalkToActive() + | rpl::distinct_until_changed()); std::move( muted ) | rpl::start_with_next([=](MuteState state) {