Improve sending speaking in voice chat typings.

This commit is contained in:
levlam 2020-12-04 17:06:37 +03:00
parent fc2215633b
commit 23f1927c07
9 changed files with 110 additions and 21 deletions

View File

@ -4344,6 +4344,10 @@ toggleGroupCallMuteNewMembers group_call_id:int32 mute_new_members:Bool = Ok;
//@group_call_id Group call identifier @user_ids User identifiers
inviteGroupCallMembers group_call_id:int32 user_ids:vector<int32> = Ok;
//@description Informs TDLib that a group call member speaking state has changed @group_call_id Group call identifier
//@source Group call member's synchronization source identifier @is_speaking True, if the user is speaking
setGroupCallMemberIsSpeaking group_call_id:int32 source:int32 is_speaking:Bool = Ok;
//@description Toggles whether a group call member is muted. Requires can_manage_calls rights to mute other group call members
//@group_call_id Group call identifier @user_id User identifier @is_muted Pass true if the user must be muted and false otherwise
toggleGroupCallMemberIsMuted group_call_id:int32 user_id:int32 is_muted:Bool = Ok;

Binary file not shown.

View File

@ -81,7 +81,7 @@ DialogAction::DialogAction(tl_object_ptr<td_api::ChatAction> &&action) {
break;
}
case td_api::chatActionSpeakingInCall::ID:
init(Type::SpeakingInCall);
init(Type::SpeakingInVoiceChat);
break;
default:
UNREACHABLE();
@ -141,7 +141,7 @@ DialogAction::DialogAction(tl_object_ptr<telegram_api::SendMessageAction> &&acti
break;
}
case telegram_api::speakingInGroupCallAction::ID:
init(Type::SpeakingInCall);
init(Type::SpeakingInVoiceChat);
break;
default:
UNREACHABLE();
@ -177,7 +177,7 @@ tl_object_ptr<telegram_api::SendMessageAction> DialogAction::get_input_send_mess
return make_tl_object<telegram_api::sendMessageRecordRoundAction>();
case Type::UploadingVideoNote:
return make_tl_object<telegram_api::sendMessageUploadRoundAction>(progress_);
case Type::SpeakingInCall:
case Type::SpeakingInVoiceChat:
return make_tl_object<telegram_api::speakingInGroupCallAction>();
default:
UNREACHABLE();
@ -213,7 +213,7 @@ tl_object_ptr<secret_api::SendMessageAction> DialogAction::get_secret_input_send
return make_tl_object<secret_api::sendMessageRecordRoundAction>();
case Type::UploadingVideoNote:
return make_tl_object<secret_api::sendMessageUploadRoundAction>();
case Type::SpeakingInCall:
case Type::SpeakingInVoiceChat:
return make_tl_object<secret_api::sendMessageTypingAction>();
default:
UNREACHABLE();
@ -249,7 +249,7 @@ tl_object_ptr<td_api::ChatAction> DialogAction::get_chat_action_object() const {
return td_api::make_object<td_api::chatActionRecordingVideoNote>();
case Type::UploadingVideoNote:
return td_api::make_object<td_api::chatActionUploadingVideoNote>(progress_);
case Type::SpeakingInCall:
case Type::SpeakingInVoiceChat:
return td_api::make_object<td_api::chatActionSpeakingInCall>();
default:
UNREACHABLE();
@ -350,6 +350,10 @@ DialogAction DialogAction::get_typing_action() {
return DialogAction(Type::Typing, 0);
}
DialogAction DialogAction::get_speaking_action() {
return DialogAction(Type::SpeakingInVoiceChat, 0);
}
StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &action) {
string_builder << "ChatAction";
const char *type = [action_type = action.type_] {
@ -380,8 +384,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &act
return "RecordingVideoNote";
case DialogAction::Type::UploadingVideoNote:
return "UploadingVideoNote";
case DialogAction::Type::SpeakingInCall:
return "SpeakingInCall";
case DialogAction::Type::SpeakingInVoiceChat:
return "SpeakingInVoiceChat";
default:
UNREACHABLE();
return "Cancel";

View File

@ -31,7 +31,7 @@ class DialogAction {
StartPlayingGame,
RecordingVideoNote,
UploadingVideoNote,
SpeakingInCall
SpeakingInVoiceChat
};
Type type_ = Type::Cancel;
int32 progress_ = 0;
@ -61,6 +61,8 @@ class DialogAction {
static DialogAction get_typing_action();
static DialogAction get_speaking_action();
friend bool operator==(const DialogAction &lhs, const DialogAction &rhs) {
return lhs.type_ == rhs.type_ && lhs.progress_ == rhs.progress_;
}

View File

@ -9,6 +9,7 @@
#include "td/telegram/AuthManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Td.h"
@ -259,7 +260,7 @@ class CheckGroupCallQuery : public Td::ResultHandler {
if (success) {
promise_.set_value(Unit());
} else {
promise_.set_error(Status::Error(200, "Group call left"));
promise_.set_error(Status::Error(400, "GROUP_CALL_JOIN_MISSING"));
}
}
@ -336,6 +337,7 @@ struct GroupCallManager::GroupCall {
bool is_inited = false;
bool is_active = false;
bool is_joined = false;
bool is_speaking = false;
bool mute_new_members = false;
bool allowed_change_mute_new_members = false;
int32 member_count = 0;
@ -352,6 +354,8 @@ struct GroupCallManager::PendingJoinRequest {
};
GroupCallManager::GroupCallManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
pending_send_speaking_action_timeout_.set_callback(on_pending_send_speaking_action_timeout_callback);
pending_send_speaking_action_timeout_.set_callback_data(static_cast<void *>(this));
}
GroupCallManager::~GroupCallManager() = default;
@ -360,8 +364,36 @@ void GroupCallManager::tear_down() {
parent_.reset();
}
void GroupCallManager::on_pending_send_speaking_action_timeout_callback(void *group_call_manager_ptr,
int64 group_call_id_int) {
if (G()->close_flag()) {
return;
}
auto group_call_manager = static_cast<GroupCallManager *>(group_call_manager_ptr);
send_closure_later(group_call_manager->actor_id(group_call_manager),
&GroupCallManager::on_send_speaking_action_timeout,
GroupCallId(narrow_cast<int32>(group_call_id_int)));
}
void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id) {
LOG(INFO) << "Receive send_speaking_action timeout in " << group_call_id;
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
auto *group_call = get_group_call(input_group_call_id);
CHECK(group_call != nullptr && group_call->is_inited && group_call->channel_id.is_valid());
if (!group_call->is_joined || !group_call->is_speaking) {
return;
}
pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 4.0);
td_->messages_manager_->send_dialog_action(DialogId(group_call->channel_id), MessageId(),
DialogAction::get_speaking_action(), Promise<Unit>());
}
GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, ChannelId channel_id) {
if (td_->auth_manager_->is_bot()) {
if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) {
return GroupCallId();
}
return add_group_call(input_group_call_id, channel_id)->group_call_id;
@ -375,7 +407,9 @@ Result<InputGroupCallId> GroupCallManager::get_input_group_call_id(GroupCallId g
return Status::Error(400, "Wrong group call identifier specified");
}
CHECK(static_cast<size_t>(group_call_id.get()) <= input_group_call_ids_.size());
return input_group_call_ids_[group_call_id.get() - 1];
auto input_group_call_id = input_group_call_ids_[group_call_id.get() - 1];
LOG(DEBUG) << "Found " << input_group_call_id;
return input_group_call_id;
}
GroupCallId GroupCallManager::get_next_group_call_id(InputGroupCallId input_group_call_id) {
@ -391,6 +425,7 @@ GroupCallManager::GroupCall *GroupCallManager::add_group_call(InputGroupCallId i
if (group_call == nullptr) {
group_call = make_unique<GroupCall>();
group_call->group_call_id = get_next_group_call_id(input_group_call_id);
LOG(INFO) << "Add " << input_group_call_id << " from " << channel_id << " as " << group_call->group_call_id;
}
if (!group_call->channel_id.is_valid()) {
group_call->channel_id = channel_id;
@ -693,6 +728,31 @@ void GroupCallManager::invite_group_call_members(GroupCallId group_call_id, vect
td_->create_handler<InviteToGroupCallQuery>(std::move(promise))->send(input_group_call_id, std::move(input_users));
}
void GroupCallManager::set_group_call_member_is_speaking(GroupCallId group_call_id, int32 source, bool is_speaking,
Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->is_joined) {
return promise.set_value(Unit());
}
if (group_call->source == source) {
if (!group_call->channel_id.is_valid()) {
return promise.set_value(Unit());
}
if (group_call->is_speaking != is_speaking) {
group_call->is_speaking = is_speaking;
if (is_speaking) {
pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 0.0);
}
}
return promise.set_value(Unit());
}
// TODO process others speaking actions
promise.set_value(Unit());
}
void GroupCallManager::toggle_group_call_member_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted,
Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
@ -746,6 +806,7 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id,
CHECK(group_call != nullptr && group_call->is_inited);
if (group_call->is_joined && group_call->source == source) {
group_call->is_joined = false;
group_call->is_speaking = false;
group_call->source = 0;
}
}
@ -821,7 +882,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr<telegra
if (!group_call->is_active) {
// never update ended calls
} else if (!call.is_active) {
// always update to an ended call, droping also is_joined flag
// always update to an ended call, droping also is_joined and is_speaking flags
*group_call = std::move(call);
need_update = true;
} else {

View File

@ -15,6 +15,7 @@
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/actor/Timeout.h"
#include "td/utils/Status.h"
@ -46,6 +47,9 @@ class GroupCallManager : public Actor {
void invite_group_call_members(GroupCallId group_call_id, vector<UserId> &&user_ids, Promise<Unit> &&promise);
void set_group_call_member_is_speaking(GroupCallId group_call_id, int32 source, bool is_speaking,
Promise<Unit> &&promise);
void toggle_group_call_member_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted,
Promise<Unit> &&promise);
@ -66,6 +70,10 @@ class GroupCallManager : public Actor {
void tear_down() override;
static void on_pending_send_speaking_action_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int);
void on_send_speaking_action_timeout(GroupCallId group_call_id);
Result<InputGroupCallId> get_input_group_call_id(GroupCallId group_call_id);
GroupCallId get_next_group_call_id(InputGroupCallId input_group_call_id);
@ -111,6 +119,8 @@ class GroupCallManager : public Actor {
std::unordered_map<InputGroupCallId, unique_ptr<PendingJoinRequest>, InputGroupCallIdHash> pending_join_requests_;
uint64 join_group_request_generation_ = 0;
MultiTimeout pending_send_speaking_action_timeout_{"PendingSendSpeakingActionTimeout"};
};
} // namespace td

