mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Resolve video chat participants by unknown ssrcs.
This commit is contained in:
parent
a6f379a17a
commit
ba02a5c46a
4 changed files with 96 additions and 30 deletions
|
@ -80,6 +80,7 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
|
||||||
|
|
||||||
struct VideoParams {
|
struct VideoParams {
|
||||||
tgcalls::GroupParticipantDescription description;
|
tgcalls::GroupParticipantDescription description;
|
||||||
|
base::flat_set<uint32> videoSsrcs;
|
||||||
uint32 hash = 0;
|
uint32 hash = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,7 +149,11 @@ std::shared_ptr<VideoParams> ParseVideoParams(
|
||||||
if (existing && existing->hash == hash) {
|
if (existing && existing->hash == hash) {
|
||||||
return existing;
|
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;
|
data->hash = hash;
|
||||||
|
|
||||||
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
||||||
|
@ -181,7 +186,9 @@ std::shared_ptr<VideoParams> ParseVideoParams(
|
||||||
const auto list = inner.value("sources").toArray();
|
const auto list = inner.value("sources").toArray();
|
||||||
sources.reserve(list.size());
|
sources.reserve(list.size());
|
||||||
for (const auto &source : list) {
|
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({
|
data->description.videoSourceGroups.push_back({
|
||||||
|
@ -209,16 +216,13 @@ std::shared_ptr<VideoParams> ParseVideoParams(
|
||||||
}
|
}
|
||||||
auto parameters = std::vector<std::pair<std::string, std::string>>();
|
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());
|
parameters.reserve(list.size());
|
||||||
for (const auto ¶meter : list) {
|
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||||
const auto inside = parameter.toObject();
|
parameters.push_back({
|
||||||
for (auto i = inside.begin(); i != inside.end(); ++i) {
|
i.key().toStdString(),
|
||||||
parameters.push_back({
|
i.value().toString().toStdString(),
|
||||||
i.key().toStdString(),
|
});
|
||||||
i.value().toString().toStdString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data->description.videoPayloadTypes.push_back({
|
data->description.videoPayloadTypes.push_back({
|
||||||
|
@ -244,6 +248,14 @@ std::shared_ptr<VideoParams> ParseVideoParams(
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const base::flat_set<uint32> &VideoSourcesFromParams(
|
||||||
|
const std::shared_ptr<VideoParams> ¶ms) {
|
||||||
|
static const auto kEmpty = base::flat_set<uint32>();
|
||||||
|
return (params && !params->videoSsrcs.empty())
|
||||||
|
? params->videoSsrcs
|
||||||
|
: kEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
GroupCall::LoadPartTask::LoadPartTask(
|
GroupCall::LoadPartTask::LoadPartTask(
|
||||||
base::weak_ptr<GroupCall> call,
|
base::weak_ptr<GroupCall> call,
|
||||||
int64 time,
|
int64 time,
|
||||||
|
@ -544,13 +556,18 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||||
const auto &now = *update.now;
|
const auto &now = *update.now;
|
||||||
const auto &was = update.was;
|
const auto &was = update.was;
|
||||||
const auto volumeChanged = 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);
|
: (now.volume != Group::kDefaultVolume || now.mutedByMe);
|
||||||
if (now.videoParams) {
|
if (now.videoParams
|
||||||
auto participants = std::vector<tgcalls::GroupParticipantDescription>();
|
&& now.ssrc
|
||||||
participants.push_back(now.videoParams->description);
|
&& (!was
|
||||||
participants.back().audioSsrc = now.ssrc;
|
|| was->videoParams != now.videoParams
|
||||||
_instance->addParticipants(std::move(participants));
|
|| was->ssrc != now.ssrc)
|
||||||
|
&& (now.peer != _joinAs)
|
||||||
|
&& (_instanceMode != InstanceMode::None)) {
|
||||||
|
prepareParticipantForAdding(now);
|
||||||
|
addPreparedParticipantsDelayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (volumeChanged) {
|
if (volumeChanged) {
|
||||||
|
@ -1113,6 +1130,8 @@ void GroupCall::handlePossibleCreateOrJoinResponse(
|
||||||
}
|
}
|
||||||
setInstanceMode(InstanceMode::Rtc);
|
setInstanceMode(InstanceMode::Rtc);
|
||||||
_instance->setJoinResponsePayload(payload, {});
|
_instance->setJoinResponsePayload(payload, {});
|
||||||
|
|
||||||
|
addParticipantsToInstance();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,6 +1162,11 @@ void GroupCall::prepareParticipantForAdding(
|
||||||
auto &added = _preparedParticipants.back();
|
auto &added = _preparedParticipants.back();
|
||||||
added.audioSsrc = participant.ssrc;
|
added.audioSsrc = participant.ssrc;
|
||||||
_unresolvedSsrcs.remove(added.audioSsrc);
|
_unresolvedSsrcs.remove(added.audioSsrc);
|
||||||
|
for (const auto &group : added.videoSourceGroups) {
|
||||||
|
for (const auto ssrc : group.ssrcs) {
|
||||||
|
_unresolvedSsrcs.remove(ssrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::addPreparedParticipants() {
|
void GroupCall::addPreparedParticipants() {
|
||||||
|
@ -1499,7 +1523,10 @@ void GroupCall::requestParticipantsInformation(
|
||||||
|
|
||||||
const auto &existing = real->participants();
|
const auto &existing = real->participants();
|
||||||
for (const auto ssrc : ssrcs) {
|
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) {
|
if (!participantPeer) {
|
||||||
_unresolvedSsrcs.emplace(ssrc);
|
_unresolvedSsrcs.emplace(ssrc);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -79,6 +79,8 @@ struct VideoParams;
|
||||||
[[nodiscard]] std::shared_ptr<VideoParams> ParseVideoParams(
|
[[nodiscard]] std::shared_ptr<VideoParams> ParseVideoParams(
|
||||||
const QByteArray &json,
|
const QByteArray &json,
|
||||||
const std::shared_ptr<VideoParams> &existing);
|
const std::shared_ptr<VideoParams> &existing);
|
||||||
|
[[nodiscard]] const base::flat_set<uint32> &VideoSourcesFromParams(
|
||||||
|
const std::shared_ptr<VideoParams> ¶ms);
|
||||||
|
|
||||||
class GroupCall final : public base::has_weak_ptr {
|
class GroupCall final : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -186,9 +186,18 @@ bool GroupCall::participantsLoaded() const {
|
||||||
return _allParticipantsLoaded;
|
return _allParticipantsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const {
|
PeerData *GroupCall::participantPeerByAudioSsrc(uint32 ssrc) const {
|
||||||
const auto i = _participantPeerBySsrc.find(ssrc);
|
const auto i = _participantPeerByAudioSsrc.find(ssrc);
|
||||||
return (i != end(_participantPeerBySsrc)) ? i->second.get() : nullptr;
|
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() {
|
rpl::producer<> GroupCall::participantsSliceAdded() {
|
||||||
|
@ -295,7 +304,8 @@ void GroupCall::processFullCallFields(const MTPphone_GroupCall &call) {
|
||||||
data.vcall().match([&](const MTPDgroupCall &data) {
|
data.vcall().match([&](const MTPDgroupCall &data) {
|
||||||
_participants.clear();
|
_participants.clear();
|
||||||
_speakingByActiveFinishes.clear();
|
_speakingByActiveFinishes.clear();
|
||||||
_participantPeerBySsrc.clear();
|
_participantPeerByAudioSsrc.clear();
|
||||||
|
_participantPeerByVideoSsrc.clear();
|
||||||
_allParticipantsLoaded = false;
|
_allParticipantsLoaded = false;
|
||||||
|
|
||||||
applyParticipantsSlice(
|
applyParticipantsSlice(
|
||||||
|
@ -488,7 +498,11 @@ void GroupCall::applyParticipantsSlice(
|
||||||
auto update = ParticipantUpdate{
|
auto update = ParticipantUpdate{
|
||||||
.was = *i,
|
.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);
|
_speakingByActiveFinishes.remove(participantPeer);
|
||||||
_participants.erase(i);
|
_participants.erase(i);
|
||||||
if (sliceSource != ApplySliceSource::SliceLoaded) {
|
if (sliceSource != ApplySliceSource::SliceLoaded) {
|
||||||
|
@ -557,18 +571,39 @@ void GroupCall::applyParticipantsSlice(
|
||||||
.onlyMinLoaded = onlyMinLoaded,
|
.onlyMinLoaded = onlyMinLoaded,
|
||||||
};
|
};
|
||||||
if (i == end(_participants)) {
|
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);
|
_participants.push_back(value);
|
||||||
if (const auto user = participantPeer->asUser()) {
|
if (const auto user = participantPeer->asUser()) {
|
||||||
_peer->owner().unregisterInvitedToCallUser(_id, user);
|
_peer->owner().unregisterInvitedToCallUser(_id, user);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i->ssrc != value.ssrc) {
|
if (i->ssrc != value.ssrc) {
|
||||||
_participantPeerBySsrc.erase(i->ssrc);
|
_participantPeerByAudioSsrc.erase(i->ssrc);
|
||||||
_participantPeerBySsrc.emplace(
|
_participantPeerByAudioSsrc.emplace(
|
||||||
value.ssrc,
|
value.ssrc,
|
||||||
participantPeer);
|
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;
|
*i = value;
|
||||||
}
|
}
|
||||||
if (data.is_just_joined()) {
|
if (data.is_just_joined()) {
|
||||||
|
@ -592,8 +627,8 @@ void GroupCall::applyLastSpoke(
|
||||||
uint32 ssrc,
|
uint32 ssrc,
|
||||||
LastSpokeTimes when,
|
LastSpokeTimes when,
|
||||||
crl::time now) {
|
crl::time now) {
|
||||||
const auto i = _participantPeerBySsrc.find(ssrc);
|
const auto i = _participantPeerByAudioSsrc.find(ssrc);
|
||||||
if (i == end(_participantPeerBySsrc)) {
|
if (i == end(_participantPeerByAudioSsrc)) {
|
||||||
_unknownSpokenSsrcs[ssrc] = when;
|
_unknownSpokenSsrcs[ssrc] = when;
|
||||||
requestUnknownParticipants();
|
requestUnknownParticipants();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -102,7 +102,8 @@ public:
|
||||||
-> const std::vector<Participant> &;
|
-> const std::vector<Participant> &;
|
||||||
void requestParticipants();
|
void requestParticipants();
|
||||||
[[nodiscard]] bool participantsLoaded() const;
|
[[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<> participantsSliceAdded();
|
||||||
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
|
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
|
||||||
|
@ -181,7 +182,8 @@ private:
|
||||||
std::optional<MTPphone_GroupCall> _savedFull;
|
std::optional<MTPphone_GroupCall> _savedFull;
|
||||||
|
|
||||||
std::vector<Participant> _participants;
|
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::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
|
||||||
base::Timer _speakingByActiveFinishTimer;
|
base::Timer _speakingByActiveFinishTimer;
|
||||||
QString _nextOffset;
|
QString _nextOffset;
|
||||||
|
|
Loading…
Add table
Reference in a new issue