RTP: Only start gstreamer pipeline once needed
This commit is contained in:
parent
b593aa05ef
commit
ea19a9c5cb
|
@ -5,10 +5,10 @@ using Xmpp.Xep;
|
||||||
public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
public Dino.Application app { get; private set; }
|
public Dino.Application app { get; private set; }
|
||||||
public CodecUtil codec_util { get; private set; }
|
public CodecUtil codec_util { get; private set; }
|
||||||
public Gst.DeviceMonitor device_monitor { get; private set; }
|
public Gst.DeviceMonitor? device_monitor { get; private set; }
|
||||||
public Gst.Pipeline pipe { get; private set; }
|
public Gst.Pipeline? pipe { get; private set; }
|
||||||
public Gst.Bin rtpbin { get; private set; }
|
public Gst.Bin? rtpbin { get; private set; }
|
||||||
public Gst.Element echoprobe { get; private set; }
|
public Gst.Element? echoprobe { get; private set; }
|
||||||
|
|
||||||
private Gee.List<Stream> streams = new ArrayList<Stream>();
|
private Gee.List<Stream> streams = new ArrayList<Stream>();
|
||||||
private Gee.List<Device> devices = new ArrayList<Device>();
|
private Gee.List<Device> devices = new ArrayList<Device>();
|
||||||
|
@ -42,18 +42,22 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
if (pause_count < 0) warning("Pause count below zero!");
|
if (pause_count < 0) warning("Pause count below zero!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startup() {
|
private void init_device_monitor() {
|
||||||
|
if (device_monitor != null) return;
|
||||||
device_monitor = new Gst.DeviceMonitor();
|
device_monitor = new Gst.DeviceMonitor();
|
||||||
device_monitor.show_all = true;
|
device_monitor.show_all = true;
|
||||||
device_monitor.get_bus().add_watch(Priority.DEFAULT, on_device_monitor_message);
|
device_monitor.get_bus().add_watch(Priority.DEFAULT, on_device_monitor_message);
|
||||||
device_monitor.start();
|
device_monitor.start();
|
||||||
foreach (Gst.Device device in device_monitor.get_devices()) {
|
foreach (Gst.Device device in device_monitor.get_devices()) {
|
||||||
if (device.properties.has_name("pipewire-proplist") && device.device_class.has_prefix("Audio/")) continue;
|
if (device.properties.has_name("pipewire-proplist") && device.has_classes("Audio")) continue;
|
||||||
if (device.properties.get_string("device.class") == "monitor") continue;
|
if (device.properties.get_string("device.class") == "monitor") continue;
|
||||||
if (devices.any_match((it) => it.matches(device))) continue;
|
if (devices.any_match((it) => it.matches(device))) continue;
|
||||||
devices.add(new Device(this, device));
|
devices.add(new Device(this, device));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init_call_pipe() {
|
||||||
|
if (pipe != null) return;
|
||||||
pipe = new Gst.Pipeline(null);
|
pipe = new Gst.Pipeline(null);
|
||||||
|
|
||||||
// RTP
|
// RTP
|
||||||
|
@ -66,7 +70,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
rtpbin.pad_added.connect(on_rtp_pad_added);
|
rtpbin.pad_added.connect(on_rtp_pad_added);
|
||||||
rtpbin.@set("latency", 100);
|
rtpbin.@set("latency", 100);
|
||||||
rtpbin.@set("do-lost", true);
|
rtpbin.@set("do-lost", true);
|
||||||
rtpbin.@set("do-sync-event", true);
|
// rtpbin.@set("do-sync-event", true);
|
||||||
rtpbin.@set("drop-on-latency", true);
|
rtpbin.@set("drop-on-latency", true);
|
||||||
rtpbin.connect("signal::request-pt-map", request_pt_map, this);
|
rtpbin.connect("signal::request-pt-map", request_pt_map, this);
|
||||||
pipe.add(rtpbin);
|
pipe.add(rtpbin);
|
||||||
|
@ -86,6 +90,20 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
pipe.set_state(Gst.State.PLAYING);
|
pipe.set_state(Gst.State.PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void destroy_call_pipe() {
|
||||||
|
if (pipe == null) return;
|
||||||
|
pipe.set_state(Gst.State.NULL);
|
||||||
|
rtpbin = null;
|
||||||
|
#if WITH_VOICE_PROCESSOR
|
||||||
|
echoprobe = null;
|
||||||
|
#endif
|
||||||
|
pipe = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startup() {
|
||||||
|
init_device_monitor();
|
||||||
|
}
|
||||||
|
|
||||||
private static Gst.Caps? request_pt_map(Gst.Element rtpbin, uint session, uint pt, Plugin plugin) {
|
private static Gst.Caps? request_pt_map(Gst.Element rtpbin, uint session, uint pt, Plugin plugin) {
|
||||||
debug("request-pt-map");
|
debug("request-pt-map");
|
||||||
return null;
|
return null;
|
||||||
|
@ -98,7 +116,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
uint8 rtpid = (uint8)int.parse(split[3]);
|
uint8 rtpid = (uint8)int.parse(split[3]);
|
||||||
foreach (Stream stream in streams) {
|
foreach (Stream stream in streams) {
|
||||||
if (stream.rtpid == rtpid) {
|
if (stream.rtpid == rtpid) {
|
||||||
stream.on_ssrc_pad_added(split[4], pad);
|
stream.on_ssrc_pad_added((uint32) split[4].to_uint64(), pad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +155,15 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
break;
|
break;
|
||||||
case Gst.MessageType.STATE_CHANGED:
|
case Gst.MessageType.STATE_CHANGED:
|
||||||
// Ignore
|
// Ignore
|
||||||
|
{
|
||||||
|
unowned Gst.Structure struc = message.get_structure();
|
||||||
|
if (struc != null && message.src is Gst.Element) {
|
||||||
|
Gst.State oldState, newState, pendingState;
|
||||||
|
message.parse_state_changed(out oldState, out newState, out pendingState);
|
||||||
|
debug("State of %s changed. Old: %s, New: %s, Pending; %s", ((Gst.Element)message.src).name, @"$oldState", @"$newState", @"$pendingState");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Gst.MessageType.STREAM_STATUS:
|
case Gst.MessageType.STREAM_STATUS:
|
||||||
Gst.StreamStatusType status;
|
Gst.StreamStatusType status;
|
||||||
|
@ -179,51 +206,39 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool on_device_monitor_message(Gst.Bus bus, Gst.Message message) {
|
private bool on_device_monitor_message(Gst.Bus bus, Gst.Message message) {
|
||||||
Gst.Device old_device = null;
|
Gst.Device? old_gst_device = null;
|
||||||
Gst.Device device = null;
|
Gst.Device? gst_device = null;
|
||||||
Device old = null;
|
Device? device = null;
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case Gst.MessageType.DEVICE_ADDED:
|
case Gst.MessageType.DEVICE_ADDED:
|
||||||
message.parse_device_added(out device);
|
message.parse_device_added(out gst_device);
|
||||||
if (device.properties.has_name("pipewire-proplist") && device.device_class.has_prefix("Audio/")) return Source.CONTINUE;
|
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||||
if (device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||||
if (devices.any_match((it) => it.matches(device))) return Source.CONTINUE;
|
if (devices.any_match((it) => it.matches(gst_device))) return Source.CONTINUE;
|
||||||
devices.add(new Device(this, device));
|
device = new Device(this, gst_device);
|
||||||
|
devices.add(device);
|
||||||
break;
|
break;
|
||||||
#if GST_1_16
|
#if GST_1_16
|
||||||
case Gst.MessageType.DEVICE_CHANGED:
|
case Gst.MessageType.DEVICE_CHANGED:
|
||||||
message.parse_device_changed(out device, out old_device);
|
message.parse_device_changed(out gst_device, out old_gst_device);
|
||||||
if (device.properties.has_name("pipewire-proplist") && device.device_class.has_prefix("Audio/")) return Source.CONTINUE;
|
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||||
if (device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||||
old = devices.first_match((it) => it.matches(old_device));
|
device = devices.first_match((it) => it.matches(old_gst_device));
|
||||||
if (old != null) old.update(device);
|
if (device != null) device.update(gst_device);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case Gst.MessageType.DEVICE_REMOVED:
|
case Gst.MessageType.DEVICE_REMOVED:
|
||||||
message.parse_device_removed(out device);
|
message.parse_device_removed(out gst_device);
|
||||||
if (device.properties.has_name("pipewire-proplist") && device.device_class.has_prefix("Audio/")) return Source.CONTINUE;
|
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||||
if (device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||||
old = devices.first_match((it) => it.matches(device));
|
device = devices.first_match((it) => it.matches(gst_device));
|
||||||
if (old != null) devices.remove(old);
|
if (device != null) devices.remove(device);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
switch (device.device_class) {
|
devices_changed(device.media, device.is_sink);
|
||||||
case "Audio/Source":
|
|
||||||
devices_changed("audio", false);
|
|
||||||
break;
|
|
||||||
case "Audio/Sink":
|
|
||||||
devices_changed("audio", true);
|
|
||||||
break;
|
|
||||||
case "Video/Source":
|
|
||||||
devices_changed("video", false);
|
|
||||||
break;
|
|
||||||
case "Video/Sink":
|
|
||||||
devices_changed("video", true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Source.CONTINUE;
|
return Source.CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -253,6 +268,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public Stream open_stream(Xmpp.Xep.Jingle.Content content) {
|
public Stream open_stream(Xmpp.Xep.Jingle.Content content) {
|
||||||
|
init_call_pipe();
|
||||||
var content_params = content.content_params as Xmpp.Xep.JingleRtp.Parameters;
|
var content_params = content.content_params as Xmpp.Xep.JingleRtp.Parameters;
|
||||||
if (content_params == null) return null;
|
if (content_params == null) return null;
|
||||||
Stream stream;
|
Stream stream;
|
||||||
|
@ -271,15 +287,15 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
device_monitor.stop();
|
if (device_monitor != null) {
|
||||||
pipe.set_state(Gst.State.NULL);
|
device_monitor.stop();
|
||||||
rtpbin = null;
|
}
|
||||||
pipe = null;
|
destroy_call_pipe();
|
||||||
Gst.deinit();
|
Gst.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool supports(string media) {
|
public bool supports(string media) {
|
||||||
if (rtpbin == null) return false;
|
if (!codec_util.is_element_supported("rtpbin")) return false;
|
||||||
|
|
||||||
if (media == "audio") {
|
if (media == "audio") {
|
||||||
if (get_devices("audio", false).is_empty) return false;
|
if (get_devices("audio", false).is_empty) return false;
|
||||||
|
@ -287,7 +303,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media == "video") {
|
if (media == "video") {
|
||||||
if (Gst.ElementFactory.make("gtksink", null) == null) return false;
|
if (!codec_util.is_element_supported("gtksink")) return false;
|
||||||
if (get_devices("video", false).is_empty) return false;
|
if (get_devices("video", false).is_empty) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,6 +311,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public VideoCallWidget? create_widget(WidgetType type) {
|
public VideoCallWidget? create_widget(WidgetType type) {
|
||||||
|
init_call_pipe();
|
||||||
if (type == WidgetType.GTK) {
|
if (type == WidgetType.GTK) {
|
||||||
return new VideoWidget(this);
|
return new VideoWidget(this);
|
||||||
}
|
}
|
||||||
|
@ -422,10 +439,11 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dump_dot() {
|
public void dump_dot() {
|
||||||
|
if (pipe == null) return;
|
||||||
string name = @"pipe-$(pipe.clock.get_time())-$(pipe.current_state)";
|
string name = @"pipe-$(pipe.clock.get_time())-$(pipe.current_state)";
|
||||||
Gst.Debug.bin_to_dot_file(pipe, Gst.DebugGraphDetails.ALL, name);
|
Gst.Debug.bin_to_dot_file(pipe, Gst.DebugGraphDetails.ALL, name);
|
||||||
debug("Stored pipe details as %s", name);
|
print(@"Stored pipe details as $name\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set_pause(Xmpp.Xep.JingleRtp.Stream stream, bool pause) {
|
public void set_pause(Xmpp.Xep.JingleRtp.Stream stream, bool pause) {
|
||||||
|
|
Loading…
Reference in a new issue