View File

@ -6037,21 +6037,18 @@ void Td::on_request(uint64 id, const td_api::createVoiceChat &request) {
promise.set_value(td_api::make_object<td_api::groupCallId>(result.ok().get()));
}
});
contacts_manager_->create_channel_voice_chat(DialogId(request.chat_id_), std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::getGroupCall &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
group_call_manager_->get_group_call(GroupCallId(request.group_call_id_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::joinGroupCall &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), std::move(request.payload_),
request.source_, request.is_muted_, std::move(promise));
}
@ -6059,7 +6056,6 @@ void Td::on_request(uint64 id, td_api::joinGroupCall &request) {
void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewMembers &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->toggle_group_call_mute_new_members(GroupCallId(request.group_call_id_),
request.mute_new_members_, std::move(promise));
}
@ -6067,7 +6063,6 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewMembers &requ
void Td::on_request(uint64 id, const td_api::inviteGroupCallMembers &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
vector<UserId> user_ids;
for (auto &user_id : request.user_ids_) {
user_ids.emplace_back(user_id);
@ -6076,10 +6071,16 @@ void Td::on_request(uint64 id, const td_api::inviteGroupCallMembers &request) {
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setGroupCallMemberIsSpeaking &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->set_group_call_member_is_speaking(GroupCallId(request.group_call_id_), request.source_,
request.is_speaking_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleGroupCallMemberIsMuted &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->toggle_group_call_member_is_muted(GroupCallId(request.group_call_id_), UserId(request.user_id_),
request.is_muted_, std::move(promise));
}
@ -6087,21 +6088,18 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallMemberIsMuted &reque
void Td::on_request(uint64 id, const td_api::checkGroupCallIsJoined &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->check_group_call_is_joined(GroupCallId(request.group_call_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::leaveGroupCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->leave_group_call(GroupCallId(request.group_call_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::discardGroupCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise));
}

View File

@ -702,6 +702,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::inviteGroupCallMembers &request);
void on_request(uint64 id, const td_api::setGroupCallMemberIsSpeaking &request);
void on_request(uint64 id, const td_api::toggleGroupCallMemberIsMuted &request);
void on_request(uint64 id, const td_api::checkGroupCallIsJoined &request);

View File

@ -2853,6 +2853,14 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::joinGroupCall>(as_group_call_id(args), nullptr, 123, true));
} else if (op == "tgcmnm" || op == "tgcmnme") {
send_request(td_api::make_object<td_api::toggleGroupCallMuteNewMembers>(as_group_call_id(args), op == "tgcmnme"));
} else if (op == "sgcmis") {
string group_call_id;
string source;
string is_speaking;
std::tie(group_call_id, args) = split(args);
std::tie(source, is_speaking) = split(args);
send_request(td_api::make_object<td_api::setGroupCallMemberIsSpeaking>(
as_group_call_id(group_call_id), to_integer<int32>(source), as_bool(is_speaking)));
} else if (op == "igcm") {
string group_call_id;
string user_ids;