static void gst_multiudpsink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstMultiUDPSink *udpsink; udpsink = GST_MULTIUDPSINK (object); switch (prop_id) { case PROP_SOCKET: if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket && udpsink->close_socket) { GError *err = NULL; if (!g_socket_close (udpsink->socket, &err)) { GST_ERROR ("failed to close socket %p: %s", udpsink->socket, err->message); g_clear_error (&err); } } if (udpsink->socket) g_object_unref (udpsink->socket); udpsink->socket = g_value_dup_object (value); GST_DEBUG_OBJECT (udpsink, "setting socket to %p", udpsink->socket); break; case PROP_CLOSE_SOCKET: udpsink->close_socket = g_value_get_boolean (value); break; case PROP_CLIENTS: gst_multiudpsink_set_clients_string (udpsink, g_value_get_string (value)); break; case PROP_AUTO_MULTICAST: udpsink->auto_multicast = g_value_get_boolean (value); break; case PROP_TTL: udpsink->ttl = g_value_get_int (value); break; case PROP_TTL_MC: udpsink->ttl_mc = g_value_get_int (value); break; case PROP_LOOP: udpsink->loop = g_value_get_boolean (value); break; case PROP_QOS_DSCP: udpsink->qos_dscp = g_value_get_int (value); gst_multiudpsink_setup_qos_dscp (udpsink); break; case PROP_SEND_DUPLICATES: udpsink->send_duplicates = g_value_get_boolean (value); break; case PROP_BUFFER_SIZE: udpsink->buffer_size = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_multiudpsink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstMultiUDPSink *udpsink; udpsink = GST_MULTIUDPSINK (object); switch (prop_id) { case PROP_SOCKFD: if (udpsink->sockfd >= 0 && udpsink->sockfd != udpsink->sock && udpsink->closefd) CLOSE_SOCKET (udpsink->sockfd); udpsink->sockfd = g_value_get_int (value); GST_DEBUG_OBJECT (udpsink, "setting SOCKFD to %d", udpsink->sockfd); break; case PROP_CLOSEFD: udpsink->closefd = g_value_get_boolean (value); break; case PROP_CLIENTS: gst_multiudpsink_set_clients_string (udpsink, g_value_get_string (value)); break; case PROP_AUTO_MULTICAST: udpsink->auto_multicast = g_value_get_boolean (value); break; case PROP_TTL: udpsink->ttl = g_value_get_int (value); break; case PROP_TTL_MC: udpsink->ttl_mc = g_value_get_int (value); break; case PROP_LOOP: udpsink->loop = g_value_get_boolean (value); break; case PROP_QOS_DSCP: udpsink->qos_dscp = g_value_get_int (value); gst_multiudpsink_setup_qos_dscp (udpsink); break; case PROP_SEND_DUPLICATES: udpsink->send_duplicates = g_value_get_boolean (value); break; case PROP_BUFFER_SIZE: udpsink->buffer_size = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* create a socket for sending to remote machine */ static gboolean gst_multiudpsink_start (GstBaseSink * bsink) { GstMultiUDPSink *sink; GList *clients; GstUDPClient *client; GError *err = NULL; sink = GST_MULTIUDPSINK (bsink); sink->external_socket = FALSE; if (sink->socket) { GST_DEBUG_OBJECT (sink, "using configured socket"); if (g_socket_get_family (sink->socket) == G_SOCKET_FAMILY_IPV6) { sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket)); sink->external_socket = TRUE; } else { sink->used_socket = G_SOCKET (g_object_ref (sink->socket)); sink->external_socket = TRUE; } } if (sink->socket_v6) { GST_DEBUG_OBJECT (sink, "using configured IPv6 socket"); g_return_val_if_fail (g_socket_get_family (sink->socket) != G_SOCKET_FAMILY_IPV6, FALSE); if (sink->used_socket_v6 && sink->used_socket_v6 != sink->socket_v6) { GST_ERROR_OBJECT (sink, "Provided different IPv6 sockets in socket and socket-v6 properties"); return FALSE; } sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket_v6)); sink->external_socket = TRUE; } if (!sink->used_socket && !sink->used_socket_v6) { GSocketAddress *bind_addr; GInetAddress *bind_iaddr; if (sink->bind_address) { GSocketFamily family; bind_iaddr = g_inet_address_new_from_string (sink->bind_address); if (!bind_iaddr) { GList *results; GResolver *resolver; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, sink->bind_address, sink->cancellable, &err); if (!results) { g_object_unref (resolver); goto name_resolve; } bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_object_unref (bind_iaddr); family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr)); if ((sink->used_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) { g_object_unref (bind_addr); goto no_socket; } g_socket_bind (sink->used_socket, bind_addr, TRUE, &err); if (err != NULL) goto bind_error; } else { /* create sender sockets if none available */ if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_socket_bind (sink->used_socket, bind_addr, TRUE, &err); g_object_unref (bind_addr); g_object_unref (bind_iaddr); if (err != NULL) goto bind_error; if ((sink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) { GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s", err->message); g_clear_error (&err); } else { bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6); bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_socket_bind (sink->used_socket_v6, bind_addr, TRUE, &err); g_object_unref (bind_addr); g_object_unref (bind_iaddr); if (err != NULL) goto bind_error; } } } #ifdef SO_SNDBUF { socklen_t len; gint sndsize, ret; len = sizeof (sndsize); if (sink->buffer_size != 0) { sndsize = sink->buffer_size; GST_DEBUG_OBJECT (sink, "setting udp buffer of %d bytes", sndsize); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ if (sink->used_socket) { ret = setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s", sndsize, ret, g_strerror (errno))); } } if (sink->used_socket_v6) { ret = setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s", sndsize, ret, g_strerror (errno))); } } } /* read the value of the receive buffer. Note that on linux this returns 2x the * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ if (sink->used_socket) { ret = getsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have UDP buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get UDP buffer size"); } if (sink->used_socket_v6) { ret = getsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have UDPv6 buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get UDPv6 buffer size"); } } #endif #ifdef SO_BINDTODEVICE if (sink->multi_iface) { if (sink->used_socket) { setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_BINDTODEVICE, sink->multi_iface, strlen (sink->multi_iface)); } if (sink->used_socket_v6) { setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_BINDTODEVICE, sink->multi_iface, strlen (sink->multi_iface)); } } #endif if (sink->used_socket) g_socket_set_broadcast (sink->used_socket, TRUE); if (sink->used_socket_v6) g_socket_set_broadcast (sink->used_socket_v6, TRUE); sink->bytes_to_serve = 0; sink->bytes_served = 0; gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket); gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket_v6); /* look for multicast clients and join multicast groups appropriately set also ttl and multicast loopback delivery appropriately */ for (clients = sink->clients; clients; clients = g_list_next (clients)) { client = (GstUDPClient *) clients->data; if (!gst_multiudpsink_configure_client (sink, client)) return FALSE; } return TRUE; /* ERRORS */ no_socket: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Could not create socket: %s", err->message)); g_clear_error (&err); return FALSE; } bind_error: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Failed to bind socket: %s", err->message)); g_clear_error (&err); return FALSE; } name_resolve: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Failed to resolve bind address %s: %s", sink->bind_address, err->message)); g_clear_error (&err); return FALSE; } }
/* create a socket for sending to remote machine */ static gboolean gst_multiudpsink_start (GstBaseSink * bsink) { GstMultiUDPSink *sink; GList *clients; GstUDPClient *client; GError *err = NULL; sink = GST_MULTIUDPSINK (bsink); if (sink->socket == NULL) { GST_DEBUG_OBJECT (sink, "creating sockets"); /* create sender socket try IP6, fall back to IP4 */ sink->family = G_SOCKET_FAMILY_IPV6; if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) { sink->family = G_SOCKET_FAMILY_IPV4; if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; } GST_DEBUG_OBJECT (sink, "have socket"); sink->external_socket = FALSE; } else { GST_DEBUG_OBJECT (sink, "using configured socket"); /* we use the configured socket */ sink->used_socket = G_SOCKET (g_object_ref (sink->socket)); sink->family = g_socket_get_family (sink->used_socket); sink->external_socket = TRUE; } #ifdef SO_SNDBUF { socklen_t len; gint sndsize, ret; len = sizeof (sndsize); if (sink->buffer_size != 0) { sndsize = sink->buffer_size; GST_DEBUG_OBJECT (sink, "setting udp buffer of %d bytes", sndsize); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ ret = setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s", sndsize, ret, g_strerror (errno))); } } /* read the value of the receive buffer. Note that on linux this returns 2x the * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ ret = getsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have udp buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get udp buffer size"); } #endif g_socket_set_broadcast (sink->used_socket, TRUE); sink->bytes_to_serve = 0; sink->bytes_served = 0; gst_multiudpsink_setup_qos_dscp (sink); /* look for multicast clients and join multicast groups appropriately set also ttl and multicast loopback delivery appropriately */ for (clients = sink->clients; clients; clients = g_list_next (clients)) { client = (GstUDPClient *) clients->data; if (!gst_multiudpsink_configure_client (sink, client)) return FALSE; } return TRUE; /* ERRORS */ no_socket: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Could not create socket: %s", err->message)); g_clear_error (&err); return FALSE; } }
/* create a socket for sending to remote machine */ static gboolean gst_multiudpsink_init_send (GstMultiUDPSink * sink) { guint bc_val; GList *clients; GstUDPClient *client; int sndsize, ret; socklen_t len; if (sink->sockfd == -1) { GST_DEBUG_OBJECT (sink, "creating sockets"); /* create sender socket try IP6, fall back to IP4 */ sink->ss_family = AF_INET6; if ((sink->sock = socket (AF_INET6, SOCK_DGRAM, 0)) == -1) { sink->ss_family = AF_INET; if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) goto no_socket; } GST_DEBUG_OBJECT (sink, "have socket"); sink->externalfd = FALSE; } else { struct sockaddr_storage myaddr; GST_DEBUG_OBJECT (sink, "using configured socket"); /* we use the configured socket, try to get some info about it */ len = sizeof (myaddr); if (getsockname (sink->sockfd, (struct sockaddr *) &myaddr, &len) < 0) goto getsockname_error; sink->ss_family = myaddr.ss_family; /* we use the configured socket */ sink->sock = sink->sockfd; sink->externalfd = TRUE; } len = sizeof (sndsize); if (sink->buffer_size != 0) { sndsize = sink->buffer_size; GST_DEBUG_OBJECT (sink, "setting udp buffer of %d bytes", sndsize); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ ret = setsockopt (sink->sock, SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s (%d)", sndsize, ret, g_strerror (errno), errno)); } } /* read the value of the receive buffer. Note that on linux this returns 2x the * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ ret = getsockopt (sink->sock, SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have udp buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get udp buffer size"); bc_val = 1; if (setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val)) < 0) goto no_broadcast; sink->bytes_to_serve = 0; sink->bytes_served = 0; gst_multiudpsink_setup_qos_dscp (sink); /* look for multicast clients and join multicast groups appropriately set also ttl and multicast loopback delivery appropriately */ for (clients = sink->clients; clients; clients = g_list_next (clients)) { client = (GstUDPClient *) clients->data; if (!gst_multiudpsink_configure_client (sink, client)) return FALSE; } return TRUE; /* ERRORS */ no_socket: { gchar *errormessage = socket_last_error_message (); int errorcode = socket_last_error_code (); GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Could not create socket (%d): %s", errorcode, errormessage)); g_free (errormessage); return FALSE; } getsockname_error: { gchar *errormessage = socket_last_error_message (); int errorcode = socket_last_error_code (); GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Could not getsockname (%d): %s", errorcode, errormessage)); g_free (errormessage); return FALSE; } no_broadcast: { gchar *errormessage = socket_last_error_message (); int errorcode = socket_last_error_code (); CLOSE_IF_REQUESTED (sink); GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), ("Could not set broadcast socket option (%d): %s", errorcode, errormessage)); g_free (errormessage); return FALSE; } }