Resolve video chat participants by unknown ssrcs.

This commit is contained in:
John Preston 2021-04-15 18:21:27 +04:00
parent a6f379a17a
commit ba02a5c46a
4 changed files with 96 additions and 30 deletions

View file

@ -80,6 +80,7 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
struct VideoParams {
tgcalls::GroupParticipantDescription description;
base::flat_set<uint32> videoSsrcs;
uint32 hash = 0;
};
@ -148,7 +149,11 @@ std::shared_ptr<VideoParams> ParseVideoParams(
if (existing && existing->hash == hash) {
return existing;
}
const auto data = existing ? existing : std::make_shared<VideoParams>();
// We don't reuse existing pointer, that way we can compare pointers
// to see if anything was changed in video params.
const auto data = /*existing
? existing
: */std::make_shared<VideoParams>();
data->hash = hash;
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
@ -181,7 +186,9 @@ std::shared_ptr<VideoParams> ParseVideoParams(
const auto list = inner.value("sources").toArray();
sources.reserve(list.size());
for (const auto &source : list) {
sources.push_back(uint32_t(source.toDouble()));
const auto ssrc = uint32_t(source.toDouble());
sources.push_back(ssrc);
data->videoSsrcs.emplace(ssrc);
}
}
data->description.videoSourceGroups.push_back({
@ -209,16 +216,13 @@ std::shared_ptr<VideoParams> ParseVideoParams(
}
auto parameters = std::vector<std::pair<std::string, std::string>>();
{
const auto list = inner.value("parameters").toArray();
const auto list = inner.value("parameters").toObject();
parameters.reserve(list.size());
for (const auto &parameter : list) {
const auto inside = parameter.toObject();
for (auto i = inside.begin(); i != inside.end(); ++i) {
parameters.push_back({
i.key().toStdString(),
i.value().toString().toStdString(),
});
}
for (auto i = list.begin(); i != list.end(); ++i) {
parameters.push_back({
i.key().toStdString(),
i.value().toString().toStdString(),
});
}
}
data->description.videoPayloadTypes.push_back({
@ -244,6 +248,14 @@ std::shared_ptr<VideoParams> ParseVideoParams(
return data;
}
const base::flat_set<uint32> &VideoSourcesFromParams(
const std::shared_ptr<VideoParams> &params) {
static const auto kEmpty = base::flat_set<uint32>();
return (params && !params->videoSsrcs.empty())
? params->videoSsrcs
: kEmpty;
}
GroupCall::LoadPartTask::LoadPartTask(
base::weak_ptr<GroupCall> call,
int64 time,
@ -544,13 +556,18 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
const auto &now = *update.now;
const auto &was = update.was;
const auto volumeChanged = was
? (was->volume != now.volume || was->mutedByMe != now.mutedByMe)
? (was->volume != now.volume
|| was->mutedByMe != now.mutedByMe)
: (now.volume != Group::kDefaultVolume || now.mutedByMe);
if (now.videoParams) {
auto participants = std::vector<tgcalls::GroupParticipantDescription>();
participants.push_back(now.videoParams->description);
participants.back().audioSsrc = now.ssrc;
_instance->addParticipants(std::move(participants));
if (now.videoParams
&& now.ssrc
&& (!was
|| was->videoParams != now.videoParams
|| was->ssrc != now.ssrc)
&& (now.peer != _joinAs)
&& (_instanceMode != InstanceMode::None)) {
prepareParticipantForAdding(now);
addPreparedParticipantsDelayed();
}
if (volumeChanged) {
@ -1113,6 +1130,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse(
}
setInstanceMode(InstanceMode::Rtc);
_instance->setJoinResponsePayload(payload, {});
addParticipantsToInstance();
});
}
@ -1143,6 +1162,11 @@ void GroupCall::prepareParticipantForAdding(
auto &added = _preparedParticipants.back();
added.audioSsrc = participant.ssrc;
_unresolvedSsrcs.remove(added.audioSsrc);
for (const auto &group : added.videoSourceGroups) {
for (const auto ssrc : group.ssrcs) {
_unresolvedSsrcs.remove(ssrc);
}
}
}
void GroupCall::addPreparedParticipants() {
@ -1499,7 +1523,10 @@ void GroupCall::requestParticipantsInformation(
const auto &existing = real->participants();
for (const auto ssrc : ssrcs) {
const auto participantPeer = real->participantPeerBySsrc(ssrc);
const auto byAudio = real->participantPeerByAudioSsrc(ssrc);
const auto participantPeer = byAudio
? byAudio
: real->participantPeerByVideoSsrc(ssrc);
if (!participantPeer) {
_unresolvedSsrcs.emplace(ssrc);
continue;

View file

@ -79,6 +79,8 @@ struct VideoParams;
[[nodiscard]] std::shared_ptr<VideoParams> ParseVideoParams(
const QByteArray &json,
const std::shared_ptr<VideoParams> &existing);
[[nodiscard]] const base::flat_set<uint32> &VideoSourcesFromParams(
const std::shared_ptr<VideoParams> &params);
class GroupCall final : public base::has_weak_ptr {
public:

View file

@ -186,9 +186,18 @@ bool GroupCall::participantsLoaded() const {
return _allParticipantsLoaded;
}
PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const {
const auto i = _participantPeerBySsrc.find(ssrc);
return (i != end(_participantPeerBySsrc)) ? i->second.get() : nullptr;
PeerData *GroupCall::participantPeerByAudioSsrc(uint32 ssrc) const {
const auto i = _participantPeerByAudioSsrc.find(ssrc);
return (i != end(_participantPeerByAudioSsrc))
? i->second.get()
: nullptr;
}
PeerData *GroupCall::participantPeerByVideoSsrc(uint32 ssrc) const {
const auto i = _participantPeerByVideoSsrc.find(ssrc);
return (i != end(_participantPeerByVideoSsrc))
? i->second.get()
: nullptr;
}
rpl::producer<> GroupCall::participantsSliceAdded() {
@ -295,7 +304,8 @@ void GroupCall::processFullCallFields(const MTPphone_GroupCall &call) {
data.vcall().match([&](const MTPDgroupCall &data) {
_participants.clear();
_speakingByActiveFinishes.clear();
_participantPeerBySsrc.clear();
_participantPeerByAudioSsrc.clear();
_participantPeerByVideoSsrc.clear();
_allParticipantsLoaded = false;
applyParticipantsSlice(
@ -488,7 +498,11 @@ void GroupCall::applyParticipantsSlice(
auto update = ParticipantUpdate{
.was = *i,
};
_participantPeerBySsrc.erase(i->ssrc);
_participantPeerByAudioSsrc.erase(i->ssrc);
const auto &all = VideoSourcesFromParams(i->videoParams);
for (const auto ssrc : all) {
_participantPeerByVideoSsrc.erase(ssrc);
}
_speakingByActiveFinishes.remove(participantPeer);
_participants.erase(i);
if (sliceSource != ApplySliceSource::SliceLoaded) {
@ -557,18 +571,39 @@ void GroupCall::applyParticipantsSlice(
.onlyMinLoaded = onlyMinLoaded,
};
if (i == end(_participants)) {
_participantPeerBySsrc.emplace(value.ssrc, participantPeer);
_participantPeerByAudioSsrc.emplace(
value.ssrc,
participantPeer);
const auto &all = VideoSourcesFromParams(value.videoParams);
for (const auto ssrc : all) {
_participantPeerByVideoSsrc.emplace(
ssrc,
participantPeer);
}
_participants.push_back(value);
if (const auto user = participantPeer->asUser()) {
_peer->owner().unregisterInvitedToCallUser(_id, user);
}
} else {
if (i->ssrc != value.ssrc) {
_participantPeerBySsrc.erase(i->ssrc);
_participantPeerBySsrc.emplace(
_participantPeerByAudioSsrc.erase(i->ssrc);
_participantPeerByAudioSsrc.emplace(
value.ssrc,
participantPeer);
}
if (i->videoParams != value.videoParams) {
const auto &old = VideoSourcesFromParams(i->videoParams);
for (const auto ssrc : old) {
_participantPeerByVideoSsrc.erase(ssrc);
}
const auto &now = VideoSourcesFromParams(
value.videoParams);
for (const auto ssrc : now) {
_participantPeerByVideoSsrc.emplace(
ssrc,
participantPeer);
}
}
*i = value;
}
if (data.is_just_joined()) {
@ -592,8 +627,8 @@ void GroupCall::applyLastSpoke(
uint32 ssrc,
LastSpokeTimes when,
crl::time now) {
const auto i = _participantPeerBySsrc.find(ssrc);
if (i == end(_participantPeerBySsrc)) {
const auto i = _participantPeerByAudioSsrc.find(ssrc);
if (i == end(_participantPeerByAudioSsrc)) {
_unknownSpokenSsrcs[ssrc] = when;
requestUnknownParticipants();
return;

View file

@ -102,7 +102,8 @@ public:
-> const std::vector<Participant> &;
void requestParticipants();
[[nodiscard]] bool participantsLoaded() const;
[[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const;
[[nodiscard]] PeerData *participantPeerByAudioSsrc(uint32 ssrc) const;
[[nodiscard]] PeerData *participantPeerByVideoSsrc(uint32 ssrc) const;
[[nodiscard]] rpl::producer<> participantsSliceAdded();
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
@ -181,7 +182,8 @@ private:
std::optional<MTPphone_GroupCall> _savedFull;
std::vector<Participant> _participants;
base::flat_map<uint32, not_null<PeerData*>> _participantPeerBySsrc;
base::flat_map<uint32, not_null<PeerData*>> _participantPeerByAudioSsrc;
base::flat_map<uint32, not_null<PeerData*>> _participantPeerByVideoSsrc;
base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
base::Timer _speakingByActiveFinishTimer;
QString _nextOffset;