Added qmafw-gst-subtitles-renderer-0.0.55 for Meego Harmattan 1.2
[mafwsubrenderer] / qmafw-gst-subtitles-renderer / src / MafwGstRenderer.cpp
diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRenderer.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRenderer.cpp
new file mode 100644 (file)
index 0000000..a595711
--- /dev/null
@@ -0,0 +1,2437 @@
+/*
+ * This file is part of QMAFW
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights
+ * reserved.
+ *
+ * Contact: Visa Smolander <visa.smolander@nokia.com>
+ *
+ * This software, including documentation, is protected by copyright controlled
+ * by Nokia Corporation. All rights are reserved. Copying, including
+ * reproducing, storing, adapting or translating, any or all of this material
+ * requires the prior written consent of Nokia Corporation. This material also
+ * contains confidential information which may not be disclosed to others
+ * without the prior written consent of Nokia.
+ *
+ */
+
+#include <QDebug>
+#include <QMetaMethod>
+#include <QTimer>
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <X11/Xdefs.h>
+
+#include <MafwCallbackHelper.h>
+#include <MafwMetadata.h>
+#include <MafwMediaInfo.h>
+
+#include "MafwGstRenderer.h"
+#include "MafwBlankingPreventer.h"
+#include "mafw-gst-renderer-worker.h"
+#include "MafwGstRendererVolume.h"
+#include "MafwGstRendererDolby.h"
+#include "MafwGstRendererNetworkMonitor.h"
+#include "MafwGstRendererHaltState.h"
+#include "MafwGstRendererPlaylistFileUtility.h"
+#include "MafwGstScreenshot.h"
+#include "MafwMmcMonitor.h"
+
+#include <QSettings>
+#include <contextsubscriber/contextproperty.h>
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <QDateTime>
+#include <QSparqlConnection>
+#include <QSparqlResult>
+#include <QSparqlQuery>
+#include <QSparqlError>
+
+// milliseconds, stamp after playing this much
+const int PLAYED_STAMP_INTERVAL = 5000;
+
+const int MAX_SUPPORTED_HEIGHT = 720;
+const int MAX_SUPPORTED_WIDTH = 1280;
+// how many time we retried to make played stamps
+const int PLAYED_STAMP_TRIES = 3;
+
+static const int ISO_DATE_BASE_LENGTH = 19; // length of "CCYY-MM-DDThh:mm:ss"
+
+// property names
+const QString PROPERTY_DOLBY_STATE_MUSIC    = "mobile-surround-state-music";
+const QString PROPERTY_DOLBY_STATE_MUSIC_ROOM    = "mobile-surround-state-music-room";
+const QString PROPERTY_DOLBY_STATE_MUSIC_COLOR    = "mobile-surround-state-music-color";
+const QString PROPERTY_DOLBY_STATE_VIDEO    = "mobile-surround-state-video";
+const QString PROPERTY_DOLBY_STATE_VIDEO_ROOM    = "mobile-surround-state-video-room";
+const QString PROPERTY_DOLBY_STATE_VIDEO_COLOR    = "mobile-surround-state-video-color";
+const QString PROPERTY_VOLUME    = "volume";
+const QString PROPERTY_AUTOPAINT = "autopaint";
+const QString PROPERTY_COLORKEY  = "colorkey";
+const QString PROPERTY_XID       = "xid";
+const QString PROPERTY_RENDER_RECT = "render-rectangle";
+const QString PROPERTY_CURRENT_FRAME_ON_PAUSE = "current-frame-on-pause";
+const QString PROPERTY_PLAYBACK_SPEED   = "playback-speed";
+const QString PROPERTY_FORCE_ASPECT_RATIO  = "force-aspect-ratio";
+
+// audio/video destinations
+const QString CONTEXT_FW_PROPERTY_AUDIO_ROUTE = "/com/nokia/policy/audio_route";
+const QString CONTEXT_FW_PROPERTY_VIDEO_ROUTE = "/com/nokia/policy/video_route";
+const QString AUDIO_ROUTE_NULL                = "null";
+const QString AUDIO_ROUTE_IHF                 = "ihf";
+const QString AUDIO_ROUTE_FMRADIO             = "fmtx";
+const QString AUDIO_ROUTE_IHF_AND_FMRADIO     = "ihfandfmtx";
+const QString AUDIO_ROUTE_EARPIECE            = "earpiece";
+const QString AUDIO_ROUTE_EARPIECE_AND_TVOUT  = "earpieceandtvout";
+const QString AUDIO_ROUTE_TV_OUT              = "tvout";
+const QString AUDIO_ROUTE_IHF_AND_TV_OUT      = "ihfandtvout";
+const QString AUDIO_ROUTE_HEADPHONE           = "headphone";
+const QString AUDIO_ROUTE_HEADSET             = "headset";
+const QString AUDIO_ROUTE_BTHSP               = "bthsp";
+const QString AUDIO_ROUTE_BTA2DP              = "bta2dp";
+const QString AUDIO_ROUTE_IHF_AND_HEADSET     = "ihfandheadset";
+const QString AUDIO_ROUTE_IHF_AND_HEADPHONE   = "ihfandheadphone";
+const QString AUDIO_ROUTE_IHF_AND_BTHSP       = "ihfandbthsp";
+const QString AUDIO_ROUTE_TV_OUT_AND_BTHSP    = "tvoutandbthsp";
+const QString AUDIO_ROUTE_TV_OUT_AND_BTA2DP   = "tvoutandbta2dp";
+const QString VIDEO_ROUTE_TV_OUT              = "tvout";
+const QString VIDEO_ROUTE_BUILT_IN            = "builtin";
+const QString VIDEO_ROUTE_BUILT_IN_AND_TV_OUT = "builtinandtvout";
+
+const QString DBUS_INTERFACE_DBUS="org.freedesktop.DBus";
+const QString DBUS_SIGNAL_NAME_OWNER_CHANGED="NameOwnerChanged";
+const QString DBUS_NAME_PCFD = "com.nokia.policy.pcfd";
+
+/********************************************************************
+ * MafwGstRenderer::MafwGstRenderer
+ ********************************************************************/
+MafwGstRenderer::MafwGstRenderer(const QString& uuid,
+                                 const QString& pluginName,
+                                 const QString& name,
+                                 QObject *parent)
+    :
+    MafwBasicRenderer(uuid, pluginName, name, parent),
+    m_initialized(false),
+    m_currentState(MafwRenderer::Invalid),
+    m_nextContent(""),
+    m_currentContent(""),
+    m_playingItem(MafwBasicRenderer::UnknownUri),
+    m_blankingPreventer(0),
+    m_screenshot(0),
+    m_networkMonitor(new MafwGstRendererNetworkMonitor()),
+    m_volume(0),
+    m_playedStamped(false),
+    m_playedStampTryCounter(0),
+    m_sparqlConnection(new QSparqlConnection("QTRACKER", QSparqlConnectionOptions(), this)),
+    m_urnQueryResult(0),
+    m_stampItResult(0),
+    m_playlistFileUtil(0),
+    m_playingPlaylistFile(false),
+    m_unsupportedTypeError(0),
+    m_playedPlaylistItem(false),
+    m_mmcMonitor(0)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_dolby = new MafwGstRendererDolby(this);
+    connect(m_dolby, SIGNAL(mafwDHMMusicPropertyChanged()),
+            this, SLOT(handleDHMMusicPropertyChanged()));
+    connect(m_dolby, SIGNAL(mafwDHMVideoPropertyChanged()),
+            this, SLOT(handleDHMVideoPropertyChanged()));
+
+    m_worker = 0;
+    m_videoRoute = 0;
+    m_audioRoute = 0;
+    gst_init(0, 0);
+
+    /* make this connection a queued connection to postpone results delivery,
+     * so that results callback is not called already in the function that
+     * initiates this procedure */
+    QObject::connect(this, SIGNAL(signalGetPosition(QObject*,
+                                                    const char*)),
+                     this, SLOT(slotGetPosition(QObject*,
+                                                const char*)),
+                     Qt::QueuedConnection);
+
+    /* make this connection a queued connection to postpone results delivery,
+     * so that results callback is not called already in the function that
+     * initiates this procedure */
+    QObject::connect(this, SIGNAL(signalMafwProperty(QString,
+                                                     QObject*,
+                                                     const char*)),
+                     this, SLOT(slotMafwProperty(QString,
+                                                 QObject*,
+                                                 const char*)),
+                     Qt::QueuedConnection);
+
+    /* make this connection a queued connection to postpone results delivery,
+     * so that results callback is not called already in the function that
+     * initiates this procedure */
+    QObject::connect(this, SIGNAL(signalGetCurrentMediaInfo(QObject*,
+                                                            const char*,
+                                                            const QString)),
+                    this, SLOT(slotGetCurrentMediaInfo(QObject*,
+                                                        const char*,
+                                                        const QString)),
+                    Qt::QueuedConnection);
+
+    m_playedStampTimer.setSingleShot(true);
+    connect(&m_playedStampTimer,SIGNAL(timeout()),this,SLOT(slotStamp()));
+
+    m_videoRoute = new ContextProperty(CONTEXT_FW_PROPERTY_VIDEO_ROUTE);
+    m_audioRoute = new ContextProperty(CONTEXT_FW_PROPERTY_AUDIO_ROUTE);
+
+    connectNameOwnerChanged();
+
+    m_playlistNextTimer.setSingleShot(true);
+    connect(&m_playlistNextTimer, SIGNAL(timeout()),
+            this, SLOT(playNextURIFromPlaylist()));
+
+    /* connection is to track when policy is on/off */
+    connect(this, SIGNAL(mafwPropertyChanged(const QString, const QVariant)),
+            this, SLOT(handlePropertyChanged(const QString&, const QVariant&)));
+
+    /* Connection to handle online status message if necessary */
+    connect(m_networkMonitor, SIGNAL(prepareNetworkChange()),
+            this, SLOT(haltStreaming()));
+    connect(m_networkMonitor, SIGNAL(networkChangeFinished()),
+            this, SLOT(continueStreaming()));
+
+    connect(&m_haltState, SIGNAL(decayed()),
+            this, SLOT(stopStreaming()));
+}
+
+/********************************************************************
+ * MafwGstRenderer::~MafwGstRenderer
+ ********************************************************************/
+MafwGstRenderer::~MafwGstRenderer()
+{
+
+    qDebug() << __PRETTY_FUNCTION__;
+    delete m_volume;
+    // this releases the resources allocated by the worker, do this before
+    // releasing anything else so any callbacks from worker won't be called
+    mafw_gst_renderer_worker_exit(m_worker);
+
+    delete m_videoRoute;
+    delete m_audioRoute;
+    delete m_networkMonitor;
+    delete m_screenshot;
+    delete m_urnQueryResult;
+    delete m_stampItResult;
+    delete m_sparqlConnection;
+
+    g_free(m_worker);
+
+    if( m_unsupportedTypeError )
+    {
+        g_error_free(m_unsupportedTypeError);
+    }
+}
+
+
+/********************************************************************
+ * MafwGstRenderer::initialize
+ ********************************************************************/
+bool MafwGstRenderer::initialize(QSettings *settings)
+{
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    //if already initialized do nothing
+    if (m_initialized)
+    {
+        return m_initialized;
+    }
+
+    m_initialized = MafwBasicRenderer::initialize();
+
+    if (m_initialized)
+    {
+        // fail to apply default policy is not considered fatal for now
+        if (MafwBasicRenderer::setDefaultRendererPolicy(MafwRendererPolicy::MediaPlayer))
+        {
+            MafwRendererPolicy *policy = rendererPolicy();
+            Q_ASSERT(policy);
+            policy->setDefaultResources(MafwRendererPolicy::Audio);
+        }
+        else
+        {
+            qWarning() << "Setting default policy failed, continuing";
+        }
+
+        m_blankingPreventer = new MafwBlankingPreventer(this);
+
+        m_screenshot = new MafwGstScreenshot(this);
+
+        connect(m_screenshot, SIGNAL(screenshotTaken(char*,GError*)),
+                this, SLOT(handleScreenshot(char*,GError*)));
+        connect(m_screenshot, SIGNAL(screenshotCancelled()),
+                this, SLOT(cancelScreenshot()));
+
+        m_worker = mafw_gst_renderer_worker_new(this);
+        m_worker->notify_play_handler = &playCallback;
+        m_worker->notify_pause_handler = &pauseCallback;
+        m_worker->notify_error_handler = &errorCallback;
+        m_worker->notify_eos_handler = &eosCallback;
+        m_worker->notify_ready_state_handler = &readyStateCallback;
+        m_worker->notify_metadata_handler = &metadataCallback;
+        m_worker->notify_property_handler = &propertyCallback;
+        m_worker->notify_buffer_status_handler = &bufferStatusCallback;
+        m_worker->blanking__control_handler = &blankingControlCallback;
+        m_worker->screenshot_handler = &screenshotCallback;
+
+        setConfiguration(settings);
+
+        // Initialize Dolby support
+        m_dolby->initialize();
+
+        m_mmcMonitor = new MafwMmcMonitor(this);
+        connect( m_mmcMonitor, SIGNAL( preUnmount() ), this, SLOT( mmcPreUnmount() ) );
+
+        // connect the audio routes AND check the current values of routes.
+        connect( m_videoRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) );
+        connect( m_audioRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) );
+        slotRouteChanged();
+    }
+    return m_initialized;
+}
+
+/********************************************************************
+ * MafwGstRenderer::playCallback
+ ********************************************************************/
+void MafwGstRenderer::playCallback(MafwGstRendererWorker *worker,
+                                   gpointer owner)
+{
+    Q_UNUSED(worker);
+
+    qDebug() << __PRETTY_FUNCTION__;
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    if( self->m_currentState == MafwRenderer::Paused )
+    {
+        Q_EMIT self->rendererResumed();
+    }
+    else
+    {
+        if( self->m_playingPlaylistFile )
+        {
+            if( !self->m_playedPlaylistItem )
+            {
+                qDebug() << "Emitting playing item event";
+                Q_EMIT self->rendererPlaying(static_cast<int>(self->m_playingItem));
+                self->m_playedPlaylistItem = true;
+            }
+        }
+        else
+        {
+            Q_EMIT self->rendererPlaying(static_cast<int>(self->m_playingItem));
+        }
+    }
+
+    if( mafw_gst_renderer_worker_get_position(worker)==0 )
+    {
+        self->m_playedStamped = false;
+        self->m_playedStampTryCounter = 0;
+    }
+
+    if( !self->m_playedStamped )
+    {
+        const QUrl url = self->m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+        if (url.scheme() == "file")
+        {
+            qDebug() << __PRETTY_FUNCTION__ << "starting play stamp timer.";
+            self->m_playedStampTimer.start(PLAYED_STAMP_INTERVAL);
+        }
+    }
+
+    self->m_currentState = MafwRenderer::Playing;
+}
+
+/********************************************************************
+ * MafwGstRenderer::bufferStatusCallback
+ ********************************************************************/
+void MafwGstRenderer::bufferStatusCallback(MafwGstRendererWorker *worker,
+                                           gpointer owner,
+                                           gdouble percent)
+{
+
+    Q_UNUSED(worker);
+
+    qDebug() << __PRETTY_FUNCTION__;
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    Q_EMIT self->bufferingInfo(static_cast<float>(percent));
+
+}
+/********************************************************************
+ * MafwGstRenderer::constructMafwError
+ ********************************************************************/
+MafwError MafwGstRenderer::constructMafwError(const GError* error)
+{
+    MafwError mafwError;
+    guint32 code = static_cast<guint32>(error->code);
+
+    //for streams the media not found is other than the default
+    if( code == WORKER_ERROR_MEDIA_NOT_FOUND && mafw_gst_renderer_worker_get_streaming(m_worker) )
+    {
+        mafwError.setCode(MafwError::RendererError_URINotAvailable);
+    }
+    else if(code == WORKER_ERROR_UNSUPPORTED_TYPE)
+    {
+        handleResolutionError(mafwError);
+    }
+    else if (errorMap().contains(code))
+    {
+        mafwError.setCode(errorMap().value(code));
+    }
+    else
+    {
+        mafwError.setCode(MafwError::NothingButErrors);
+    }
+
+    mafwError.setMessage(error->message);
+    return mafwError;
+}
+
+/********************************************************************
+ * MafwGstRenderer::errorCallback
+ ********************************************************************/
+void MafwGstRenderer::errorCallback(MafwGstRendererWorker *worker,
+                                    gpointer owner,
+                                    const GError *error)
+{
+    Q_UNUSED(worker);
+    qWarning() << __PRETTY_FUNCTION__ << error->message;
+    MafwError mafwError;
+    guint32 code;
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    code = static_cast<guint32>(error->code);
+
+    //The content might be a playlist file which was tried to play without
+    //mime type. This case can be detected by trying to play it as playlist
+    //file. If that was not the case same error will be signalled via
+    //MafwGstRenderer::handlePlaylistFileParsingErrors
+    if (!self->m_playingPlaylistFile &&
+        !self->m_unsupportedTypeError &&
+        code == WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE)
+    {
+        QMap<QString, QVariant> mime;
+        mime[MAFW_METADATA_KEY_MIME] = "audio/x-scpls";
+        self->m_currentContent.setMetaData(mime);
+        self->doPlay(self->m_currentContent);
+        self->m_unsupportedTypeError = g_error_copy(error);
+        qWarning() << __PRETTY_FUNCTION__ << "Probably we were trying to play playlist file without mime type. If that's the case use bool play(url, 'audio/x-scpls').";
+        qWarning() << __PRETTY_FUNCTION__ << "Trying to play as playlist file now...";
+        return;
+    }
+    mafwError = self->constructMafwError(error);
+
+    /* We release resources when we got error that causes stop.
+     * WORKER_ERROR_CANNOT_SET_POSITION and WORKER_ERROR_DRM_NOT_ALLOWED error don't cause stop.
+     */
+    if((code != WORKER_ERROR_CANNOT_SET_POSITION
+        && code != WORKER_ERROR_DRM_NOT_ALLOWED)
+        && !self->m_playingPlaylistFile)
+    {
+        Q_EMIT self->rendererError(mafwError);
+        MafwRendererPolicy *policy = self->rendererPolicy();
+        Q_ASSERT(policy);
+        if( policy )
+        {
+            policy->release();
+            qDebug() << __PRETTY_FUNCTION__ << "Resources released because of error" << mafwError.code();
+        }
+        else
+        {
+            qWarning() << __PRETTY_FUNCTION__ << "No policy exists!";
+        }
+
+        self->doStop();
+    }
+    else if (code != WORKER_ERROR_CANNOT_SET_POSITION && code != WORKER_ERROR_DRM_NOT_ALLOWED) //Try next uri
+    {
+        //using singleshot gives worker/gstreamer time to do
+        //cleanup before calling worker_play
+        if (self->m_playlistFileUtil->getUriList().isEmpty())
+        {
+          //delayed call to playNextURIFromPlaylist used to give the parser
+          //enough time to read new items from the playlist
+          self->m_playlistFileUtil->setPendingError(mafwError);
+
+          self->m_playlistNextTimer.start(1000);
+        }
+        else
+        {
+            self->m_playlistNextTimer.start(0);
+        }
+    }
+    else
+    {
+        Q_EMIT self->rendererError(mafwError);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::propertyCallback
+ ********************************************************************/
+void MafwGstRenderer::propertyCallback(MafwGstRendererWorker *worker,
+                                       gpointer owner,
+                                       gint id,
+                                       GValue *value)
+{
+
+    QString name;
+
+    Q_UNUSED(worker);
+
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    switch (id)
+    {
+        case WORKER_PROPERTY_AUTOPAINT:
+            name = PROPERTY_AUTOPAINT;
+            break;
+        case WORKER_PROPERTY_COLORKEY:
+            name = PROPERTY_COLORKEY;
+            break;
+        case WORKER_PROPERTY_XID:
+            name = PROPERTY_XID;
+            break;
+        case WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE:
+            name = PROPERTY_CURRENT_FRAME_ON_PAUSE;
+            break;
+        case WORKER_PROPERTY_PLAYBACK_SPEED:
+            name = PROPERTY_PLAYBACK_SPEED;
+            break;
+        case WORKER_PROPERTY_FORCE_ASPECT_RATIO:
+            name = PROPERTY_FORCE_ASPECT_RATIO;
+            break;
+        case WORKER_PROPERTY_RENDER_RECTANGLE:
+            name = PROPERTY_RENDER_RECT;
+            break;
+        default:
+            qWarning() << __PRETTY_FUNCTION__ << "unknown property id:" << id;
+            return;
+            break;
+    }
+
+    qDebug() << __PRETTY_FUNCTION__ << name;
+
+    QVariant result = getValue(value);
+
+    if (result.isValid())
+    {
+        Q_EMIT self->mafwPropertyChanged(name, result);
+    }
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::blankingControlCallback
+ ********************************************************************/
+void MafwGstRenderer::blankingControlCallback(MafwGstRendererWorker *worker,
+                                   gpointer owner, gboolean prohibit)
+{
+
+    Q_UNUSED(worker);
+    qDebug() << __PRETTY_FUNCTION__ << prohibit;
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+    if(self->m_videoRoute->value() == VIDEO_ROUTE_TV_OUT ||
+       self->m_videoRoute->value() == VIDEO_ROUTE_BUILT_IN_AND_TV_OUT)
+    {
+        prohibit = false;
+    }
+
+    if( prohibit )
+    {
+        self->m_blankingPreventer->blankingProhibit();
+    }
+    else
+    {
+        self->m_blankingPreventer->blankingAllow();
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::screenshotCallback
+ ********************************************************************/
+void MafwGstRenderer::screenshotCallback(MafwGstRendererWorker *worker,
+                                         gpointer owner, GstBuffer *buffer,
+                                         const char *filename, gboolean cancel)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    MafwGstRenderer *self = static_cast<MafwGstRenderer*>(owner);
+
+    if(cancel)
+    {
+        self->m_screenshot->cancelPauseFrame();
+    }
+    else
+    {
+        if(!self->m_screenshot->savePauseFrame(buffer, filename))
+        {
+            worker->taking_screenshot = FALSE;
+            qCritical() << "Failed to create pause frame pipeline";
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::getValue
+ ********************************************************************/
+QVariant MafwGstRenderer::getValue(const GValue *v)
+{
+
+    QVariant result;
+
+    if (G_IS_VALUE(v))
+    {
+        if (G_VALUE_TYPE(v) == G_TYPE_STRING)
+        {
+            // tags from GStreamer are always expected to be UTF-8
+            result = QVariant(QString::fromUtf8(g_value_get_string(v)));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_UINT)
+        {
+            result = QVariant(g_value_get_uint(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_INT)
+        {
+            result = QVariant(g_value_get_int(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_BOOLEAN)
+        {
+            result = QVariant::fromValue<bool>(g_value_get_boolean(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_DOUBLE)
+        {
+            result = QVariant(g_value_get_double(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_INT64)
+        {
+            result = QVariant(g_value_get_int64(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_FLOAT)
+        {
+            result = QVariant(g_value_get_float(v));
+        }
+        else if (G_VALUE_TYPE(v) == G_TYPE_VALUE_ARRAY)
+        {
+            GValueArray *vals = static_cast<GValueArray*>(g_value_get_boxed(v));
+            if( vals->n_values == 4 )
+            {
+               result = QString("%1,%2,%3,%4")
+                       .arg(g_value_get_int(g_value_array_get_nth(vals, 0)))
+                       .arg(g_value_get_int(g_value_array_get_nth(vals, 1)))
+                       .arg(g_value_get_int(g_value_array_get_nth(vals, 2)))
+                       .arg(g_value_get_int(g_value_array_get_nth(vals, 3)));
+            }
+            else
+            {
+                qWarning() << "Invalid rect values received? Size:" << vals->n_values;
+            }
+
+        }
+        else
+        {
+            qWarning() << "unsupported value g_type";
+        }
+    }
+
+    return result;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::metadataCallback
+ ********************************************************************/
+void MafwGstRenderer::metadataCallback(MafwGstRendererWorker *worker,
+                                       gpointer owner,
+                                       gint key,
+                                       GType type,
+                                       gpointer value)
+{
+
+    QList<QVariant> results;
+
+    Q_UNUSED(worker);
+
+    qDebug() << __PRETTY_FUNCTION__ << key << metadataMap().value(key);
+
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    if (metadataMap().contains(key))
+    {
+        if (type == G_TYPE_VALUE_ARRAY)
+        {
+            uint i;
+            GValueArray *vals = static_cast<GValueArray*>(value);
+            for (i = 0; i < vals->n_values; i++)
+            {
+                QVariant v = getValue(g_value_array_get_nth(vals, i));
+                if (v.isValid())
+                {
+                    results << v;
+                }
+            }
+
+            QString mafwMetadataKey = metadataMap().value(key);
+
+            self->appendRelatedMetadata(mafwMetadataKey, &results);
+
+            Q_EMIT self->metadataChanged(mafwMetadataKey, results);
+            self->m_currentMetaData.insert(mafwMetadataKey, results);
+        }
+        else
+        {
+            qWarning() << "unsupported g_type";
+        }
+    }
+    else
+    {
+        qWarning() << "unknown metadata key:" << key;
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::appendRelatedMetadata
+ ********************************************************************/
+void MafwGstRenderer::appendRelatedMetadata(const QString key, QList<QVariant>* results)
+{
+    if(key == MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI)
+    {
+        gint position = mafw_gst_renderer_worker_get_position(m_worker);
+        if(position < 0)
+        {
+            position = 0;
+        }
+
+        QUrl uri = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+        *results << uri.toEncoded().constData();
+        *results << QVariant(position);
+    }
+}
+
+//
+// QMafw renderer interface implementation
+//
+
+/********************************************************************
+ * MafwGstRenderer::doPlay
+ ********************************************************************/
+void MafwGstRenderer::doPlay(const MafwContent& content)
+{
+    Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!");
+    Q_UNUSED(content);
+}
+
+/********************************************************************
+ * MafwGstRenderer::doPlay
+ ********************************************************************/
+void MafwGstRenderer::doPlay(const MafwMediaInfo& mediaInfo)
+{
+    //Preserve m_currentContent for keeping usage count up if the same item is
+    //played again.
+    if(mediaInfo.uuid().isEmpty() ||
+        mediaInfo.uuid() != m_currentContent.uuid())
+    {
+        m_currentContent = mediaInfo;
+    }
+    m_playingItem = MafwBasicRenderer::CurrentUri;
+    m_currentMetaData.clear();
+
+    const QUrl url = mediaInfo.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+    qDebug() << __PRETTY_FUNCTION__ << url.toEncoded();
+
+    m_haltState.clear();
+
+    if( !m_mmcMonitor->isMounted() && url.toString().startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
+    {
+        qDebug() << "MafwGstRenderer::doPlay: Can't play MMC not mounted";
+        MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded());
+        Q_EMIT rendererError(mafwError);
+        return;
+    }
+
+    m_playedPlaylistItem = false;
+    m_playingPlaylistFile = false;
+    if (m_unsupportedTypeError)
+    {
+        g_error_free(m_unsupportedTypeError);
+        m_unsupportedTypeError = 0;
+    }
+
+    if( url.isValid() )
+    {
+        stopTimers();
+
+        // Set correct value for the Dolby Headphones Mobile effect plugin
+        set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
+        set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
+        set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
+        set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
+        set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
+        set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
+
+        const QString& mimeType = mediaInfo.firstMetaData(MAFW_METADATA_KEY_MIME).toString();
+        if (mimeType == "audio/x-scpls" )
+        {
+            if (!m_playlistFileUtil)
+            {
+                m_playlistFileUtil = new MafwGstRendererPlaylistFileUtility(this);
+                connect(m_playlistFileUtil, SIGNAL(firstItemParsed()),
+                        this, SLOT(startPlayingPlaylistFile()), Qt::QueuedConnection);
+                connect(m_playlistFileUtil, SIGNAL(parsingReady(bool)),
+                        this, SLOT(handlePlaylistFileParsingErrors(bool)), Qt::QueuedConnection);
+            }
+            m_playlistFileUtil->parsePlaylistFile(url);
+
+        }
+        else
+        {
+            playURI(url.toEncoded());
+
+            QVariant startPosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_START_POSITION);
+            if( startPosition.isValid() )
+            {
+                uint pos = startPosition.toUInt();
+                qDebug() << "Immediate seek requested to: " << pos;
+                doSeek(pos, MafwRenderer::SeekAbsolute);
+            }
+            else
+            {
+                QVariant pausePosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_PAUSED_POSITION);
+                if( pausePosition.isValid() )
+                {
+                    uint position = pausePosition.toUInt();
+                    qDebug() << "Immediate pause requested at:" << position;
+                    mafw_gst_renderer_worker_pause_at(m_worker, position);
+                }
+            }
+        }
+    }
+    else
+    {
+        MafwError mafwError(MafwError::RendererError_InvalidURI, url.toString());
+        Q_EMIT rendererError(mafwError);
+        doStop();
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::doStop
+ ********************************************************************/
+void MafwGstRenderer::doStop()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    mafw_gst_renderer_worker_stop(m_worker);
+    m_currentState = MafwRenderer::Stopped;
+    m_playingItem = MafwBasicRenderer::UnknownUri;
+
+    m_haltState.clear();
+
+    stopTimers();
+    Q_EMIT rendererStopped();
+}
+
+/********************************************************************
+ * MafwGstRenderer::doPause
+ ********************************************************************/
+void MafwGstRenderer::doPause()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if( m_haltState.isSet() && m_haltState.state() == MafwRenderer::Playing )
+    {
+        m_haltState.setState(MafwRenderer::Paused);
+        m_currentState = MafwRenderer::Paused;
+        Q_EMIT rendererPaused();
+    }
+    else
+    {
+        mafw_gst_renderer_worker_pause(m_worker);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::doResume
+ ********************************************************************/
+void MafwGstRenderer::doResume()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if( m_currentState == MafwRenderer::Paused && m_haltState.isSet() && m_haltState.state() == MafwRenderer::Paused )
+    {
+        mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData());
+        m_currentState = MafwRenderer::Paused;
+        if( m_haltState.position() > 0 )
+        {
+            doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute);
+        }
+    }
+    else
+    {
+        mafw_gst_renderer_worker_resume(m_worker);
+    }
+
+    if( m_haltState.isSet() )
+    {
+        m_haltState.clear();
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::doSeek
+ ********************************************************************/
+void MafwGstRenderer::doSeek(int position, MafwRenderer::SeekMode seekMode)
+{
+    GError *error = 0;
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    GstSeekType seekType;
+    if( MafwRenderer::SeekAbsolute == seekMode )
+    {
+        seekType = GST_SEEK_TYPE_SET;
+    }
+    else if( MafwRenderer::SeekRelative == seekMode )
+    {
+        seekType = GST_SEEK_TYPE_CUR;
+    }
+    else
+    {
+        qCritical("MafwGstRenderer: Invalid seek operation requested!");
+        return;
+    }
+
+    mafw_gst_renderer_worker_set_position(m_worker,
+                                          seekType,
+                                          position,
+                                          &error);
+
+    if (error)
+    {
+        MafwError mafwError;
+        mafwError.setCode(MafwError::RendererError_CannotSetPosition);
+        mafwError.setMessage(error->message);
+        Q_EMIT rendererError(mafwError);
+        g_error_free(error);
+    }
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::doNextHint
+ ********************************************************************/
+bool MafwGstRenderer::doNextHint(const MafwContent& content)
+{
+    Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!");
+    Q_UNUSED(content);
+    return false;
+}
+
+/********************************************************************
+ * MafwGstRenderer::doNextHint
+ ********************************************************************/
+bool MafwGstRenderer::doNextHint(const MafwMediaInfo& mediaInfo)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_nextContent = mediaInfo;
+    // If we have already reached EOS trigger a new play attempt because the
+    // next content was signalled too late. However, if we have gone from playing
+    // state we can not continue, because we have released resources.
+    if (m_worker->eos && (m_currentState == MafwRenderer::Playing))
+    {
+        QTimer::singleShot(0, this, SLOT(playNext()));
+    }
+    return true;
+}
+
+/********************************************************************
+ * MafwGstRenderer::getPosition
+ ********************************************************************/
+bool MafwGstRenderer::getPosition(QObject* resultsReceiver,
+                                  const char* resultsMember)
+{
+
+    Q_EMIT signalGetPosition(resultsReceiver,
+                           resultsMember);
+
+    return true;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::setMafwProperty
+ ********************************************************************/
+bool MafwGstRenderer::setMafwProperty(const QString& name,
+                                      const QVariant& value)
+{
+    qDebug() << __PRETTY_FUNCTION__ << name;
+
+    bool success = true;
+    if (name == PROPERTY_VOLUME)
+    {
+        if (!m_volume)
+        {
+            m_volume = new MafwGstRendererVolume();
+            connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint)));
+        }
+        success = m_volume->setVolume(value.toUInt());
+    }
+    else if (name == PROPERTY_DOLBY_STATE_MUSIC)
+    {
+        success = m_dolby->setMusicDolbyState(value.toUInt());
+        if (success)
+        {
+            set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
+        }
+    }
+    else if (name == PROPERTY_DOLBY_STATE_MUSIC_ROOM)
+    {
+        success = m_dolby->setMusicDolbyState(value.toInt());
+        if (success)
+        {
+            set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
+        }
+    }
+    else if (name == PROPERTY_DOLBY_STATE_MUSIC_COLOR)
+    {
+        success = m_dolby->setMusicDolbyState(value.toInt());
+        if (success)
+        {
+            set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
+        }
+    }
+    else if (name == PROPERTY_DOLBY_STATE_VIDEO)
+    {
+        success = m_dolby->setVideoDolbyState(value.toUInt());
+        if (success)
+        {
+            set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
+        }
+    }
+    else if (name == PROPERTY_DOLBY_STATE_VIDEO_ROOM)
+    {
+        success = m_dolby->setVideoDolbyState(value.toInt());
+        if (success)
+        {
+            set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
+        }
+    }
+    else if (name == PROPERTY_DOLBY_STATE_VIDEO_COLOR)
+    {
+        success = m_dolby->setVideoDolbyState(value.toInt());
+        if (success)
+        {
+            set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
+        }
+    }
+    else if (name == PROPERTY_AUTOPAINT)
+    {
+        mafw_gst_renderer_worker_set_autopaint(m_worker, value.toBool());
+    }
+    else if (name == PROPERTY_XID)
+    {
+        if (rendererPolicy())
+        {
+            rendererPolicy()->setDefaultResources(MafwRendererPolicy::Audio | MafwRendererPolicy::Video);
+        }
+        else
+        {
+            qCritical() << __PRETTY_FUNCTION__ << "unable to append video to default resources";
+        }
+
+        mafw_gst_renderer_worker_set_xid(m_worker, value.toUInt());
+    }
+    else if (name == PROPERTY_CURRENT_FRAME_ON_PAUSE)
+    {
+        mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker,
+                                                            value.toBool());
+    }
+    else if (name == PROPERTY_PLAYBACK_SPEED)
+    {
+        success = mafw_gst_renderer_worker_set_playback_speed(m_worker, value.toFloat());
+    }
+    else if (name == PROPERTY_FORCE_ASPECT_RATIO)
+    {
+        mafw_gst_renderer_worker_set_force_aspect_ratio(m_worker, value.toBool());
+    }
+    else if( name == PROPERTY_RENDER_RECT )
+    {
+        if( value.type() != QVariant::String )
+        {
+            qWarning() << "MafwGstRenderer Invalid ("<<PROPERTY_RENDER_RECT<<") value received:" << value;
+        }
+        else
+        {
+            QString str = value.toString();
+            QStringList list = str.split(",");
+            bool success = true;
+            int array[4]; // x, y, width, height
+            if( list.size() != 4 )
+            {
+                success=false;
+            }
+            else
+            {
+                for( int i = 0; i < 4 && success; ++i )
+                {
+                    QString str = list.at(i);
+                    array[i] = str.toInt(&success);
+                }
+            }
+            if( !success )
+            {
+                qWarning() << "Invalid property (" << name << ") value received: " << value;
+            }
+            else
+            {
+                render_rectangle rect = {array[0], array[1], array[2], array[3]};
+                mafw_gst_renderer_worker_set_render_rectangle(m_worker, &rect);
+            }
+        }
+    }
+    else
+    {
+        success = MafwBasicRenderer::setMafwProperty(name, value);
+    }
+
+    if (!success)
+    {
+        MafwError err;
+        err.setCode(MafwError::RendererError_CannotSetProperty);
+        Q_EMIT rendererError(err);
+    }
+
+    return success;
+}
+
+/********************************************************************
+ * MafwGstRenderer::mafwProperty
+ ********************************************************************/
+bool MafwGstRenderer::mafwProperty(QString& name,
+                                   QObject* receiver,
+                                   const char* member)
+{
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    Q_EMIT signalMafwProperty(name, receiver, member);
+
+    return true;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::mafwProperty
+ ********************************************************************/
+bool MafwGstRenderer::getCurrentMediaInfo(QObject* receiver,
+                                   const char* member,
+                                   const QString& metadataKey)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if(m_currentState == MafwRenderer::Playing || m_currentState == MafwRenderer::Paused)
+    {
+        Q_EMIT signalGetCurrentMediaInfo(receiver, member, metadataKey);
+    }
+    else
+    {
+        return false;
+    }
+
+    return true;
+}
+
+/********************************************************************
+ * MafwGstRenderer::pauseCallback
+ ********************************************************************/
+void MafwGstRenderer::pauseCallback(MafwGstRendererWorker *worker,
+                                    gpointer owner)
+{
+
+    Q_UNUSED(worker);
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    self->m_playedStampTimer.stop();
+
+    Q_EMIT self->rendererPaused();
+
+    //are we staying in paused after stopped state (pauseAt requested)
+    //we'll need to inform the MafwBasicRenderer to give the next item to play after current
+    //if so start fetching next also in this case
+    if( self->m_currentState == MafwRenderer::Stopped )
+    {
+        Q_EMIT self->rendererReadyForNext(self->m_playingItem);
+    }
+
+    self->m_currentState = MafwRenderer::Paused;
+}
+
+/********************************************************************
+ * MafwGstRenderer::eosCallback
+ * Renderer does not stop here, because there could be set next item to play.
+ ********************************************************************/
+void MafwGstRenderer::eosCallback(MafwGstRendererWorker *worker,
+                                  gpointer owner)
+{
+
+    Q_UNUSED(worker);
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
+
+    //this is very special case to restart playing streams of undetermined duration and nonseekable
+    if( mafw_gst_renderer_worker_get_streaming(worker)
+        && mafw_gst_renderer_worker_get_last_known_duration(worker) < 0
+        && !mafw_gst_renderer_worker_get_seekable(worker) )
+    {
+        QTimer::singleShot(0, self, SLOT(restartPlay()));
+        return;
+    }
+
+    if( self->m_playedStampTimer.isActive() ) // eos before stamped, stamp now
+    {
+        self->m_playedStampTimer.stop();
+        self->slotStamp();
+    }
+
+    if (self->m_playingPlaylistFile) //Try next uri if exists
+    {
+        self->m_playlistNextTimer.start(0);
+    }
+    else
+    {
+        QTimer::singleShot(0, self, SLOT(playNext()));
+        Q_EMIT self->rendererEos();
+    }
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::restartPlay
+ * Slot to call asynchronously to restart playback (e.g. when internet radio disconnect due to network issues)
+ ********************************************************************/
+void MafwGstRenderer::restartPlay()
+{
+    //only restart if we're still playing
+    if( m_currentState == MafwRenderer::Playing )
+    {
+        doPlay(m_currentContent);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::readyStateCallback
+ * Worker informs via this when it is no longer using any resources when paused
+ ********************************************************************/
+void MafwGstRenderer::readyStateCallback(MafwGstRendererWorker *worker, gpointer owner)
+{
+    Q_UNUSED(worker);
+
+    MafwGstRenderer *self = static_cast<MafwGstRenderer*>(owner);
+
+    if( self->m_currentState != MafwRenderer::Paused )
+    {
+        qCritical("MafwGstRenderer: Ready state informed, but not in PAUSED state! Not releasing resources!");
+        return;
+    }
+
+    MafwRendererPolicy *policy = self->rendererPolicy();
+    if( policy )
+    {
+        policy->release();
+    }
+}
+
+//
+//Private implementation
+//
+
+/********************************************************************
+ * MafwGstRenderer::slotGetPosition
+ ********************************************************************/
+void MafwGstRenderer::slotGetPosition(QObject* resultsReceiver,
+                                      const char* resultsMember)
+{
+    QMetaMethod method;
+    bool methodFound;
+    gint pos;
+
+    if(m_currentState == MafwRenderer::Stopped)
+    {
+        pos = 0;
+    }
+    else if( m_haltState.isSet() )
+    {
+        pos = m_haltState.position();
+    }
+    else
+    {
+        /* this returns -1 on failure */
+        pos = mafw_gst_renderer_worker_get_position(m_worker);
+    }
+
+    if (pos < 0)
+    {
+        MafwError err;
+        err.setCode(MafwError::RendererError_CannotGetPosition);
+        Q_EMIT rendererError(err);
+    }
+    else
+    {
+        methodFound = MafwCallbackHelper::getCallbackMethod(resultsReceiver,
+                                                            resultsMember,
+                                                            method);
+
+        if (!methodFound ||
+            method.invoke(resultsReceiver, Q_ARG(uint, pos)) == false)
+        {
+            qCritical() << "Invoking the get position callback method failed!";
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotMafwProperty
+ ********************************************************************/
+void MafwGstRenderer::slotMafwProperty(const QString& name,
+                                       QObject* receiver,
+                                       const char* member)
+{
+
+    QVariant prop;
+    QMetaMethod method;
+    bool methodFound;
+
+    if (name == PROPERTY_VOLUME)
+    {
+        if (!m_volume)
+        {
+            m_volume = new MafwGstRendererVolume();
+            connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint)));
+        }
+
+        uint value = m_volume->getVolume();
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_DOLBY_STATE_MUSIC)
+    {
+        uint value = m_dolby->getMusicDolbyState();
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_DOLBY_STATE_VIDEO)
+    {
+        uint value = m_dolby->getVideoDolbyState();
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_AUTOPAINT)
+    {
+        gboolean value;
+        value = mafw_gst_renderer_worker_get_autopaint(m_worker);
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_COLORKEY)
+    {
+        gint value;
+        value = mafw_gst_renderer_worker_get_colorkey(m_worker);
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_XID)
+    {
+        XID value;
+        value = mafw_gst_renderer_worker_get_xid(m_worker);
+        prop = QVariant(static_cast<uint>(value));
+    }
+    else if (name == PROPERTY_PLAYBACK_SPEED)
+    {
+        gfloat value;
+        value = mafw_gst_renderer_worker_get_playback_speed(m_worker);
+        prop = QVariant(value);
+    }
+    else if (name == PROPERTY_FORCE_ASPECT_RATIO)
+    {
+        gboolean value;
+        value = mafw_gst_renderer_worker_get_force_aspect_ratio(m_worker);
+        prop = QVariant(value);
+    }
+    else if( name == PROPERTY_RENDER_RECT)
+    {
+        const render_rectangle *rect = mafw_gst_renderer_worker_get_render_rectangle(m_worker);
+        prop = QString("%1,%2,%3,%4")
+               .arg(rect->x).arg(rect->y).arg(rect->width).arg(rect->height);
+    }
+    else
+    {
+        qWarning() << "unknown property: " << name;
+    }
+
+    methodFound = MafwCallbackHelper::getCallbackMethod(receiver,
+                                                        member,
+                                                        method);
+
+    if (!methodFound || method.invoke(receiver,
+                                      Q_ARG(QString, name),
+                                      Q_ARG(QVariant, prop)) == false)
+    {
+        qCritical() << "Invoking the callback method failed!";
+    }
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotStamp
+ ********************************************************************/
+void MafwGstRenderer::slotStamp()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    QString uid=m_currentContent.uuid();
+    if( !uid.isEmpty() )
+    {
+        // create live node from MAFW object ID. Tracker case only implemented
+        // here. There definitely should be helper function for this.
+        const QString TRACKER_SOURCE_UUID = "MafwTrackerSource";
+        const QString MAFW_UUID_SEPARATOR = "::";
+
+        QString source = uid.section(MAFW_UUID_SEPARATOR, 0 , 0);
+
+        if ( source == TRACKER_SOURCE_UUID )
+        {
+            QString uniqueNodeIdentifier = uid.section(MAFW_UUID_SEPARATOR, 1, 1);
+            if (uniqueNodeIdentifier.length() > 0)
+            {
+                int counter = m_currentContent.firstMetaData(MAFW_METADATA_KEY_PLAY_COUNT).toInt();
+                counter++;
+                qDebug() << "MafwGstRenderer::slotStamp counter" << counter;
+                m_currentContent.appendMetaData(MAFW_METADATA_KEY_PLAY_COUNT, QList<QVariant>() << QVariant(counter));
+
+                int storedDuration = m_currentContent.firstMetaData(MAFW_METADATA_KEY_DURATION).toInt();
+                int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker);
+                int stampDuration = -1;
+                if( currentDuration >= 0 && storedDuration != currentDuration )
+                {
+                    qDebug() << "Will store new duration:" << currentDuration;
+                    stampDuration = currentDuration;
+                    Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList<QVariant>() << stampDuration));
+                }
+
+                stampIt(uniqueNodeIdentifier, counter, stampDuration);
+            }
+        }
+    }
+    else // UUID is unknown
+    {
+        const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+
+        if( url.isValid() && url.toString().startsWith("file://") )
+        {
+            qDebug() << "MafwGstRenderer::slotStamp query from tracker" << url;
+
+            QSparqlQuery query(QString("SELECT ?urn ?usageCount ?duration WHERE { "
+                                       "?urn nie:url \"%1\". "
+                                       "OPTIONAL { "
+                                            "?urn nie:usageCounter ?usageCount. "
+                                            "?urn nfo:duration ?duration } "
+                                       "}")
+                               .arg(url.toEncoded().constData()));
+
+            delete m_urnQueryResult;
+            m_urnQueryResult = m_sparqlConnection->exec(query);
+            connect(m_urnQueryResult, SIGNAL(finished()),
+                    this, SLOT(slotStampQueryReady()));
+        }
+    }
+
+    m_playedStamped=true;
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotStampQueryReady
+ ********************************************************************/
+void MafwGstRenderer::slotStampQueryReady()
+{
+    m_playedStampTryCounter++;
+    if( !m_urnQueryResult || m_urnQueryResult->hasError() || !m_urnQueryResult->first() )
+    {
+        qWarning() << "MafwGstRenderer::slotStampQueryReady: surprising result";
+        if (!m_playedStampTimer.isActive()
+            && m_currentState == MafwRenderer::Playing
+            && m_playedStampTryCounter < PLAYED_STAMP_TRIES)
+        {
+            qDebug() << __PRETTY_FUNCTION__ << "restarting timer.";
+            m_playedStampTimer.start(PLAYED_STAMP_INTERVAL);
+        }
+        else
+        {
+            qWarning() << __PRETTY_FUNCTION__ << "played stamping didn't succeeded.";
+            m_playedStamped = false;
+        }
+    }
+    else
+    {
+        QString urn = m_urnQueryResult->stringValue(0);
+        int usageCount = m_urnQueryResult->stringValue(1).toInt();
+        int storedDuration = m_urnQueryResult->stringValue(2).toInt();
+
+        int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker);
+
+        int mediaDuration = -1;
+        if( storedDuration != currentDuration)
+        {
+            mediaDuration = currentDuration;
+            Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList<QVariant>() << mediaDuration));
+        }
+
+        qDebug() << "MafwGstRenderer::slotStampQueryReady" << urn << usageCount << mediaDuration;
+
+        stampIt(urn, usageCount+1, mediaDuration);
+    }
+
+
+    delete m_urnQueryResult;
+    m_urnQueryResult = 0;
+}
+
+/********************************************************************
+ * MafwGstRenderer::stopTimers
+ ********************************************************************/
+void MafwGstRenderer::stopTimers()
+{
+    m_playlistNextTimer.stop();
+    if (m_playlistFileUtil)
+    {
+        m_playlistFileUtil->takePendingError();
+    }
+    m_playedStampTimer.stop();
+}
+
+/********************************************************************
+ * MafwGstRenderer::stampIt
+ ********************************************************************/
+void MafwGstRenderer::stampIt(const QString& urn, int usageCount, int mediaDuration)
+{
+    QString isoDate=QDateTime::currentDateTime().toUTC().toString(Qt::ISODate);
+    // Add UTC mark "Z" if it is missing (Qt behaviour has changed it seems to add it nowadays)
+    if( isoDate.length()==ISO_DATE_BASE_LENGTH )
+    {
+        isoDate.append("Z");
+    }
+
+    QSparqlQuery update;
+    if( mediaDuration > -1 )
+    {
+        update.setQuery(QString(
+                                " DELETE { <%1> nie:contentAccessed ?old } "
+                                " WHERE { <%1> nie:contentAccessed ?old } "
+                                " DELETE { <%1> nie:usageCounter ?oldu } "
+                                " WHERE { <%1> nie:usageCounter ?oldu } "
+                                " DELETE { <%1> nfo:duration ?oldd } "
+                                " WHERE { <%1> nfo:duration ?oldd } "
+                                " INSERT { <%1> nie:contentAccessed \"%2\" . "
+                                "         <%1> nie:usageCounter \"%3\" . "
+                                "         <%1> nfo:duration \"%4\" }")
+                                .arg(urn)
+                                .arg(isoDate)
+                                .arg(usageCount)
+                                .arg(mediaDuration));
+    }
+    else
+    {
+        update.setQuery(QString(
+                                "DELETE { <%1> nie:contentAccessed ?old } "
+                                " WHERE { <%1> nie:contentAccessed ?old } "
+                                "DELETE { <%1> nie:usageCounter ?oldu } "
+                                " WHERE { <%1> nie:usageCounter ?oldu } "
+                                "INSERT { <%1> nie:contentAccessed \"%2\" . "
+                                "         <%1> nie:usageCounter \"%3\"}")
+                                .arg(urn)
+                                .arg(isoDate)
+                                .arg(usageCount));
+    }
+
+    update.setType(QSparqlQuery::InsertStatement);
+
+
+    delete m_stampItResult;
+    m_stampItResult = m_sparqlConnection->exec(update);
+    connect(m_stampItResult, SIGNAL(finished()),
+            this, SLOT(slotStampItDone()));
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotStampItDone()
+ ********************************************************************/
+void MafwGstRenderer::slotStampItDone()
+{
+    if( !m_stampItResult )
+    {
+        qWarning() << "Stampit cannot be done without stmapit result! Invalid slot call?";
+        return;
+    }
+
+    if( m_stampItResult->hasError() )
+    {
+        qWarning() << "Stampit failed:" << m_stampItResult->lastError().message();
+    }
+    delete m_stampItResult;
+    m_stampItResult = 0;
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotRouteChanged()
+ ********************************************************************/
+void MafwGstRenderer::slotRouteChanged()
+{
+    QSet<int> set;
+    QString route;
+
+    // 1. add audio route(s) to the route set
+    route = m_audioRoute->value().toString();
+    qDebug() << "audio route is:" << route;
+    if (audioRouteMap().contains(route))
+    {
+        Q_FOREACH (int value, audioRouteMap().value(route))
+        {
+            set.insert(value);
+        }
+    }
+    else
+    {
+        // TODO: Is it ok to use NULL here?
+        qWarning() << "adding null route (audio)";
+        set.insert(WORKER_OUTPUT_NULL);
+    }
+
+    // 2. add video route(s) to the route set
+    route = m_videoRoute->value().toString();
+    qDebug() << "video route is:" << route;
+    if (videoRouteMap().contains(route))
+    {
+        Q_FOREACH (int value, videoRouteMap().value(route))
+        {
+            set.insert(value);
+        }
+    }
+    else
+    {
+        // TODO: Is it ok to use NULL here?
+        qWarning() << "adding null route (video)";
+        set.insert(WORKER_OUTPUT_NULL);
+    }
+
+    // 3. finally notify the worker about the current routes
+    GSList *destinations = NULL;
+    Q_FOREACH (int value, set)
+    {
+        destinations = g_slist_append(destinations, GINT_TO_POINTER(value));
+    }
+    mafw_gst_renderer_worker_notify_media_destination(this->m_worker,
+                                                      destinations);
+    g_slist_free(destinations);
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::playURI
+ ********************************************************************/
+void MafwGstRenderer::playURI(const QString& uri)
+{
+    m_playedStamped = false;
+    m_playedStampTryCounter = 0;
+
+    //little hack to get pause-to-play transition to be signalled
+    //correctly, in case different URI is asked to be played.
+    //So it's not resume transition
+    m_currentState = MafwRenderer::Stopped;
+    mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
+    m_nextContent = MafwMediaInfo();
+}
+
+/********************************************************************
+ * MafwGstRenderer::startPlayingPlaylistFile
+ ********************************************************************/
+void MafwGstRenderer::startPlayingPlaylistFile()
+{
+    m_playlistNextTimer.stop();
+    QString uri = QString();
+    if (m_playlistFileUtil)
+    {
+        uri = m_playlistFileUtil->takeFirstUri();
+        m_playlistFileUtil->takePendingError();
+    }
+    else
+    {
+        qCritical() << __PRETTY_FUNCTION__ << "playlist file util is NULL!";
+    }
+
+    if (!uri.isEmpty())
+    {
+        qDebug() << __PRETTY_FUNCTION__ << uri;
+
+        if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
+        {
+            qDebug() << "MafwGstRenderer::startPlayingPlaylistFile: Can't play MMC not mounted";
+            MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri);
+            Q_EMIT rendererError(mafwError);
+            return;
+        }
+
+        m_playingPlaylistFile = true;
+        mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
+        QList<QVariant> metadataValue;
+        metadataValue << uri;
+        Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue);
+    }
+    else
+    {
+        MafwError err;
+        err.setCode(MafwError::RendererError_PlaylistParsing);
+        Q_EMIT rendererError(err);
+    }
+}
+
+
+/********************************************************************
+ * MafwGstRenderer::handlePlaylistFileParsingErrors
+ ********************************************************************/
+void MafwGstRenderer::handlePlaylistFileParsingErrors(bool succeeded)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if (!succeeded)
+    {
+        if (m_unsupportedTypeError)
+        {
+            errorCallback(m_worker, this, m_unsupportedTypeError);
+            g_error_free(m_unsupportedTypeError);
+            m_unsupportedTypeError = 0;
+        }
+        else
+        {
+        MafwError err;
+        err.setCode(MafwError::RendererError_PlaylistParsing);
+        Q_EMIT rendererError(err);
+        }
+    }
+    else if (!m_playingPlaylistFile)
+    {
+        qDebug() << __PRETTY_FUNCTION__ << "waiting for playlist file items...";
+        MafwError err;
+        err.setCode(MafwError::RendererError_NoPlaylist);
+        m_playlistFileUtil->setPendingError(err);
+        m_playlistNextTimer.start(1000);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::playNext
+ ********************************************************************/
+void MafwGstRenderer::playNext()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    m_playingPlaylistFile = false;
+    m_playedPlaylistItem = false;
+
+    //Preserve m_currentContent for keeping usage count up if the same item is
+    //played again.
+    if( !m_nextContent.uuid().isEmpty() && (m_nextContent.uuid() == m_currentContent.uuid()) )
+    {
+        m_nextContent = m_currentContent;
+    }
+
+    const QUrl nextURI = m_nextContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+    if( !nextURI.isEmpty() )
+    {
+        m_playingItem = MafwBasicRenderer::NextUri;
+        m_currentContent = m_nextContent;
+        m_nextContent = MafwMediaInfo();
+
+        playURI(nextURI.toEncoded());
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::playNextURIFromPlaylist
+ ********************************************************************/
+void MafwGstRenderer::playNextURIFromPlaylist()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    QString uri = m_playlistFileUtil->takeFirstUri();
+
+    bool okToPlay=true;
+    if(uri.isEmpty())
+    {
+        okToPlay=false;
+    }
+    else if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
+    {
+        qDebug() << "MafwGstRenderer::playNextURIFromPlaylist: Can't play MMC not mounted";
+        MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri);
+        m_playlistFileUtil->setPendingError( mafwError );
+        okToPlay=false;
+    }
+
+    if (okToPlay)
+    {
+        m_playlistFileUtil->takePendingError(); // clear it, we have a new candidate
+        qDebug() << "Trying next uri: " << uri;
+        mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
+        QList<QVariant> metadataValue;
+        metadataValue << uri;
+        Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue);
+    }
+    else
+    {
+        m_playingPlaylistFile = false;
+
+        if (m_playedPlaylistItem)
+        {
+            Q_EMIT rendererEos();
+        }
+        m_playedPlaylistItem = false;
+
+
+        MafwError mafwError = m_playlistFileUtil->takePendingError();
+        if ( mafwError.code() != MafwError::NoError)
+        {
+            Q_EMIT rendererError(mafwError);
+            doStop();
+            MafwRendererPolicy *policy = rendererPolicy();
+            if( policy )
+            {
+                policy->release();
+            }
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::slotCurrentMediaInfo
+ ********************************************************************/
+void MafwGstRenderer::slotGetCurrentMediaInfo(QObject* receiver, const char* member, const QString& metadataKey)
+{
+    MafwMediaInfo info(m_currentContent.uuid());
+
+    //get all metadata
+    if(metadataKey.isEmpty())
+    {
+        info.setMetaData(m_currentMetaData);
+    }
+    //get one item
+    else
+    {
+        QMap<QString, QList<QVariant> >::const_iterator iter = m_currentMetaData.find(metadataKey);
+        if (iter != m_currentMetaData.end())
+        {
+            info.appendMetaData(iter.key(), iter.value());
+        }
+    }
+
+    sendMediaInfo(info, receiver, member);
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleVolumeChange
+ ********************************************************************/
+void MafwGstRenderer::handleVolumeChange(uint level)
+{
+    qDebug() << "MafwGstRenderer::handleVolumeChange: " << level;
+    Q_EMIT mafwPropertyChanged(PROPERTY_VOLUME, level);
+}
+
+/********************************************************************
+ * MafwGstRenderer::stopStreaming
+ ********************************************************************/
+void MafwGstRenderer::stopStreaming()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    if( mafw_gst_renderer_worker_get_streaming(m_worker) )
+    {
+        mafw_gst_renderer_worker_stop(m_worker);
+        stopTimers();
+    }
+
+    // emit error and stop for real, only if no valid halt state is set
+    if( !m_haltState.isSet() )
+    {
+        doStop();
+        MafwError error;
+        error.setCode(MafwError::RendererError_StreamDisconnected);
+        Q_EMIT rendererError(error);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::haltStreaming
+ ********************************************************************/
+void MafwGstRenderer::haltStreaming()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    if( mafw_gst_renderer_worker_get_streaming(m_worker) )
+    {
+        QString uri;
+        if( m_playlistNextTimer.isActive() )
+        {
+            uri = m_playlistFileUtil->takeFirstUri();
+        }
+        else
+        {
+            uri = mafw_gst_renderer_worker_get_uri(m_worker);
+        }
+
+        int position = -1;
+        if( mafw_gst_renderer_worker_get_seekable(m_worker) )
+        {
+            position = mafw_gst_renderer_worker_get_position(m_worker);
+            if( position < 0 )
+            {
+                qWarning() << "Cannot resume to correct position after networkchange!";
+            }
+        }
+
+        //make sure we've uri to resume, the playlist parser may have been trying to parse something
+        if( uri.length() > 0 )
+        {
+            m_haltState = MafwGstRendererHaltState(uri, m_currentState, position);
+            //valid haltstate constructed, clear the possible pending error in playlist handling
+            if( m_playlistFileUtil )
+            {
+                m_playlistFileUtil->takePendingError();
+            }
+        }
+        else
+        {
+            //just in case
+            m_haltState.clear();
+        }
+
+        //now actually stop, and depending on the haltstate validity it will also emit error
+        stopStreaming();
+    }
+    else
+    {
+        qDebug() << "Not streaming!";
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::continueStreaming
+ ********************************************************************/
+void MafwGstRenderer::continueStreaming()
+{
+    if( mafw_gst_renderer_worker_get_streaming(m_worker) || m_haltState.isSet() )
+    {
+        //if not yet halted, do it now
+        if( !m_haltState.isSet() )
+        {
+            haltStreaming();
+        }
+
+        m_playingItem = MafwBasicRenderer::CurrentUri;
+
+        if( m_haltState.state() == MafwRenderer::Playing )
+        {
+            mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData());
+            int pausePos = m_haltState.position() > 0 ? m_haltState.position() : 0;
+
+            if( m_haltState.state() == MafwRenderer::Playing && pausePos > 0 )
+            {
+                qDebug() << "Resuming streaming from position: " << m_haltState.position();
+                doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute);
+            }
+            m_haltState.clear();
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::handlePropertyChanged
+ ********************************************************************/
+void MafwGstRenderer::handlePropertyChanged(const QString& name,
+                                            const QVariant& value)
+{
+    // This is a way to check if the policy is on. We need to set the
+    // PAUSED-to-READY timeout to zero, since we need to be sure that the
+    // resources really get released by the GStreamer.  It is unfortunate that
+    // a doPause() and PAUSED state is not enough, e.g. in case of XVideo.
+    if (name == MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE)
+    {
+        guint timeout;
+        if (value.toBool() == true)
+        {
+            timeout = 0;
+        }
+        else
+        {
+            timeout = MAFW_GST_RENDERER_WORKER_READY_TIMEOUT;
+        }
+        mafw_gst_renderer_worker_set_ready_timeout(m_worker, timeout);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleDHMMusicPropertyChanged
+ ********************************************************************/
+void MafwGstRenderer::handleDHMMusicPropertyChanged()
+{
+    if (m_worker)
+    {
+        qDebug() << "MafwGstRenderer::handleDHMMusicPropertyChanged set_dolby_music_property" << m_dolby->getMusicDolbyState();
+        set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
+        set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
+        set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleDHMVideoPropertyChanged
+ ********************************************************************/
+void MafwGstRenderer::handleDHMVideoPropertyChanged()
+{
+    if (m_worker)
+    {
+        qDebug() << "MafwGstRenderer::handleDHMVideoPropertyChanged set_dolby_video_property" << m_dolby->getVideoDolbyState();
+        set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
+        set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
+        set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleScreenshot
+ ********************************************************************/
+void MafwGstRenderer::handleScreenshot(char *location, GError *error)
+{
+    if(!error)
+    {
+        QList<QVariant> results;
+        results << location;
+
+        QString mafwMetadataKey = MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI;
+
+        appendRelatedMetadata(mafwMetadataKey, &results);
+        Q_EMIT metadataChanged(mafwMetadataKey, results);
+        m_currentMetaData.insert(mafwMetadataKey, results);
+    }
+    else
+    {
+        qCritical() << error->message;
+    }
+
+    m_worker->taking_screenshot = FALSE;
+}
+
+/********************************************************************
+ * MafwGstRenderer::cancelScreenshot
+ ********************************************************************/
+void MafwGstRenderer::cancelScreenshot()
+{
+    if(m_worker)
+    {
+        m_worker->taking_screenshot = FALSE;
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::sendMediaInfo
+ ********************************************************************/
+void MafwGstRenderer::sendMediaInfo(const MafwMediaInfo& info, QObject* receiver, const char* member)
+{
+    QMetaMethod method;
+    bool methodFound;
+
+    methodFound = MafwCallbackHelper::getCallbackMethod(receiver, member, method);
+
+    if (!methodFound)
+    {
+        MafwError err;
+        err.setCode(MafwError::CallbackSlotNotFound);
+        Q_EMIT error(err);
+    }
+    //actual result callback call is inside this if()
+    else if( !method.invoke(receiver, Q_ARG(MafwMediaInfo, info)) )
+    {
+        MafwError err;
+        err.setCode(MafwError::CallbackCouldNotInvoke);
+        Q_EMIT error(err);
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::mmcPreUnmount
+ ********************************************************************/
+void MafwGstRenderer::mmcPreUnmount()
+{
+    qDebug() << "MafwGstRenderer::mmcPreUnmount" << m_currentState;
+
+    if( m_currentState!=MafwRenderer::Stopped )
+    {
+        const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+        if( url.toString().startsWith(MafwMmcMonitor::MMC_URI_PREFIX) )
+        {
+            qDebug() << "MafwGstRenderer::mmcPreUnmount: playing from MMC, going to stop";
+            doStop();
+            MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded());
+            Q_EMIT rendererError(mafwError);
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::connectNameOwnerChanged
+ ********************************************************************/
+bool MafwGstRenderer::connectNameOwnerChanged()
+{
+    QStringList argumentMatch;
+    argumentMatch << DBUS_NAME_PCFD;
+
+    QDBusConnection connection = QDBusConnection::systemBus();
+    return connection.connect( QString(),
+                                 QString(),
+                                 DBUS_INTERFACE_DBUS,
+                                 DBUS_SIGNAL_NAME_OWNER_CHANGED,
+                                 argumentMatch,
+                                 QString(),
+                                 this,
+                                 SLOT(handleContextProviderRemoval(QDBusMessage) ) );
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleContextProviderRemoval
+ ********************************************************************/
+void MafwGstRenderer::handleContextProviderRemoval( const QDBusMessage& message )
+{
+    QList<QVariant> arguments;
+    QString name;
+    QString oldName;
+    QString newName;
+
+    arguments= message.arguments();
+
+    if ( message.type() == QDBusMessage::SignalMessage && arguments.size()==3 )
+    {
+
+        name = arguments.at(0).toString();
+        oldName = arguments.at(1).toString();
+        newName = arguments.at(2).toString();
+
+        if ( oldName.length() && newName.length()==0 )
+        {
+            qDebug() << "MafwGstRenderer::handleContextProviderRemoval context provider died";
+
+            // add null output
+            GSList *destinations = NULL;
+            destinations = g_slist_append(destinations,
+                                          GINT_TO_POINTER(WORKER_OUTPUT_NULL));
+            mafw_gst_renderer_worker_notify_media_destination(this->m_worker,
+                                                              destinations);
+            g_slist_free(destinations);
+        }
+    }
+}
+
+/********************************************************************
+ * MafwGstRenderer::handleResolutionError
+ ********************************************************************/
+void MafwGstRenderer::handleResolutionError(MafwError &error)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+    const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
+    MafwError::Code errorCode = MafwError::RendererError_UnsuppertedType;
+
+    if( url.isValid() && url.toString().startsWith("file://") )
+    {
+        qDebug() << __PRETTY_FUNCTION__ << url;
+
+        QSparqlQuery query(QString("SELECT ?height ?width WHERE { "
+                                   "?_u nie:url \"%1\" ."
+                                   "?_u nfo:height ?height . "
+                                   "?_u nfo:width ?width }")
+                           .arg(QString(url.toEncoded())));
+
+        QSparqlResult *result = m_sparqlConnection->syncExec(query);
+
+        if( result->hasError() )
+        {
+            qWarning() << __PRETTY_FUNCTION__ << " surprising result";
+            qWarning() << result->lastError().message();
+        }
+        else if( result->first() )
+        {
+            int height = result->stringValue(0).toInt();
+            int width = result->stringValue(1).toInt();
+
+            if (height > MAX_SUPPORTED_HEIGHT || width > MAX_SUPPORTED_WIDTH)
+            {
+                errorCode = MafwError::RendererError_UnsupportedResolution;
+            }
+        }
+        delete result;
+    }
+    error.setCode(errorCode);
+}
+
+/********************************************************************
+ * MafwGstRenderer::setConfiguration
+ ********************************************************************/
+void MafwGstRenderer::setConfiguration(QSettings *settings)
+{
+    //if no settings use "factory" configuration
+    if( !settings )
+    {
+        return;
+    }
+
+    configuration *defaultconfig = mafw_gst_renderer_worker_create_default_configuration(m_worker);
+
+    //pipeline settings
+    settings->beginGroup("pipeline");
+    QVariant value = readSettingsValue(settings, "audio-sink", defaultconfig->asink);
+    qFree(defaultconfig->asink);
+    defaultconfig->asink = g_strdup(value.toString().toAscii());
+
+    value = readSettingsValue(settings, "video-sink", defaultconfig->vsink);
+    qFree(defaultconfig->vsink);
+    defaultconfig->vsink = g_strdup(value.toString().toAscii());
+
+    value = readSettingsValue(settings, "flags", defaultconfig->flags);
+    defaultconfig->flags = value.toInt();
+
+    value = readSettingsValue(settings, "use_dhmmixer", defaultconfig->use_dhmmixer);
+    defaultconfig->use_dhmmixer = value.toBool();
+
+    value = readSettingsValue(settings, "buffer-time", defaultconfig->buffer_time);
+    defaultconfig->buffer_time = value.toULongLong();
+
+    value = readSettingsValue(settings, "latency-time", defaultconfig->latency_time);
+    defaultconfig->latency_time = value.toULongLong();
+
+    value = readSettingsValue(settings, "autoload_subtitles", defaultconfig->autoload_subtitles);
+    defaultconfig->autoload_subtitles = value.toBool();
+
+    value = readSettingsValue(settings, "subtitle_encoding", defaultconfig->subtitle_encoding);
+    qFree(defaultconfig->subtitle_encoding);
+    defaultconfig->subtitle_encoding = g_strdup(value.toString().toAscii());
+
+    value = readSettingsValue(settings, "subtitle_font", defaultconfig->subtitle_font);
+    qFree(defaultconfig->subtitle_font);
+    defaultconfig->subtitle_font = g_strdup(value.toString().toAscii());
+    settings->endGroup();
+
+    //timers
+    settings->beginGroup("timers");
+    value = readSettingsValue(settings, "pause-frame", defaultconfig->milliseconds_to_pause_frame);
+    defaultconfig->milliseconds_to_pause_frame = value.toUInt();
+
+    value = readSettingsValue(settings, "pause-to-ready", defaultconfig->seconds_to_pause_to_ready);
+    defaultconfig->seconds_to_pause_to_ready = value.toUInt();
+    settings->endGroup();
+
+    //dhmmixer
+    settings->beginGroup("dhmmixer");
+    value = readSettingsValue(settings, "dhm-music-surround", defaultconfig->mobile_surround_music.state);
+    defaultconfig->mobile_surround_music.state = value.toUInt();
+
+    value = readSettingsValue(settings, "dhm-music-color", defaultconfig->mobile_surround_music.color);
+    defaultconfig->mobile_surround_music.color = value.toInt();
+
+    value = readSettingsValue(settings, "dhm-music-room-size", defaultconfig->mobile_surround_music.room);
+    defaultconfig->mobile_surround_music.room = value.toInt();
+
+    value = readSettingsValue(settings, "dhm-video-surround", defaultconfig->mobile_surround_video.state);
+    defaultconfig->mobile_surround_video.state = value.toUInt();
+
+    value = readSettingsValue(settings, "dhm-video-color", defaultconfig->mobile_surround_video.color);
+    defaultconfig->mobile_surround_video.color = value.toInt();
+
+    value = readSettingsValue(settings, "dhm-video-room-size", defaultconfig->mobile_surround_video.room);
+    defaultconfig->mobile_surround_video.room = value.toInt();
+    settings->endGroup();
+
+    mafw_gst_renderer_worker_set_configuration(m_worker, defaultconfig);
+}
+
+/********************************************************************
+ * MafwGstRenderer::readSettingsValue
+ ********************************************************************/
+QVariant MafwGstRenderer::readSettingsValue(QSettings *settings,
+                                            const QString &valueName,
+                                            const QVariant &defaultValue) const
+{
+    QVariant value = settings->value(valueName, defaultValue);
+    if( !settings->contains(valueName) )
+    {
+        qWarning() << "No value for: (" << valueName << ") in configuration file! Using factory default";
+    }
+    return value;
+}
+
+/********************************************************************
+ * MafwGstRenderer::errorMap
+ ********************************************************************/
+const QHash<int, MafwError::Code>& MafwGstRenderer::errorMap()
+{
+
+    static QHash<int, MafwError::Code> map;
+
+    if (map.isEmpty())
+    {
+        /* initialize error map */
+        map[WORKER_ERROR_PLAYBACK] =
+            MafwError::RendererError_Playback;
+        map[WORKER_ERROR_VIDEO_CODEC_NOT_FOUND] =
+            MafwError::RendererError_VideoCodeNotFound;
+        map[WORKER_ERROR_AUDIO_CODEC_NOT_FOUND] =
+            MafwError::RendererError_AudioCodecNotFound;
+        map[WORKER_ERROR_CODEC_NOT_FOUND] =
+            MafwError::RendererError_CodecNotFound;
+        map[WORKER_ERROR_UNSUPPORTED_TYPE] =
+            MafwError::RendererError_UnsuppertedType;
+        map[WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE] =
+            MafwError::RendererError_UnsuppertedType;
+        map[WORKER_ERROR_UNABLE_TO_PERFORM] =
+            MafwError::RendererError_UnableToPerform;
+        map[WORKER_ERROR_CANNOT_SET_POSITION] =
+            MafwError::RendererError_CannotSetPosition;
+        map[WORKER_ERROR_PLAYLIST_PARSING] =
+            MafwError::RendererError_PlaylistParsing;
+        map[WORKER_ERROR_DRM_NO_LICENSE] =
+            MafwError::RendererError_DRMNoLicense;
+        map[WORKER_ERROR_DRM_NOT_ALLOWED] =
+            MafwError::RendererError_DRMNotAllowed;
+        map[WORKER_ERROR_DRM_OTHER] =
+            MafwError::RendererError_DRMOther;
+        map[WORKER_ERROR_STREAM_DISCONNECTED] =
+            MafwError::RendererError_StreamDisconnected;
+        map[WORKER_ERROR_INVALID_URI] =
+            MafwError::RendererError_InvalidURI;
+        map[WORKER_ERROR_MEDIA_NOT_FOUND] =
+            MafwError::RendererError_MediaNotFound;
+        map[WORKER_ERROR_CORRUPTED_FILE] =
+            MafwError::RendererError_CorruptedFile;
+        map[WORKER_ERROR_TYPE_NOT_AVAILABLE] =
+            MafwError::RendererError_TypeNotAvailable;
+    }
+
+    return map;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::metadataMap
+ ********************************************************************/
+const QHash<int, QString>& MafwGstRenderer::metadataMap()
+{
+
+    static QHash<int, QString> map;
+
+    if (map.isEmpty())
+    {
+        /* initialize metadata key map */
+        map[WORKER_METADATA_KEY_TITLE] =
+            MAFW_METADATA_KEY_TITLE;
+        map[WORKER_METADATA_KEY_ARTIST] =
+            MAFW_METADATA_KEY_ARTIST;
+        map[WORKER_METADATA_KEY_AUDIO_CODEC] =
+            MAFW_METADATA_KEY_AUDIO_CODEC;
+        map[WORKER_METADATA_KEY_VIDEO_CODEC] =
+            MAFW_METADATA_KEY_VIDEO_CODEC;
+        map[WORKER_METADATA_KEY_BITRATE] =
+            MAFW_METADATA_KEY_BITRATE;
+        map[WORKER_METADATA_KEY_ENCODING] =
+            MAFW_METADATA_KEY_ENCODING;
+        map[WORKER_METADATA_KEY_ALBUM] =
+            MAFW_METADATA_KEY_ALBUM;
+        map[WORKER_METADATA_KEY_GENRE] =
+            MAFW_METADATA_KEY_GENRE;
+        map[WORKER_METADATA_KEY_TRACK] =
+            MAFW_METADATA_KEY_TRACK;
+        map[WORKER_METADATA_KEY_ORGANIZATION] =
+            MAFW_METADATA_KEY_ORGANIZATION;
+        map[WORKER_METADATA_KEY_RENDERER_ART_URI] =
+            MAFW_METADATA_KEY_RENDERER_ART_URI;
+        map[WORKER_METADATA_KEY_RES_X] =
+            MAFW_METADATA_KEY_RES_X;
+        map[WORKER_METADATA_KEY_RES_Y] =
+            MAFW_METADATA_KEY_RES_Y;
+        map[WORKER_METADATA_KEY_VIDEO_FRAMERATE] =
+            MAFW_METADATA_KEY_VIDEO_FRAMERATE;
+        map[WORKER_METADATA_KEY_DURATION] =
+            MAFW_METADATA_KEY_DURATION;
+        map[WORKER_METADATA_KEY_IS_SEEKABLE] =
+            MAFW_METADATA_KEY_IS_SEEKABLE;
+        map[WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI] =
+            MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI;
+        map[WORKER_METADATA_KEY_URI] =
+            MAFW_METADATA_KEY_URI;
+    }
+
+    return map;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::audioRouteMap
+ ********************************************************************/
+const QHash<QString, QList<int> >& MafwGstRenderer::audioRouteMap()
+{
+
+    static QHash<QString, QList<int> > map;
+
+    if (map.isEmpty())
+    {
+        map[AUDIO_ROUTE_NULL]               = QList<int>() << WORKER_OUTPUT_NULL;
+        map[AUDIO_ROUTE_IHF]                = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS;
+        map[AUDIO_ROUTE_FMRADIO]            = QList<int>() << WORKER_OUTPUT_FM_RADIO;
+        map[AUDIO_ROUTE_IHF_AND_FMRADIO]    = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_FM_RADIO;
+
+        // earpiece is intentionally handled as builtdin speaker, well it kinda is
+        map[AUDIO_ROUTE_EARPIECE]           = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS;
+        map[AUDIO_ROUTE_EARPIECE_AND_TVOUT] = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT;
+
+        map[AUDIO_ROUTE_TV_OUT]             = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
+        map[AUDIO_ROUTE_IHF_AND_TV_OUT]     = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT;
+        map[AUDIO_ROUTE_HEADPHONE]          = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
+        map[AUDIO_ROUTE_HEADSET]            = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
+        map[AUDIO_ROUTE_BTHSP]              = QList<int>() << WORKER_OUTPUT_BLUETOOTH_AUDIO;
+        map[AUDIO_ROUTE_BTA2DP]             = QList<int>() << WORKER_OUTPUT_BLUETOOTH_AUDIO;
+        map[AUDIO_ROUTE_IHF_AND_HEADSET]    = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK;
+        map[AUDIO_ROUTE_IHF_AND_HEADPHONE]  = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK;
+        map[AUDIO_ROUTE_IHF_AND_BTHSP]      = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_BLUETOOTH_AUDIO;
+        map[AUDIO_ROUTE_TV_OUT_AND_BTHSP]   = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO;
+        map[AUDIO_ROUTE_TV_OUT_AND_BTA2DP]  = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO;
+    }
+
+    return map;
+
+}
+
+/********************************************************************
+ * MafwGstRenderer::videoRouteMap
+ ********************************************************************/
+const QHash<QString, QList<int> >& MafwGstRenderer::videoRouteMap()
+{
+
+    static QHash<QString, QList<int> > map;
+
+    if (map.isEmpty())
+    {
+        map[VIDEO_ROUTE_TV_OUT]              = QList<int>() << WORKER_OUTPUT_TVOUT;
+        map[VIDEO_ROUTE_BUILT_IN]            = QList<int>() << WORKER_OUTPUT_BUILTIN_DISPLAY;
+        map[VIDEO_ROUTE_BUILT_IN_AND_TV_OUT] = QList<int>() << WORKER_OUTPUT_BUILTIN_DISPLAY << WORKER_OUTPUT_TVOUT;
+    }
+
+    return map;
+
+}
+