Calls: Device picker
This commit is contained in:
parent
35526ab5a5
commit
43ea088f64
|
@ -118,9 +118,9 @@ public abstract interface VideoCallWidget : Object {
|
|||
}
|
||||
|
||||
public abstract interface MediaDevice : Object {
|
||||
public abstract string id { get; }
|
||||
public abstract string display_name { get; }
|
||||
public abstract string detail_name { get; }
|
||||
public abstract string id { owned get; }
|
||||
public abstract string display_name { owned get; }
|
||||
public abstract string detail_name { owned get; }
|
||||
}
|
||||
|
||||
public abstract interface NotificationPopulator : Object {
|
||||
|
|
|
@ -26,17 +26,21 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover {
|
|||
Gee.List<Plugins.MediaDevice> devices = call_plugin.get_devices("audio", false);
|
||||
|
||||
Box micro_box = new Box(Orientation.VERTICAL, 10) { visible=true };
|
||||
micro_box.add(new Label("<b>" + "Microphones" + "</b>") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ });
|
||||
micro_box.add(new Label("<b>" + _("Microphones") + "</b>") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ });
|
||||
|
||||
if (devices.size == 0) {
|
||||
micro_box.add(new Label("No microphones found."));
|
||||
micro_box.add(new Label(_("No microphones found.")));
|
||||
} else {
|
||||
ListBox micro_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true };
|
||||
micro_list_box.set_header_func(listbox_header_func);
|
||||
Frame micro_frame = new Frame(null) { visible=true };
|
||||
micro_frame.add(micro_list_box);
|
||||
foreach (Plugins.MediaDevice device in devices) {
|
||||
Label label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label display_name_label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true };
|
||||
detail_name_label.get_style_context().add_class("dim-label");
|
||||
detail_name_label.attributes = new Pango.AttrList();
|
||||
detail_name_label.attributes.insert(Pango.attr_scale_new(0.8));
|
||||
Image image = new Image.from_icon_name("object-select-symbolic", IconSize.BUTTON) { visible=true };
|
||||
if (current_microphone_device == null || current_microphone_device.id != device.id) {
|
||||
image.opacity = 0;
|
||||
|
@ -50,7 +54,10 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover {
|
|||
});
|
||||
Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, margin=7, visible=true };
|
||||
device_box.add(image);
|
||||
device_box.add(label);
|
||||
Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true };
|
||||
label_box.add(display_name_label);
|
||||
label_box.add(detail_name_label);
|
||||
device_box.add(label_box);
|
||||
ListBoxRow list_box_row = new ListBoxRow() { visible=true };
|
||||
list_box_row.add(device_box);
|
||||
micro_list_box.add(list_box_row);
|
||||
|
@ -73,10 +80,10 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover {
|
|||
Gee.List<Plugins.MediaDevice> devices = call_plugin.get_devices("audio", true);
|
||||
|
||||
Box speaker_box = new Box(Orientation.VERTICAL, 10) { visible=true };
|
||||
speaker_box.add(new Label("<b>" + "Speakers" +"</b>") { use_markup=true, xalign=0, visible=true });
|
||||
speaker_box.add(new Label("<b>" + _("Speakers") +"</b>") { use_markup=true, xalign=0, visible=true });
|
||||
|
||||
if (devices.size == 0) {
|
||||
speaker_box.add(new Label("No speakers found."));
|
||||
speaker_box.add(new Label(_("No speakers found.")));
|
||||
} else {
|
||||
ListBox speaker_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true };
|
||||
speaker_list_box.set_header_func(listbox_header_func);
|
||||
|
@ -86,7 +93,11 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover {
|
|||
Frame speaker_frame = new Frame(null) { visible=true };
|
||||
speaker_frame.add(speaker_list_box);
|
||||
foreach (Plugins.MediaDevice device in devices) {
|
||||
Label label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label display_name_label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true };
|
||||
detail_name_label.get_style_context().add_class("dim-label");
|
||||
detail_name_label.attributes = new Pango.AttrList();
|
||||
detail_name_label.attributes.insert(Pango.attr_scale_new(0.8));
|
||||
Image image = new Image.from_icon_name("object-select-symbolic", IconSize.BUTTON) { visible=true };
|
||||
if (current_speaker_device == null || current_speaker_device.id != device.id) {
|
||||
image.opacity = 0;
|
||||
|
@ -100,7 +111,10 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover {
|
|||
});
|
||||
Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, margin=7, visible=true };
|
||||
device_box.add(image);
|
||||
device_box.add(label);
|
||||
Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true };
|
||||
label_box.add(display_name_label);
|
||||
label_box.add(detail_name_label);
|
||||
device_box.add(label_box);
|
||||
ListBoxRow list_box_row = new ListBoxRow() { visible=true };
|
||||
list_box_row.add(device_box);
|
||||
speaker_list_box.add(list_box_row);
|
||||
|
|
|
@ -271,12 +271,9 @@ public class Dino.Ui.CallWindowController : Object {
|
|||
private void update_audio_device_choices() {
|
||||
if (call_plugin.get_devices("audio", true).size == 0 || call_plugin.get_devices("audio", false).size == 0) {
|
||||
call_window.bottom_bar.show_audio_device_error();
|
||||
} /*else if (call_plugin.get_devices("audio", true).size == 1 && call_plugin.get_devices("audio", false).size == 1) {
|
||||
} else if (call_plugin.get_devices("audio", true).size == 1 && call_plugin.get_devices("audio", false).size == 1) {
|
||||
call_window.bottom_bar.show_audio_device_choices(false);
|
||||
return;
|
||||
}*/ else {
|
||||
call_window.bottom_bar.show_video_device_choices(false);
|
||||
return;
|
||||
}
|
||||
|
||||
AudioSettingsPopover? audio_settings_popover = call_window.bottom_bar.show_audio_device_choices(true);
|
||||
|
@ -290,11 +287,6 @@ public class Dino.Ui.CallWindowController : Object {
|
|||
call_state.set_audio_device(device);
|
||||
update_current_audio_device(audio_settings_popover);
|
||||
});
|
||||
// calls.stream_created.connect((call, media) => {
|
||||
// if (media == "audio") {
|
||||
// update_current_audio_device(audio_settings_popover);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private void update_current_audio_device(AudioSettingsPopover audio_settings_popover) {
|
||||
|
@ -307,10 +299,7 @@ public class Dino.Ui.CallWindowController : Object {
|
|||
|
||||
if (device_count == 0) {
|
||||
call_window.bottom_bar.show_video_device_error();
|
||||
} /*else if (device_count == 1 || call_state.get_video_device() == null) {
|
||||
call_window.bottom_bar.show_video_device_choices(false);
|
||||
return;
|
||||
}*/ else {
|
||||
} else if (device_count == 1 || call_state.get_video_device() == null) {
|
||||
call_window.bottom_bar.show_video_device_choices(false);
|
||||
return;
|
||||
}
|
||||
|
@ -323,11 +312,6 @@ public class Dino.Ui.CallWindowController : Object {
|
|||
update_current_video_device(video_settings_popover);
|
||||
own_video.display_device(device);
|
||||
});
|
||||
// call_state.stream_created.connect((call, media) => {
|
||||
// if (media == "video") {
|
||||
// update_current_video_device(video_settings_popover);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private void update_current_video_device(VideoSettingsPopover video_settings_popover) {
|
||||
|
|
|
@ -22,17 +22,21 @@ public class Dino.Ui.VideoSettingsPopover : Gtk.Popover {
|
|||
Gee.List<Plugins.MediaDevice> devices = call_plugin.get_devices("video", false);
|
||||
|
||||
Box camera_box = new Box(Orientation.VERTICAL, 10) { visible=true };
|
||||
camera_box.add(new Label("<b>" + "Cameras" + "</b>") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ });
|
||||
camera_box.add(new Label("<b>" + _("Cameras") + "</b>") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ });
|
||||
|
||||
if (devices.size == 0) {
|
||||
camera_box.add(new Label("No cameras found.") { visible=true });
|
||||
camera_box.add(new Label(_("No cameras found.")) { visible=true });
|
||||
} else {
|
||||
ListBox list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true };
|
||||
list_box.set_header_func(listbox_header_func);
|
||||
Frame frame = new Frame(null) { visible=true };
|
||||
frame.add(list_box);
|
||||
foreach (Plugins.MediaDevice device in devices) {
|
||||
Label label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label display_name_label = new Label(device.display_name) { xalign=0, visible=true };
|
||||
Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true };
|
||||
detail_name_label.get_style_context().add_class("dim-label");
|
||||
detail_name_label.attributes = new Pango.AttrList();
|
||||
detail_name_label.attributes.insert(Pango.attr_scale_new(0.8));
|
||||
Image image = new Image.from_icon_name("object-select-symbolic", IconSize.BUTTON) { visible=true };
|
||||
if (current_device == null || current_device.id != device.id) {
|
||||
image.opacity = 0;
|
||||
|
@ -46,7 +50,10 @@ public class Dino.Ui.VideoSettingsPopover : Gtk.Popover {
|
|||
});
|
||||
Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, margin=7, visible=true };
|
||||
device_box.add(image);
|
||||
device_box.add(label);
|
||||
Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true };
|
||||
label_box.add(display_name_label);
|
||||
label_box.add(detail_name_label);
|
||||
device_box.add(label_box);
|
||||
ListBoxRow list_box_row = new ListBoxRow() { visible=true };
|
||||
list_box_row.add(device_box);
|
||||
list_box.add(list_box_row);
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
using Xmpp.Xep.JingleRtp;
|
||||
using Gee;
|
||||
|
||||
public enum Dino.Plugins.Rtp.DeviceProtocol {
|
||||
OTHER,
|
||||
PIPEWIRE,
|
||||
V4L2,
|
||||
PULSEAUDIO,
|
||||
ALSA
|
||||
}
|
||||
|
||||
public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
|
||||
private const int[] common_widths = {320, 360, 400, 480, 640, 960, 1280, 1920, 2560, 3840};
|
||||
|
||||
|
@ -8,10 +16,10 @@ public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
|
|||
public CodecUtil codec_util { get { return plugin.codec_util; } }
|
||||
public Gst.Device device { get; private set; }
|
||||
|
||||
public string id { get { return device_name; }}
|
||||
public string display_name { get { return device_display_name; }}
|
||||
public string detail_name { get {
|
||||
return device.properties.get_string("alsa.card_name") ?? device.properties.get_string("alsa.id") ?? id;
|
||||
public string id { owned get { return device_name; }}
|
||||
public string display_name { owned get { return device_display_name; }}
|
||||
public string detail_name { owned get {
|
||||
return device.properties.get_string("alsa.card_name") ?? device.properties.get_string("alsa.name") ?? device.properties.get_string("alsa.id") ?? device.properties.get_string("api.v4l2.cap.card") ?? id;
|
||||
}}
|
||||
|
||||
public Gst.Pipeline pipe { get { return plugin.pipe; }}
|
||||
|
@ -26,6 +34,18 @@ public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
|
|||
}}
|
||||
public bool is_source { get { return device.has_classes("Source"); }}
|
||||
public bool is_sink { get { return device.has_classes("Sink"); }}
|
||||
public bool is_monitor { get { return device.properties.get_string("device.class") == "monitor" || (protocol == DeviceProtocol.PIPEWIRE && device.has_classes("Stream")); } }
|
||||
public bool is_default { get {
|
||||
bool ret;
|
||||
device.properties.get_boolean("is-default", out ret);
|
||||
return ret;
|
||||
}}
|
||||
public DeviceProtocol protocol { get {
|
||||
if (device.properties.has_name("pulse-proplist")) return DeviceProtocol.PULSEAUDIO;
|
||||
if (device.properties.has_name("pipewire-proplist")) return DeviceProtocol.PIPEWIRE;
|
||||
if (device.properties.has_name("v4l2deviceprovider")) return DeviceProtocol.V4L2;
|
||||
return DeviceProtocol.OTHER;
|
||||
}}
|
||||
|
||||
private string device_name;
|
||||
private string device_display_name;
|
||||
|
|
|
@ -203,8 +203,6 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
|||
switch (message.type) {
|
||||
case Gst.MessageType.DEVICE_ADDED:
|
||||
message.parse_device_added(out gst_device);
|
||||
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||
if (devices.any_match((it) => it.matches(gst_device))) return Source.CONTINUE;
|
||||
device = new Device(this, gst_device);
|
||||
devices.add(device);
|
||||
|
@ -212,16 +210,12 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
|||
#if GST_1_16
|
||||
case Gst.MessageType.DEVICE_CHANGED:
|
||||
message.parse_device_changed(out gst_device, out old_gst_device);
|
||||
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||
device = devices.first_match((it) => it.matches(old_gst_device));
|
||||
if (device != null) device.update(gst_device);
|
||||
break;
|
||||
#endif
|
||||
case Gst.MessageType.DEVICE_REMOVED:
|
||||
message.parse_device_removed(out gst_device);
|
||||
if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
|
||||
if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
|
||||
device = devices.first_match((it) => it.matches(gst_device));
|
||||
if (device != null) devices.remove(device);
|
||||
break;
|
||||
|
@ -310,46 +304,42 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
|||
}
|
||||
|
||||
public Gee.List<MediaDevice> get_devices(string media, bool incoming) {
|
||||
|
||||
Gee.List<MediaDevice> devices;
|
||||
if (media == "video" && !incoming) {
|
||||
return get_video_sources();
|
||||
devices = get_video_sources();
|
||||
} else if (media == "audio") {
|
||||
devices = get_audio_devices(incoming);
|
||||
} else {
|
||||
devices = new ArrayList<MediaDevice>();
|
||||
devices.add_all_iterator(this.devices.filter(it => it.media == media && (incoming && it.is_sink || !incoming && it.is_source) && !it.is_monitor));
|
||||
}
|
||||
devices.sort((media_left, media_right) => {
|
||||
return strcmp(media_left.id, media_right.id);
|
||||
});
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
public Gee.List<MediaDevice> get_audio_devices(bool incoming) {
|
||||
ArrayList<MediaDevice> pulse_devices = new ArrayList<MediaDevice>();
|
||||
ArrayList<MediaDevice> other_devices = new ArrayList<MediaDevice>();
|
||||
|
||||
ArrayList<MediaDevice> result = new ArrayList<MediaDevice>();
|
||||
foreach (Device device in devices) {
|
||||
if (device.media == media && (incoming && device.is_sink || !incoming && device.is_source)) {
|
||||
result.add(device);
|
||||
if (device.media != "audio") continue;
|
||||
if (incoming && !device.is_sink || !incoming && !device.is_source) continue;
|
||||
|
||||
// Skip monitors
|
||||
if (device.is_monitor) continue;
|
||||
|
||||
if (device.protocol == DeviceProtocol.PULSEAUDIO) {
|
||||
pulse_devices.add(device);
|
||||
} else {
|
||||
other_devices.add(device);
|
||||
}
|
||||
}
|
||||
if (media == "audio") {
|
||||
// Reorder sources
|
||||
result.sort((media_left, media_right) => {
|
||||
Device left = media_left as Device;
|
||||
Device right = media_right as Device;
|
||||
if (left == null) return 1;
|
||||
if (right == null) return -1;
|
||||
|
||||
bool left_is_pipewire = left.device.properties.has_name("pipewire-proplist");
|
||||
bool right_is_pipewire = right.device.properties.has_name("pipewire-proplist");
|
||||
|
||||
bool left_is_default = false;
|
||||
left.device.properties.get_boolean("is-default", out left_is_default);
|
||||
bool right_is_default = false;
|
||||
right.device.properties.get_boolean("is-default", out right_is_default);
|
||||
|
||||
// Prefer pipewire
|
||||
if (left_is_pipewire && !right_is_pipewire) return -1;
|
||||
if (right_is_pipewire && !left_is_pipewire) return 1;
|
||||
|
||||
// Prefer pulse audio default device
|
||||
if (left_is_default && !right_is_default) return -1;
|
||||
if (right_is_default && !left_is_default) return 1;
|
||||
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
// If we have any pulseaudio devices, present only those. Don't want duplicated devices from pipewire and pulseaudio.
|
||||
return pulse_devices.size > 0 ? pulse_devices : other_devices;
|
||||
}
|
||||
|
||||
public Gee.List<MediaDevice> get_video_sources() {
|
||||
|
@ -371,7 +361,10 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
|||
// Don't allow grey-scale devices
|
||||
if (!is_color) continue;
|
||||
|
||||
if (device.device.properties.has_name("pipewire-proplist")) {
|
||||
// Skip monitors
|
||||
if (device.is_monitor) continue;
|
||||
|
||||
if (device.protocol == DeviceProtocol.PIPEWIRE) {
|
||||
pipewire_devices.add(device);
|
||||
} else {
|
||||
other_devices.add(device);
|
||||
|
@ -379,46 +372,56 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
|
|||
}
|
||||
|
||||
// If we have any pipewire devices, present only those. Don't want duplicated devices from pipewire and video for linux.
|
||||
ArrayList<MediaDevice> devices = pipewire_devices.size > 0 ? pipewire_devices : other_devices;
|
||||
return pipewire_devices.size > 0 ? pipewire_devices : other_devices;
|
||||
}
|
||||
|
||||
// Reorder sources
|
||||
devices.sort((media_left, media_right) => {
|
||||
Device left = media_left as Device;
|
||||
Device right = media_right as Device;
|
||||
if (left == null) return 1;
|
||||
if (right == null) return -1;
|
||||
|
||||
int left_fps = 0;
|
||||
for (int i = 0; i < left.device.caps.get_size(); i++) {
|
||||
unowned Gst.Structure structure = left.device.caps.get_structure(i);
|
||||
int num = 0, den = 0;
|
||||
if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) left_fps = int.max(left_fps, num / den);
|
||||
}
|
||||
|
||||
int right_fps = 0;
|
||||
for (int i = 0; i < left.device.caps.get_size(); i++) {
|
||||
unowned Gst.Structure structure = left.device.caps.get_structure(i);
|
||||
int num = 0, den = 0;
|
||||
if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) right_fps = int.max(right_fps, num / den);
|
||||
}
|
||||
|
||||
// More FPS is better
|
||||
if (left_fps > right_fps) return -1;
|
||||
if (right_fps > left_fps) return 1;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return devices;
|
||||
private int get_max_fps(Device device) {
|
||||
int fps = 0;
|
||||
for (int i = 0; i < device.device.caps.get_size(); i++) {
|
||||
unowned Gst.Structure structure = device.device.caps.get_structure(i);
|
||||
int num = 0, den = 0;
|
||||
if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) fps = int.max(fps, num / den);
|
||||
}
|
||||
return fps;
|
||||
}
|
||||
|
||||
public Device? get_preferred_device(string media, bool incoming) {
|
||||
Gee.List<Device> devices = new ArrayList<Device>();
|
||||
foreach (MediaDevice media_device in get_devices(media, incoming)) {
|
||||
Device? device = media_device as Device;
|
||||
if (device != null) return device;
|
||||
if (media_device is Device) devices.add((Device)media_device);
|
||||
}
|
||||
if (devices.is_empty) {
|
||||
warning("No preferred device for %s %s. Media will not be processed.", incoming ? "incoming" : "outgoing", media);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Take default if present
|
||||
foreach (Device device in devices) {
|
||||
if (device.is_default) {
|
||||
debug("Using %s for %s %s as it's default", device.display_name, incoming ? "incoming" : "outgoing", media);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
if (media == "video") {
|
||||
// Pick best FPS
|
||||
int max_fps = 0;
|
||||
Device? max_fps_device = null;
|
||||
foreach (Device device in devices) {
|
||||
int fps = get_max_fps(device);
|
||||
if (fps > max_fps) {
|
||||
max_fps = fps;
|
||||
max_fps_device = device;
|
||||
}
|
||||
}
|
||||
debug("Using %s for %s %s as it has max FPS (%d)", max_fps_device.display_name, incoming ? "incoming" : "outgoing", media, max_fps);
|
||||
return max_fps_device;
|
||||
} else {
|
||||
// Pick any
|
||||
Device? device = devices.first();
|
||||
debug("Using %s for %s %s as it's first pick", device.display_name, incoming ? "incoming" : "outgoing", media);
|
||||
return device;
|
||||
}
|
||||
warning("No preferred device for %s %s. Media will not be processed.", incoming ? "incoming" : "outgoing", media);
|
||||
return null;
|
||||
}
|
||||
|
||||
public MediaDevice? get_device(Xmpp.Xep.JingleRtp.Stream stream, bool incoming) {
|
||||
|
|
|
@ -318,8 +318,6 @@ public class Dino.Plugins.Rtp.Stream : Xmpp.Xep.JingleRtp.Stream {
|
|||
}
|
||||
if (our_ssrc != buffer_ssrc) {
|
||||
warning("Sending RTP %s buffer seq %u with SSRC %u when our ssrc is %u", media, buffer_seq, buffer_ssrc, our_ssrc);
|
||||
} else {
|
||||
debug("Sending RTP %s buffer seq %u with SSRC %u", media, buffer_seq, buffer_ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue