Track peer together with video endpoint.

This commit is contained in:
John Preston 2021-05-07 11:20:31 +04:00
parent 909a3cef9b
commit 8001efe6ab
3 changed files with 143 additions and 84 deletions

View file

@ -563,7 +563,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
: endpoint;
};
const auto guard = gsl::finally([&] {
if (newLarge.empty()) {
if (!newLarge) {
newLarge = chooseLargeVideoEndpoint();
}
if (_videoEndpointLarge.current() != newLarge) {
@ -577,6 +577,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
}
});
const auto peer = data.was ? data.was->peer : data.now->peer;
const auto &wasCameraEndpoint = (data.was && data.was->videoParams)
? regularEndpoint(data.was->videoParams->camera.endpoint)
: EmptyString();
@ -595,8 +596,9 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
&& _activeVideoEndpoints.remove(wasCameraEndpoint)
&& _incomingVideoEndpoints.contains(wasCameraEndpoint)) {
updateCameraNotStreams = wasCameraEndpoint;
if (newLarge == wasCameraEndpoint) {
_videoEndpointPinned = newLarge = std::string();
if (newLarge.endpoint == wasCameraEndpoint) {
newLarge = VideoEndpoint();
_videoEndpointPinned = false;
}
}
}
@ -618,8 +620,9 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
&& _activeVideoEndpoints.remove(wasScreenEndpoint)
&& _incomingVideoEndpoints.contains(wasScreenEndpoint)) {
updateScreenNotStreams = wasScreenEndpoint;
if (newLarge == wasScreenEndpoint) {
_videoEndpointPinned = newLarge = std::string();
if (newLarge.endpoint == wasScreenEndpoint) {
newLarge = VideoEndpoint();
_videoEndpointPinned = false;
}
}
}
@ -629,62 +632,67 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
const auto wasSounding = data.was && data.was->sounding;
if (nowSpeaking == wasSpeaking && nowSounding == wasSounding) {
return;
} else if (!_videoEndpointPinned.current().empty()) {
} else if (_videoEndpointPinned.current()) {
return;
}
if (nowScreenEndpoint != newLarge
if (nowScreenEndpoint != newLarge.endpoint
&& streamsVideo(nowScreenEndpoint)
&& activeVideoEndpointType(newLarge) != EndpointType::Screen) {
newLarge = nowScreenEndpoint;
&& (activeVideoEndpointType(newLarge.endpoint)
!= EndpointType::Screen)) {
newLarge = { peer, nowScreenEndpoint };
}
const auto &participants = real->participants();
if (!nowSpeaking
&& (wasSpeaking || wasSounding)
&& (wasCameraEndpoint == newLarge)) {
auto screenEndpoint = std::string();
auto speakingEndpoint = std::string();
auto soundingEndpoint = std::string();
&& (wasCameraEndpoint == newLarge.endpoint)) {
auto screenEndpoint = VideoEndpoint();
auto speakingEndpoint = VideoEndpoint();
auto soundingEndpoint = VideoEndpoint();
for (const auto &participant : participants) {
const auto params = participant.videoParams.get();
if (!params) {
continue;
}
const auto peer = participant.peer;
if (streamsVideo(params->screen.endpoint)) {
screenEndpoint = params->screen.endpoint;
screenEndpoint = { peer, params->screen.endpoint };
break;
} else if (participant.speaking
&& speakingEndpoint.empty()) {
&& !speakingEndpoint) {
if (streamsVideo(params->camera.endpoint)) {
speakingEndpoint = params->camera.endpoint;
speakingEndpoint = { peer, params->camera.endpoint };
}
} else if (!nowSounding
&& participant.sounding
&& soundingEndpoint.empty()) {
&& !soundingEndpoint) {
if (streamsVideo(params->camera.endpoint)) {
soundingEndpoint = params->camera.endpoint;
soundingEndpoint = { peer, params->camera.endpoint };
}
}
}
if (!screenEndpoint.empty()) {
if (screenEndpoint) {
newLarge = screenEndpoint;
} else if (!speakingEndpoint.empty()) {
} else if (speakingEndpoint) {
newLarge = speakingEndpoint;
} else if (!soundingEndpoint.empty()) {
} else if (soundingEndpoint) {
newLarge = soundingEndpoint;
}
} else if ((nowSpeaking || nowSounding)
&& (nowCameraEndpoint != newLarge)
&& (activeVideoEndpointType(newLarge) != EndpointType::Screen)
&& (nowCameraEndpoint != newLarge.endpoint)
&& (activeVideoEndpointType(newLarge.endpoint)
!= EndpointType::Screen)
&& streamsVideo(nowCameraEndpoint)) {
const auto participant = real->participantByEndpoint(newLarge);
const auto participant = real->participantByEndpoint(
newLarge.endpoint);
const auto screen = participant
&& (participant->videoParams->screen.endpoint == newLarge);
&& (participant->videoParams->screen.endpoint
== newLarge.endpoint);
const auto speaking = participant && participant->speaking;
const auto sounding = participant && participant->sounding;
if (!screen
&& ((nowSpeaking && !speaking)
|| (nowSounding && !sounding))) {
newLarge = nowCameraEndpoint;
newLarge = { peer, nowCameraEndpoint };
}
}
}, _lifetime);
@ -878,8 +886,8 @@ void GroupCall::setMyEndpointType(
const auto was2 = _activeVideoEndpoints.remove(endpoint);
if (was1 && was2) {
auto newLarge = _videoEndpointLarge.current();
if (newLarge == endpoint) {
_videoEndpointPinned = std::string();
if (newLarge.endpoint == endpoint) {
_videoEndpointPinned = false;
_videoEndpointLarge = chooseLargeVideoEndpoint();
}
_streamsVideoUpdated.fire({ endpoint, false });
@ -893,13 +901,13 @@ void GroupCall::setMyEndpointType(
_streamsVideoUpdated.fire({ endpoint, true });
}
const auto nowLarge = activeVideoEndpointType(
_videoEndpointLarge.current());
if (_videoEndpointPinned.current().empty()
_videoEndpointLarge.current().endpoint);
if (!_videoEndpointPinned.current()
&& ((type == EndpointType::Screen
&& nowLarge != EndpointType::Screen)
|| (type == EndpointType::Camera
&& nowLarge == EndpointType::None))) {
_videoEndpointLarge = endpoint;
_videoEndpointLarge = VideoEndpoint{ _joinAs, endpoint };
}
}
}
@ -1837,8 +1845,8 @@ void GroupCall::ensureControllerCreated() {
std::move(descriptor));
_videoEndpointLarge.changes(
) | rpl::start_with_next([=](const std::string &endpoint) {
_instance->setFullSizeVideoEndpointId(endpoint);
) | rpl::start_with_next([=](const VideoEndpoint &endpoint) {
_instance->setFullSizeVideoEndpointId(endpoint.endpoint);
_videoLargeTrack = nullptr;
_videoLargeTrackWrap = nullptr;
if (endpoint.empty()) {
@ -1850,7 +1858,7 @@ void GroupCall::ensureControllerCreated() {
}
_videoLargeTrackWrap->sink = Webrtc::CreateProxySink(
_videoLargeTrackWrap->track.sink());
addVideoOutput(endpoint, { _videoLargeTrackWrap->sink });
addVideoOutput(endpoint.endpoint, { _videoLargeTrackWrap->sink });
}, _lifetime);
updateInstanceMuteState();
@ -2063,7 +2071,7 @@ void GroupCall::setIncomingVideoEndpoints(
const auto feedOne = [&](const std::string &endpoint) {
if (endpoint.empty()) {
return;
} else if (endpoint == newLarge) {
} else if (endpoint == newLarge.endpoint) {
newLargeFound = true;
}
if (!removed.remove(endpoint)) {
@ -2080,8 +2088,9 @@ void GroupCall::setIncomingVideoEndpoints(
}
feedOne(cameraSharingEndpoint());
feedOne(screenSharingEndpoint());
if (!newLarge.empty() && !newLargeFound) {
_videoEndpointPinned = newLarge = std::string();
if (newLarge && !newLargeFound) {
_videoEndpointPinned = false;
newLarge = VideoEndpoint();
}
if (newLarge.empty()) {
_videoEndpointLarge = chooseLargeVideoEndpoint();
@ -2106,7 +2115,7 @@ void GroupCall::fillActiveVideoEndpoints() {
EndpointType type) {
if (endpoint.empty()) {
return;
} else if (endpoint == newLarge) {
} else if (endpoint == newLarge.endpoint) {
newLargeFound = true;
}
if (!removed.remove(endpoint)) {
@ -2129,9 +2138,10 @@ void GroupCall::fillActiveVideoEndpoints() {
feedOne(cameraSharingEndpoint(), EndpointType::Camera);
feedOne(screenSharingEndpoint(), EndpointType::Screen);
if (!newLarge.empty() && !newLargeFound) {
_videoEndpointPinned = newLarge = std::string();
_videoEndpointPinned = false;
newLarge = VideoEndpoint();
}
if (newLarge.empty()) {
if (!newLarge) {
_videoEndpointLarge = chooseLargeVideoEndpoint();
}
for (const auto &[endpoint, type] : removed) {
@ -2152,15 +2162,15 @@ GroupCall::EndpointType GroupCall::activeVideoEndpointType(
: EndpointType::None;
}
std::string GroupCall::chooseLargeVideoEndpoint() const {
VideoEndpoint GroupCall::chooseLargeVideoEndpoint() const {
const auto real = lookupReal();
if (!real) {
return std::string();
return VideoEndpoint();
}
auto anyEndpoint = std::string();
auto screenEndpoint = std::string();
auto speakingEndpoint = std::string();
auto soundingEndpoint = std::string();
auto anyEndpoint = VideoEndpoint();
auto screenEndpoint = VideoEndpoint();
auto speakingEndpoint = VideoEndpoint();
auto soundingEndpoint = VideoEndpoint();
const auto &myCameraEndpoint = cameraSharingEndpoint();
const auto &myScreenEndpoint = screenSharingEndpoint();
const auto &participants = real->participants();
@ -2171,35 +2181,36 @@ std::string GroupCall::chooseLargeVideoEndpoint() const {
continue;
}
if (const auto participant = real->participantByEndpoint(endpoint)) {
const auto peer = participant->peer;
if (screenEndpoint.empty()
&& participant->videoParams->screen.endpoint == endpoint) {
screenEndpoint = endpoint;
screenEndpoint = { peer, endpoint };
break;
}
if (speakingEndpoint.empty() && participant->speaking) {
speakingEndpoint = endpoint;
speakingEndpoint = { peer, endpoint };
}
if (soundingEndpoint.empty() && participant->sounding) {
soundingEndpoint = endpoint;
soundingEndpoint = { peer, endpoint };
}
if (anyEndpoint.empty()) {
anyEndpoint = endpoint;
anyEndpoint = { peer, endpoint };
}
}
}
return !screenEndpoint.empty()
return screenEndpoint
? screenEndpoint
: streamsVideo(myScreenEndpoint)
? myScreenEndpoint
: !speakingEndpoint.empty()
? VideoEndpoint{ _joinAs, myScreenEndpoint }
: speakingEndpoint
? speakingEndpoint
: !soundingEndpoint.empty()
: soundingEndpoint
? soundingEndpoint
: !anyEndpoint.empty()
: anyEndpoint
? anyEndpoint
: streamsVideo(myCameraEndpoint)
? myCameraEndpoint
: std::string();
? VideoEndpoint{ _joinAs, myCameraEndpoint }
: VideoEndpoint();
}
void GroupCall::updateInstanceMuteState() {
@ -2491,13 +2502,13 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
}).send();
}
void GroupCall::pinVideoEndpoint(const std::string &endpoint) {
if (endpoint.empty()) {
_videoEndpointPinned = endpoint;
} else if (streamsVideo(endpoint)) {
_videoEndpointPinned = std::string();
void GroupCall::pinVideoEndpoint(const VideoEndpoint &endpoint) {
if (!endpoint) {
_videoEndpointPinned = false;
} else if (streamsVideo(endpoint.endpoint)) {
_videoEndpointPinned = false;
_videoEndpointLarge = endpoint;
_videoEndpointPinned = endpoint;
_videoEndpointPinned = true;
}
}

View file

@ -74,6 +74,55 @@ struct LevelUpdate {
bool me = false;
};
struct VideoEndpoint {
PeerData *peer = nullptr;
std::string endpoint;
[[nodiscard]] bool empty() const noexcept {
return !peer;
}
[[nodiscard]] explicit operator bool() const noexcept {
return !empty();
}
};
inline bool operator==(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return (a.peer == b.peer) && (a.endpoint == b.endpoint);
}
inline bool operator!=(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return !(a == b);
}
inline bool operator<(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return (a.peer < b.peer)
|| (a.peer == b.peer && a.endpoint < b.endpoint);
}
inline bool operator>(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return (b < a);
}
inline bool operator<=(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return !(b < a);
}
inline bool operator>=(
const VideoEndpoint &a,
const VideoEndpoint &b) noexcept {
return !(a < b);
}
struct StreamsVideoUpdate {
std::string endpoint;
bool streams = false;
@ -234,18 +283,18 @@ public:
&& _incomingVideoEndpoints.contains(endpoint)
&& activeVideoEndpointType(endpoint) != EndpointType::None;
}
[[nodiscard]] const std::string &videoEndpointPinned() const {
[[nodiscard]] bool videoEndpointPinned() const {
return _videoEndpointPinned.current();
}
[[nodiscard]] rpl::producer<std::string> videoEndpointPinnedValue() const {
[[nodiscard]] rpl::producer<bool> videoEndpointPinnedValue() const {
return _videoEndpointPinned.value();
}
void pinVideoEndpoint(const std::string &endpoint);
[[nodiscard]] const std::string &videoEndpointLarge() const {
void pinVideoEndpoint(const VideoEndpoint &endpoint);
[[nodiscard]] const VideoEndpoint &videoEndpointLarge() const {
return _videoEndpointLarge.current();
}
[[nodiscard]] auto videoEndpointLargeValue() const
-> rpl::producer<std::string> {
-> rpl::producer<VideoEndpoint> {
return _videoEndpointLarge.value();
}
[[nodiscard]] Webrtc::VideoTrack *videoLargeTrack() const {
@ -386,7 +435,7 @@ private:
void setIncomingVideoEndpoints(
const std::vector<std::string> &endpoints);
void fillActiveVideoEndpoints();
[[nodiscard]] std::string chooseLargeVideoEndpoint() const;
[[nodiscard]] VideoEndpoint chooseLargeVideoEndpoint() const;
[[nodiscard]] EndpointType activeVideoEndpointType(
const std::string &endpoint) const;
@ -473,8 +522,8 @@ private:
rpl::event_stream<StreamsVideoUpdate> _streamsVideoUpdated;
base::flat_set<std::string> _incomingVideoEndpoints;
base::flat_map<std::string, EndpointType> _activeVideoEndpoints;
rpl::variable<std::string> _videoEndpointLarge;
rpl::variable<std::string> _videoEndpointPinned;
rpl::variable<VideoEndpoint> _videoEndpointLarge;
rpl::variable<bool> _videoEndpointPinned;
std::unique_ptr<LargeTrack> _videoLargeTrackWrap;
rpl::variable<Webrtc::VideoTrack*> _videoLargeTrack;
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;

View file

@ -1228,9 +1228,9 @@ void MembersController::setupListChangeViewers() {
}, _lifetime);
_call->videoEndpointLargeValue(
) | rpl::filter([=](const std::string &largeEndpoint) {
return (_largeEndpoint != largeEndpoint);
}) | rpl::start_with_next([=](const std::string &largeEndpoint) {
) | rpl::filter([=](const VideoEndpoint &largeEndpoint) {
return (_largeEndpoint != largeEndpoint.endpoint);
}) | rpl::start_with_next([=](const VideoEndpoint &largeEndpoint) {
if (_call->streamsVideo(_largeEndpoint)) {
if (const auto participant = findParticipant(_largeEndpoint)) {
if (const auto row = findRow(participant->peer)) {
@ -1243,7 +1243,7 @@ void MembersController::setupListChangeViewers() {
}
}
}
_largeEndpoint = largeEndpoint;
_largeEndpoint = largeEndpoint.endpoint;
if (const auto participant = findParticipant(_largeEndpoint)) {
if (const auto row = findRow(participant->peer)) {
if (row->videoTrackEndpoint() == _largeEndpoint) {
@ -2013,12 +2013,14 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
});
if (const auto real = _call->lookupReal()) {
const auto pinnedEndpoint = _call->videoEndpointPinned();
const auto pinnedEndpoint = _call->videoEndpointPinned()
? _call->videoEndpointLarge().endpoint
: std::string();
const auto participant = real->participantByEndpoint(pinnedEndpoint);
if (participant && participant->peer == participantPeer) {
result->addAction(
tr::lng_group_call_context_unpin_camera(tr::now),
[=] { _call->pinVideoEndpoint(std::string()); });
[=] { _call->pinVideoEndpoint(VideoEndpoint()); });
} else {
const auto &participants = real->participants();
const auto i = ranges::find(
@ -2031,9 +2033,9 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
const auto streamsScreen = _call->streamsVideo(screen);
if (streamsScreen || _call->streamsVideo(camera)) {
const auto callback = [=] {
_call->pinVideoEndpoint(streamsScreen
? screen
: camera);
_call->pinVideoEndpoint(VideoEndpoint{
participantPeer,
streamsScreen ? screen : camera });
};
result->addAction(
tr::lng_group_call_context_pin_camera(tr::now),
@ -2438,10 +2440,7 @@ void Members::setupPinnedVideo() {
_mode.changes() | rpl::filter(
_1 == PanelMode::Default
) | rpl::to_empty,
_call->videoEndpointLargeValue(
) | rpl::filter([=](const std::string &endpoint) {
return endpoint == _call->videoEndpointPinned();
}) | rpl::to_empty
_call->videoEndpointPinnedValue() | rpl::filter(_1) | rpl::to_empty
) | rpl::start_with_next([=] {
_scroll->scrollToY(0);
}, _scroll->lifetime());