gst-plugins-rs/generic/threadshare/src/udpsink/imp.rs

1256 lines
44 KiB
Rust
Raw Normal View History

// Copyright (C) 2019 Mathieu Duponchelle <mathieu@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.
//
// SPDX-License-Identifier: LGPL-2.1-or-later
use futures::future::BoxFuture;
use futures::prelude::*;
2021-06-03 18:20:54 +00:00
use gst::glib;
use gst::prelude::*;
use gst::subclass::prelude::*;
use gst::EventView;
use gst::{element_error, error_msg};
use once_cell::sync::Lazy;
use crate::runtime::executor::block_on_or_add_sub_task;
use crate::runtime::prelude::*;
use crate::runtime::{self, Async, Context, PadSink};
use crate::socket::{wrap_socket, GioSocketWrapper};
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
use std::collections::BTreeSet;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::u16;
use std::u8;
const DEFAULT_HOST: Option<&str> = Some("127.0.0.1");
const DEFAULT_PORT: i32 = 5004;
const DEFAULT_SYNC: bool = true;
const DEFAULT_BIND_ADDRESS: &str = "0.0.0.0";
const DEFAULT_BIND_PORT: i32 = 0;
const DEFAULT_BIND_ADDRESS_V6: &str = "::";
const DEFAULT_BIND_PORT_V6: i32 = 0;
const DEFAULT_SOCKET: Option<GioSocketWrapper> = None;
const DEFAULT_USED_SOCKET: Option<GioSocketWrapper> = None;
const DEFAULT_SOCKET_V6: Option<GioSocketWrapper> = None;
const DEFAULT_USED_SOCKET_V6: Option<GioSocketWrapper> = None;
const DEFAULT_AUTO_MULTICAST: bool = true;
const DEFAULT_LOOP: bool = true;
const DEFAULT_TTL: u32 = 64;
const DEFAULT_TTL_MC: u32 = 1;
const DEFAULT_QOS_DSCP: i32 = -1;
const DEFAULT_CLIENTS: &str = "";
const DEFAULT_CONTEXT: &str = "";
const DEFAULT_CONTEXT_WAIT: Duration = Duration::ZERO;
#[derive(Debug, Clone, Copy)]
struct SocketConf {
auto_multicast: bool,
multicast_loop: bool,
ttl: u32,
ttl_mc: u32,
}
impl Default for SocketConf {
fn default() -> Self {
SocketConf {
auto_multicast: DEFAULT_AUTO_MULTICAST,
multicast_loop: DEFAULT_LOOP,
ttl: DEFAULT_TTL,
ttl_mc: DEFAULT_TTL_MC,
}
}
}
#[derive(Debug, Clone)]
struct Settings {
sync: bool,
bind_address: String,
bind_port: i32,
bind_address_v6: String,
bind_port_v6: i32,
socket: Option<GioSocketWrapper>,
used_socket: Option<GioSocketWrapper>,
socket_v6: Option<GioSocketWrapper>,
used_socket_v6: Option<GioSocketWrapper>,
socket_conf: SocketConf,
qos_dscp: i32,
context: String,
context_wait: Duration,
}
impl Default for Settings {
fn default() -> Self {
Settings {
sync: DEFAULT_SYNC,
bind_address: DEFAULT_BIND_ADDRESS.into(),
bind_port: DEFAULT_BIND_PORT,
bind_address_v6: DEFAULT_BIND_ADDRESS_V6.into(),
bind_port_v6: DEFAULT_BIND_PORT_V6,
socket: DEFAULT_SOCKET,
used_socket: DEFAULT_USED_SOCKET,
socket_v6: DEFAULT_SOCKET_V6,
used_socket_v6: DEFAULT_USED_SOCKET_V6,
socket_conf: SocketConf::default(),
qos_dscp: DEFAULT_QOS_DSCP,
context: DEFAULT_CONTEXT.into(),
context_wait: DEFAULT_CONTEXT_WAIT,
}
}
}
2020-11-22 14:24:55 +00:00
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"ts-udpsink",
gst::DebugColorFlags::empty(),
Some("Thread-sharing UDP sink"),
2020-11-22 14:24:55 +00:00
)
});
#[derive(Clone, Debug, Default)]
struct UdpSinkPadHandler(Arc<futures::lock::Mutex<UdpSinkPadHandlerInner>>);
impl UdpSinkPadHandler {
fn prepare(
&self,
_imp: &UdpSink,
socket: Option<Async<UdpSocket>>,
socket_v6: Option<Async<UdpSocket>>,
settings: &Settings,
) -> Result<(), gst::ErrorMessage> {
futures::executor::block_on(async move {
let mut inner = self.0.lock().await;
inner.sync = settings.sync;
inner.socket_conf = settings.socket_conf;
inner.socket = socket;
inner.socket_v6 = socket_v6;
for addr in inner.clients.iter() {
inner.configure_client(addr)?;
}
Ok(())
})
}
fn unprepare(&self) {
futures::executor::block_on(async move {
let mut inner = self.0.lock().await;
for addr in inner.clients.iter() {
let _ = inner.unconfigure_client(addr);
}
inner.socket = None;
inner.socket_v6 = None;
})
}
fn start(&self) {
futures::executor::block_on(async move {
self.0.lock().await.is_flushing = false;
})
}
fn stop(&self) {
futures::executor::block_on(async move {
self.0.lock().await.is_flushing = true;
})
}
fn set_sync(&self, sync: bool) {
futures::executor::block_on(async move {
self.0.lock().await.sync = sync;
})
}
fn set_latency(&self, latency: Option<gst::ClockTime>) {
futures::executor::block_on(async move {
self.0.lock().await.latency = latency;
})
}
fn set_socket_conf(&self, socket_conf: SocketConf) {
futures::executor::block_on(async move {
self.0.lock().await.socket_conf = socket_conf;
})
}
fn clients(&self) -> BTreeSet<SocketAddr> {
futures::executor::block_on(async move { self.0.lock().await.clients.clone() })
}
fn add_client(&self, imp: &UdpSink, addr: SocketAddr) {
futures::executor::block_on(async move {
let mut inner = self.0.lock().await;
if inner.clients.contains(&addr) {
gst::warning!(CAT, imp: imp, "Not adding client {addr:?} again");
return;
}
match inner.configure_client(&addr) {
Ok(()) => {
gst::info!(CAT, imp: imp, "Added client {addr:?}");
inner.clients.insert(addr);
}
Err(err) => {
gst::error!(CAT, imp: imp, "Failed to add client {addr:?}: {err}");
imp.obj().post_error_message(err);
}
}
})
}
fn remove_client(&self, imp: &UdpSink, addr: SocketAddr) {
futures::executor::block_on(async move {
let mut inner = self.0.lock().await;
if inner.clients.take(&addr).is_none() {
gst::warning!(CAT, imp: imp, "Not removing unknown client {addr:?}");
return;
}
2020-03-26 18:07:25 +00:00
match inner.unconfigure_client(&addr) {
Ok(()) => {
gst::info!(CAT, imp: imp, "Removed client {addr:?}");
}
Err(err) => {
gst::error!(CAT, imp: imp, "Failed to remove client {addr:?}: {err}");
imp.obj().post_error_message(err);
}
}
})
}
fn replace_clients(&self, imp: &UdpSink, mut new_clients: BTreeSet<SocketAddr>) {
futures::executor::block_on(async move {
let mut inner = self.0.lock().await;
if new_clients.is_empty() {
gst::info!(CAT, imp: imp, "Clearing clients");
} else {
gst::info!(CAT, imp: imp, "Replacing clients");
}
let old_clients = std::mem::take(&mut inner.clients);
let mut res = Ok(());
for addr in old_clients.iter() {
if new_clients.take(addr).is_some() {
// client is already configured
inner.clients.insert(*addr);
} else if let Err(err) = inner.unconfigure_client(addr) {
gst::error!(CAT, imp: imp, "Failed to remove client {addr:?}: {err}");
res = Err(err);
} else {
gst::info!(CAT, imp: imp, "Removed client {addr:?}");
}
}
for addr in new_clients.into_iter() {
if let Err(err) = inner.configure_client(&addr) {
gst::error!(CAT, imp: imp, "Failed to add client {addr:?}: {err}");
res = Err(err);
} else {
gst::info!(CAT, imp: imp, "Added client {addr:?}");
inner.clients.insert(addr);
}
}
// FIXME: which error handling:
// - If at least one client could be configured, should we keep going? (current)
// - or, should we consider the preparation failed when the first client
// configuration fails? (previously)
if let Err(err) = res {
imp.obj().post_error_message(err);
}
})
}
}
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
impl PadSinkHandler for UdpSinkPadHandler {
type ElementImpl = UdpSink;
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
fn sink_chain(
self,
_pad: gst::Pad,
elem: super::UdpSink,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
buffer: gst::Buffer,
) -> BoxFuture<'static, Result<gst::FlowSuccess, gst::FlowError>> {
async move { self.0.lock().await.handle_buffer(&elem, buffer).await }.boxed()
2020-03-26 18:07:25 +00:00
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
fn sink_chain_list(
self,
_pad: gst::Pad,
elem: super::UdpSink,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
list: gst::BufferList,
) -> BoxFuture<'static, Result<gst::FlowSuccess, gst::FlowError>> {
async move {
let mut inner = self.0.lock().await;
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
for buffer in list.iter_owned() {
inner.handle_buffer(&elem, buffer).await?;
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
}
Ok(gst::FlowSuccess::Ok)
2020-03-26 18:07:25 +00:00
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
.boxed()
}
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
fn sink_event_serialized(
self,
_pad: gst::Pad,
elem: super::UdpSink,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
event: gst::Event,
) -> BoxFuture<'static, bool> {
async move {
gst::debug!(CAT, obj: elem, "Handling {event:?}");
match event.view() {
EventView::Eos(_) => {
let _ = elem.post_message(gst::message::Eos::builder().src(&elem).build());
}
EventView::Segment(e) => {
self.0.lock().await.segment = Some(e.segment().clone());
}
EventView::FlushStop(_) => {
self.0.lock().await.is_flushing = false;
}
EventView::SinkMessage(e) => {
let _ = elem.post_message(e.message());
}
_ => (),
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
}
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
true
}
.boxed()
2020-03-26 18:07:25 +00:00
}
fn sink_event(self, _pad: &gst::Pad, imp: &UdpSink, event: gst::Event) -> bool {
gst::debug!(CAT, imp: imp, "Handling {event:?}");
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let EventView::FlushStart(..) = event.view() {
block_on_or_add_sub_task(async move {
self.0.lock().await.is_flushing = true;
});
2020-03-26 18:07:25 +00:00
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
true
2020-03-26 18:07:25 +00:00
}
}
#[derive(Debug)]
struct UdpSinkPadHandlerInner {
is_flushing: bool,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
sync: bool,
latency: Option<gst::ClockTime>,
socket: Option<Async<UdpSocket>>,
socket_v6: Option<Async<UdpSocket>>,
clients: BTreeSet<SocketAddr>,
socket_conf: SocketConf,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
segment: Option<gst::Segment>,
}
2020-03-26 18:07:25 +00:00
impl Default for UdpSinkPadHandlerInner {
fn default() -> Self {
Self {
is_flushing: true,
sync: DEFAULT_SYNC,
latency: None,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
socket: None,
socket_v6: None,
clients: BTreeSet::from([SocketAddr::new(
DEFAULT_HOST.unwrap().parse().unwrap(),
DEFAULT_PORT as u16,
)]),
socket_conf: Default::default(),
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
segment: None,
}
2020-03-26 18:07:25 +00:00
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
}
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
/// Socket configuration.
impl UdpSinkPadHandlerInner {
fn configure_client(&self, client: &SocketAddr) -> Result<(), gst::ErrorMessage> {
if client.ip().is_multicast() {
match client.ip() {
IpAddr::V4(addr) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket.as_ref() {
if self.socket_conf.auto_multicast {
socket
.as_ref()
.join_multicast_v4(&addr, &Ipv4Addr::new(0, 0, 0, 0))
.map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
[
"Failed to join multicast group for {:?}: {}",
client,
err
]
)
})?;
}
if self.socket_conf.multicast_loop {
socket.as_ref().set_multicast_loop_v4(true).map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
["Failed to set multicast loop for {:?}: {}", client, err]
)
})?;
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
socket
.as_ref()
.set_multicast_ttl_v4(self.socket_conf.ttl_mc)
.map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
["Failed to set multicast ttl for {:?}: {}", client, err]
)
})?;
}
}
IpAddr::V6(addr) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket_v6.as_ref() {
if self.socket_conf.auto_multicast {
socket.as_ref().join_multicast_v6(&addr, 0).map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
["Failed to join multicast group for {:?}: {}", client, err]
)
})?;
}
if self.socket_conf.multicast_loop {
socket.as_ref().set_multicast_loop_v6(true).map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
["Failed to set multicast loop for {:?}: {}", client, err]
)
})?;
}
/* FIXME no API for set_multicast_ttl_v6 ? */
}
}
}
} else {
match client.ip() {
IpAddr::V4(_) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket.as_ref() {
socket
.as_ref()
.set_ttl(self.socket_conf.ttl)
.map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to set unicast ttl for {:?}: {}", client, err]
)
})?;
}
}
IpAddr::V6(_) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket_v6.as_ref() {
socket
.as_ref()
.set_ttl(self.socket_conf.ttl)
.map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to set unicast ttl for {:?}: {}", client, err]
)
})?;
}
}
}
}
Ok(())
}
fn unconfigure_client(&self, client: &SocketAddr) -> Result<(), gst::ErrorMessage> {
if client.ip().is_multicast() {
match client.ip() {
IpAddr::V4(addr) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket.as_ref() {
if self.socket_conf.auto_multicast {
socket
.as_ref()
.leave_multicast_v4(&addr, &Ipv4Addr::new(0, 0, 0, 0))
.map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
[
"Failed to leave multicast group for {:?}: {}",
client,
err
]
)
})?;
}
}
}
IpAddr::V6(addr) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
if let Some(socket) = self.socket_v6.as_ref() {
if self.socket_conf.auto_multicast {
socket
.as_ref()
.leave_multicast_v6(&addr, 0)
.map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
[
"Failed to leave multicast group for {:?}: {}",
client,
err
]
)
})?;
}
}
}
}
}
Ok(())
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
/// Buffer handling.
impl UdpSinkPadHandlerInner {
async fn render(
&mut self,
elem: &super::UdpSink,
buffer: gst::Buffer,
) -> Result<gst::FlowSuccess, gst::FlowError> {
let data = buffer.map_readable().map_err(|_| {
gst::element_error!(
elem,
gst::StreamError::Format,
["Failed to map buffer readable"]
);
gst::FlowError::Error
})?;
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
for client in self.clients.iter() {
let socket = match client.ip() {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
IpAddr::V4(_) => &mut self.socket,
IpAddr::V6(_) => &mut self.socket_v6,
};
if let Some(socket) = socket.as_mut() {
gst::log!(CAT, obj: elem, "Sending to {client:?}");
socket.send_to(&data, *client).await.map_err(|err| {
gst::element_error!(
elem,
gst::StreamError::Failed,
("I/O error"),
["streaming stopped, I/O error {}", err]
);
gst::FlowError::Error
})?;
} else {
gst::element_error!(
elem,
gst::StreamError::Failed,
("I/O error"),
["No socket available for sending to {}", client]
);
return Err(gst::FlowError::Error);
}
}
gst::log!(CAT, obj: elem, "Sent buffer {buffer:?} to all clients");
Ok(gst::FlowSuccess::Ok)
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
/// Waits until specified time.
async fn sync(&self, elem: &super::UdpSink, running_time: gst::ClockTime) {
let now = elem.current_running_time();
if let Ok(Some(delay)) = running_time.opt_checked_sub(now) {
gst::trace!(CAT, obj: elem, "sync: waiting {delay}");
runtime::timer::delay_for(delay.into()).await;
}
}
async fn handle_buffer(
&mut self,
elem: &super::UdpSink,
buffer: gst::Buffer,
) -> Result<gst::FlowSuccess, gst::FlowError> {
if self.is_flushing {
gst::info!(CAT, obj: elem, "Discarding {buffer:?} (flushing)");
return Err(gst::FlowError::Flushing);
}
if self.sync {
let rtime = self.segment.as_ref().and_then(|segment| {
segment
.downcast_ref::<gst::format::Time>()
.and_then(|segment| segment.to_running_time(buffer.pts()).opt_add(self.latency))
});
if let Some(rtime) = rtime {
self.sync(elem, rtime).await;
if self.is_flushing {
gst::info!(CAT, obj: elem, "Discarding {buffer:?} (flushing)");
return Err(gst::FlowError::Flushing);
}
}
}
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
gst::debug!(CAT, obj: elem, "Handling {buffer:?}");
self.render(elem, buffer).await.map_err(|err| {
element_error!(
elem,
gst::StreamError::Failed,
["Failed to render item, stopping task: {}", err]
);
gst::FlowError::Error
})
}
}
2020-03-26 18:07:25 +00:00
#[derive(Debug)]
enum SocketFamily {
Ipv4,
Ipv6,
}
#[derive(Debug)]
pub struct UdpSink {
2020-03-26 18:07:25 +00:00
sink_pad: PadSink,
sink_pad_handler: UdpSinkPadHandler,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
settings: Mutex<Settings>,
ts_ctx: Mutex<Option<Context>>,
2020-03-26 18:07:25 +00:00
}
impl UdpSink {
fn prepare_socket(
&self,
ts_ctx: &Context,
settings: &mut Settings,
family: SocketFamily,
) -> Result<Option<Async<UdpSocket>>, gst::ErrorMessage> {
let wrapped_socket = match family {
SocketFamily::Ipv4 => &settings.socket,
SocketFamily::Ipv6 => &settings.socket_v6,
};
if let Some(ref wrapped_socket) = wrapped_socket {
let socket: UdpSocket = wrapped_socket.get();
let socket = ts_ctx.enter(|| {
Async::<UdpSocket>::try_from(socket).map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to setup Async socket: {}", err]
)
})
})?;
match family {
SocketFamily::Ipv4 => {
settings.used_socket = Some(wrapped_socket.clone());
}
SocketFamily::Ipv6 => {
settings.used_socket_v6 = Some(wrapped_socket.clone());
}
}
Ok(Some(socket))
} else {
let bind_addr = match family {
SocketFamily::Ipv4 => &settings.bind_address,
SocketFamily::Ipv6 => &settings.bind_address_v6,
};
let bind_addr: IpAddr = bind_addr.parse().map_err(|err| {
error_msg!(
gst::ResourceError::Settings,
["Invalid address '{}' set: {}", bind_addr, err]
)
})?;
let bind_port = match family {
SocketFamily::Ipv4 => settings.bind_port,
SocketFamily::Ipv6 => settings.bind_port_v6,
};
let saddr = SocketAddr::new(bind_addr, bind_port as u16);
gst::debug!(CAT, imp: self, "Binding to {:?}", saddr);
let socket = match family {
SocketFamily::Ipv4 => socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::UDP),
),
SocketFamily::Ipv6 => socket2::Socket::new(
socket2::Domain::IPV6,
socket2::Type::DGRAM,
Some(socket2::Protocol::UDP),
),
};
let socket = match socket {
Ok(socket) => socket,
Err(err) => {
gst::warning!(
CAT,
imp: self,
"Failed to create {} socket: {}",
match family {
SocketFamily::Ipv4 => "IPv4",
SocketFamily::Ipv6 => "IPv6",
},
err
);
return Ok(None);
}
};
socket.bind(&saddr.into()).map_err(|err| {
2020-12-20 18:43:45 +00:00
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to bind socket: {}", err]
)
})?;
let socket = ts_ctx.enter(|| {
Async::<UdpSocket>::try_from(socket).map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to setup Async socket: {}", err]
)
})
})?;
let wrapper = wrap_socket(&socket)?;
if settings.qos_dscp != -1 {
wrapper.set_tos(settings.qos_dscp).map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to set QoS DSCP: {}", err]
)
})?;
}
match family {
SocketFamily::Ipv4 => {
settings.used_socket = Some(wrapper);
}
SocketFamily::Ipv6 => {
settings.used_socket_v6 = Some(wrapper);
}
}
Ok(Some(socket))
}
}
fn prepare(&self) -> Result<(), gst::ErrorMessage> {
gst::debug!(CAT, imp: self, "Preparing");
let mut settings = self.settings.lock().unwrap();
let ts_ctx = Context::acquire(&settings.context, settings.context_wait).map_err(|err| {
error_msg!(
gst::ResourceError::OpenWrite,
["Failed to acquire Context: {}", err]
)
})?;
let socket = self.prepare_socket(&ts_ctx, &mut settings, SocketFamily::Ipv4)?;
let socket_v6 = self.prepare_socket(&ts_ctx, &mut settings, SocketFamily::Ipv6)?;
self.sink_pad_handler
.prepare(self, socket, socket_v6, &settings)?;
*self.ts_ctx.lock().unwrap() = Some(ts_ctx);
gst::debug!(CAT, imp: self, "Started preparation");
Ok(())
}
fn unprepare(&self) {
gst::debug!(CAT, imp: self, "Unpreparing");
self.sink_pad_handler.unprepare();
*self.ts_ctx.lock().unwrap() = None;
gst::debug!(CAT, imp: self, "Unprepared");
}
fn stop(&self) -> Result<(), gst::ErrorMessage> {
gst::debug!(CAT, imp: self, "Stopping");
self.sink_pad_handler.stop();
gst::debug!(CAT, imp: self, "Stopped");
Ok(())
}
fn start(&self) -> Result<(), gst::ErrorMessage> {
gst::debug!(CAT, imp: self, "Starting");
self.sink_pad_handler.start();
gst::debug!(CAT, imp: self, "Started");
Ok(())
2020-03-26 18:07:25 +00:00
}
fn try_into_socket_addr(&self, host: &str, port: i32) -> Result<SocketAddr, ()> {
let addr: IpAddr = match host.parse() {
Err(err) => {
gst::error!(CAT, imp: self, "Failed to parse host {}: {}", host, err);
return Err(());
}
Ok(addr) => addr,
};
let port: u16 = match port.try_into() {
Err(err) => {
gst::error!(CAT, imp: self, "Invalid port {}: {}", port, err);
return Err(());
}
Ok(port) => port,
};
Ok(SocketAddr::new(addr, port))
2020-03-26 18:07:25 +00:00
}
}
#[glib::object_subclass]
impl ObjectSubclass for UdpSink {
const NAME: &'static str = "GstTsUdpSink";
type Type = super::UdpSink;
type ParentType = gst::Element;
fn with_class(klass: &Self::Class) -> Self {
let sink_pad_handler = UdpSinkPadHandler::default();
Self {
sink_pad: PadSink::new(
gst::Pad::from_template(&klass.pad_template("sink").unwrap()),
sink_pad_handler.clone(),
),
sink_pad_handler,
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
settings: Default::default(),
ts_ctx: Default::default(),
}
}
}
impl ObjectImpl for UdpSink {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpecString::builder("context")
.nick("Context")
.blurb("Context name to share threads with")
.default_value(Some(DEFAULT_CONTEXT))
.build(),
glib::ParamSpecUInt::builder("context-wait")
.nick("Context Wait")
.blurb("Throttle poll loop to run at most once every this many ms")
.maximum(1000)
.default_value(DEFAULT_CONTEXT_WAIT.as_millis() as u32)
.build(),
glib::ParamSpecBoolean::builder("sync")
.nick("Sync")
.blurb("Sync on the clock")
.default_value(DEFAULT_SYNC)
.build(),
glib::ParamSpecString::builder("bind-address")
.nick("Bind Address")
.blurb("Address to bind the socket to")
.default_value(Some(DEFAULT_BIND_ADDRESS))
.build(),
glib::ParamSpecInt::builder("bind-port")
.nick("Bind Port")
.blurb("Port to bind the socket to")
.minimum(0)
.maximum(u16::MAX as i32)
.default_value(DEFAULT_BIND_PORT)
.build(),
glib::ParamSpecString::builder("bind-address-v6")
.nick("Bind Address V6")
.blurb("Address to bind the V6 socket to")
.default_value(Some(DEFAULT_BIND_ADDRESS_V6))
.build(),
glib::ParamSpecInt::builder("bind-port-v6")
.nick("Bind Port")
.blurb("Port to bind the V6 socket to")
.minimum(0)
.maximum(u16::MAX as i32)
.default_value(DEFAULT_BIND_PORT_V6)
.build(),
glib::ParamSpecObject::builder::<gio::Socket>("socket")
.nick("Socket")
.blurb("Socket to use for UDP transmission. (None == allocate)")
.build(),
glib::ParamSpecObject::builder::<gio::Socket>("used-socket")
.nick("Used Socket")
.blurb("Socket currently in use for UDP transmission. (None = no socket)")
.read_only()
.build(),
glib::ParamSpecObject::builder::<gio::Socket>("socket-v6")
.nick("Socket V6")
.blurb("IPV6 Socket to use for UDP transmission. (None == allocate)")
.build(),
glib::ParamSpecObject::builder::<gio::Socket>("used-socket-v6")
.nick("Used Socket V6")
.blurb("V6 Socket currently in use for UDP transmission. (None = no socket)")
.read_only()
.build(),
glib::ParamSpecBoolean::builder("auto-multicast")
.nick("Auto multicast")
.blurb("Automatically join/leave the multicast groups, FALSE means user has to do it himself")
.default_value(DEFAULT_AUTO_MULTICAST)
.build(),
glib::ParamSpecBoolean::builder("loop")
.nick("Loop")
.blurb("Set the multicast loop parameter.")
.default_value(DEFAULT_LOOP)
.build(),
glib::ParamSpecUInt::builder("ttl")
.nick("Time To Live")
.blurb("Used for setting the unicast TTL parameter")
.maximum(u8::MAX as u32)
.default_value(DEFAULT_TTL)
.build(),
glib::ParamSpecUInt::builder("ttl-mc")
.nick("Time To Live Multicast")
.blurb("Used for setting the multicast TTL parameter")
.maximum(u8::MAX as u32)
.default_value(DEFAULT_TTL_MC)
.build(),
glib::ParamSpecInt::builder("qos-dscp")
.nick("QoS DSCP")
.blurb("Quality of Service, differentiated services code point (-1 default)")
.minimum(-1)
.maximum(63)
.default_value(DEFAULT_QOS_DSCP)
.build(),
glib::ParamSpecString::builder("clients")
.nick("Clients")
.blurb("A comma separated list of host:port pairs with destinations")
.default_value(Some(DEFAULT_CLIENTS))
.build(),
]
});
PROPERTIES.as_ref()
}
fn signals() -> &'static [glib::subclass::Signal] {
static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
vec![
2022-07-21 15:09:17 +00:00
glib::subclass::Signal::builder("add")
.param_types([String::static_type(), i32::static_type()])
2022-07-21 15:09:17 +00:00
.action()
.class_handler(|_, args| {
let elem = args[0].get::<super::UdpSink>().expect("signal arg");
2022-07-21 15:09:17 +00:00
let host = args[1].get::<String>().expect("signal arg");
let port = args[2].get::<i32>().expect("signal arg");
let imp = elem.imp();
if let Ok(addr) = imp.try_into_socket_addr(&host, port) {
imp.sink_pad_handler.add_client(imp, addr);
2022-07-21 15:09:17 +00:00
}
2022-07-21 15:09:17 +00:00
None
})
.build(),
glib::subclass::Signal::builder("remove")
.param_types([String::static_type(), i32::static_type()])
2022-07-21 15:09:17 +00:00
.action()
.class_handler(|_, args| {
let elem = args[0].get::<super::UdpSink>().expect("signal arg");
2022-07-21 15:09:17 +00:00
let host = args[1].get::<String>().expect("signal arg");
let port = args[2].get::<i32>().expect("signal arg");
let imp = elem.imp();
if let Ok(addr) = imp.try_into_socket_addr(&host, port) {
imp.sink_pad_handler.remove_client(imp, addr);
2022-07-21 15:09:17 +00:00
}
2022-07-21 15:09:17 +00:00
None
})
.build(),
glib::subclass::Signal::builder("clear")
.action()
.class_handler(|_, args| {
let elem = args[0].get::<super::UdpSink>().expect("signal arg");
let imp = elem.imp();
imp.sink_pad_handler.replace_clients(imp, BTreeSet::new());
None
})
.build(),
]
});
SIGNALS.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
let mut settings = self.settings.lock().unwrap();
2021-04-12 12:49:54 +00:00
match pspec.name() {
"sync" => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
let sync = value.get().expect("type checked upstream");
settings.sync = sync;
self.sink_pad_handler.set_sync(sync);
}
"bind-address" => {
settings.bind_address = value
2021-04-25 12:41:22 +00:00
.get::<Option<String>>()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
"bind-port" => {
2021-04-25 12:41:22 +00:00
settings.bind_port = value.get().expect("type checked upstream");
}
"bind-address-v6" => {
settings.bind_address_v6 = value
2021-04-25 12:41:22 +00:00
.get::<Option<String>>()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
"bind-port-v6" => {
2021-04-25 12:41:22 +00:00
settings.bind_port_v6 = value.get().expect("type checked upstream");
}
"socket" => {
settings.socket = value
2021-04-25 12:41:22 +00:00
.get::<Option<gio::Socket>>()
.expect("type checked upstream")
.map(|socket| GioSocketWrapper::new(&socket));
}
"used-socket" => {
unreachable!();
}
"socket-v6" => {
settings.socket_v6 = value
2021-04-25 12:41:22 +00:00
.get::<Option<gio::Socket>>()
.expect("type checked upstream")
.map(|socket| GioSocketWrapper::new(&socket));
}
"used-socket-v6" => {
unreachable!();
}
"auto-multicast" => {
settings.socket_conf.auto_multicast = value.get().expect("type checked upstream");
self.sink_pad_handler.set_socket_conf(settings.socket_conf);
}
"loop" => {
settings.socket_conf.multicast_loop = value.get().expect("type checked upstream");
self.sink_pad_handler.set_socket_conf(settings.socket_conf);
}
"ttl" => {
settings.socket_conf.ttl = value.get().expect("type checked upstream");
self.sink_pad_handler.set_socket_conf(settings.socket_conf);
}
"ttl-mc" => {
settings.socket_conf.ttl_mc = value.get().expect("type checked upstream");
self.sink_pad_handler.set_socket_conf(settings.socket_conf);
}
"qos-dscp" => {
2021-04-25 12:41:22 +00:00
settings.qos_dscp = value.get().expect("type checked upstream");
}
"clients" => {
2021-04-25 12:41:22 +00:00
let clients = value
.get::<Option<String>>()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
2020-03-26 18:07:25 +00:00
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
let clients = clients.split(',').filter_map(|client| {
2023-07-06 10:50:17 +00:00
let mut split = client.splitn(2, ':');
if let Some((addr, port)) = split.next().zip(split.next()) {
match port.parse::<i32>() {
Ok(port) => match self.try_into_socket_addr(addr, port) {
Ok(socket_addr) => Some(socket_addr),
Err(()) => {
gst::error!(
CAT,
imp: self,
"Invalid socket address {addr}:{port}"
);
None
}
},
Err(err) => {
gst::error!(CAT, imp: self, "Invalid port {err}");
None
}
}
2020-03-26 18:07:25 +00:00
} else {
gst::error!(CAT, imp: self, "Invalid client {client}");
2020-03-26 18:07:25 +00:00
None
}
});
2020-03-26 18:07:25 +00:00
let clients = BTreeSet::from_iter(clients);
self.sink_pad_handler.replace_clients(self, clients);
}
"context" => {
settings.context = value
2021-04-25 12:41:22 +00:00
.get::<Option<String>>()
.expect("type checked upstream")
.unwrap_or_else(|| DEFAULT_CONTEXT.into());
}
"context-wait" => {
settings.context_wait = Duration::from_millis(
value.get::<u32>().expect("type checked upstream").into(),
);
}
_ => unimplemented!(),
}
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
2021-04-12 12:49:54 +00:00
match pspec.name() {
"sync" => settings.sync.to_value(),
"bind-address" => settings.bind_address.to_value(),
"bind-port" => settings.bind_port.to_value(),
"bind-address-v6" => settings.bind_address_v6.to_value(),
"bind-port-v6" => settings.bind_port_v6.to_value(),
"socket" => settings
.socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
"used-socket" => settings
.used_socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
"socket-v6" => settings
.socket_v6
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
"used-socket-v6" => settings
.used_socket_v6
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
"auto-multicast" => settings.socket_conf.auto_multicast.to_value(),
"loop" => settings.socket_conf.multicast_loop.to_value(),
"ttl" => settings.socket_conf.ttl.to_value(),
"ttl-mc" => settings.socket_conf.ttl_mc.to_value(),
"qos-dscp" => settings.qos_dscp.to_value(),
"clients" => {
let clients = self.sink_pad_handler.clients();
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
let clients: Vec<String> = clients.iter().map(ToString::to_string).collect();
clients.join(",").to_value()
}
"context" => settings.context.to_value(),
"context-wait" => (settings.context_wait.as_millis() as u32).to_value(),
_ => unimplemented!(),
}
}
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
obj.add_pad(self.sink_pad.gst_pad()).unwrap();
obj.set_element_flags(gst::ElementFlags::SINK);
}
}
2021-10-23 08:57:31 +00:00
impl GstObjectImpl for UdpSink {}
impl ElementImpl for UdpSink {
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"Thread-sharing UDP sink",
"Sink/Network",
"Thread-sharing UDP sink",
"Mathieu <mathieu@centricular.com>",
)
});
Some(&*ELEMENT_METADATA)
}
fn pad_templates() -> &'static [gst::PadTemplate] {
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
let caps = gst::Caps::new_any();
let sink_pad_template = gst::PadTemplate::new(
"sink",
gst::PadDirection::Sink,
gst::PadPresence::Always,
&caps,
)
.unwrap();
vec![sink_pad_template]
});
PAD_TEMPLATES.as_ref()
}
fn change_state(
&self,
transition: gst::StateChange,
) -> Result<gst::StateChangeSuccess, gst::StateChangeError> {
gst::trace!(CAT, imp: self, "Changing state {:?}", transition);
match transition {
gst::StateChange::NullToReady => {
self.prepare().map_err(|err| {
self.post_error_message(err);
gst::StateChangeError
})?;
}
gst::StateChange::ReadyToPaused => {
self.start().map_err(|_| gst::StateChangeError)?;
}
gst::StateChange::PausedToReady => {
self.stop().map_err(|_| gst::StateChangeError)?;
}
gst::StateChange::ReadyToNull => {
self.unprepare();
}
_ => (),
}
self.parent_change_state(transition)
}
fn send_event(&self, event: gst::Event) -> bool {
match event.view() {
EventView::Latency(ev) => {
ts/udpsink: reduce sync primitives in async hot path The way the runtime::Task is implemented, UdpSinkTask is available as a mutable ref in all the TaskImpl functions, which offers the opportunity to avoid using Mutexes. Main higlights: - Removed the back and forth calls between UdpSinkPadHandler and UdpSinkTask. - Udp sockets are now part of UdpSinkTask, which is also in charge of preparing them instead of leaving this to UdpSink. This removed the need for Context::enter since TaskImpl::prepare already operates under the target Context. - In order for the clients list to be visible from the UdpSink, this list was maintained by UdpSinkPadHandler which was also in charge of (un)configuring the Udp sockets. The sockets are now part of UdpSinkTask, which is also in charge of the (un)configuration. Add/remove/replace requests are passed as commands to the UdpSinkTask via a channel. - The clients list visible to the UdpSink is now part of the Settings (it is also a read/write property). Since the actual socket (un)configuration is asynchronously handled by the Task, the clients list is updated by the add/remove/replace signals and set_property("clients", ..). Should a problem occur during the async (un)configuration, and only in this case, the UdpSinkTask would update the clients lists in Settings accordingly so that it stays consistent with the internal state. - The function clear_clients was renamed as replace_with_clients. - clients is now based on a BTreeSet instead of a Vec. All the managing functions perform some sort of lookup prior to updating the collection. It also ease implementation. - Removed the UdpSinkPadHandler RwLock. Using flume channels, we are able to clone the Receiver so it can be stored in UdpSink and reused when preparing the UdpSinkTask.
2022-06-23 16:50:11 +00:00
let latency = Some(ev.latency());
self.sink_pad_handler.set_latency(latency);
self.sink_pad.gst_pad().push_event(event)
}
EventView::Step(..) => false,
_ => self.sink_pad.gst_pad().push_event(event),
}
}
}