rtsp: make address-pool return an address object

Return a boxed GstRTSPAddress from the GstRTSPAddressPool. This allows us to
store more info in the structure and allows us to more easily return the address
to the right pool when no longer needed.
Pass the address to the StreamTransport so that we can return it to the pool
when the stream transport is freed or changed.
This commit is contained in:
Wim Taymans 2012-11-15 13:25:14 +01:00
parent fde8c01a85
commit 45b6693b39
8 changed files with 143 additions and 70 deletions

View file

@ -22,6 +22,43 @@
#include "rtsp-address-pool.h"
GstRTSPAddress *
gst_rtsp_address_copy (GstRTSPAddress * addr)
{
GstRTSPAddress *copy;
g_return_val_if_fail (addr != NULL, NULL);
copy = g_slice_dup (GstRTSPAddress, addr);
/* only release to the pool when the original is freed. It's a bit
* weird but this will do for now as it avoid us to use refcounting. */
copy->pool = NULL;
copy->address = g_strdup (copy->address);
return copy;
}
static void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
GstRTSPAddress * addr);
void
gst_rtsp_address_free (GstRTSPAddress * addr)
{
g_return_if_fail (addr != NULL);
if (addr->pool) {
/* unrefs the pool and sets it to NULL */
gst_rtsp_address_pool_release_address (addr->pool, addr);
}
g_free (addr->address);
g_slice_free (GstRTSPAddress, addr);
}
G_DEFINE_BOXED_TYPE (GstRTSPAddress, gst_rtsp_address,
(GBoxedCopyFunc) gst_rtsp_address_copy,
(GBoxedFreeFunc) gst_rtsp_address_free);
GST_DEBUG_CATEGORY_STATIC (rtsp_address_pool_debug);
#define GST_CAT_DEFAULT rtsp_address_pool_debug
@ -298,35 +335,29 @@ split_range (GstRTSPAddressPool * pool, AddrRange * range, gint skip,
* @pool: a #GstRTSPAddressPool
* @flags: flags
* @n_ports: the amount of ports
* @address: result address
* @port: result port
* @ttl: result TTL
*
* Take an address and ports from @pool. @flags can be used to control the
* allocation. @n_ports consecutive ports will be allocated of which the first
* one can be found in @port.
*
* Returns: a pointer that should be used to release the address with
* gst_rtsp_address_pool_release_address() after usage or %NULL when no
* address could be acquired.
* Returns: a #GstRTSPAddress that should be freed with gst_rtsp_address_free
* after use or %NULL when no address could be acquired.
*/
gpointer
GstRTSPAddress *
gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
GstRTSPAddressFlags flags, gint n_ports, gchar ** address,
guint16 * port, guint8 * ttl)
GstRTSPAddressFlags flags, gint n_ports)
{
GstRTSPAddressPoolPrivate *priv;
GList *walk, *next;
AddrRange *result;
GstRTSPAddress *addr;
g_return_val_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool), NULL);
g_return_val_if_fail (n_ports > 0, NULL);
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (port != NULL, NULL);
g_return_val_if_fail (ttl != NULL, NULL);
priv = pool->priv;
result = NULL;
addr = NULL;
g_mutex_lock (&priv->lock);
/* go over available ranges */
@ -363,13 +394,19 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
g_mutex_unlock (&priv->lock);
if (result) {
*address = get_address_string (&result->min);
*port = result->min.port;
*ttl = result->ttl;
addr = g_slice_new0 (GstRTSPAddress);
addr->pool = g_object_ref (pool);
addr->address = get_address_string (&result->min);
addr->n_ports = n_ports;
addr->port = result->min.port;
addr->ttl = result->ttl;
addr->priv = result;
GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", *address, *port, *ttl);
GST_DEBUG_OBJECT (pool, "got address %s:%u ttl %u", addr->address,
addr->port, addr->ttl);
}
return result;
return addr;
}
/**
@ -380,34 +417,44 @@ gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
* Release a previously acquired address (with
* gst_rtsp_address_pool_acquire_address()) back into @pool.
*/
void
gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool, gpointer id)
static void
gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
GstRTSPAddress * addr)
{
GstRTSPAddressPoolPrivate *priv;
GList *find;
AddrRange *range;
g_return_if_fail (GST_IS_RTSP_ADDRESS_POOL (pool));
g_return_if_fail (id != NULL);
g_return_if_fail (addr != NULL);
g_return_if_fail (addr->pool == pool);
priv = pool->priv;
range = addr->priv;
/* we don't want to free twice */
addr->priv = NULL;
addr->pool = NULL;
g_mutex_lock (&priv->lock);
find = g_list_find (priv->allocated, id);
find = g_list_find (priv->allocated, range);
if (find == NULL)
goto not_found;
priv->allocated = g_list_delete_link (priv->allocated, find);
/* FIXME, merge and do something clever */
priv->addresses = g_list_prepend (priv->addresses, id);
priv->addresses = g_list_prepend (priv->addresses, range);
g_mutex_unlock (&priv->lock);
g_object_unref (pool);
return;
/* ERRORS */
not_found:
{
g_warning ("Released unknown id %p", id);
g_warning ("Released unknown address %p", addr);
g_mutex_unlock (&priv->lock);
return;
}

View file

@ -33,10 +33,29 @@ G_BEGIN_DECLS
#define GST_RTSP_ADDRESS_POOL_CAST(obj) ((GstRTSPAddressPool*)(obj))
#define GST_RTSP_ADDRESS_POOL_CLASS_CAST(klass) ((GstRTSPAddressPoolClass*)(klass))
typedef struct _GstRTSPAddress GstRTSPAddress;
typedef struct _GstRTSPAddressClass GstRTSPAddressClass;
typedef struct _GstRTSPAddressPool GstRTSPAddressPool;
typedef struct _GstRTSPAddressPoolClass GstRTSPAddressPoolClass;
typedef struct _GstRTSPAddressPoolPrivate GstRTSPAddressPoolPrivate;
struct _GstRTSPAddress {
GstRTSPAddressPool *pool;
gchar *address;
guint16 port;
gint n_ports;
guint8 ttl;
gpointer priv;
};
GType gst_rtsp_address_get_type (void);
GstRTSPAddress * gst_rtsp_address_copy (GstRTSPAddress *addr);
void gst_rtsp_address_free (GstRTSPAddress *addr);
typedef enum {
GST_RTSP_ADDRESS_FLAG_NONE = 0,
GST_RTSP_ADDRESS_FLAG_IPV4 = (1 << 0),
@ -74,13 +93,9 @@ gboolean gst_rtsp_address_pool_add_range (GstRTSPAddressPool
guint16 max_port,
guint8 ttl);
gpointer gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
GstRTSPAddress * gst_rtsp_address_pool_acquire_address (GstRTSPAddressPool * pool,
GstRTSPAddressFlags flags,
gint n_ports,
gchar **address,
guint16 *port, guint8 *ttl);
void gst_rtsp_address_pool_release_address (GstRTSPAddressPool * pool,
gpointer);
gint n_ports);
G_END_DECLS
#endif /* __GST_RTSP_ADDRESS_POOL_H__ */

View file

@ -973,31 +973,30 @@ handle_blocksize (GstRTSPMedia * media, GstRTSPMessage * request)
static gboolean
configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
GstRTSPTransport * ct)
GstRTSPTransport * ct, GstRTSPAddress ** addr)
{
/* we have a valid transport now, set the destination of the client. */
if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
if (ct->destination == NULL || !client->use_client_settings) {
GstRTSPAddressPool *pool;
gchar *address;
guint16 port;
guint8 ttl;
gpointer id;
GstRTSPAddress *ad;
pool = gst_rtsp_media_get_address_pool (state->media);
if (pool == NULL)
goto no_pool;
id = gst_rtsp_address_pool_acquire_address (pool,
GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2, &address, &port, &ttl);
if (id == NULL)
ad = gst_rtsp_address_pool_acquire_address (pool,
GST_RTSP_ADDRESS_FLAG_EVEN_PORT, 2);
if (ad == NULL)
goto no_address;
g_free (ct->destination);
ct->destination = address;
ct->port.min = port;
ct->port.max = port + 1;
ct->ttl = ttl;
ct->destination = g_strdup (ad->address);
ct->port.min = ad->port;
ct->port.max = ad->port + 1;
ct->ttl = ad->ttl;
*addr = ad;
}
} else {
GstRTSPUrl *url;
@ -1019,10 +1018,12 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
/* ERRORS */
no_pool:
{
GST_ERROR_OBJECT (client, "no address pool specified");
return FALSE;
}
no_address:
{
GST_ERROR_OBJECT (client, "failed to acquire address from pool");
return FALSE;
}
}
@ -1078,6 +1079,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
GstRTSPSessionMedia *sessmedia;
GstRTSPMedia *media;
GstRTSPStream *stream;
GstRTSPAddress *addr;
uri = state->uri;
@ -1166,11 +1168,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
goto invalid_blocksize;
/* update the client transport */
if (!configure_client_transport (client, state, ct))
addr = NULL;
if (!configure_client_transport (client, state, ct, &addr))
goto unsupported_client_transport;
/* set in the session media transport */
trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct, addr);
/* configure keepalive for this transport */
gst_rtsp_stream_transport_set_keepalive (trans,

View file

@ -123,6 +123,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
* @media: a #GstRTSPSessionMedia
* @stream: a #GstRTSPStream
* @tr: a #GstRTSPTransport
* @addr: (transfer full) (allow none): an optional #GstRTSPAddress
*
* Configure the transport for @stream to @tr in @media.
*
@ -130,7 +131,7 @@ gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
*/
GstRTSPStreamTransport *
gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
GstRTSPStream * stream, GstRTSPTransport * tr)
GstRTSPStream * stream, GstRTSPTransport * tr, GstRTSPAddress * addr)
{
GstRTSPStreamTransport *result;
@ -141,11 +142,11 @@ gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
g_mutex_lock (&media->lock);
result = g_ptr_array_index (media->transports, stream->idx);
if (result == NULL) {
result = gst_rtsp_stream_transport_new (stream, tr);
result = gst_rtsp_stream_transport_new (stream, tr, addr);
g_ptr_array_index (media->transports, stream->idx) = result;
g_mutex_unlock (&media->lock);
} else {
gst_rtsp_stream_transport_set_transport (result, tr);
gst_rtsp_stream_transport_set_transport (result, tr, addr);
g_mutex_unlock (&media->lock);
}

View file

@ -78,7 +78,8 @@ gboolean gst_rtsp_session_media_set_state (GstRTSPSessionMe
/* get stream transport config */
GstRTSPStreamTransport * gst_rtsp_session_media_set_transport (GstRTSPSessionMedia *media,
GstRTSPStream *stream,
GstRTSPTransport *tr);
GstRTSPTransport *tr,
GstRTSPAddress *addr);
GstRTSPStreamTransport * gst_rtsp_session_media_get_transport (GstRTSPSessionMedia *media,
guint idx);

View file

@ -70,6 +70,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
if (trans->transport)
gst_rtsp_transport_free (trans->transport);
if (trans->addr)
gst_rtsp_address_free (trans->addr);
#if 0
if (trans->rtpsource)
@ -83,6 +85,7 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
* gst_rtsp_stream_transport_new:
* @stream: a #GstRTSPStream
* @tr: (transfer full): a GstRTSPTransport
* @addr: (transfer full) (allow none): an optional GstRTSPAddress
*
* Create a new #GstRTSPStreamTransport that can be used to manage
* @stream with transport @tr.
@ -90,7 +93,8 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
* Returns: a new #GstRTSPStreamTransport
*/
GstRTSPStreamTransport *
gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr,
GstRTSPAddress * addr)
{
GstRTSPStreamTransport *trans;
@ -100,6 +104,7 @@ gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
trans->stream = stream;
trans->transport = tr;
trans->addr = addr;
return trans;
}
@ -154,13 +159,14 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
* gst_rtsp_stream_transport_set_transport:
* @trans: a #GstRTSPStreamTransport
* @tr: (transfer full): a client #GstRTSPTransport
* @addr: (transfer full) (allow none): a ##GstRTSPAddress
*
* Set @ct as the client transport. This function takes ownership of
* the passed @tr.
* Set @tr and the optional @addr as the client transport. This function
* takes ownership of the passed @tr and @addr.
*/
void
gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
GstRTSPTransport * tr)
GstRTSPTransport * tr, GstRTSPAddress * addr)
{
g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
g_return_if_fail (tr != NULL);
@ -169,6 +175,9 @@ gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
if (trans->transport)
gst_rtsp_transport_free (trans->transport);
trans->transport = tr;
if (trans->addr)
gst_rtsp_address_free (trans->addr);
trans->addr = addr;
}
/**

View file

@ -40,6 +40,7 @@ typedef struct _GstRTSPStreamTransport GstRTSPStreamTransport;
typedef struct _GstRTSPStreamTransportClass GstRTSPStreamTransportClass;
#include "rtsp-stream.h"
#include "rtsp-address-pool.h"
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
@ -58,6 +59,7 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
* @active: if we are actively sending
* @timeout: if we timed out
* @transport: a transport description
* @addr: an optional address
* @rtpsource: the receiver rtp source object
*
* A Transport description for stream @idx
@ -79,6 +81,7 @@ struct _GstRTSPStreamTransport {
gboolean timeout;
GstRTSPTransport *transport;
GstRTSPAddress *addr;
GObject *rtpsource;
};
@ -90,10 +93,12 @@ struct _GstRTSPStreamTransportClass {
GType gst_rtsp_stream_transport_get_type (void);
GstRTSPStreamTransport * gst_rtsp_stream_transport_new (GstRTSPStream *stream,
GstRTSPTransport *tr);
GstRTSPTransport *tr,
GstRTSPAddress *addr);
void gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport *trans,
GstRTSPTransport * tr);
GstRTSPTransport * tr,
GstRTSPAddress *addr);
void gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport *trans,
GstRTSPSendFunc send_rtp,

View file

@ -23,11 +23,8 @@
GST_START_TEST (test_pool)
{
gpointer id;
GstRTSPAddressPool *pool;
gchar *address;
guint16 port;
guint8 ttl;
GstRTSPAddress *addr;
pool = gst_rtsp_address_pool_new ();
@ -44,23 +41,18 @@ GST_START_TEST (test_pool)
"233.255.0.0", "233.255.0.0", 5020, 5020, 1));
/* should fail, we can't allocate a block of 256 ports */
id = gst_rtsp_address_pool_acquire_address (pool,
0, 256, &address, &port, &ttl);
fail_unless (id == NULL);
addr = gst_rtsp_address_pool_acquire_address (pool, 0, 256);
fail_unless (addr == NULL);
id = gst_rtsp_address_pool_acquire_address (pool,
0, 2, &address, &port, &ttl);
fail_unless (id != NULL);
addr = gst_rtsp_address_pool_acquire_address (pool, 0, 2);
fail_unless (addr != NULL);
gst_rtsp_address_pool_release_address (pool, id);
g_free (address);
gst_rtsp_address_free (addr);
id = gst_rtsp_address_pool_acquire_address (pool,
0, 4, &address, &port, &ttl);
fail_unless (id != NULL);
addr = gst_rtsp_address_pool_acquire_address (pool, 0, 4);
fail_unless (addr != NULL);
gst_rtsp_address_pool_release_address (pool, id);
g_free (address);
gst_rtsp_address_free (addr);
g_object_unref (pool);
}