2022-10-18 18:16:49 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-10-20 10:25:32 +00:00
|
|
|
/**
|
|
|
|
* element-webrtcsink:
|
|
|
|
*
|
|
|
|
* {{ net/webrtc/README.md[0:190] }}
|
|
|
|
*
|
|
|
|
*/
|
2021-10-05 21:28:05 +00:00
|
|
|
use gst::glib;
|
|
|
|
use gst::prelude::*;
|
2022-05-11 20:58:53 +00:00
|
|
|
use gst::subclass::prelude::*;
|
2021-12-21 22:37:29 +00:00
|
|
|
use std::error::Error;
|
2021-10-05 21:28:05 +00:00
|
|
|
|
2022-07-28 03:22:25 +00:00
|
|
|
mod homegrown_cc;
|
2021-10-05 21:28:05 +00:00
|
|
|
mod imp;
|
|
|
|
|
|
|
|
glib::wrapper! {
|
2021-12-24 12:26:26 +00:00
|
|
|
pub struct WebRTCSink(ObjectSubclass<imp::WebRTCSink>) @extends gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy, gst_video::Navigation;
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for WebRTCSink {}
|
|
|
|
unsafe impl Sync for WebRTCSink {}
|
|
|
|
|
2021-12-21 22:37:29 +00:00
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
pub enum WebRTCSinkError {
|
2022-07-14 18:25:12 +00:00
|
|
|
#[error("no session with id")]
|
|
|
|
NoSessionWithId(String),
|
2021-12-21 22:37:29 +00:00
|
|
|
#[error("consumer refused media")]
|
2022-07-14 18:25:12 +00:00
|
|
|
ConsumerRefusedMedia { session_id: String, media_idx: u32 },
|
2021-12-21 22:37:29 +00:00
|
|
|
#[error("consumer did not provide valid payload for media")]
|
2022-07-14 18:25:12 +00:00
|
|
|
ConsumerNoValidPayload { session_id: String, media_idx: u32 },
|
2021-12-21 22:37:29 +00:00
|
|
|
#[error("SDP mline index is currently mandatory")]
|
|
|
|
MandatorySdpMlineIndex,
|
2022-07-14 18:25:12 +00:00
|
|
|
#[error("duplicate session id")]
|
|
|
|
DuplicateSessionId(String),
|
2021-12-21 22:37:29 +00:00
|
|
|
#[error("error setting up consumer pipeline")]
|
2022-07-14 18:25:12 +00:00
|
|
|
SessionPipelineError {
|
|
|
|
session_id: String,
|
|
|
|
peer_id: String,
|
|
|
|
details: String,
|
|
|
|
},
|
2021-12-21 22:37:29 +00:00
|
|
|
}
|
|
|
|
|
2021-10-05 21:28:05 +00:00
|
|
|
pub trait Signallable: Sync + Send + 'static {
|
2021-12-21 22:37:29 +00:00
|
|
|
fn start(&mut self, element: &WebRTCSink) -> Result<(), Box<dyn Error>>;
|
2021-10-05 21:28:05 +00:00
|
|
|
|
|
|
|
fn handle_sdp(
|
|
|
|
&mut self,
|
|
|
|
element: &WebRTCSink,
|
2022-07-14 18:25:12 +00:00
|
|
|
session_id: &str,
|
2021-10-05 21:28:05 +00:00
|
|
|
sdp: &gst_webrtc::WebRTCSessionDescription,
|
2021-12-21 22:37:29 +00:00
|
|
|
) -> Result<(), Box<dyn Error>>;
|
2021-10-05 21:28:05 +00:00
|
|
|
|
|
|
|
/// sdp_mid is exposed for future proofing, see
|
|
|
|
/// https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1174,
|
2022-03-03 03:30:44 +00:00
|
|
|
/// at the moment sdp_m_line_index will always be Some and sdp_mid will always
|
2021-10-05 21:28:05 +00:00
|
|
|
/// be None
|
|
|
|
fn handle_ice(
|
|
|
|
&mut self,
|
|
|
|
element: &WebRTCSink,
|
2022-07-14 18:25:12 +00:00
|
|
|
session_id: &str,
|
2021-10-05 21:28:05 +00:00
|
|
|
candidate: &str,
|
2022-03-03 03:30:44 +00:00
|
|
|
sdp_m_line_index: Option<u32>,
|
2021-10-05 21:28:05 +00:00
|
|
|
sdp_mid: Option<String>,
|
2021-12-21 22:37:29 +00:00
|
|
|
) -> Result<(), Box<dyn Error>>;
|
2021-10-05 21:28:05 +00:00
|
|
|
|
2022-07-14 18:25:12 +00:00
|
|
|
fn session_ended(&mut self, element: &WebRTCSink, session_id: &str);
|
2021-10-05 21:28:05 +00:00
|
|
|
|
|
|
|
fn stop(&mut self, element: &WebRTCSink);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// When providing a signaller, we expect it to both be a GObject
|
|
|
|
/// and be Signallable. This is arguably a bit strange, but exposing
|
|
|
|
/// a GInterface from rust is at the moment a bit awkward, so I went
|
|
|
|
/// for a rust interface for now. The reason the signaller needs to be
|
|
|
|
/// a GObject is to make its properties available through the GstChildProxy
|
|
|
|
/// interface.
|
|
|
|
pub trait SignallableObject: AsRef<glib::Object> + Signallable {}
|
|
|
|
|
|
|
|
impl<T: AsRef<glib::Object> + Signallable> SignallableObject for T {}
|
|
|
|
|
2021-12-26 10:02:09 +00:00
|
|
|
impl Default for WebRTCSink {
|
|
|
|
fn default() -> Self {
|
2023-01-31 10:24:07 +00:00
|
|
|
glib::Object::new()
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
2021-12-26 10:02:09 +00:00
|
|
|
}
|
2021-10-05 21:28:05 +00:00
|
|
|
|
2021-12-26 10:02:09 +00:00
|
|
|
impl WebRTCSink {
|
2021-10-05 21:28:05 +00:00
|
|
|
pub fn with_signaller(signaller: Box<dyn SignallableObject>) -> Self {
|
2023-01-31 10:24:07 +00:00
|
|
|
let ret = glib::Object::new::<WebRTCSink>();
|
2021-10-05 21:28:05 +00:00
|
|
|
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = ret.imp();
|
2021-10-05 21:28:05 +00:00
|
|
|
ws.set_signaller(signaller).unwrap();
|
|
|
|
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn handle_sdp(
|
|
|
|
&self,
|
2022-07-14 18:25:12 +00:00
|
|
|
session_id: &str,
|
2021-10-05 21:28:05 +00:00
|
|
|
sdp: &gst_webrtc::WebRTCSessionDescription,
|
2021-12-21 22:37:29 +00:00
|
|
|
) -> Result<(), WebRTCSinkError> {
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = self.imp();
|
2022-07-14 18:25:12 +00:00
|
|
|
ws.handle_sdp(self, session_id, sdp)
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// sdp_mid is exposed for future proofing, see
|
|
|
|
/// https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1174,
|
2022-03-03 03:30:44 +00:00
|
|
|
/// at the moment sdp_m_line_index must be Some
|
2021-10-05 21:28:05 +00:00
|
|
|
pub fn handle_ice(
|
|
|
|
&self,
|
2022-07-14 18:25:12 +00:00
|
|
|
session_id: &str,
|
2022-03-03 03:30:44 +00:00
|
|
|
sdp_m_line_index: Option<u32>,
|
2021-10-05 21:28:05 +00:00
|
|
|
sdp_mid: Option<String>,
|
|
|
|
candidate: &str,
|
2021-12-21 22:37:29 +00:00
|
|
|
) -> Result<(), WebRTCSinkError> {
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = self.imp();
|
2022-07-14 18:25:12 +00:00
|
|
|
ws.handle_ice(self, session_id, sdp_m_line_index, sdp_mid, candidate)
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
|
2021-12-21 22:37:29 +00:00
|
|
|
pub fn handle_signalling_error(&self, error: Box<dyn Error + Send + Sync>) {
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = self.imp();
|
2021-12-21 22:37:29 +00:00
|
|
|
ws.handle_signalling_error(self, anyhow::anyhow!(error));
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
|
2022-07-14 18:25:12 +00:00
|
|
|
pub fn start_session(&self, session_id: &str, peer_id: &str) -> Result<(), WebRTCSinkError> {
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = self.imp();
|
2022-07-14 18:25:12 +00:00
|
|
|
ws.start_session(self, session_id, peer_id)
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
|
2022-07-14 18:25:12 +00:00
|
|
|
pub fn end_session(&self, session_id: &str) -> Result<(), WebRTCSinkError> {
|
2022-10-23 20:03:22 +00:00
|
|
|
let ws = self.imp();
|
2022-07-14 18:25:12 +00:00
|
|
|
ws.remove_session(self, session_id, false)
|
2021-10-05 21:28:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 14:05:44 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)]
|
2021-11-04 17:26:50 +00:00
|
|
|
#[repr(u32)]
|
2021-11-24 14:05:44 +00:00
|
|
|
#[enum_type(name = "GstWebRTCSinkCongestionControl")]
|
2021-11-04 17:26:50 +00:00
|
|
|
pub enum WebRTCSinkCongestionControl {
|
2021-11-24 14:05:44 +00:00
|
|
|
#[enum_value(name = "Disabled: no congestion control is applied", nick = "disabled")]
|
2021-11-04 17:26:50 +00:00
|
|
|
Disabled,
|
2021-11-24 14:05:44 +00:00
|
|
|
#[enum_value(name = "Homegrown: simple sender-side heuristic", nick = "homegrown")]
|
2021-11-04 17:26:50 +00:00
|
|
|
Homegrown,
|
2022-05-11 20:58:53 +00:00
|
|
|
#[enum_value(name = "Google Congestion Control algorithm", nick = "gcc")]
|
|
|
|
GoogleCongestionControl,
|
2021-11-04 17:26:50 +00:00
|
|
|
}
|
|
|
|
|
2021-11-30 21:43:17 +00:00
|
|
|
#[glib::flags(name = "GstWebRTCSinkMitigationMode")]
|
|
|
|
enum WebRTCSinkMitigationMode {
|
|
|
|
#[flags_value(name = "No mitigation applied", nick = "none")]
|
|
|
|
NONE = 0b00000000,
|
|
|
|
#[flags_value(name = "Lowered resolution", nick = "downscaled")]
|
|
|
|
DOWNSCALED = 0b00000001,
|
|
|
|
#[flags_value(name = "Lowered framerate", nick = "downsampled")]
|
|
|
|
DOWNSAMPLED = 0b00000010,
|
|
|
|
}
|
|
|
|
|
2021-10-05 21:28:05 +00:00
|
|
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
2022-08-16 14:44:41 +00:00
|
|
|
WebRTCSinkCongestionControl::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
2021-10-05 21:28:05 +00:00
|
|
|
gst::Element::register(
|
|
|
|
Some(plugin),
|
|
|
|
"webrtcsink",
|
|
|
|
gst::Rank::None,
|
|
|
|
WebRTCSink::static_type(),
|
|
|
|
)
|
|
|
|
}
|