UI + libdino: Improve MUJI calls from MUC
- Move calls from ICE-thead onto main thread - Identify Call.ourpart as MUC nick if in MUC - Keep track of the initiator of a call
This commit is contained in:
parent
ff4e2540ae
commit
f0c7dd0682
|
@ -20,9 +20,12 @@ namespace Dino.Entities {
|
|||
|
||||
public int id { get; set; default=-1; }
|
||||
public Account account { get; set; }
|
||||
public Jid counterpart { get; set; } // For backwards compatibility with db version 21. Not to be used anymore.
|
||||
public Jid counterpart { get; set; }
|
||||
public Gee.List<Jid> counterparts = new Gee.ArrayList<Jid>(Jid.equals_bare_func);
|
||||
public Jid ourpart { get; set; }
|
||||
public Jid proposer {
|
||||
get { return direction == DIRECTION_OUTGOING ? ourpart : counterpart; }
|
||||
}
|
||||
public bool direction { get; set; }
|
||||
public DateTime time { get; set; }
|
||||
public DateTime local_time { get; set; }
|
||||
|
@ -58,7 +61,6 @@ namespace Dino.Entities {
|
|||
if (!counterparts.contains(peer)) { // Legacy: The first peer is also in the `call` table. Don't add twice.
|
||||
counterparts.add(peer);
|
||||
}
|
||||
if (counterpart == null) counterpart = peer;
|
||||
}
|
||||
|
||||
counterpart = db.get_jid_by_id(row[db.call.counterpart_id]);
|
||||
|
@ -66,7 +68,6 @@ namespace Dino.Entities {
|
|||
if (counterpart_resource != null) counterpart = counterpart.with_resource(counterpart_resource);
|
||||
if (counterparts.is_empty) {
|
||||
counterparts.add(counterpart);
|
||||
counterpart = counterpart;
|
||||
}
|
||||
|
||||
notify.connect(on_update);
|
||||
|
@ -107,8 +108,6 @@ namespace Dino.Entities {
|
|||
}
|
||||
|
||||
public void add_peer(Jid peer) {
|
||||
if (counterpart == null) counterpart = peer;
|
||||
|
||||
if (counterparts.contains(peer)) return;
|
||||
|
||||
counterparts.add(peer);
|
||||
|
|
|
@ -127,8 +127,6 @@ public class Dino.PeerState : Object {
|
|||
}
|
||||
|
||||
public void reject() {
|
||||
call.state = Call.State.DECLINED;
|
||||
|
||||
if (session != null) {
|
||||
foreach (Xep.Jingle.Content content in session.contents) {
|
||||
content.reject();
|
||||
|
@ -299,7 +297,12 @@ public class Dino.PeerState : Object {
|
|||
|
||||
debug(@"[%s] %s connecting content signals %s", call.account.bare_jid.to_string(), jid.to_string(), rtp_content_parameter.media);
|
||||
rtp_content_parameter.stream_created.connect((stream) => on_stream_created(rtp_content_parameter.media, stream));
|
||||
rtp_content_parameter.connection_ready.connect((status) => on_connection_ready(content, rtp_content_parameter.media));
|
||||
rtp_content_parameter.connection_ready.connect((status) => {
|
||||
Idle.add(() => {
|
||||
on_connection_ready(content, rtp_content_parameter.media);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
content.senders_modify_incoming.connect((content, proposed_senders) => {
|
||||
if (content.session.senders_include_us(content.senders) != content.session.senders_include_us(proposed_senders)) {
|
||||
|
@ -342,7 +345,10 @@ public class Dino.PeerState : Object {
|
|||
if (media == "video" && stream.receiving) {
|
||||
counterpart_sends_video = true;
|
||||
video_content_parameter.connection_ready.connect((status) => {
|
||||
Idle.add(() => {
|
||||
counterpart_sends_video_updated(false);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ public class Dino.CallState : Object {
|
|||
foreach (PeerState peer in peers_cpy) {
|
||||
peer.end(Xep.Jingle.ReasonElement.CANCEL);
|
||||
}
|
||||
if (parent_muc != null) {
|
||||
if (parent_muc != null && group_call != null) {
|
||||
XmppStream stream = stream_interactor.get_stream(call.account);
|
||||
if (stream == null) return;
|
||||
stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_retract_to_peer(stream, parent_muc, group_call.muc_jid, message_type);
|
||||
|
@ -242,7 +242,12 @@ public class Dino.CallState : Object {
|
|||
XmppStream stream = stream_interactor.get_stream(call.account);
|
||||
if (stream == null) return;
|
||||
|
||||
Jid muc_jid = stream_interactor.get_module(MucManager.IDENTITY).default_muc_server[call.account] ?? new Jid("chat.jabberfr.org");
|
||||
Jid? muc_jid = null;
|
||||
if (muc_jid == null) {
|
||||
warning("Failed to initiate group call: MUC server not known.");
|
||||
return;
|
||||
}
|
||||
|
||||
muc_jid = new Jid("%08x@".printf(Random.next_int()) + muc_jid.to_string()); // TODO longer?
|
||||
|
||||
debug("[%s] Converting call to groupcall %s", call.account.bare_jid.to_string(), muc_jid.to_string());
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Dino {
|
|||
cache_call(call);
|
||||
}
|
||||
|
||||
public Call? get_call_by_id(int id) {
|
||||
public Call? get_call_by_id(int id, Conversation conversation) {
|
||||
Call? call = calls_by_db_id[id];
|
||||
if (call != null) {
|
||||
return call;
|
||||
|
@ -38,14 +38,17 @@ namespace Dino {
|
|||
|
||||
RowOption row_option = db.call.select().with(db.call.id, "=", id).row();
|
||||
|
||||
return create_call_from_row_opt(row_option);
|
||||
return create_call_from_row_opt(row_option, conversation);
|
||||
}
|
||||
|
||||
private Call? create_call_from_row_opt(RowOption row_opt) {
|
||||
private Call? create_call_from_row_opt(RowOption row_opt, Conversation conversation) {
|
||||
if (!row_opt.is_present()) return null;
|
||||
|
||||
try {
|
||||
Call call = new Call.from_row(db, row_opt.inner);
|
||||
if (conversation.type_.is_muc_semantic()) {
|
||||
call.ourpart = conversation.counterpart.with_resource(call.ourpart.resourcepart);
|
||||
}
|
||||
cache_call(call);
|
||||
return call;
|
||||
} catch (InvalidJidError e) {
|
||||
|
|
|
@ -39,9 +39,8 @@ namespace Dino {
|
|||
Call call = new Call();
|
||||
call.direction = Call.DIRECTION_OUTGOING;
|
||||
call.account = conversation.account;
|
||||
// TODO we should only do that for Conversation.Type.CHAT, but the database currently requires a counterpart from the start
|
||||
call.counterpart = conversation.counterpart;
|
||||
call.ourpart = conversation.account.full_jid;
|
||||
call.ourpart = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account) ?? conversation.account.full_jid;
|
||||
call.time = call.local_time = call.end_time = new DateTime.now_utc();
|
||||
call.state = Call.State.RINGING;
|
||||
|
||||
|
@ -57,7 +56,7 @@ namespace Dino {
|
|||
PeerState peer_state = call_state.set_first_peer(conversation.counterpart);
|
||||
yield peer_state.initiate_call(conversation.counterpart);
|
||||
} else {
|
||||
call_state.initiate_groupchat_call(conversation.counterpart);
|
||||
call_state.initiate_groupchat_call.begin(conversation.counterpart);
|
||||
}
|
||||
|
||||
conversation.last_active = call.time;
|
||||
|
@ -213,24 +212,23 @@ namespace Dino {
|
|||
|
||||
private PeerState create_received_call(Account account, Jid from, Jid to, bool video_requested) {
|
||||
Call call = new Call();
|
||||
Jid counterpart = null;
|
||||
if (from.equals_bare(account.bare_jid)) {
|
||||
// Call requested by another of our devices
|
||||
call.direction = Call.DIRECTION_OUTGOING;
|
||||
call.ourpart = from;
|
||||
call.state = Call.State.OTHER_DEVICE;
|
||||
counterpart = to;
|
||||
call.counterpart = to;
|
||||
} else {
|
||||
call.direction = Call.DIRECTION_INCOMING;
|
||||
call.ourpart = account.full_jid;
|
||||
call.state = Call.State.RINGING;
|
||||
counterpart = from;
|
||||
call.counterpart = from;
|
||||
}
|
||||
call.add_peer(counterpart);
|
||||
call.add_peer(call.counterpart);
|
||||
call.account = account;
|
||||
call.time = call.local_time = call.end_time = new DateTime.now_utc();
|
||||
|
||||
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(counterpart.bare_jid, account, Conversation.Type.CHAT);
|
||||
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(call.counterpart.bare_jid, account, Conversation.Type.CHAT);
|
||||
|
||||
stream_interactor.get_module(CallStore.IDENTITY).add_call(call, conversation);
|
||||
|
||||
|
@ -238,7 +236,7 @@ namespace Dino {
|
|||
|
||||
var call_state = new CallState(call, stream_interactor);
|
||||
connect_call_state_signals(call_state);
|
||||
PeerState peer_state = call_state.set_first_peer(counterpart);
|
||||
PeerState peer_state = call_state.set_first_peer(call.counterpart);
|
||||
call_state.we_should_send_video = video_requested;
|
||||
call_state.we_should_send_audio = true;
|
||||
|
||||
|
@ -283,7 +281,7 @@ namespace Dino {
|
|||
Call call = new Call();
|
||||
call.direction = Call.DIRECTION_INCOMING;
|
||||
call.ourpart = account.full_jid;
|
||||
call.add_peer(inviter_jid); // not rly
|
||||
call.counterpart = inviter_jid;
|
||||
call.account = account;
|
||||
call.time = call.local_time = call.end_time = new DateTime.now_utc();
|
||||
call.state = Call.State.RINGING;
|
||||
|
@ -361,13 +359,14 @@ namespace Dino {
|
|||
if (from.equals(account.full_jid)) return;
|
||||
|
||||
Call call = current_jmi_request_peer[account].call;
|
||||
call.ourpart = from;
|
||||
call.state = Call.State.OTHER_DEVICE;
|
||||
remove_call_from_datastructures(call);
|
||||
} else if (from.equals_bare(current_jmi_request_peer[account].jid) && to.equals(account.full_jid)) { // Message from our peer
|
||||
// We proposed the call
|
||||
// We know the full jid of our peer now
|
||||
current_jmi_request_call[account].rename_peer(current_jmi_request_peer[account].jid, from);
|
||||
current_jmi_request_peer[account].call_resource(from);
|
||||
current_jmi_request_peer[account].call_resource.begin(from);
|
||||
}
|
||||
});
|
||||
mi_module.session_rejected.connect((from, to, sid) => {
|
||||
|
@ -378,6 +377,9 @@ namespace Dino {
|
|||
bool incoming_reject = call.direction == Call.DIRECTION_INCOMING && from.equals_bare(account.bare_jid);
|
||||
if (!outgoing_reject && !incoming_reject) return;
|
||||
|
||||
// We don't care if a single person in a group call rejected the call
|
||||
if (incoming_reject && call_states[call].group_call != null) return;
|
||||
|
||||
call.state = Call.State.DECLINED;
|
||||
call_states[call].terminated(from, Xep.Jingle.ReasonElement.DECLINE, "JMI reject");
|
||||
remove_call_from_datastructures(call);
|
||||
|
|
|
@ -69,7 +69,7 @@ public class ContentItemStore : StreamInteractionModule, Object {
|
|||
}
|
||||
break;
|
||||
case 3:
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(foreign_id);
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(foreign_id, conversation);
|
||||
if (call != null) {
|
||||
var call_item = new CallItem(call, conversation, row[db.content_item.id]);
|
||||
items.add(call_item);
|
||||
|
@ -321,7 +321,7 @@ public class CallItem : ContentItem {
|
|||
public Conversation conversation;
|
||||
|
||||
public CallItem(Call call, Conversation conversation, int id) {
|
||||
base(id, TYPE, call.direction == Call.DIRECTION_OUTGOING ? conversation.account.bare_jid : conversation.counterpart, call.time, call.encryption, Message.Marked.NONE);
|
||||
base(id, TYPE, call.proposer, call.time, call.encryption, Message.Marked.NONE);
|
||||
|
||||
this.call = call;
|
||||
this.conversation = conversation;
|
||||
|
|
|
@ -424,7 +424,7 @@ public class MucManager : StreamInteractionModule, Object {
|
|||
foreach (Xep.ServiceDiscovery.Identity identity in identities) {
|
||||
if (identity.category == Xep.ServiceDiscovery.Identity.CATEGORY_CONFERENCE) {
|
||||
default_muc_server[account] = item.jid;
|
||||
print(@"$(account.bare_jid) Default MUC: $(item.jid)\n");
|
||||
debug("[%s] Default MUC: %s", account.bare_jid.to_string(), item.jid.to_string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
<child>
|
||||
<object class="GtkBox" id="multiparty_peer_box">
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="spacing">7</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -206,9 +206,14 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application {
|
|||
});
|
||||
add_action(open_shortcuts_action);
|
||||
|
||||
SimpleAction accept_call_action = new SimpleAction("accept-call", VariantType.INT32);
|
||||
SimpleAction accept_call_action = new SimpleAction("accept-call", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32}));
|
||||
accept_call_action.activate.connect((variant) => {
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(variant.get_int32());
|
||||
int conversation_id = variant.get_child_value(0).get_int32();
|
||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id);
|
||||
if (conversation == null) return;
|
||||
|
||||
int call_id = variant.get_child_value(1).get_int32();
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(call_id, conversation);
|
||||
CallState? call_state = stream_interactor.get_module(Calls.IDENTITY).call_states[call];
|
||||
if (call_state == null) return;
|
||||
|
||||
|
@ -220,9 +225,14 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application {
|
|||
});
|
||||
add_action(accept_call_action);
|
||||
|
||||
SimpleAction deny_call_action = new SimpleAction("reject-call", VariantType.INT32);
|
||||
SimpleAction deny_call_action = new SimpleAction("reject-call", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32}));
|
||||
deny_call_action.activate.connect((variant) => {
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(variant.get_int32());
|
||||
int conversation_id = variant.get_child_value(0).get_int32();
|
||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id);
|
||||
if (conversation == null) return;
|
||||
|
||||
int call_id = variant.get_child_value(1).get_int32();
|
||||
Call? call = stream_interactor.get_module(CallStore.IDENTITY).get_call_by_id(call_id, conversation);
|
||||
CallState? call_state = stream_interactor.get_module(Calls.IDENTITY).call_states[call];
|
||||
if (call_state == null) return;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Dino.Ui {
|
|||
public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true };
|
||||
public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END, visible=true };
|
||||
public Revealer invite_button_revealer = new Revealer() { margin_top=50, margin_right=30, halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200 };
|
||||
public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE };
|
||||
public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE, visible=false };
|
||||
private Widget? own_video = null;
|
||||
private HashMap<string, ParticipantWidget> participant_widgets = new HashMap<string, ParticipantWidget>();
|
||||
private ArrayList<string> participants = new ArrayList<string>();
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace Dino.Ui {
|
|||
|
||||
private void update_counterparts() {
|
||||
if (call.state != Call.State.IN_PROGRESS && call.state != Call.State.ENDED) return;
|
||||
if (call.counterparts.size <= 1) return;
|
||||
if (call.counterparts.size <= 1 && conversation.type_ == Conversation.Type.CHAT) return;
|
||||
|
||||
multiparty_peer_box.foreach((widget) => { multiparty_peer_box.remove(widget); });
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ namespace Dino.Ui {
|
|||
return;
|
||||
}
|
||||
|
||||
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||
Conversation conv_bak = conversation;
|
||||
bool audio_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_audio_calls_async(conversation);
|
||||
bool video_works = yield stream_interactor.get_module(Calls.IDENTITY).can_do_video_calls_async(conversation);
|
||||
|
@ -122,6 +123,9 @@ namespace Dino.Ui {
|
|||
|
||||
visible = audio_works;
|
||||
video_button.visible = video_works;
|
||||
} else {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public new void unset_conversation() { }
|
||||
|
|
|
@ -141,10 +141,12 @@ public class Dino.Ui.FreeDesktopNotifier : NotificationProvider, Object {
|
|||
GLib.Application.get_default().activate_action("open-conversation", new Variant.int32(conversation.id));
|
||||
});
|
||||
add_action_listener(notification_id, "reject", () => {
|
||||
GLib.Application.get_default().activate_action("reject-call", new Variant.int32(call.id));
|
||||
var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.int32(call.id)});
|
||||
GLib.Application.get_default().activate_action("reject-call", variant);
|
||||
});
|
||||
add_action_listener(notification_id, "accept", () => {
|
||||
GLib.Application.get_default().activate_action("accept-call", new Variant.int32(call.id));
|
||||
var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.int32(call.id)});
|
||||
GLib.Application.get_default().activate_action("accept-call", variant);
|
||||
});
|
||||
} catch (Error e) {
|
||||
warning("Failed showing subscription request notification: %s", e.message);
|
||||
|
|
Loading…
Reference in a new issue