Switch between videos by left click.

This commit is contained in:
John Preston 2021-05-11 13:35:04 +04:00
parent 7e8d1f7974
commit 3a321d64f6
5 changed files with 173 additions and 134 deletions

View file

@ -47,6 +47,7 @@ constexpr auto kCheckLastSpokeInterval = crl::time(1000);
constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000); constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000);
constexpr auto kUpdateSendActionEach = crl::time(500); constexpr auto kUpdateSendActionEach = crl::time(500);
constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000); constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
constexpr auto kFixLargeVideoDuration = 5 * crl::time(1000);
[[nodiscard]] std::unique_ptr<Webrtc::MediaDevices> CreateMediaDevices() { [[nodiscard]] std::unique_ptr<Webrtc::MediaDevices> CreateMediaDevices() {
const auto &settings = Core::App().settings(); const auto &settings = Core::App().settings();
@ -61,15 +62,9 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
uint64 id, uint64 id,
not_null<PeerData*> participantPeer) { not_null<PeerData*> participantPeer) {
const auto call = peer->groupCall(); const auto call = peer->groupCall();
if (!id || !call || call->id() != id) { return (id && call && call->id() == id)
return nullptr; ? call->participantByPeer(participantPeer)
} : nullptr;
const auto &participants = call->participants();
const auto i = ranges::find(
participants,
participantPeer,
&Data::GroupCallParticipant::peer);
return (i != end(participants)) ? &*i : nullptr;
} }
[[nodiscard]] double TimestampFromMsgId(mtpMsgId msgId) { [[nodiscard]] double TimestampFromMsgId(mtpMsgId msgId) {
@ -559,7 +554,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
newLarge = chooseLargeVideoEndpoint(); newLarge = chooseLargeVideoEndpoint();
} }
if (_videoEndpointLarge.current() != newLarge) { if (_videoEndpointLarge.current() != newLarge) {
_videoEndpointLarge = newLarge; setVideoEndpointLarge(newLarge);
} }
if (!updateCameraNotStreams.empty()) { if (!updateCameraNotStreams.empty()) {
_streamsVideoUpdated.fire({ updateCameraNotStreams, false }); _streamsVideoUpdated.fire({ updateCameraNotStreams, false });
@ -624,7 +619,10 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
const auto wasSounding = data.was && data.was->sounding; const auto wasSounding = data.was && data.was->sounding;
if (nowSpeaking == wasSpeaking && nowSounding == wasSounding) { if (nowSpeaking == wasSpeaking && nowSounding == wasSounding) {
return; return;
} else if (_videoEndpointPinned.current()) { } else if (_videoEndpointPinned.current()
|| (_videoLargeShowTime
&& _videoLargeShowTime + kFixLargeVideoDuration
> crl::now())) {
return; return;
} }
if (nowScreenEndpoint != newLarge.endpoint if (nowScreenEndpoint != newLarge.endpoint
@ -880,7 +878,7 @@ void GroupCall::setMyEndpointType(
auto newLarge = _videoEndpointLarge.current(); auto newLarge = _videoEndpointLarge.current();
if (newLarge.endpoint == endpoint) { if (newLarge.endpoint == endpoint) {
_videoEndpointPinned = false; _videoEndpointPinned = false;
_videoEndpointLarge = chooseLargeVideoEndpoint(); setVideoEndpointLarge(chooseLargeVideoEndpoint());
} }
_streamsVideoUpdated.fire({ endpoint, false }); _streamsVideoUpdated.fire({ endpoint, false });
} }
@ -899,7 +897,7 @@ void GroupCall::setMyEndpointType(
&& nowLarge != EndpointType::Screen) && nowLarge != EndpointType::Screen)
|| (type == EndpointType::Camera || (type == EndpointType::Camera
&& nowLarge == EndpointType::None))) { && nowLarge == EndpointType::None))) {
_videoEndpointLarge = VideoEndpoint{ _joinAs, endpoint }; setVideoEndpointLarge(VideoEndpoint{ _joinAs, endpoint });
} }
} }
} }
@ -1132,34 +1130,30 @@ void GroupCall::leavePresentation() {
} }
void GroupCall::applyMeInCallLocally() { void GroupCall::applyMeInCallLocally() {
const auto call = _peer->groupCall(); const auto real = lookupReal();
if (!call || call->id() != _id) { if (!real) {
return; return;
} }
using Flag = MTPDgroupCallParticipant::Flag; using Flag = MTPDgroupCallParticipant::Flag;
const auto &participants = call->participants(); const auto participant = real->participantByPeer(_joinAs);
const auto i = ranges::find( const auto date = participant
participants, ? participant->date
_joinAs,
&Data::GroupCallParticipant::peer);
const auto date = (i != end(participants))
? i->date
: base::unixtime::now(); : base::unixtime::now();
const auto lastActive = (i != end(participants)) const auto lastActive = participant
? i->lastActive ? participant->lastActive
: TimeId(0); : TimeId(0);
const auto volume = (i != end(participants)) const auto volume = participant
? i->volume ? participant->volume
: Group::kDefaultVolume; : Group::kDefaultVolume;
const auto canSelfUnmute = (muted() != MuteState::ForceMuted) const auto canSelfUnmute = (muted() != MuteState::ForceMuted)
&& (muted() != MuteState::RaisedHand); && (muted() != MuteState::RaisedHand);
const auto raisedHandRating = (muted() != MuteState::RaisedHand) const auto raisedHandRating = (muted() != MuteState::RaisedHand)
? uint64(0) ? uint64(0)
: (i != end(participants)) : participant
? i->raisedHandRating ? participant->raisedHandRating
: FindLocalRaisedHandRating(participants); : FindLocalRaisedHandRating(real->participants());
const auto params = (i != end(participants)) const auto params = participant
? i->videoParams.get() ? participant->videoParams.get()
: nullptr; : nullptr;
const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0)) const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0))
| (lastActive ? Flag::f_active_date : Flag(0)) | (lastActive ? Flag::f_active_date : Flag(0))
@ -1173,7 +1167,7 @@ void GroupCall::applyMeInCallLocally() {
? Flag::f_presentation ? Flag::f_presentation
: Flag(0)) : Flag(0))
| (raisedHandRating > 0 ? Flag::f_raise_hand_rating : Flag(0)); | (raisedHandRating > 0 ? Flag::f_raise_hand_rating : Flag(0));
call->applyLocalUpdate( real->applyLocalUpdate(
MTP_updateGroupCallParticipants( MTP_updateGroupCallParticipants(
inputCall(), inputCall(),
MTP_vector<MTPGroupCallParticipant>( MTP_vector<MTPGroupCallParticipant>(
@ -2013,17 +2007,15 @@ bool GroupCall::mediaChannelDescriptionsFill(
const auto addVideoChannel = [&]( const auto addVideoChannel = [&](
not_null<PeerData*> participantPeer, not_null<PeerData*> participantPeer,
const auto field) { const auto field) {
const auto i = ranges::find( const auto participant = real->participantByPeer(
existing, participantPeer);
participantPeer, Assert(participant != nullptr);
&Data::GroupCallParticipant::peer); Assert(participant->videoParams != nullptr);
Assert(i != end(existing)); const auto &params = participant->videoParams.get()->*field;
Assert(i->videoParams != nullptr);
const auto &params = i->videoParams.get()->*field;
Assert(!params.empty()); Assert(!params.empty());
add(Channel{ add(Channel{
.type = Channel::Type::Video, .type = Channel::Type::Video,
.audioSsrc = i->ssrc, .audioSsrc = participant->ssrc,
.videoInformation = params.json.toStdString(), .videoInformation = params.json.toStdString(),
}, (field == &ParticipantVideoParams::screen)); }, (field == &ParticipantVideoParams::screen));
}; };
@ -2085,7 +2077,7 @@ void GroupCall::setIncomingVideoEndpoints(
newLarge = VideoEndpoint(); newLarge = VideoEndpoint();
} }
if (newLarge.empty()) { if (newLarge.empty()) {
_videoEndpointLarge = chooseLargeVideoEndpoint(); setVideoEndpointLarge(chooseLargeVideoEndpoint());
} }
for (const auto &endpoint : removed) { for (const auto &endpoint : removed) {
if (_activeVideoEndpoints.contains(endpoint)) { if (_activeVideoEndpoints.contains(endpoint)) {
@ -2134,7 +2126,7 @@ void GroupCall::fillActiveVideoEndpoints() {
newLarge = VideoEndpoint(); newLarge = VideoEndpoint();
} }
if (!newLarge) { if (!newLarge) {
_videoEndpointLarge = chooseLargeVideoEndpoint(); setVideoEndpointLarge(chooseLargeVideoEndpoint());
} }
for (const auto &[endpoint, type] : removed) { for (const auto &[endpoint, type] : removed) {
if (_activeVideoEndpoints.remove(endpoint)) { if (_activeVideoEndpoints.remove(endpoint)) {
@ -2494,16 +2486,30 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
}).send(); }).send();
} }
void GroupCall::pinVideoEndpoint(const VideoEndpoint &endpoint) { void GroupCall::pinVideoEndpoint(VideoEndpoint endpoint) {
if (!endpoint) { if (!endpoint) {
_videoEndpointPinned = false; _videoEndpointPinned = false;
} else if (streamsVideo(endpoint.endpoint)) { } else if (streamsVideo(endpoint.endpoint)) {
_videoEndpointPinned = false; _videoEndpointPinned = false;
_videoEndpointLarge = endpoint; setVideoEndpointLarge(std::move(endpoint));
_videoEndpointPinned = true; _videoEndpointPinned = true;
} }
} }
void GroupCall::showVideoEndpointLarge(VideoEndpoint endpoint) {
if (!streamsVideo(endpoint.endpoint)) {
return;
}
_videoEndpointPinned = false;
setVideoEndpointLarge(std::move(endpoint));
_videoLargeShowTime = crl::now();
}
void GroupCall::setVideoEndpointLarge(VideoEndpoint endpoint) {
_videoEndpointLarge = endpoint;
_videoLargeShowTime = 0;
}
void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) { void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) {
if (input) { if (input) {
_mediaDevices->switchToAudioInput(deviceId); _mediaDevices->switchToAudioInput(deviceId);
@ -2572,13 +2578,9 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
} }
const auto owner = &_peer->owner(); const auto owner = &_peer->owner();
const auto &invited = owner->invitedToCallUsers(_id); const auto &invited = owner->invitedToCallUsers(_id);
const auto &participants = real->participants();
auto &&toInvite = users | ranges::views::filter([&]( auto &&toInvite = users | ranges::views::filter([&](
not_null<UserData*> user) { not_null<UserData*> user) {
return !invited.contains(user) && !ranges::contains( return !invited.contains(user) && !real->participantByPeer(user);
participants,
user,
&Data::GroupCallParticipant::peer);
}); });
auto count = 0; auto count = 0;

View file

@ -289,7 +289,7 @@ public:
[[nodiscard]] rpl::producer<bool> videoEndpointPinnedValue() const { [[nodiscard]] rpl::producer<bool> videoEndpointPinnedValue() const {
return _videoEndpointPinned.value(); return _videoEndpointPinned.value();
} }
void pinVideoEndpoint(const VideoEndpoint &endpoint); void pinVideoEndpoint(VideoEndpoint endpoint);
[[nodiscard]] const VideoEndpoint &videoEndpointLarge() const { [[nodiscard]] const VideoEndpoint &videoEndpointLarge() const {
return _videoEndpointLarge.current(); return _videoEndpointLarge.current();
} }
@ -297,6 +297,7 @@ public:
-> rpl::producer<VideoEndpoint> { -> rpl::producer<VideoEndpoint> {
return _videoEndpointLarge.value(); return _videoEndpointLarge.value();
} }
void showVideoEndpointLarge(VideoEndpoint endpoint);
struct LargeTrack { struct LargeTrack {
Webrtc::VideoTrack *track = nullptr; Webrtc::VideoTrack *track = nullptr;
PeerData *peer = nullptr; PeerData *peer = nullptr;
@ -451,6 +452,7 @@ private:
[[nodiscard]] VideoEndpoint chooseLargeVideoEndpoint() const; [[nodiscard]] VideoEndpoint chooseLargeVideoEndpoint() const;
[[nodiscard]] EndpointType activeVideoEndpointType( [[nodiscard]] EndpointType activeVideoEndpointType(
const std::string &endpoint) const; const std::string &endpoint) const;
void setVideoEndpointLarge(VideoEndpoint endpoint);
void editParticipant( void editParticipant(
not_null<PeerData*> participantPeer, not_null<PeerData*> participantPeer,
@ -539,6 +541,7 @@ private:
rpl::variable<bool> _videoEndpointPinned; rpl::variable<bool> _videoEndpointPinned;
std::unique_ptr<Webrtc::VideoTrack> _videoLargeTrackWrap; std::unique_ptr<Webrtc::VideoTrack> _videoLargeTrackWrap;
rpl::variable<LargeTrack> _videoLargeTrack; rpl::variable<LargeTrack> _videoLargeTrack;
crl::time _videoLargeShowTime = 0;
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke; base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;
rpl::event_stream<Group::RejoinEvent> _rejoinEvents; rpl::event_stream<Group::RejoinEvent> _rejoinEvents;
rpl::event_stream<> _allowedToSpeakNotifications; rpl::event_stream<> _allowedToSpeakNotifications;

View file

@ -159,6 +159,8 @@ private:
void setRowVideoEndpoint( void setRowVideoEndpoint(
not_null<Row*> row, not_null<Row*> row,
const std::string &endpoint); const std::string &endpoint);
bool toggleRowVideo(not_null<PeerListRow*> row);
void showRowMenu(not_null<PeerListRow*> row);
void generateNarrowShadow(); void generateNarrowShadow();
void appendInvitedUsers(); void appendInvitedUsers();
@ -377,16 +379,13 @@ void Members::Controller::setupListChangeViewers() {
const auto row = i->second; const auto row = i->second;
const auto real = _call->lookupReal(); const auto real = _call->lookupReal();
Assert(real != nullptr); Assert(real != nullptr);
const auto &participants = real->participants(); const auto participant = real->participantByPeer(
const auto j = ranges::find( row->peer());
participants, if (!participant) {
row->peer(),
&Data::GroupCallParticipant::peer);
if (j == end(participants)) {
setRowVideoEndpoint(row, std::string()); setRowVideoEndpoint(row, std::string());
} else { } else {
const auto &camera = computeCameraEndpoint(&*j); const auto &camera = computeCameraEndpoint(participant);
const auto &screen = computeScreenEndpoint(&*j); const auto &screen = computeScreenEndpoint(participant);
if (update.endpoint == camera if (update.endpoint == camera
&& (_largeEndpoint != screen) && (_largeEndpoint != screen)
&& _call->streamsVideo(screen)) { && _call->streamsVideo(screen)) {
@ -730,12 +729,7 @@ const Data::GroupCallParticipant *Members::Controller::findParticipant(
return nullptr; return nullptr;
} else if (endpoint == _call->screenSharingEndpoint() } else if (endpoint == _call->screenSharingEndpoint()
|| endpoint == _call->cameraSharingEndpoint()) { || endpoint == _call->cameraSharingEndpoint()) {
const auto &participants = real->participants(); return real->participantByPeer(_call->joinAs());
const auto i = ranges::find(
participants,
_call->joinAs(),
&Data::GroupCallParticipant::peer);
return (i != end(participants)) ? &*i : nullptr;
} else { } else {
return real->participantByEndpoint(endpoint); return real->participantByEndpoint(endpoint);
} }
@ -784,7 +778,6 @@ bool Members::Controller::isMe(not_null<PeerData*> participantPeer) const {
void Members::Controller::prepareRows(not_null<Data::GroupCall*> real) { void Members::Controller::prepareRows(not_null<Data::GroupCall*> real) {
auto foundMe = false; auto foundMe = false;
auto changed = false; auto changed = false;
const auto &participants = real->participants();
auto count = delegate()->peerListFullRowsCount(); auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count;) { for (auto i = 0; i != count;) {
auto row = delegate()->peerListRowAt(i); auto row = delegate()->peerListRowAt(i);
@ -794,11 +787,7 @@ void Members::Controller::prepareRows(not_null<Data::GroupCall*> real) {
++i; ++i;
continue; continue;
} }
const auto contains = ranges::contains( if (real->participantByPeer(participantPeer)) {
participants,
participantPeer,
&Data::GroupCallParticipant::peer);
if (contains) {
++i; ++i;
} else { } else {
changed = true; changed = true;
@ -808,19 +797,16 @@ void Members::Controller::prepareRows(not_null<Data::GroupCall*> real) {
} }
if (!foundMe) { if (!foundMe) {
const auto me = _call->joinAs(); const auto me = _call->joinAs();
const auto i = ranges::find( const auto participant = real->participantByPeer(me);
participants, auto row = participant
me, ? createRow(*participant)
&Data::GroupCallParticipant::peer);
auto row = (i != end(participants))
? createRow(*i)
: createRowForMe(); : createRowForMe();
if (row) { if (row) {
changed = true; changed = true;
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
} }
} }
for (const auto &participant : participants) { for (const auto &participant : real->participants()) {
if (auto row = createRow(participant)) { if (auto row = createRow(participant)) {
changed = true; changed = true;
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
@ -1089,6 +1075,12 @@ auto Members::Controller::kickParticipantRequests() const
} }
void Members::Controller::rowClicked(not_null<PeerListRow*> row) { void Members::Controller::rowClicked(not_null<PeerListRow*> row) {
if (!toggleRowVideo(row)) {
showRowMenu(row);
}
}
void Members::Controller::showRowMenu(not_null<PeerListRow*> row) {
delegate()->peerListShowRowMenu(row, [=](not_null<Ui::PopupMenu*> menu) { delegate()->peerListShowRowMenu(row, [=](not_null<Ui::PopupMenu*> menu) {
if (!_menu || _menu.get() != menu) { if (!_menu || _menu.get() != menu) {
return; return;
@ -1103,9 +1095,51 @@ void Members::Controller::rowClicked(not_null<PeerListRow*> row) {
}); });
} }
bool Members::Controller::toggleRowVideo(not_null<PeerListRow*> row) {
const auto real = _call->lookupReal();
if (!real) {
return false;
}
const auto participantPeer = row->peer();
const auto isMe = (participantPeer == _call->joinAs());
const auto participant = real->participantByPeer(participantPeer);
if (!participant) {
return false;
}
const auto params = participant->videoParams.get();
const auto empty = std::string();
const auto &camera = isMe
? _call->cameraSharingEndpoint()
: (params && _call->streamsVideo(params->camera.endpoint))
? params->camera.endpoint
: empty;
const auto &screen = isMe
? _call->screenSharingEndpoint()
: (params && _call->streamsVideo(params->screen.endpoint))
? params->screen.endpoint
: empty;
const auto &large = _call->videoEndpointLarge().endpoint;
const auto show = [&] {
if (!screen.empty() && large != screen) {
return screen;
} else if (!camera.empty() && large != camera) {
return camera;
}
return std::string();
}();
if (show.empty()) {
return false;
} else if (_call->videoEndpointPinned()) {
_call->pinVideoEndpoint({ participantPeer, show });
} else {
_call->showVideoEndpointLarge({ participantPeer, show });
}
return true;
}
void Members::Controller::rowActionClicked( void Members::Controller::rowActionClicked(
not_null<PeerListRow*> row) { not_null<PeerListRow*> row) {
rowClicked(row); showRowMenu(row);
} }
base::unique_qptr<Ui::PopupMenu> Members::Controller::rowContextMenu( base::unique_qptr<Ui::PopupMenu> Members::Controller::rowContextMenu(
@ -1195,26 +1229,20 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
result->addAction( result->addAction(
tr::lng_group_call_context_unpin_camera(tr::now), tr::lng_group_call_context_unpin_camera(tr::now),
[=] { _call->pinVideoEndpoint(VideoEndpoint()); }); [=] { _call->pinVideoEndpoint(VideoEndpoint()); });
} else { } else if (const auto participant = real->participantByPeer(
const auto &participants = real->participants(); participantPeer)) {
const auto i = ranges::find( const auto &camera = computeCameraEndpoint(participant);
participants, const auto &screen = computeScreenEndpoint(participant);
participantPeer, const auto streamsScreen = _call->streamsVideo(screen);
&Data::GroupCallParticipant::peer); if (streamsScreen || _call->streamsVideo(camera)) {
if (i != end(participants)) { const auto callback = [=] {
const auto &camera = computeCameraEndpoint(&*i); _call->pinVideoEndpoint(VideoEndpoint{
const auto &screen = computeScreenEndpoint(&*i); participantPeer,
const auto streamsScreen = _call->streamsVideo(screen); streamsScreen ? screen : camera });
if (streamsScreen || _call->streamsVideo(camera)) { };
const auto callback = [=] { result->addAction(
_call->pinVideoEndpoint(VideoEndpoint{ tr::lng_group_call_context_pin_camera(tr::now),
participantPeer, callback);
streamsScreen ? screen : camera });
};
result->addAction(
tr::lng_group_call_context_pin_camera(tr::now),
callback);
}
} }
} }
} }

View file

@ -229,6 +229,17 @@ PeerData *GroupCall::participantPeerByScreenSsrc(uint32 ssrc) const {
: nullptr; : nullptr;
} }
const GroupCallParticipant *GroupCall::participantByPeer(
not_null<PeerData*> peer) const {
return const_cast<GroupCall*>(this)->findParticipant(peer);
}
GroupCallParticipant *GroupCall::findParticipant(
not_null<PeerData*> peer) {
const auto i = ranges::find(_participants, peer, &Participant::peer);
return (i != end(_participants)) ? &*i : nullptr;
}
const GroupCallParticipant *GroupCall::participantByEndpoint( const GroupCallParticipant *GroupCall::participantByEndpoint(
const std::string &endpoint) const { const std::string &endpoint) const {
if (endpoint.empty()) { if (endpoint.empty()) {
@ -683,24 +694,22 @@ void GroupCall::applyLastSpoke(
requestUnknownParticipants(); requestUnknownParticipants();
return; return;
} }
const auto j = ranges::find( const auto participant = findParticipant(i->second);
_participants, Assert(participant != nullptr);
i->second,
&Participant::peer);
Assert(j != end(_participants));
_speakingByActiveFinishes.remove(j->peer); _speakingByActiveFinishes.remove(participant->peer);
const auto sounding = (when.anything + kSoundStatusKeptFor >= now) const auto sounding = (when.anything + kSoundStatusKeptFor >= now)
&& j->canSelfUnmute; && participant->canSelfUnmute;
const auto speaking = sounding const auto speaking = sounding
&& (when.voice + kSoundStatusKeptFor >= now); && (when.voice + kSoundStatusKeptFor >= now);
if (j->sounding != sounding || j->speaking != speaking) { if (participant->sounding != sounding
const auto was = *j; || participant->speaking != speaking) {
j->sounding = sounding; const auto was = *participant;
j->speaking = speaking; participant->sounding = sounding;
participant->speaking = speaking;
_participantUpdates.fire({ _participantUpdates.fire({
.was = was, .was = was,
.now = *j, .now = *participant,
}); });
} }
} }
@ -722,41 +731,37 @@ void GroupCall::applyActiveUpdate(
if (inCall()) { if (inCall()) {
return; return;
} }
const auto i = participantPeerLoaded const auto participant = participantPeerLoaded
? ranges::find( ? findParticipant(participantPeerLoaded)
_participants, : nullptr;
not_null{ participantPeerLoaded }, const auto loadByUserId = !participant || participant->onlyMinLoaded;
&Participant::peer)
: _participants.end();
const auto notFound = (i == end(_participants));
const auto loadByUserId = notFound || i->onlyMinLoaded;
if (loadByUserId) { if (loadByUserId) {
_unknownSpokenPeerIds[participantPeerId] = when; _unknownSpokenPeerIds[participantPeerId] = when;
requestUnknownParticipants(); requestUnknownParticipants();
} }
if (notFound || !i->canSelfUnmute) { if (!participant || !participant->canSelfUnmute) {
return; return;
} }
const auto was = std::make_optional(*i); const auto was = std::make_optional(*participant);
const auto now = crl::now(); const auto now = crl::now();
const auto elapsed = TimeId((now - when.anything) / crl::time(1000)); const auto elapsed = TimeId((now - when.anything) / crl::time(1000));
const auto lastActive = base::unixtime::now() - elapsed; const auto lastActive = base::unixtime::now() - elapsed;
const auto finishes = when.anything + kSpeakingAfterActive; const auto finishes = when.anything + kSpeakingAfterActive;
if (lastActive <= i->lastActive || finishes <= now) { if (lastActive <= participant->lastActive || finishes <= now) {
return; return;
} }
_speakingByActiveFinishes[i->peer] = finishes; _speakingByActiveFinishes[participant->peer] = finishes;
if (!_speakingByActiveFinishTimer.isActive()) { if (!_speakingByActiveFinishTimer.isActive()) {
_speakingByActiveFinishTimer.callOnce(finishes - now); _speakingByActiveFinishTimer.callOnce(finishes - now);
} }
i->lastActive = lastActive; participant->lastActive = lastActive;
i->speaking = true; participant->speaking = true;
i->canSelfUnmute = true; participant->canSelfUnmute = true;
if (!was->speaking || !was->canSelfUnmute) { if (!was->speaking || !was->canSelfUnmute) {
_participantUpdates.fire({ _participantUpdates.fire({
.was = was, .was = was,
.now = *i, .now = *participant,
}); });
} }
} }
@ -779,16 +784,14 @@ void GroupCall::checkFinishSpeakingByActive() {
} }
} }
for (const auto participantPeer : stop) { for (const auto participantPeer : stop) {
const auto i = ranges::find( const auto participant = findParticipant(participantPeer);
_participants, Assert(participant != nullptr);
participantPeer, if (participant->speaking) {
&Participant::peer); const auto was = *participant;
if (i->speaking) { participant->speaking = false;
const auto was = *i;
i->speaking = false;
_participantUpdates.fire({ _participantUpdates.fire({
.was = was, .was = was,
.now = *i, .now = *participant,
}); });
} }
} }

View file

@ -108,6 +108,8 @@ public:
[[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const; [[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const;
[[nodiscard]] PeerData *participantPeerByCameraSsrc(uint32 ssrc) const; [[nodiscard]] PeerData *participantPeerByCameraSsrc(uint32 ssrc) const;
[[nodiscard]] PeerData *participantPeerByScreenSsrc(uint32 ssrc) const; [[nodiscard]] PeerData *participantPeerByScreenSsrc(uint32 ssrc) const;
[[nodiscard]] const Participant *participantByPeer(
not_null<PeerData*> peer) const;
[[nodiscard]] const Participant *participantByEndpoint( [[nodiscard]] const Participant *participantByEndpoint(
const std::string &endpoint) const; const std::string &endpoint) const;
@ -178,6 +180,7 @@ private:
const MTPphone_GroupCall &call) const; const MTPphone_GroupCall &call) const;
[[nodiscard]] bool processSavedFullCall(); [[nodiscard]] bool processSavedFullCall();
void finishParticipantsSliceRequest(); void finishParticipantsSliceRequest();
[[nodiscard]] Participant *findParticipant(not_null<PeerData*> peer);
void emplaceVideoSsrcs(const Participant &participant); void emplaceVideoSsrcs(const Participant &participant);
void eraseVideoSsrcs(const Participant &participant); void eraseVideoSsrcs(const Participant &participant);