souphttpsrc: add support for keep-alive sessions

https://bugzilla.gnome.org/show_bug.cgi?id=699926
This commit is contained in:
Andoni Morales Alastruey 2013-02-28 12:20:52 +01:00 committed by Sebastian Dröge
parent 106bc2b17b
commit 4d80d3fad9
2 changed files with 90 additions and 37 deletions

View file

@ -108,17 +108,20 @@ enum
PROP_TIMEOUT, PROP_TIMEOUT,
PROP_EXTRA_HEADERS, PROP_EXTRA_HEADERS,
PROP_SOUP_LOG_LEVEL, PROP_SOUP_LOG_LEVEL,
PROP_COMPRESS PROP_COMPRESS,
PROP_KEEP_ALIVE
}; };
#define DEFAULT_USER_AGENT "GStreamer souphttpsrc " #define DEFAULT_USER_AGENT "GStreamer souphttpsrc "
#define DEFAULT_IRADIO_MODE TRUE #define DEFAULT_IRADIO_MODE TRUE
#define DEFAULT_SOUP_LOG_LEVEL SOUP_LOGGER_LOG_NONE #define DEFAULT_SOUP_LOG_LEVEL SOUP_LOGGER_LOG_NONE
#define DEFAULT_COMPRESS FALSE #define DEFAULT_COMPRESS FALSE
#define DEFAULT_KEEP_ALIVE FALSE
static void gst_soup_http_src_uri_handler_init (gpointer g_iface, static void gst_soup_http_src_uri_handler_init (gpointer g_iface,
gpointer iface_data); gpointer iface_data);
static void gst_soup_http_src_finalize (GObject * gobject); static void gst_soup_http_src_finalize (GObject * gobject);
static void gst_soup_http_src_dispose (GObject * gobject);
static void gst_soup_http_src_set_property (GObject * object, guint prop_id, static void gst_soup_http_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
@ -191,6 +194,7 @@ gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
gobject_class->set_property = gst_soup_http_src_set_property; gobject_class->set_property = gst_soup_http_src_set_property;
gobject_class->get_property = gst_soup_http_src_get_property; gobject_class->get_property = gst_soup_http_src_get_property;
gobject_class->finalize = gst_soup_http_src_finalize; gobject_class->finalize = gst_soup_http_src_finalize;
gobject_class->dispose = gst_soup_http_src_dispose;
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_LOCATION, PROP_LOCATION,
@ -248,6 +252,7 @@ gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
"Enable internet radio mode (ask server to send shoutcast/icecast " "Enable internet radio mode (ask server to send shoutcast/icecast "
"metadata interleaved with the actual stream data)", "metadata interleaved with the actual stream data)",
DEFAULT_IRADIO_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_IRADIO_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstSoupHTTPSrc::http-log-level: * GstSoupHTTPSrc::http-log-level:
* *
@ -277,6 +282,20 @@ gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
"Allow compressed content encodings", "Allow compressed content encodings",
DEFAULT_COMPRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_COMPRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstSoupHTTPSrc::keep-alive:
*
* If set to %TRUE, souphttpsrc will keep alive connections when being
* set to READY state and only will close connections when connecting
* to a different server or when going to NULL state..
*
* Since: 1.4
*/
g_object_class_install_property (gobject_class, PROP_KEEP_ALIVE,
g_param_spec_boolean ("keep-alive", "keep-alive",
"Use HTTP persistent connections", DEFAULT_KEEP_ALIVE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate)); gst_static_pad_template_get (&srctemplate));
@ -357,6 +376,18 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
gst_soup_http_src_reset (src); gst_soup_http_src_reset (src);
} }
static void
gst_soup_http_src_dispose (GObject * gobject)
{
GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (gobject);
GST_DEBUG_OBJECT (src, "dispose");
gst_soup_http_src_session_close (src);
G_OBJECT_CLASS (parent_class)->dispose (gobject);
}
static void static void
gst_soup_http_src_finalize (GObject * gobject) gst_soup_http_src_finalize (GObject * gobject)
{ {
@ -478,6 +509,9 @@ gst_soup_http_src_set_property (GObject * object, guint prop_id,
case PROP_COMPRESS: case PROP_COMPRESS:
src->compress = g_value_get_boolean (value); src->compress = g_value_get_boolean (value);
break; break;
case PROP_KEEP_ALIVE:
src->keep_alive = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -545,6 +579,9 @@ gst_soup_http_src_get_property (GObject * object, guint prop_id,
case PROP_COMPRESS: case PROP_COMPRESS:
g_value_set_boolean (value, src->compress); g_value_set_boolean (value, src->compress);
break; break;
case PROP_KEEP_ALIVE:
g_value_set_boolean (value, src->keep_alive);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -707,9 +744,11 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
return FALSE; return FALSE;
} }
src->context = g_main_context_new (); if (!src->context)
src->context = g_main_context_new ();
src->loop = g_main_loop_new (src->context, TRUE); if (!src->loop)
src->loop = g_main_loop_new (src->context, TRUE);
if (!src->loop) { if (!src->loop) {
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_ELEMENT_ERROR (src, LIBRARY, INIT,
(NULL), ("Failed to start GMainLoop")); (NULL), ("Failed to start GMainLoop"));
@ -717,36 +756,43 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
return FALSE; return FALSE;
} }
GST_DEBUG_OBJECT (src, "Creating session");
if (src->proxy == NULL) {
src->session =
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
SOUP_SESSION_TIMEOUT, src->timeout,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
NULL);
} else {
src->session =
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
src->context, SOUP_SESSION_PROXY_URI, src->proxy,
SOUP_SESSION_TIMEOUT, src->timeout,
SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
}
if (!src->session) { if (!src->session) {
GST_ELEMENT_ERROR (src, LIBRARY, INIT, GST_DEBUG_OBJECT (src, "Creating session");
(NULL), ("Failed to create async session")); if (src->proxy == NULL) {
return FALSE; src->session =
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
SOUP_SESSION_TIMEOUT, src->timeout,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
NULL);
} else {
src->session =
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
src->context, SOUP_SESSION_PROXY_URI, src->proxy,
SOUP_SESSION_TIMEOUT, src->timeout,
SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
}
if (!src->session) {
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
(NULL), ("Failed to create async session"));
return FALSE;
}
g_signal_connect (src->session, "authenticate",
G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
/* Set up logging */
gst_soup_util_log_setup (src->session, src->log_level, GST_ELEMENT (src));
} else {
GST_DEBUG_OBJECT (src, "Re-using session");
} }
g_signal_connect (src->session, "authenticate",
G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
/* Set up logging */
gst_soup_util_log_setup (src->session, src->log_level, GST_ELEMENT (src));
if (src->compress) if (src->compress)
soup_session_add_feature_by_type (src->session, SOUP_TYPE_CONTENT_DECODER); soup_session_add_feature_by_type (src->session, SOUP_TYPE_CONTENT_DECODER);
else
soup_session_remove_feature_by_type (src->session,
SOUP_TYPE_CONTENT_DECODER);
return TRUE; return TRUE;
} }
@ -760,6 +806,12 @@ gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
src->session = NULL; src->session = NULL;
src->msg = NULL; src->msg = NULL;
} }
if (src->loop) {
g_main_loop_unref (src->loop);
g_main_context_unref (src->context);
src->loop = NULL;
src->context = NULL;
}
} }
static void static void
@ -1263,8 +1315,10 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
return FALSE; return FALSE;
} }
src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE; src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE;
soup_message_headers_append (src->msg->request_headers, "Connection", if (!src->keep_alive) {
"close"); soup_message_headers_append (src->msg->request_headers, "Connection",
"close");
}
if (src->iradio_mode) { if (src->iradio_mode) {
soup_message_headers_append (src->msg->request_headers, "icy-metadata", soup_message_headers_append (src->msg->request_headers, "icy-metadata",
"1"); "1");
@ -1396,13 +1450,11 @@ gst_soup_http_src_stop (GstBaseSrc * bsrc)
src = GST_SOUP_HTTP_SRC (bsrc); src = GST_SOUP_HTTP_SRC (bsrc);
GST_DEBUG_OBJECT (src, "stop()"); GST_DEBUG_OBJECT (src, "stop()");
gst_soup_http_src_session_close (src); if (src->keep_alive)
if (src->loop) { gst_soup_http_src_cancel_message (src);
g_main_loop_unref (src->loop); else
g_main_context_unref (src->context); gst_soup_http_src_session_close (src);
src->loop = NULL;
src->context = NULL;
}
if (src->extra_headers) { if (src->extra_headers) {
gst_structure_free (src->extra_headers); gst_structure_free (src->extra_headers);
src->extra_headers = NULL; src->extra_headers = NULL;

View file

@ -83,6 +83,7 @@ struct _GstSoupHTTPSrc {
* decide if an out of range request should be * decide if an out of range request should be
* handled as an error or EOS when the content * handled as an error or EOS when the content
* size is unknown */ * size is unknown */
gboolean keep_alive; /* Use keep-alive sessions */
/* Shoutcast/icecast metadata extraction handling. */ /* Shoutcast/icecast metadata extraction handling. */
gboolean iradio_mode; gboolean iradio_mode;