Update self as channel in voice chats.

This commit is contained in:
John Preston 2021-03-05 15:36:07 +04:00
parent 02e9b8fd18
commit 4d093f78e2
11 changed files with 118 additions and 67 deletions

View file

@ -1207,7 +1207,7 @@ groupCall#c0c2052e flags:# join_muted:flags.1?true can_change_join_muted:flags.2
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
groupCallParticipant#d27d3adf flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string = GroupCallParticipant;
groupCallParticipant#7c48057b flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:flags.12?int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long = GroupCallParticipant;
phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;
@ -1611,8 +1611,8 @@ phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall durati
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
phone.createGroupCall#1fd59252 flags:# peer:InputPeer join_as:flags.0?InputPeer random_id:int = Updates;
phone.joinGroupCall#2e8166b8 flags:# muted:flags.0?true call:InputGroupCall join_as:flags.1?InputPeer params:DataJSON = Updates;
phone.createGroupCall#7c068f5 peer:InputPeer join_as:InputPeer random_id:int = Updates;
phone.joinGroupCall#3633a5b0 flags:# muted:flags.0?true call:InputGroupCall join_as:InputPeer params:DataJSON = Updates;
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
@ -1621,7 +1621,7 @@ phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall;
phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector<int> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool;
phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates;
phone.editGroupCallParticipant#4713e7a3 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int = Updates;
phone.editGroupCallParticipant#d975eb80 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int raise_hand:flags.2?Bool = Updates;
phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;

View file

@ -705,6 +705,10 @@ void PeerListRow::setCheckedInternal(bool checked, anim::type animated) {
_checkbox->setChecked(checked, animated);
}
void PeerListRow::finishCheckedAnimation() {
_checkbox->setChecked(_checkbox->checked(), anim::type::instant);
}
PeerListContent::PeerListContent(
QWidget *parent,
not_null<PeerListController*> controller)

View file

@ -169,6 +169,7 @@ public:
}
setCheckedInternal(checked, animated);
}
void finishCheckedAnimation();
void invalidatePixmapsCache();
template <typename UpdateCallback>

View file

