Changeset 154683 in webkit


Ignore:
Timestamp:
Aug 27, 2013 8:00:07 AM (11 years ago)
Author:
commit-queue@webkit.org
Message:

[gstreamer] Make sure gstreamer source element is thread-safe
https://bugs.webkit.org/show_bug.cgi?id=115352

Patch by Andre Moreira Magalhaes <Andre Moreira Magalhaes> on 2013-08-27
Reviewed by Philippe Normand.

Source/WebCore:

GStreamer source element may be created by any gstreamer element on any thread by calling
gst_element_make_from_uri with the URIs handled by the source element.
This patch makes sure the gstreamer source element is thread-safe to avoid issues with it
being created outside the main thread.

  • platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:

(webkit_web_src_init):
(webKitWebSrcDispose):
(webKitWebSrcFinalize):
(webKitWebSrcSetProperty):
(webKitWebSrcGetProperty):
(removeTimeoutSources):
(webKitWebSrcStop):
(webKitWebSrcStart):
(webKitWebSrcChangeState):
(webKitWebSrcQueryWithParent):
(webKitWebSrcGetUri):
(webKitWebSrcSetUri):
(webKitWebSrcNeedDataMainCb):
(webKitWebSrcNeedDataCb):
(webKitWebSrcEnoughDataMainCb):
(webKitWebSrcEnoughDataCb):
(webKitWebSrcSeekMainCb):
(webKitWebSrcSeekDataCb):
(webKitWebSrcSetMediaPlayer):
(StreamingClient::StreamingClient):
(StreamingClient::~StreamingClient):
(StreamingClient::createReadBuffer):
(StreamingClient::handleResponseReceived):
(StreamingClient::handleDataReceived):
(StreamingClient::handleNotifyFinished):
(CachedResourceStreamingClient::CachedResourceStreamingClient):
(CachedResourceStreamingClient::~CachedResourceStreamingClient):
(CachedResourceStreamingClient::loadFailed):
(CachedResourceStreamingClient::setDefersLoading):
(CachedResourceStreamingClient::getOrCreateReadBuffer):
(CachedResourceStreamingClient::responseReceived):
(CachedResourceStreamingClient::dataReceived):
(CachedResourceStreamingClient::notifyFinished):
(ResourceHandleStreamingClient::ResourceHandleStreamingClient):
(ResourceHandleStreamingClient::~ResourceHandleStreamingClient):
(ResourceHandleStreamingClient::loadFailed):
(ResourceHandleStreamingClient::setDefersLoading):
(ResourceHandleStreamingClient::getOrCreateReadBuffer):
(ResourceHandleStreamingClient::willSendRequest):
(ResourceHandleStreamingClient::didReceiveResponse):
(ResourceHandleStreamingClient::didReceiveData):
(ResourceHandleStreamingClient::didFinishLoading):
(ResourceHandleStreamingClient::didFail):
(ResourceHandleStreamingClient::wasBlocked):
(ResourceHandleStreamingClient::cannotShowURL):
Make element thread-safe, add support to use the element without a player associated (e.g.
the DASH plugin using the webkitsrc to download fragments), use GMutexLocker to simplify
locks and other general improvements.

Source/WTF:

Add convenience class that simplifies locking and unlocking a GMutex.

  • GNUmakefile.list.am:
  • wtf/gobject/GMutexLocker.h: Added.

(WebCore::GMutexLocker::GMutexLocker):
(WebCore::GMutexLocker::~GMutexLocker):
(WebCore::GMutexLocker::lock):
(WebCore::GMutexLocker::unlock):
(WebCore::GMutexLocker::mutex):

