2 * Copyright (C) 2011 Andoni Morales Alastruey <ylatuya@gmail.com>
3 * Copyright (C) 2021-2022 Jan Schmidt <jan@centricular.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include <gst/base/gsttypefindhelper.h>
28 #include <gst/base/gstadapter.h>
29 #include "downloadrequest.h"
31 typedef struct _DownloadRequestPrivate DownloadRequestPrivate;
33 struct _DownloadRequestPrivate
35 DownloadRequest request;
41 DownloadRequestEventCallback completion_cb;
42 DownloadRequestEventCallback cancellation_cb;
43 DownloadRequestEventCallback error_cb;
44 DownloadRequestEventCallback progress_cb;
48 #define DOWNLOAD_REQUEST_PRIVATE(frag) ((DownloadRequestPrivate *)(frag))
50 static void download_request_free (DownloadRequest * request);
53 download_request_new (void)
55 DownloadRequest *request =
56 (DownloadRequest *) g_slice_new0 (DownloadRequestPrivate);
57 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
59 g_atomic_int_set (&request->ref_count, 1);
61 g_rec_mutex_init (&priv->lock);
65 request->state = DOWNLOAD_REQUEST_STATE_UNSENT;
66 request->status_code = 0;
68 request->download_request_time = GST_CLOCK_TIME_NONE;
69 request->download_start_time = GST_CLOCK_TIME_NONE;
70 request->download_end_time = GST_CLOCK_TIME_NONE;
71 request->headers = NULL;
73 return (DownloadRequest *) (request);
77 download_request_new_uri (const gchar * uri)
79 DownloadRequest *request = download_request_new ();
81 request->uri = g_strdup (uri);
82 request->range_start = 0;
83 request->range_end = -1;
89 download_request_new_uri_range (const gchar * uri, gint64 range_start,
92 DownloadRequest *request = download_request_new ();
94 request->uri = g_strdup (uri);
95 request->range_start = range_start;
96 request->range_end = range_end;
102 download_request_free (DownloadRequest * request)
104 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
106 g_free (request->uri);
107 g_free (request->redirect_uri);
108 if (request->headers) {
109 gst_structure_free (request->headers);
110 request->headers = NULL;
113 if (priv->buffer != NULL) {
114 gst_buffer_unref (priv->buffer);
118 if (priv->caps != NULL) {
119 gst_caps_unref (priv->caps);
123 g_rec_mutex_clear (&priv->lock);
125 g_slice_free1 (sizeof (DownloadRequestPrivate), priv);
129 download_request_set_callbacks (DownloadRequest * request,
130 DownloadRequestEventCallback on_completion,
131 DownloadRequestEventCallback on_error,
132 DownloadRequestEventCallback on_cancellation,
133 DownloadRequestEventCallback on_progress, void *cb_data)
135 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
136 g_rec_mutex_lock (&priv->lock);
137 priv->completion_cb = on_completion;
138 priv->error_cb = on_error;
139 priv->cancellation_cb = on_cancellation;
140 priv->progress_cb = on_progress;
141 priv->cb_data = cb_data;
143 request->send_progress = (on_progress != NULL);
145 g_rec_mutex_unlock (&priv->lock);
148 /* Called with request lock held */
150 download_request_despatch_progress (DownloadRequest * request)
152 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
153 if (priv->progress_cb)
154 priv->progress_cb (request, request->state, priv->cb_data);
157 /* Called with request lock held */
159 download_request_despatch_completion (DownloadRequest * request)
161 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
162 switch (request->state) {
163 case DOWNLOAD_REQUEST_STATE_UNSENT:
164 if (priv->cancellation_cb)
165 priv->cancellation_cb (request, request->state, priv->cb_data);
167 case DOWNLOAD_REQUEST_STATE_COMPLETE:
168 if (priv->completion_cb)
169 priv->completion_cb (request, request->state, priv->cb_data);
171 case DOWNLOAD_REQUEST_STATE_ERROR:
173 priv->error_cb (request, request->state, priv->cb_data);
176 g_assert_not_reached ();
182 download_request_ref (DownloadRequest * request)
184 g_return_val_if_fail (request != NULL, NULL);
185 g_atomic_int_inc (&request->ref_count);
191 download_request_unref (DownloadRequest * request)
193 g_return_if_fail (request != NULL);
195 if (g_atomic_int_dec_and_test (&request->ref_count)) {
196 download_request_free (request);
201 download_request_lock (DownloadRequest * request)
203 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
204 g_rec_mutex_lock (&priv->lock);
208 download_request_unlock (DownloadRequest * request)
210 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
211 g_rec_mutex_unlock (&priv->lock);
215 download_request_take_buffer (DownloadRequest * request)
217 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
218 GstBuffer *buffer = NULL;
220 g_return_val_if_fail (request != NULL, NULL);
222 g_rec_mutex_lock (&priv->lock);
224 if (request->state != DOWNLOAD_REQUEST_STATE_LOADING
225 && request->state != DOWNLOAD_REQUEST_STATE_COMPLETE) {
226 g_rec_mutex_unlock (&priv->lock);
230 buffer = priv->buffer;
233 g_rec_mutex_unlock (&priv->lock);
239 download_request_set_uri (DownloadRequest * request, const gchar * uri,
240 gint64 range_start, gint64 range_end)
242 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
243 g_rec_mutex_lock (&priv->lock);
245 g_assert (request->in_use == FALSE);
247 if (request->uri != uri) {
248 g_free (request->uri);
249 request->uri = g_strdup (uri);
252 g_free (request->redirect_uri);
253 request->redirect_uri = NULL;
254 request->redirect_permanent = FALSE;
256 request->range_start = range_start;
257 request->range_end = range_end;
259 g_rec_mutex_unlock (&priv->lock);
263 download_request_reset (DownloadRequest * request)
265 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
267 g_rec_mutex_lock (&priv->lock);
268 g_assert (request->in_use == FALSE);
269 request->state = DOWNLOAD_REQUEST_STATE_UNSENT;
271 if (request->headers) {
272 gst_structure_free (request->headers);
273 request->headers = NULL;
276 if (priv->buffer != NULL) {
277 gst_buffer_unref (priv->buffer);
281 if (priv->caps != NULL) {
282 gst_caps_unref (priv->caps);
286 g_rec_mutex_unlock (&priv->lock);
289 /* Called when the request is submitted, to clear any settings from a previous
292 download_request_begin_download (DownloadRequest * request)
294 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
296 g_return_if_fail (request != NULL);
298 g_rec_mutex_lock (&priv->lock);
300 if (priv->buffer != NULL) {
301 gst_buffer_unref (priv->buffer);
305 if (request->headers) {
306 gst_structure_free (request->headers);
307 request->headers = NULL;
310 if (priv->caps != NULL) {
311 gst_caps_unref (priv->caps);
315 request->content_length = 0;
316 request->content_received = 0;
318 request->download_request_time = GST_CLOCK_TIME_NONE;
319 request->download_start_time = GST_CLOCK_TIME_NONE;
320 request->download_end_time = GST_CLOCK_TIME_NONE;
322 g_rec_mutex_unlock (&priv->lock);
326 download_request_set_caps (DownloadRequest * request, GstCaps * caps)
328 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
329 g_return_if_fail (request != NULL);
331 g_rec_mutex_lock (&priv->lock);
332 gst_caps_replace (&priv->caps, caps);
333 g_rec_mutex_unlock (&priv->lock);
337 download_request_get_caps (DownloadRequest * request)
339 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
342 g_return_val_if_fail (request != NULL, NULL);
344 if (request->state != DOWNLOAD_REQUEST_STATE_LOADING
345 && request->state != DOWNLOAD_REQUEST_STATE_COMPLETE)
348 g_rec_mutex_lock (&priv->lock);
349 if (priv->caps == NULL) {
350 guint64 offset, offset_end;
352 /* FIXME: This is currently necessary as typefinding only
353 * works with 0 offsets... need to find a better way to
355 offset = GST_BUFFER_OFFSET (priv->buffer);
356 offset_end = GST_BUFFER_OFFSET_END (priv->buffer);
357 GST_BUFFER_OFFSET (priv->buffer) = GST_BUFFER_OFFSET_NONE;
358 GST_BUFFER_OFFSET_END (priv->buffer) = GST_BUFFER_OFFSET_NONE;
359 priv->caps = gst_type_find_helper_for_buffer (NULL, priv->buffer, NULL);
360 GST_BUFFER_OFFSET (priv->buffer) = offset;
361 GST_BUFFER_OFFSET_END (priv->buffer) = offset_end;
364 caps = gst_caps_ref (priv->caps);
365 g_rec_mutex_unlock (&priv->lock);
371 download_request_add_buffer (DownloadRequest * request, GstBuffer * buffer)
373 DownloadRequestPrivate *priv = DOWNLOAD_REQUEST_PRIVATE (request);
375 g_return_val_if_fail (request != NULL, FALSE);
376 g_return_val_if_fail (buffer != NULL, FALSE);
378 if (request->state == DOWNLOAD_REQUEST_STATE_COMPLETE) {
379 GST_WARNING ("Download request is completed, could not add more buffers");
380 gst_buffer_unref (buffer);
384 GST_DEBUG ("Adding new buffer %" GST_PTR_FORMAT " to the request data",
387 request->content_received += gst_buffer_get_size (buffer);
389 /* We steal the buffers you pass in */
390 if (priv->buffer == NULL)
391 priv->buffer = buffer;
393 priv->buffer = gst_buffer_append (priv->buffer, buffer);