Handle non-existant call support
This commit is contained in:
parent
3880628de4
commit
5d85b6cdb0
|
@ -85,6 +85,8 @@ public abstract interface ConversationAdditionPopulator : ConversationItemPopula
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface VideoCallPlugin : Object {
|
public abstract interface VideoCallPlugin : Object {
|
||||||
|
|
||||||
|
public abstract bool supports(string media);
|
||||||
// Video widget
|
// Video widget
|
||||||
public abstract VideoCallWidget? create_widget(WidgetType type);
|
public abstract VideoCallWidget? create_widget(WidgetType type);
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace Dino {
|
||||||
we_should_send_video[call] = video;
|
we_should_send_video[call] = video;
|
||||||
we_should_send_audio[call] = true;
|
we_should_send_audio[call] = true;
|
||||||
|
|
||||||
if (yield has_jmi_resources(conversation)) {
|
if (has_jmi_resources(conversation)) {
|
||||||
XmppStream? stream = stream_interactor.get_stream(conversation.account);
|
XmppStream? stream = stream_interactor.get_stream(conversation.account);
|
||||||
jmi_call[conversation.account] = call;
|
jmi_call[conversation.account] = call;
|
||||||
jmi_video[conversation.account] = video;
|
jmi_video[conversation.account] = video;
|
||||||
|
@ -245,8 +245,28 @@ namespace Dino {
|
||||||
// If video_feed == null && !mute we're trying to mute a non-existant feed. It will be muted as soon as it is created.
|
// If video_feed == null && !mute we're trying to mute a non-existant feed. It will be muted as soon as it is created.
|
||||||
}
|
}
|
||||||
|
|
||||||
public async bool can_do_calls(Conversation conversation) {
|
public async bool can_do_audio_calls_async(Conversation conversation) {
|
||||||
return (yield get_call_resources(conversation)).size > 0 || yield has_jmi_resources(conversation);
|
if (!can_do_audio_calls()) return false;
|
||||||
|
return (yield get_call_resources(conversation)).size > 0 || has_jmi_resources(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool can_do_audio_calls() {
|
||||||
|
Plugins.VideoCallPlugin? plugin = Application.get_default().plugin_registry.video_call_plugin;
|
||||||
|
if (plugin == null) return false;
|
||||||
|
|
||||||
|
return plugin.supports("audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async bool can_do_video_calls_async(Conversation conversation) {
|
||||||
|
if (!can_do_video_calls()) return false;
|
||||||
|
return (yield get_call_resources(conversation)).size > 0 || has_jmi_resources(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool can_do_video_calls() {
|
||||||
|
Plugins.VideoCallPlugin? plugin = Application.get_default().plugin_registry.video_call_plugin;
|
||||||
|
if (plugin == null) return false;
|
||||||
|
|
||||||
|
return plugin.supports("video");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Gee.List<Jid> get_call_resources(Conversation conversation) {
|
private async Gee.List<Jid> get_call_resources(Conversation conversation) {
|
||||||
|
@ -266,7 +286,7 @@ namespace Dino {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async bool has_jmi_resources(Conversation conversation) {
|
private bool has_jmi_resources(Conversation conversation) {
|
||||||
int64 jmi_resources = db.entity.select()
|
int64 jmi_resources = db.entity.select()
|
||||||
.with(db.entity.jid_id, "=", db.get_jid_id(conversation.counterpart))
|
.with(db.entity.jid_id, "=", db.get_jid_id(conversation.counterpart))
|
||||||
.join_with(db.entity_feature, db.entity.caps_hash, db.entity_feature.entity)
|
.join_with(db.entity_feature, db.entity.caps_hash, db.entity_feature.entity)
|
||||||
|
@ -289,6 +309,11 @@ namespace Dino {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void on_incoming_call(Account account, Xep.Jingle.Session session) {
|
private void on_incoming_call(Account account, Xep.Jingle.Session session) {
|
||||||
|
if (!can_do_audio_calls()) {
|
||||||
|
warning("Incoming call but no call support detected. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool counterpart_wants_video = false;
|
bool counterpart_wants_video = false;
|
||||||
foreach (Xep.Jingle.Content content in session.contents) {
|
foreach (Xep.Jingle.Content content in session.contents) {
|
||||||
Xep.JingleRtp.Parameters? rtp_content_parameter = content.content_params as Xep.JingleRtp.Parameters;
|
Xep.JingleRtp.Parameters? rtp_content_parameter = content.content_params as Xep.JingleRtp.Parameters;
|
||||||
|
@ -550,6 +575,11 @@ namespace Dino {
|
||||||
|
|
||||||
Xep.JingleMessageInitiation.Module mi_module = stream_interactor.module_manager.get_module(account, Xep.JingleMessageInitiation.Module.IDENTITY);
|
Xep.JingleMessageInitiation.Module mi_module = stream_interactor.module_manager.get_module(account, Xep.JingleMessageInitiation.Module.IDENTITY);
|
||||||
mi_module.session_proposed.connect((from, to, sid, descriptions) => {
|
mi_module.session_proposed.connect((from, to, sid, descriptions) => {
|
||||||
|
if (!can_do_audio_calls()) {
|
||||||
|
warning("Incoming call but no call support detected. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool audio_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "audio");
|
bool audio_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "audio");
|
||||||
bool video_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "video");
|
bool video_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "video");
|
||||||
if (!audio_requested && !video_requested) return;
|
if (!audio_requested && !video_requested) return;
|
||||||
|
|
|
@ -34,6 +34,9 @@ namespace Dino.Ui {
|
||||||
private StreamInteractor stream_interactor;
|
private StreamInteractor stream_interactor;
|
||||||
private Conversation conversation;
|
private Conversation conversation;
|
||||||
|
|
||||||
|
private ModelButton audio_button = new ModelButton() { text="Audio call", visible=true };
|
||||||
|
private ModelButton video_button = new ModelButton() { text="Video call", visible=true };
|
||||||
|
|
||||||
public CallButton(StreamInteractor stream_interactor) {
|
public CallButton(StreamInteractor stream_interactor) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
|
||||||
|
@ -42,7 +45,6 @@ namespace Dino.Ui {
|
||||||
|
|
||||||
Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu();
|
Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu();
|
||||||
Box box = new Box(Orientation.VERTICAL, 0) { margin=10, visible=true };
|
Box box = new Box(Orientation.VERTICAL, 0) { margin=10, visible=true };
|
||||||
ModelButton audio_button = new ModelButton() { text="Audio call", visible=true };
|
|
||||||
audio_button.clicked.connect(() => {
|
audio_button.clicked.connect(() => {
|
||||||
stream_interactor.get_module(Calls.IDENTITY).initiate_call.begin(conversation, false, (_, res) => {
|
stream_interactor.get_module(Calls.IDENTITY).initiate_call.begin(conversation, false, (_, res) => {
|
||||||
Call call = stream_interactor.get_module(Calls.IDENTITY).initiate_call.end(res);
|
Call call = stream_interactor.get_module(Calls.IDENTITY).initiate_call.end(res);
|
||||||
|
@ -50,7 +52,7 @@ namespace Dino.Ui {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
box.add(audio_button);
|
box.add(audio_button);
|
||||||
ModelButton video_button = new ModelButton() { text="Video call", visible=true };
|
|
||||||
video_button.clicked.connect(() => {
|
video_button.clicked.connect(() => {
|
||||||
stream_interactor.get_module(Calls.IDENTITY).initiate_call.begin(conversation, true, (_, res) => {
|
stream_interactor.get_module(Calls.IDENTITY).initiate_call.begin(conversation, true, (_, res) => {
|
||||||
Call call = stream_interactor.get_module(Calls.IDENTITY).initiate_call.end(res);
|
Call call = stream_interactor.get_module(Calls.IDENTITY).initiate_call.end(res);
|
||||||
|
@ -116,9 +118,12 @@ namespace Dino.Ui {
|
||||||
private async void update_visibility() {
|
private async void update_visibility() {
|
||||||
if (conversation.type_ == Conversation.Type.CHAT) {
|
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||||
Conversation conv_bak = conversation;
|
Conversation conv_bak = conversation;
|
||||||
bool can_do_calls = yield stream_interactor.get_module(Calls.IDENTITY).can_do_calls(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_audio_calls_async(conversation);
|
||||||
if (conv_bak != conversation) return;
|
if (conv_bak != conversation) return;
|
||||||
visible = can_do_calls;
|
|
||||||
|
visible = audio_works;
|
||||||
|
video_button.visible = video_works;
|
||||||
} else {
|
} else {
|
||||||
visible = false;
|
visible = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ public class Dino.Plugins.Rtp.CodecUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? get_encode_element_name(string media, string? codec) {
|
public string? get_encode_element_name(string media, string? codec) {
|
||||||
|
if (!is_element_supported(get_pay_element_name(media, codec))) return null;
|
||||||
foreach (string candidate in get_encode_candidates(media, codec)) {
|
foreach (string candidate in get_encode_candidates(media, codec)) {
|
||||||
if (is_element_supported(candidate)) return candidate;
|
if (is_element_supported(candidate)) return candidate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,13 +64,13 @@ public class Dino.Plugins.Rtp.Module : JingleRtp.Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async bool is_payload_supported(string media, JingleRtp.PayloadType payload_type) {
|
private async bool is_payload_supported(string media, JingleRtp.PayloadType payload_type) {
|
||||||
string codec = CodecUtil.get_codec_from_payload(media, payload_type);
|
string? codec = CodecUtil.get_codec_from_payload(media, payload_type);
|
||||||
if (codec == null) return false;
|
if (codec == null) return false;
|
||||||
if (unsupported_codecs.contains(codec)) return false;
|
if (unsupported_codecs.contains(codec)) return false;
|
||||||
if (supported_codecs.contains(codec)) return true;
|
if (supported_codecs.contains(codec)) return true;
|
||||||
|
|
||||||
string encode_element = codec_util.get_encode_element_name(media, codec);
|
string? encode_element = codec_util.get_encode_element_name(media, codec);
|
||||||
string decode_element = codec_util.get_decode_element_name(media, codec);
|
string? decode_element = codec_util.get_decode_element_name(media, codec);
|
||||||
if (encode_element == null || decode_element == null) {
|
if (encode_element == null || decode_element == null) {
|
||||||
debug("No suitable encoder or decoder found for %s", codec);
|
debug("No suitable encoder or decoder found for %s", codec);
|
||||||
unsupported_codecs.add(codec);
|
unsupported_codecs.add(codec);
|
||||||
|
|
|
@ -278,6 +278,22 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
Gst.deinit();
|
Gst.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool supports(string media) {
|
||||||
|
if (rtpbin == null) return false;
|
||||||
|
|
||||||
|
if (media == "audio") {
|
||||||
|
if (get_devices("audio", false).is_empty) return false;
|
||||||
|
if (get_devices("audio", true).is_empty) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (media == "video") {
|
||||||
|
if (Gst.ElementFactory.make("gtksink", null) == null) return false;
|
||||||
|
if (get_devices("video", false).is_empty) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public VideoCallWidget? create_widget(WidgetType type) {
|
public VideoCallWidget? create_widget(WidgetType type) {
|
||||||
if (type == WidgetType.GTK) {
|
if (type == WidgetType.GTK) {
|
||||||
return new VideoWidget(this);
|
return new VideoWidget(this);
|
||||||
|
|
Loading…
Reference in a new issue