Added DUI control panel applet
[mafwsubrenderer] / qmafw-gst-subtitles-renderer / src / MafwGstRenderer.cpp
1 /*
2  * This file is part of QMAFW
3  *
4  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights
5  * reserved.
6  *
7  * Contact: Visa Smolander <visa.smolander@nokia.com>
8  *
9  * This software, including documentation, is protected by copyright controlled
10  * by Nokia Corporation. All rights are reserved. Copying, including
11  * reproducing, storing, adapting or translating, any or all of this material
12  * requires the prior written consent of Nokia Corporation. This material also
13  * contains confidential information which may not be disclosed to others
14  * without the prior written consent of Nokia.
15  *
16  */
17
18 #include <QDebug>
19 #include <QMetaMethod>
20 #include <QTimer>
21
22 #include <glib.h>
23 #include <gst/gst.h>
24 #include <X11/Xdefs.h>
25
26 #include <MafwCallbackHelper.h>
27 #include <MafwMetadata.h>
28 #include <MafwMediaInfo.h>
29
30 #include "MafwGstRenderer.h"
31 #include "MafwBlankingPreventer.h"
32 #include "mafw-gst-renderer-worker.h"
33 #include "MafwGstRendererVolume.h"
34 #include "MafwGstRendererDolby.h"
35 #include "MafwGstRendererNetworkMonitor.h"
36 #include "MafwGstRendererHaltState.h"
37 #include "MafwGstRendererPlaylistFileUtility.h"
38 #include "MafwGstScreenshot.h"
39 #include "MafwMmcMonitor.h"
40
41 #include <QSettings>
42 #include <contextsubscriber/contextproperty.h>
43 #include <QDBusConnection>
44 #include <QDBusMessage>
45 #include <QDateTime>
46 #include <QSparqlConnection>
47 #include <QSparqlResult>
48 #include <QSparqlQuery>
49 #include <QSparqlError>
50
51 // milliseconds, stamp after playing this much
52 const int PLAYED_STAMP_INTERVAL = 5000;
53
54 const int MAX_SUPPORTED_HEIGHT = 720;
55 const int MAX_SUPPORTED_WIDTH = 1280;
56 // how many time we retried to make played stamps
57 const int PLAYED_STAMP_TRIES = 3;
58
59 static const int ISO_DATE_BASE_LENGTH = 19; // length of "CCYY-MM-DDThh:mm:ss"
60
61 // property names
62 const QString PROPERTY_DOLBY_STATE_MUSIC    = "mobile-surround-state-music";
63 const QString PROPERTY_DOLBY_STATE_MUSIC_ROOM    = "mobile-surround-state-music-room";
64 const QString PROPERTY_DOLBY_STATE_MUSIC_COLOR    = "mobile-surround-state-music-color";
65 const QString PROPERTY_DOLBY_STATE_VIDEO    = "mobile-surround-state-video";
66 const QString PROPERTY_DOLBY_STATE_VIDEO_ROOM    = "mobile-surround-state-video-room";
67 const QString PROPERTY_DOLBY_STATE_VIDEO_COLOR    = "mobile-surround-state-video-color";
68 const QString PROPERTY_VOLUME    = "volume";
69 const QString PROPERTY_AUTOPAINT = "autopaint";
70 const QString PROPERTY_COLORKEY  = "colorkey";
71 const QString PROPERTY_XID       = "xid";
72 const QString PROPERTY_RENDER_RECT = "render-rectangle";
73 const QString PROPERTY_CURRENT_FRAME_ON_PAUSE = "current-frame-on-pause";
74 const QString PROPERTY_PLAYBACK_SPEED   = "playback-speed";
75 const QString PROPERTY_FORCE_ASPECT_RATIO  = "force-aspect-ratio";
76
77 // audio/video destinations
78 const QString CONTEXT_FW_PROPERTY_AUDIO_ROUTE = "/com/nokia/policy/audio_route";
79 const QString CONTEXT_FW_PROPERTY_VIDEO_ROUTE = "/com/nokia/policy/video_route";
80 const QString AUDIO_ROUTE_NULL                = "null";
81 const QString AUDIO_ROUTE_IHF                 = "ihf";
82 const QString AUDIO_ROUTE_FMRADIO             = "fmtx";
83 const QString AUDIO_ROUTE_IHF_AND_FMRADIO     = "ihfandfmtx";
84 const QString AUDIO_ROUTE_EARPIECE            = "earpiece";
85 const QString AUDIO_ROUTE_EARPIECE_AND_TVOUT  = "earpieceandtvout";
86 const QString AUDIO_ROUTE_TV_OUT              = "tvout";
87 const QString AUDIO_ROUTE_IHF_AND_TV_OUT      = "ihfandtvout";
88 const QString AUDIO_ROUTE_HEADPHONE           = "headphone";
89 const QString AUDIO_ROUTE_HEADSET             = "headset";
90 const QString AUDIO_ROUTE_BTHSP               = "bthsp";
91 const QString AUDIO_ROUTE_BTA2DP              = "bta2dp";
92 const QString AUDIO_ROUTE_IHF_AND_HEADSET     = "ihfandheadset";
93 const QString AUDIO_ROUTE_IHF_AND_HEADPHONE   = "ihfandheadphone";
94 const QString AUDIO_ROUTE_IHF_AND_BTHSP       = "ihfandbthsp";
95 const QString AUDIO_ROUTE_TV_OUT_AND_BTHSP    = "tvoutandbthsp";
96 const QString AUDIO_ROUTE_TV_OUT_AND_BTA2DP   = "tvoutandbta2dp";
97 const QString VIDEO_ROUTE_TV_OUT              = "tvout";
98 const QString VIDEO_ROUTE_BUILT_IN            = "builtin";
99 const QString VIDEO_ROUTE_BUILT_IN_AND_TV_OUT = "builtinandtvout";
100
101 const QString DBUS_INTERFACE_DBUS="org.freedesktop.DBus";
102 const QString DBUS_SIGNAL_NAME_OWNER_CHANGED="NameOwnerChanged";
103 const QString DBUS_NAME_PCFD = "com.nokia.policy.pcfd";
104
105 /********************************************************************
106  * MafwGstRenderer::MafwGstRenderer
107  ********************************************************************/
108 MafwGstRenderer::MafwGstRenderer(const QString& uuid,
109                                  const QString& pluginName,
110                                  const QString& name,
111                                  QObject *parent)
112     :
113     MafwBasicRenderer(uuid, pluginName, name, parent),
114     m_initialized(false),
115     m_currentState(MafwRenderer::Invalid),
116     m_nextContent(""),
117     m_currentContent(""),
118     m_playingItem(MafwBasicRenderer::UnknownUri),
119     m_blankingPreventer(0),
120     m_screenshot(0),
121     m_networkMonitor(new MafwGstRendererNetworkMonitor()),
122     m_volume(0),
123     m_playedStamped(false),
124     m_playedStampTryCounter(0),
125     m_sparqlConnection(new QSparqlConnection("QTRACKER", QSparqlConnectionOptions(), this)),
126     m_urnQueryResult(0),
127     m_stampItResult(0),
128     m_playlistFileUtil(0),
129     m_playingPlaylistFile(false),
130     m_unsupportedTypeError(0),
131     m_playedPlaylistItem(false),
132     m_mmcMonitor(0)
133 {
134     qDebug() << __PRETTY_FUNCTION__;
135
136     m_dolby = new MafwGstRendererDolby(this);
137     connect(m_dolby, SIGNAL(mafwDHMMusicPropertyChanged()),
138             this, SLOT(handleDHMMusicPropertyChanged()));
139     connect(m_dolby, SIGNAL(mafwDHMVideoPropertyChanged()),
140             this, SLOT(handleDHMVideoPropertyChanged()));
141
142     m_worker = 0;
143     m_videoRoute = 0;
144     m_audioRoute = 0;
145     gst_init(0, 0);
146
147     /* make this connection a queued connection to postpone results delivery,
148      * so that results callback is not called already in the function that
149      * initiates this procedure */
150     QObject::connect(this, SIGNAL(signalGetPosition(QObject*,
151                                                     const char*)),
152                      this, SLOT(slotGetPosition(QObject*,
153                                                 const char*)),
154                      Qt::QueuedConnection);
155
156     /* make this connection a queued connection to postpone results delivery,
157      * so that results callback is not called already in the function that
158      * initiates this procedure */
159     QObject::connect(this, SIGNAL(signalMafwProperty(QString,
160                                                      QObject*,
161                                                      const char*)),
162                      this, SLOT(slotMafwProperty(QString,
163                                                  QObject*,
164                                                  const char*)),
165                      Qt::QueuedConnection);
166
167     /* make this connection a queued connection to postpone results delivery,
168      * so that results callback is not called already in the function that
169      * initiates this procedure */
170     QObject::connect(this, SIGNAL(signalGetCurrentMediaInfo(QObject*,
171                                                             const char*,
172                                                             const QString)),
173                     this, SLOT(slotGetCurrentMediaInfo(QObject*,
174                                                         const char*,
175                                                         const QString)),
176                     Qt::QueuedConnection);
177
178     m_playedStampTimer.setSingleShot(true);
179     connect(&m_playedStampTimer,SIGNAL(timeout()),this,SLOT(slotStamp()));
180
181     m_videoRoute = new ContextProperty(CONTEXT_FW_PROPERTY_VIDEO_ROUTE);
182     m_audioRoute = new ContextProperty(CONTEXT_FW_PROPERTY_AUDIO_ROUTE);
183
184     connectNameOwnerChanged();
185
186     m_playlistNextTimer.setSingleShot(true);
187     connect(&m_playlistNextTimer, SIGNAL(timeout()),
188             this, SLOT(playNextURIFromPlaylist()));
189
190     /* connection is to track when policy is on/off */
191     connect(this, SIGNAL(mafwPropertyChanged(const QString, const QVariant)),
192             this, SLOT(handlePropertyChanged(const QString&, const QVariant&)));
193
194     /* Connection to handle online status message if necessary */
195     connect(m_networkMonitor, SIGNAL(prepareNetworkChange()),
196             this, SLOT(haltStreaming()));
197     connect(m_networkMonitor, SIGNAL(networkChangeFinished()),
198             this, SLOT(continueStreaming()));
199
200     connect(&m_haltState, SIGNAL(decayed()),
201             this, SLOT(stopStreaming()));
202 }
203
204 /********************************************************************
205  * MafwGstRenderer::~MafwGstRenderer
206  ********************************************************************/
207 MafwGstRenderer::~MafwGstRenderer()
208 {
209
210     qDebug() << __PRETTY_FUNCTION__;
211     delete m_volume;
212     // this releases the resources allocated by the worker, do this before
213     // releasing anything else so any callbacks from worker won't be called
214     mafw_gst_renderer_worker_exit(m_worker);
215
216     delete m_videoRoute;
217     delete m_audioRoute;
218     delete m_networkMonitor;
219     delete m_screenshot;
220     delete m_urnQueryResult;
221     delete m_stampItResult;
222     delete m_sparqlConnection;
223
224     g_free(m_worker);
225
226     if( m_unsupportedTypeError )
227     {
228         g_error_free(m_unsupportedTypeError);
229     }
230 }
231
232
233 /********************************************************************
234  * MafwGstRenderer::initialize
235  ********************************************************************/
236 bool MafwGstRenderer::initialize(QSettings *settings)
237 {
238
239     qDebug() << __PRETTY_FUNCTION__;
240
241     //if already initialized do nothing
242     if (m_initialized)
243     {
244         return m_initialized;
245     }
246
247     m_initialized = MafwBasicRenderer::initialize();
248
249     if (m_initialized)
250     {
251         // fail to apply default policy is not considered fatal for now
252         if (MafwBasicRenderer::setDefaultRendererPolicy(MafwRendererPolicy::MediaPlayer))
253         {
254             MafwRendererPolicy *policy = rendererPolicy();
255             Q_ASSERT(policy);
256             policy->setDefaultResources(MafwRendererPolicy::Audio);
257         }
258         else
259         {
260             qWarning() << "Setting default policy failed, continuing";
261         }
262
263         m_blankingPreventer = new MafwBlankingPreventer(this);
264
265         m_screenshot = new MafwGstScreenshot(this);
266
267         connect(m_screenshot, SIGNAL(screenshotTaken(char*,GError*)),
268                 this, SLOT(handleScreenshot(char*,GError*)));
269         connect(m_screenshot, SIGNAL(screenshotCancelled()),
270                 this, SLOT(cancelScreenshot()));
271
272         m_worker = mafw_gst_renderer_worker_new(this);
273         m_worker->notify_play_handler = &playCallback;
274         m_worker->notify_pause_handler = &pauseCallback;
275         m_worker->notify_error_handler = &errorCallback;
276         m_worker->notify_eos_handler = &eosCallback;
277         m_worker->notify_ready_state_handler = &readyStateCallback;
278         m_worker->notify_metadata_handler = &metadataCallback;
279         m_worker->notify_property_handler = &propertyCallback;
280         m_worker->notify_buffer_status_handler = &bufferStatusCallback;
281         m_worker->blanking__control_handler = &blankingControlCallback;
282         m_worker->screenshot_handler = &screenshotCallback;
283
284         setConfiguration(settings);
285
286         // Initialize Dolby support
287         m_dolby->initialize();
288
289         m_mmcMonitor = new MafwMmcMonitor(this);
290         connect( m_mmcMonitor, SIGNAL( preUnmount() ), this, SLOT( mmcPreUnmount() ) );
291
292         // connect the audio routes AND check the current values of routes.
293         connect( m_videoRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) );
294         connect( m_audioRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) );
295         slotRouteChanged();
296     }
297     return m_initialized;
298 }
299
300 /********************************************************************
301  * MafwGstRenderer::playCallback
302  ********************************************************************/
303 void MafwGstRenderer::playCallback(MafwGstRendererWorker *worker,
304                                    gpointer owner)
305 {
306     Q_UNUSED(worker);
307
308     qDebug() << __PRETTY_FUNCTION__;
309     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
310
311     if( self->m_currentState == MafwRenderer::Paused )
312     {
313         Q_EMIT self->rendererResumed();
314     }
315     else
316     {
317         if( self->m_playingPlaylistFile )
318         {
319             if( !self->m_playedPlaylistItem )
320             {
321                 qDebug() << "Emitting playing item event";
322                 Q_EMIT self->rendererPlaying(static_cast<int>(self->m_playingItem));
323                 self->m_playedPlaylistItem = true;
324             }
325         }
326         else
327         {
328             Q_EMIT self->rendererPlaying(static_cast<int>(self->m_playingItem));
329         }
330     }
331
332     if( mafw_gst_renderer_worker_get_position(worker)==0 )
333     {
334         self->m_playedStamped = false;
335         self->m_playedStampTryCounter = 0;
336     }
337
338     if( !self->m_playedStamped )
339     {
340         const QUrl url = self->m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
341         if (url.scheme() == "file")
342         {
343             qDebug() << __PRETTY_FUNCTION__ << "starting play stamp timer.";
344             self->m_playedStampTimer.start(PLAYED_STAMP_INTERVAL);
345         }
346     }
347
348     self->m_currentState = MafwRenderer::Playing;
349 }
350
351 /********************************************************************
352  * MafwGstRenderer::bufferStatusCallback
353  ********************************************************************/
354 void MafwGstRenderer::bufferStatusCallback(MafwGstRendererWorker *worker,
355                                            gpointer owner,
356                                            gdouble percent)
357 {
358
359     Q_UNUSED(worker);
360
361     qDebug() << __PRETTY_FUNCTION__;
362     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
363
364     Q_EMIT self->bufferingInfo(static_cast<float>(percent));
365
366 }
367 /********************************************************************
368  * MafwGstRenderer::constructMafwError
369  ********************************************************************/
370 MafwError MafwGstRenderer::constructMafwError(const GError* error)
371 {
372     MafwError mafwError;
373     guint32 code = static_cast<guint32>(error->code);
374
375     //for streams the media not found is other than the default
376     if( code == WORKER_ERROR_MEDIA_NOT_FOUND && mafw_gst_renderer_worker_get_streaming(m_worker) )
377     {
378         mafwError.setCode(MafwError::RendererError_URINotAvailable);
379     }
380     else if(code == WORKER_ERROR_UNSUPPORTED_TYPE)
381     {
382         handleResolutionError(mafwError);
383     }
384     else if (errorMap().contains(code))
385     {
386         mafwError.setCode(errorMap().value(code));
387     }
388     else
389     {
390         mafwError.setCode(MafwError::NothingButErrors);
391     }
392
393     mafwError.setMessage(error->message);
394     return mafwError;
395 }
396
397 /********************************************************************
398  * MafwGstRenderer::errorCallback
399  ********************************************************************/
400 void MafwGstRenderer::errorCallback(MafwGstRendererWorker *worker,
401                                     gpointer owner,
402                                     const GError *error)
403 {
404     Q_UNUSED(worker);
405     qWarning() << __PRETTY_FUNCTION__ << error->message;
406     MafwError mafwError;
407     guint32 code;
408     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
409
410     code = static_cast<guint32>(error->code);
411
412     //The content might be a playlist file which was tried to play without
413     //mime type. This case can be detected by trying to play it as playlist
414     //file. If that was not the case same error will be signalled via
415     //MafwGstRenderer::handlePlaylistFileParsingErrors
416     if (!self->m_playingPlaylistFile &&
417         !self->m_unsupportedTypeError &&
418         code == WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE)
419     {
420         QMap<QString, QVariant> mime;
421         mime[MAFW_METADATA_KEY_MIME] = "audio/x-scpls";
422         self->m_currentContent.setMetaData(mime);
423         self->doPlay(self->m_currentContent);
424         self->m_unsupportedTypeError = g_error_copy(error);
425         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').";
426         qWarning() << __PRETTY_FUNCTION__ << "Trying to play as playlist file now...";
427         return;
428     }
429     mafwError = self->constructMafwError(error);
430
431     /* We release resources when we got error that causes stop.
432      * WORKER_ERROR_CANNOT_SET_POSITION and WORKER_ERROR_DRM_NOT_ALLOWED error don't cause stop.
433      */
434     if((code != WORKER_ERROR_CANNOT_SET_POSITION
435         && code != WORKER_ERROR_DRM_NOT_ALLOWED)
436         && !self->m_playingPlaylistFile)
437     {
438         Q_EMIT self->rendererError(mafwError);
439         MafwRendererPolicy *policy = self->rendererPolicy();
440         Q_ASSERT(policy);
441         if( policy )
442         {
443             policy->release();
444             qDebug() << __PRETTY_FUNCTION__ << "Resources released because of error" << mafwError.code();
445         }
446         else
447         {
448             qWarning() << __PRETTY_FUNCTION__ << "No policy exists!";
449         }
450
451         self->doStop();
452     }
453     else if (code != WORKER_ERROR_CANNOT_SET_POSITION && code != WORKER_ERROR_DRM_NOT_ALLOWED) //Try next uri
454     {
455         //using singleshot gives worker/gstreamer time to do
456         //cleanup before calling worker_play
457         if (self->m_playlistFileUtil->getUriList().isEmpty())
458         {
459           //delayed call to playNextURIFromPlaylist used to give the parser
460           //enough time to read new items from the playlist
461           self->m_playlistFileUtil->setPendingError(mafwError);
462
463           self->m_playlistNextTimer.start(1000);
464         }
465         else
466         {
467             self->m_playlistNextTimer.start(0);
468         }
469     }
470     else
471     {
472         Q_EMIT self->rendererError(mafwError);
473     }
474 }
475
476 /********************************************************************
477  * MafwGstRenderer::propertyCallback
478  ********************************************************************/
479 void MafwGstRenderer::propertyCallback(MafwGstRendererWorker *worker,
480                                        gpointer owner,
481                                        gint id,
482                                        GValue *value)
483 {
484
485     QString name;
486
487     Q_UNUSED(worker);
488
489     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
490
491     switch (id)
492     {
493         case WORKER_PROPERTY_AUTOPAINT:
494             name = PROPERTY_AUTOPAINT;
495             break;
496         case WORKER_PROPERTY_COLORKEY:
497             name = PROPERTY_COLORKEY;
498             break;
499         case WORKER_PROPERTY_XID:
500             name = PROPERTY_XID;
501             break;
502         case WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE:
503             name = PROPERTY_CURRENT_FRAME_ON_PAUSE;
504             break;
505         case WORKER_PROPERTY_PLAYBACK_SPEED:
506             name = PROPERTY_PLAYBACK_SPEED;
507             break;
508         case WORKER_PROPERTY_FORCE_ASPECT_RATIO:
509             name = PROPERTY_FORCE_ASPECT_RATIO;
510             break;
511         case WORKER_PROPERTY_RENDER_RECTANGLE:
512             name = PROPERTY_RENDER_RECT;
513             break;
514         default:
515             qWarning() << __PRETTY_FUNCTION__ << "unknown property id:" << id;
516             return;
517             break;
518     }
519
520     qDebug() << __PRETTY_FUNCTION__ << name;
521
522     QVariant result = getValue(value);
523
524     if (result.isValid())
525     {
526         Q_EMIT self->mafwPropertyChanged(name, result);
527     }
528
529 }
530
531 /********************************************************************
532  * MafwGstRenderer::blankingControlCallback
533  ********************************************************************/
534 void MafwGstRenderer::blankingControlCallback(MafwGstRendererWorker *worker,
535                                    gpointer owner, gboolean prohibit)
536 {
537
538     Q_UNUSED(worker);
539     qDebug() << __PRETTY_FUNCTION__ << prohibit;
540     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
541     if(self->m_videoRoute->value() == VIDEO_ROUTE_TV_OUT ||
542        self->m_videoRoute->value() == VIDEO_ROUTE_BUILT_IN_AND_TV_OUT)
543     {
544         prohibit = false;
545     }
546
547     if( prohibit )
548     {
549         self->m_blankingPreventer->blankingProhibit();
550     }
551     else
552     {
553         self->m_blankingPreventer->blankingAllow();
554     }
555 }
556
557 /********************************************************************
558  * MafwGstRenderer::screenshotCallback
559  ********************************************************************/
560 void MafwGstRenderer::screenshotCallback(MafwGstRendererWorker *worker,
561                                          gpointer owner, GstBuffer *buffer,
562                                          const char *filename, gboolean cancel)
563 {
564     qDebug() << __PRETTY_FUNCTION__;
565     MafwGstRenderer *self = static_cast<MafwGstRenderer*>(owner);
566
567     if(cancel)
568     {
569         self->m_screenshot->cancelPauseFrame();
570     }
571     else
572     {
573         if(!self->m_screenshot->savePauseFrame(buffer, filename))
574         {
575             worker->taking_screenshot = FALSE;
576             qCritical() << "Failed to create pause frame pipeline";
577         }
578     }
579 }
580
581 /********************************************************************
582  * MafwGstRenderer::getValue
583  ********************************************************************/
584 QVariant MafwGstRenderer::getValue(const GValue *v)
585 {
586
587     QVariant result;
588
589     if (G_IS_VALUE(v))
590     {
591         if (G_VALUE_TYPE(v) == G_TYPE_STRING)
592         {
593             // tags from GStreamer are always expected to be UTF-8
594             result = QVariant(QString::fromUtf8(g_value_get_string(v)));
595         }
596         else if (G_VALUE_TYPE(v) == G_TYPE_UINT)
597         {
598             result = QVariant(g_value_get_uint(v));
599         }
600         else if (G_VALUE_TYPE(v) == G_TYPE_INT)
601         {
602             result = QVariant(g_value_get_int(v));
603         }
604         else if (G_VALUE_TYPE(v) == G_TYPE_BOOLEAN)
605         {
606             result = QVariant::fromValue<bool>(g_value_get_boolean(v));
607         }
608         else if (G_VALUE_TYPE(v) == G_TYPE_DOUBLE)
609         {
610             result = QVariant(g_value_get_double(v));
611         }
612         else if (G_VALUE_TYPE(v) == G_TYPE_INT64)
613         {
614             result = QVariant(g_value_get_int64(v));
615         }
616         else if (G_VALUE_TYPE(v) == G_TYPE_FLOAT)
617         {
618             result = QVariant(g_value_get_float(v));
619         }
620         else if (G_VALUE_TYPE(v) == G_TYPE_VALUE_ARRAY)
621         {
622             GValueArray *vals = static_cast<GValueArray*>(g_value_get_boxed(v));
623             if( vals->n_values == 4 )
624             {
625                result = QString("%1,%2,%3,%4")
626                        .arg(g_value_get_int(g_value_array_get_nth(vals, 0)))
627                        .arg(g_value_get_int(g_value_array_get_nth(vals, 1)))
628                        .arg(g_value_get_int(g_value_array_get_nth(vals, 2)))
629                        .arg(g_value_get_int(g_value_array_get_nth(vals, 3)));
630             }
631             else
632             {
633                 qWarning() << "Invalid rect values received? Size:" << vals->n_values;
634             }
635
636         }
637         else
638         {
639             qWarning() << "unsupported value g_type";
640         }
641     }
642
643     return result;
644
645 }
646
647 /********************************************************************
648  * MafwGstRenderer::metadataCallback
649  ********************************************************************/
650 void MafwGstRenderer::metadataCallback(MafwGstRendererWorker *worker,
651                                        gpointer owner,
652                                        gint key,
653                                        GType type,
654                                        gpointer value)
655 {
656
657     QList<QVariant> results;
658
659     Q_UNUSED(worker);
660
661     qDebug() << __PRETTY_FUNCTION__ << key << metadataMap().value(key);
662
663     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
664
665     if (metadataMap().contains(key))
666     {
667         if (type == G_TYPE_VALUE_ARRAY)
668         {
669             uint i;
670             GValueArray *vals = static_cast<GValueArray*>(value);
671             for (i = 0; i < vals->n_values; i++)
672             {
673                 QVariant v = getValue(g_value_array_get_nth(vals, i));
674                 if (v.isValid())
675                 {
676                     results << v;
677                 }
678             }
679
680             QString mafwMetadataKey = metadataMap().value(key);
681
682             self->appendRelatedMetadata(mafwMetadataKey, &results);
683
684             Q_EMIT self->metadataChanged(mafwMetadataKey, results);
685             self->m_currentMetaData.insert(mafwMetadataKey, results);
686         }
687         else
688         {
689             qWarning() << "unsupported g_type";
690         }
691     }
692     else
693     {
694         qWarning() << "unknown metadata key:" << key;
695     }
696 }
697
698 /********************************************************************
699  * MafwGstRenderer::appendRelatedMetadata
700  ********************************************************************/
701 void MafwGstRenderer::appendRelatedMetadata(const QString key, QList<QVariant>* results)
702 {
703     if(key == MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI)
704     {
705         gint position = mafw_gst_renderer_worker_get_position(m_worker);
706         if(position < 0)
707         {
708             position = 0;
709         }
710
711         QUrl uri = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
712         *results << uri.toEncoded().constData();
713         *results << QVariant(position);
714     }
715 }
716
717 //
718 // QMafw renderer interface implementation
719 //
720
721 /********************************************************************
722  * MafwGstRenderer::doPlay
723  ********************************************************************/
724 void MafwGstRenderer::doPlay(const MafwContent& content)
725 {
726     Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!");
727     Q_UNUSED(content);
728 }
729
730 /********************************************************************
731  * MafwGstRenderer::doPlay
732  ********************************************************************/
733 void MafwGstRenderer::doPlay(const MafwMediaInfo& mediaInfo)
734 {
735     //Preserve m_currentContent for keeping usage count up if the same item is
736     //played again.
737     if(mediaInfo.uuid().isEmpty() ||
738         mediaInfo.uuid() != m_currentContent.uuid())
739     {
740         m_currentContent = mediaInfo;
741     }
742     m_playingItem = MafwBasicRenderer::CurrentUri;
743     m_currentMetaData.clear();
744
745     const QUrl url = mediaInfo.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
746     qDebug() << __PRETTY_FUNCTION__ << url.toEncoded();
747
748     m_haltState.clear();
749
750     if( !m_mmcMonitor->isMounted() && url.toString().startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
751     {
752         qDebug() << "MafwGstRenderer::doPlay: Can't play MMC not mounted";
753         MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded());
754         Q_EMIT rendererError(mafwError);
755         return;
756     }
757
758     m_playedPlaylistItem = false;
759     m_playingPlaylistFile = false;
760     if (m_unsupportedTypeError)
761     {
762         g_error_free(m_unsupportedTypeError);
763         m_unsupportedTypeError = 0;
764     }
765
766     if( url.isValid() )
767     {
768         stopTimers();
769
770         // Set correct value for the Dolby Headphones Mobile effect plugin
771         set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
772         set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
773         set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
774         set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
775         set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
776         set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
777
778         const QString& mimeType = mediaInfo.firstMetaData(MAFW_METADATA_KEY_MIME).toString();
779         if (mimeType == "audio/x-scpls" )
780         {
781             if (!m_playlistFileUtil)
782             {
783                 m_playlistFileUtil = new MafwGstRendererPlaylistFileUtility(this);
784                 connect(m_playlistFileUtil, SIGNAL(firstItemParsed()),
785                         this, SLOT(startPlayingPlaylistFile()), Qt::QueuedConnection);
786                 connect(m_playlistFileUtil, SIGNAL(parsingReady(bool)),
787                         this, SLOT(handlePlaylistFileParsingErrors(bool)), Qt::QueuedConnection);
788             }
789             m_playlistFileUtil->parsePlaylistFile(url);
790
791         }
792         else
793         {
794             playURI(url.toEncoded());
795
796             QVariant startPosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_START_POSITION);
797             if( startPosition.isValid() )
798             {
799                 uint pos = startPosition.toUInt();
800                 qDebug() << "Immediate seek requested to: " << pos;
801                 doSeek(pos, MafwRenderer::SeekAbsolute);
802             }
803             else
804             {
805                 QVariant pausePosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_PAUSED_POSITION);
806                 if( pausePosition.isValid() )
807                 {
808                     uint position = pausePosition.toUInt();
809                     qDebug() << "Immediate pause requested at:" << position;
810                     mafw_gst_renderer_worker_pause_at(m_worker, position);
811                 }
812             }
813         }
814     }
815     else
816     {
817         MafwError mafwError(MafwError::RendererError_InvalidURI, url.toString());
818         Q_EMIT rendererError(mafwError);
819         doStop();
820     }
821 }
822
823 /********************************************************************
824  * MafwGstRenderer::doStop
825  ********************************************************************/
826 void MafwGstRenderer::doStop()
827 {
828     qDebug() << __PRETTY_FUNCTION__;
829
830     mafw_gst_renderer_worker_stop(m_worker);
831     m_currentState = MafwRenderer::Stopped;
832     m_playingItem = MafwBasicRenderer::UnknownUri;
833
834     m_haltState.clear();
835
836     stopTimers();
837     Q_EMIT rendererStopped();
838 }
839
840 /********************************************************************
841  * MafwGstRenderer::doPause
842  ********************************************************************/
843 void MafwGstRenderer::doPause()
844 {
845     qDebug() << __PRETTY_FUNCTION__;
846
847     if( m_haltState.isSet() && m_haltState.state() == MafwRenderer::Playing )
848     {
849         m_haltState.setState(MafwRenderer::Paused);
850         m_currentState = MafwRenderer::Paused;
851         Q_EMIT rendererPaused();
852     }
853     else
854     {
855         mafw_gst_renderer_worker_pause(m_worker);
856     }
857 }
858
859 /********************************************************************
860  * MafwGstRenderer::doResume
861  ********************************************************************/
862 void MafwGstRenderer::doResume()
863 {
864     qDebug() << __PRETTY_FUNCTION__;
865
866     if( m_currentState == MafwRenderer::Paused && m_haltState.isSet() && m_haltState.state() == MafwRenderer::Paused )
867     {
868         mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData());
869         m_currentState = MafwRenderer::Paused;
870         if( m_haltState.position() > 0 )
871         {
872             doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute);
873         }
874     }
875     else
876     {
877         mafw_gst_renderer_worker_resume(m_worker);
878     }
879
880     if( m_haltState.isSet() )
881     {
882         m_haltState.clear();
883     }
884 }
885
886 /********************************************************************
887  * MafwGstRenderer::doSeek
888  ********************************************************************/
889 void MafwGstRenderer::doSeek(int position, MafwRenderer::SeekMode seekMode)
890 {
891     GError *error = 0;
892
893     qDebug() << __PRETTY_FUNCTION__;
894
895     GstSeekType seekType;
896     if( MafwRenderer::SeekAbsolute == seekMode )
897     {
898         seekType = GST_SEEK_TYPE_SET;
899     }
900     else if( MafwRenderer::SeekRelative == seekMode )
901     {
902         seekType = GST_SEEK_TYPE_CUR;
903     }
904     else
905     {
906         qCritical("MafwGstRenderer: Invalid seek operation requested!");
907         return;
908     }
909
910     mafw_gst_renderer_worker_set_position(m_worker,
911                                           seekType,
912                                           position,
913                                           &error);
914
915     if (error)
916     {
917         MafwError mafwError;
918         mafwError.setCode(MafwError::RendererError_CannotSetPosition);
919         mafwError.setMessage(error->message);
920         Q_EMIT rendererError(mafwError);
921         g_error_free(error);
922     }
923
924 }
925
926 /********************************************************************
927  * MafwGstRenderer::doNextHint
928  ********************************************************************/
929 bool MafwGstRenderer::doNextHint(const MafwContent& content)
930 {
931     Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!");
932     Q_UNUSED(content);
933     return false;
934 }
935
936 /********************************************************************
937  * MafwGstRenderer::doNextHint
938  ********************************************************************/
939 bool MafwGstRenderer::doNextHint(const MafwMediaInfo& mediaInfo)
940 {
941     qDebug() << __PRETTY_FUNCTION__;
942
943     m_nextContent = mediaInfo;
944     // If we have already reached EOS trigger a new play attempt because the
945     // next content was signalled too late. However, if we have gone from playing
946     // state we can not continue, because we have released resources.
947     if (m_worker->eos && (m_currentState == MafwRenderer::Playing))
948     {
949         QTimer::singleShot(0, this, SLOT(playNext()));
950     }
951     return true;
952 }
953
954 /********************************************************************
955  * MafwGstRenderer::getPosition
956  ********************************************************************/
957 bool MafwGstRenderer::getPosition(QObject* resultsReceiver,
958                                   const char* resultsMember)
959 {
960
961     Q_EMIT signalGetPosition(resultsReceiver,
962                            resultsMember);
963
964     return true;
965
966 }
967
968 /********************************************************************
969  * MafwGstRenderer::setMafwProperty
970  ********************************************************************/
971 bool MafwGstRenderer::setMafwProperty(const QString& name,
972                                       const QVariant& value)
973 {
974     qDebug() << __PRETTY_FUNCTION__ << name;
975
976     bool success = true;
977     if (name == PROPERTY_VOLUME)
978     {
979         if (!m_volume)
980         {
981             m_volume = new MafwGstRendererVolume();
982             connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint)));
983         }
984         success = m_volume->setVolume(value.toUInt());
985     }
986     else if (name == PROPERTY_DOLBY_STATE_MUSIC)
987     {
988         success = m_dolby->setMusicDolbyState(value.toUInt());
989         if (success)
990         {
991             set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
992         }
993     }
994     else if (name == PROPERTY_DOLBY_STATE_MUSIC_ROOM)
995     {
996         success = m_dolby->setMusicDolbyState(value.toInt());
997         if (success)
998         {
999             set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
1000         }
1001     }
1002     else if (name == PROPERTY_DOLBY_STATE_MUSIC_COLOR)
1003     {
1004         success = m_dolby->setMusicDolbyState(value.toInt());
1005         if (success)
1006         {
1007             set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
1008         }
1009     }
1010     else if (name == PROPERTY_DOLBY_STATE_VIDEO)
1011     {
1012         success = m_dolby->setVideoDolbyState(value.toUInt());
1013         if (success)
1014         {
1015             set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
1016         }
1017     }
1018     else if (name == PROPERTY_DOLBY_STATE_VIDEO_ROOM)
1019     {
1020         success = m_dolby->setVideoDolbyState(value.toInt());
1021         if (success)
1022         {
1023             set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
1024         }
1025     }
1026     else if (name == PROPERTY_DOLBY_STATE_VIDEO_COLOR)
1027     {
1028         success = m_dolby->setVideoDolbyState(value.toInt());
1029         if (success)
1030         {
1031             set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
1032         }
1033     }
1034     else if (name == PROPERTY_AUTOPAINT)
1035     {
1036         mafw_gst_renderer_worker_set_autopaint(m_worker, value.toBool());
1037     }
1038     else if (name == PROPERTY_XID)
1039     {
1040         if (rendererPolicy())
1041         {
1042             rendererPolicy()->setDefaultResources(MafwRendererPolicy::Audio | MafwRendererPolicy::Video);
1043         }
1044         else
1045         {
1046             qCritical() << __PRETTY_FUNCTION__ << "unable to append video to default resources";
1047         }
1048
1049         mafw_gst_renderer_worker_set_xid(m_worker, value.toUInt());
1050     }
1051     else if (name == PROPERTY_CURRENT_FRAME_ON_PAUSE)
1052     {
1053         mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker,
1054                                                             value.toBool());
1055     }
1056     else if (name == PROPERTY_PLAYBACK_SPEED)
1057     {
1058         success = mafw_gst_renderer_worker_set_playback_speed(m_worker, value.toFloat());
1059     }
1060     else if (name == PROPERTY_FORCE_ASPECT_RATIO)
1061     {
1062         mafw_gst_renderer_worker_set_force_aspect_ratio(m_worker, value.toBool());
1063     }
1064     else if( name == PROPERTY_RENDER_RECT )
1065     {
1066         if( value.type() != QVariant::String )
1067         {
1068             qWarning() << "MafwGstRenderer Invalid ("<<PROPERTY_RENDER_RECT<<") value received:" << value;
1069         }
1070         else
1071         {
1072             QString str = value.toString();
1073             QStringList list = str.split(",");
1074             bool success = true;
1075             int array[4]; // x, y, width, height
1076             if( list.size() != 4 )
1077             {
1078                 success=false;
1079             }
1080             else
1081             {
1082                 for( int i = 0; i < 4 && success; ++i )
1083                 {
1084                     QString str = list.at(i);
1085                     array[i] = str.toInt(&success);
1086                 }
1087             }
1088             if( !success )
1089             {
1090                 qWarning() << "Invalid property (" << name << ") value received: " << value;
1091             }
1092             else
1093             {
1094                 render_rectangle rect = {array[0], array[1], array[2], array[3]};
1095                 mafw_gst_renderer_worker_set_render_rectangle(m_worker, &rect);
1096             }
1097         }
1098     }
1099     else
1100     {
1101         success = MafwBasicRenderer::setMafwProperty(name, value);
1102     }
1103
1104     if (!success)
1105     {
1106         MafwError err;
1107         err.setCode(MafwError::RendererError_CannotSetProperty);
1108         Q_EMIT rendererError(err);
1109     }
1110
1111     return success;
1112 }
1113
1114 /********************************************************************
1115  * MafwGstRenderer::mafwProperty
1116  ********************************************************************/
1117 bool MafwGstRenderer::mafwProperty(QString& name,
1118                                    QObject* receiver,
1119                                    const char* member)
1120 {
1121
1122     qDebug() << __PRETTY_FUNCTION__;
1123
1124     Q_EMIT signalMafwProperty(name, receiver, member);
1125
1126     return true;
1127
1128 }
1129
1130 /********************************************************************
1131  * MafwGstRenderer::mafwProperty
1132  ********************************************************************/
1133 bool MafwGstRenderer::getCurrentMediaInfo(QObject* receiver,
1134                                    const char* member,
1135                                    const QString& metadataKey)
1136 {
1137     qDebug() << __PRETTY_FUNCTION__;
1138
1139     if(m_currentState == MafwRenderer::Playing || m_currentState == MafwRenderer::Paused)
1140     {
1141         Q_EMIT signalGetCurrentMediaInfo(receiver, member, metadataKey);
1142     }
1143     else
1144     {
1145         return false;
1146     }
1147
1148     return true;
1149 }
1150
1151 /********************************************************************
1152  * MafwGstRenderer::pauseCallback
1153  ********************************************************************/
1154 void MafwGstRenderer::pauseCallback(MafwGstRendererWorker *worker,
1155                                     gpointer owner)
1156 {
1157
1158     Q_UNUSED(worker);
1159
1160     qDebug() << __PRETTY_FUNCTION__;
1161
1162     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
1163
1164     self->m_playedStampTimer.stop();
1165
1166     Q_EMIT self->rendererPaused();
1167
1168     //are we staying in paused after stopped state (pauseAt requested)
1169     //we'll need to inform the MafwBasicRenderer to give the next item to play after current
1170     //if so start fetching next also in this case
1171     if( self->m_currentState == MafwRenderer::Stopped )
1172     {
1173         Q_EMIT self->rendererReadyForNext(self->m_playingItem);
1174     }
1175
1176     self->m_currentState = MafwRenderer::Paused;
1177 }
1178
1179 /********************************************************************
1180  * MafwGstRenderer::eosCallback
1181  * Renderer does not stop here, because there could be set next item to play.
1182  ********************************************************************/
1183 void MafwGstRenderer::eosCallback(MafwGstRendererWorker *worker,
1184                                   gpointer owner)
1185 {
1186
1187     Q_UNUSED(worker);
1188
1189     qDebug() << __PRETTY_FUNCTION__;
1190
1191     MafwGstRenderer* self = static_cast<MafwGstRenderer*>(owner);
1192
1193     //this is very special case to restart playing streams of undetermined duration and nonseekable
1194     if( mafw_gst_renderer_worker_get_streaming(worker)
1195         && mafw_gst_renderer_worker_get_last_known_duration(worker) < 0
1196         && !mafw_gst_renderer_worker_get_seekable(worker) )
1197     {
1198         QTimer::singleShot(0, self, SLOT(restartPlay()));
1199         return;
1200     }
1201
1202     if( self->m_playedStampTimer.isActive() ) // eos before stamped, stamp now
1203     {
1204         self->m_playedStampTimer.stop();
1205         self->slotStamp();
1206     }
1207
1208     if (self->m_playingPlaylistFile) //Try next uri if exists
1209     {
1210         self->m_playlistNextTimer.start(0);
1211     }
1212     else
1213     {
1214         QTimer::singleShot(0, self, SLOT(playNext()));
1215         Q_EMIT self->rendererEos();
1216     }
1217
1218 }
1219
1220 /********************************************************************
1221  * MafwGstRenderer::restartPlay
1222  * Slot to call asynchronously to restart playback (e.g. when internet radio disconnect due to network issues)
1223  ********************************************************************/
1224 void MafwGstRenderer::restartPlay()
1225 {
1226     //only restart if we're still playing
1227     if( m_currentState == MafwRenderer::Playing )
1228     {
1229         doPlay(m_currentContent);
1230     }
1231 }
1232
1233 /********************************************************************
1234  * MafwGstRenderer::readyStateCallback
1235  * Worker informs via this when it is no longer using any resources when paused
1236  ********************************************************************/
1237 void MafwGstRenderer::readyStateCallback(MafwGstRendererWorker *worker, gpointer owner)
1238 {
1239     Q_UNUSED(worker);
1240
1241     MafwGstRenderer *self = static_cast<MafwGstRenderer*>(owner);
1242
1243     if( self->m_currentState != MafwRenderer::Paused )
1244     {
1245         qCritical("MafwGstRenderer: Ready state informed, but not in PAUSED state! Not releasing resources!");
1246         return;
1247     }
1248
1249     MafwRendererPolicy *policy = self->rendererPolicy();
1250     if( policy )
1251     {
1252         policy->release();
1253     }
1254 }
1255
1256 //
1257 //Private implementation
1258 //
1259
1260 /********************************************************************
1261  * MafwGstRenderer::slotGetPosition
1262  ********************************************************************/
1263 void MafwGstRenderer::slotGetPosition(QObject* resultsReceiver,
1264                                       const char* resultsMember)
1265 {
1266     QMetaMethod method;
1267     bool methodFound;
1268     gint pos;
1269
1270     if(m_currentState == MafwRenderer::Stopped)
1271     {
1272         pos = 0;
1273     }
1274     else if( m_haltState.isSet() )
1275     {
1276         pos = m_haltState.position();
1277     }
1278     else
1279     {
1280         /* this returns -1 on failure */
1281         pos = mafw_gst_renderer_worker_get_position(m_worker);
1282     }
1283
1284     if (pos < 0)
1285     {
1286         MafwError err;
1287         err.setCode(MafwError::RendererError_CannotGetPosition);
1288         Q_EMIT rendererError(err);
1289     }
1290     else
1291     {
1292         methodFound = MafwCallbackHelper::getCallbackMethod(resultsReceiver,
1293                                                             resultsMember,
1294                                                             method);
1295
1296         if (!methodFound ||
1297             method.invoke(resultsReceiver, Q_ARG(uint, pos)) == false)
1298         {
1299             qCritical() << "Invoking the get position callback method failed!";
1300         }
1301     }
1302 }
1303
1304 /********************************************************************
1305  * MafwGstRenderer::slotMafwProperty
1306  ********************************************************************/
1307 void MafwGstRenderer::slotMafwProperty(const QString& name,
1308                                        QObject* receiver,
1309                                        const char* member)
1310 {
1311
1312     QVariant prop;
1313     QMetaMethod method;
1314     bool methodFound;
1315
1316     if (name == PROPERTY_VOLUME)
1317     {
1318         if (!m_volume)
1319         {
1320             m_volume = new MafwGstRendererVolume();
1321             connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint)));
1322         }
1323
1324         uint value = m_volume->getVolume();
1325         prop = QVariant(value);
1326     }
1327     else if (name == PROPERTY_DOLBY_STATE_MUSIC)
1328     {
1329         uint value = m_dolby->getMusicDolbyState();
1330         prop = QVariant(value);
1331     }
1332     else if (name == PROPERTY_DOLBY_STATE_VIDEO)
1333     {
1334         uint value = m_dolby->getVideoDolbyState();
1335         prop = QVariant(value);
1336     }
1337     else if (name == PROPERTY_AUTOPAINT)
1338     {
1339         gboolean value;
1340         value = mafw_gst_renderer_worker_get_autopaint(m_worker);
1341         prop = QVariant(value);
1342     }
1343     else if (name == PROPERTY_COLORKEY)
1344     {
1345         gint value;
1346         value = mafw_gst_renderer_worker_get_colorkey(m_worker);
1347         prop = QVariant(value);
1348     }
1349     else if (name == PROPERTY_XID)
1350     {
1351         XID value;
1352         value = mafw_gst_renderer_worker_get_xid(m_worker);
1353         prop = QVariant(static_cast<uint>(value));
1354     }
1355     else if (name == PROPERTY_PLAYBACK_SPEED)
1356     {
1357         gfloat value;
1358         value = mafw_gst_renderer_worker_get_playback_speed(m_worker);
1359         prop = QVariant(value);
1360     }
1361     else if (name == PROPERTY_FORCE_ASPECT_RATIO)
1362     {
1363         gboolean value;
1364         value = mafw_gst_renderer_worker_get_force_aspect_ratio(m_worker);
1365         prop = QVariant(value);
1366     }
1367     else if( name == PROPERTY_RENDER_RECT)
1368     {
1369         const render_rectangle *rect = mafw_gst_renderer_worker_get_render_rectangle(m_worker);
1370         prop = QString("%1,%2,%3,%4")
1371                .arg(rect->x).arg(rect->y).arg(rect->width).arg(rect->height);
1372     }
1373     else
1374     {
1375         qWarning() << "unknown property: " << name;
1376     }
1377
1378     methodFound = MafwCallbackHelper::getCallbackMethod(receiver,
1379                                                         member,
1380                                                         method);
1381
1382     if (!methodFound || method.invoke(receiver,
1383                                       Q_ARG(QString, name),
1384                                       Q_ARG(QVariant, prop)) == false)
1385     {
1386         qCritical() << "Invoking the callback method failed!";
1387     }
1388
1389 }
1390
1391 /********************************************************************
1392  * MafwGstRenderer::slotStamp
1393  ********************************************************************/
1394 void MafwGstRenderer::slotStamp()
1395 {
1396     qDebug() << __PRETTY_FUNCTION__;
1397
1398     QString uid=m_currentContent.uuid();
1399     if( !uid.isEmpty() )
1400     {
1401         // create live node from MAFW object ID. Tracker case only implemented
1402         // here. There definitely should be helper function for this.
1403         const QString TRACKER_SOURCE_UUID = "MafwTrackerSource";
1404         const QString MAFW_UUID_SEPARATOR = "::";
1405
1406         QString source = uid.section(MAFW_UUID_SEPARATOR, 0 , 0);
1407
1408         if ( source == TRACKER_SOURCE_UUID )
1409         {
1410             QString uniqueNodeIdentifier = uid.section(MAFW_UUID_SEPARATOR, 1, 1);
1411             if (uniqueNodeIdentifier.length() > 0)
1412             {
1413                 int counter = m_currentContent.firstMetaData(MAFW_METADATA_KEY_PLAY_COUNT).toInt();
1414                 counter++;
1415                 qDebug() << "MafwGstRenderer::slotStamp counter" << counter;
1416                 m_currentContent.appendMetaData(MAFW_METADATA_KEY_PLAY_COUNT, QList<QVariant>() << QVariant(counter));
1417
1418                 int storedDuration = m_currentContent.firstMetaData(MAFW_METADATA_KEY_DURATION).toInt();
1419                 int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker);
1420                 int stampDuration = -1;
1421                 if( currentDuration >= 0 && storedDuration != currentDuration )
1422                 {
1423                     qDebug() << "Will store new duration:" << currentDuration;
1424                     stampDuration = currentDuration;
1425                     Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList<QVariant>() << stampDuration));
1426                 }
1427
1428                 stampIt(uniqueNodeIdentifier, counter, stampDuration);
1429             }
1430         }
1431     }
1432     else // UUID is unknown
1433     {
1434         const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
1435
1436         if( url.isValid() && url.toString().startsWith("file://") )
1437         {
1438             qDebug() << "MafwGstRenderer::slotStamp query from tracker" << url;
1439
1440             QSparqlQuery query(QString("SELECT ?urn ?usageCount ?duration WHERE { "
1441                                        "?urn nie:url \"%1\". "
1442                                        "OPTIONAL { "
1443                                             "?urn nie:usageCounter ?usageCount. "
1444                                             "?urn nfo:duration ?duration } "
1445                                        "}")
1446                                .arg(url.toEncoded().constData()));
1447
1448             delete m_urnQueryResult;
1449             m_urnQueryResult = m_sparqlConnection->exec(query);
1450             connect(m_urnQueryResult, SIGNAL(finished()),
1451                     this, SLOT(slotStampQueryReady()));
1452         }
1453     }
1454
1455     m_playedStamped=true;
1456 }
1457
1458 /********************************************************************
1459  * MafwGstRenderer::slotStampQueryReady
1460  ********************************************************************/
1461 void MafwGstRenderer::slotStampQueryReady()
1462 {
1463     m_playedStampTryCounter++;
1464     if( !m_urnQueryResult || m_urnQueryResult->hasError() || !m_urnQueryResult->first() )
1465     {
1466         qWarning() << "MafwGstRenderer::slotStampQueryReady: surprising result";
1467         if (!m_playedStampTimer.isActive()
1468             && m_currentState == MafwRenderer::Playing
1469             && m_playedStampTryCounter < PLAYED_STAMP_TRIES)
1470         {
1471             qDebug() << __PRETTY_FUNCTION__ << "restarting timer.";
1472             m_playedStampTimer.start(PLAYED_STAMP_INTERVAL);
1473         }
1474         else
1475         {
1476             qWarning() << __PRETTY_FUNCTION__ << "played stamping didn't succeeded.";
1477             m_playedStamped = false;
1478         }
1479     }
1480     else
1481     {
1482         QString urn = m_urnQueryResult->stringValue(0);
1483         int usageCount = m_urnQueryResult->stringValue(1).toInt();
1484         int storedDuration = m_urnQueryResult->stringValue(2).toInt();
1485
1486         int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker);
1487
1488         int mediaDuration = -1;
1489         if( storedDuration != currentDuration)
1490         {
1491             mediaDuration = currentDuration;
1492             Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList<QVariant>() << mediaDuration));
1493         }
1494
1495         qDebug() << "MafwGstRenderer::slotStampQueryReady" << urn << usageCount << mediaDuration;
1496
1497         stampIt(urn, usageCount+1, mediaDuration);
1498     }
1499
1500
1501     delete m_urnQueryResult;
1502     m_urnQueryResult = 0;
1503 }
1504
1505 /********************************************************************
1506  * MafwGstRenderer::stopTimers
1507  ********************************************************************/
1508 void MafwGstRenderer::stopTimers()
1509 {
1510     m_playlistNextTimer.stop();
1511     if (m_playlistFileUtil)
1512     {
1513         m_playlistFileUtil->takePendingError();
1514     }
1515     m_playedStampTimer.stop();
1516 }
1517
1518 /********************************************************************
1519  * MafwGstRenderer::stampIt
1520  ********************************************************************/
1521 void MafwGstRenderer::stampIt(const QString& urn, int usageCount, int mediaDuration)
1522 {
1523     QString isoDate=QDateTime::currentDateTime().toUTC().toString(Qt::ISODate);
1524     // Add UTC mark "Z" if it is missing (Qt behaviour has changed it seems to add it nowadays)
1525     if( isoDate.length()==ISO_DATE_BASE_LENGTH )
1526     {
1527         isoDate.append("Z");
1528     }
1529
1530     QSparqlQuery update;
1531     if( mediaDuration > -1 )
1532     {
1533         update.setQuery(QString(
1534                                 " DELETE { <%1> nie:contentAccessed ?old } "
1535                                 " WHERE { <%1> nie:contentAccessed ?old } "
1536                                 " DELETE { <%1> nie:usageCounter ?oldu } "
1537                                 " WHERE { <%1> nie:usageCounter ?oldu } "
1538                                 " DELETE { <%1> nfo:duration ?oldd } "
1539                                 " WHERE { <%1> nfo:duration ?oldd } "
1540                                 " INSERT { <%1> nie:contentAccessed \"%2\" . "
1541                                 "         <%1> nie:usageCounter \"%3\" . "
1542                                 "         <%1> nfo:duration \"%4\" }")
1543                                 .arg(urn)
1544                                 .arg(isoDate)
1545                                 .arg(usageCount)
1546                                 .arg(mediaDuration));
1547     }
1548     else
1549     {
1550         update.setQuery(QString(
1551                                 "DELETE { <%1> nie:contentAccessed ?old } "
1552                                 " WHERE { <%1> nie:contentAccessed ?old } "
1553                                 "DELETE { <%1> nie:usageCounter ?oldu } "
1554                                 " WHERE { <%1> nie:usageCounter ?oldu } "
1555                                 "INSERT { <%1> nie:contentAccessed \"%2\" . "
1556                                 "         <%1> nie:usageCounter \"%3\"}")
1557                                 .arg(urn)
1558                                 .arg(isoDate)
1559                                 .arg(usageCount));
1560     }
1561
1562     update.setType(QSparqlQuery::InsertStatement);
1563
1564
1565     delete m_stampItResult;
1566     m_stampItResult = m_sparqlConnection->exec(update);
1567     connect(m_stampItResult, SIGNAL(finished()),
1568             this, SLOT(slotStampItDone()));
1569 }
1570
1571 /********************************************************************
1572  * MafwGstRenderer::slotStampItDone()
1573  ********************************************************************/
1574 void MafwGstRenderer::slotStampItDone()
1575 {
1576     if( !m_stampItResult )
1577     {
1578         qWarning() << "Stampit cannot be done without stmapit result! Invalid slot call?";
1579         return;
1580     }
1581
1582     if( m_stampItResult->hasError() )
1583     {
1584         qWarning() << "Stampit failed:" << m_stampItResult->lastError().message();
1585     }
1586     delete m_stampItResult;
1587     m_stampItResult = 0;
1588 }
1589
1590 /********************************************************************
1591  * MafwGstRenderer::slotRouteChanged()
1592  ********************************************************************/
1593 void MafwGstRenderer::slotRouteChanged()
1594 {
1595     QSet<int> set;
1596     QString route;
1597
1598     // 1. add audio route(s) to the route set
1599     route = m_audioRoute->value().toString();
1600     qDebug() << "audio route is:" << route;
1601     if (audioRouteMap().contains(route))
1602     {
1603         Q_FOREACH (int value, audioRouteMap().value(route))
1604         {
1605             set.insert(value);
1606         }
1607     }
1608     else
1609     {
1610         // TODO: Is it ok to use NULL here?
1611         qWarning() << "adding null route (audio)";
1612         set.insert(WORKER_OUTPUT_NULL);
1613     }
1614
1615     // 2. add video route(s) to the route set
1616     route = m_videoRoute->value().toString();
1617     qDebug() << "video route is:" << route;
1618     if (videoRouteMap().contains(route))
1619     {
1620         Q_FOREACH (int value, videoRouteMap().value(route))
1621         {
1622             set.insert(value);
1623         }
1624     }
1625     else
1626     {
1627         // TODO: Is it ok to use NULL here?
1628         qWarning() << "adding null route (video)";
1629         set.insert(WORKER_OUTPUT_NULL);
1630     }
1631
1632     // 3. finally notify the worker about the current routes
1633     GSList *destinations = NULL;
1634     Q_FOREACH (int value, set)
1635     {
1636         destinations = g_slist_append(destinations, GINT_TO_POINTER(value));
1637     }
1638     mafw_gst_renderer_worker_notify_media_destination(this->m_worker,
1639                                                       destinations);
1640     g_slist_free(destinations);
1641
1642 }
1643
1644 /********************************************************************
1645  * MafwGstRenderer::playURI
1646  ********************************************************************/
1647 void MafwGstRenderer::playURI(const QString& uri)
1648 {
1649     m_playedStamped = false;
1650     m_playedStampTryCounter = 0;
1651
1652     //little hack to get pause-to-play transition to be signalled
1653     //correctly, in case different URI is asked to be played.
1654     //So it's not resume transition
1655     m_currentState = MafwRenderer::Stopped;
1656     mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
1657     m_nextContent = MafwMediaInfo();
1658 }
1659
1660 /********************************************************************
1661  * MafwGstRenderer::startPlayingPlaylistFile
1662  ********************************************************************/
1663 void MafwGstRenderer::startPlayingPlaylistFile()
1664 {
1665     m_playlistNextTimer.stop();
1666     QString uri = QString();
1667     if (m_playlistFileUtil)
1668     {
1669         uri = m_playlistFileUtil->takeFirstUri();
1670         m_playlistFileUtil->takePendingError();
1671     }
1672     else
1673     {
1674         qCritical() << __PRETTY_FUNCTION__ << "playlist file util is NULL!";
1675     }
1676
1677     if (!uri.isEmpty())
1678     {
1679         qDebug() << __PRETTY_FUNCTION__ << uri;
1680
1681         if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
1682         {
1683             qDebug() << "MafwGstRenderer::startPlayingPlaylistFile: Can't play MMC not mounted";
1684             MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri);
1685             Q_EMIT rendererError(mafwError);
1686             return;
1687         }
1688
1689         m_playingPlaylistFile = true;
1690         mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
1691         QList<QVariant> metadataValue;
1692         metadataValue << uri;
1693         Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue);
1694     }
1695     else
1696     {
1697         MafwError err;
1698         err.setCode(MafwError::RendererError_PlaylistParsing);
1699         Q_EMIT rendererError(err);
1700     }
1701 }
1702
1703
1704 /********************************************************************
1705  * MafwGstRenderer::handlePlaylistFileParsingErrors
1706  ********************************************************************/
1707 void MafwGstRenderer::handlePlaylistFileParsingErrors(bool succeeded)
1708 {
1709     qDebug() << __PRETTY_FUNCTION__;
1710
1711     if (!succeeded)
1712     {
1713         if (m_unsupportedTypeError)
1714         {
1715             errorCallback(m_worker, this, m_unsupportedTypeError);
1716             g_error_free(m_unsupportedTypeError);
1717             m_unsupportedTypeError = 0;
1718         }
1719         else
1720         {
1721         MafwError err;
1722         err.setCode(MafwError::RendererError_PlaylistParsing);
1723         Q_EMIT rendererError(err);
1724         }
1725     }
1726     else if (!m_playingPlaylistFile)
1727     {
1728         qDebug() << __PRETTY_FUNCTION__ << "waiting for playlist file items...";
1729         MafwError err;
1730         err.setCode(MafwError::RendererError_NoPlaylist);
1731         m_playlistFileUtil->setPendingError(err);
1732         m_playlistNextTimer.start(1000);
1733     }
1734 }
1735
1736 /********************************************************************
1737  * MafwGstRenderer::playNext
1738  ********************************************************************/
1739 void MafwGstRenderer::playNext()
1740 {
1741     qDebug() << __PRETTY_FUNCTION__;
1742     m_playingPlaylistFile = false;
1743     m_playedPlaylistItem = false;
1744
1745     //Preserve m_currentContent for keeping usage count up if the same item is
1746     //played again.
1747     if( !m_nextContent.uuid().isEmpty() && (m_nextContent.uuid() == m_currentContent.uuid()) )
1748     {
1749         m_nextContent = m_currentContent;
1750     }
1751
1752     const QUrl nextURI = m_nextContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
1753     if( !nextURI.isEmpty() )
1754     {
1755         m_playingItem = MafwBasicRenderer::NextUri;
1756         m_currentContent = m_nextContent;
1757         m_nextContent = MafwMediaInfo();
1758
1759         playURI(nextURI.toEncoded());
1760     }
1761 }
1762
1763 /********************************************************************
1764  * MafwGstRenderer::playNextURIFromPlaylist
1765  ********************************************************************/
1766 void MafwGstRenderer::playNextURIFromPlaylist()
1767 {
1768     qDebug() << __PRETTY_FUNCTION__;
1769     QString uri = m_playlistFileUtil->takeFirstUri();
1770
1771     bool okToPlay=true;
1772     if(uri.isEmpty())
1773     {
1774         okToPlay=false;
1775     }
1776     else if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) )
1777     {
1778         qDebug() << "MafwGstRenderer::playNextURIFromPlaylist: Can't play MMC not mounted";
1779         MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri);
1780         m_playlistFileUtil->setPendingError( mafwError );
1781         okToPlay=false;
1782     }
1783
1784     if (okToPlay)
1785     {
1786         m_playlistFileUtil->takePendingError(); // clear it, we have a new candidate
1787         qDebug() << "Trying next uri: " << uri;
1788         mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData());
1789         QList<QVariant> metadataValue;
1790         metadataValue << uri;
1791         Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue);
1792     }
1793     else
1794     {
1795         m_playingPlaylistFile = false;
1796
1797         if (m_playedPlaylistItem)
1798         {
1799             Q_EMIT rendererEos();
1800         }
1801         m_playedPlaylistItem = false;
1802
1803
1804         MafwError mafwError = m_playlistFileUtil->takePendingError();
1805         if ( mafwError.code() != MafwError::NoError)
1806         {
1807             Q_EMIT rendererError(mafwError);
1808             doStop();
1809             MafwRendererPolicy *policy = rendererPolicy();
1810             if( policy )
1811             {
1812                 policy->release();
1813             }
1814         }
1815     }
1816 }
1817
1818 /********************************************************************
1819  * MafwGstRenderer::slotCurrentMediaInfo
1820  ********************************************************************/
1821 void MafwGstRenderer::slotGetCurrentMediaInfo(QObject* receiver, const char* member, const QString& metadataKey)
1822 {
1823     MafwMediaInfo info(m_currentContent.uuid());
1824
1825     //get all metadata
1826     if(metadataKey.isEmpty())
1827     {
1828         info.setMetaData(m_currentMetaData);
1829     }
1830     //get one item
1831     else
1832     {
1833         QMap<QString, QList<QVariant> >::const_iterator iter = m_currentMetaData.find(metadataKey);
1834         if (iter != m_currentMetaData.end())
1835         {
1836             info.appendMetaData(iter.key(), iter.value());
1837         }
1838     }
1839
1840     sendMediaInfo(info, receiver, member);
1841 }
1842
1843 /********************************************************************
1844  * MafwGstRenderer::handleVolumeChange
1845  ********************************************************************/
1846 void MafwGstRenderer::handleVolumeChange(uint level)
1847 {
1848     qDebug() << "MafwGstRenderer::handleVolumeChange: " << level;
1849     Q_EMIT mafwPropertyChanged(PROPERTY_VOLUME, level);
1850 }
1851
1852 /********************************************************************
1853  * MafwGstRenderer::stopStreaming
1854  ********************************************************************/
1855 void MafwGstRenderer::stopStreaming()
1856 {
1857     qDebug() << __PRETTY_FUNCTION__;
1858     if( mafw_gst_renderer_worker_get_streaming(m_worker) )
1859     {
1860         mafw_gst_renderer_worker_stop(m_worker);
1861         stopTimers();
1862     }
1863
1864     // emit error and stop for real, only if no valid halt state is set
1865     if( !m_haltState.isSet() )
1866     {
1867         doStop();
1868         MafwError error;
1869         error.setCode(MafwError::RendererError_StreamDisconnected);
1870         Q_EMIT rendererError(error);
1871     }
1872 }
1873
1874 /********************************************************************
1875  * MafwGstRenderer::haltStreaming
1876  ********************************************************************/
1877 void MafwGstRenderer::haltStreaming()
1878 {
1879     qDebug() << __PRETTY_FUNCTION__;
1880     if( mafw_gst_renderer_worker_get_streaming(m_worker) )
1881     {
1882         QString uri;
1883         if( m_playlistNextTimer.isActive() )
1884         {
1885             uri = m_playlistFileUtil->takeFirstUri();
1886         }
1887         else
1888         {
1889             uri = mafw_gst_renderer_worker_get_uri(m_worker);
1890         }
1891
1892         int position = -1;
1893         if( mafw_gst_renderer_worker_get_seekable(m_worker) )
1894         {
1895             position = mafw_gst_renderer_worker_get_position(m_worker);
1896             if( position < 0 )
1897             {
1898                 qWarning() << "Cannot resume to correct position after networkchange!";
1899             }
1900         }
1901
1902         //make sure we've uri to resume, the playlist parser may have been trying to parse something
1903         if( uri.length() > 0 )
1904         {
1905             m_haltState = MafwGstRendererHaltState(uri, m_currentState, position);
1906             //valid haltstate constructed, clear the possible pending error in playlist handling
1907             if( m_playlistFileUtil )
1908             {
1909                 m_playlistFileUtil->takePendingError();
1910             }
1911         }
1912         else
1913         {
1914             //just in case
1915             m_haltState.clear();
1916         }
1917
1918         //now actually stop, and depending on the haltstate validity it will also emit error
1919         stopStreaming();
1920     }
1921     else
1922     {
1923         qDebug() << "Not streaming!";
1924     }
1925 }
1926
1927 /********************************************************************
1928  * MafwGstRenderer::continueStreaming
1929  ********************************************************************/
1930 void MafwGstRenderer::continueStreaming()
1931 {
1932     if( mafw_gst_renderer_worker_get_streaming(m_worker) || m_haltState.isSet() )
1933     {
1934         //if not yet halted, do it now
1935         if( !m_haltState.isSet() )
1936         {
1937             haltStreaming();
1938         }
1939
1940         m_playingItem = MafwBasicRenderer::CurrentUri;
1941
1942         if( m_haltState.state() == MafwRenderer::Playing )
1943         {
1944             mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData());
1945             int pausePos = m_haltState.position() > 0 ? m_haltState.position() : 0;
1946
1947             if( m_haltState.state() == MafwRenderer::Playing && pausePos > 0 )
1948             {
1949                 qDebug() << "Resuming streaming from position: " << m_haltState.position();
1950                 doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute);
1951             }
1952             m_haltState.clear();
1953         }
1954     }
1955 }
1956
1957 /********************************************************************
1958  * MafwGstRenderer::handlePropertyChanged
1959  ********************************************************************/
1960 void MafwGstRenderer::handlePropertyChanged(const QString& name,
1961                                             const QVariant& value)
1962 {
1963     // This is a way to check if the policy is on. We need to set the
1964     // PAUSED-to-READY timeout to zero, since we need to be sure that the
1965     // resources really get released by the GStreamer.  It is unfortunate that
1966     // a doPause() and PAUSED state is not enough, e.g. in case of XVideo.
1967     if (name == MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE)
1968     {
1969         guint timeout;
1970         if (value.toBool() == true)
1971         {
1972             timeout = 0;
1973         }
1974         else
1975         {
1976             timeout = MAFW_GST_RENDERER_WORKER_READY_TIMEOUT;
1977         }
1978         mafw_gst_renderer_worker_set_ready_timeout(m_worker, timeout);
1979     }
1980 }
1981
1982 /********************************************************************
1983  * MafwGstRenderer::handleDHMMusicPropertyChanged
1984  ********************************************************************/
1985 void MafwGstRenderer::handleDHMMusicPropertyChanged()
1986 {
1987     if (m_worker)
1988     {
1989         qDebug() << "MafwGstRenderer::handleDHMMusicPropertyChanged set_dolby_music_property" << m_dolby->getMusicDolbyState();
1990         set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState());
1991         set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE);
1992         set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE);
1993     }
1994 }
1995
1996 /********************************************************************
1997  * MafwGstRenderer::handleDHMVideoPropertyChanged
1998  ********************************************************************/
1999 void MafwGstRenderer::handleDHMVideoPropertyChanged()
2000 {
2001     if (m_worker)
2002     {
2003         qDebug() << "MafwGstRenderer::handleDHMVideoPropertyChanged set_dolby_video_property" << m_dolby->getVideoDolbyState();
2004         set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState());
2005         set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE);
2006         set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE);
2007     }
2008 }
2009
2010 /********************************************************************
2011  * MafwGstRenderer::handleScreenshot
2012  ********************************************************************/
2013 void MafwGstRenderer::handleScreenshot(char *location, GError *error)
2014 {
2015     if(!error)
2016     {
2017         QList<QVariant> results;
2018         results << location;
2019
2020         QString mafwMetadataKey = MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI;
2021
2022         appendRelatedMetadata(mafwMetadataKey, &results);
2023         Q_EMIT metadataChanged(mafwMetadataKey, results);
2024         m_currentMetaData.insert(mafwMetadataKey, results);
2025     }
2026     else
2027     {
2028         qCritical() << error->message;
2029     }
2030
2031     m_worker->taking_screenshot = FALSE;
2032 }
2033
2034 /********************************************************************
2035  * MafwGstRenderer::cancelScreenshot
2036  ********************************************************************/
2037 void MafwGstRenderer::cancelScreenshot()
2038 {
2039     if(m_worker)
2040     {
2041         m_worker->taking_screenshot = FALSE;
2042     }
2043 }
2044
2045 /********************************************************************
2046  * MafwGstRenderer::sendMediaInfo
2047  ********************************************************************/
2048 void MafwGstRenderer::sendMediaInfo(const MafwMediaInfo& info, QObject* receiver, const char* member)
2049 {
2050     QMetaMethod method;
2051     bool methodFound;
2052
2053     methodFound = MafwCallbackHelper::getCallbackMethod(receiver, member, method);
2054
2055     if (!methodFound)
2056     {
2057         MafwError err;
2058         err.setCode(MafwError::CallbackSlotNotFound);
2059         Q_EMIT error(err);
2060     }
2061     //actual result callback call is inside this if()
2062     else if( !method.invoke(receiver, Q_ARG(MafwMediaInfo, info)) )
2063     {
2064         MafwError err;
2065         err.setCode(MafwError::CallbackCouldNotInvoke);
2066         Q_EMIT error(err);
2067     }
2068 }
2069
2070 /********************************************************************
2071  * MafwGstRenderer::mmcPreUnmount
2072  ********************************************************************/
2073 void MafwGstRenderer::mmcPreUnmount()
2074 {
2075     qDebug() << "MafwGstRenderer::mmcPreUnmount" << m_currentState;
2076
2077     if( m_currentState!=MafwRenderer::Stopped )
2078     {
2079         const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
2080         if( url.toString().startsWith(MafwMmcMonitor::MMC_URI_PREFIX) )
2081         {
2082             qDebug() << "MafwGstRenderer::mmcPreUnmount: playing from MMC, going to stop";
2083             doStop();
2084             MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded());
2085             Q_EMIT rendererError(mafwError);
2086         }
2087     }
2088 }
2089
2090 /********************************************************************
2091  * MafwGstRenderer::connectNameOwnerChanged
2092  ********************************************************************/
2093 bool MafwGstRenderer::connectNameOwnerChanged()
2094 {
2095     QStringList argumentMatch;
2096     argumentMatch << DBUS_NAME_PCFD;
2097
2098     QDBusConnection connection = QDBusConnection::systemBus();
2099     return connection.connect( QString(),
2100                                  QString(),
2101                                  DBUS_INTERFACE_DBUS,
2102                                  DBUS_SIGNAL_NAME_OWNER_CHANGED,
2103                                  argumentMatch,
2104                                  QString(),
2105                                  this,
2106                                  SLOT(handleContextProviderRemoval(QDBusMessage) ) );
2107 }
2108
2109 /********************************************************************
2110  * MafwGstRenderer::handleContextProviderRemoval
2111  ********************************************************************/
2112 void MafwGstRenderer::handleContextProviderRemoval( const QDBusMessage& message )
2113 {
2114     QList<QVariant> arguments;
2115     QString name;
2116     QString oldName;
2117     QString newName;
2118
2119     arguments= message.arguments();
2120
2121     if ( message.type() == QDBusMessage::SignalMessage && arguments.size()==3 )
2122     {
2123
2124         name = arguments.at(0).toString();
2125         oldName = arguments.at(1).toString();
2126         newName = arguments.at(2).toString();
2127
2128         if ( oldName.length() && newName.length()==0 )
2129         {
2130             qDebug() << "MafwGstRenderer::handleContextProviderRemoval context provider died";
2131
2132             // add null output
2133             GSList *destinations = NULL;
2134             destinations = g_slist_append(destinations,
2135                                           GINT_TO_POINTER(WORKER_OUTPUT_NULL));
2136             mafw_gst_renderer_worker_notify_media_destination(this->m_worker,
2137                                                               destinations);
2138             g_slist_free(destinations);
2139         }
2140     }
2141 }
2142
2143 /********************************************************************
2144  * MafwGstRenderer::handleResolutionError
2145  ********************************************************************/
2146 void MafwGstRenderer::handleResolutionError(MafwError &error)
2147 {
2148     qDebug() << __PRETTY_FUNCTION__;
2149     const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl();
2150     MafwError::Code errorCode = MafwError::RendererError_UnsuppertedType;
2151
2152     if( url.isValid() && url.toString().startsWith("file://") )
2153     {
2154         qDebug() << __PRETTY_FUNCTION__ << url;
2155
2156         QSparqlQuery query(QString("SELECT ?height ?width WHERE { "
2157                                    "?_u nie:url \"%1\" ."
2158                                    "?_u nfo:height ?height . "
2159                                    "?_u nfo:width ?width }")
2160                            .arg(QString(url.toEncoded())));
2161
2162         QSparqlResult *result = m_sparqlConnection->syncExec(query);
2163
2164         if( result->hasError() )
2165         {
2166             qWarning() << __PRETTY_FUNCTION__ << " surprising result";
2167             qWarning() << result->lastError().message();
2168         }
2169         else if( result->first() )
2170         {
2171             int height = result->stringValue(0).toInt();
2172             int width = result->stringValue(1).toInt();
2173
2174             if (height > MAX_SUPPORTED_HEIGHT || width > MAX_SUPPORTED_WIDTH)
2175             {
2176                 errorCode = MafwError::RendererError_UnsupportedResolution;
2177             }
2178         }
2179         delete result;
2180     }
2181     error.setCode(errorCode);
2182 }
2183
2184 /********************************************************************
2185  * MafwGstRenderer::setConfiguration
2186  ********************************************************************/
2187 void MafwGstRenderer::setConfiguration(QSettings *settings)
2188 {
2189     //if no settings use "factory" configuration
2190     if( !settings )
2191     {
2192         return;
2193     }
2194
2195     configuration *defaultconfig = mafw_gst_renderer_worker_create_default_configuration(m_worker);
2196
2197     //pipeline settings
2198     settings->beginGroup("pipeline");
2199     QVariant value = readSettingsValue(settings, "audio-sink", defaultconfig->asink);
2200     qFree(defaultconfig->asink);
2201     defaultconfig->asink = g_strdup(value.toString().toAscii());
2202
2203     value = readSettingsValue(settings, "video-sink", defaultconfig->vsink);
2204     qFree(defaultconfig->vsink);
2205     defaultconfig->vsink = g_strdup(value.toString().toAscii());
2206
2207     value = readSettingsValue(settings, "flags", defaultconfig->flags);
2208     defaultconfig->flags = value.toInt();
2209
2210     value = readSettingsValue(settings, "use_dhmmixer", defaultconfig->use_dhmmixer);
2211     defaultconfig->use_dhmmixer = value.toBool();
2212
2213     value = readSettingsValue(settings, "buffer-time", defaultconfig->buffer_time);
2214     defaultconfig->buffer_time = value.toULongLong();
2215
2216     value = readSettingsValue(settings, "latency-time", defaultconfig->latency_time);
2217     defaultconfig->latency_time = value.toULongLong();
2218
2219     value = readSettingsValue(settings, "autoload_subtitles", defaultconfig->autoload_subtitles);
2220     defaultconfig->autoload_subtitles = value.toBool();
2221
2222     value = readSettingsValue(settings, "subtitle_encoding", defaultconfig->subtitle_encoding);
2223     qFree(defaultconfig->subtitle_encoding);
2224     defaultconfig->subtitle_encoding = g_strdup(value.toString().toAscii());
2225
2226     value = readSettingsValue(settings, "subtitle_font", defaultconfig->subtitle_font);
2227     qFree(defaultconfig->subtitle_font);
2228     defaultconfig->subtitle_font = g_strdup(value.toString().toAscii());
2229     settings->endGroup();
2230
2231     //timers
2232     settings->beginGroup("timers");
2233     value = readSettingsValue(settings, "pause-frame", defaultconfig->milliseconds_to_pause_frame);
2234     defaultconfig->milliseconds_to_pause_frame = value.toUInt();
2235
2236     value = readSettingsValue(settings, "pause-to-ready", defaultconfig->seconds_to_pause_to_ready);
2237     defaultconfig->seconds_to_pause_to_ready = value.toUInt();
2238     settings->endGroup();
2239
2240     //dhmmixer
2241     settings->beginGroup("dhmmixer");
2242     value = readSettingsValue(settings, "dhm-music-surround", defaultconfig->mobile_surround_music.state);
2243     defaultconfig->mobile_surround_music.state = value.toUInt();
2244
2245     value = readSettingsValue(settings, "dhm-music-color", defaultconfig->mobile_surround_music.color);
2246     defaultconfig->mobile_surround_music.color = value.toInt();
2247
2248     value = readSettingsValue(settings, "dhm-music-room-size", defaultconfig->mobile_surround_music.room);
2249     defaultconfig->mobile_surround_music.room = value.toInt();
2250
2251     value = readSettingsValue(settings, "dhm-video-surround", defaultconfig->mobile_surround_video.state);
2252     defaultconfig->mobile_surround_video.state = value.toUInt();
2253
2254     value = readSettingsValue(settings, "dhm-video-color", defaultconfig->mobile_surround_video.color);
2255     defaultconfig->mobile_surround_video.color = value.toInt();
2256
2257     value = readSettingsValue(settings, "dhm-video-room-size", defaultconfig->mobile_surround_video.room);
2258     defaultconfig->mobile_surround_video.room = value.toInt();
2259     settings->endGroup();
2260
2261     mafw_gst_renderer_worker_set_configuration(m_worker, defaultconfig);
2262 }
2263
2264 /********************************************************************
2265  * MafwGstRenderer::readSettingsValue
2266  ********************************************************************/
2267 QVariant MafwGstRenderer::readSettingsValue(QSettings *settings,
2268                                             const QString &valueName,
2269                                             const QVariant &defaultValue) const
2270 {
2271     QVariant value = settings->value(valueName, defaultValue);
2272     if( !settings->contains(valueName) )
2273     {
2274         qWarning() << "No value for: (" << valueName << ") in configuration file! Using factory default";
2275     }
2276     return value;
2277 }
2278
2279 /********************************************************************
2280  * MafwGstRenderer::errorMap
2281  ********************************************************************/
2282 const QHash<int, MafwError::Code>& MafwGstRenderer::errorMap()
2283 {
2284
2285     static QHash<int, MafwError::Code> map;
2286
2287     if (map.isEmpty())
2288     {
2289         /* initialize error map */
2290         map[WORKER_ERROR_PLAYBACK] =
2291             MafwError::RendererError_Playback;
2292         map[WORKER_ERROR_VIDEO_CODEC_NOT_FOUND] =
2293             MafwError::RendererError_VideoCodeNotFound;
2294         map[WORKER_ERROR_AUDIO_CODEC_NOT_FOUND] =
2295             MafwError::RendererError_AudioCodecNotFound;
2296         map[WORKER_ERROR_CODEC_NOT_FOUND] =
2297             MafwError::RendererError_CodecNotFound;
2298         map[WORKER_ERROR_UNSUPPORTED_TYPE] =
2299             MafwError::RendererError_UnsuppertedType;
2300         map[WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE] =
2301             MafwError::RendererError_UnsuppertedType;
2302         map[WORKER_ERROR_UNABLE_TO_PERFORM] =
2303             MafwError::RendererError_UnableToPerform;
2304         map[WORKER_ERROR_CANNOT_SET_POSITION] =
2305             MafwError::RendererError_CannotSetPosition;
2306         map[WORKER_ERROR_PLAYLIST_PARSING] =
2307             MafwError::RendererError_PlaylistParsing;
2308         map[WORKER_ERROR_DRM_NO_LICENSE] =
2309             MafwError::RendererError_DRMNoLicense;
2310         map[WORKER_ERROR_DRM_NOT_ALLOWED] =
2311             MafwError::RendererError_DRMNotAllowed;
2312         map[WORKER_ERROR_DRM_OTHER] =
2313             MafwError::RendererError_DRMOther;
2314         map[WORKER_ERROR_STREAM_DISCONNECTED] =
2315             MafwError::RendererError_StreamDisconnected;
2316         map[WORKER_ERROR_INVALID_URI] =
2317             MafwError::RendererError_InvalidURI;
2318         map[WORKER_ERROR_MEDIA_NOT_FOUND] =
2319             MafwError::RendererError_MediaNotFound;
2320         map[WORKER_ERROR_CORRUPTED_FILE] =
2321             MafwError::RendererError_CorruptedFile;
2322         map[WORKER_ERROR_TYPE_NOT_AVAILABLE] =
2323             MafwError::RendererError_TypeNotAvailable;
2324     }
2325
2326     return map;
2327
2328 }
2329
2330 /********************************************************************
2331  * MafwGstRenderer::metadataMap
2332  ********************************************************************/
2333 const QHash<int, QString>& MafwGstRenderer::metadataMap()
2334 {
2335
2336     static QHash<int, QString> map;
2337
2338     if (map.isEmpty())
2339     {
2340         /* initialize metadata key map */
2341         map[WORKER_METADATA_KEY_TITLE] =
2342             MAFW_METADATA_KEY_TITLE;
2343         map[WORKER_METADATA_KEY_ARTIST] =
2344             MAFW_METADATA_KEY_ARTIST;
2345         map[WORKER_METADATA_KEY_AUDIO_CODEC] =
2346             MAFW_METADATA_KEY_AUDIO_CODEC;
2347         map[WORKER_METADATA_KEY_VIDEO_CODEC] =
2348             MAFW_METADATA_KEY_VIDEO_CODEC;
2349         map[WORKER_METADATA_KEY_BITRATE] =
2350             MAFW_METADATA_KEY_BITRATE;
2351         map[WORKER_METADATA_KEY_ENCODING] =
2352             MAFW_METADATA_KEY_ENCODING;
2353         map[WORKER_METADATA_KEY_ALBUM] =
2354             MAFW_METADATA_KEY_ALBUM;
2355         map[WORKER_METADATA_KEY_GENRE] =
2356             MAFW_METADATA_KEY_GENRE;
2357         map[WORKER_METADATA_KEY_TRACK] =
2358             MAFW_METADATA_KEY_TRACK;
2359         map[WORKER_METADATA_KEY_ORGANIZATION] =
2360             MAFW_METADATA_KEY_ORGANIZATION;
2361         map[WORKER_METADATA_KEY_RENDERER_ART_URI] =
2362             MAFW_METADATA_KEY_RENDERER_ART_URI;
2363         map[WORKER_METADATA_KEY_RES_X] =
2364             MAFW_METADATA_KEY_RES_X;
2365         map[WORKER_METADATA_KEY_RES_Y] =
2366             MAFW_METADATA_KEY_RES_Y;
2367         map[WORKER_METADATA_KEY_VIDEO_FRAMERATE] =
2368             MAFW_METADATA_KEY_VIDEO_FRAMERATE;
2369         map[WORKER_METADATA_KEY_DURATION] =
2370             MAFW_METADATA_KEY_DURATION;
2371         map[WORKER_METADATA_KEY_IS_SEEKABLE] =
2372             MAFW_METADATA_KEY_IS_SEEKABLE;
2373         map[WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI] =
2374             MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI;
2375         map[WORKER_METADATA_KEY_URI] =
2376             MAFW_METADATA_KEY_URI;
2377     }
2378
2379     return map;
2380
2381 }
2382
2383 /********************************************************************
2384  * MafwGstRenderer::audioRouteMap
2385  ********************************************************************/
2386 const QHash<QString, QList<int> >& MafwGstRenderer::audioRouteMap()
2387 {
2388
2389     static QHash<QString, QList<int> > map;
2390
2391     if (map.isEmpty())
2392     {
2393         map[AUDIO_ROUTE_NULL]               = QList<int>() << WORKER_OUTPUT_NULL;
2394         map[AUDIO_ROUTE_IHF]                = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS;
2395         map[AUDIO_ROUTE_FMRADIO]            = QList<int>() << WORKER_OUTPUT_FM_RADIO;
2396         map[AUDIO_ROUTE_IHF_AND_FMRADIO]    = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_FM_RADIO;
2397
2398         // earpiece is intentionally handled as builtdin speaker, well it kinda is
2399         map[AUDIO_ROUTE_EARPIECE]           = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS;
2400         map[AUDIO_ROUTE_EARPIECE_AND_TVOUT] = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT;
2401
2402         map[AUDIO_ROUTE_TV_OUT]             = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
2403         map[AUDIO_ROUTE_IHF_AND_TV_OUT]     = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT;
2404         map[AUDIO_ROUTE_HEADPHONE]          = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
2405         map[AUDIO_ROUTE_HEADSET]            = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK;
2406         map[AUDIO_ROUTE_BTHSP]              = QList<int>() << WORKER_OUTPUT_BLUETOOTH_AUDIO;
2407         map[AUDIO_ROUTE_BTA2DP]             = QList<int>() << WORKER_OUTPUT_BLUETOOTH_AUDIO;
2408         map[AUDIO_ROUTE_IHF_AND_HEADSET]    = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK;
2409         map[AUDIO_ROUTE_IHF_AND_HEADPHONE]  = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK;
2410         map[AUDIO_ROUTE_IHF_AND_BTHSP]      = QList<int>() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_BLUETOOTH_AUDIO;
2411         map[AUDIO_ROUTE_TV_OUT_AND_BTHSP]   = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO;
2412         map[AUDIO_ROUTE_TV_OUT_AND_BTA2DP]  = QList<int>() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO;
2413     }
2414
2415     return map;
2416
2417 }
2418
2419 /********************************************************************
2420  * MafwGstRenderer::videoRouteMap
2421  ********************************************************************/
2422 const QHash<QString, QList<int> >& MafwGstRenderer::videoRouteMap()
2423 {
2424
2425     static QHash<QString, QList<int> > map;
2426
2427     if (map.isEmpty())
2428     {
2429         map[VIDEO_ROUTE_TV_OUT]              = QList<int>() << WORKER_OUTPUT_TVOUT;
2430         map[VIDEO_ROUTE_BUILT_IN]            = QList<int>() << WORKER_OUTPUT_BUILTIN_DISPLAY;
2431         map[VIDEO_ROUTE_BUILT_IN_AND_TV_OUT] = QList<int>() << WORKER_OUTPUT_BUILTIN_DISPLAY << WORKER_OUTPUT_TVOUT;
2432     }
2433
2434     return map;
2435
2436 }
2437