Location:
trunk/Source
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r154655 r154683  
     12013-08-27  Andre Moreira Magalhaes   <andre.magalhaes@collabora.co.uk>
     2
     3        [gstreamer] Make sure gstreamer source element is thread-safe
     4        https://bugs.webkit.org/show_bug.cgi?id=115352
     5
     6        Reviewed by Philippe Normand.
     7
     8        Add convenience class that simplifies locking and unlocking a GMutex.
     9
     10        * GNUmakefile.list.am:
     11        * wtf/gobject/GMutexLocker.h: Added.
     12        (WebCore::GMutexLocker::GMutexLocker):
     13        (WebCore::GMutexLocker::~GMutexLocker):
     14        (WebCore::GMutexLocker::lock):
     15        (WebCore::GMutexLocker::unlock):
     16        (WebCore::GMutexLocker::mutex):
     17
    1182013-08-26  Andy Estes  <aestes@apple.com>
    219
  • trunk/Source/WTF/GNUmakefile.list.am

    r154498 r154683  
    214214    Source/WTF/wtf/dtoa/strtod.h \
    215215    Source/WTF/wtf/dtoa/utils.h \
     216    Source/WTF/wtf/gobject/GMutexLocker.h \
    216217    Source/WTF/wtf/gobject/GOwnPtr.cpp \
    217218    Source/WTF/wtf/gobject/GOwnPtr.h \
  • trunk/Source/WebCore/ChangeLog

    r154682 r154683  
     12013-08-27  Andre Moreira Magalhaes   <andre.magalhaes@collabora.co.uk>
     2
     3        [gstreamer] Make sure gstreamer source element is thread-safe
     4        https://bugs.webkit.org/show_bug.cgi?id=115352
     5
     6        Reviewed by Philippe Normand.
     7
     8        GStreamer source element may be created by any gstreamer element on any thread by calling
     9        gst_element_make_from_uri with the URIs handled by the source element.
     10        This patch makes sure the gstreamer source element is thread-safe to avoid issues with it
     11        being created outside the main thread.
     12
     13        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
     14        (webkit_web_src_init):
     15        (webKitWebSrcDispose):
     16        (webKitWebSrcFinalize):
     17        (webKitWebSrcSetProperty):
     18        (webKitWebSrcGetProperty):
     19        (removeTimeoutSources):
     20        (webKitWebSrcStop):
     21        (webKitWebSrcStart):
     22        (webKitWebSrcChangeState):
     23        (webKitWebSrcQueryWithParent):
     24        (webKitWebSrcGetUri):
     25        (webKitWebSrcSetUri):
     26        (webKitWebSrcNeedDataMainCb):
     27        (webKitWebSrcNeedDataCb):
     28        (webKitWebSrcEnoughDataMainCb):
     29        (webKitWebSrcEnoughDataCb):
     30        (webKitWebSrcSeekMainCb):
     31        (webKitWebSrcSeekDataCb):
     32        (webKitWebSrcSetMediaPlayer):
     33        (StreamingClient::StreamingClient):
     34        (StreamingClient::~StreamingClient):
     35        (StreamingClient::createReadBuffer):
     36        (StreamingClient::handleResponseReceived):
     37        (StreamingClient::handleDataReceived):
     38        (StreamingClient::handleNotifyFinished):
     39        (CachedResourceStreamingClient::CachedResourceStreamingClient):
     40        (CachedResourceStreamingClient::~CachedResourceStreamingClient):
     41        (CachedResourceStreamingClient::loadFailed):
     42        (CachedResourceStreamingClient::setDefersLoading):
     43        (CachedResourceStreamingClient::getOrCreateReadBuffer):
     44        (CachedResourceStreamingClient::responseReceived):
     45        (CachedResourceStreamingClient::dataReceived):
     46        (CachedResourceStreamingClient::notifyFinished):
     47        (ResourceHandleStreamingClient::ResourceHandleStreamingClient):
     48        (ResourceHandleStreamingClient::~ResourceHandleStreamingClient):
     49        (ResourceHandleStreamingClient::loadFailed):
     50        (ResourceHandleStreamingClient::setDefersLoading):
     51        (ResourceHandleStreamingClient::getOrCreateReadBuffer):
     52        (ResourceHandleStreamingClient::willSendRequest):
     53        (ResourceHandleStreamingClient::didReceiveResponse):
     54        (ResourceHandleStreamingClient::didReceiveData):
     55        (ResourceHandleStreamingClient::didFinishLoading):
     56        (ResourceHandleStreamingClient::didFail):
     57        (ResourceHandleStreamingClient::wasBlocked):
     58        (ResourceHandleStreamingClient::cannotShowURL):
     59        Make element thread-safe, add support to use the element without a player associated (e.g.
     60        the DASH plugin using the webkitsrc to download fragments), use GMutexLocker to simplify
     61        locks and other general improvements.
     62
    1632013-08-27  Antti Koivisto  <antti@apple.com>
    264
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp

    r153795 r154683  
    3232#include "MediaPlayer.h"
    3333#include "NotImplemented.h"
     34#include "ResourceHandle.h"
     35#include "ResourceHandleClient.h"
    3436#include "ResourceRequest.h"
    3537#include "ResourceResponse.h"
     
    3840#include <gst/pbutils/missing-plugins.h>
    3941#include <wtf/Noncopyable.h>
     42#include <wtf/gobject/GMutexLocker.h>
    4043#include <wtf/gobject/GOwnPtr.h>
    4144#include <wtf/gobject/GRefPtr.h>
     
    4447using namespace WebCore;
    4548
    46 class StreamingClient : public CachedRawResourceClient {
    47     WTF_MAKE_NONCOPYABLE(StreamingClient); WTF_MAKE_FAST_ALLOCATED;
     49class StreamingClient {
    4850    public:
    4951        StreamingClient(WebKitWebSrc*);
    5052        virtual ~StreamingClient();
    5153
     54        virtual bool loadFailed() const = 0;
     55        virtual void setDefersLoading(bool) = 0;
     56
     57    protected:
     58        char* createReadBuffer(size_t requestedSize, size_t& actualSize);
     59        void handleResponseReceived(const ResourceResponse&);
     60        void handleDataReceived(const char*, int);
     61        void handleNotifyFinished();
     62
     63        GRefPtr<GstElement> m_src;
     64};
     65
     66class CachedResourceStreamingClient : public CachedRawResourceClient, public StreamingClient {
     67    WTF_MAKE_NONCOPYABLE(CachedResourceStreamingClient); WTF_MAKE_FAST_ALLOCATED;
     68    public:
     69        CachedResourceStreamingClient(WebKitWebSrc*, CachedResourceLoader*, const ResourceRequest&);
     70        virtual ~CachedResourceStreamingClient();
     71
     72        // StreamingClient virtual methods.
     73        virtual bool loadFailed() const;
     74        virtual void setDefersLoading(bool);
     75
    5276    private:
    53         // CachedResourceClient
     77        // CachedResourceClient virtual methods.
     78        virtual char* getOrCreateReadBuffer(CachedResource*, size_t requestedSize, size_t& actualSize);
    5479        virtual void responseReceived(CachedResource*, const ResourceResponse&);
    5580        virtual void dataReceived(CachedResource*, const char*, int);
    5681        virtual void notifyFinished(CachedResource*);
    57         virtual char* getOrCreateReadBuffer(CachedResource*, size_t requestedSize, size_t& actualSize);
    58 
    59         WebKitWebSrc* m_src;
     82
     83        CachedResourceHandle<CachedRawResource> m_resource;
     84};
     85
     86class ResourceHandleStreamingClient : public ResourceHandleClient, public StreamingClient {
     87    WTF_MAKE_NONCOPYABLE(ResourceHandleStreamingClient); WTF_MAKE_FAST_ALLOCATED;
     88    public:
     89        ResourceHandleStreamingClient(WebKitWebSrc*, const ResourceRequest&);
     90        virtual ~ResourceHandleStreamingClient();
     91
     92        // StreamingClient virtual methods.
     93        virtual bool loadFailed() const;
     94        virtual void setDefersLoading(bool);
     95
     96    private:
     97        // ResourceHandleClient virtual methods.
     98        virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize);
     99        virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
     100        virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
     101        virtual void didReceiveData(ResourceHandle*, const char*, int, int);
     102        virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
     103        virtual void didFail(ResourceHandle*, const ResourceError&);
     104        virtual void wasBlocked(ResourceHandle*);
     105        virtual void cannotShowURL(ResourceHandle*);
     106
     107        RefPtr<ResourceHandle> m_resource;
    60108};
    61109
     
    69117
    70118    StreamingClient* client;
    71     CachedResourceHandle<CachedRawResource> resource;
    72119
    73120    guint64 offset;
     
    78125    guint64 requestedOffset;
    79126
     127    guint startID;
     128    guint stopID;
    80129    guint needDataID;
    81130    guint enoughDataID;
     
    130179static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer userData);
    131180
    132 static void webKitWebSrcStop(WebKitWebSrc*, bool);
    133 
    134181static GstAppSrcCallbacks appsrcCallbacks = {
    135182    webKitWebSrcNeedDataCb,
     
    185232                                                        0,
    186233                                                        (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
    187                                                        
     234
    188235    g_object_class_install_property(oklass,
    189236                                    PROP_IRADIO_URL,
     
    222269
    223270    src->priv = priv;
    224 
    225     priv->client = new StreamingClient(src);
    226271
    227272    priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0));
     
    273318        g_object_set(priv->appsrc, "min-percent", 20, NULL);
    274319
    275     webKitWebSrcStop(src, false);
     320    gst_app_src_set_caps(priv->appsrc, 0);
     321    gst_app_src_set_size(priv->appsrc, -1);
    276322}
    277323
     
    281327    WebKitWebSrcPrivate* priv = src->priv;
    282328
    283     if (priv->buffer) {
    284 #ifdef GST_API_VERSION_1
    285         unmapGstBuffer(priv->buffer.get());
    286 #endif
    287         priv->buffer.clear();
    288     }
    289 
    290329    priv->player = 0;
    291330
     
    298337    WebKitWebSrcPrivate* priv = src->priv;
    299338
    300     delete priv->client;
    301 
    302339    g_free(priv->uri);
    303340
     
    311348
    312349    switch (propID) {
    313     case PROP_IRADIO_MODE:
     350    case PROP_IRADIO_MODE: {
     351        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    314352        priv->iradioMode = g_value_get_boolean(value);
    315353        break;
     354    }
    316355    case PROP_LOCATION:
    317356#ifdef GST_API_VERSION_1
     
    332371    WebKitWebSrcPrivate* priv = src->priv;
    333372
     373    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    334374    switch (propID) {
    335375    case PROP_IRADIO_MODE:
     
    357397}
    358398
    359 
    360 static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking)
    361 {
    362     WebKitWebSrcPrivate* priv = src->priv;
    363 
    364     if (priv->resource) {
    365         priv->resource->removeClient(priv->client);
    366         priv->resource = 0;
    367     }
     399static void removeTimeoutSources(WebKitWebSrc* src)
     400{
     401    WebKitWebSrcPrivate* priv = src->priv;
     402
     403    if (priv->startID)
     404        g_source_remove(priv->startID);
     405    priv->startID = 0;
     406
     407    if (priv->needDataID)
     408        g_source_remove(priv->needDataID);
     409    priv->needDataID = 0;
     410
     411    if (priv->enoughDataID)
     412        g_source_remove(priv->enoughDataID);
     413    priv->enoughDataID = 0;
     414
     415    if (priv->seekID)
     416        g_source_remove(priv->seekID);
     417    priv->seekID = 0;
     418}
     419
     420static gboolean webKitWebSrcStop(WebKitWebSrc* src)
     421{
     422    WebKitWebSrcPrivate* priv = src->priv;
     423
     424    ASSERT(isMainThread());
     425
     426    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     427
     428    bool seeking = priv->seekID;
     429
     430    removeTimeoutSources(src);
     431    priv->stopID = 0;
    368432
    369433    if (priv->client) {
     
    379443    }
    380444
    381     GST_OBJECT_LOCK(src);
    382     if (priv->needDataID)
    383         g_source_remove(priv->needDataID);
    384     priv->needDataID = 0;
    385 
    386     if (priv->enoughDataID)
    387         g_source_remove(priv->enoughDataID);
    388     priv->enoughDataID = 0;
    389 
    390     if (priv->seekID)
    391         g_source_remove(priv->seekID);
    392     priv->seekID = 0;
    393 
    394445    priv->paused = FALSE;
    395     GST_OBJECT_UNLOCK(src);
    396446
    397447    g_free(priv->iradioName);
     
    406456    g_free(priv->iradioTitle);
    407457    priv->iradioTitle = 0;
     458
     459    priv->offset = 0;
     460    priv->seekable = FALSE;
     461
     462    if (!seeking) {
     463        priv->size = 0;
     464        priv->requestedOffset = 0;
     465        priv->player = 0;
     466    }
     467
     468    locker.unlock();
    408469
    409470    if (priv->appsrc) {
     
    413474    }
    414475
    415     priv->offset = 0;
    416     priv->seekable = FALSE;
    417 
    418     if (!seeking) {
    419         priv->size = 0;
    420         priv->requestedOffset = 0;
    421     }
    422 
    423476    GST_DEBUG_OBJECT(src, "Stopped request");
    424 }
    425 
    426 static bool webKitWebSrcStart(WebKitWebSrc* src)
    427 {
    428     WebKitWebSrcPrivate* priv = src->priv;
     477
     478    return FALSE;
     479}
     480
     481static gboolean webKitWebSrcStart(WebKitWebSrc* src)
     482{
     483    WebKitWebSrcPrivate* priv = src->priv;
     484
     485    ASSERT(isMainThread());
     486
     487    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     488
     489    priv->startID = 0;
    429490
    430491    if (!priv->uri) {
    431492        GST_ERROR_OBJECT(src, "No URI provided");
    432         return false;
    433     }
    434 
    435     ASSERT(priv->player);
     493        locker.unlock();
     494        webKitWebSrcStop(src);
     495        return FALSE;
     496    }
     497
     498    ASSERT(!priv->client);
    436499
    437500    KURL url = KURL(KURL(), priv->uri);
     
    439502    ResourceRequest request(url);
    440503    request.setAllowCookies(true);
    441     request.setHTTPReferrer(priv->player->referrer());
     504
     505    if (priv->player)
     506        request.setHTTPReferrer(priv->player->referrer());
    442507
    443508#if USE(SOUP)
     
    470535    request.setHTTPHeaderField("transferMode.dlna", "Streaming");
    471536
    472     if (CachedResourceLoader* loader = priv->player->cachedResourceLoader()) {
    473         CachedResourceRequest cacheRequest(request, ResourceLoaderOptions(SendCallbacks, DoNotSniffContent, DoNotBufferData, DoNotAllowStoredCredentials, DoNotAskClientForCrossOriginCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType));
    474         priv->resource = loader->requestRawResource(cacheRequest);
    475         if (priv->resource) {
    476             priv->client = new StreamingClient(src);
    477             priv->resource->addClient(priv->client);
     537    if (priv->player) {
     538        if (CachedResourceLoader* loader = priv->player->cachedResourceLoader())
     539            priv->client = new CachedResourceStreamingClient(src, loader, request);
     540    }
     541
     542    if (!priv->client)
     543        priv->client = new ResourceHandleStreamingClient(src, request);
     544
     545    if (!priv->client || priv->client->loadFailed()) {
     546        GST_ERROR_OBJECT(src, "Failed to setup streaming client");
     547        if (priv->client) {
     548            delete priv->client;
     549            priv->client = 0;
    478550        }
    479     }
    480 
    481     if (!priv->resource) {
    482         GST_ERROR_OBJECT(src, "Failed to schedule resource load");
    483         return false;
    484     }
    485 
     551        locker.unlock();
     552        webKitWebSrcStop(src);
     553        return FALSE;
     554    }
    486555    GST_DEBUG_OBJECT(src, "Started request");
    487 
    488     return true;
     556    return FALSE;
    489557}
    490558
     
    514582    }
    515583
     584    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    516585    switch (transition) {
    517586    case GST_STATE_CHANGE_READY_TO_PAUSED:
    518587        GST_DEBUG_OBJECT(src, "READY->PAUSED");
    519         if (!webKitWebSrcStart(src))
    520             ret = GST_STATE_CHANGE_FAILURE;
     588        priv->startID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcStart, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    521589        break;
    522590    case GST_STATE_CHANGE_PAUSED_TO_READY:
    523591        GST_DEBUG_OBJECT(src, "PAUSED->READY");
    524         webKitWebSrcStop(src, false);
     592        // cancel pending sources
     593        removeTimeoutSources(src);
     594        priv->stopID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcStop, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    525595        break;
    526596    default:
     
    533603static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query)
    534604{
    535     WebKitWebSrc* webkitSrc = WEBKIT_WEB_SRC(GST_ELEMENT(parent));
     605    WebKitWebSrc* src = WEBKIT_WEB_SRC(GST_ELEMENT(parent));
    536606    gboolean result = FALSE;
    537607
     
    542612        gst_query_parse_duration(query, &format, NULL);
    543613
    544         GST_DEBUG_OBJECT(webkitSrc, "duration query in format %s", gst_format_get_name(format));
    545         if ((format == GST_FORMAT_BYTES) && (webkitSrc->priv->size > 0)) {
    546             gst_query_set_duration(query, format, webkitSrc->priv->size);
     614        GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format));
     615        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     616        if (format == GST_FORMAT_BYTES && src->priv->size > 0) {
     617            gst_query_set_duration(query, format, src->priv->size);
    547618            result = TRUE;
    548619        }
     
    550621    }
    551622    case GST_QUERY_URI: {
    552         gst_query_set_uri(query, webkitSrc->priv->uri);
     623        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     624        gst_query_set_uri(query, src->priv->uri);
    553625        result = TRUE;
    554626        break;
     
    591663static gchar* webKitWebSrcGetUri(GstURIHandler* handler)
    592664{
    593     return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri);
     665    WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
     666    gchar* ret;
     667
     668    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     669    ret = g_strdup(src->priv->uri);
     670    return ret;
    594671}
    595672
     
    604681    }
    605682
     683    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     684
    606685    g_free(priv->uri);
    607686    priv->uri = 0;
     
    635714static const gchar* webKitWebSrcGetUri(GstURIHandler* handler)
    636715{
    637     return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri);
     716    WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
     717    gchar* ret;
     718
     719    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     720    ret = g_strdup(src->priv->uri);
     721    return ret;
    638722}
    639723
     
    647731        return FALSE;
    648732    }
     733
     734    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    649735
    650736    g_free(priv->uri);
     
    682768    WebKitWebSrcPrivate* priv = src->priv;
    683769
    684     priv->resource->setDefersLoading(false);
    685 
    686     GST_OBJECT_LOCK(src);
     770    ASSERT(isMainThread());
     771
     772    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     773    // already stopped
     774    if (!priv->needDataID)
     775        return FALSE;
     776
    687777    priv->paused = FALSE;
    688778    priv->needDataID = 0;
    689     GST_OBJECT_UNLOCK(src);
     779    locker.unlock();
     780
     781    if (priv->client)
     782        priv->client->setDefersLoading(false);
    690783    return FALSE;
    691784}
     
    698791    GST_DEBUG_OBJECT(src, "Need more data: %u", length);
    699792
    700     GST_OBJECT_LOCK(src);
     793    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    701794    if (priv->needDataID || !priv->paused) {
    702         GST_OBJECT_UNLOCK(src);
    703795        return;
    704796    }
    705797
    706     priv->needDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    707     GST_OBJECT_UNLOCK(src);
     798    priv->needDataID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    708799}
    709800
     
    712803    WebKitWebSrcPrivate* priv = src->priv;
    713804
    714     priv->resource->setDefersLoading(true);
    715 
    716     GST_OBJECT_LOCK(src);
     805    ASSERT(isMainThread());
     806
     807    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     808    // already stopped
     809    if (!priv->enoughDataID)
     810        return FALSE;
     811
    717812    priv->paused = TRUE;
    718813    priv->enoughDataID = 0;
    719     GST_OBJECT_UNLOCK(src);
    720 
     814    locker.unlock();
     815
     816    if (priv->client)
     817        priv->client->setDefersLoading(true);
    721818    return FALSE;
    722819}
     
    729826    GST_DEBUG_OBJECT(src, "Have enough data");
    730827
    731     GST_OBJECT_LOCK(src);
     828    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    732829    if (priv->enoughDataID || priv->paused) {
    733         GST_OBJECT_UNLOCK(src);
    734830        return;
    735831    }
    736832
    737     priv->enoughDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    738     GST_OBJECT_UNLOCK(src);
     833    priv->enoughDataID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    739834}
    740835
    741836static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src)
    742837{
    743     webKitWebSrcStop(src, true);
     838    WebKitWebSrcPrivate* priv = src->priv;
     839
     840    ASSERT(isMainThread());
     841
     842    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     843    // already stopped
     844    if (!priv->seekID)
     845        return FALSE;
     846    locker.unlock();
     847
     848    webKitWebSrcStop(src);
    744849    webKitWebSrcStart(src);
    745850
     
    753858
    754859    GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, offset);
     860    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    755861    if (offset == priv->offset && priv->requestedOffset == priv->offset)
    756862        return TRUE;
     
    762868    priv->requestedOffset = offset;
    763869
    764     GST_OBJECT_LOCK(src);
    765870    if (priv->seekID)
    766871        g_source_remove(priv->seekID);
    767     priv->seekID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    768     GST_OBJECT_UNLOCK(src);
    769    
     872    priv->seekID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
    770873    return TRUE;
    771874}
     
    774877{
    775878    ASSERT(player);
     879    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    776880    src->priv->player = player;
    777881}
    778882
    779 StreamingClient::StreamingClient(WebKitWebSrc* src) : m_src(src)
    780 {
    781 
     883StreamingClient::StreamingClient(WebKitWebSrc* src)
     884    : m_src(adoptGRef(static_cast<GstElement*>(gst_object_ref(src))))
     885{
    782886}
    783887
    784888StreamingClient::~StreamingClient()
    785889{
    786 
    787 }
    788 
    789 void StreamingClient::responseReceived(CachedResource* resource, const ResourceResponse& response)
    790 {
    791     WebKitWebSrcPrivate* priv = m_src->priv;
    792 
    793     GST_DEBUG_OBJECT(m_src, "Received response: %d", response.httpStatusCode());
     890}
     891
     892char* StreamingClient::createReadBuffer(size_t requestedSize, size_t& actualSize)
     893{
     894    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     895    WebKitWebSrcPrivate* priv = src->priv;
     896
     897    ASSERT(!priv->buffer);
     898
     899    GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
     900
     901#ifdef GST_API_VERSION_1
     902    mapGstBuffer(buffer);
     903#endif
     904
     905    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     906    priv->buffer = adoptGRef(buffer);
     907    locker.unlock();
     908
     909    actualSize = getGstBufferSize(buffer);
     910    return getGstBufferDataPointer(buffer);
     911}
     912
     913void StreamingClient::handleResponseReceived(const ResourceResponse& response)
     914{
     915    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     916    WebKitWebSrcPrivate* priv = src->priv;
     917
     918    GST_DEBUG_OBJECT(src, "Received response: %d", response.httpStatusCode());
     919
     920    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
    794921
    795922    // If we seeked we need 206 == PARTIAL_CONTENT
    796923    if (priv->requestedOffset && response.httpStatusCode() != 206) {
    797         GST_ELEMENT_ERROR(m_src, RESOURCE, READ, (0), (0));
     924        locker.unlock();
     925        GST_ELEMENT_ERROR(src, RESOURCE, READ, (0), (0));
    798926        gst_app_src_end_of_stream(priv->appsrc);
    799         webKitWebSrcStop(m_src, false);
     927        webKitWebSrcStop(src);
    800928        return;
    801929    }
    802930
    803931    long long length = response.expectedContentLength();
    804     if (length > 0) {
     932    if (length > 0)
    805933        length += priv->requestedOffset;
    806         gst_app_src_set_size(priv->appsrc, length);
    807 
    808 #ifndef GST_API_VERSION_1
    809         if (!priv->haveAppSrc27) {
    810             gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);
    811             gst_element_post_message(GST_ELEMENT(priv->appsrc),
    812                                      gst_message_new_duration(GST_OBJECT(priv->appsrc),
    813                                                               GST_FORMAT_BYTES, length));
    814         }
    815 #endif
    816     }
    817934
    818935    priv->size = length >= 0 ? length : 0;
    819936    priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField("Accept-Ranges").utf8().data());
    820 
    821     // icecast stuff
    822     String value = response.httpHeaderField("icy-metaint");
    823     if (!value.isEmpty()) {
    824         gchar* endptr = 0;
    825         gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10);
    826            
    827         if (endptr && *endptr == '\0' && icyMetaInt > 0) {
    828             GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_simple("application/x-icy", "metadata-interval", G_TYPE_INT, (gint) icyMetaInt, NULL));
    829 
    830             gst_app_src_set_caps(priv->appsrc, caps.get());
    831         }
    832     }
    833937
    834938#ifdef GST_API_VERSION_1
     
    837941    GstTagList* tags = gst_tag_list_new();
    838942#endif
    839     value = response.httpHeaderField("icy-name");
     943    String value = response.httpHeaderField("icy-name");
    840944    if (!value.isEmpty()) {
    841945        g_free(priv->iradioName);
    842946        priv->iradioName = g_strdup(value.utf8().data());
    843         g_object_notify(G_OBJECT(m_src), "iradio-name");
     947        g_object_notify(G_OBJECT(src), "iradio-name");
    844948        gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, priv->iradioName, NULL);
    845949    }
     
    848952        g_free(priv->iradioGenre);
    849953        priv->iradioGenre = g_strdup(value.utf8().data());
    850         g_object_notify(G_OBJECT(m_src), "iradio-genre");
     954        g_object_notify(G_OBJECT(src), "iradio-genre");
    851955        gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, priv->iradioGenre, NULL);
    852956    }
     
    855959        g_free(priv->iradioUrl);
    856960        priv->iradioUrl = g_strdup(value.utf8().data());
    857         g_object_notify(G_OBJECT(m_src), "iradio-url");
     961        g_object_notify(G_OBJECT(src), "iradio-url");
    858962        gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, priv->iradioUrl, NULL);
    859963    }
     
    862966        g_free(priv->iradioTitle);
    863967        priv->iradioTitle = g_strdup(value.utf8().data());
    864         g_object_notify(G_OBJECT(m_src), "iradio-title");
     968        g_object_notify(G_OBJECT(src), "iradio-title");
    865969        gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, priv->iradioTitle, NULL);
    866970    }
    867971
     972    locker.unlock();
     973
     974    // notify size/duration
     975    if (length > 0) {
     976        gst_app_src_set_size(priv->appsrc, length);
     977
     978#ifndef GST_API_VERSION_1
     979        if (!priv->haveAppSrc27) {
     980            gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);
     981            gst_element_post_message(GST_ELEMENT(priv->appsrc),
     982                gst_message_new_duration(GST_OBJECT(priv->appsrc),
     983                    GST_FORMAT_BYTES, length));
     984        }
     985#endif
     986    } else
     987        gst_app_src_set_size(priv->appsrc, -1);
     988
     989    // icecast stuff
     990    value = response.httpHeaderField("icy-metaint");
     991    if (!value.isEmpty()) {
     992        gchar* endptr = 0;
     993        gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10);
     994
     995        if (endptr && *endptr == '\0' && icyMetaInt > 0) {
     996            GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_simple("application/x-icy", "metadata-interval", G_TYPE_INT, (gint) icyMetaInt, NULL));
     997
     998            gst_app_src_set_caps(priv->appsrc, caps.get());
     999        }
     1000    } else
     1001        gst_app_src_set_caps(priv->appsrc, 0);
     1002
     1003    // notify tags
    8681004    if (gst_tag_list_is_empty(tags))
    8691005#ifdef GST_API_VERSION_1
     
    8731009#endif
    8741010    else
    875         notifyGstTagsOnPad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags);
    876 }
    877 
    878 void StreamingClient::dataReceived(CachedResource* resource, const char* data, int length)
    879 {
    880     WebKitWebSrcPrivate* priv = m_src->priv;
    881 
    882     GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length);
     1011        notifyGstTagsOnPad(GST_ELEMENT(src), priv->srcpad, tags);
     1012}
     1013
     1014void StreamingClient::handleDataReceived(const char* data, int length)
     1015{
     1016    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1017    WebKitWebSrcPrivate* priv = src->priv;
     1018
     1019    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     1020
     1021    GST_LOG_OBJECT(src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length);
    8831022
    8841023    ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
     
    8891028#endif
    8901029
    891     if (priv->seekID || resource != priv->resource) {
    892         GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data");
     1030    if (priv->seekID) {
     1031        GST_DEBUG_OBJECT(src, "Seek in progress, ignoring data");
    8931032        priv->buffer.clear();
    8941033        return;
     
    9081047    // priv->size == 0 if received length on didReceiveResponse < 0.
    9091048    if (priv->size > 0 && priv->offset > priv->size) {
    910         GST_DEBUG_OBJECT(m_src, "Updating internal size from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT, priv->size, priv->offset);
     1049        GST_DEBUG_OBJECT(src, "Updating internal size from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT, priv->size, priv->offset);
    9111050        gst_app_src_set_size(priv->appsrc, priv->offset);
    9121051        priv->size = priv->offset;
    9131052    }
    9141053    GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset;
     1054
     1055    locker.unlock();
    9151056
    9161057    GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef());
     
    9201061    if (ret != GST_FLOW_OK && ret != GST_FLOW_UNEXPECTED)
    9211062#endif
    922         GST_ELEMENT_ERROR(m_src, CORE, FAILED, (0), (0));
    923 }
    924 
    925 char* StreamingClient::getOrCreateReadBuffer(CachedResource*, size_t requestedSize, size_t& actualSize)
    926 {
    927     WebKitWebSrcPrivate* priv = m_src->priv;
    928 
    929     ASSERT(!priv->buffer);
    930 
    931     GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
    932 
    933 #ifdef GST_API_VERSION_1
    934     mapGstBuffer(buffer);
    935 #endif
    936 
    937     priv->buffer = adoptGRef(buffer);
    938 
    939     actualSize = getGstBufferSize(buffer);
    940     return getGstBufferDataPointer(buffer);
    941 }
    942 
    943 void StreamingClient::notifyFinished(CachedResource* resource)
    944 {
    945     WebKitWebSrcPrivate* priv = m_src->priv;
    946 
     1063        GST_ELEMENT_ERROR(src, CORE, FAILED, (0), (0));
     1064}
     1065
     1066void StreamingClient::handleNotifyFinished()
     1067{
     1068    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1069    WebKitWebSrcPrivate* priv = src->priv;
     1070
     1071    GST_DEBUG_OBJECT(src, "Have EOS");
     1072
     1073    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     1074    if (!priv->seekID) {
     1075        locker.unlock();
     1076        gst_app_src_end_of_stream(priv->appsrc);
     1077    }
     1078}
     1079
     1080CachedResourceStreamingClient::CachedResourceStreamingClient(WebKitWebSrc* src, CachedResourceLoader* resourceLoader, const ResourceRequest& request)
     1081    : StreamingClient(src)
     1082{
     1083    CachedResourceRequest cacheRequest(request, ResourceLoaderOptions(SendCallbacks, DoNotSniffContent, DoNotBufferData, DoNotAllowStoredCredentials, DoNotAskClientForCrossOriginCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType));
     1084    m_resource = resourceLoader->requestRawResource(cacheRequest);
     1085    if (m_resource)
     1086        m_resource->addClient(this);
     1087}
     1088
     1089CachedResourceStreamingClient::~CachedResourceStreamingClient()
     1090{
     1091    if (m_resource) {
     1092        m_resource->removeClient(this);
     1093        m_resource = 0;
     1094    }
     1095}
     1096
     1097bool CachedResourceStreamingClient::loadFailed() const
     1098{
     1099    return !m_resource;
     1100}
     1101
     1102void CachedResourceStreamingClient::setDefersLoading(bool defers)
     1103{
     1104    if (m_resource)
     1105        m_resource->setDefersLoading(defers);
     1106}
     1107
     1108char* CachedResourceStreamingClient::getOrCreateReadBuffer(CachedResource*, size_t requestedSize, size_t& actualSize)
     1109{
     1110    return createReadBuffer(requestedSize, actualSize);
     1111}
     1112
     1113void CachedResourceStreamingClient::responseReceived(CachedResource*, const ResourceResponse& response)
     1114{
     1115    handleResponseReceived(response);
     1116}
     1117
     1118void CachedResourceStreamingClient::dataReceived(CachedResource*, const char* data, int length)
     1119{
     1120    handleDataReceived(data, length);
     1121}
     1122
     1123void CachedResourceStreamingClient::notifyFinished(CachedResource* resource)
     1124{
    9471125    if (resource->loadFailedOrCanceled()) {
     1126        WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1127
    9481128        if (!resource->wasCanceled()) {
    9491129            const ResourceError& error = resource->resourceError();
    950             GST_ERROR_OBJECT(m_src, "Have failure: %s", error.localizedDescription().utf8().data());
    951             GST_ELEMENT_ERROR(m_src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
     1130            GST_ERROR_OBJECT(src, "Have failure: %s", error.localizedDescription().utf8().data());
     1131            GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
    9521132        }
    953         gst_app_src_end_of_stream(m_src->priv->appsrc);
     1133        gst_app_src_end_of_stream(src->priv->appsrc);
    9541134        return;
    9551135    }
    9561136
    957     GST_DEBUG_OBJECT(m_src, "Have EOS");
    958 
    959     if (!priv->seekID)
    960         gst_app_src_end_of_stream(m_src->priv->appsrc);
     1137    handleNotifyFinished();
     1138}
     1139
     1140ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, const ResourceRequest& request)
     1141    : StreamingClient(src)
     1142{
     1143    m_resource = ResourceHandle::create(0 /*context*/, request, this, false, false);
     1144}
     1145
     1146ResourceHandleStreamingClient::~ResourceHandleStreamingClient()
     1147{
     1148    if (m_resource) {
     1149        m_resource->cancel();
     1150        m_resource.release();
     1151        m_resource = 0;
     1152    }
     1153}
     1154
     1155bool ResourceHandleStreamingClient::loadFailed() const
     1156{
     1157    return !m_resource;
     1158}
     1159
     1160void ResourceHandleStreamingClient::setDefersLoading(bool defers)
     1161{
     1162    if (m_resource)
     1163        m_resource->setDefersLoading(defers);
     1164}
     1165
     1166char* ResourceHandleStreamingClient::getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize)
     1167{
     1168    return createReadBuffer(requestedSize, actualSize);
     1169}
     1170
     1171void ResourceHandleStreamingClient::willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&)
     1172{
     1173}
     1174
     1175void ResourceHandleStreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
     1176{
     1177    handleResponseReceived(response);
     1178}
     1179
     1180void ResourceHandleStreamingClient::didReceiveData(ResourceHandle*, const char* data, int length, int)
     1181{
     1182    handleDataReceived(data, length);
     1183}
     1184
     1185void ResourceHandleStreamingClient::didFinishLoading(ResourceHandle*, double)
     1186{
     1187    handleNotifyFinished();
     1188}
     1189
     1190void ResourceHandleStreamingClient::didFail(ResourceHandle*, const ResourceError& error)
     1191{
     1192    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1193
     1194    GST_ERROR_OBJECT(src, "Have failure: %s", error.localizedDescription().utf8().data());
     1195    GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
     1196    gst_app_src_end_of_stream(src->priv->appsrc);
     1197}
     1198
     1199void ResourceHandleStreamingClient::wasBlocked(ResourceHandle*)
     1200{
     1201    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1202    GOwnPtr<gchar> uri;
     1203
     1204    GST_ERROR_OBJECT(src, "Request was blocked");
     1205
     1206    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     1207    uri.set(g_strdup(src->priv->uri));
     1208    locker.unlock();
     1209
     1210    GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", uri.get()), (0));
     1211}
     1212
     1213void ResourceHandleStreamingClient::cannotShowURL(ResourceHandle*)
     1214{
     1215    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
     1216    GOwnPtr<gchar> uri;
     1217
     1218    GST_ERROR_OBJECT(src, "Cannot show URL");
     1219
     1220    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
     1221    uri.set(g_strdup(src->priv->uri));
     1222    locker.unlock();
     1223
     1224    GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", uri.get()), (0));
    9611225}
    9621226
Note: See TracChangeset for help on using the changeset viewer.