net/webrtc: Extract BaseWebRTCSrc

Define a Base for all the webrtcsrc type elements
so they can all be derived from it. Similar to base
element defined for webrtcsink type elements

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1284>
This commit is contained in:
Taruntej Kanakamalla 2023-07-28 18:39:38 +05:30 committed by GStreamer Marge Bot
parent 3fcab67570
commit a0638ec983
3 changed files with 229 additions and 170 deletions

View file

@ -6440,6 +6440,7 @@
"description": "WebRTC src", "description": "WebRTC src",
"hierarchy": [ "hierarchy": [
"GstWebRTCSrc", "GstWebRTCSrc",
"GstBaseWebRTCSrc",
"GstBin", "GstBin",
"GstElement", "GstElement",
"GstObject", "GstObject",
@ -6466,108 +6467,7 @@
"type": "GstWebRTCSrcPad" "type": "GstWebRTCSrcPad"
} }
}, },
"properties": { "rank": "primary"
"audio-codecs": {
"blurb": "Names of audio codecs to be be used during the SDP negotiation. Valid values: [OPUS]",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
},
"enable-data-channel-navigation": {
"blurb": "Enable navigation events through a dedicated WebRTCDataChannel",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "ready",
"readable": true,
"type": "gboolean",
"writable": true
},
"meta": {
"blurb": "Free form metadata about the consumer",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstStructure",
"writable": true
},
"signaller": {
"blurb": "The Signallable object to use to handle WebRTC Signalling",
"conditionally-available": false,
"construct": false,
"construct-only": true,
"controllable": false,
"mutable": "null",
"readable": true,
"type": "GstRSWebRTCSignallableIface",
"writable": true
},
"stun-server": {
"blurb": "The STUN server of the form stun://host:port",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "stun://stun.l.google.com:19302",
"mutable": "ready",
"readable": true,
"type": "gchararray",
"writable": true
},
"turn-servers": {
"blurb": "The TURN servers of the form <\"turn(s)://username:password@host:port\", \"turn(s)://username1:password1@host1:port1\">",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
},
"video-codecs": {
"blurb": "Names of video codecs to be be used during the SDP negotiation. Valid values: [VP8, H264, VP9, H265]",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
}
},
"rank": "primary",
"signals": {
"request-encoded-filter": {
"args": [
{
"name": "arg0",
"type": "gchararray"
},
{
"name": "arg1",
"type": "gchararray"
},
{
"name": "arg2",
"type": "GstCaps"
}
],
"return-type": "GstElement",
"when": "last"
}
}
}, },
"whipclientsink": { "whipclientsink": {
"author": "Taruntej Kanakamalla <taruntej@asymptotic.io>", "author": "Taruntej Kanakamalla <taruntej@asymptotic.io>",
@ -6890,6 +6790,121 @@
} }
} }
}, },
"GstBaseWebRTCSrc": {
"hierarchy": [
"GstBaseWebRTCSrc",
"GstBin",
"GstElement",
"GstObject",
"GInitiallyUnowned",
"GObject"
],
"interfaces": [
"GstChildProxy"
],
"kind": "object",
"properties": {
"audio-codecs": {
"blurb": "Names of audio codecs to be be used during the SDP negotiation. Valid values: [OPUS]",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
},
"enable-data-channel-navigation": {
"blurb": "Enable navigation events through a dedicated WebRTCDataChannel",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "ready",
"readable": true,
"type": "gboolean",
"writable": true
},
"meta": {
"blurb": "Free form metadata about the consumer",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstStructure",
"writable": true
},
"signaller": {
"blurb": "The Signallable object to use to handle WebRTC Signalling",
"conditionally-available": false,
"construct": false,
"construct-only": true,
"controllable": false,
"mutable": "null",
"readable": true,
"type": "GstRSWebRTCSignallableIface",
"writable": true
},
"stun-server": {
"blurb": "The STUN server of the form stun://host:port",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "stun://stun.l.google.com:19302",
"mutable": "ready",
"readable": true,
"type": "gchararray",
"writable": true
},
"turn-servers": {
"blurb": "The TURN servers of the form <\"turn(s)://username:password@host:port\", \"turn(s)://username1:password1@host1:port1\">",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
},
"video-codecs": {
"blurb": "Names of video codecs to be be used during the SDP negotiation. Valid values: [VP8, H264, VP9, H265]",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"mutable": "ready",
"readable": true,
"type": "GstValueArray",
"writable": true
}
},
"signals": {
"request-encoded-filter": {
"args": [
{
"name": "arg0",
"type": "gchararray"
},
{
"name": "arg1",
"type": "gchararray"
},
{
"name": "arg2",
"type": "GstCaps"
}
],
"return-type": "GstElement",
"when": "last"
}
}
},
"GstRSWebRTCSignallableIface": { "GstRSWebRTCSignallableIface": {
"hierarchy": [ "hierarchy": [
"GstRSWebRTCSignallableIface", "GstRSWebRTCSignallableIface",

View file

@ -43,7 +43,7 @@ struct Settings {
} }
#[derive(Default)] #[derive(Default)]
pub struct WebRTCSrc { pub struct BaseWebRTCSrc {
settings: Mutex<Settings>, settings: Mutex<Settings>,
n_video_pads: AtomicU16, n_video_pads: AtomicU16,
n_audio_pads: AtomicU16, n_audio_pads: AtomicU16,
@ -51,14 +51,21 @@ pub struct WebRTCSrc {
} }
#[glib::object_subclass] #[glib::object_subclass]
impl ObjectSubclass for WebRTCSrc { impl ObjectSubclass for BaseWebRTCSrc {
const NAME: &'static str = "GstWebRTCSrc"; const NAME: &'static str = "GstBaseWebRTCSrc";
type Type = super::WebRTCSrc; type Type = super::BaseWebRTCSrc;
type ParentType = gst::Bin; type ParentType = gst::Bin;
type Interfaces = (gst::URIHandler, gst::ChildProxy); type Interfaces = (gst::ChildProxy,);
} }
impl ObjectImpl for WebRTCSrc { unsafe impl<T: BaseWebRTCSrcImpl> IsSubclassable<T> for super::BaseWebRTCSrc {
fn class_init(class: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(class);
}
}
pub(crate) trait BaseWebRTCSrcImpl: BinImpl {}
impl ObjectImpl for BaseWebRTCSrc {
fn properties() -> &'static [glib::ParamSpec] { fn properties() -> &'static [glib::ParamSpec] {
static PROPS: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { static PROPS: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![ vec![
@ -205,7 +212,7 @@ impl ObjectImpl for WebRTCSrc {
static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| { static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
vec![ vec![
/** /**
* WebRTCSrc::request-encoded-filter: * BaseWebRTCSrc::request-encoded-filter:
* @producer_id: Identifier of the producer * @producer_id: Identifier of the producer
* @pad_name: The name of the output pad * @pad_name: The name of the output pad
* @allowed_caps: the allowed caps for the output pad * @allowed_caps: the allowed caps for the output pad
@ -278,7 +285,7 @@ struct SignallerSignals {
handle_ice: glib::SignalHandlerId, handle_ice: glib::SignalHandlerId,
} }
impl WebRTCSrc { impl BaseWebRTCSrc {
fn webrtcbin(&self) -> gst::Bin { fn webrtcbin(&self) -> gst::Bin {
let state = self.state.lock().unwrap(); let state = self.state.lock().unwrap();
let webrtcbin = state let webrtcbin = state
@ -562,15 +569,22 @@ impl WebRTCSrc {
let mline = transceiver.map_or(mline, |t| Some(t.mlineindex())); let mline = transceiver.map_or(mline, |t| Some(t.mlineindex()));
// Same logic as gst_pad_create_stream_id and friends, making a hash of // Same logic as gst_pad_create_stream_id and friends, making a hash of
// the URI and adding `:<some-id>`, here the ID is the mline of the // the URI (session id, if URI doesn't exist) and adding `:<some-id>`, here the ID is the mline of the
// stream in the SDP. // stream in the SDP.
mline.map(|mline| { mline.map(|mline| {
let mut cs = glib::Checksum::new(glib::ChecksumType::Sha256).unwrap(); let mut cs = glib::Checksum::new(glib::ChecksumType::Sha256).unwrap();
cs.update(
self.uri() let data: String = if self
.expect("get_stream_id should never be called if no URI has been set") .signaller()
.as_bytes(), .has_property("uri", Some(String::static_type()))
); {
self.signaller().property::<Option<String>>("uri").unwrap()
} else {
// use the session id
self.state.lock().unwrap().session_id.clone().unwrap()
};
cs.update(data.as_bytes());
format!("{}:{mline}", cs.string().unwrap()) format!("{}:{mline}", cs.string().unwrap())
}) })
@ -983,20 +997,7 @@ impl WebRTCSrc {
} }
} }
impl ElementImpl for WebRTCSrc { impl ElementImpl for BaseWebRTCSrc {
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"WebRTCSrc",
"Source/Network/WebRTC",
"WebRTC src",
"Thibault Saunier <tsaunier@igalia.com>",
)
});
Some(&*ELEMENT_METADATA)
}
fn pad_templates() -> &'static [gst::PadTemplate] { fn pad_templates() -> &'static [gst::PadTemplate] {
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
let mut video_caps_builder = gst::Caps::builder_full() let mut video_caps_builder = gst::Caps::builder_full()
@ -1095,11 +1096,11 @@ impl ElementImpl for WebRTCSrc {
} }
} }
impl GstObjectImpl for WebRTCSrc {} impl GstObjectImpl for BaseWebRTCSrc {}
impl BinImpl for WebRTCSrc {} impl BinImpl for BaseWebRTCSrc {}
impl ChildProxyImpl for WebRTCSrc { impl ChildProxyImpl for BaseWebRTCSrc {
fn child_by_index(&self, index: u32) -> Option<glib::Object> { fn child_by_index(&self, index: u32) -> Option<glib::Object> {
if index == 0 { if index == 0 {
Some(self.signaller().upcast()) Some(self.signaller().upcast())
@ -1123,42 +1124,6 @@ impl ChildProxyImpl for WebRTCSrc {
} }
} }
impl URIHandlerImpl for WebRTCSrc {
const URI_TYPE: gst::URIType = gst::URIType::Src;
fn protocols() -> &'static [&'static str] {
&["gstwebrtc", "gstwebrtcs"]
}
fn uri(&self) -> Option<String> {
self.signaller().property::<Option<String>>("uri")
}
fn set_uri(&self, uri: &str) -> Result<(), glib::Error> {
let uri = Url::from_str(uri)
.map_err(|err| glib::Error::new(gst::URIError::BadUri, &format!("{:?}", err)))?;
let socket_scheme = match uri.scheme() {
"gstwebrtc" => Ok("ws"),
"gstwebrtcs" => Ok("wss"),
_ => Err(glib::Error::new(
gst::URIError::BadUri,
&format!("Invalid protocol: {}", uri.scheme()),
)),
}?;
let mut url_str = uri.to_string();
// Not using `set_scheme()` because it doesn't work with `http`
// See https://github.com/servo/rust-url/pull/768 for a PR implementing that
url_str.replace_range(0..uri.scheme().len(), socket_scheme);
self.signaller().set_property("uri", &url_str);
Ok(())
}
}
#[derive(PartialEq)] #[derive(PartialEq)]
enum SignallerState { enum SignallerState {
Started, Started,
@ -1186,3 +1151,77 @@ impl Default for State {
} }
} }
} }
#[derive(Default)]
pub struct WebRTCSrc {}
impl ObjectImpl for WebRTCSrc {}
impl GstObjectImpl for WebRTCSrc {}
impl BinImpl for WebRTCSrc {}
impl ElementImpl for WebRTCSrc {
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"WebRTCSrc",
"Source/Network/WebRTC",
"WebRTC src",
"Thibault Saunier <tsaunier@igalia.com>",
)
});
Some(&*ELEMENT_METADATA)
}
}
impl BaseWebRTCSrcImpl for WebRTCSrc {}
impl URIHandlerImpl for WebRTCSrc {
const URI_TYPE: gst::URIType = gst::URIType::Src;
fn protocols() -> &'static [&'static str] {
&["gstwebrtc", "gstwebrtcs"]
}
fn uri(&self) -> Option<String> {
let obj = self.obj();
let base = obj.upcast_ref::<super::BaseWebRTCSrc>().imp();
base.signaller().property::<Option<String>>("uri")
}
fn set_uri(&self, uri: &str) -> Result<(), glib::Error> {
let uri = Url::from_str(uri)
.map_err(|err| glib::Error::new(gst::URIError::BadUri, &format!("{:?}", err)))?;
let socket_scheme = match uri.scheme() {
"gstwebrtc" => Ok("ws"),
"gstwebrtcs" => Ok("wss"),
_ => Err(glib::Error::new(
gst::URIError::BadUri,
&format!("Invalid protocol: {}", uri.scheme()),
)),
}?;
let mut url_str = uri.to_string();
// Not using `set_scheme()` because it doesn't work with `http`
// See https://github.com/servo/rust-url/pull/768 for a PR implementing that
url_str.replace_range(0..uri.scheme().len(), socket_scheme);
let obj = self.obj();
let base = obj.upcast_ref::<super::BaseWebRTCSrc>().imp();
base.signaller().set_property("uri", &url_str);
Ok(())
}
}
#[glib::object_subclass]
impl ObjectSubclass for WebRTCSrc {
const NAME: &'static str = "GstWebRTCSrc";
type Type = super::WebRTCSrc;
type ParentType = super::BaseWebRTCSrc;
type Interfaces = (gst::URIHandler,);
}

View file

@ -42,7 +42,11 @@ use gst::prelude::*;
use gst::{glib, prelude::StaticType}; use gst::{glib, prelude::StaticType};
glib::wrapper! { glib::wrapper! {
pub struct WebRTCSrc(ObjectSubclass<imp::WebRTCSrc>) @extends gst::Bin, gst::Element, gst::Object, @implements gst::URIHandler, gst::ChildProxy; pub struct BaseWebRTCSrc(ObjectSubclass<imp::BaseWebRTCSrc>) @extends gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy;
}
glib::wrapper! {
pub struct WebRTCSrc(ObjectSubclass<imp::WebRTCSrc>) @extends BaseWebRTCSrc, gst::Bin, gst::Element, gst::Object, @implements gst::URIHandler, gst::ChildProxy;
} }
glib::wrapper! { glib::wrapper! {
@ -50,6 +54,7 @@ glib::wrapper! {
} }
pub fn register(plugin: Option<&gst::Plugin>) -> Result<(), glib::BoolError> { pub fn register(plugin: Option<&gst::Plugin>) -> Result<(), glib::BoolError> {
BaseWebRTCSrc::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
WebRTCSignallerRole::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); WebRTCSignallerRole::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
WebRTCSrcPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); WebRTCSrcPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
Signallable::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); Signallable::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());