static gboolean gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src,
const gchar * uri);
static char *gst_soup_http_src_unicodify (const char *str);
-static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src);
+static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src,
+ const gchar * method);
static void gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src);
static void gst_soup_http_src_queue_message (GstSoupHTTPSrc * src);
static gboolean gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src,
guint64 offset);
static void gst_soup_http_src_session_unpause_message (GstSoupHTTPSrc * src);
static void gst_soup_http_src_session_pause_message (GstSoupHTTPSrc * src);
+static gboolean gst_soup_http_src_session_open (GstSoupHTTPSrc * src);
static void gst_soup_http_src_session_close (GstSoupHTTPSrc * src);
static void gst_soup_http_src_parse_status (SoupMessage * msg,
GstSoupHTTPSrc * src);
src->interrupted = FALSE;
src->retry = FALSE;
src->have_size = FALSE;
+ src->got_headers = FALSE;
src->seekable = FALSE;
src->read_position = 0;
src->request_position = 0;
{
const gchar *proxy;
+ g_mutex_init (&src->mutex);
+ g_cond_init (&src->request_finished_cond);
src->location = NULL;
src->automatic_redirect = TRUE;
src->user_agent = g_strdup (DEFAULT_USER_AGENT);
GST_DEBUG_OBJECT (src, "finalize");
+ g_mutex_clear (&src->mutex);
+ g_cond_clear (&src->request_finished_cond);
g_free (src->location);
g_free (src->user_agent);
if (src->proxy != NULL) {
soup_session_pause_message (src->session, src->msg);
}
+static gboolean
+gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
+{
+ if (src->session) {
+ GST_DEBUG_OBJECT (src, "Session is already open");
+ return TRUE;
+ }
+
+ if (!src->location) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
+ ("Missing location property"));
+ return FALSE;
+ }
+
+ src->context = g_main_context_new ();
+
+ src->loop = g_main_loop_new (src->context, TRUE);
+ if (!src->loop) {
+ GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+ (NULL), ("Failed to start GMainLoop"));
+ g_main_context_unref (src->context);
+ 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) {
+ 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);
+ return TRUE;
+}
+
static void
gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
{
return;
src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING;
+ src->got_headers = TRUE;
/* Parse Content-Length. */
if (soup_message_headers_get_encoding (msg->response_headers) ==
if (src->loop)
g_main_loop_quit (src->loop);
}
+ g_cond_signal (&src->request_finished_cond);
}
/* Have body. Signal EOS. */
}
if (src->loop)
g_main_loop_quit (src->loop);
+ g_cond_signal (&src->request_finished_cond);
}
/* Buffer lifecycle management.
}
static gboolean
-gst_soup_http_src_build_message (GstSoupHTTPSrc * src)
+gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
{
- src->msg = soup_message_new (SOUP_METHOD_GET, src->location);
+ src->msg = soup_message_new (method, src->location);
if (!src->msg) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
("Error parsing URL."), ("URL: %s", src->location));
}
static GstFlowReturn
-gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
+gst_soup_http_src_do_request (GstSoupHTTPSrc * src, const gchar * method,
+ GstBuffer ** outbuf)
{
- GstSoupHTTPSrc *src;
-
- src = GST_SOUP_HTTP_SRC (psrc);
-
+ GST_LOG_OBJECT (src, "Running request for method: %s", method);
if (src->msg && (src->request_position != src->read_position)) {
if (src->session_io_status == GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE) {
gst_soup_http_src_add_range_header (src, src->request_position);
}
}
if (!src->msg)
- if (!gst_soup_http_src_build_message (src))
+ if (!gst_soup_http_src_build_message (src, method)) {
return GST_FLOW_ERROR;
+ }
src->ret = GST_FLOW_CUSTOM_ERROR;
src->outbuf = outbuf;
}
if (src->retry) {
GST_DEBUG_OBJECT (src, "Reconnecting");
- if (!gst_soup_http_src_build_message (src))
+ if (!gst_soup_http_src_build_message (src, method)) {
return GST_FLOW_ERROR;
+ }
src->retry = FALSE;
continue;
}
if (src->ret == GST_FLOW_CUSTOM_ERROR)
src->ret = GST_FLOW_EOS;
+ g_cond_signal (&src->request_finished_cond);
return src->ret;
}
+static GstFlowReturn
+gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
+{
+ GstSoupHTTPSrc *src;
+ GstFlowReturn ret;
+
+ src = GST_SOUP_HTTP_SRC (psrc);
+
+ g_mutex_lock (&src->mutex);
+ ret = gst_soup_http_src_do_request (src, SOUP_METHOD_GET, outbuf);
+ g_mutex_unlock (&src->mutex);
+ return ret;
+}
+
static gboolean
gst_soup_http_src_start (GstBaseSrc * bsrc)
{
GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
- if (!src->location) {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
- ("Missing location property"));
- return FALSE;
- }
-
- src->context = g_main_context_new ();
-
- src->loop = g_main_loop_new (src->context, TRUE);
- if (!src->loop) {
- GST_ELEMENT_ERROR (src, LIBRARY, INIT,
- (NULL), ("Failed to start GMainLoop"));
- g_main_context_unref (src->context);
- return FALSE;
- }
-
- 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) {
- 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);
- return TRUE;
+ return gst_soup_http_src_session_open (src);
}
static gboolean
src->interrupted = TRUE;
if (src->loop)
g_main_loop_quit (src->loop);
+ g_cond_signal (&src->request_finished_cond);
return TRUE;
}
gst_soup_http_src_is_seekable (GstBaseSrc * bsrc)
{
GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ /* Special case to check if the server allows range requests
+ * before really starting to get data in the buffer creation
+ * loops.
+ */
+ if (!src->got_headers && GST_STATE (src) != GST_STATE_NULL) {
+ g_mutex_lock (&src->mutex);
+ while (!src->got_headers && !src->interrupted && ret == GST_FLOW_OK) {
+ if ((src->msg && src->msg->method != SOUP_METHOD_HEAD) &&
+ src->session_io_status != GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE) {
+ /* wait for the current request to finish */
+ g_cond_wait (&src->request_finished_cond, &src->mutex);
+ } else {
+ if (gst_soup_http_src_session_open (src)) {
+ ret = gst_soup_http_src_do_request (src, SOUP_METHOD_HEAD, NULL);
+ }
+ }
+ }
+ if (src->ret == GST_FLOW_EOS) {
+ /* A HEAD request shouldn't lead to EOS */
+ src->ret = GST_FLOW_OK;
+ }
+ /* resets status to idle */
+ gst_soup_http_src_cancel_message (src);
+ g_mutex_unlock (&src->mutex);
+ }
return src->seekable;
}