Remove "virtual" from all lines that have both "virtual" and "override".
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / WebKitWebSourceGStreamer.cpp
1 /*
2  *  Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3  *  Copyright (C) 2013 Collabora Ltd.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "config.h"
21 #include "WebKitWebSourceGStreamer.h"
22
23 #if ENABLE(VIDEO) && USE(GSTREAMER)
24
25 #include "GRefPtrGStreamer.h"
26 #include "GStreamerUtilities.h"
27 #include "GUniquePtrGStreamer.h"
28 #include "HTTPHeaderNames.h"
29 #include "MainThreadNotifier.h"
30 #include "MediaPlayer.h"
31 #include "NotImplemented.h"
32 #include "PlatformMediaResourceLoader.h"
33 #include "ResourceError.h"
34 #include "ResourceHandle.h"
35 #include "ResourceHandleClient.h"
36 #include "ResourceRequest.h"
37 #include "ResourceResponse.h"
38 #include "SharedBuffer.h"
39 #include <gst/app/gstappsrc.h>
40 #include <gst/gst.h>
41 #include <gst/pbutils/missing-plugins.h>
42 #include <wtf/MainThread.h>
43 #include <wtf/Noncopyable.h>
44 #include <wtf/glib/GMutexLocker.h>
45 #include <wtf/glib/GRefPtr.h>
46 #include <wtf/glib/GUniquePtr.h>
47 #include <wtf/text/CString.h>
48
49 using namespace WebCore;
50
51 class StreamingClient {
52     public:
53         StreamingClient(WebKitWebSrc*);
54         virtual ~StreamingClient();
55
56     protected:
57         char* createReadBuffer(size_t requestedSize, size_t& actualSize);
58         void handleResponseReceived(const ResourceResponse&);
59         void handleDataReceived(const char*, int);
60         void handleNotifyFinished();
61
62         GstElement* m_src;
63 };
64
65 class CachedResourceStreamingClient final : public PlatformMediaResourceClient, public StreamingClient {
66     WTF_MAKE_NONCOPYABLE(CachedResourceStreamingClient);
67     public:
68         CachedResourceStreamingClient(WebKitWebSrc*);
69         virtual ~CachedResourceStreamingClient();
70
71     private:
72         // PlatformMediaResourceClient virtual methods.
73 #if USE(SOUP)
74         char* getOrCreateReadBuffer(PlatformMediaResource&, size_t requestedSize, size_t& actualSize) override;
75 #endif
76         void responseReceived(PlatformMediaResource&, const ResourceResponse&) override;
77         void dataReceived(PlatformMediaResource&, const char*, int) override;
78         void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) override;
79         void loadFailed(PlatformMediaResource&, const ResourceError&) override;
80         void loadFinished(PlatformMediaResource&) override;
81 };
82
83 class ResourceHandleStreamingClient : public ResourceHandleClient, public StreamingClient {
84     WTF_MAKE_NONCOPYABLE(ResourceHandleStreamingClient); WTF_MAKE_FAST_ALLOCATED;
85     public:
86         ResourceHandleStreamingClient(WebKitWebSrc*, const ResourceRequest&);
87         virtual ~ResourceHandleStreamingClient();
88
89         // StreamingClient virtual methods.
90         bool loadFailed() const;
91         void setDefersLoading(bool);
92
93     private:
94         // ResourceHandleClient virtual methods.
95         virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize);
96         virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
97         virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
98         virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int);
99         virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer>, int encodedLength);
100         virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
101         virtual void didFail(ResourceHandle*, const ResourceError&);
102         virtual void wasBlocked(ResourceHandle*);
103         virtual void cannotShowURL(ResourceHandle*);
104
105         RefPtr<ResourceHandle> m_resource;
106 };
107
108 enum MainThreadSourceNotification {
109     Start = 1 << 0,
110     Stop = 1 << 1,
111     NeedData = 1 << 2,
112     EnoughData = 1 << 3,
113     Seek = 1 << 4
114 };
115
116 #define WEBKIT_WEB_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_SRC, WebKitWebSrcPrivate))
117 struct _WebKitWebSrcPrivate {
118     GstAppSrc* appsrc;
119     GstPad* srcpad;
120     gchar* uri;
121     bool keepAlive;
122     GUniquePtr<GstStructure> extraHeaders;
123     bool compress;
124     GUniquePtr<gchar> httpMethod;
125
126     WebCore::MediaPlayer* player;
127
128     RefPtr<PlatformMediaResourceLoader> loader;
129     RefPtr<PlatformMediaResource> resource;
130     ResourceHandleStreamingClient* client;
131
132     bool didPassAccessControlCheck;
133
134     guint64 offset;
135     guint64 size;
136     gboolean seekable;
137     gboolean paused;
138     bool isSeeking;
139
140     guint64 requestedOffset;
141
142     MainThreadNotifier<MainThreadSourceNotification> notifier;
143     GRefPtr<GstBuffer> buffer;
144 };
145
146 enum {
147     PROP_0,
148     PROP_LOCATION,
149     PROP_KEEP_ALIVE,
150     PROP_EXTRA_HEADERS,
151     PROP_COMPRESS,
152     PROP_METHOD
153 };
154
155 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
156                                                                   GST_PAD_SRC,
157                                                                   GST_PAD_ALWAYS,
158                                                                   GST_STATIC_CAPS_ANY);
159
160 GST_DEBUG_CATEGORY_STATIC(webkit_web_src_debug);
161 #define GST_CAT_DEFAULT webkit_web_src_debug
162
163 static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
164
165 static void webKitWebSrcDispose(GObject*);
166 static void webKitWebSrcFinalize(GObject*);
167 static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*);
168 static void webKitWebSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*);
169 static GstStateChangeReturn webKitWebSrcChangeState(GstElement*, GstStateChange);
170
171 static gboolean webKitWebSrcQueryWithParent(GstPad*, GstObject*, GstQuery*);
172
173 static void webKitWebSrcNeedData(WebKitWebSrc*);
174 static void webKitWebSrcEnoughData(WebKitWebSrc*);
175 static void webKitWebSrcSeek(WebKitWebSrc*);
176
177 static GstAppSrcCallbacks appsrcCallbacks = {
178     // need_data
179     [](GstAppSrc*, guint, gpointer userData) {
180         WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
181         WebKitWebSrcPrivate* priv = src->priv;
182
183         {
184             WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
185             if (!priv->paused)
186                 return;
187         }
188
189         GRefPtr<WebKitWebSrc> protector(src);
190         priv->notifier.notify(MainThreadSourceNotification::NeedData, [protector] { webKitWebSrcNeedData(protector.get()); });
191     },
192     // enough_data
193     [](GstAppSrc*, gpointer userData) {
194         WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
195         WebKitWebSrcPrivate* priv = src->priv;
196
197         {
198             WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
199             if (priv->paused)
200                 return;
201         }
202
203         GRefPtr<WebKitWebSrc> protector(src);
204         priv->notifier.notify(MainThreadSourceNotification::EnoughData, [protector] { webKitWebSrcEnoughData(protector.get()); });
205     },
206     // seek_data
207     [](GstAppSrc*, guint64 offset, gpointer userData) -> gboolean {
208         WebKitWebSrc* src = WEBKIT_WEB_SRC(userData);
209         WebKitWebSrcPrivate* priv = src->priv;
210
211         {
212             WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
213             if (offset == priv->offset && priv->requestedOffset == priv->offset)
214                 return TRUE;
215
216             if (!priv->seekable)
217                 return FALSE;
218
219             priv->isSeeking = true;
220             priv->requestedOffset = offset;
221         }
222
223         GRefPtr<WebKitWebSrc> protector(src);
224         priv->notifier.notify(MainThreadSourceNotification::Seek, [protector] { webKitWebSrcSeek(protector.get()); });
225         return TRUE;
226     },
227     { nullptr }
228 };
229
230 #define webkit_web_src_parent_class parent_class
231 // We split this out into another macro to avoid a check-webkit-style error.
232 #define WEBKIT_WEB_SRC_CATEGORY_INIT GST_DEBUG_CATEGORY_INIT(webkit_web_src_debug, "webkitwebsrc", 0, "websrc element");
233 G_DEFINE_TYPE_WITH_CODE(WebKitWebSrc, webkit_web_src, GST_TYPE_BIN,
234                          G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webKitWebSrcUriHandlerInit);
235                          WEBKIT_WEB_SRC_CATEGORY_INIT);
236
237 static void webkit_web_src_class_init(WebKitWebSrcClass* klass)
238 {
239     GObjectClass* oklass = G_OBJECT_CLASS(klass);
240     GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
241
242     oklass->dispose = webKitWebSrcDispose;
243     oklass->finalize = webKitWebSrcFinalize;
244     oklass->set_property = webKitWebSrcSetProperty;
245     oklass->get_property = webKitWebSrcGetProperty;
246
247     gst_element_class_add_pad_template(eklass,
248                                        gst_static_pad_template_get(&srcTemplate));
249     gst_element_class_set_metadata(eklass, "WebKit Web source element", "Source", "Handles HTTP/HTTPS uris",
250                                "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
251
252     /* Allows setting the uri using the 'location' property, which is used
253      * for example by gst_element_make_from_uri() */
254     g_object_class_install_property(oklass,
255                                     PROP_LOCATION,
256                                     g_param_spec_string("location",
257                                                         "location",
258                                                         "Location to read from",
259                                                         0,
260                                                         (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
261
262     g_object_class_install_property(oklass, PROP_KEEP_ALIVE,
263         g_param_spec_boolean("keep-alive", "keep-alive", "Use HTTP persistent connections",
264             FALSE, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
265
266     g_object_class_install_property(oklass, PROP_EXTRA_HEADERS,
267         g_param_spec_boxed("extra-headers", "Extra Headers", "Extra headers to append to the HTTP request",
268             GST_TYPE_STRUCTURE, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
269
270     g_object_class_install_property(oklass, PROP_COMPRESS,
271         g_param_spec_boolean("compress", "Compress", "Allow compressed content encodings",
272             FALSE, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
273
274     g_object_class_install_property(oklass, PROP_METHOD,
275         g_param_spec_string("method", "method", "The HTTP method to use (default: GET)",
276             nullptr, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
277
278     eklass->change_state = webKitWebSrcChangeState;
279
280     g_type_class_add_private(klass, sizeof(WebKitWebSrcPrivate));
281 }
282
283 static void webkit_web_src_init(WebKitWebSrc* src)
284 {
285     WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src);
286
287     src->priv = priv;
288     new (priv) WebKitWebSrcPrivate();
289
290     priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0));
291     if (!priv->appsrc) {
292         GST_ERROR_OBJECT(src, "Failed to create appsrc");
293         return;
294     }
295
296     gst_bin_add(GST_BIN(src), GST_ELEMENT(priv->appsrc));
297
298
299     GRefPtr<GstPad> targetPad = adoptGRef(gst_element_get_static_pad(GST_ELEMENT(priv->appsrc), "src"));
300     priv->srcpad = webkitGstGhostPadFromStaticTemplate(&srcTemplate, "src", targetPad.get());
301
302     gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
303
304     GST_OBJECT_FLAG_SET(priv->srcpad, GST_PAD_FLAG_NEED_PARENT);
305     gst_pad_set_query_function(priv->srcpad, webKitWebSrcQueryWithParent);
306
307     gst_app_src_set_callbacks(priv->appsrc, &appsrcCallbacks, src, 0);
308     gst_app_src_set_emit_signals(priv->appsrc, FALSE);
309     gst_app_src_set_stream_type(priv->appsrc, GST_APP_STREAM_TYPE_SEEKABLE);
310
311     // 512k is a abitrary number but we should choose a value
312     // here to not pause/unpause the SoupMessage too often and
313     // to make sure there's always some data available for
314     // GStreamer to handle.
315     gst_app_src_set_max_bytes(priv->appsrc, 512 * 1024);
316
317     // Emit the need-data signal if the queue contains less
318     // than 20% of data. Without this the need-data signal
319     // is emitted when the queue is empty, we then dispatch
320     // the soup message unpausing to the main loop and from
321     // there unpause the soup message. This already takes
322     // quite some time and libsoup even needs some more time
323     // to actually provide data again. If we do all this
324     // already if the queue is 20% empty, it's much more
325     // likely that libsoup already provides new data before
326     // the queue is really empty.
327     // This might need tweaking for ports not using libsoup.
328     g_object_set(priv->appsrc, "min-percent", 20, NULL);
329
330     gst_app_src_set_caps(priv->appsrc, 0);
331     gst_app_src_set_size(priv->appsrc, -1);
332 }
333
334 static void webKitWebSrcDispose(GObject* object)
335 {
336     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
337     WebKitWebSrcPrivate* priv = src->priv;
338
339     priv->player = 0;
340
341     GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
342 }
343
344 static void webKitWebSrcFinalize(GObject* object)
345 {
346     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
347     WebKitWebSrcPrivate* priv = src->priv;
348
349     g_free(priv->uri);
350     priv->~WebKitWebSrcPrivate();
351
352     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
353 }
354
355 static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
356 {
357     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
358
359     switch (propID) {
360     case PROP_LOCATION:
361         gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value), 0);
362         break;
363     case PROP_KEEP_ALIVE:
364         src->priv->keepAlive = g_value_get_boolean(value);
365         break;
366     case PROP_EXTRA_HEADERS: {
367         const GstStructure* s = gst_value_get_structure(value);
368         src->priv->extraHeaders.reset(s ? gst_structure_copy(s) : nullptr);
369         break;
370     }
371     case PROP_COMPRESS:
372         src->priv->compress = g_value_get_boolean(value);
373         break;
374     case PROP_METHOD:
375         src->priv->httpMethod.reset(g_value_dup_string(value));
376         break;
377     default:
378         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
379         break;
380     }
381 }
382
383 static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec)
384 {
385     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
386     WebKitWebSrcPrivate* priv = src->priv;
387
388     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
389     switch (propID) {
390     case PROP_LOCATION:
391         g_value_set_string(value, priv->uri);
392         break;
393     case PROP_KEEP_ALIVE:
394         g_value_set_boolean(value, priv->keepAlive);
395         break;
396     case PROP_EXTRA_HEADERS:
397         gst_value_set_structure(value, priv->extraHeaders.get());
398         break;
399     case PROP_COMPRESS:
400         g_value_set_boolean(value, priv->compress);
401         break;
402     case PROP_METHOD:
403         g_value_set_string(value, priv->httpMethod.get());
404         break;
405     default:
406         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
407         break;
408     }
409 }
410
411 static void webKitWebSrcStop(WebKitWebSrc* src)
412 {
413     WebKitWebSrcPrivate* priv = src->priv;
414
415     ASSERT(isMainThread());
416
417     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
418
419     bool wasSeeking = std::exchange(priv->isSeeking, false);
420
421     priv->notifier.cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek);
422
423     if (priv->client) {
424         delete priv->client;
425         priv->client = 0;
426     }
427
428     if (!priv->keepAlive)
429         priv->loader = nullptr;
430
431     if (priv->buffer) {
432         unmapGstBuffer(priv->buffer.get());
433         priv->buffer.clear();
434     }
435
436     priv->paused = FALSE;
437
438     priv->offset = 0;
439     priv->seekable = FALSE;
440
441     if (!wasSeeking) {
442         priv->size = 0;
443         priv->requestedOffset = 0;
444         priv->player = 0;
445     }
446
447     locker.unlock();
448
449     if (priv->appsrc) {
450         gst_app_src_set_caps(priv->appsrc, 0);
451         if (!wasSeeking)
452             gst_app_src_set_size(priv->appsrc, -1);
453     }
454
455     GST_DEBUG_OBJECT(src, "Stopped request");
456 }
457
458 static bool webKitWebSrcSetExtraHeader(GQuark fieldId, const GValue* value, gpointer userData)
459 {
460     GUniquePtr<gchar> fieldContent;
461
462     if (G_VALUE_HOLDS_STRING(value))
463         fieldContent.reset(g_value_dup_string(value));
464     else {
465         GValue dest = G_VALUE_INIT;
466
467         g_value_init(&dest, G_TYPE_STRING);
468         if (g_value_transform(value, &dest))
469             fieldContent.reset(g_value_dup_string(&dest));
470     }
471
472     const gchar* fieldName = g_quark_to_string(fieldId);
473     if (!fieldContent.get()) {
474         GST_ERROR("extra-headers field '%s' contains no value or can't be converted to a string", fieldName);
475         return false;
476     }
477
478     GST_DEBUG("Appending extra header: \"%s: %s\"", fieldName, fieldContent.get());
479     ResourceRequest* request = static_cast<ResourceRequest*>(userData);
480     request->setHTTPHeaderField(fieldName, fieldContent.get());
481     return true;
482 }
483
484 static gboolean webKitWebSrcProcessExtraHeaders(GQuark fieldId, const GValue* value, gpointer userData)
485 {
486     if (G_VALUE_TYPE(value) == GST_TYPE_ARRAY) {
487         unsigned size = gst_value_array_get_size(value);
488
489         for (unsigned i = 0; i < size; i++) {
490             if (!webKitWebSrcSetExtraHeader(fieldId, gst_value_array_get_value(value, i), userData))
491                 return FALSE;
492         }
493         return TRUE;
494     }
495
496     if (G_VALUE_TYPE(value) == GST_TYPE_LIST) {
497         unsigned size = gst_value_list_get_size(value);
498
499         for (unsigned i = 0; i < size; i++) {
500             if (!webKitWebSrcSetExtraHeader(fieldId, gst_value_list_get_value(value, i), userData))
501                 return FALSE;
502         }
503         return TRUE;
504     }
505
506     return webKitWebSrcSetExtraHeader(fieldId, value, userData);
507 }
508
509 static void webKitWebSrcStart(WebKitWebSrc* src)
510 {
511     WebKitWebSrcPrivate* priv = src->priv;
512
513     ASSERT(isMainThread());
514
515     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
516
517     priv->didPassAccessControlCheck = false;
518
519     if (!priv->uri) {
520         GST_ERROR_OBJECT(src, "No URI provided");
521         locker.unlock();
522         webKitWebSrcStop(src);
523         return;
524     }
525
526     ASSERT(!priv->client);
527
528     GST_DEBUG_OBJECT(src, "Fetching %s", priv->uri);
529     URL url = URL(URL(), priv->uri);
530
531     ResourceRequest request(url);
532     request.setAllowCookies(true);
533     request.setFirstPartyForCookies(url);
534
535     priv->size = 0;
536
537     if (priv->player)
538         request.setHTTPReferrer(priv->player->referrer());
539
540     if (priv->httpMethod.get())
541         request.setHTTPMethod(priv->httpMethod.get());
542
543 #if USE(SOUP)
544     // By default, HTTP Accept-Encoding is disabled here as we don't
545     // want the received response to be encoded in any way as we need
546     // to rely on the proper size of the returned data on
547     // didReceiveResponse.
548     // If Accept-Encoding is used, the server may send the data in encoded format and
549     // request.expectedContentLength() will have the "wrong" size (the size of the
550     // compressed data), even though the data received in didReceiveData is uncompressed.
551     // This is however useful to enable for adaptive streaming
552     // scenarios, when the demuxer needs to download playlists.
553     if (!priv->compress)
554         request.setAcceptEncoding(false);
555 #endif
556
557     // Let Apple web servers know we want to access their nice movie trailers.
558     if (!g_ascii_strcasecmp("movies.apple.com", url.host().utf8().data())
559         || !g_ascii_strcasecmp("trailers.apple.com", url.host().utf8().data()))
560         request.setHTTPUserAgent("Quicktime/7.6.6");
561
562     if (priv->requestedOffset) {
563         GUniquePtr<gchar> val(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset));
564         request.setHTTPHeaderField(HTTPHeaderName::Range, val.get());
565     }
566     priv->offset = priv->requestedOffset;
567
568     if (!priv->keepAlive) {
569         GST_DEBUG_OBJECT(src, "Persistent connection support disabled");
570         request.setHTTPHeaderField(HTTPHeaderName::Connection, "close");
571     }
572
573     if (priv->extraHeaders)
574         gst_structure_foreach(priv->extraHeaders.get(), webKitWebSrcProcessExtraHeaders, &request);
575
576     // We always request Icecast/Shoutcast metadata, just in case ...
577     request.setHTTPHeaderField(HTTPHeaderName::IcyMetadata, "1");
578
579     bool loadFailed = true;
580     if (priv->player && !priv->loader)
581         priv->loader = priv->player->createResourceLoader();
582
583     if (priv->loader) {
584         PlatformMediaResourceLoader::LoadOptions loadOptions = 0;
585         if (request.url().protocolIs("blob"))
586             loadOptions |= PlatformMediaResourceLoader::LoadOption::BufferData;
587         priv->resource = priv->loader->requestResource(request, loadOptions);
588         loadFailed = !priv->resource;
589
590         if (priv->resource)
591             priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(src));
592     } else {
593         priv->client = new ResourceHandleStreamingClient(src, request);
594         loadFailed = priv->client->loadFailed();
595     }
596
597     if (loadFailed) {
598         GST_ERROR_OBJECT(src, "Failed to setup streaming client");
599         if (priv->client) {
600             delete priv->client;
601             priv->client = nullptr;
602         }
603         priv->loader = nullptr;
604         priv->resource = nullptr;
605         locker.unlock();
606         webKitWebSrcStop(src);
607         return;
608     }
609     GST_DEBUG_OBJECT(src, "Started request");
610 }
611
612 static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition)
613 {
614     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
615     WebKitWebSrc* src = WEBKIT_WEB_SRC(element);
616     WebKitWebSrcPrivate* priv = src->priv;
617
618     switch (transition) {
619     case GST_STATE_CHANGE_NULL_TO_READY:
620         if (!priv->appsrc) {
621             gst_element_post_message(element,
622                                      gst_missing_element_message_new(element, "appsrc"));
623             GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no appsrc"));
624             return GST_STATE_CHANGE_FAILURE;
625         }
626         break;
627     default:
628         break;
629     }
630
631     ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
632     if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) {
633         GST_DEBUG_OBJECT(src, "State change failed");
634         return ret;
635     }
636
637     switch (transition) {
638     case GST_STATE_CHANGE_READY_TO_PAUSED:
639     {
640         GST_DEBUG_OBJECT(src, "READY->PAUSED");
641         GRefPtr<WebKitWebSrc> protector(src);
642         priv->notifier.notify(MainThreadSourceNotification::Start, [protector] { webKitWebSrcStart(protector.get()); });
643         break;
644     }
645     case GST_STATE_CHANGE_PAUSED_TO_READY:
646     {
647         GST_DEBUG_OBJECT(src, "PAUSED->READY");
648         priv->notifier.cancelPendingNotifications();
649         GRefPtr<WebKitWebSrc> protector(src);
650         priv->notifier.notify(MainThreadSourceNotification::Stop, [protector] { webKitWebSrcStop(protector.get()); });
651         break;
652     }
653     default:
654         break;
655     }
656
657     return ret;
658 }
659
660 static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query)
661 {
662     WebKitWebSrc* src = WEBKIT_WEB_SRC(GST_ELEMENT(parent));
663     gboolean result = FALSE;
664
665     switch (GST_QUERY_TYPE(query)) {
666     case GST_QUERY_DURATION: {
667         GstFormat format;
668
669         gst_query_parse_duration(query, &format, NULL);
670
671         GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format));
672         WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
673         if (format == GST_FORMAT_BYTES && src->priv->size > 0) {
674             gst_query_set_duration(query, format, src->priv->size);
675             result = TRUE;
676         }
677         break;
678     }
679     case GST_QUERY_URI: {
680         WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
681         gst_query_set_uri(query, src->priv->uri);
682         result = TRUE;
683         break;
684     }
685 #if GST_CHECK_VERSION(1, 2, 0)
686     case GST_QUERY_SCHEDULING: {
687         GstSchedulingFlags flags;
688         int minSize, maxSize, align;
689
690         gst_query_parse_scheduling(query, &flags, &minSize, &maxSize, &align);
691         gst_query_set_scheduling(query, static_cast<GstSchedulingFlags>(flags | GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED), minSize, maxSize, align);
692         result = TRUE;
693         break;
694     }
695 #endif
696     default: {
697         GRefPtr<GstPad> target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad)));
698
699         // Forward the query to the proxy target pad.
700         if (target)
701             result = gst_pad_query(target.get(), query);
702         break;
703     }
704     }
705
706     return result;
707 }
708
709 static bool urlHasSupportedProtocol(const URL& url)
710 {
711     return url.isValid() && (url.protocolIsInHTTPFamily() || url.protocolIs("blob"));
712 }
713
714 // uri handler interface
715
716 static GstURIType webKitWebSrcUriGetType(GType)
717 {
718     return GST_URI_SRC;
719 }
720
721 const gchar* const* webKitWebSrcGetProtocols(GType)
722 {
723     static const char* protocols[] = {"http", "https", "blob", 0 };
724     return protocols;
725 }
726
727 static gchar* webKitWebSrcGetUri(GstURIHandler* handler)
728 {
729     WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
730     gchar* ret;
731
732     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
733     ret = g_strdup(src->priv->uri);
734     return ret;
735 }
736
737 static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri, GError** error)
738 {
739     WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
740     WebKitWebSrcPrivate* priv = src->priv;
741
742     if (GST_STATE(src) >= GST_STATE_PAUSED) {
743         GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
744         return FALSE;
745     }
746
747     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
748
749     g_free(priv->uri);
750     priv->uri = 0;
751
752     if (!uri)
753         return TRUE;
754
755     URL url(URL(), uri);
756     if (!urlHasSupportedProtocol(url)) {
757         g_set_error(error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Invalid URI '%s'", uri);
758         return FALSE;
759     }
760
761     priv->uri = g_strdup(url.string().utf8().data());
762     return TRUE;
763 }
764
765 static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer)
766 {
767     GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
768
769     iface->get_type = webKitWebSrcUriGetType;
770     iface->get_protocols = webKitWebSrcGetProtocols;
771     iface->get_uri = webKitWebSrcGetUri;
772     iface->set_uri = webKitWebSrcSetUri;
773 }
774
775 // appsrc callbacks
776
777 static void webKitWebSrcNeedData(WebKitWebSrc* src)
778 {
779     WebKitWebSrcPrivate* priv = src->priv;
780
781     ASSERT(isMainThread());
782
783     GST_DEBUG_OBJECT(src, "Need more data");
784
785     {
786         WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
787         priv->paused = FALSE;
788     }
789
790     if (priv->client)
791         priv->client->setDefersLoading(false);
792     if (priv->resource)
793         priv->resource->setDefersLoading(false);
794 }
795
796 static void webKitWebSrcEnoughData(WebKitWebSrc* src)
797 {
798     WebKitWebSrcPrivate* priv = src->priv;
799
800     ASSERT(isMainThread());
801
802     GST_DEBUG_OBJECT(src, "Have enough data");
803
804     {
805         WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
806         priv->paused = TRUE;
807     }
808
809     if (priv->client)
810         priv->client->setDefersLoading(true);
811     if (priv->resource)
812         priv->resource->setDefersLoading(true);
813 }
814
815 static void webKitWebSrcSeek(WebKitWebSrc* src)
816 {
817     ASSERT(isMainThread());
818
819     GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, src->priv->requestedOffset);
820
821     webKitWebSrcStop(src);
822     webKitWebSrcStart(src);
823 }
824
825 void webKitWebSrcSetMediaPlayer(WebKitWebSrc* src, WebCore::MediaPlayer* player)
826 {
827     ASSERT(player);
828     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
829     src->priv->player = player;
830 }
831
832 bool webKitSrcPassedCORSAccessCheck(WebKitWebSrc* src)
833 {
834     return src->priv->didPassAccessControlCheck;
835 }
836
837 StreamingClient::StreamingClient(WebKitWebSrc* src)
838     : m_src(static_cast<GstElement*>(gst_object_ref(src)))
839 {
840 }
841
842 StreamingClient::~StreamingClient()
843 {
844     gst_object_unref(m_src);
845 }
846
847 char* StreamingClient::createReadBuffer(size_t requestedSize, size_t& actualSize)
848 {
849     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
850     WebKitWebSrcPrivate* priv = src->priv;
851
852     ASSERT(!priv->buffer);
853
854     GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
855
856     mapGstBuffer(buffer);
857
858     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
859     priv->buffer = adoptGRef(buffer);
860     locker.unlock();
861
862     actualSize = gst_buffer_get_size(buffer);
863     return getGstBufferDataPointer(buffer);
864 }
865
866 void StreamingClient::handleResponseReceived(const ResourceResponse& response)
867 {
868     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
869     WebKitWebSrcPrivate* priv = src->priv;
870
871     GST_DEBUG_OBJECT(src, "Received response: %d", response.httpStatusCode());
872
873     if (response.httpStatusCode() >= 400) {
874         GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received %d HTTP error code", response.httpStatusCode()), (nullptr));
875         gst_app_src_end_of_stream(priv->appsrc);
876         webKitWebSrcStop(src);
877         return;
878     }
879
880     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
881
882     if (priv->isSeeking) {
883         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring response");
884         return;
885     }
886
887     if (priv->requestedOffset) {
888         // Seeking ... we expect a 206 == PARTIAL_CONTENT
889         if (response.httpStatusCode() == 200) {
890             // Range request didn't have a ranged response; resetting offset.
891             priv->offset = 0;
892         } else if (response.httpStatusCode() != 206) {
893             // Range request completely failed.
894             locker.unlock();
895             GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received unexpected %d HTTP status code", response.httpStatusCode()), (nullptr));
896             gst_app_src_end_of_stream(priv->appsrc);
897             webKitWebSrcStop(src);
898             return;
899         }
900     }
901
902     long long length = response.expectedContentLength();
903     if (length > 0 && priv->requestedOffset && response.httpStatusCode() == 206)
904         length += priv->requestedOffset;
905
906     priv->size = length >= 0 ? length : 0;
907     priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField(HTTPHeaderName::AcceptRanges).utf8().data());
908
909     locker.unlock();
910
911     // notify size/duration
912     if (length > 0) {
913         gst_app_src_set_size(priv->appsrc, length);
914     } else
915         gst_app_src_set_size(priv->appsrc, -1);
916
917     gst_app_src_set_caps(priv->appsrc, 0);
918 }
919
920 void StreamingClient::handleDataReceived(const char* data, int length)
921 {
922     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
923     WebKitWebSrcPrivate* priv = src->priv;
924
925     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
926
927     GST_LOG_OBJECT(src, "Have %lld bytes of data", priv->buffer ? static_cast<long long>(gst_buffer_get_size(priv->buffer.get())) : length);
928
929     ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
930
931     if (priv->buffer)
932         unmapGstBuffer(priv->buffer.get());
933
934     if (priv->isSeeking) {
935         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring data");
936         priv->buffer.clear();
937         return;
938     }
939
940     if (priv->offset < priv->requestedOffset) {
941         // Range request failed; seeking manually.
942         if (priv->offset + length <= priv->requestedOffset) {
943             // Discard all the buffers coming before the requested seek position.
944             priv->offset += length;
945             priv->buffer.clear();
946             return;
947         }
948
949         if (priv->offset + length > priv->requestedOffset) {
950             guint64 offset = priv->requestedOffset - priv->offset;
951             data += offset;
952             length -= offset;
953             if (priv->buffer)
954                 gst_buffer_resize(priv->buffer.get(), offset, -1);
955             priv->offset = priv->requestedOffset;
956         }
957
958         priv->requestedOffset = 0;
959     }
960
961     // Ports using the GStreamer backend but not the soup implementation of ResourceHandle
962     // won't be using buffers provided by this client, the buffer is created here in that case.
963     if (!priv->buffer)
964         priv->buffer = adoptGRef(createGstBufferForData(data, length));
965     else
966         gst_buffer_set_size(priv->buffer.get(), static_cast<gssize>(length));
967
968     GST_BUFFER_OFFSET(priv->buffer.get()) = priv->offset;
969     if (priv->requestedOffset == priv->offset)
970         priv->requestedOffset += length;
971     priv->offset += length;
972     // priv->size == 0 if received length on didReceiveResponse < 0.
973     if (priv->size > 0 && priv->offset > priv->size) {
974         GST_DEBUG_OBJECT(src, "Updating internal size from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT, priv->size, priv->offset);
975         gst_app_src_set_size(priv->appsrc, priv->offset);
976         priv->size = priv->offset;
977     }
978     GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset;
979
980     locker.unlock();
981
982     GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef());
983     if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
984         GST_ELEMENT_ERROR(src, CORE, FAILED, (0), (0));
985 }
986
987 void StreamingClient::handleNotifyFinished()
988 {
989     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
990     WebKitWebSrcPrivate* priv = src->priv;
991
992     GST_DEBUG_OBJECT(src, "Have EOS");
993
994     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
995     if (!priv->isSeeking) {
996         locker.unlock();
997         gst_app_src_end_of_stream(priv->appsrc);
998     }
999 }
1000
1001 CachedResourceStreamingClient::CachedResourceStreamingClient(WebKitWebSrc* src)
1002     : StreamingClient(src)
1003 {
1004 }
1005
1006 CachedResourceStreamingClient::~CachedResourceStreamingClient()
1007 {
1008 }
1009
1010 #if USE(SOUP)
1011 char* CachedResourceStreamingClient::getOrCreateReadBuffer(PlatformMediaResource&, size_t requestedSize, size_t& actualSize)
1012 {
1013     return createReadBuffer(requestedSize, actualSize);
1014 }
1015 #endif
1016
1017 void CachedResourceStreamingClient::responseReceived(PlatformMediaResource&, const ResourceResponse& response)
1018 {
1019     WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC(m_src)->priv;
1020     priv->didPassAccessControlCheck = priv->resource->didPassAccessControlCheck();
1021     handleResponseReceived(response);
1022 }
1023
1024 void CachedResourceStreamingClient::dataReceived(PlatformMediaResource&, const char* data, int length)
1025 {
1026     handleDataReceived(data, length);
1027 }
1028
1029 void CachedResourceStreamingClient::accessControlCheckFailed(PlatformMediaResource&, const ResourceError& error)
1030 {
1031     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
1032     GST_ELEMENT_ERROR(src, RESOURCE, READ, ("%s", error.localizedDescription().utf8().data()), (nullptr));
1033     gst_app_src_end_of_stream(src->priv->appsrc);
1034     webKitWebSrcStop(src);
1035 }
1036
1037 void CachedResourceStreamingClient::loadFailed(PlatformMediaResource&, const ResourceError& error)
1038 {
1039     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
1040
1041     if (!error.isCancellation()) {
1042         GST_ERROR_OBJECT(src, "Have failure: %s", error.localizedDescription().utf8().data());
1043         GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (nullptr));
1044     }
1045
1046     gst_app_src_end_of_stream(src->priv->appsrc);
1047 }
1048
1049 void CachedResourceStreamingClient::loadFinished(PlatformMediaResource&)
1050 {
1051     handleNotifyFinished();
1052 }
1053
1054 ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, const ResourceRequest& request)
1055     : StreamingClient(src)
1056 {
1057     m_resource = ResourceHandle::create(0 /*context*/, request, this, false, false);
1058 }
1059
1060 ResourceHandleStreamingClient::~ResourceHandleStreamingClient()
1061 {
1062     if (m_resource) {
1063         m_resource->cancel();
1064         m_resource = nullptr;
1065     }
1066 }
1067
1068 bool ResourceHandleStreamingClient::loadFailed() const
1069 {
1070     return !m_resource;
1071 }
1072
1073 void ResourceHandleStreamingClient::setDefersLoading(bool defers)
1074 {
1075     if (m_resource)
1076         m_resource->setDefersLoading(defers);
1077 }
1078
1079 char* ResourceHandleStreamingClient::getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize)
1080 {
1081     return createReadBuffer(requestedSize, actualSize);
1082 }
1083
1084 void ResourceHandleStreamingClient::willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&)
1085 {
1086 }
1087
1088 void ResourceHandleStreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
1089 {
1090     handleResponseReceived(response);
1091 }
1092
1093 void ResourceHandleStreamingClient::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int)
1094 {
1095     ASSERT_NOT_REACHED();
1096 }
1097
1098 void ResourceHandleStreamingClient::didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int /* encodedLength */)
1099 {
1100     // This pattern is suggested by SharedBuffer.h.
1101     const char* segment;
1102     unsigned position = 0;
1103     while (unsigned length = buffer->getSomeData(segment, position)) {
1104         handleDataReceived(segment, length);
1105         position += length;
1106     }
1107 }
1108
1109 void ResourceHandleStreamingClient::didFinishLoading(ResourceHandle*, double)
1110 {
1111     handleNotifyFinished();
1112 }
1113
1114 void ResourceHandleStreamingClient::didFail(ResourceHandle*, const ResourceError& error)
1115 {
1116     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
1117
1118     GST_ERROR_OBJECT(src, "Have failure: %s", error.localizedDescription().utf8().data());
1119     GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
1120     gst_app_src_end_of_stream(src->priv->appsrc);
1121 }
1122
1123 void ResourceHandleStreamingClient::wasBlocked(ResourceHandle*)
1124 {
1125     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
1126     GUniquePtr<gchar> uri;
1127
1128     GST_ERROR_OBJECT(src, "Request was blocked");
1129
1130     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
1131     uri.reset(g_strdup(src->priv->uri));
1132     locker.unlock();
1133
1134     GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", uri.get()), (0));
1135 }
1136
1137 void ResourceHandleStreamingClient::cannotShowURL(ResourceHandle*)
1138 {
1139     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
1140     GUniquePtr<gchar> uri;
1141
1142     GST_ERROR_OBJECT(src, "Cannot show URL");
1143
1144     WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src));
1145     uri.reset(g_strdup(src->priv->uri));
1146     locker.unlock();
1147
1148     GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", uri.get()), (0));
1149 }
1150
1151 #endif // USE(GSTREAMER)
1152