@ -82,6 +82,7 @@ void ListController::prepare() {
delegate()->peerListAppendRow(std::move(row));
if (peer == _selected) {
delegate()->peerListSetRowChecked(raw, true);
raw->finishCheckedAnimation();
}
}
delegate()->peerListRefreshRows();
@ -136,9 +137,7 @@ void ChooseJoinAsBox(
delegate->setContent(content);
controller->setDelegate(delegate);
box->addButton(tr::lng_continue(), [=] {
const auto selected = controller->selected();
box->closeBox();
done(selected);
done(controller->selected());
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
@ -184,8 +183,12 @@ void ChooseJoinAsProcess::start(
const auto finish = [=](not_null<PeerData*> joinAs) {
const auto peer = _request->peer;
const auto done = std::move(_request->done);
const auto box = _request->box;
_request = nullptr;
done(peer, joinAs);
if (const auto strong = box.data()) {
strong->closeBox();
}
};
using Flag = MTPchannels_GetAdminedPublicChannels::Flag;
_request->id = session->api().request(
@ -217,7 +220,7 @@ void ChooseJoinAsProcess::start(
? not_null(loaded)
: self;
}();
Ui::show(
_request->box = Ui::show(
Box(
ChooseJoinAsBox,
_request->context,
@ -225,6 +228,11 @@ void ChooseJoinAsProcess::start(
selected,
crl::guard(&_request->guard, finish)),
Ui::LayerOption::KeepOther);
_request->box->boxClosing(
) | rpl::start_with_next([=] {
_request = nullptr;
}, _request->lifetime);
}).fail([=](const RPCError &error) {
finish(session->user());
}).send();

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class PeerData;
namespace Ui {
class BoxContent;
} // namespace Ui
namespace Calls {
class ChooseJoinAsProcess final {
@ -34,6 +38,7 @@ private:
not_null<PeerData*> peer;
Fn<void(not_null<PeerData*>, not_null<PeerData*>)> done;
base::has_weak_ptr guard;
QPointer<Ui::BoxContent> box;
rpl::lifetime lifetime;
Context context = Context();
mtpRequestId id = 0;

View file

@ -246,7 +246,6 @@ void GroupCall::playConnectingSoundOnce() {
void GroupCall::start() {
_createRequestId = _api.request(MTPphone_CreateGroupCall(
MTP_flags(MTPphone_CreateGroupCall::Flag::f_join_as),
_peer->input,
_joinAs->input,
MTP_int(openssl::RandomValue<int32>())
@ -321,7 +320,7 @@ void GroupCall::rejoin() {
_mySsrc = 0;
setState(State::Joining);
createAndStartController();
applySelfInCallLocally();
applyMeInCallLocally();
LOG(("Call Info: Requesting join payload."));
const auto weak = base::make_weak(this);
@ -353,10 +352,9 @@ void GroupCall::rejoin() {
const auto wasMuteState = muted();
using Flag = MTPphone_JoinGroupCall::Flag;
_api.request(MTPphone_JoinGroupCall(
MTP_flags(Flag::f_join_as
| (wasMuteState != MuteState::Active
? Flag::f_muted
: Flag(0))),
MTP_flags((wasMuteState != MuteState::Active)
? Flag::f_muted
: Flag(0)),
inputCall(),
_joinAs->input,
MTP_dataJSON(MTP_bytes(json))
@ -365,7 +363,7 @@ void GroupCall::rejoin() {
setState(_instanceConnected
? State::Joined
: State::Connecting);
applySelfInCallLocally();
applyMeInCallLocally();
maybeSendMutedUpdate(wasMuteState);
_peer->session().api().applyUpdates(updates);
}).fail([=](const RPCError &error) {
@ -392,17 +390,16 @@ void GroupCall::rejoin() {
});
}
void GroupCall::applySelfInCallLocally() {
void GroupCall::applyMeInCallLocally() {
const auto call = _peer->groupCall();
if (!call || call->id() != _id) {
return;
}
using Flag = MTPDgroupCallParticipant::Flag;
const auto &participants = call->participants();
const auto self = _peer->session().user();
const auto i = ranges::find(
participants,
self,
_joinAs,
&Data::GroupCall::Participant::peer);
const auto date = (i != end(participants))
? i->date
@ -428,12 +425,13 @@ void GroupCall::applySelfInCallLocally() {
1,
MTP_groupCallParticipant(
MTP_flags(flags),
peerToMTP(self->id), // #TODO calls channel or self
peerToMTP(_joinAs->id),
MTP_int(date),
MTP_int(lastActive),
MTP_int(_mySsrc),
MTP_int(volume),
MTPstring())), // #TODO calls about
MTPstring(), // #TODO calls about
MTPlong())), // #TODO calls raise hand rating
MTP_int(0)).c_updateGroupCallParticipants());
}
@ -460,7 +458,8 @@ void GroupCall::applyParticipantLocally(
: Flag(0))
| (participant->lastActive ? Flag::f_active_date : Flag(0))
| (isMuted ? Flag::f_muted : Flag(0))
| (isMutedByYou ? Flag::f_muted_by_you : Flag(0)); // #TODO calls self?
| (isMutedByYou ? Flag::f_muted_by_you : Flag(0))
| (participantPeer == _joinAs ? Flag::f_self : Flag(0));
_peer->groupCall()->applyUpdateChecked(
MTP_updateGroupCallParticipants(
inputCall(),
@ -473,7 +472,8 @@ void GroupCall::applyParticipantLocally(
MTP_int(participant->lastActive),
MTP_int(participant->ssrc),
MTP_int(volume.value_or(participant->volume)),
MTPstring())), // #TODO calls about
MTPstring(), // #TODO calls about
MTPlong())), // #TODO calls raise hand rating
MTP_int(0)).c_updateGroupCallParticipants());
}
@ -547,7 +547,7 @@ void GroupCall::setMuted(MuteState mute) {
const auto nowMuted = (muted() == MuteState::Muted)
|| (muted() == MuteState::PushToTalk);
if (wasMuted != nowMuted) {
applySelfInCallLocally();
applyMeInCallLocally();
}
};
if (mute == MuteState::Active || mute == MuteState::PushToTalk) {
@ -667,15 +667,15 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
handleOtherParticipants(data);
return;
}
if (data.is_left() && data.vsource().v == _mySsrc) {
if (data.is_left() && data.vsource().value_or_empty() == _mySsrc) {
// I was removed from the call, rejoin.
LOG(("Call Info: Rejoin after got 'left' with my ssrc."));
setState(State::Joining);
rejoin();
} else if (!data.is_left() && data.vsource().v != _mySsrc) {
} else if (!data.is_left() && data.vsource().value_or_empty() != _mySsrc) {
// I joined from another device, hangup.
LOG(("Call Info: Hangup after '!left' with ssrc %1, my %2."
).arg(data.vsource().v
).arg(data.vsource().value_or_empty()
).arg(_mySsrc));
_mySsrc = 0;
hangup();
@ -785,17 +785,17 @@ void GroupCall::audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data) {
const auto ssrc = ssrcOrZero ? ssrcOrZero : _mySsrc;
const auto level = value.level;
const auto voice = value.voice;
const auto self = (ssrc == _mySsrc);
const auto me = (ssrc == _mySsrc);
_levelUpdates.fire(LevelUpdate{
.ssrc = ssrc,
.value = level,
.voice = voice,
.self = self
.me = me
});
if (level <= kSpeakLevelThreshold) {
continue;
}
if (self
if (me
&& voice
&& (!_lastSendProgressUpdate
|| _lastSendProgressUpdate + kUpdateSendActionEach < now)) {
@ -912,8 +912,9 @@ void GroupCall::sendMutedUpdate() {
_updateMuteRequestId = _api.request(MTPphone_EditGroupCallParticipant(
MTP_flags((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)),
inputCall(),
MTP_inputPeerSelf(),
MTP_int(100000) // volume
_joinAs->input,
MTP_int(100000), // volume
MTPBool() // #TODO calls raise_hand
)).done([=](const MTPUpdates &result) {
_updateMuteRequestId = 0;
_peer->session().api().applyUpdates(result);
@ -977,7 +978,8 @@ void GroupCall::editParticipant(
MTP_flags(flags),
inputCall(),
participantPeer->input,
MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume))
MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume)),
MTPBool() // #TODO calls raise_hand
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
}).fail([=](const RPCError &error) {

View file

@ -62,7 +62,7 @@ struct LevelUpdate {
uint32 ssrc = 0;
float value = 0.;
bool voice = false;
bool self = false;
bool me = false;
};
class GroupCall final : public base::has_weak_ptr {
@ -99,6 +99,9 @@ public:
[[nodiscard]] not_null<PeerData*> peer() const {
return _peer;
}
[[nodiscard]] not_null<PeerData*> joinAs() const {
return _joinAs;
}
void start();
void hangup();
@ -179,7 +182,7 @@ private:
void sendMutedUpdate();
void updateInstanceMuteState();
void updateInstanceVolumes();
void applySelfInCallLocally();
void applyMeInCallLocally();
void rejoin();
void audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data);

View file

@ -78,6 +78,7 @@ class Row;
class RowDelegate {
public:
virtual bool rowIsMe(not_null<PeerData*> participantPeer) = 0;
virtual bool rowCanMuteMembers() = 0;
virtual void rowUpdateRow(not_null<Row*> row) = 0;
virtual void rowPaintIcon(
@ -135,7 +136,7 @@ public:
st::groupCallActiveButton.height);
}
bool actionDisabled() const override {
return peer()->isSelf()
return _delegate->rowIsMe(peer())
|| (_state == State::Invited)
|| !_delegate->rowCanMuteMembers();
}
@ -271,6 +272,7 @@ public:
[[nodiscard]] auto kickParticipantRequests() const
-> rpl::producer<not_null<PeerData*>>;
bool rowIsMe(not_null<PeerData*> participantPeer) override;
bool rowCanMuteMembers() override;
void rowUpdateRow(not_null<Row*> row) override;
void rowPaintIcon(
@ -282,12 +284,13 @@ public:
bool mutedByMe) override;
private:
[[nodiscard]] std::unique_ptr<Row> createSelfRow();
[[nodiscard]] std::unique_ptr<Row> createRowForMe();
[[nodiscard]] std::unique_ptr<Row> createRow(
const Data::GroupCall::Participant &participant);
[[nodiscard]] std::unique_ptr<Row> createInvitedRow(
not_null<PeerData*> participantPeer);
[[nodiscard]] bool isMe(not_null<PeerData*> participantPeer) const;
void prepareRows(not_null<Data::GroupCall*> real);
//void repaintByTimer();
@ -690,7 +693,7 @@ void Row::paintStatusText(
outerWidth,
(_state == State::MutedByMe
? tr::lng_group_call_muted_by_me_status(tr::now)
: peer()->isSelf()
: _delegate->rowIsMe(peer())
? tr::lng_status_connecting(tr::now)
: tr::lng_group_call_invited_status(tr::now)));
}
@ -882,9 +885,12 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
if (!update.now) {
if (const auto row = findRow(participantPeer)) {
const auto owner = &participantPeer->owner();
if (participantPeer->isSelf()) {
if (isMe(participantPeer)) {
updateRow(row, nullptr);
} else {
if (const auto min = _fullCountMin.current()) {
_fullCountMin = min - 1;
}
removeRow(row);
delegate()->peerListRefreshRows();
}
@ -1008,6 +1014,7 @@ void MembersController::updateRow(
const Data::GroupCall::Participant *participant) {
const auto wasSounding = row->sounding();
const auto wasSsrc = row->ssrc();
const auto wasInChat = (row->state() != Row::State::Invited);
row->setSkipLevelUpdate(_skipRowLevelUpdate);
row->updateState(participant);
const auto nowSounding = row->sounding();
@ -1036,6 +1043,11 @@ void MembersController::updateRow(
_soundingAnimation.stop();
}
if (!participant && wasInChat) {
if (const auto min = _fullCountMin.current()) {
_fullCountMin = min - 1;
}
}
delegate()->peerListUpdateRow(row);
}
@ -1080,7 +1092,7 @@ void MembersController::prepare() {
if (const auto real = _peer->groupCall()
; real && call && real->id() == call->id()) {
prepareRows(real);
} else if (auto row = createSelfRow()) {
} else if (auto row = createRowForMe()) {
_fullCountMin = (row->state() == Row::State::Invited) ? 0 : 1;
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
@ -1093,8 +1105,13 @@ void MembersController::prepare() {
_prepared = true;
}
bool MembersController::isMe(not_null<PeerData*> participantPeer) const {
const auto call = _call.get();
return call && (call->joinAs() == participantPeer);
}
void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
auto foundSelf = false;
auto foundMe = false;
auto changed = false;
const auto &participants = real->participants();
auto fullCountMin = 0;
@ -1102,8 +1119,8 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
for (auto i = 0; i != count;) {
auto row = delegate()->peerListRowAt(i);
auto participantPeer = row->peer();
if (participantPeer->isSelf()) { // #TODO calls add self even if channel
foundSelf = true;
if (isMe(participantPeer)) {
foundMe = true;
++i;
continue;
}
@ -1120,19 +1137,23 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
--count;
}
}
if (!foundSelf) {
const auto self = _peer->session().user();
const auto i = ranges::find(
participants,
self,
&Data::GroupCall::Participant::peer);
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
if (row) {
if (row->state() != Row::State::Invited) {
++fullCountMin;
if (!foundMe) {
if (const auto call = _call.get()) {
const auto me = call->joinAs();
const auto i = ranges::find(
participants,
me,
&Data::GroupCall::Participant::peer);
auto row = (i != end(participants))
? createRow(*i)
: createRowForMe();
if (row) {
if (row->state() != Row::State::Invited) {
++fullCountMin;
}
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
}
for (const auto &participant : participants) {
@ -1170,6 +1191,10 @@ auto MembersController::changeVolumeRequests() const
return _changeVolumeRequests.events();
}
bool MembersController::rowIsMe(not_null<PeerData*> participantPeer) {
return isMe(participantPeer);
}
bool MembersController::rowCanMuteMembers() {
return _peer->canManageGroupCall();
}
@ -1279,7 +1304,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
not_null<PeerListRow*> row) {
const auto participantPeer = row->peer();
const auto real = static_cast<Row*>(row.get());
if (participantPeer->isSelf()
if (isMe(participantPeer)
&& (!_peer->canManageGroupCall() || !real->ssrc())) {
return nullptr;
}
@ -1342,7 +1367,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
addMuteActionsToContextMenu(result, participantPeer, admin, real);
}
if (!participantPeer->isSelf()) { // #TODO calls correct check self
if (!isMe(participantPeer)) {
result->addAction(
tr::lng_context_view_profile(tr::now),
showProfile);
@ -1418,8 +1443,8 @@ void MembersController::addMuteActionsToContextMenu(
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
if (!isMuted || participantPeer->isSelf()) {
const auto call = _call.get();
const auto call = _call.get();
if (!isMuted || (call && call->joinAs() == participantPeer)) {
auto otherParticipantStateValue = call
? call->otherParticipantStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) {
@ -1451,7 +1476,7 @@ void MembersController::addMuteActionsToContextMenu(
volumeItem->toggleMuteLocallyRequests(
) | rpl::start_with_next([=](bool muted) {
if (!participantPeer->isSelf()) { // #TODO calls check self
if (!isMe(participantPeer)) {
toggleMute(muted, true);
}
}, volumeItem->lifetime());
@ -1463,7 +1488,7 @@ void MembersController::addMuteActionsToContextMenu(
volumeItem->changeVolumeLocallyRequests(
) | rpl::start_with_next([=](int volume) {
if (!participantPeer->isSelf()) { // #TODO calls check self
if (!isMe(participantPeer)) {
changeVolume(volume, true);
}
}, volumeItem->lifetime());
@ -1473,7 +1498,7 @@ void MembersController::addMuteActionsToContextMenu(
const auto muteAction = [&]() -> QAction* {
if (muteState == Row::State::Invited
|| participantPeer->isSelf() // #TODO calls check self
|| isMe(participantPeer)
|| (muteState == Row::State::Muted
&& participantIsCallAdmin
&& _peer->canManageGroupCall())) {
@ -1499,9 +1524,12 @@ void MembersController::addMuteActionsToContextMenu(
}
}
std::unique_ptr<Row> MembersController::createSelfRow() {
const auto self = _peer->session().user(); // #TODO calls check self
auto result = std::make_unique<Row>(this, self);
std::unique_ptr<Row> MembersController::createRowForMe() {
const auto call = _call.get();
if (!call) {
return nullptr;
}
auto result = std::make_unique<Row>(this, call->joinAs());
updateRow(result.get(), nullptr);
return result;
}

View file

@ -501,7 +501,7 @@ void GroupPanel::initWithCall(GroupCall *call) {
call->levelUpdates(
) | rpl::filter([=](const LevelUpdate &update) {
return update.self;
return update.me;
}) | rpl::start_with_next([=](const LevelUpdate &update) {
_mute->setLevel(update.value);
}, _callLifetime);

View file

@ -296,7 +296,7 @@ void GroupCall::applyParticipantsSlice(
.peer = participantPeer,
.date = data.vdate().v,
.lastActive = lastActive,
.ssrc = uint32(data.vsource().v),
.ssrc = uint32(data.vsource().value_or_empty()),
.volume = volume,
.applyVolumeFromMin = applyVolumeFromMin,
.speaking = canSelfUnmute && (was ? was->speaking : false),

View file

@ -56,7 +56,6 @@ public:
-> const std::vector<Participant> &;
void requestParticipants();
[[nodiscard]] bool participantsLoaded() const;
[[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const;
[[nodiscard]] rpl::producer<> participantsSliceAdded();
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
@ -97,6 +96,7 @@ private:
void requestUnknownParticipants();
void changePeerEmptyCallFlag();
void checkFinishSpeakingByActive();
[[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const;
const uint64 _id = 0;
const uint64 _accessHash = 0;