From: Roman Moravcik Date: Thu, 23 Jun 2011 12:02:17 +0000 (+0200) Subject: Added qmafw-gst-subtitles-renderer-0.0.55 for Meego Harmattan 1.2 X-Git-Url: https://vcs.maemo.org/git/?a=commitdiff_plain;h=226d35244df85a27c332d3a3ded1b25b3c7f4951;p=mafwsubrenderer Added qmafw-gst-subtitles-renderer-0.0.55 for Meego Harmattan 1.2 --- diff --git a/qmafw-gst-subtitles-renderer/com.nokia.mafw.context_provider.libqmafw_gst_renderer.context b/qmafw-gst-subtitles-renderer/com.nokia.mafw.context_provider.libqmafw_gst_renderer.context new file mode 100644 index 0000000..e222b15 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/com.nokia.mafw.context_provider.libqmafw_gst_renderer.context @@ -0,0 +1,5 @@ + + + + diff --git a/qmafw-gst-subtitles-renderer/com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin.service b/qmafw-gst-subtitles-renderer/com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin.service new file mode 100644 index 0000000..e323c3a --- /dev/null +++ b/qmafw-gst-subtitles-renderer/com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin +Exec=/usr/bin/qmafw-dbus-wrapper /usr/lib/qmafw-plugin/libqmafw-gst-renderer-plugin.so diff --git a/qmafw-gst-subtitles-renderer/debian/changelog b/qmafw-gst-subtitles-renderer/debian/changelog new file mode 100644 index 0000000..f1b69f7 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/changelog @@ -0,0 +1,1276 @@ +qmafw-gst-subtitles-renderer (0.0.55-1+0m6-1) unstable; urgency=low + + * Added subtitles support. + * Added Subtitles control panel applet. + + -- Roman Moravcik Wed, 22 Jun 2011 08:48:29 +0200 + +qmafw-gst-renderer (0.0.55-1+0m6) unstable; urgency=low + + * This entry has been added by BIFH queue processor + version has been changed to 0.0.55-1+0m6 + + -- BIFH Bot Mon, 23 May 2011 20:10:36 +0300 + +qmafw-gst-renderer (0.0.55-1) unstable; urgency=low + + * Fixes: NB#258573 - Never played , most played , recently payed queries does not yield any results + + -- Mika Tapojärvi Mon, 23 May 2011 20:10:35 +0300 + +qmafw-gst-renderer (0.0.54-1) unstable; urgency=low + + * Fixes: NB#253849 - “Can’t play the video because it’s the wrong format” error throws while trying to play any video when music suite is in background. + * MafwGstRenderer creates video-sink only if XID is set. + * Dependency to new gstreamer added. + * Fixing coverity findings. + + -- Mika Tapojärvi Wed, 11 May 2011 07:44:56 +0300 + +qmafw-gst-renderer (0.0.53-1) unstable; urgency=low + + * Fixes: NB#240728 - Resources are granted too early + * Fixes: NB#250212 - Possible memory leak [+1332kB] could be seen in qmafw-dbus-wrapper + * VideoResource PID usage plus resources released even with non-seekable + streams. + * GstBuffer now deleted with gst_buffer_unref (GstBuffer does not inherit + GstObject). + + -- Mika Tapojärvi Thu, 05 May 2011 13:29:33 +0300 + +qmafw-gst-renderer (0.0.52-1) unstable; urgency=low + + * Fixes: NB#248815 - Dolby setting changes has no effect after relaunching application + * Check the values of the audio/video route ContextProperty instances after + creating them. + + -- Mika Tapojärvi Mon, 02 May 2011 19:46:02 +0300 + +qmafw-gst-renderer (0.0.51-1) unstable; urgency=low + + * Fixes: NB#245854 - [SSU-Package Manager]:error seen at 'CRITICAL [contextc.cpp:109:int context_provider_init(DBusBusType, const char*)] Service already initialized' after SSU when opening video + * Fixes: NB#246993 - Renderer crashes if network is disabled during stream playback + * MAFW GStreamer renderer's latency-time setting changed back to 300000. + * Added global variable to monitor the initialisation state of process wide + singleton inside context fw. + * Also stopped setting some properties that omapxvsink doesn't have. + * MafwGstRenderer can handle network changes for simple streams. + + -- Mika Tapojärvi Wed, 20 Apr 2011 18:30:41 +0300 + +qmafw-gst-renderer (0.0.50-1) unstable; urgency=low + + * Fixes: NB#244162 - "Unable to play unsupported video format" is displayed while playing 1080p video file. + * Fixes: NB#242441 - wrong error message displayed when stream is not reachable + * Fixes: NB#242345 - Renderer goes to buffering loop when playing online stream + * MafwGstRenderer correctly generates unsupported resolution error. + * MafwGstRenderer sends URINotAvailable error for not found streams. + + -- Mika Tapojärvi Thu, 07 Apr 2011 10:01:57 +0300 + +qmafw-gst-renderer (0.0.49-1) unstable; urgency=low + + * Removed obsolete code for pausing playback when headphones get disconnected. + + -- Mika Tapojärvi Tue, 05 Apr 2011 07:48:12 +0300 + +qmafw-gst-renderer (0.0.48-1) unstable; urgency=low + + * Fixes: NB#236498 - Music suite does not continue internet radio playback after internet connection is renegotiated. + * Fixes: NB#238504 - Handover from WLAN to 3G does not happen when streaming audio + * Fixes: NB#240756 - defects from qmafw-gst-renderer/0.0.46-1_0m6 + * Fixes: NB#239983 - Remove dependencies to DRM Subsystem + * Fixes: NB#239428 - Black thumbnail displayed in minimized view after seek and swiping during online playback + * MafwGstRenderer tries to handle network changes gracefully. + + -- Mika Tapojärvi Wed, 30 Mar 2011 20:55:34 +0300 + +qmafw-gst-renderer (0.0.47-1) unstable; urgency=low + + * Fixes: NB#235660 - The note "Unable to play song, file not found" is shown with some music clips + * Adds proper encoding for file URI in some cases. Affects file paths which + contain non-ASCII characters. + + -- Mika Tapojärvi Thu, 24 Mar 2011 19:04:58 +0200 + +qmafw-gst-renderer (0.0.46-1) unstable; urgency=low + + * Fixes: NB#238161 - Playback fails until reboot after playing unsupported media file + * Fixes: NB#236869 - Names with special characters are not shown correctly in Music Player + * Fixes: NB#237491 - nie:usageCounter isn't updated if one of nie:usageCounter and nie:contentAccessed is missing + * Fixes: NB#237464 - Song play count is not updated properly. + * Dependencies modified for new DRM packaging. + * MafwGstRenderer returns duration as position in eos if query is not + succesful. + * Gst Renderer now uses QString::fromUtf8 to read in the UTF-8 (or ASCII) + tags from GStreamer. + * MafwGstRenderer updates usageCounter for repeating media. + + -- Mika Tapojärvi Tue, 22 Mar 2011 21:39:56 +0200 + +qmafw-gst-renderer (0.0.45-1) unstable; urgency=low + + * Fixes: NB#236498 - Music suite does not continue internet radio playback after internet connection is renegotiated. + * Fixes: NB#233404 - Renderer removed when play->stop actions are repeated many times + * Fixes: NB#229794 - Music Player failed to handle empty playlists (qtn_musi_empty_playlist not shown) + * MafwBasicRenderer better handling for stopped to pause transitions for + updating the mediaChanged() signal. + * MafwGstRenderer tries to restart infinite length streams when EOS + encountered. + * Switch to using the new policy context keys. + * Changed critical message to just warning and added hint why it maybe printed. + * Error signalling when trying to play empty playlist file. + * libqttracker removed from mafw. + + -- Mika Tapojärvi Thu, 17 Mar 2011 14:12:12 +0200 + +qmafw-gst-renderer (0.0.44-1) unstable; urgency=low + + * Fixes: NB#225667 - First frame flashes for fraction of sec just before playback resumes from previously watched position + * Fixes: NB#231298 - libqmafw-gst-renderer pulls gstreamer0.10-plugins-good-extra + * Fixes: NB#225941 - While Adding two songs via BT,One song goes to never played playlist and other goes to recently played playlist. + * Removed some unnecessary dependencies. + * Removed the dependency to plugins-good-extra. + * Unit testing for played stamping fixed. + * Fix for played stamping if piece was not harvested when it is played. + * MafwGstRenderer duration is signaled, among others. + + -- Mika Tapojärvi Thu, 03 Mar 2011 22:23:09 +0200 + +qmafw-gst-renderer (0.0.43-1) unstable; urgency=low + + * Implemented: SWP#MMAFW-2666 + + -- Mika Tapojärvi Fri, 25 Feb 2011 06:20:50 +0200 + +qmafw-gst-renderer (0.0.42-1) unstable; urgency=low + + * Fixes: NB#228964 - Video Rendrer crashes randomly on tapping next. + * Fixes: NB#219808 - Renderer state doesn't change, when video stream is launched. + * Removed unnecessary XError handling from mafw-gst-renderer. + + -- Mika Tapojärvi Tue, 22 Feb 2011 18:22:29 +0200 + +qmafw-gst-renderer (0.0.41-1) unstable; urgency=low + + * Fixes: NB#219808 - Renderer state doesn't change, when video stream is launched. + * MACHINE READABLE LINE: pre-release commit. + * ABI BREAK: Changes MafwRenderer::play(QUrl) to accept starting position to + start playback from as parameter + * MACHINE READABLE LINE: pre-release commit. + + -- Mika Tapojärvi Mon, 21 Feb 2011 10:17:29 +0200 + +qmafw-gst-renderer (0.0.40-1) unstable; urgency=low + + * ABI BREAK: Changes MafwRenderer::play(QUrl) to accept starting position to + start playback from as parameter. + + -- Mika Tapojärvi Thu, 17 Feb 2011 23:26:02 +0200 + +qmafw-gst-renderer (0.0.39-1) unstable; urgency=low + + * Fixes: NB#224017 - Hash marks are double encoded in renderer's metadataChanged signals + * MafwRenderer URL encoding handling improvements. Delimiter characters + handled correctly. + + -- Mika Tapojärvi Sun, 13 Feb 2011 22:06:45 +0200 + +qmafw-gst-renderer (0.0.38-1) unstable; urgency=low + + * Fixes: NB#207278 - Fast forward /rewind can not work during playing special MPEG4 video clip. + * Fixes: NB#222381 - pauseframes don't have unique names + * MafwGstRenderer tries to do better seek if a key frame seeks does not + advance or even goes backwards. It tries to find the next key frame. + + -- Mika Tapojärvi Tue, 08 Feb 2011 06:21:07 +0200 + +qmafw-gst-renderer (0.0.37-1) unstable; urgency=low + + * Fixes: NB#214335 - Unable to play. file not found message appears before the online playback starts + * Fixes: NB#217783 - Seekbar information and timer increment mismatch for particular .AAC clip. + * Fixes: NB#180798 - Music does not stop playing after DUT and PC were connected as Mass storage mode + * Now the playlist file playback doesn't report errors about individual uris. + * The possible error is reported only after the last uri has also been tried. + * MafwGstRenderer does not sent duration in nanosecond precision in some + scenarios. + * MafwGstRenderer listens for pre-unmount signal from usb_moded. + + -- Mika Tapojärvi Thu, 03 Feb 2011 19:54:23 +0200 + +qmafw-gst-renderer (0.0.36-1) unstable; urgency=low + + * Fixes: NB#220938 - Buffering banner not displayed for Iradio applet if applet invoked first time(Before Audio Player) after flashing + * Fixes: NB#210899 - Playback is stopped after TV-Out cable is plugged and unplugged for DRM restricted video + * MafwGstRenderer pauses when unallowed route switch occurs. + * MafwGstRenderer updates duration to tracker, also MafwBasicRenderer + provides duration metadata in MafwMediaInfo with doPlay(). + + -- Mika Tapojärvi Mon, 31 Jan 2011 08:30:21 +0200 + +qmafw-gst-renderer (0.0.35-2) unstable; urgency=low + + * Version increased for reintegration. + * Pause frame timer now takes milliseconds instead of seconds and default is + now 700 ms. + + -- Mika Tapojärvi Thu, 27 Jan 2011 11:18:14 +0200 + +qmafw-gst-renderer (0.0.35-1) unstable; urgency=low + + * Pause frame timer now takes milliseconds instead of seconds and default is + now 700 ms. + + -- Mika Tapojärvi Mon, 24 Jan 2011 06:17:12 +0200 + +qmafw-gst-renderer (0.0.34-1) unstable; urgency=low + + * Fixes: NB#213693 - TVandvideo releases playback resources too early + * Fixes: NB#217389 - Black screen is displayed in video pause mode when an incoming call comes + * Png encoder now uses compression-level 1. This should improve performance. + * MafwGstRenderer copies gstbuffer for further handling of pause. Also + resources are informed as being released only when they are released. + * Pause frame pipeline is now reused. + + -- Mika Tapojärvi Tue, 18 Jan 2011 22:11:19 +0200 + +qmafw-gst-renderer (0.0.33-2) unstable; urgency=low + + * Fixes: NB#215967 - When tapped during first 3 secs of playback seekbar behaves strangely in online player + * Fixes: NB#211139 - Pause button shown instead of stop for non seekable streams + * Fixes: NB#214376 - getPosition starts returning constant value after setPosition for nonseekable stream + * Version increased. + * Added resetting the error flag of the pipeline, if the playback attempt + ends because of DRM destination check, before the pipeline gets actually used. + * Changed the redirect message test case. + * MafwGstRenderer duration query fixes for media startup. + + -- Mika Tapojärvi Mon, 17 Jan 2011 09:42:43 +0200 + +qmafw-gst-renderer (0.0.32-1) unstable; urgency=low + + * Implemented: SWP#MMAFW-2546 + * Fixes: NB#214969 - No audio while playback when auto advance is set 'off' and then 'on' in a particular scenario + * Fixes: NB#213330 - Whitespaces are not encoded in renderer's metadataChanged signals + * Fixes: NB#206030 - Music playback prevents reaching 60 fps panning performance + * Added MafwGstScreenshot.cpp and .h to .pro file. + * Added MafwGstScreenshot.h and .cpp to pro file. + * mmcPreUnmount is back. + * MAFW_METADATA_KEY_URI emitted in encoded form. + * MafwGstRenderer latency-time tuning. + + -- Mika Tapojärvi Tue, 04 Jan 2011 08:17:20 +0200 + +qmafw-gst-renderer (0.0.31-1) unstable; urgency=low + + * Fixes: NB#194458 - CJSE:NFT:AudioPlayer:CJSE_NFT13 test case is failing + * Fixes: NB#211505 - Internet stream URI metadata not emitted + * Fixes: NB#209526 - Noise heard on DRM protected clip playback attempt + * Fixed few TYPOs on ut_MafwMmcMonitor. + * Wrong notification was displayed if text file which was not playlist were + tried to be played without mime type. + * MafwGstRenderer MMC monitoring. + * trackerRelease call added to gst-renderer unit tests cleanup. + * MAFW error code DRM error for clock not set added. + * Playback outputs are checked for DRM clips before starting playback. + + -- Mika Tapojärvi Tue, 21 Dec 2010 12:35:49 +0200 + +qmafw-gst-renderer (0.0.30-1) unstable; urgency=low + + * Fixes: NB#206367 - calling pauseAt(uint) emits playing state signal before pause signal + * MafwGstRenderer does not send playing state first when calling pauseAt. + + -- Mika Tapojärvi Mon, 13 Dec 2010 06:49:56 +0200 + +qmafw-gst-renderer (0.0.29-1) unstable; urgency=low + + * Fixes: NB#207882 - Seek does not work for the attached mp3 clip. + + -- Mika Tapojärvi Thu, 09 Dec 2010 10:55:48 +0200 + +qmafw-gst-renderer (0.0.28-1) unstable; urgency=low + + * Fixes: NB#208336 - Wrong notification is displayed when playing 1080p video clip. + * Fixes: NB#207288 - Video playback starts from beginning when resumed playback in certain scenario + * Fixes: NB#207837 - Dolby effectss not preserved after reconnecting the headset + * There was a logical error in the for loop, which caused infinite loop with + some medias. + * Some files were earlier left out of the commit (pipeline configurability) + because of conflicts. + * Duration handling removed in ready state. + * MafwGstRenderer can be configured via text file. + * Bug changed video settings as the active ones when reconnecting headset. + Now works correctly. + + -- Mika Tapojärvi Tue, 07 Dec 2010 21:50:59 +0200 + +qmafw-gst-renderer (0.0.27-1) unstable; urgency=low + + * Fixes: NB#208106 - Playback starts from the beginning of the clip on Resume after a call + * g_asserts removed from release builds. + * Added dependency to gstreamer0.10-plugins-bad + * There was a small error in the logic of handling the duration + unavailability. + * Now the last known seekability value is actually used, if the duration is + not known. + * Small fixes for MMS stream buffer size handling. + + -- Mika Tapojärvi Fri, 03 Dec 2010 08:27:33 +0200 + +qmafw-gst-renderer (0.0.26-1) unstable; urgency=low + + * Fixes: NB#199374 - Unable to stream ASF videos + * Fixes: NB#199405 - Unable to stream WMV videos through MMS and http + * Fixes: NB#203058 - “Unable to play song, Media format is not supported” pops up after the special playback is finished. + * Fixes: NB#207747 - WMA with Multichannel encoding not playing + * Fixes: NB#208036 - "unable to play song, media format not supported" is displayed for few WMA files. + * CI Test case for bug that timers for calling playNextURIFromPlaylist are + not cancelled. + * Fallback mechanism for playlist file playback error. + * Changed flags from 99 to 67 when using DHM to support "unsupported" audio. + + -- Mika Tapojärvi Tue, 30 Nov 2010 21:14:12 +0200 + +qmafw-gst-renderer (0.0.25-1) unstable; urgency=low + + * Fixes: NB#204996 - COREWEB: /usr/bin/qmafw-dbus-wrapper 'QString::operator< qMapLessThanKey findNode value MafwMediaInfo::firstMetaData' + * Fixes: NB#206947 - Duplicated is-seekable metadata received + * MafwGstRenderer does not send same metadata value again + * Added cancellation of screenshot capture into various cases. + * It is a strong assumption that 204996 is caused by the screenshot never + being cancelled. + * MafwGstRenderer does not send seekability metadata unless it changes. + + -- Mika Tapojärvi Sun, 28 Nov 2010 18:32:23 +0200 + +qmafw-gst-renderer (0.0.24-1) unstable; urgency=low + + * Fixes: NB#206561 - Playback fails after multiple seek of mms stream + * Fixes: NB#205172 - Audio not heard for the next file playable when "codec not found" error pops up + * MafwGstRenderer: Improved handling of seeking-buffering-pause sequences + * MafwGstRenderer reuses audio elements when reconstructing pipeline. + + -- Jukka Heikkilä Thu, 25 Nov 2010 08:26:54 +0200 + +qmafw-gst-renderer (0.0.23-1) unstable; urgency=low + + * Fixes: NB#202071 - Unable to stream WMA audio through MMS. + * Added dependency to gstreamer0.10-plugins-good-extra. + * It is needed because it provides png encoder. + + -- Jukka Heikkilä Fri, 19 Nov 2010 08:16:55 +0200 + +qmafw-gst-renderer (0.0.22-1) unstable; urgency=low + + * Fixes: NB#203250 - Dropping sdpdemux patch from meego gstreamer -bad package + * Fixes: NB#203010 - ‘Playback error: 326’ pops up when seeked till end during playback + * Fixes: NB#197812 - Error message displayed while resuming an rtsp stream playback + * Use "element-added" signal to get queue2 element from the pipeline. + * rm ==> rm -f + + -- Jukka Heikkilä Thu, 11 Nov 2010 12:59:59 +0200 + +qmafw-gst-renderer (0.0.21-1) unstable; urgency=low + + * GstRenderer remove unnecessary context provider check from initialize. + * Default room size of Dolby effect changed from 0 to 2. + + -- Mika Tapojärvi Mon, 08 Nov 2010 16:24:07 +0200 + +qmafw-gst-renderer (0.0.20-1) unstable; urgency=low + + * Fixes: NB#201764 - Playing online stream doesn't always start + * Fixes: NB#201569 - Play count and content accessed data not available when video clip is played with uri. + * Fixes: NB#199784 - No audio output for YouTube video when audio is paused from music application by unplug the headset. + * Removed one buffer size optimisation (setting buffer-duration in playbin2) + as it seemed to make gstreamer a bit unstable. + * Replaced Qt keywords with appropriate macros. + * MAFW to use libqmsystem2. + * Replaced emit and signals keywords with corresponding macros to make the + test compile again. + * Removing code that is nowadays unnecessary and causing valgrind findings. + * Gst renderer updating usageCount and contentAccessed in play URI case + * MafwGstRenderer now releases resources when headphones are disconnected, + which causes playback to pause. + * Added one more suppression related to g_type_register_static. + + -- Mika Tapojärvi Thu, 04 Nov 2010 22:54:27 +0200 + +qmafw-gst-renderer (0.0.19-2) unstable; urgency=low + + * Version increased. + + -- Mika Tapojärvi Tue, 02 Nov 2010 14:56:39 +0200 + +qmafw-gst-renderer (0.0.19-1) unstable; urgency=low + + * Fixes: NB#199965 - mafw-gst-renderer fails to build with GLib 2.26 + * The error code mapping was changed earlier. Now correcting the unit test + accordingly. + * Disabled moc keywords from mafw-gst-renderer. + * CI tests for dbus-wrapper lingering. + * Generalised libc6 library condition in some suppresions. + + -- Mika Tapojärvi Mon, 01 Nov 2010 13:52:03 +0200 + +qmafw-gst-renderer (0.0.18-1) unstable; urgency=low + + * Removed unnecessary LKM stubs from unit tests and enabled -Werror where it + was disabled because of LKM-caused warnings. + * Little formatting change in mafw-gst-renderer and error code fix when + mapping gstreamer errors to worker errors. + + -- Mika Tapojärvi Fri, 29 Oct 2010 10:46:35 +0300 + +qmafw-gst-renderer (0.0.17-1) unstable; urgency=low + + * Removed unnecessary LKM stubs from unit tests and enabled -Werror where it + was disabled because of LKM-caused warnings. + * Little formatting change in mafw-gst-renderer and error code fix when + mapping gstreamer errors to worker errors + + -- Mika Tapojärvi Thu, 28 Oct 2010 13:50:53 +0300 + +qmafw-gst-renderer (0.0.16-1) unstable; urgency=low + + * Fixes: NB#197421 - Seeking back functions as 'Next', and also jumps to every second video in a yt playlist after seek back at an end of a clip once + * Fixes: NB#196798 - Total duration of a seekable stream is not seen if a playlist is present already + * Fixes: NB#197812 - Error message displayed while resuming an rtsp stream playback + * Gst renderer regression fixed when resuming from ready state now works. + * Live source seeking is now delayed in Paused state. CITA test fixes, plus + last version info commits. + * Removed temporary fixes to counter build break on x86 target: DRM libraries + are again required for all architectures and temporary stubs are removed. + * Added initilization for m_pendingCall member on MafwGstRendererVolume. + * Dolby mixer enabled. + * MafwGstRenderer behaves correctly and sends only one playing state change + even when seeking while in playing state. + * A bug prevented DRM playback because drm_create_uri() was given 0 as + maximum length of string. + * Seekability is now send as false, when duration is unknown. + * DRM stub definitions changed to function declarations. + + -- Mika Tapojärvi Tue, 26 Oct 2010 22:07:05 +0300 + +qmafw-gst-renderer (0.0.15-1) unstable; urgency=low + + * Removed volume intialization at gst renderer startup. Volume is currently + set by system component and volume initialization at gst-renderer startup + causes unneeded processing. + * DRM client i486 support was removed. Implemented temporary stubs for those + used in i486 target. + * Updated DRM library version numbers to dependencies and removed dependency + to DRM from non-ARM. + + -- Mika Tapojärvi Mon, 18 Oct 2010 21:10:09 +0300 + +qmafw-gst-renderer (0.0.14-1) unstable; urgency=low + + * Implemented: SWP#MMAFW-2457 + * Fixes: NB#197668 - Unable to play DRM clip second time using the same renderer and not more than twice using any renderer + * Fixes: NB#186008 - MaFW play for audio streaming taking long time + * Fixes: NB#196891 - Sometimes resume is not working when called after audiopolicy is given back to music-suite + * Adaptation to API change in libdrm-playready0. + * Moved clearing worker->destinations from _reset_pipeline_and_worker() to + mafw_gst_renderer_worker_exit(). + * Increased mmsh buffer duration. + * Added usage of connection-speed and buffer-duration properties of playbin2. + Subsequent task is needed to make more elegant final solution, but this + should be enough for the bug. + * MafwGstRenderer handles earpiece audio route as builtin speaker route. + + -- Mika Tapojärvi Thu, 14 Oct 2010 15:42:56 +0300 + +qmafw-gst-renderer (0.0.13-1) unstable; urgency=low + + * Fixes: NB#196975 - defects from MAFW + * Dolby effect disabled for now. + * Part VIII: MafwGstRenderer unittest valgrind suppression file updated. + * Part VII: MafwGstRenderer unittest valgrind suppression file updated. + * Coverity findings fixed. + + -- Mika Tapojärvi Mon, 11 Oct 2010 12:09:24 +0300 + +qmafw-gst-renderer (0.0.12-1) unstable; urgency=low + + * MafwGstRenderer unittest valgrind suppression file updated. + * Unittests for Dolby effect. + + -- Mika Tapojärvi Fri, 08 Oct 2010 09:47:20 +0300 + +qmafw-gst-renderer (0.0.11-1) unstable; urgency=low + + * Fixes: NB#196267 - Renderer is lost after random qmafw-dbus-wrapper crash, only reflash the way out + * Fixes: NB#196026 - Renderer gets stuck on performing playback by 'Play uri' for a particular m3u playlist + * GstRenderer and YoutubeSource plugins dbus .service file naming convention. + * Moved Dolby initialization to worker initialization and added check for + m_worker. + * Added Dolby effect audio route handling. + * MafwGstRenderer send playbackCompleted() even if error case when playing + playlistURI. Fixes faulty cleanup in mafw-gst-renderer-worker. + + -- Mika Tapojärvi Wed, 06 Oct 2010 19:57:13 +0300 + +qmafw-gst-renderer (0.0.10-1) unstable; urgency=low + + * Implemented: SWP#MMAFW-1820 + * Fixes: NB#182065 - BT downloaded music clip does not play while camera is open in still picture mode. + * Added initialization list to get correct behavior. + * Added support for Dolby Headphone feature. + * GstRenderer fix in render-rectangle parsing. + + -- Mika Tapojärvi Tue, 05 Oct 2010 08:23:43 +0300 + +qmafw-gst-renderer (0.0.9-1) unstable; urgency=low + + * Fixes: NB#188929 - The Audio is not heard through wired headset when already connected BT headset is disconnected + * In MafwGstRenderer bluetooth headset disconnecting is handled in same way + as wired headset. + * Correct error code emission for DRM "no license" case. + + -- Mika Tapojärvi Fri, 01 Oct 2010 10:53:27 +0300 + +qmafw-gst-renderer (0.0.8-1) unstable; urgency=low + + * Fixes: NB#194221 - Seekability value is wrong for Internet radio streams + * Partial fix for #194442. MafwGstRenderer does more robust network change + observations + * We don't send out a gstreamer query in case we don't know the duration. + + -- Mika Tapojärvi Wed, 29 Sep 2010 18:29:54 +0300 + +qmafw-gst-renderer (0.0.7-1) unstable; urgency=low + + * Fixes: NB#193425 - Video image it not seen when starting playback in some cases + + -- Mika Tapojärvi Thu, 23 Sep 2010 20:46:07 +0300 + +qmafw-gst-renderer (0.0.6-1) unstable; urgency=low + + * Fixes: NB#193662 - qmafw package may have resource token problem with Tracker, please verify. + * Fixes: NB#193682 - qmafw-gst-renderer package may have resource token problem with Tracker, please verify. + * Fixes: NB#186008 - MaFW play for audio streaming taking long time + * Fixes: NB#190121 - Online video clip fails to play from the position where it was paused before + * Fixes: NB#192157 - qmafw-shared: add pkg-config to build-deps + * Added API documentation about the required credentials. + * Decreased the buffer size to 30 % of the original. It takes another second + off the stream start delay. + * gst-renderer seeks live streams in PLAYING state. + + -- Mika Tapojärvi Wed, 22 Sep 2010 21:20:17 +0300 + +qmafw-gst-renderer (0.0.5-1) unstable; urgency=low + + * Fixes: NB#192243 - Pause->resume->pause->resume sequence causes some videos to start from beginning. + * Fixes: NB#191257 - performance problem after renderer pause playback + * InvalidURI was sometimes incorrectly received as error code. Changed to + correct UNSUPPRTED TYPE code. + * Added a check for seekability request's result validity. If unknown is + * passed as a value, it's ignored. + + -- Mika Tapojärvi Mon, 20 Sep 2010 07:35:57 +0300 + +qmafw-gst-renderer (0.0.4-1) unstable; urgency=low + + * Fixes: NB#190307 - Black frame displayed when tap on screen after swiping to next clip + * Fixes: NB#189621 - Stream Playback starts playing from the beginning after a call or pause/resume after few seconds. + * Fixes: NB#190121 - Online video clip fails to play from the position where it was paused before + * MafwGstRenderer resumes from correct position after resources released in + pause state when streaming content. + + -- Mika Tapojärvi Fri, 17 Sep 2010 05:42:44 +0300 + +qmafw-gst-renderer (0.0.3-1) unstable; urgency=low + + * Implemented: MMAFW-2416 + * Fixes: NB#190752 - Music player does not plays after invalid video is played + * MafwGstRenderer reacts to network changes by emitting and error when + streaming cannot continue. + * Version dependency for playready packages updated. + * Fixed bug that stream playback is resumed automatically after a call. + + -- Mika Tapojärvi Wed, 15 Sep 2010 07:51:45 +0300 + +qmafw-gst-renderer (0.0.2-1) unstable; urgency=low + + * Fixes: NB#190393 - Stream buffers after 1-2 seconds of playback ,everytime after playback is initiated + * Fixes: NB#186008 - MaFW play for audio streaming taking long time + * Streaming optimization for mms streams. + * added CONFIG += plugin in .pro file + * fallback to alsasink in worker code + + -- Mika Tapojärvi Fri, 10 Sep 2010 13:22:17 +0300 + +qmafw-gst-renderer (0.0.1-73) unstable; urgency=low + + * Buffering optimization for mms streams. + + -- Mika Tapojärvi Wed, 08 Sep 2010 06:54:04 +0300 + +qmafw-gst-renderer (0.0.1-72) unstable; urgency=low + + * Fixes: NB#189707 - Playback from a playlist differs with the presence of local playlist + * Added getUriList function to MafwPlaylistFileUtilityStub so that the + untitests can pass. + * Added a waiting time for the playlist parser so that playing URI lists + doesn't stop when empty items are found before parsing the list far enough. + + -- Mika Tapojärvi Mon, 06 Sep 2010 22:24:21 +0300 + +qmafw-gst-renderer (0.0.1-71) unstable; urgency=low + + * Lintian warnings fixed. + + -- Mika Tapojärvi Sun, 05 Sep 2010 21:58:13 +0300 + +qmafw-gst-renderer (0.0.1-70) unstable; urgency=low + + * mafw-gst-renderer rebuild needed because of libplayready packaging changes. + + -- Mika Tapojärvi Thu, 02 Sep 2010 10:47:27 +0300 + +qmafw-gst-renderer (0.0.1-69) unstable; urgency=low + + * Implemented: MMAFW-2006 + * Fixes: NB#187115 - DRM playback stops and throws a error on receiving a call. + * Fixes: NB#188378 - End of playlist reached after playing first song/stream in the Playlist file + * Fixes to playlist URI playing and signalling. + + -- Mika Tapojärvi Tue, 31 Aug 2010 10:08:44 +0300 + +qmafw-gst-renderer (0.0.1-68) unstable; urgency=low + + * Implemented: SWP#MMAFW-2006 + * Implemented: SWP#MMAFW-2243 + * Fixes: NB#183176 - Resuming music after playing video with music in paused state doesn't work + * Fixes: NB#176434 - When pausing a song, music-suite does not release audio resource + * Signalling paused-thumbnail-uri metadata fixed. + * Playlist file playback support in gst-renderer. + * Pause state releases resources, although 2 seconds later. + + -- Mika Tapojärvi Thu, 26 Aug 2010 13:56:02 +0300 + +qmafw-gst-renderer (0.0.1-67) unstable; urgency=low + + * Implemented: MMAFW-2331 + * Fixes: NB#184640 - Fast seek makes playback unreliable + * Related metadata added to pause-frame-uri metadata: URI to video file the + frame is from and the position in seconds. + * RTSP redirect MAFW implementation. + + -- Mika Tapojärvi Mon, 23 Aug 2010 15:46:40 +0300 + +qmafw-gst-renderer (0.0.1-66) unstable; urgency=low + + * Implemented: SWP#MMAFW-2261 + * Implemented: SWP#MMAFW-2359 + * Fixes: NB#184583 - audio continues even after playback is completed when tried to play an online video + * No longer automatic resume when buffering after seek after EOS. + * Bypasses bug of resetting render-rectangle values does not work. + * Werror compile flag back to use. + * GstRenderer media routing info provider's credential check. + * Missing unittests change for render rectangle added. + * gstreamer X Overlay render rectangle setting possible via mafwgstrenderer. + * colorkey reverted back to 0x080810. + + -- Mika Tapojärvi Wed, 18 Aug 2010 07:30:56 +0300 + +qmafw-gst-renderer (0.0.1-65) unstable; urgency=low + + * Fixes to pkg-config usage, now pointing PKG_CONFIG_PATH into -uninstalled + .pc files makes it possible to compile mafw, mafw-shared and mafw-gst-plugin. + * Video sink colorkey is now 0xff00ff. + + -- Mika Tapojärvi Thu, 12 Aug 2010 15:05:34 +0300 + +qmafw-gst-renderer (0.0.1-64) unstable; urgency=low + + * Implemented: SWP#MMAFW-2358 + * Implemented: SWP#MMAFW-380 + * Pause playback when headset disconnected. + + -- Mika Tapojärvi Mon, 09 Aug 2010 09:38:36 +0300 + +qmafw-gst-renderer (0.0.1-63) unstable; urgency=low + + * Implemented: SWP#MMAFW-918 + * Fixes: NB#183564 - Video doesn't play when tap on a video file in VideosandTv application + * Explicit version for libdrm-playready0-dev build dependency. + * Enhancements to gstscreenshot code. + + -- Mika Tapojärvi Fri, 06 Aug 2010 07:46:00 +0300 + +qmafw-gst-renderer (0.0.1-62) unstable; urgency=low + + * Fixes: NB#176165 - MAFW should not wait for gst state changes to complete + * Fixes mafw-gst-renderer unittests. Policy functionality changes in + MafwBasicRenderer changed the API + + -- Tuomas Inkeroinen Thu, 29 Jul 2010 12:43:20 +0300 + +qmafw-gst-renderer (0.0.1-61) unstable; urgency=low + + * Fixes: NB#179733 - + * Fix for bug 179733 - Multiple seek beyond the duration of the video clip + hangs playback + + -- Tuomas Inkeroinen Mon, 26 Jul 2010 10:58:33 +0300 + +qmafw-gst-renderer (0.0.1-60) unstable; urgency=low + + * Fixes: NB#179782 - When a video is continuously skipped forward by 10 seconds in playing state, the pause control changes to play, while video continues to play + + -- Tuomas Inkeroinen Thu, 22 Jul 2010 08:54:27 +0300 + +qmafw-gst-renderer (0.0.1-59) unstable; urgency=low + + * Implemented: SWP#MMAFW-2330 + * We now use pngenc for pause frames instead of jpegenc + + -- Jukka Heikkilä Thu, 15 Jul 2010 09:55:39 +0300 + +qmafw-gst-renderer (0.0.1-58) unstable; urgency=low + + * Fixes: NB#177617 - Playcount does not increase when a clip is played repeatedly in player view + * Coverity issues fixed. + * mafw-gst-renderer usageCounter and contentAccessed update on replay + + -- Jukka Heikkilä Tue, 13 Jul 2010 12:34:26 +0300 + +qmafw-gst-renderer (0.0.1-57) unstable; urgency=low + + * Fixes: NB#176727 - Invalid pause frame given with pauseAt + * GstRenderer policy-context-daemon security token check + + + -- Jukka Heikkilä Thu, 08 Jul 2010 12:55:38 +0300 + +qmafw-gst-renderer (0.0.1-56) unstable; urgency=low + + * Fixes: NB#177006 - MAFW crash when playing regina spectres album. + * Earlier the "Next" URI was read from MafwMediaInfo into QString instead of + QUrl. + * This caused the uri that was passed to be percent encoded. + * Syslog routines then failed with because they assumed the uri to specify + format containing variables to be replaced. + * Append 'release'/'debug' into CONFIG variable rather than overwrite it. + * Earlier version caused extra 'strip' command into the Makefile. This in + turn, cause dbg-package to be empty. + + -- Jukka Heikkilä Tue, 29 Jun 2010 13:01:33 +0300 + +qmafw-gst-renderer (0.0.1-55) unstable; urgency=low + + * Fixes: NB#176077 - Screen blanking doesn't happen on playing videos in from video suite with TV-out connected + * Removed accidentally forgot wrt dependencies from pro file. + + -- Mika Tapojärvi Thu, 24 Jun 2010 13:10:05 +0300 + +qmafw-gst-renderer (0.0.1-54) unstable; urgency=low + + * Remove lisence fething from mafw and only report error from gst-renderer. + + -- Mika Tapojärvi Wed, 23 Jun 2010 10:14:45 +0300 + +qmafw-gst-renderer (0.0.1-53) unstable; urgency=low + + * Volume robustness test failing fixed. + * Build-Depends for libqttracker-dev (>= 1~6.9.5) and Depends for + libqttracker1pre6 (>= 1~6.9.5) added, Standards-Version: 3.8.0 updated where + needed. + + -- Mika Tapojärvi Thu, 17 Jun 2010 07:47:49 +0300 + +qmafw-gst-renderer (0.0.1-52) unstable; urgency=low + + * Fixes: NB#170773 - Renderer doesn't show up in MTG atall, if MTG gets closed before the renderer loads for the first time + + -- Mika Tapojärvi Sat, 12 Jun 2010 12:53:51 +0300 + +qmafw-gst-renderer (0.0.1-51) unstable; urgency=low + + * Fixes: NB#172047 - Resuming a song from paused state updates usageCount and contentAccessed + * Fixes: NB#170238 - Volume level of music is set to the same as alarm level (maximum) + * Fixes: NB#172330 - Video Rendrer crash on playing a video + * Temporarily removing DRM check. + * Getting lkm service interface commented temporarily out. + * Adapted changes in drmclient.h so that gst-renderer compiles: + drm_check_destination stub updated. + * Adapted changes in drmclient.h so that gst-renderer compiles. Actual fix + will come later... + * Fix for bug "Volume level of music is set to the same as alarm level + (maximum)". + * Removing unnecessary debian configuration. + * mafw-gst-renderer now informs of visual content when going to playing state. + * Mafwgstrenderer debian package building fix for servicehandler lib changes. + * Fix to get mafw-gstrenderer to compile againts lkm 1.7 + + -- Mika Tapojärvi Fri, 11 Jun 2010 12:45:20 +0300 + +qmafw-gst-renderer (0.0.1-50) unstable; urgency=low + + * Implemented: SWP#MMAFW-2024 + * Added a missing wrt lib for linking. + * Video resource is released when it is not needed. + * Undoing resource usage optimization when paused. + * mafw-gst-renderer libqttracker/dbus usage optimization. + + -- Mika Tapojärvi Wed, 02 Jun 2010 22:41:04 +0300 + +qmafw-gst-renderer (0.0.1-49) unstable; urgency=low + + * Implemented: SWP#MMAFW-2243 + * Implemented: SWP#MMAFW-2288 + * Fixes: NB#169418 - Playback resumption after 'pause at' set starts the playback from beginning + * Optimize resource usage when paused. + * Gst-renderer config file has a separate uuid for the in-process renderer. + When loaded in-process, the plugin creates the renderer with that uuid. + * New CI-test testInProcessPlayUri. + + -- Mika Tapojärvi Mon, 31 May 2010 19:41:45 +0300 + +qmafw-gst-renderer (0.0.1-48) unstable; urgency=low + + * Implemented: SWP#MMAFW-1925 + * Fixes: NB#170621 - qmafw crash while playing a video which blocks videoandTV testing + * When the reconnect to pulse audio was done, earlier the old connection was + unref'd synchronously. This caused problems in libdbus-qeventloop so now the + unref (and the reconnect) is done asynchronously in a separate event. + * Merge from fremantle: Bug 149945 - mafw-gst-renderer leaks some GStreamer + messages + * Merge from fremantle: Bug 137609 - UPnP: playback pauses often when + seek the attached content. + + -- Mika Tapojärvi Thu, 27 May 2010 22:55:54 +0300 + +qmafw-gst-renderer (0.0.1-47) unstable; urgency=low + + * Fixes: NB#169742 - Seekbar Maximum Value: Actual Length of the video clip is not displayed in Player view + * Merge from fremantle: Bug 141508 - Specific video file (mjpeg) makes + Mediaplayer unusable + * Use wildcard for the target name in the suppression file. + * Merge from fremantle: Bug 143429 - [PR1.2 proposal] memory fragemntation + & unneeded copies + * Merge from fremantle: Bug 134495 - [PR1.1 proposal] State changed signal + does not come sometimes when stream is played + * Corrected Ut_MafwGstRendererWorker::basicPlaybackTestCase() to expect + test.wav duration 3 instead of 2 because of new changed duration rounding. + * Fixed one memory leak in a unittest and added some suppressions for glib + related leaks. + * Merge from fremantle: Bug 143972 - [PR1.2 proposal] bundle g_object_set + calls + + -- Mika Tapojärvi Mon, 24 May 2010 20:42:03 +0300 + +qmafw-gst-renderer (0.0.1-46) unstable; urgency=low + + * Implemented: SWP#MMAFW-2237 + * Added the destructor stub to the QmDisplayState stub (the real destructor + assumed that the constructor created a private class instance). + * More robustness for using pulseaudio dbus volume API. + + -- Mika Tapojärvi Thu, 20 May 2010 13:04:53 +0300 + +qmafw-gst-renderer (0.0.1-45) unstable; urgency=low + + * Fixes: NB#167753 - Playback state does not change and focus does not move to next clip in this scenario + * Pending volume calls cancelled at destructor. + * So added internal stop when the license check fails. + * Fixed memory leak in ut_MafwGstRenderer. + + -- Mika Tapojärvi Mon, 17 May 2010 13:50:15 +0300 + +qmafw-gst-renderer (0.0.1-44) unstable; urgency=low + + * Implemented: SWP#MMAFW-2243 + * Implemented: SWP#MMAFW-2189 + * Fixes: NB#166855 - Tv and Video does not release Xv resources correctly + * Optimize resource usage when paused. + * MafwRenderer now has playbackCompleted signal. + * libtimed-dev added as a build dependency. + + -- Mika Tapojärvi Wed, 12 May 2010 09:49:05 +0300 + +qmafw-gst-renderer (0.0.1-43) unstable; urgency=low + + * Implemented: SWP#MMAFW-2053 + * Implemented: SWP#MMAFW-2138 + * Fixes: NB#167042 - MAFW video seeking is very slow + * debian/changelog files copied from tag to trunk. + * Fixes to renderer(s) when using pauseAt with too large value. Also required + changes to unittests. Plus proxyplaylist test fix. + * Prepared for the upcoming omapxvsink (patch from Rene Stadler) + * Updated handle screen blanking in video playback appropriately, when TV-OUT + cable is connected. + + -- Mika Tapojärvi Sat, 08 May 2010 11:35:09 +0300 + +qmafw-gst-renderer (0.0.1-42) unstable; urgency=low + + * Version increased. + + -- Mika Tapojärvi Fri, 07 May 2010 12:57:26 +0300 + +qmafw-gst-renderer (0.0.1-41) unstable; urgency=low + + * Implemented: SWP#MMAFW-2156 + * Fixes: NB#166473 - Volume resets to zero from the second instance of MTG launch, after resetting it for the first time + * Modified valgrind.xls for new valgring version. + * Volume resets to zero from the second instance of MTG launch, after + resetting it for the first time. + + -- Mika Tapojärvi Mon, 03 May 2010 22:07:19 +0300 + +qmafw-gst-renderer (0.0.1-40) unstable; urgency=low + + * Implemented: SWP#MMAFW-2156 + + -- Mika Tapojärvi Thu, 29 Apr 2010 13:34:15 +0300 + +qmafw-gst-renderer (0.0.1-39) unstable; urgency=low + + * Fixes: NB#165339 - Renderer crash on playing mp3s in music suite + * Added a NULL pointer check to gotoindex implementation of playlist handler. + + -- Mika Tapojärvi Wed, 28 Apr 2010 19:48:12 +0300 + +qmafw-gst-renderer (0.0.1-38) unstable; urgency=low + + * Audio routing to TV-out was not taken into account. + * Tv-out CF property should be "tvout", not "tv-out". + * A potential bug fix included: mafw_gst_renderer_worker_exit() is called in + the destructor before anything else. + * Added a check against NULL ptr for blanking__control_handler callback in + the worker code. + + -- Mika Tapojärvi Tue, 27 Apr 2010 20:09:41 +0300 + +qmafw-gst-renderer (0.0.1-37) unstable; urgency=low + + * Missing library dependencies temporarily added with debian/shlibs.local + file. + + -- Mika Tapojärvi Mon, 26 Apr 2010 18:35:27 +0300 + +qmafw-gst-renderer (0.0.1-36) unstable; urgency=low + + * Implemented: SWP#MMAFW-918 + * DRM content playback restrictions. + * Added missing contextsubscriber-1.0 into pro -file. + * Added libcontextsubscriber-dev into mafw-gst-renderer debian/control. + + -- Mika Tapojärvi Thu, 22 Apr 2010 19:32:42 +0300 + +qmafw-gst-renderer (0.0.1-35) unstable; urgency=low + + * Implemented: SWP#MMAFW-2138 + * Handle screen blanking in video playback appropriately, when TV-OUT cable + is connected. ContextFW provides com.nokia.policy.video_route property + that is used to check TV-OUT cable status. + + -- Mika Tapojärvi Sun, 18 Apr 2010 22:18:37 +0300 + +qmafw-gst-renderer (0.0.1-34) unstable; urgency=low + + * Implemented: SWP#MMAFW-1532 + * Fixes: NB#163774 - First absolute seek fails after playback start + * Fixes: NB#158231 - Last video frame is displayed briefly when playback has stopped and it's started again + * Gst-renderer, show last video frame when video at end. + * Making unittests to be compiled as single process on build-bot. + * Removed deprecated MafwRenderer API parts. + + -- Mika Tapojärvi Thu, 15 Apr 2010 11:42:07 +0300 + +qmafw-gst-renderer (0.0.1-33) unstable; urgency=low + + * Implemented: SWP#MMAFW-2057 + * Support "force aspect ratio" property in qmafw-gst-renderer. + * Removed deprecated MafwRenderer API parts. + * Updating run_valgrind.sh script for new valgring version. + * Two little coverity findings fixed. + + -- Mika Tapojärvi Mon, 12 Apr 2010 11:49:28 +0300 + +qmafw-gst-renderer (0.0.1-32) unstable; urgency=low + + * Fixes: NB#163168 - Qmafw renderer crash on youtube playback + * Fixes: NB#162434 - Removing items from a playing MafwPlaylist disturbs playback + * MafwGstRenderer no longer makes an LKM check for remote URI's. + * MafwProxyPlaylist caches size and current index as much as possible. + * dh_shlibdeps commented in debian/rules. + + -- Mika Tapojärvi Tue, 06 Apr 2010 13:29:47 +0300 + +qmafw-gst-renderer (0.0.1-31) unstable; urgency=low + + * Implemented: SWP#MMAFW-728 + * DRM fulfills the OVI service authentication (LKM) requirements. + * Moved LKM/CP stuff to common dir. + + -- Mika Tapojärvi Thu, 01 Apr 2010 09:18:29 +0300 + +qmafw-gst-renderer (0.0.1-30) unstable; urgency=low + + * Implemented: SW#MMAFW-2129 + * Implemented MafwGstRenderer property playback-speed. + * GstRenderer does not show the first frame when starting from certain point + in video media. + + -- Mika Tapojärvi Wed, 24 Mar 2010 07:47:26 +0200 + +qmafw-gst-renderer (0.0.1-29) unstable; urgency=low + + * Implemented: SWP#MMAFW-2114 + * Implemented: SWP#MMAFW-2137 + * Video pause frame must not be scaled in MAFW. + * MafwRenderer pauseAt addition plus bunch of changes. + + -- Mika Tapojärvi Mon, 22 Mar 2010 07:04:25 +0200 + +qmafw-gst-renderer (0.0.1-28) unstable; urgency=low + + * Implemented: SWP#MMAFW-2137 + * RHL: Video pause frame must not be scaled in MAFW + + -- Mika Tapojärvi Thu, 18 Mar 2010 15:24:05 +0200 + +qmafw-gst-renderer (0.0.1-27) unstable; urgency=low + + * Fixes: NB#160986 - qmafw-gst-renderer Disappears on attempting to play. + * Added the build dependency needed by libplayready0 + + -- Mika Tapojärvi Wed, 17 Mar 2010 13:57:44 +0200 + +qmafw-gst-renderer (0.0.1-26) unstable; urgency=low + + * Fixes: NB#159904 - libqmafw-gst-renderer depends on libosso1 + * Gst renderer use QmSystem instead of libosso in screen blanking prevention. + + -- Mika Tapojärvi Wed, 17 Mar 2010 06:58:27 +0200 + +qmafw-gst-renderer (0.0.1-25) unstable; urgency=low + + * Fixes: NB#158438 - Playback of the next clip does not happen after the DRM licence fetch error dialog is displayed. + * GstRenderer can be issued pause command quickly after play command has been + issued. + * Added clearing of the worker->is_error after drm check failure. As the + worker was exited, the is_error state wasn't handled in anyway later on. + * Removed unnecessary libosso from gst renderer's .pro file. + + -- Mika Tapojärvi Mon, 15 Mar 2010 10:13:50 +0200 + +qmafw-gst-renderer (0.0.1-24) unstable; urgency=low + + * Changed the initialisation test so that the default policy assignment + always fails. + * Even if it fails always, it doesn't affect the rest of the tests in anyway. + Just gives us more complete unittest. + + -- Mika Tapojärvi Mon, 08 Mar 2010 15:42:57 +0200 + +qmafw-gst-renderer (0.0.1-23) unstable; urgency=low + + * Implemented: SWP#MMAFW-2053 + * Implemented: SWP#MMAFW-871 + * Fixes: NB#156704 - Youtube playback_Play/Pause toggle gets reset on a seek operation + * Policy mgmt in qmafw-gst-renderer. + * Removed renderer error handling from state-machine. Now gst-renderer goes + into STOPPED state if there is an error that requires that. Updated + MafwRendererStateMachine unittest. + * Fixed coverity findings. + + -- Mika Tapojärvi Thu, 04 Mar 2010 15:16:11 +0200 + +qmafw-gst-renderer (0.0.1-22) unstable; urgency=low + + * Implemented: SWP#MMAFW-1964 + * Fixes: NB#158196 - Pausing the video right after playback starts will put renderer to invalid state + * If pause comes during seeking, now it is performed after the seek is + completed. + * MafwBasicRenderer has readonly property for policy override. + * New test.suppression files for valgrind. + + -- Mika Tapojärvi Mon, 01 Mar 2010 18:26:17 +0200 + +qmafw-gst-renderer (0.0.1-21) unstable; urgency=low + + * Implemented: SWP#MMAFW-2100 + * GST renderer publishing media duration to context framework. + + -- Mika Tapojärvi Mon, 22 Feb 2010 20:39:08 +0200 + +qmafw-gst-renderer (0.0.1-20) unstable; urgency=low + + * Unittests pass rate to 100% for mafw-gst-renderer. + * CI test and unittest for getCurrentMediaInfo. + + -- Mika Tapojärvi Thu, 18 Feb 2010 21:43:24 +0200 + +qmafw-gst-renderer (0.0.1-19) unstable; urgency=low + + * Implemented: SWP#MMAFW-1827 + * Implemented: SWP#MMAFW-1898 + * Fixes: NB#155284 - Tapping on the Player View - View Menu - Play Album stops the playback of the current playing song. + * Fixes: NB#155820 - Renderer goes into Stopped state after automatic next instead of Transitioning state. + * Only necessary headers are exported. + * MafwInMemoryPlaylist updates the current index based on the changes in the + playlist. + * MafwBasicRenderer also acts better to changes in the playlist contents. + * Removed the "fixes" statements from the changelog, because of current + problems in integration systems. + * Renderer goes into Stopped state after automatic next instead of + Transitioning state. + * Implemented MafwRenderer::getCurrentMediaInfo(). + + -- Mika Tapojärvi Tue, 09 Feb 2010 21:18:53 +0200 + +qmafw-gst-renderer (0.0.1-18) unstable; urgency=low + + * Non-maintainer upload. + * Version increased. + + -- Toni Mäki Mon, 08 Feb 2010 09:39:31 +0200 + +qmafw-gst-renderer (0.0.1-17) unstable; urgency=low + + * Bug 155343 removed - Last entry of a playlist plays twice when it comes to focus by 'Next' function + * context provider DBus name fixed not to conflict with MAFW plugin DBus name. + * Replace/Remove unnecessary includes. + + -- Mika Tapojärvi Wed, 03 Feb 2010 15:16:30 +0200 + +qmafw-gst-renderer (0.0.1-16) unstable; urgency=low + + * Version increased. + + -- Mika Tapojärvi Tue, 02 Feb 2010 10:22:49 +0200 + +qmafw-gst-renderer (0.0.1-15) unstable; urgency=low + + * Removing added renederer from registry at GstRenderer plugin destructor. + * implemented provider for context framework core property Media.NowPlaying + * provider for old context framework properties removed + * Versions increased. + * Maintainer and Standards-Version updated. + + -- Mika Tapojärvi Tue, 02 Feb 2010 10:08:24 +0200 + +qmafw-gst-renderer (0.0.1-14) unstable; urgency=low + + * Version increased. + + -- Mika Tapojärvi Wed, 27 Jan 2010 15:40:40 +0200 + +qmafw-gst-renderer (0.0.1-13) unstable; urgency=low + + * Version increased. + * Rebuild. + + -- Mika Tapojärvi Tue, 26 Jan 2010 12:39:48 +0200 + +qmafw-gst-renderer (0.0.1-12) unstable; urgency=low + + * MafwRenderer can be given a parent. + * MafwRenderer API Harmonization step1. Both scenarios supported with or + without callback slots. + + -- Mika Tapojärvi Mon, 25 Jan 2010 09:22:23 +0200 + +qmafw-gst-renderer (0.0.1-11) unstable; urgency=low + + * Mafw-Gst-renderer returns 0 for getPosition() when gstreamer isn't playing + or paused. + * Renderer property API tests for gst-renderer. + + -- Mika Tapojärvi Thu, 21 Jan 2010 15:18:07 +0200 + +qmafw-gst-renderer (0.0.1-10) unstable; urgency=low + + * Non-maintainer upload. + * Version increased. + + -- Toni Mäki Tue, 19 Jan 2010 08:29:28 +0200 + +qmafw-gst-renderer (0.0.1-9) unstable; urgency=low + + * Version increased. + + -- Mika Tapojärvi Mon, 18 Jan 2010 13:42:48 +0200 + +qmafw-gst-renderer (0.0.1-8) unstable; urgency=low + + * Mostly editorial fixes based on code review. + + -- Mika Tapojärvi Fri, 15 Jan 2010 13:24:47 +0200 + +qmafw-gst-renderer (0.0.1-7) unstable; urgency=low + + * Non-maintainer upload. + * Version increased after release. + + -- Toni Mäki Fri, 15 Jan 2010 08:57:03 +0200 + +qmafw-gst-renderer (0.0.1-6) unstable; urgency=low + + * Fixes: NB#151525 - qmafw fails to build with cs2009q1 toolchain + * Play URI implemented in renderer state-machine. + * Increased the version numbers for unstable repo delivery. + * Next & previous will wrap in first and last item respectively. + * qmafw gst renderer added libqttracker-dev to build-depends. + * qmafw gst renderer include path change did not help undo. + * good GStreamer error mapping. + * qmafw gst renderer's QtTracker includepath. + * gst renderer usageCounter and contentAccessed update. + * Error signal from renderer now goes all the way through to MTG + * Various changes to Renderer CI and unittests because of new + qmafw-gst-renderer and changed playlist API. + * setting global_drm_uri to NULL in init(). + * context framework fixes. + * MafwRenderer can now signal that is doesn't have a playlist to play, via + playlistChanged signal. + * Added seek functionality to MafwBasicRenderer, with additional fixes to URL + handling. Was doubly encoded sometimes. + * Changes after the updated toolchain. + * Also some changes after the playlist sorting API. + * better drm testing. + * added gettersTestCase and improved coverage. + * added resumeDelayedTestCase. + * merged mafw-gst-renderer from branch to trunk. + * merged drm stuff from fmafw trunk gst-renderer. + + -- Mika Tapojärvi Tue, 12 Jan 2010 09:08:17 +0200 + +qmafw-gst-renderer (0.0.1-5) unstable; urgency=low + + * Non-maintainer upload. + * Version increased. + + -- Toni Mäki Fri, 08 Jan 2010 11:14:06 +0200 + +qmafw-gst-renderer (0.0.1-4) unstable; urgency=low + + * Version increased. + + -- Toni Mäki Thu, 07 Jan 2010 11:28:58 +0200 + +qmafw-gst-renderer (0.0.1-3) unstable; urgency=low + + * Version increased. + + -- Toni Mäki Wed, 23 Dec 2009 11:53:04 +0200 + +qmafw-gst-renderer (0.0.1-2) unstable; urgency=low + + * compiled with new toolchain + * Non-maintainer upload. + * Version increased. + + -- Toni Mäki Mon, 21 Dec 2009 15:15:34 +0200 + +qmafw-gst-renderer (0.0.1-1) unstable; urgency=low + + * Initial release + + -- Seppo Yliklaavu Tue, 27 Oct 2009 11:01:57 +0200 + diff --git a/qmafw-gst-subtitles-renderer/debian/compat b/qmafw-gst-subtitles-renderer/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/compat @@ -0,0 +1 @@ +5 diff --git a/qmafw-gst-subtitles-renderer/debian/control b/qmafw-gst-subtitles-renderer/debian/control new file mode 100644 index 0000000..61b45c2 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/control @@ -0,0 +1,30 @@ +Source: qmafw-gst-subtitles-renderer +Section: debug +Priority: extra +Maintainer: Roman Moravcik +XSBC-Original-Maintainer: Mika Tapojarvi +Build-Depends: debhelper (>= 4), libqmafw0-dev, libglib2.0-dev, + libgstreamer0.10-dev (>= 0.10.32.2), libgq-gconf-dev, + libgstreamer-plugins-base0.10-dev (>= 0.10.28.3), + libqmsystem2-dev,libcontextprovider-dev, + libqtsparql-dev, libcontextsubscriber-dev, + libdbus-qeventloop-dev, libtotem-plparser-dev, usb-moded-dev, + pkg-config +Standards-Version: 3.8.0 +Homepage: http://mafwsubrenderer.garage.maemo.org/ +Vcs-Browser: https://garage.maemo.org/plugins/ggit/browse.php/?p=mafwsubrenderer +Vcs-Git: https://vcs.maemo.org/git/mafwsubrenderer + +Package: libqmafw-gst-subtitles-renderer +Architecture: any +Depends: ${shlibs:Depends}, libqtsparql0, libqtsparql-tracker, libdbus-qeventloop1, gstreamer0.10-plugins-bad (>= 0.10.21), gstreamer0.10-plugins-base-subtitles (>= 0.10.34-0maemo1+0m6) +Replaces: qmafw-gst-renderer +Description: QMAFW GStreamer renderer with subtitles support + GStreamer based renderer plugin for QMAFW. + +Package: libqmafw-gst-subtitles-renderer-dbg +Architecture: any +Depends: libqmafw-gst-subtitles-renderer (= ${binary:Version}) +Priority: extra +Description: Debug symbols for QMAFW GStreamer renderer with subtitles support + Debug symbols for QMAFW GStreamer renderer, makes debugging fun. diff --git a/qmafw-gst-subtitles-renderer/debian/copyright b/qmafw-gst-subtitles-renderer/debian/copyright new file mode 100644 index 0000000..269555d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/copyright @@ -0,0 +1,3 @@ +Copyright (C) 2009 Nokia Corporation. All rights reserved. + +Contact: Visa Smolander diff --git a/qmafw-gst-subtitles-renderer/debian/dirs b/qmafw-gst-subtitles-renderer/debian/dirs new file mode 100644 index 0000000..6845771 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/dirs @@ -0,0 +1 @@ +usr/lib diff --git a/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.install b/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.install new file mode 100644 index 0000000..6b70264 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.install @@ -0,0 +1,4 @@ +usr/lib/qmafw-plugin/* +usr/share/dbus-1/services/* +usr/share/contextkit/providers/* +usr/share/qmafw/* diff --git a/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.postinst b/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.postinst new file mode 100644 index 0000000..56b8eb4 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/libqmafw-gst-subtitles-renderer.postinst @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +chmod 444 /usr/share/qmafw/mafw-gst-renderer-plugin.conf diff --git a/qmafw-gst-subtitles-renderer/debian/rules b/qmafw-gst-subtitles-renderer/debian/rules new file mode 100755 index 0000000..b681d05 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/debian/rules @@ -0,0 +1,98 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + +APPNAME = qmafw-gst-subtitles-renderer + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + MODE=debug +else + MODE=release +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + qmake PREFIX=/usr MODE=$(MODE) $(APPNAME).pro && $(MAKE) + + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #docbook-to-man debian/qmafw-gst-renderer.sgml > qmafw-gst-renderer.1 + + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -rm -f debian/build-stamp + [ ! -f Makefile ] || $(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/app_name + $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(APPNAME) install + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_install -a --sourcedir=debian/$(APPNAME) +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_python +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link + dh_strip --dbg-package=libqmafw-gst-subtitles-renderer-dbg + dh_compress + dh_fixperms +# dh_perl + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/qmafw-gst-subtitles-renderer/inc/MafwBlankingPreventer.h b/qmafw-gst-subtitles-renderer/inc/MafwBlankingPreventer.h new file mode 100644 index 0000000..14bf085 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwBlankingPreventer.h @@ -0,0 +1,57 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFW_BLANKING_PREVENTER_H +#define MAFW_BLANKING_PREVENTER_H + +#include +#include + +namespace MeeGo +{ + class QmDisplayState; +}; + +/** + * Helper class for preventing screen blanking. + */ +class MafwBlankingPreventer : public QObject +{ + Q_OBJECT + +public: + MafwBlankingPreventer(QObject* parent); + + /** + * Disable screen blanking. + */ + void blankingProhibit(); + + /** + * Enable screen blanking. + */ + void blankingAllow(); + +private Q_SLOTS: + void refresh(); + +private: + QTimer m_refreshTimer; + MeeGo::QmDisplayState *m_display; +}; + +#endif // MAFW_BLANKING_PREVENTER_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRenderer.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRenderer.h new file mode 100644 index 0000000..9e3fcb0 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRenderer.h @@ -0,0 +1,508 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFW_GSTRENDERER_INTERFACE_H +#define MAFW_GSTRENDERER_INTERFACE_H + +#include "mafw-gst-renderer-worker.h" +#include "MafwGstRendererHaltState.h" + +#include +#include +#include + +#include +#include + +class MafwBlankingPreventer; +class MafwGstRendererVolume; +class MafwGstRendererDolby; +class MafwGstRendererNetworkMonitor; +class ContextProperty; +class QDBusMessage; +class MafwGstRendererPlaylistFileUtility; +class MafwMmcMonitor; +class QSettings; +class MafwGstScreenshot; +class MafwGstRendererHaltState; + +class QSparqlConnection; +class QSparqlResult; + +/** + * Implements MAFW GStreamer renderer. + * @credential TrackerReadAccess Tracker read access + * @credential TrackerWriteAccess Tracker write access + * + */ +class MafwGstRenderer : public MafwBasicRenderer +{ + Q_OBJECT + +private: + /** + * Callback function that gets called when the GStreamer worker pipeline has + * gone to playing state. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + */ + static void playCallback(MafwGstRendererWorker *worker, gpointer owner); + + /** + * Callback function that gets called when the GStreamer worker pipeline has + * gone to paused state. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + */ + static void pauseCallback(MafwGstRendererWorker *worker, gpointer owner); + + /** + * Callback function that gets called when the GStreamer worker pipeline has + * reached EOS state. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + */ + static void eosCallback(MafwGstRendererWorker *worker, gpointer owner); + + /** + * Callback for informing when resources are no longer used in PAUSED state. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + */ + static void readyStateCallback(MafwGstRendererWorker *worker, gpointer owner); + + /** + * Callback function that gets called when the GStreamer worker signals an + * error. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + * @param error Pointer to signalled error + */ + static void errorCallback(MafwGstRendererWorker *worker, + gpointer owner, + const GError *error); + + /** + * Callback function that gets called when the GStreamer worker signals + * new metadata. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + * @param key Metadata key indicating what metadata is signalled + * @param type Type of signalled metadata + * @param value Pointer to actual metadata value + */ + static void metadataCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint key, + GType type, + gpointer value); + + /** + * Callback function that gets called when the GStreamer worker signals + * a (new) property value. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + * @param id ID indicating what property is signalled + * @param value Pointer to actual property value + */ + static void propertyCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint id, + GValue *value); + + /** + * Callback function that gets called when the GStreamer worker signals + * a status when it is buffering a stream. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instance of this class) + * @param percent Buffering percentage value + */ + static void bufferStatusCallback(MafwGstRendererWorker *worker, + gpointer owner, + gdouble percent); + + static void blankingControlCallback(MafwGstRendererWorker *worker, + gpointer owner, + gboolean prohibit); + + /** + * Callback funtion that gets called when we save new pause frame. + * @param worker Pointer to GStreamer worker instance + * @param owner Pointer to GStreamer worker owner (instence of this class) + * @param buffer Pointer to GstBuffer that contains pause frame data + * @param filename Location where the pause frame is saved + * @param cancel True if pause frame saving is canceled + */ + static void screenshotCallback(MafwGstRendererWorker *worker, + gpointer owner, + GstBuffer *buffer, + const char *filename, + gboolean cancel); + + /** + * Helper function to convert a GValue to a QVariant + * @param v Pointer to GValue to be converted + * @return QVariant holding the same value as the GValue held + */ + static QVariant getValue(const GValue *v); + + /** + * Mapping between GStreamer worker metadata vs mafw metadata + */ + static const QHash& metadataMap(); + + /** + * Mapping of obtained audio route to internal type + */ + static const QHash >& audioRouteMap(); + + /** + * Mapping of obtained video route to internal type + */ + static const QHash >& videoRouteMap(); + + /** + * Mapping between GStreamer worker errors vs mafw errors + */ + static const QHash& errorMap(); + +public: + + MafwGstRenderer(const QString& uuid, + const QString& pluginName, + const QString& name, + QObject* parent = 0); + /** + * Desctructor + */ + ~MafwGstRenderer(); + + /** + * Initializes the renderer. + * @param settings Settings to use for configuration + * @return True on success, false otherwise + */ + bool initialize(QSettings *settings); + +public: //MafwBasicRenderer implementation + + void doPlay(const MafwContent& content); + void doPlay(const MafwMediaInfo& mediaInfo); + + void doStop(); + + void doPause(); + + void doResume(); + + void doSeek(int position, MafwRenderer::SeekMode); + + bool doNextHint(const MafwContent& next); + bool doNextHint(const MafwMediaInfo& nextMediaInfo); + +public: // MafwRenderer implementation + bool getPosition(QObject* resultsReceiver, const char* resultsMember); + + bool setMafwProperty(const QString& name, const QVariant& value); + bool mafwProperty(QString& name, QObject* receiver, const char* member); + bool getCurrentMediaInfo(QObject* receiver, const char* member, const QString& metadataKey=0); + +private: //functionality + void playURI(const QString& uri); + void sendMediaInfo(const MafwMediaInfo& content, QObject* receiver, const char* member); + bool connectNameOwnerChanged(); + void setConfiguration(QSettings *settings); + QVariant readSettingsValue(QSettings *settings, const QString &valueName, + const QVariant &defaultValue) const; + /*Helper function for metadataCallback(). Appends related metadata to the result list for emitting metadataChanged().*/ + void appendRelatedMetadata(const QString key, QList* results); + void stampIt(const QString& node, int usageCount, int mediaDuration); + /** + * Helper function which sets the error code to be RendererError_UnsupportedResolution if + * resolution is above boundaries 720 x 1280, otherwise error code is to + * RendererError_UnsupportedResolution. + * @param error reference to error which code is set. + */ + void handleResolutionError(MafwError& error); + /** Helper function for creating a MafwError from GError */ + MafwError constructMafwError(const GError* error); + +private Q_SLOTS: + + /** + * Slot to call when the current playback position queried. + * @param resultsReceiver Pointer to object where to deliver result + * @param resultsMember Pointer to member where to deliver result + */ + void slotGetPosition(QObject* resultsReceiver, + const char* resultsMember); + + /** + * Slot to call when a property value is queried. + * @param name Property name to be queried + * @param receiver Pointer to object where to deliver result + * @param member Pointer to member where to deliver result + */ + void slotMafwProperty(const QString& name, QObject* receiver, const char* member); + + /** + * Store usageCounter and contentAccessed properties of currently playing media to Tracker. + */ + void slotStamp(); + + /** + * Slot to call when stampit has finished. + */ + void slotStampItDone(); + + /** + * usageCounter query ready in play uri case + */ + void slotStampQueryReady(); + + /** + * Commands the next URI to be played. + */ + void playNext(); + + /** + * Tries to play the next URI from the given playlist URI. If no next + * URI commands playNext() + */ + void playNextURIFromPlaylist(); + + /** + * Slot to call asynchronously to restart playback + * (e.g. when internet radio disconnect due to network issues) + */ + void restartPlay(); + + /** + * Query metadata from currently played clip or stream. + */ + void slotGetCurrentMediaInfo(QObject* receiver, const char* member, const QString& metadataKey); + + /** + * Called when volume has been changed. + */ + void handleVolumeChange(uint level); + + /** + * Slot called when audio/video route context framework property changes. + */ + void slotRouteChanged(); + + /** + * Called when a property has been changed. + */ + void handlePropertyChanged(const QString& name, const QVariant& value); + + /** + * Called when Dolby Headphones Mobile music property has been changed. + */ + void handleDHMMusicPropertyChanged(); + + /** + * Called when Dolby Headphones Mobile video property has been changed. + */ + void handleDHMVideoPropertyChanged(); + + /** + * Handle NameOwnerChanged signal of policy-context-daemon. + */ + void handleContextProviderRemoval( const QDBusMessage& message ); + + /** + * Starts playing playlist file. This is called when parsing has been done. + */ + void startPlayingPlaylistFile(); + + /** + * Handles the errors occured while parsing playlist file. + * @param succeeded true if no errors occured. + */ + void handlePlaylistFileParsingErrors(bool succeeded); + + /** + * Stops streaming if necessary + */ + void stopStreaming(); + + /** + * Halts streaming if necessary, stores the needed info for future reference (@see MafwGstRenderer::continueStreaming()) + */ + void haltStreaming(); + + /** + * Continues streaming + */ + void continueStreaming(); + + /** + * Any timers e.g. playlist file util & stamping timers will be stopped here + */ + void stopTimers(); + + /** + * Called when new pause frame is ready or + * when there was error with pause frame encoding. + */ + void handleScreenshot(char *location, GError *error); + + /** + * Called when pause frame is cancelled. + */ + void cancelScreenshot(); + + /** + * MMC going to be unmounted. + */ + void mmcPreUnmount(); + +Q_SIGNALS: + void signalGetPosition(QObject* resultsReceiver, + const char* resultsMember); + + void signalMafwProperty(const QString& name, QObject* receiver, + const char* member); + + void signalGetCurrentMediaInfo(QObject*, const char*, const QString); + +private: //data + + /** + * Has this instance been initialized? + */ + bool m_initialized; + + /** + * Helps determining whether to request a new item to play + */ + MafwRenderer::State m_currentState; + + /** + * The next Content to play, if any. + */ + MafwMediaInfo m_nextContent; + + /** + * The currently to be played Content + */ + MafwMediaInfo m_currentContent; + + QMap > m_currentMetaData; + + /** + * What item is the renderer currently playing? + */ + MafwRendererPlayingUri m_playingItem; + + /** + * GStreamer renderer worker + */ + MafwGstRendererWorker *m_worker; + + /** + * Timer for stamping media usageCount and contentAccessed + */ + QTimer m_playedStampTimer; + + MafwBlankingPreventer* m_blankingPreventer; + + MafwGstScreenshot* m_screenshot; + + /** + * Help to monitor network access + */ + MafwGstRendererNetworkMonitor *m_networkMonitor; + + /** + * "Halt" state to store state when changing network access point + */ + MafwGstRendererHaltState m_haltState; + + /** + * Object to handle volume + */ + MafwGstRendererVolume* m_volume; + + /** + * Object to handle Dolby Headphones Mobile plugin + */ + MafwGstRendererDolby* m_dolby; + + /** + * Context framework property for video route + */ + ContextProperty *m_videoRoute; + + /** + * Context framework property for audio route + */ + ContextProperty *m_audioRoute; + + /** + * Is contentAccessed and usageCount of current playing item already updated. (Update process has started) + */ + bool m_playedStamped; + int m_playedStampTryCounter; + + /** + * Used to stamp usageCount and updated duration + */ + QSparqlConnection *m_sparqlConnection; + /** + * If playing just an URI this result is used to get the tracker urn for it + */ + QSparqlResult *m_urnQueryResult; + + /** + * Result handle for stampit actions + */ + QSparqlResult *m_stampItResult; + + /** + * Pointer to playlist file parsing utility + */ + MafwGstRendererPlaylistFileUtility* m_playlistFileUtil; + + /** + * Timer to try to play next item from given playlist URI, totem parser can be slow sometimes. + */ + QTimer m_playlistNextTimer; + + /** + * Flag indicating whether we are playing playlist file. + */ + bool m_playingPlaylistFile; + + /** + * The error we got when we have possibly tried gstreamer to play playlist file. + */ + GError* m_unsupportedTypeError; + + /** + * Flag indicating whether we have already played an item from URI playlist. + * I.e. an URI was given which points to a playlist, this flag + * tells if rendererPlaying() signal has already been sent for URI. + */ + bool m_playedPlaylistItem; + + MafwMmcMonitor* m_mmcMonitor; +}; + +#endif // MAFW_GSTRENDERER_INTERFACE_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererDolby.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererDolby.h new file mode 100644 index 0000000..6382000 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererDolby.h @@ -0,0 +1,81 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWGSTRENDERERDOLBY_H +#define MAFWGSTRENDERERDOLBY_H + +#include +#include + +/** + * Provides volume setting, getting and listening functionality using + * PulseAudioMainVolume DBus API. + */ +class MafwGstRendererDolby : public QObject +{ + Q_OBJECT +public: + /** + * Constructor + */ + MafwGstRendererDolby( QObject* parent ); + ~MafwGstRendererDolby(); + void initialize(); + bool setMusicDolbyState (uint value); + bool setMusicDolbyRoom (int value); + bool setMusicDolbyColor (int value); + uint getMusicDolbyState (); + int getMusicDolbyRoom (); + int getMusicDolbyColor (); + bool setVideoDolbyState (uint value); + bool setVideoDolbyRoom (int value); + bool setVideoDolbyColor (int value); + uint getVideoDolbyState (); + int getVideoDolbyRoom (); + int getVideoDolbyColor (); + +Q_SIGNALS: + /** + * Signal telling that music surround is OFF/ON/AUTO. + */ + void mafwDHMMusicPropertyChanged(); + /** + * Signal telling that video surround is OFF/ON/AUTO. + */ + void mafwDHMVideoPropertyChanged(); + +private Q_SLOTS: + void valueMusicChanged(); + void valueVideoChanged(); + +private: + uint m_currentMusicDolbyState; + int m_currentMusicDolbyRoom; + int m_currentMusicDolbyColor; + uint m_currentVideoDolbyState; + int m_currentVideoDolbyRoom; + int m_currentVideoDolbyColor; + + GConfItem *m_dolbyConfMusic; + GConfItem *m_dolbyConfMusicRoom; + GConfItem *m_dolbyConfMusicColor; + GConfItem *m_dolbyConfVideo; + GConfItem *m_dolbyConfVideoRoom; + GConfItem *m_dolbyConfVideoColor; +}; + +#endif // MAFWGSTRENDERERDOLBY_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererHaltState.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererHaltState.h new file mode 100644 index 0000000..d7168d1 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererHaltState.h @@ -0,0 +1,83 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWGSTRENDERERHALTSTATE_H +#define MAFWGSTRENDERERHALTSTATE_H + +#include + +#include + +class MafwGstRendererHaltState : public QObject +{ + Q_OBJECT +public: + static int DECAY_TIME; +public: + MafwGstRendererHaltState(); + MafwGstRendererHaltState(const QString &uri, MafwRenderer::State state, int position); + ~MafwGstRendererHaltState(); + + /** + * Assigns other halt state to this object, also resets the decay timer. + */ + MafwGstRendererHaltState(const MafwGstRendererHaltState &other); + + /** + * Assigns other halt state to this object, also resets the decay timer. + */ + MafwGstRendererHaltState& operator =(const MafwGstRendererHaltState &other); + + + /** + * Set new renderer state for halt state, user pressed pause etc + * @param newState, if newState is MafwRenderer::Paused the decay time is paused also + */ + void setState(MafwRenderer::State newState); + + /** + * Is the halt state valid? Not decayed and contains relevenat information + */ + bool isSet() const; + + /** + * Clears the halt state from any valid content, also stop the decay timer + */ + void clear(); + + QString uri() const; + MafwRenderer::State state() const; + int position() const; + +Q_SIGNALS: + /** + * This signal is emitted when the MafwGstRendererHaltState::DECAY_TIME has passed + * from object creation or when valid parameters were assigned to it. + */ + void decayed(); + +private: + void initializeDecayTimer(); + +private: + QString m_uri; + MafwRenderer::State m_state; + int m_position; + QTimer m_decayTimer; +}; + +#endif // MAFWGSTRENDERERHALTSTATE_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererNetworkMonitor.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererNetworkMonitor.h new file mode 100644 index 0000000..48a345f --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererNetworkMonitor.h @@ -0,0 +1,45 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWGSTRENDERERNETWORKMONITOR_H +#define MAFWGSTRENDERERNETWORKMONITOR_H + +#include +#include + +class QNetworkConfigurationManager; +class MafwGstRendererNetworkMonitor : public QObject +{ + Q_OBJECT + +public: + MafwGstRendererNetworkMonitor(); + virtual ~MafwGstRendererNetworkMonitor(); + +Q_SIGNALS: + void prepareNetworkChange(); + void networkChangeFinished(); + +private Q_SLOTS: + void handleConfigurationChange(const QNetworkConfiguration & config); + +private: + QNetworkConfigurationManager *m_networkManager; + QNetworkConfiguration m_currentConfiguration; +}; + +#endif // MAFWGSTRENDERERNETWORKMONITOR_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlaylistFileUtility.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlaylistFileUtility.h new file mode 100644 index 0000000..3e5bb76 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlaylistFileUtility.h @@ -0,0 +1,94 @@ +#ifndef MafwGstRendererPlaylistFileUtility_H +#define MafwGstRendererPlaylistFileUtility_H + +#include +#include +#include +#include + +class QUrl; + +/** + * Utility class for parsing playlist files. + */ +class MafwGstRendererPlaylistFileUtility : public QObject +{ + Q_OBJECT +public: + /** + * Constructor + */ + MafwGstRendererPlaylistFileUtility(QObject* parent); + + /** + * Destructor + */ + ~MafwGstRendererPlaylistFileUtility(); + + /** + * Returns the parsed URI list + * @return list of parsed URIs + */ + QStringList getUriList(); + + /** + * Starts playlist file parsing, parsingReady is signalled when parsing + * has been done. Parsed uris can be fetched using getUri() function. + * @param uri The absolute uri to the playlist file. + */ + void parsePlaylistFile(const QUrl& uri); + + /** + * Removes the first unused uri parsed from playlist and returns it. + * @return The first unused playlist uri or empty string if each uris are + * used or parsing has been failed. + */ + QString takeFirstUri(); + + /** + * Saves the pending error that will be fired, if no new URI's are found. + * This error saving feature is needed because we don't get the proper + * "parsing ended" signals from Totem playlist parser. + * @param error The error to be saved. + */ + void setPendingError(MafwError& error); + + /** + * Returns the saved error. + * @return The saved error. + */ + MafwError takePendingError(); + +Q_SIGNALS: + /** Signal telling that first uri on playlist file is parsed. */ + void firstItemParsed(); + /** Signal telling that parsing is ready. */ + void parsingReady(bool succeeded); + +private: + static void readyCb(TotemPlParser* parser, + GAsyncResult *async_result, + MafwGstRendererPlaylistFileUtility* self); + static void uriParsed(TotemPlParser *parser, + gchar* uri, + gpointer metadata, + MafwGstRendererPlaylistFileUtility* self); + +private: + /** Modifies the resulting item URI if necessary. + * Unfortunately there are various reasons why this is required. + */ + QString manHandleURI(const QString &itemUri) const; + +private: + /** Unique id (=pointer) of currently used parser. */ + TotemPlParser* m_parserId; + /** The list of parsed uris. */ + QStringList m_uriList; + /** Parsing the first item */ + bool m_firstItem; + /** The pending error */ + MafwError m_pendingError; +}; + +#endif // MafwGstRendererPlaylistFileUtility_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlugin.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlugin.h new file mode 100644 index 0000000..05863aa --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererPlugin.h @@ -0,0 +1,58 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFW_GST_RENDERER_PLUGIN_H +#define MAFW_GST_RENDERER_PLUGIN_H + +#include +#include + +class MafwGstRendererPlugin : public QObject, public MafwPlugin +{ + Q_OBJECT + Q_INTERFACES(MafwPlugin) + +public: + void initialize(MafwInternalRegistry* registry); + ~MafwGstRendererPlugin(); + + QString name() const; + +protected: + MafwInternalRegistry* m_registry; + +private: + QList m_rendererIds; + + /** + * Loads gst-renderers from config file. + * Config file contais "renderers" and "in-process-renderers" arrays. + * Renderer Array contains gst-renderer's id and it's "friendly" name. + * Syntax of the "renderers" array: + * [renderers] + * 1\Id=mafw_gst_renderer + * 1\FriendlyName=MafwGstRenderer + * 2\Id=mafw_gst_internal_video_renderer + * 2\FriendlyName=MafwGstVideoRenderer + * size=2 + * If config file is deleted of empty we create default renderer with "mafw_gst_renderer" uuid. + **/ + void loadRenderers(const QString& rendererArrayKey); + +}; + +#endif diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstRendererVolume.h b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererVolume.h new file mode 100644 index 0000000..47d415d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstRendererVolume.h @@ -0,0 +1,97 @@ +#ifndef MAFWGSTRENDERERVOLUME_H +#define MAFWGSTRENDERERVOLUME_H + +#include + +class DBusConnection; +class DBusMessage; +class DBusPendingCall; +class DBusMessageIter; +class DBusPendingCall; + +/** + * Provides volume setting, getting and listening functionality using + * PulseAudioMainVolume DBus API. + */ +class MafwGstRendererVolume : public QObject +{ + Q_OBJECT +public: + /** + * Constructor + */ + MafwGstRendererVolume(); + ~MafwGstRendererVolume(); + + /** + * Get the volume level. Initial volume level is always got via volumeChanged signal. + * Before that signal returns always 0. + * @return The current volume level. Value is between 0 to 99. + */ + uint getVolume(); + + /** + * Set the volume level to pulse audio. + * @note Volume setting happens asynchronously + * and may wait until dbus connection to pulse audio is ready. + * @param The volume level to be set. Valid value range is between 0 to 99. + * @return true on success. + */ + bool setVolume (uint value); + +Q_SIGNALS: + /** + * Signal telling that volume level has been changed. + */ + void volumeChanged(uint newLevel); + +private Q_SLOTS: + /** Makes p2p dbus connection to pulse audio. */ + void connectToPulseAudio(); + +private: + /** + * Starts to listen signal from PulseAudioMainVolume DBus API + */ + void listenVolumeSignals(); + + /** + * Get the step configuration asynchronously from PulseAudioMainVolume + */ + void getRestoreEntryForMediaRole(); + + /** + * Catch signals from PulseAudioMainVolume telling that volume step configuration has been changed + */ + static void handleIncomingMessages( DBusConnection* conn, + DBusMessage* message, + MafwGstRendererVolume* self); + + /** + * Catch reply callback for step configuration request from PulseAudioMainVolume. + */ + static void getEntryReply(DBusPendingCall *pending, MafwGstRendererVolume *self); + + static void volumeReply(DBusPendingCall *pending, MafwGstRendererVolume *self); + + bool readVolumeFromStruct(DBusMessageIter *iterator); + +private: + /** The current volume step, values are between 0, used maximum volume level */ + uint m_currentVolume; + + /** The volume step which is pending to be set. */ + uint m_pendingVolumeValue; + + /** The dbus connection object */ + DBusConnection* m_dbusConnection; + + QString m_objectPath; + + /** The pending call. */ + DBusPendingCall* m_pendingCall; + + +}; + +#endif // MAFWGSTRENDERERVOLUME_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwGstScreenshot.h b/qmafw-gst-subtitles-renderer/inc/MafwGstScreenshot.h new file mode 100644 index 0000000..a032c04 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwGstScreenshot.h @@ -0,0 +1,55 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWGSTSCREENSHOT_H +#define MAFWGSTSCREENSHOT_H + +#include +#include + +class MafwGstScreenshot : public QObject +{ + Q_OBJECT +public: + MafwGstScreenshot(QObject* parent); + ~MafwGstScreenshot(); + + bool savePauseFrame(GstBuffer *buffer, const char *filename); + void cancelPauseFrame(); + bool reportBack(GError *error); + +private: + /* All GStreamer elements are owned by m_pipeline. + Elements are destroyed when m_pipeline is destroyed.*/ + GstElement *m_src; + GstElement *m_sink; + GstElement *m_pipeline; + GstElement *m_filter; + GstElement *m_enc; + GstElement *m_csp; + GstBus *m_bus; + GstCaps *m_caps; + GstStructure *m_structure; + + gulong m_handler_id; + +Q_SIGNALS: + void screenshotCancelled(); + void screenshotTaken(char *location, GError *error); +}; + +#endif // MAFWGSTSCREENSHOT_H diff --git a/qmafw-gst-subtitles-renderer/inc/MafwMmcMonitor.h b/qmafw-gst-subtitles-renderer/inc/MafwMmcMonitor.h new file mode 100644 index 0000000..8c65055 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/MafwMmcMonitor.h @@ -0,0 +1,59 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFW_MMC_MONITOR_H +#define MAFW_MMC_MONITOR_H + +#include + +#include + +/** + * Helper class for MMC state. + */ +class MafwMmcMonitor : public QObject +{ + Q_OBJECT + +public: + static const QString MMC_URI_PREFIX; + + MafwMmcMonitor(QObject* parent); + ~MafwMmcMonitor(); + bool isMounted(); + +Q_SIGNALS: + void preUnmount(); + +private: + static void unmountEvent(GVolumeMonitor* mon, + GMount* event, + gpointer userData); + static void mountEvent(GVolumeMonitor* mon, + GMount* event, + gpointer userData); + static bool isMyDocs(GMount* mount); + +private Q_SLOTS: + void preUnmountEvent(const QString &state); + +private: + GVolumeMonitor* m_gVolMonitor; + bool m_mounted; +}; + +#endif // MAFW_MMC_MONITOR_H diff --git a/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-seeker.h b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-seeker.h new file mode 100644 index 0000000..9010111 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-seeker.h @@ -0,0 +1,43 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWGSTRENDERERSEEKER_H +#define MAFWGSTRENDERERSEEKER_H + +#include + +G_BEGIN_DECLS + +typedef struct _MafwGstRendererSeeker MafwGstRendererSeeker; + + +MafwGstRendererSeeker* mafw_gst_renderer_seeker_new(); +void mafw_gst_renderer_seeker_set_pipeline(MafwGstRendererSeeker *seeker, GstElement *pipeline); +gboolean mafw_gst_renderer_seeker_seek_to(MafwGstRendererSeeker *seeker, gint64 seek_pos); + +/* + * Processes possible seek results. Check if position has changed correctly or enough, if not + * executes new seek operation on the pipeline element. + * @return The new seek request position or -1 if no new seek request is necessary. + */ +gint64 mafw_gst_renderer_seeker_process(MafwGstRendererSeeker *seeker); +void mafw_gst_renderer_seeker_cancel(MafwGstRendererSeeker *seeker); +void mafw_gst_renderer_seeker_free(MafwGstRendererSeeker *seeker); + +G_END_DECLS + +#endif // MAFWGSTRENDERERSEEKER_H diff --git a/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-utils.h b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-utils.h new file mode 100644 index 0000000..41e30eb --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-utils.h @@ -0,0 +1,38 @@ +/* + * This file is a part of MAFW + * + * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved. + * + * Contact: Visa Smolander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef MAFW_GST_RENDERER_UTILS_H +#define MAFW_GST_RENDERER_UTILS_H + +G_BEGIN_DECLS +#include +#include +#include "mafw-gst-renderer-worker.h" + +gboolean convert_utf8(const gchar *src, gchar **dst); +gboolean uri_is_stream(const gchar *uri); +gint remap_gst_error_code(const GError *error); + +char *uri_get_subtitle_uri(const char *uri); + +G_END_DECLS +#endif diff --git a/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-worker.h b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-worker.h new file mode 100644 index 0000000..592b67f --- /dev/null +++ b/qmafw-gst-subtitles-renderer/inc/mafw-gst-renderer-worker.h @@ -0,0 +1,382 @@ +/* + * This file is a part of MAFW + * + * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved. + * + * Contact: Visa Smolander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef MAFW_GST_RENDERER_WORKER_H +#define MAFW_GST_RENDERER_WORKER_H + +#include +G_BEGIN_DECLS +#include +#include +#include + +#include "mafw-gst-renderer-seeker.h" + +#define MAFW_GST_RENDERER_WORKER_READY_TIMEOUT 3 +#define MAFW_GST_RENDERER_MAX_TMP_FILES 5 + +enum { + WORKER_ERROR_PLAYBACK, + WORKER_ERROR_VIDEO_CODEC_NOT_FOUND, + WORKER_ERROR_AUDIO_CODEC_NOT_FOUND, + WORKER_ERROR_CODEC_NOT_FOUND, + WORKER_ERROR_UNSUPPORTED_TYPE, + WORKER_ERROR_UNABLE_TO_PERFORM, + WORKER_ERROR_CANNOT_SET_POSITION, + WORKER_ERROR_PLAYLIST_PARSING, + WORKER_ERROR_DRM_NO_LICENSE, + WORKER_ERROR_DRM_NOT_ALLOWED, + WORKER_ERROR_DRM_CLOCK_NOT_SET, + WORKER_ERROR_DRM_OTHER, + WORKER_ERROR_STREAM_DISCONNECTED, + WORKER_ERROR_INVALID_URI, + WORKER_ERROR_MEDIA_NOT_FOUND, + WORKER_ERROR_CORRUPTED_FILE, + WORKER_ERROR_TYPE_NOT_AVAILABLE, + WORKER_ERROR_UNKOWN, + WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE = 1000, +}; + +enum { + WORKER_METADATA_KEY_TITLE = 1, /* 1st must be non-zero! */ + WORKER_METADATA_KEY_ARTIST, + WORKER_METADATA_KEY_AUDIO_CODEC, + WORKER_METADATA_KEY_VIDEO_CODEC, + WORKER_METADATA_KEY_BITRATE, + WORKER_METADATA_KEY_ENCODING, + WORKER_METADATA_KEY_ALBUM, + WORKER_METADATA_KEY_GENRE, + WORKER_METADATA_KEY_TRACK, + WORKER_METADATA_KEY_ORGANIZATION, + WORKER_METADATA_KEY_RENDERER_ART_URI, + WORKER_METADATA_KEY_RES_X, + WORKER_METADATA_KEY_RES_Y, + WORKER_METADATA_KEY_VIDEO_FRAMERATE, + WORKER_METADATA_KEY_DURATION, + WORKER_METADATA_KEY_IS_SEEKABLE, + WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI, + WORKER_METADATA_KEY_URI +}; + +enum { + WORKER_PROPERTY_VOLUME, + WORKER_PROPERTY_MUTE, + WORKER_PROPERTY_AUTOPAINT, + WORKER_PROPERTY_COLORKEY, + WORKER_PROPERTY_XID, + WORKER_PROPERTY_RENDER_RECTANGLE, + WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE, + WORKER_PROPERTY_PLAYBACK_SPEED, + WORKER_PROPERTY_FORCE_ASPECT_RATIO +}; + +enum { + WORKER_OUTPUT_NULL, + WORKER_OUTPUT_BUILTIN_SPEAKERS, + WORKER_OUTPUT_FM_RADIO, + WORKER_OUTPUT_BLUETOOTH_AUDIO, + WORKER_OUTPUT_HEADPHONE_JACK, + WORKER_OUTPUT_BUILTIN_DISPLAY, + WORKER_OUTPUT_TVOUT +}; + +typedef struct _MafwGstRendererWorker MafwGstRendererWorker; + +typedef void (*MafwGstRendererWorkerNotifySeekCb)(MafwGstRendererWorker *worker, gpointer owner); +typedef void (*MafwGstRendererWorkerNotifyPauseCb)(MafwGstRendererWorker *worker, gpointer owner); +typedef void (*MafwGstRendererWorkerNotifyPlayCb)(MafwGstRendererWorker *worker, gpointer owner); +typedef void (*MafwGstRendererWorkerNotifyReadyStateCb)(MafwGstRendererWorker *worker, gpointer owner); +typedef void (*MafwGstRendererWorkerNotifyBufferStatusCb)(MafwGstRendererWorker *worker, gpointer owner, gdouble percent); +typedef void (*MafwGstRendererWorkerNotifyEOSCb)(MafwGstRendererWorker *worker, gpointer owner); +typedef void (*MafwGstRendererWorkerNotifyMetadataCb)(MafwGstRendererWorker *worker, gpointer owner, gint key, GType type, gpointer value); +typedef void (*MafwGstRendererWorkerNotifyErrorCb)(MafwGstRendererWorker *worker, gpointer owner, const GError *error); +typedef void (*MafwGstRendererWorkerNotifyPropertyCb)(MafwGstRendererWorker *worker, gpointer owner, gint id, GValue *value); +typedef void (*MafwGstRendererWorkerBlankingControlCb)(MafwGstRendererWorker *worker, gpointer owner, gboolean prohibit); +typedef void (*MafwGstRendererWorkerScreenshotCb)(MafwGstRendererWorker *worker, gpointer owner, GstBuffer *buffer, const char *filename, gboolean cancel); + +typedef enum { + SEEKABILITY_UNKNOWN = -1, + SEEKABILITY_NO_SEEKABLE, + SEEKABILITY_SEEKABLE, +} SeekabilityType; + +typedef enum { + DURATION_UNQUERIED = -2, + DURATION_INDEFINITE = -1 + /* other values are actual */ +} Duration; + +typedef struct { + gint x; + gint y; + gint width; + gint height; +} render_rectangle; + +/* This struct contains all configurable settings + update this and the conf file synchronously, plz + */ +typedef struct { + /* pipeline */ + gchar *asink; + gchar *vsink; + gint flags; + gint64 buffer_time; + gint64 latency_time; + gboolean autoload_subtitles; + gchar *subtitle_encoding; + gchar *subtitle_font; + + /* timers */ + guint milliseconds_to_pause_frame; + guint seconds_to_pause_to_ready; + + /* dhmmixer */ + gboolean use_dhmmixer; + struct { + guint state; + gint room; + gint color; + } mobile_surround_music; + struct { + guint state; + gint room; + gint color; + } mobile_surround_video; +} configuration; + +/* + * media: Information about currently selected media. + * location: Current media location + * length_nanos: Length of the media, in nanoseconds + * has_visual_content: the clip contains some visual content (video) + * video_width: If media contains video, this tells the video width + * video_height: If media contains video, this tells the video height + * seekable: Tells whether the media can be seeked + * par_n: Video pixel aspect ratio numerator + * par_d: Video pixel aspect ratio denominator + * owner: Owner of the worker; usually a MafwGstRenderer (FIXME USUALLY?) + * pipeline: Playback pipeline + * bus: Message bus + * state: Current playback pipeline state + * is_stream: Is currently playing media a stream + * muted: Is the audio muted + * eos: Has playback reached EOS already + * is_error: Has there been an error situation + * buffering: Indicates the buffering state + * prerolling: Indicates the prerolling state (NULL -> PAUSED) + * report_statechanges: Report state change bus messages + * current_volume: Current audio volume [0.0 .. 1.0], see playbin:volume + * async_bus_id: ID handle for GstBus + * buffer_probe_id: ID of the video renderer buffer probe + * seek_position: Indicates the pos where to seek, in seconds + * vsink: Video sink element of the pipeline + * asink: Audio sink element of the pipeline + * tsink: Text sink element of the pipeline + * xid: XID for video playback + * current_frame_on_pause: whether to emit current frame when pausing + */ +struct _MafwGstRendererWorker { + struct { + gchar *location; + gint64 length_nanos; + gboolean has_visual_content; + gint video_width; + gint video_height; + gdouble fps; + SeekabilityType seekable; + gint par_n; + gint par_d; + } media; + gpointer owner; + GstElement *pipeline; + + // Audio bin for Dolby Headphones Mobile plugin + GstElement *audiobin; + + GstBus *bus; + /* GStreamer state we are considering right now */ + GstState state; + gboolean is_stream; + gboolean muted; + /* we are handing eos or we did */ + gboolean eos; + /* if we are handling (or handled) and error */ + gboolean is_error; + /* pipeline is buffering */ + gboolean buffering; + /* pipeline is prerolling */ + gboolean prerolling; + /* stream is live and doesn't need prerolling */ + gboolean is_live; + /* if we have to stay in paused though a do_play was + * requested. Usually used when pausing in transitioning */ + gboolean stay_paused; + /* this variable should be FALSE while we are hiding state + * changed to the UI. This is that GStreamer can perform + * state_changes without us requiring it, for example, then + * seeking, buffering and so on and we have to hide those + * changes */ + gboolean report_statechanges; + guint async_bus_id; + gint seek_position; + guint ready_timeout; + guint duration_seek_timeout; + guint duration_seek_timeout_loop_count; + /* TRUE when a transition to GST_STATE_READY has been + * requested or we are actually in GST_STATE_READY (requested + * by us) */ + gboolean in_ready; + /* Flag indicating whether taking image from pause frame has succeed after pause. */ + gboolean pause_frame_taken; + guint pause_frame_timeout; + GstBuffer *pause_frame_buffer; + GstElement *vsink; + GstElement *asink; + GstElement *tsink; + + // Dolby Headphones Mobile mixer + GstElement *amixer; + + XID xid; + render_rectangle x_overlay_rectangle; + gboolean autopaint; + gfloat playback_speed; + gboolean force_aspect_ratio; + gint colorkey; + GPtrArray *tag_list; + GHashTable *current_metadata; + gpointer context_nowplaying; + + gboolean current_frame_on_pause; + gboolean taking_screenshot; + gchar *tmp_files_pool[MAFW_GST_RENDERER_MAX_TMP_FILES]; + guint8 tmp_files_pool_index; + + GSList *destinations; + + GstElement *queue; + + configuration *config; + + MafwGstRendererSeeker *seeker; + + /* Handlers for notifications */ + MafwGstRendererWorkerNotifySeekCb notify_seek_handler; + MafwGstRendererWorkerNotifyPauseCb notify_pause_handler; + MafwGstRendererWorkerNotifyPlayCb notify_play_handler; + MafwGstRendererWorkerNotifyBufferStatusCb notify_buffer_status_handler; + MafwGstRendererWorkerNotifyEOSCb notify_eos_handler; + MafwGstRendererWorkerNotifyReadyStateCb notify_ready_state_handler; + MafwGstRendererWorkerNotifyMetadataCb notify_metadata_handler; + MafwGstRendererWorkerNotifyErrorCb notify_error_handler; + MafwGstRendererWorkerNotifyPropertyCb notify_property_handler; + + MafwGstRendererWorkerBlankingControlCb blanking__control_handler; + MafwGstRendererWorkerScreenshotCb screenshot_handler; +}; + + +MafwGstRendererWorker *mafw_gst_renderer_worker_new(gpointer owner); + +void mafw_gst_renderer_worker_exit(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_set_current_frame_on_pause( + MafwGstRendererWorker *worker, + gboolean current_frame_on_pause); + +void mafw_gst_renderer_worker_set_ready_timeout(MafwGstRendererWorker *worker, + guint seconds); + +gboolean mafw_gst_renderer_worker_get_current_frame_on_pause( + MafwGstRendererWorker *worker); + +configuration* mafw_gst_renderer_worker_create_default_configuration(MafwGstRendererWorker *worker); +void mafw_gst_renderer_worker_set_configuration(MafwGstRendererWorker *worker, + configuration *config); + +void mafw_gst_renderer_worker_set_position(MafwGstRendererWorker *worker, + GstSeekType seek_type, + gint position, + GError **error); + +gint mafw_gst_renderer_worker_get_position(MafwGstRendererWorker *worker); + +gint64 mafw_gst_renderer_worker_get_last_known_duration(MafwGstRendererWorker *worker); +gint64 mafw_gst_renderer_worker_get_duration(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_set_xid(MafwGstRendererWorker *worker, XID xid); + +XID mafw_gst_renderer_worker_get_xid(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_set_render_rectangle(MafwGstRendererWorker *worker, render_rectangle *rect); +const render_rectangle* mafw_gst_renderer_worker_get_render_rectangle(MafwGstRendererWorker *worker); + +gboolean mafw_gst_renderer_worker_get_autopaint(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_set_autopaint(MafwGstRendererWorker *worker, + gboolean autopaint); + +gboolean mafw_gst_renderer_worker_set_playback_speed(MafwGstRendererWorker *worker, gfloat speed); + +gfloat mafw_gst_renderer_worker_get_playback_speed(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_set_force_aspect_ratio(MafwGstRendererWorker *worker, gboolean force); + +gboolean mafw_gst_renderer_worker_get_force_aspect_ratio(MafwGstRendererWorker *worker); + +gint mafw_gst_renderer_worker_get_colorkey(MafwGstRendererWorker *worker); + +gboolean mafw_gst_renderer_worker_get_seekable(MafwGstRendererWorker *worker); + +gboolean mafw_gst_renderer_worker_get_streaming(MafwGstRendererWorker *worker); + +const char* mafw_gst_renderer_worker_get_uri(MafwGstRendererWorker *worker); + +GHashTable *mafw_gst_renderer_worker_get_current_metadata( + MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker, + const gchar *uri); + +void mafw_gst_renderer_worker_stop(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_pause(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_resume(MafwGstRendererWorker *worker); + +void mafw_gst_renderer_worker_pause_at(MafwGstRendererWorker *worker, guint position); + +guint check_dolby_audioroute(MafwGstRendererWorker *worker, guint prop); + +void set_dolby_music_property(MafwGstRendererWorker *worker, guint prop); +void set_dolby_music_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty); + +void set_dolby_video_property(MafwGstRendererWorker *worker, guint prop); +void set_dolby_video_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty); + +void mafw_gst_renderer_worker_notify_media_destination(MafwGstRendererWorker *worker, + GSList *destinations); + +G_END_DECLS +#endif diff --git a/qmafw-gst-subtitles-renderer/mafw-gst-renderer-plugin.conf b/qmafw-gst-subtitles-renderer/mafw-gst-renderer-plugin.conf new file mode 100644 index 0000000..2767d34 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/mafw-gst-renderer-plugin.conf @@ -0,0 +1,37 @@ +;Renderer instances +[renderers] +1\Id=mafw_gst_renderer +1\FriendlyName=MafwGstRenderer +2\Id=mafw_gst_internal_video_renderer +2\FriendlyName=MafwGstVideoRenderer +size=2 + +[in-process-renderers] +1\Id=mafw_in_process_gst_renderer +1\FriendlyName=MafwInProcessGstRenderer +size=1 + +;Renderer's configuration +[pipeline] +audio-sink=pulsesink +video-sink=omapxvsink +flags=71 +use_dhmmixer=1 +buffer-time=600000 +latency-time=300000 +autoload_subtitles=1 +subtitle_encoding=NULL +subtitle_font=Sans Bold 18 + +[timers] +pause-frame=700 +pause-to-ready=3 + +[dhmmixer] +;default values should be overwritten from gconf +dhm-music-surround=0 +dhm-music-color=2 +dhm-music-room-size=2 +dhm-video-surround=0 +dhm-video-color=2 +dhm-video-room-size=2 diff --git a/qmafw-gst-subtitles-renderer/qmafw-gst-subtitles-renderer.pro b/qmafw-gst-subtitles-renderer/qmafw-gst-subtitles-renderer.pro new file mode 100644 index 0000000..05636b4 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/qmafw-gst-subtitles-renderer.pro @@ -0,0 +1,99 @@ +TEMPLATE = lib +TARGET = qmafw-gst-renderer-plugin +VERSION = 0.0.55-1 + +QT = core network + +isEmpty(PREFIX) { + PREFIX=/usr +} + +isEmpty(MODE) { + CONFIG += release + QMAKE_CXXFLAGS += -g + QMAKE_CFLAGS += -g +} + +contains(MODE, release) { + CONFIG += release + DEFINES += G_DISABLE_ASSERT + QMAKE_CXXFLAGS += -g + QMAKE_CFLAGS += -g +} + +contains(MODE, debug) { + CONFIG += debug +} + +CONFIG += no_keywords qt qdbus link_pkgconfig plugin +PKGCONFIG += qmafw glib-2.0 gobject-2.0 gq-gconf gstreamer-0.10 gstreamer-plugins-base-0.10 QtSparql +PKGCONFIG += contextprovider-1.0 contextsubscriber-1.0 qmsystem2 usb_moded + +LIBS += -lgstinterfaces-0.10 -lgstpbutils-0.10 -ldbus-qeventloop -ltotem-plparser + +DEPENDPATH += . inc src +INCLUDEPATH += . inc $$system(pkg-config --variable=includedir qmafw) + +#DEFINES += QT_NO_DEBUG_OUTPUT + +QMAKE_CXXFLAGS += -Wall -Werror +QMAKE_CFLAGS += -Wall -Werror + +QMAKE_CLEAN += build-stamp \ + configure-stamp + +# Version info +DEFINES += _VERSION_INFO +QMAKE_EXTRA_TARGETS += revtarget +revtarget.target = inc/version.h +revtarget.commands += @echo update version info +revtarget.commands += $$escape_expand( \\n\\t )@echo \"namespace \{\" > $$revtarget.target +revtarget.commands += $$escape_expand( \\n\\t )@echo \"const char *revision = \\\"$(shell svnversion -n . || echo N/A )\\\";\" >> $$revtarget.target +revtarget.commands += $$escape_expand( \\n\\t )@echo \"const char *build_time = \\\"$(shell date )\\\";\" >> $$revtarget.target +revtarget.commands += $$escape_expand( \\n\\t )@echo \"\};\" >> $$revtarget.target +# update revision/buildtime every time when linking is required +QMAKE_POST_LINK += @rm -f $$revtarget.target + +# Input +HEADERS += MafwGstRenderer.h \ + MafwGstRendererPlugin.h \ + MafwBlankingPreventer.h \ + mafw-gst-renderer-utils.h \ + mafw-gst-renderer-worker.h \ + MafwGstRendererVolume.h \ + MafwGstRendererPlaylistFileUtility.h \ + MafwGstRendererNetworkMonitor.h \ + MafwGstRendererDolby.h \ + MafwGstScreenshot.h \ + MafwMmcMonitor.h \ + mafw-gst-renderer-seeker.h \ + MafwGstRendererHaltState.h + +SOURCES += MafwGstRenderer.cpp \ + MafwGstRendererPlugin.cpp \ + MafwBlankingPreventer.cpp \ + mafw-gst-renderer-utils.c \ + mafw-gst-renderer-worker.c \ + MafwGstRendererVolume.cpp \ + MafwGstRendererPlaylistFileUtility.cpp \ + MafwGstRendererNetworkMonitor.cpp \ + MafwGstRendererDolby.cpp \ + MafwGstScreenshot.cpp \ + MafwMmcMonitor.cpp \ + mafw-gst-renderer-seeker.c \ + MafwGstRendererHaltState.cpp + +DISTFILES += qmafw-gst-renderer.service + +# Installation +service.files = com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin.service +service.path = $$PREFIX/share/dbus-1/services +target.path = $$PREFIX/lib/qmafw-plugin + +context.files = com.nokia.mafw.context_provider.libqmafw_gst_renderer.context +context.path = $$PREFIX/share/contextkit/providers + +settings.files = mafw-gst-renderer-plugin.conf +settings.path = /usr/share/qmafw + +INSTALLS += target service context settings diff --git a/qmafw-gst-subtitles-renderer/src/MafwBlankingPreventer.cpp b/qmafw-gst-subtitles-renderer/src/MafwBlankingPreventer.cpp new file mode 100644 index 0000000..e328255 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwBlankingPreventer.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwBlankingPreventer.h" +#include +#include + +/* Interval of recalling setBlankingPause in seconds */ +const int BLANKING_TIMER_INTERVAL=45; + +MafwBlankingPreventer::MafwBlankingPreventer(QObject* parent) : QObject(parent) +{ + connect( &m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh())); + m_refreshTimer.setInterval( BLANKING_TIMER_INTERVAL*1000 ); + m_display = new MeeGo::QmDisplayState(this); +} + +void MafwBlankingPreventer::blankingProhibit() +{ + qDebug() << "MafwBlankingPreventer::blankingProhibit"; + refresh(); + m_refreshTimer.start(); +} + +void MafwBlankingPreventer::blankingAllow() +{ + qDebug() << "MafwBlankingPreventer::blankingAllow"; + m_refreshTimer.stop(); + m_display->cancelBlankingPause(); +} + +void MafwBlankingPreventer::refresh() +{ + bool success = m_display->setBlankingPause(); + qDebug() << "MafwBlankingPreventer::refresh success" << success; +} + diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRenderer.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRenderer.cpp new file mode 100644 index 0000000..a595711 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRenderer.cpp @@ -0,0 +1,2437 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "MafwGstRenderer.h" +#include "MafwBlankingPreventer.h" +#include "mafw-gst-renderer-worker.h" +#include "MafwGstRendererVolume.h" +#include "MafwGstRendererDolby.h" +#include "MafwGstRendererNetworkMonitor.h" +#include "MafwGstRendererHaltState.h" +#include "MafwGstRendererPlaylistFileUtility.h" +#include "MafwGstScreenshot.h" +#include "MafwMmcMonitor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// milliseconds, stamp after playing this much +const int PLAYED_STAMP_INTERVAL = 5000; + +const int MAX_SUPPORTED_HEIGHT = 720; +const int MAX_SUPPORTED_WIDTH = 1280; +// how many time we retried to make played stamps +const int PLAYED_STAMP_TRIES = 3; + +static const int ISO_DATE_BASE_LENGTH = 19; // length of "CCYY-MM-DDThh:mm:ss" + +// property names +const QString PROPERTY_DOLBY_STATE_MUSIC = "mobile-surround-state-music"; +const QString PROPERTY_DOLBY_STATE_MUSIC_ROOM = "mobile-surround-state-music-room"; +const QString PROPERTY_DOLBY_STATE_MUSIC_COLOR = "mobile-surround-state-music-color"; +const QString PROPERTY_DOLBY_STATE_VIDEO = "mobile-surround-state-video"; +const QString PROPERTY_DOLBY_STATE_VIDEO_ROOM = "mobile-surround-state-video-room"; +const QString PROPERTY_DOLBY_STATE_VIDEO_COLOR = "mobile-surround-state-video-color"; +const QString PROPERTY_VOLUME = "volume"; +const QString PROPERTY_AUTOPAINT = "autopaint"; +const QString PROPERTY_COLORKEY = "colorkey"; +const QString PROPERTY_XID = "xid"; +const QString PROPERTY_RENDER_RECT = "render-rectangle"; +const QString PROPERTY_CURRENT_FRAME_ON_PAUSE = "current-frame-on-pause"; +const QString PROPERTY_PLAYBACK_SPEED = "playback-speed"; +const QString PROPERTY_FORCE_ASPECT_RATIO = "force-aspect-ratio"; + +// audio/video destinations +const QString CONTEXT_FW_PROPERTY_AUDIO_ROUTE = "/com/nokia/policy/audio_route"; +const QString CONTEXT_FW_PROPERTY_VIDEO_ROUTE = "/com/nokia/policy/video_route"; +const QString AUDIO_ROUTE_NULL = "null"; +const QString AUDIO_ROUTE_IHF = "ihf"; +const QString AUDIO_ROUTE_FMRADIO = "fmtx"; +const QString AUDIO_ROUTE_IHF_AND_FMRADIO = "ihfandfmtx"; +const QString AUDIO_ROUTE_EARPIECE = "earpiece"; +const QString AUDIO_ROUTE_EARPIECE_AND_TVOUT = "earpieceandtvout"; +const QString AUDIO_ROUTE_TV_OUT = "tvout"; +const QString AUDIO_ROUTE_IHF_AND_TV_OUT = "ihfandtvout"; +const QString AUDIO_ROUTE_HEADPHONE = "headphone"; +const QString AUDIO_ROUTE_HEADSET = "headset"; +const QString AUDIO_ROUTE_BTHSP = "bthsp"; +const QString AUDIO_ROUTE_BTA2DP = "bta2dp"; +const QString AUDIO_ROUTE_IHF_AND_HEADSET = "ihfandheadset"; +const QString AUDIO_ROUTE_IHF_AND_HEADPHONE = "ihfandheadphone"; +const QString AUDIO_ROUTE_IHF_AND_BTHSP = "ihfandbthsp"; +const QString AUDIO_ROUTE_TV_OUT_AND_BTHSP = "tvoutandbthsp"; +const QString AUDIO_ROUTE_TV_OUT_AND_BTA2DP = "tvoutandbta2dp"; +const QString VIDEO_ROUTE_TV_OUT = "tvout"; +const QString VIDEO_ROUTE_BUILT_IN = "builtin"; +const QString VIDEO_ROUTE_BUILT_IN_AND_TV_OUT = "builtinandtvout"; + +const QString DBUS_INTERFACE_DBUS="org.freedesktop.DBus"; +const QString DBUS_SIGNAL_NAME_OWNER_CHANGED="NameOwnerChanged"; +const QString DBUS_NAME_PCFD = "com.nokia.policy.pcfd"; + +/******************************************************************** + * MafwGstRenderer::MafwGstRenderer + ********************************************************************/ +MafwGstRenderer::MafwGstRenderer(const QString& uuid, + const QString& pluginName, + const QString& name, + QObject *parent) + : + MafwBasicRenderer(uuid, pluginName, name, parent), + m_initialized(false), + m_currentState(MafwRenderer::Invalid), + m_nextContent(""), + m_currentContent(""), + m_playingItem(MafwBasicRenderer::UnknownUri), + m_blankingPreventer(0), + m_screenshot(0), + m_networkMonitor(new MafwGstRendererNetworkMonitor()), + m_volume(0), + m_playedStamped(false), + m_playedStampTryCounter(0), + m_sparqlConnection(new QSparqlConnection("QTRACKER", QSparqlConnectionOptions(), this)), + m_urnQueryResult(0), + m_stampItResult(0), + m_playlistFileUtil(0), + m_playingPlaylistFile(false), + m_unsupportedTypeError(0), + m_playedPlaylistItem(false), + m_mmcMonitor(0) +{ + qDebug() << __PRETTY_FUNCTION__; + + m_dolby = new MafwGstRendererDolby(this); + connect(m_dolby, SIGNAL(mafwDHMMusicPropertyChanged()), + this, SLOT(handleDHMMusicPropertyChanged())); + connect(m_dolby, SIGNAL(mafwDHMVideoPropertyChanged()), + this, SLOT(handleDHMVideoPropertyChanged())); + + m_worker = 0; + m_videoRoute = 0; + m_audioRoute = 0; + gst_init(0, 0); + + /* make this connection a queued connection to postpone results delivery, + * so that results callback is not called already in the function that + * initiates this procedure */ + QObject::connect(this, SIGNAL(signalGetPosition(QObject*, + const char*)), + this, SLOT(slotGetPosition(QObject*, + const char*)), + Qt::QueuedConnection); + + /* make this connection a queued connection to postpone results delivery, + * so that results callback is not called already in the function that + * initiates this procedure */ + QObject::connect(this, SIGNAL(signalMafwProperty(QString, + QObject*, + const char*)), + this, SLOT(slotMafwProperty(QString, + QObject*, + const char*)), + Qt::QueuedConnection); + + /* make this connection a queued connection to postpone results delivery, + * so that results callback is not called already in the function that + * initiates this procedure */ + QObject::connect(this, SIGNAL(signalGetCurrentMediaInfo(QObject*, + const char*, + const QString)), + this, SLOT(slotGetCurrentMediaInfo(QObject*, + const char*, + const QString)), + Qt::QueuedConnection); + + m_playedStampTimer.setSingleShot(true); + connect(&m_playedStampTimer,SIGNAL(timeout()),this,SLOT(slotStamp())); + + m_videoRoute = new ContextProperty(CONTEXT_FW_PROPERTY_VIDEO_ROUTE); + m_audioRoute = new ContextProperty(CONTEXT_FW_PROPERTY_AUDIO_ROUTE); + + connectNameOwnerChanged(); + + m_playlistNextTimer.setSingleShot(true); + connect(&m_playlistNextTimer, SIGNAL(timeout()), + this, SLOT(playNextURIFromPlaylist())); + + /* connection is to track when policy is on/off */ + connect(this, SIGNAL(mafwPropertyChanged(const QString, const QVariant)), + this, SLOT(handlePropertyChanged(const QString&, const QVariant&))); + + /* Connection to handle online status message if necessary */ + connect(m_networkMonitor, SIGNAL(prepareNetworkChange()), + this, SLOT(haltStreaming())); + connect(m_networkMonitor, SIGNAL(networkChangeFinished()), + this, SLOT(continueStreaming())); + + connect(&m_haltState, SIGNAL(decayed()), + this, SLOT(stopStreaming())); +} + +/******************************************************************** + * MafwGstRenderer::~MafwGstRenderer + ********************************************************************/ +MafwGstRenderer::~MafwGstRenderer() +{ + + qDebug() << __PRETTY_FUNCTION__; + delete m_volume; + // this releases the resources allocated by the worker, do this before + // releasing anything else so any callbacks from worker won't be called + mafw_gst_renderer_worker_exit(m_worker); + + delete m_videoRoute; + delete m_audioRoute; + delete m_networkMonitor; + delete m_screenshot; + delete m_urnQueryResult; + delete m_stampItResult; + delete m_sparqlConnection; + + g_free(m_worker); + + if( m_unsupportedTypeError ) + { + g_error_free(m_unsupportedTypeError); + } +} + + +/******************************************************************** + * MafwGstRenderer::initialize + ********************************************************************/ +bool MafwGstRenderer::initialize(QSettings *settings) +{ + + qDebug() << __PRETTY_FUNCTION__; + + //if already initialized do nothing + if (m_initialized) + { + return m_initialized; + } + + m_initialized = MafwBasicRenderer::initialize(); + + if (m_initialized) + { + // fail to apply default policy is not considered fatal for now + if (MafwBasicRenderer::setDefaultRendererPolicy(MafwRendererPolicy::MediaPlayer)) + { + MafwRendererPolicy *policy = rendererPolicy(); + Q_ASSERT(policy); + policy->setDefaultResources(MafwRendererPolicy::Audio); + } + else + { + qWarning() << "Setting default policy failed, continuing"; + } + + m_blankingPreventer = new MafwBlankingPreventer(this); + + m_screenshot = new MafwGstScreenshot(this); + + connect(m_screenshot, SIGNAL(screenshotTaken(char*,GError*)), + this, SLOT(handleScreenshot(char*,GError*))); + connect(m_screenshot, SIGNAL(screenshotCancelled()), + this, SLOT(cancelScreenshot())); + + m_worker = mafw_gst_renderer_worker_new(this); + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_eos_handler = &eosCallback; + m_worker->notify_ready_state_handler = &readyStateCallback; + m_worker->notify_metadata_handler = &metadataCallback; + m_worker->notify_property_handler = &propertyCallback; + m_worker->notify_buffer_status_handler = &bufferStatusCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + m_worker->screenshot_handler = &screenshotCallback; + + setConfiguration(settings); + + // Initialize Dolby support + m_dolby->initialize(); + + m_mmcMonitor = new MafwMmcMonitor(this); + connect( m_mmcMonitor, SIGNAL( preUnmount() ), this, SLOT( mmcPreUnmount() ) ); + + // connect the audio routes AND check the current values of routes. + connect( m_videoRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) ); + connect( m_audioRoute, SIGNAL( valueChanged() ), this, SLOT( slotRouteChanged() ) ); + slotRouteChanged(); + } + return m_initialized; +} + +/******************************************************************** + * MafwGstRenderer::playCallback + ********************************************************************/ +void MafwGstRenderer::playCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + MafwGstRenderer* self = static_cast(owner); + + if( self->m_currentState == MafwRenderer::Paused ) + { + Q_EMIT self->rendererResumed(); + } + else + { + if( self->m_playingPlaylistFile ) + { + if( !self->m_playedPlaylistItem ) + { + qDebug() << "Emitting playing item event"; + Q_EMIT self->rendererPlaying(static_cast(self->m_playingItem)); + self->m_playedPlaylistItem = true; + } + } + else + { + Q_EMIT self->rendererPlaying(static_cast(self->m_playingItem)); + } + } + + if( mafw_gst_renderer_worker_get_position(worker)==0 ) + { + self->m_playedStamped = false; + self->m_playedStampTryCounter = 0; + } + + if( !self->m_playedStamped ) + { + const QUrl url = self->m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + if (url.scheme() == "file") + { + qDebug() << __PRETTY_FUNCTION__ << "starting play stamp timer."; + self->m_playedStampTimer.start(PLAYED_STAMP_INTERVAL); + } + } + + self->m_currentState = MafwRenderer::Playing; +} + +/******************************************************************** + * MafwGstRenderer::bufferStatusCallback + ********************************************************************/ +void MafwGstRenderer::bufferStatusCallback(MafwGstRendererWorker *worker, + gpointer owner, + gdouble percent) +{ + + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + MafwGstRenderer* self = static_cast(owner); + + Q_EMIT self->bufferingInfo(static_cast(percent)); + +} +/******************************************************************** + * MafwGstRenderer::constructMafwError + ********************************************************************/ +MafwError MafwGstRenderer::constructMafwError(const GError* error) +{ + MafwError mafwError; + guint32 code = static_cast(error->code); + + //for streams the media not found is other than the default + if( code == WORKER_ERROR_MEDIA_NOT_FOUND && mafw_gst_renderer_worker_get_streaming(m_worker) ) + { + mafwError.setCode(MafwError::RendererError_URINotAvailable); + } + else if(code == WORKER_ERROR_UNSUPPORTED_TYPE) + { + handleResolutionError(mafwError); + } + else if (errorMap().contains(code)) + { + mafwError.setCode(errorMap().value(code)); + } + else + { + mafwError.setCode(MafwError::NothingButErrors); + } + + mafwError.setMessage(error->message); + return mafwError; +} + +/******************************************************************** + * MafwGstRenderer::errorCallback + ********************************************************************/ +void MafwGstRenderer::errorCallback(MafwGstRendererWorker *worker, + gpointer owner, + const GError *error) +{ + Q_UNUSED(worker); + qWarning() << __PRETTY_FUNCTION__ << error->message; + MafwError mafwError; + guint32 code; + MafwGstRenderer* self = static_cast(owner); + + code = static_cast(error->code); + + //The content might be a playlist file which was tried to play without + //mime type. This case can be detected by trying to play it as playlist + //file. If that was not the case same error will be signalled via + //MafwGstRenderer::handlePlaylistFileParsingErrors + if (!self->m_playingPlaylistFile && + !self->m_unsupportedTypeError && + code == WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE) + { + QMap mime; + mime[MAFW_METADATA_KEY_MIME] = "audio/x-scpls"; + self->m_currentContent.setMetaData(mime); + self->doPlay(self->m_currentContent); + self->m_unsupportedTypeError = g_error_copy(error); + qWarning() << __PRETTY_FUNCTION__ << "Probably we were trying to play playlist file without mime type. If that's the case use bool play(url, 'audio/x-scpls')."; + qWarning() << __PRETTY_FUNCTION__ << "Trying to play as playlist file now..."; + return; + } + mafwError = self->constructMafwError(error); + + /* We release resources when we got error that causes stop. + * WORKER_ERROR_CANNOT_SET_POSITION and WORKER_ERROR_DRM_NOT_ALLOWED error don't cause stop. + */ + if((code != WORKER_ERROR_CANNOT_SET_POSITION + && code != WORKER_ERROR_DRM_NOT_ALLOWED) + && !self->m_playingPlaylistFile) + { + Q_EMIT self->rendererError(mafwError); + MafwRendererPolicy *policy = self->rendererPolicy(); + Q_ASSERT(policy); + if( policy ) + { + policy->release(); + qDebug() << __PRETTY_FUNCTION__ << "Resources released because of error" << mafwError.code(); + } + else + { + qWarning() << __PRETTY_FUNCTION__ << "No policy exists!"; + } + + self->doStop(); + } + else if (code != WORKER_ERROR_CANNOT_SET_POSITION && code != WORKER_ERROR_DRM_NOT_ALLOWED) //Try next uri + { + //using singleshot gives worker/gstreamer time to do + //cleanup before calling worker_play + if (self->m_playlistFileUtil->getUriList().isEmpty()) + { + //delayed call to playNextURIFromPlaylist used to give the parser + //enough time to read new items from the playlist + self->m_playlistFileUtil->setPendingError(mafwError); + + self->m_playlistNextTimer.start(1000); + } + else + { + self->m_playlistNextTimer.start(0); + } + } + else + { + Q_EMIT self->rendererError(mafwError); + } +} + +/******************************************************************** + * MafwGstRenderer::propertyCallback + ********************************************************************/ +void MafwGstRenderer::propertyCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint id, + GValue *value) +{ + + QString name; + + Q_UNUSED(worker); + + MafwGstRenderer* self = static_cast(owner); + + switch (id) + { + case WORKER_PROPERTY_AUTOPAINT: + name = PROPERTY_AUTOPAINT; + break; + case WORKER_PROPERTY_COLORKEY: + name = PROPERTY_COLORKEY; + break; + case WORKER_PROPERTY_XID: + name = PROPERTY_XID; + break; + case WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE: + name = PROPERTY_CURRENT_FRAME_ON_PAUSE; + break; + case WORKER_PROPERTY_PLAYBACK_SPEED: + name = PROPERTY_PLAYBACK_SPEED; + break; + case WORKER_PROPERTY_FORCE_ASPECT_RATIO: + name = PROPERTY_FORCE_ASPECT_RATIO; + break; + case WORKER_PROPERTY_RENDER_RECTANGLE: + name = PROPERTY_RENDER_RECT; + break; + default: + qWarning() << __PRETTY_FUNCTION__ << "unknown property id:" << id; + return; + break; + } + + qDebug() << __PRETTY_FUNCTION__ << name; + + QVariant result = getValue(value); + + if (result.isValid()) + { + Q_EMIT self->mafwPropertyChanged(name, result); + } + +} + +/******************************************************************** + * MafwGstRenderer::blankingControlCallback + ********************************************************************/ +void MafwGstRenderer::blankingControlCallback(MafwGstRendererWorker *worker, + gpointer owner, gboolean prohibit) +{ + + Q_UNUSED(worker); + qDebug() << __PRETTY_FUNCTION__ << prohibit; + MafwGstRenderer* self = static_cast(owner); + if(self->m_videoRoute->value() == VIDEO_ROUTE_TV_OUT || + self->m_videoRoute->value() == VIDEO_ROUTE_BUILT_IN_AND_TV_OUT) + { + prohibit = false; + } + + if( prohibit ) + { + self->m_blankingPreventer->blankingProhibit(); + } + else + { + self->m_blankingPreventer->blankingAllow(); + } +} + +/******************************************************************** + * MafwGstRenderer::screenshotCallback + ********************************************************************/ +void MafwGstRenderer::screenshotCallback(MafwGstRendererWorker *worker, + gpointer owner, GstBuffer *buffer, + const char *filename, gboolean cancel) +{ + qDebug() << __PRETTY_FUNCTION__; + MafwGstRenderer *self = static_cast(owner); + + if(cancel) + { + self->m_screenshot->cancelPauseFrame(); + } + else + { + if(!self->m_screenshot->savePauseFrame(buffer, filename)) + { + worker->taking_screenshot = FALSE; + qCritical() << "Failed to create pause frame pipeline"; + } + } +} + +/******************************************************************** + * MafwGstRenderer::getValue + ********************************************************************/ +QVariant MafwGstRenderer::getValue(const GValue *v) +{ + + QVariant result; + + if (G_IS_VALUE(v)) + { + if (G_VALUE_TYPE(v) == G_TYPE_STRING) + { + // tags from GStreamer are always expected to be UTF-8 + result = QVariant(QString::fromUtf8(g_value_get_string(v))); + } + else if (G_VALUE_TYPE(v) == G_TYPE_UINT) + { + result = QVariant(g_value_get_uint(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_INT) + { + result = QVariant(g_value_get_int(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_BOOLEAN) + { + result = QVariant::fromValue(g_value_get_boolean(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_DOUBLE) + { + result = QVariant(g_value_get_double(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_INT64) + { + result = QVariant(g_value_get_int64(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_FLOAT) + { + result = QVariant(g_value_get_float(v)); + } + else if (G_VALUE_TYPE(v) == G_TYPE_VALUE_ARRAY) + { + GValueArray *vals = static_cast(g_value_get_boxed(v)); + if( vals->n_values == 4 ) + { + result = QString("%1,%2,%3,%4") + .arg(g_value_get_int(g_value_array_get_nth(vals, 0))) + .arg(g_value_get_int(g_value_array_get_nth(vals, 1))) + .arg(g_value_get_int(g_value_array_get_nth(vals, 2))) + .arg(g_value_get_int(g_value_array_get_nth(vals, 3))); + } + else + { + qWarning() << "Invalid rect values received? Size:" << vals->n_values; + } + + } + else + { + qWarning() << "unsupported value g_type"; + } + } + + return result; + +} + +/******************************************************************** + * MafwGstRenderer::metadataCallback + ********************************************************************/ +void MafwGstRenderer::metadataCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint key, + GType type, + gpointer value) +{ + + QList results; + + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__ << key << metadataMap().value(key); + + MafwGstRenderer* self = static_cast(owner); + + if (metadataMap().contains(key)) + { + if (type == G_TYPE_VALUE_ARRAY) + { + uint i; + GValueArray *vals = static_cast(value); + for (i = 0; i < vals->n_values; i++) + { + QVariant v = getValue(g_value_array_get_nth(vals, i)); + if (v.isValid()) + { + results << v; + } + } + + QString mafwMetadataKey = metadataMap().value(key); + + self->appendRelatedMetadata(mafwMetadataKey, &results); + + Q_EMIT self->metadataChanged(mafwMetadataKey, results); + self->m_currentMetaData.insert(mafwMetadataKey, results); + } + else + { + qWarning() << "unsupported g_type"; + } + } + else + { + qWarning() << "unknown metadata key:" << key; + } +} + +/******************************************************************** + * MafwGstRenderer::appendRelatedMetadata + ********************************************************************/ +void MafwGstRenderer::appendRelatedMetadata(const QString key, QList* results) +{ + if(key == MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI) + { + gint position = mafw_gst_renderer_worker_get_position(m_worker); + if(position < 0) + { + position = 0; + } + + QUrl uri = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + *results << uri.toEncoded().constData(); + *results << QVariant(position); + } +} + +// +// QMafw renderer interface implementation +// + +/******************************************************************** + * MafwGstRenderer::doPlay + ********************************************************************/ +void MafwGstRenderer::doPlay(const MafwContent& content) +{ + Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!"); + Q_UNUSED(content); +} + +/******************************************************************** + * MafwGstRenderer::doPlay + ********************************************************************/ +void MafwGstRenderer::doPlay(const MafwMediaInfo& mediaInfo) +{ + //Preserve m_currentContent for keeping usage count up if the same item is + //played again. + if(mediaInfo.uuid().isEmpty() || + mediaInfo.uuid() != m_currentContent.uuid()) + { + m_currentContent = mediaInfo; + } + m_playingItem = MafwBasicRenderer::CurrentUri; + m_currentMetaData.clear(); + + const QUrl url = mediaInfo.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + qDebug() << __PRETTY_FUNCTION__ << url.toEncoded(); + + m_haltState.clear(); + + if( !m_mmcMonitor->isMounted() && url.toString().startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) ) + { + qDebug() << "MafwGstRenderer::doPlay: Can't play MMC not mounted"; + MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded()); + Q_EMIT rendererError(mafwError); + return; + } + + m_playedPlaylistItem = false; + m_playingPlaylistFile = false; + if (m_unsupportedTypeError) + { + g_error_free(m_unsupportedTypeError); + m_unsupportedTypeError = 0; + } + + if( url.isValid() ) + { + stopTimers(); + + // Set correct value for the Dolby Headphones Mobile effect plugin + set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState()); + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE); + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE); + set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState()); + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE); + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE); + + const QString& mimeType = mediaInfo.firstMetaData(MAFW_METADATA_KEY_MIME).toString(); + if (mimeType == "audio/x-scpls" ) + { + if (!m_playlistFileUtil) + { + m_playlistFileUtil = new MafwGstRendererPlaylistFileUtility(this); + connect(m_playlistFileUtil, SIGNAL(firstItemParsed()), + this, SLOT(startPlayingPlaylistFile()), Qt::QueuedConnection); + connect(m_playlistFileUtil, SIGNAL(parsingReady(bool)), + this, SLOT(handlePlaylistFileParsingErrors(bool)), Qt::QueuedConnection); + } + m_playlistFileUtil->parsePlaylistFile(url); + + } + else + { + playURI(url.toEncoded()); + + QVariant startPosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_START_POSITION); + if( startPosition.isValid() ) + { + uint pos = startPosition.toUInt(); + qDebug() << "Immediate seek requested to: " << pos; + doSeek(pos, MafwRenderer::SeekAbsolute); + } + else + { + QVariant pausePosition = mediaInfo.firstMetaData(MAFW_METADATA_KEY_PAUSED_POSITION); + if( pausePosition.isValid() ) + { + uint position = pausePosition.toUInt(); + qDebug() << "Immediate pause requested at:" << position; + mafw_gst_renderer_worker_pause_at(m_worker, position); + } + } + } + } + else + { + MafwError mafwError(MafwError::RendererError_InvalidURI, url.toString()); + Q_EMIT rendererError(mafwError); + doStop(); + } +} + +/******************************************************************** + * MafwGstRenderer::doStop + ********************************************************************/ +void MafwGstRenderer::doStop() +{ + qDebug() << __PRETTY_FUNCTION__; + + mafw_gst_renderer_worker_stop(m_worker); + m_currentState = MafwRenderer::Stopped; + m_playingItem = MafwBasicRenderer::UnknownUri; + + m_haltState.clear(); + + stopTimers(); + Q_EMIT rendererStopped(); +} + +/******************************************************************** + * MafwGstRenderer::doPause + ********************************************************************/ +void MafwGstRenderer::doPause() +{ + qDebug() << __PRETTY_FUNCTION__; + + if( m_haltState.isSet() && m_haltState.state() == MafwRenderer::Playing ) + { + m_haltState.setState(MafwRenderer::Paused); + m_currentState = MafwRenderer::Paused; + Q_EMIT rendererPaused(); + } + else + { + mafw_gst_renderer_worker_pause(m_worker); + } +} + +/******************************************************************** + * MafwGstRenderer::doResume + ********************************************************************/ +void MafwGstRenderer::doResume() +{ + qDebug() << __PRETTY_FUNCTION__; + + if( m_currentState == MafwRenderer::Paused && m_haltState.isSet() && m_haltState.state() == MafwRenderer::Paused ) + { + mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData()); + m_currentState = MafwRenderer::Paused; + if( m_haltState.position() > 0 ) + { + doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute); + } + } + else + { + mafw_gst_renderer_worker_resume(m_worker); + } + + if( m_haltState.isSet() ) + { + m_haltState.clear(); + } +} + +/******************************************************************** + * MafwGstRenderer::doSeek + ********************************************************************/ +void MafwGstRenderer::doSeek(int position, MafwRenderer::SeekMode seekMode) +{ + GError *error = 0; + + qDebug() << __PRETTY_FUNCTION__; + + GstSeekType seekType; + if( MafwRenderer::SeekAbsolute == seekMode ) + { + seekType = GST_SEEK_TYPE_SET; + } + else if( MafwRenderer::SeekRelative == seekMode ) + { + seekType = GST_SEEK_TYPE_CUR; + } + else + { + qCritical("MafwGstRenderer: Invalid seek operation requested!"); + return; + } + + mafw_gst_renderer_worker_set_position(m_worker, + seekType, + position, + &error); + + if (error) + { + MafwError mafwError; + mafwError.setCode(MafwError::RendererError_CannotSetPosition); + mafwError.setMessage(error->message); + Q_EMIT rendererError(mafwError); + g_error_free(error); + } + +} + +/******************************************************************** + * MafwGstRenderer::doNextHint + ********************************************************************/ +bool MafwGstRenderer::doNextHint(const MafwContent& content) +{ + Q_ASSERT_X(false, "MafwGstRenderer", "Wrong play function called!"); + Q_UNUSED(content); + return false; +} + +/******************************************************************** + * MafwGstRenderer::doNextHint + ********************************************************************/ +bool MafwGstRenderer::doNextHint(const MafwMediaInfo& mediaInfo) +{ + qDebug() << __PRETTY_FUNCTION__; + + m_nextContent = mediaInfo; + // If we have already reached EOS trigger a new play attempt because the + // next content was signalled too late. However, if we have gone from playing + // state we can not continue, because we have released resources. + if (m_worker->eos && (m_currentState == MafwRenderer::Playing)) + { + QTimer::singleShot(0, this, SLOT(playNext())); + } + return true; +} + +/******************************************************************** + * MafwGstRenderer::getPosition + ********************************************************************/ +bool MafwGstRenderer::getPosition(QObject* resultsReceiver, + const char* resultsMember) +{ + + Q_EMIT signalGetPosition(resultsReceiver, + resultsMember); + + return true; + +} + +/******************************************************************** + * MafwGstRenderer::setMafwProperty + ********************************************************************/ +bool MafwGstRenderer::setMafwProperty(const QString& name, + const QVariant& value) +{ + qDebug() << __PRETTY_FUNCTION__ << name; + + bool success = true; + if (name == PROPERTY_VOLUME) + { + if (!m_volume) + { + m_volume = new MafwGstRendererVolume(); + connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint))); + } + success = m_volume->setVolume(value.toUInt()); + } + else if (name == PROPERTY_DOLBY_STATE_MUSIC) + { + success = m_dolby->setMusicDolbyState(value.toUInt()); + if (success) + { + set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState()); + } + } + else if (name == PROPERTY_DOLBY_STATE_MUSIC_ROOM) + { + success = m_dolby->setMusicDolbyState(value.toInt()); + if (success) + { + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE); + } + } + else if (name == PROPERTY_DOLBY_STATE_MUSIC_COLOR) + { + success = m_dolby->setMusicDolbyState(value.toInt()); + if (success) + { + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE); + } + } + else if (name == PROPERTY_DOLBY_STATE_VIDEO) + { + success = m_dolby->setVideoDolbyState(value.toUInt()); + if (success) + { + set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState()); + } + } + else if (name == PROPERTY_DOLBY_STATE_VIDEO_ROOM) + { + success = m_dolby->setVideoDolbyState(value.toInt()); + if (success) + { + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE); + } + } + else if (name == PROPERTY_DOLBY_STATE_VIDEO_COLOR) + { + success = m_dolby->setVideoDolbyState(value.toInt()); + if (success) + { + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE); + } + } + else if (name == PROPERTY_AUTOPAINT) + { + mafw_gst_renderer_worker_set_autopaint(m_worker, value.toBool()); + } + else if (name == PROPERTY_XID) + { + if (rendererPolicy()) + { + rendererPolicy()->setDefaultResources(MafwRendererPolicy::Audio | MafwRendererPolicy::Video); + } + else + { + qCritical() << __PRETTY_FUNCTION__ << "unable to append video to default resources"; + } + + mafw_gst_renderer_worker_set_xid(m_worker, value.toUInt()); + } + else if (name == PROPERTY_CURRENT_FRAME_ON_PAUSE) + { + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, + value.toBool()); + } + else if (name == PROPERTY_PLAYBACK_SPEED) + { + success = mafw_gst_renderer_worker_set_playback_speed(m_worker, value.toFloat()); + } + else if (name == PROPERTY_FORCE_ASPECT_RATIO) + { + mafw_gst_renderer_worker_set_force_aspect_ratio(m_worker, value.toBool()); + } + else if( name == PROPERTY_RENDER_RECT ) + { + if( value.type() != QVariant::String ) + { + qWarning() << "MafwGstRenderer Invalid ("<(owner); + + self->m_playedStampTimer.stop(); + + Q_EMIT self->rendererPaused(); + + //are we staying in paused after stopped state (pauseAt requested) + //we'll need to inform the MafwBasicRenderer to give the next item to play after current + //if so start fetching next also in this case + if( self->m_currentState == MafwRenderer::Stopped ) + { + Q_EMIT self->rendererReadyForNext(self->m_playingItem); + } + + self->m_currentState = MafwRenderer::Paused; +} + +/******************************************************************** + * MafwGstRenderer::eosCallback + * Renderer does not stop here, because there could be set next item to play. + ********************************************************************/ +void MafwGstRenderer::eosCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + + MafwGstRenderer* self = static_cast(owner); + + //this is very special case to restart playing streams of undetermined duration and nonseekable + if( mafw_gst_renderer_worker_get_streaming(worker) + && mafw_gst_renderer_worker_get_last_known_duration(worker) < 0 + && !mafw_gst_renderer_worker_get_seekable(worker) ) + { + QTimer::singleShot(0, self, SLOT(restartPlay())); + return; + } + + if( self->m_playedStampTimer.isActive() ) // eos before stamped, stamp now + { + self->m_playedStampTimer.stop(); + self->slotStamp(); + } + + if (self->m_playingPlaylistFile) //Try next uri if exists + { + self->m_playlistNextTimer.start(0); + } + else + { + QTimer::singleShot(0, self, SLOT(playNext())); + Q_EMIT self->rendererEos(); + } + +} + +/******************************************************************** + * MafwGstRenderer::restartPlay + * Slot to call asynchronously to restart playback (e.g. when internet radio disconnect due to network issues) + ********************************************************************/ +void MafwGstRenderer::restartPlay() +{ + //only restart if we're still playing + if( m_currentState == MafwRenderer::Playing ) + { + doPlay(m_currentContent); + } +} + +/******************************************************************** + * MafwGstRenderer::readyStateCallback + * Worker informs via this when it is no longer using any resources when paused + ********************************************************************/ +void MafwGstRenderer::readyStateCallback(MafwGstRendererWorker *worker, gpointer owner) +{ + Q_UNUSED(worker); + + MafwGstRenderer *self = static_cast(owner); + + if( self->m_currentState != MafwRenderer::Paused ) + { + qCritical("MafwGstRenderer: Ready state informed, but not in PAUSED state! Not releasing resources!"); + return; + } + + MafwRendererPolicy *policy = self->rendererPolicy(); + if( policy ) + { + policy->release(); + } +} + +// +//Private implementation +// + +/******************************************************************** + * MafwGstRenderer::slotGetPosition + ********************************************************************/ +void MafwGstRenderer::slotGetPosition(QObject* resultsReceiver, + const char* resultsMember) +{ + QMetaMethod method; + bool methodFound; + gint pos; + + if(m_currentState == MafwRenderer::Stopped) + { + pos = 0; + } + else if( m_haltState.isSet() ) + { + pos = m_haltState.position(); + } + else + { + /* this returns -1 on failure */ + pos = mafw_gst_renderer_worker_get_position(m_worker); + } + + if (pos < 0) + { + MafwError err; + err.setCode(MafwError::RendererError_CannotGetPosition); + Q_EMIT rendererError(err); + } + else + { + methodFound = MafwCallbackHelper::getCallbackMethod(resultsReceiver, + resultsMember, + method); + + if (!methodFound || + method.invoke(resultsReceiver, Q_ARG(uint, pos)) == false) + { + qCritical() << "Invoking the get position callback method failed!"; + } + } +} + +/******************************************************************** + * MafwGstRenderer::slotMafwProperty + ********************************************************************/ +void MafwGstRenderer::slotMafwProperty(const QString& name, + QObject* receiver, + const char* member) +{ + + QVariant prop; + QMetaMethod method; + bool methodFound; + + if (name == PROPERTY_VOLUME) + { + if (!m_volume) + { + m_volume = new MafwGstRendererVolume(); + connect(m_volume, SIGNAL(volumeChanged(uint)), this, SLOT(handleVolumeChange(uint))); + } + + uint value = m_volume->getVolume(); + prop = QVariant(value); + } + else if (name == PROPERTY_DOLBY_STATE_MUSIC) + { + uint value = m_dolby->getMusicDolbyState(); + prop = QVariant(value); + } + else if (name == PROPERTY_DOLBY_STATE_VIDEO) + { + uint value = m_dolby->getVideoDolbyState(); + prop = QVariant(value); + } + else if (name == PROPERTY_AUTOPAINT) + { + gboolean value; + value = mafw_gst_renderer_worker_get_autopaint(m_worker); + prop = QVariant(value); + } + else if (name == PROPERTY_COLORKEY) + { + gint value; + value = mafw_gst_renderer_worker_get_colorkey(m_worker); + prop = QVariant(value); + } + else if (name == PROPERTY_XID) + { + XID value; + value = mafw_gst_renderer_worker_get_xid(m_worker); + prop = QVariant(static_cast(value)); + } + else if (name == PROPERTY_PLAYBACK_SPEED) + { + gfloat value; + value = mafw_gst_renderer_worker_get_playback_speed(m_worker); + prop = QVariant(value); + } + else if (name == PROPERTY_FORCE_ASPECT_RATIO) + { + gboolean value; + value = mafw_gst_renderer_worker_get_force_aspect_ratio(m_worker); + prop = QVariant(value); + } + else if( name == PROPERTY_RENDER_RECT) + { + const render_rectangle *rect = mafw_gst_renderer_worker_get_render_rectangle(m_worker); + prop = QString("%1,%2,%3,%4") + .arg(rect->x).arg(rect->y).arg(rect->width).arg(rect->height); + } + else + { + qWarning() << "unknown property: " << name; + } + + methodFound = MafwCallbackHelper::getCallbackMethod(receiver, + member, + method); + + if (!methodFound || method.invoke(receiver, + Q_ARG(QString, name), + Q_ARG(QVariant, prop)) == false) + { + qCritical() << "Invoking the callback method failed!"; + } + +} + +/******************************************************************** + * MafwGstRenderer::slotStamp + ********************************************************************/ +void MafwGstRenderer::slotStamp() +{ + qDebug() << __PRETTY_FUNCTION__; + + QString uid=m_currentContent.uuid(); + if( !uid.isEmpty() ) + { + // create live node from MAFW object ID. Tracker case only implemented + // here. There definitely should be helper function for this. + const QString TRACKER_SOURCE_UUID = "MafwTrackerSource"; + const QString MAFW_UUID_SEPARATOR = "::"; + + QString source = uid.section(MAFW_UUID_SEPARATOR, 0 , 0); + + if ( source == TRACKER_SOURCE_UUID ) + { + QString uniqueNodeIdentifier = uid.section(MAFW_UUID_SEPARATOR, 1, 1); + if (uniqueNodeIdentifier.length() > 0) + { + int counter = m_currentContent.firstMetaData(MAFW_METADATA_KEY_PLAY_COUNT).toInt(); + counter++; + qDebug() << "MafwGstRenderer::slotStamp counter" << counter; + m_currentContent.appendMetaData(MAFW_METADATA_KEY_PLAY_COUNT, QList() << QVariant(counter)); + + int storedDuration = m_currentContent.firstMetaData(MAFW_METADATA_KEY_DURATION).toInt(); + int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker); + int stampDuration = -1; + if( currentDuration >= 0 && storedDuration != currentDuration ) + { + qDebug() << "Will store new duration:" << currentDuration; + stampDuration = currentDuration; + Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList() << stampDuration)); + } + + stampIt(uniqueNodeIdentifier, counter, stampDuration); + } + } + } + else // UUID is unknown + { + const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + + if( url.isValid() && url.toString().startsWith("file://") ) + { + qDebug() << "MafwGstRenderer::slotStamp query from tracker" << url; + + QSparqlQuery query(QString("SELECT ?urn ?usageCount ?duration WHERE { " + "?urn nie:url \"%1\". " + "OPTIONAL { " + "?urn nie:usageCounter ?usageCount. " + "?urn nfo:duration ?duration } " + "}") + .arg(url.toEncoded().constData())); + + delete m_urnQueryResult; + m_urnQueryResult = m_sparqlConnection->exec(query); + connect(m_urnQueryResult, SIGNAL(finished()), + this, SLOT(slotStampQueryReady())); + } + } + + m_playedStamped=true; +} + +/******************************************************************** + * MafwGstRenderer::slotStampQueryReady + ********************************************************************/ +void MafwGstRenderer::slotStampQueryReady() +{ + m_playedStampTryCounter++; + if( !m_urnQueryResult || m_urnQueryResult->hasError() || !m_urnQueryResult->first() ) + { + qWarning() << "MafwGstRenderer::slotStampQueryReady: surprising result"; + if (!m_playedStampTimer.isActive() + && m_currentState == MafwRenderer::Playing + && m_playedStampTryCounter < PLAYED_STAMP_TRIES) + { + qDebug() << __PRETTY_FUNCTION__ << "restarting timer."; + m_playedStampTimer.start(PLAYED_STAMP_INTERVAL); + } + else + { + qWarning() << __PRETTY_FUNCTION__ << "played stamping didn't succeeded."; + m_playedStamped = false; + } + } + else + { + QString urn = m_urnQueryResult->stringValue(0); + int usageCount = m_urnQueryResult->stringValue(1).toInt(); + int storedDuration = m_urnQueryResult->stringValue(2).toInt(); + + int currentDuration = mafw_gst_renderer_worker_get_duration(m_worker); + + int mediaDuration = -1; + if( storedDuration != currentDuration) + { + mediaDuration = currentDuration; + Q_EMIT(metadataChanged(MAFW_METADATA_KEY_DURATION, QList() << mediaDuration)); + } + + qDebug() << "MafwGstRenderer::slotStampQueryReady" << urn << usageCount << mediaDuration; + + stampIt(urn, usageCount+1, mediaDuration); + } + + + delete m_urnQueryResult; + m_urnQueryResult = 0; +} + +/******************************************************************** + * MafwGstRenderer::stopTimers + ********************************************************************/ +void MafwGstRenderer::stopTimers() +{ + m_playlistNextTimer.stop(); + if (m_playlistFileUtil) + { + m_playlistFileUtil->takePendingError(); + } + m_playedStampTimer.stop(); +} + +/******************************************************************** + * MafwGstRenderer::stampIt + ********************************************************************/ +void MafwGstRenderer::stampIt(const QString& urn, int usageCount, int mediaDuration) +{ + QString isoDate=QDateTime::currentDateTime().toUTC().toString(Qt::ISODate); + // Add UTC mark "Z" if it is missing (Qt behaviour has changed it seems to add it nowadays) + if( isoDate.length()==ISO_DATE_BASE_LENGTH ) + { + isoDate.append("Z"); + } + + QSparqlQuery update; + if( mediaDuration > -1 ) + { + update.setQuery(QString( + " DELETE { <%1> nie:contentAccessed ?old } " + " WHERE { <%1> nie:contentAccessed ?old } " + " DELETE { <%1> nie:usageCounter ?oldu } " + " WHERE { <%1> nie:usageCounter ?oldu } " + " DELETE { <%1> nfo:duration ?oldd } " + " WHERE { <%1> nfo:duration ?oldd } " + " INSERT { <%1> nie:contentAccessed \"%2\" . " + " <%1> nie:usageCounter \"%3\" . " + " <%1> nfo:duration \"%4\" }") + .arg(urn) + .arg(isoDate) + .arg(usageCount) + .arg(mediaDuration)); + } + else + { + update.setQuery(QString( + "DELETE { <%1> nie:contentAccessed ?old } " + " WHERE { <%1> nie:contentAccessed ?old } " + "DELETE { <%1> nie:usageCounter ?oldu } " + " WHERE { <%1> nie:usageCounter ?oldu } " + "INSERT { <%1> nie:contentAccessed \"%2\" . " + " <%1> nie:usageCounter \"%3\"}") + .arg(urn) + .arg(isoDate) + .arg(usageCount)); + } + + update.setType(QSparqlQuery::InsertStatement); + + + delete m_stampItResult; + m_stampItResult = m_sparqlConnection->exec(update); + connect(m_stampItResult, SIGNAL(finished()), + this, SLOT(slotStampItDone())); +} + +/******************************************************************** + * MafwGstRenderer::slotStampItDone() + ********************************************************************/ +void MafwGstRenderer::slotStampItDone() +{ + if( !m_stampItResult ) + { + qWarning() << "Stampit cannot be done without stmapit result! Invalid slot call?"; + return; + } + + if( m_stampItResult->hasError() ) + { + qWarning() << "Stampit failed:" << m_stampItResult->lastError().message(); + } + delete m_stampItResult; + m_stampItResult = 0; +} + +/******************************************************************** + * MafwGstRenderer::slotRouteChanged() + ********************************************************************/ +void MafwGstRenderer::slotRouteChanged() +{ + QSet set; + QString route; + + // 1. add audio route(s) to the route set + route = m_audioRoute->value().toString(); + qDebug() << "audio route is:" << route; + if (audioRouteMap().contains(route)) + { + Q_FOREACH (int value, audioRouteMap().value(route)) + { + set.insert(value); + } + } + else + { + // TODO: Is it ok to use NULL here? + qWarning() << "adding null route (audio)"; + set.insert(WORKER_OUTPUT_NULL); + } + + // 2. add video route(s) to the route set + route = m_videoRoute->value().toString(); + qDebug() << "video route is:" << route; + if (videoRouteMap().contains(route)) + { + Q_FOREACH (int value, videoRouteMap().value(route)) + { + set.insert(value); + } + } + else + { + // TODO: Is it ok to use NULL here? + qWarning() << "adding null route (video)"; + set.insert(WORKER_OUTPUT_NULL); + } + + // 3. finally notify the worker about the current routes + GSList *destinations = NULL; + Q_FOREACH (int value, set) + { + destinations = g_slist_append(destinations, GINT_TO_POINTER(value)); + } + mafw_gst_renderer_worker_notify_media_destination(this->m_worker, + destinations); + g_slist_free(destinations); + +} + +/******************************************************************** + * MafwGstRenderer::playURI + ********************************************************************/ +void MafwGstRenderer::playURI(const QString& uri) +{ + m_playedStamped = false; + m_playedStampTryCounter = 0; + + //little hack to get pause-to-play transition to be signalled + //correctly, in case different URI is asked to be played. + //So it's not resume transition + m_currentState = MafwRenderer::Stopped; + mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData()); + m_nextContent = MafwMediaInfo(); +} + +/******************************************************************** + * MafwGstRenderer::startPlayingPlaylistFile + ********************************************************************/ +void MafwGstRenderer::startPlayingPlaylistFile() +{ + m_playlistNextTimer.stop(); + QString uri = QString(); + if (m_playlistFileUtil) + { + uri = m_playlistFileUtil->takeFirstUri(); + m_playlistFileUtil->takePendingError(); + } + else + { + qCritical() << __PRETTY_FUNCTION__ << "playlist file util is NULL!"; + } + + if (!uri.isEmpty()) + { + qDebug() << __PRETTY_FUNCTION__ << uri; + + if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) ) + { + qDebug() << "MafwGstRenderer::startPlayingPlaylistFile: Can't play MMC not mounted"; + MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri); + Q_EMIT rendererError(mafwError); + return; + } + + m_playingPlaylistFile = true; + mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData()); + QList metadataValue; + metadataValue << uri; + Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue); + } + else + { + MafwError err; + err.setCode(MafwError::RendererError_PlaylistParsing); + Q_EMIT rendererError(err); + } +} + + +/******************************************************************** + * MafwGstRenderer::handlePlaylistFileParsingErrors + ********************************************************************/ +void MafwGstRenderer::handlePlaylistFileParsingErrors(bool succeeded) +{ + qDebug() << __PRETTY_FUNCTION__; + + if (!succeeded) + { + if (m_unsupportedTypeError) + { + errorCallback(m_worker, this, m_unsupportedTypeError); + g_error_free(m_unsupportedTypeError); + m_unsupportedTypeError = 0; + } + else + { + MafwError err; + err.setCode(MafwError::RendererError_PlaylistParsing); + Q_EMIT rendererError(err); + } + } + else if (!m_playingPlaylistFile) + { + qDebug() << __PRETTY_FUNCTION__ << "waiting for playlist file items..."; + MafwError err; + err.setCode(MafwError::RendererError_NoPlaylist); + m_playlistFileUtil->setPendingError(err); + m_playlistNextTimer.start(1000); + } +} + +/******************************************************************** + * MafwGstRenderer::playNext + ********************************************************************/ +void MafwGstRenderer::playNext() +{ + qDebug() << __PRETTY_FUNCTION__; + m_playingPlaylistFile = false; + m_playedPlaylistItem = false; + + //Preserve m_currentContent for keeping usage count up if the same item is + //played again. + if( !m_nextContent.uuid().isEmpty() && (m_nextContent.uuid() == m_currentContent.uuid()) ) + { + m_nextContent = m_currentContent; + } + + const QUrl nextURI = m_nextContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + if( !nextURI.isEmpty() ) + { + m_playingItem = MafwBasicRenderer::NextUri; + m_currentContent = m_nextContent; + m_nextContent = MafwMediaInfo(); + + playURI(nextURI.toEncoded()); + } +} + +/******************************************************************** + * MafwGstRenderer::playNextURIFromPlaylist + ********************************************************************/ +void MafwGstRenderer::playNextURIFromPlaylist() +{ + qDebug() << __PRETTY_FUNCTION__; + QString uri = m_playlistFileUtil->takeFirstUri(); + + bool okToPlay=true; + if(uri.isEmpty()) + { + okToPlay=false; + } + else if( !m_mmcMonitor->isMounted() && uri.startsWith( MafwMmcMonitor::MMC_URI_PREFIX ) ) + { + qDebug() << "MafwGstRenderer::playNextURIFromPlaylist: Can't play MMC not mounted"; + MafwError mafwError(MafwError::RendererError_MmcNotAvailable, uri); + m_playlistFileUtil->setPendingError( mafwError ); + okToPlay=false; + } + + if (okToPlay) + { + m_playlistFileUtil->takePendingError(); // clear it, we have a new candidate + qDebug() << "Trying next uri: " << uri; + mafw_gst_renderer_worker_play(m_worker, uri.toAscii().constData()); + QList metadataValue; + metadataValue << uri; + Q_EMIT metadataChanged(MAFW_METADATA_KEY_URI, metadataValue); + } + else + { + m_playingPlaylistFile = false; + + if (m_playedPlaylistItem) + { + Q_EMIT rendererEos(); + } + m_playedPlaylistItem = false; + + + MafwError mafwError = m_playlistFileUtil->takePendingError(); + if ( mafwError.code() != MafwError::NoError) + { + Q_EMIT rendererError(mafwError); + doStop(); + MafwRendererPolicy *policy = rendererPolicy(); + if( policy ) + { + policy->release(); + } + } + } +} + +/******************************************************************** + * MafwGstRenderer::slotCurrentMediaInfo + ********************************************************************/ +void MafwGstRenderer::slotGetCurrentMediaInfo(QObject* receiver, const char* member, const QString& metadataKey) +{ + MafwMediaInfo info(m_currentContent.uuid()); + + //get all metadata + if(metadataKey.isEmpty()) + { + info.setMetaData(m_currentMetaData); + } + //get one item + else + { + QMap >::const_iterator iter = m_currentMetaData.find(metadataKey); + if (iter != m_currentMetaData.end()) + { + info.appendMetaData(iter.key(), iter.value()); + } + } + + sendMediaInfo(info, receiver, member); +} + +/******************************************************************** + * MafwGstRenderer::handleVolumeChange + ********************************************************************/ +void MafwGstRenderer::handleVolumeChange(uint level) +{ + qDebug() << "MafwGstRenderer::handleVolumeChange: " << level; + Q_EMIT mafwPropertyChanged(PROPERTY_VOLUME, level); +} + +/******************************************************************** + * MafwGstRenderer::stopStreaming + ********************************************************************/ +void MafwGstRenderer::stopStreaming() +{ + qDebug() << __PRETTY_FUNCTION__; + if( mafw_gst_renderer_worker_get_streaming(m_worker) ) + { + mafw_gst_renderer_worker_stop(m_worker); + stopTimers(); + } + + // emit error and stop for real, only if no valid halt state is set + if( !m_haltState.isSet() ) + { + doStop(); + MafwError error; + error.setCode(MafwError::RendererError_StreamDisconnected); + Q_EMIT rendererError(error); + } +} + +/******************************************************************** + * MafwGstRenderer::haltStreaming + ********************************************************************/ +void MafwGstRenderer::haltStreaming() +{ + qDebug() << __PRETTY_FUNCTION__; + if( mafw_gst_renderer_worker_get_streaming(m_worker) ) + { + QString uri; + if( m_playlistNextTimer.isActive() ) + { + uri = m_playlistFileUtil->takeFirstUri(); + } + else + { + uri = mafw_gst_renderer_worker_get_uri(m_worker); + } + + int position = -1; + if( mafw_gst_renderer_worker_get_seekable(m_worker) ) + { + position = mafw_gst_renderer_worker_get_position(m_worker); + if( position < 0 ) + { + qWarning() << "Cannot resume to correct position after networkchange!"; + } + } + + //make sure we've uri to resume, the playlist parser may have been trying to parse something + if( uri.length() > 0 ) + { + m_haltState = MafwGstRendererHaltState(uri, m_currentState, position); + //valid haltstate constructed, clear the possible pending error in playlist handling + if( m_playlistFileUtil ) + { + m_playlistFileUtil->takePendingError(); + } + } + else + { + //just in case + m_haltState.clear(); + } + + //now actually stop, and depending on the haltstate validity it will also emit error + stopStreaming(); + } + else + { + qDebug() << "Not streaming!"; + } +} + +/******************************************************************** + * MafwGstRenderer::continueStreaming + ********************************************************************/ +void MafwGstRenderer::continueStreaming() +{ + if( mafw_gst_renderer_worker_get_streaming(m_worker) || m_haltState.isSet() ) + { + //if not yet halted, do it now + if( !m_haltState.isSet() ) + { + haltStreaming(); + } + + m_playingItem = MafwBasicRenderer::CurrentUri; + + if( m_haltState.state() == MafwRenderer::Playing ) + { + mafw_gst_renderer_worker_play(m_worker, m_haltState.uri().toAscii().constData()); + int pausePos = m_haltState.position() > 0 ? m_haltState.position() : 0; + + if( m_haltState.state() == MafwRenderer::Playing && pausePos > 0 ) + { + qDebug() << "Resuming streaming from position: " << m_haltState.position(); + doSeek(m_haltState.position(), MafwRenderer::SeekAbsolute); + } + m_haltState.clear(); + } + } +} + +/******************************************************************** + * MafwGstRenderer::handlePropertyChanged + ********************************************************************/ +void MafwGstRenderer::handlePropertyChanged(const QString& name, + const QVariant& value) +{ + // This is a way to check if the policy is on. We need to set the + // PAUSED-to-READY timeout to zero, since we need to be sure that the + // resources really get released by the GStreamer. It is unfortunate that + // a doPause() and PAUSED state is not enough, e.g. in case of XVideo. + if (name == MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE) + { + guint timeout; + if (value.toBool() == true) + { + timeout = 0; + } + else + { + timeout = MAFW_GST_RENDERER_WORKER_READY_TIMEOUT; + } + mafw_gst_renderer_worker_set_ready_timeout(m_worker, timeout); + } +} + +/******************************************************************** + * MafwGstRenderer::handleDHMMusicPropertyChanged + ********************************************************************/ +void MafwGstRenderer::handleDHMMusicPropertyChanged() +{ + if (m_worker) + { + qDebug() << "MafwGstRenderer::handleDHMMusicPropertyChanged set_dolby_music_property" << m_dolby->getMusicDolbyState(); + set_dolby_music_property(m_worker, m_dolby->getMusicDolbyState()); + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyRoom(), TRUE); + set_dolby_music_sound_property(m_worker, m_dolby->getMusicDolbyColor(), FALSE); + } +} + +/******************************************************************** + * MafwGstRenderer::handleDHMVideoPropertyChanged + ********************************************************************/ +void MafwGstRenderer::handleDHMVideoPropertyChanged() +{ + if (m_worker) + { + qDebug() << "MafwGstRenderer::handleDHMVideoPropertyChanged set_dolby_video_property" << m_dolby->getVideoDolbyState(); + set_dolby_video_property(m_worker, m_dolby->getVideoDolbyState()); + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyRoom(), TRUE); + set_dolby_video_sound_property(m_worker, m_dolby->getVideoDolbyColor(), FALSE); + } +} + +/******************************************************************** + * MafwGstRenderer::handleScreenshot + ********************************************************************/ +void MafwGstRenderer::handleScreenshot(char *location, GError *error) +{ + if(!error) + { + QList results; + results << location; + + QString mafwMetadataKey = MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI; + + appendRelatedMetadata(mafwMetadataKey, &results); + Q_EMIT metadataChanged(mafwMetadataKey, results); + m_currentMetaData.insert(mafwMetadataKey, results); + } + else + { + qCritical() << error->message; + } + + m_worker->taking_screenshot = FALSE; +} + +/******************************************************************** + * MafwGstRenderer::cancelScreenshot + ********************************************************************/ +void MafwGstRenderer::cancelScreenshot() +{ + if(m_worker) + { + m_worker->taking_screenshot = FALSE; + } +} + +/******************************************************************** + * MafwGstRenderer::sendMediaInfo + ********************************************************************/ +void MafwGstRenderer::sendMediaInfo(const MafwMediaInfo& info, QObject* receiver, const char* member) +{ + QMetaMethod method; + bool methodFound; + + methodFound = MafwCallbackHelper::getCallbackMethod(receiver, member, method); + + if (!methodFound) + { + MafwError err; + err.setCode(MafwError::CallbackSlotNotFound); + Q_EMIT error(err); + } + //actual result callback call is inside this if() + else if( !method.invoke(receiver, Q_ARG(MafwMediaInfo, info)) ) + { + MafwError err; + err.setCode(MafwError::CallbackCouldNotInvoke); + Q_EMIT error(err); + } +} + +/******************************************************************** + * MafwGstRenderer::mmcPreUnmount + ********************************************************************/ +void MafwGstRenderer::mmcPreUnmount() +{ + qDebug() << "MafwGstRenderer::mmcPreUnmount" << m_currentState; + + if( m_currentState!=MafwRenderer::Stopped ) + { + const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + if( url.toString().startsWith(MafwMmcMonitor::MMC_URI_PREFIX) ) + { + qDebug() << "MafwGstRenderer::mmcPreUnmount: playing from MMC, going to stop"; + doStop(); + MafwError mafwError(MafwError::RendererError_MmcNotAvailable, url.toEncoded()); + Q_EMIT rendererError(mafwError); + } + } +} + +/******************************************************************** + * MafwGstRenderer::connectNameOwnerChanged + ********************************************************************/ +bool MafwGstRenderer::connectNameOwnerChanged() +{ + QStringList argumentMatch; + argumentMatch << DBUS_NAME_PCFD; + + QDBusConnection connection = QDBusConnection::systemBus(); + return connection.connect( QString(), + QString(), + DBUS_INTERFACE_DBUS, + DBUS_SIGNAL_NAME_OWNER_CHANGED, + argumentMatch, + QString(), + this, + SLOT(handleContextProviderRemoval(QDBusMessage) ) ); +} + +/******************************************************************** + * MafwGstRenderer::handleContextProviderRemoval + ********************************************************************/ +void MafwGstRenderer::handleContextProviderRemoval( const QDBusMessage& message ) +{ + QList arguments; + QString name; + QString oldName; + QString newName; + + arguments= message.arguments(); + + if ( message.type() == QDBusMessage::SignalMessage && arguments.size()==3 ) + { + + name = arguments.at(0).toString(); + oldName = arguments.at(1).toString(); + newName = arguments.at(2).toString(); + + if ( oldName.length() && newName.length()==0 ) + { + qDebug() << "MafwGstRenderer::handleContextProviderRemoval context provider died"; + + // add null output + GSList *destinations = NULL; + destinations = g_slist_append(destinations, + GINT_TO_POINTER(WORKER_OUTPUT_NULL)); + mafw_gst_renderer_worker_notify_media_destination(this->m_worker, + destinations); + g_slist_free(destinations); + } + } +} + +/******************************************************************** + * MafwGstRenderer::handleResolutionError + ********************************************************************/ +void MafwGstRenderer::handleResolutionError(MafwError &error) +{ + qDebug() << __PRETTY_FUNCTION__; + const QUrl url = m_currentContent.firstMetaData(MAFW_METADATA_KEY_URI).toUrl(); + MafwError::Code errorCode = MafwError::RendererError_UnsuppertedType; + + if( url.isValid() && url.toString().startsWith("file://") ) + { + qDebug() << __PRETTY_FUNCTION__ << url; + + QSparqlQuery query(QString("SELECT ?height ?width WHERE { " + "?_u nie:url \"%1\" ." + "?_u nfo:height ?height . " + "?_u nfo:width ?width }") + .arg(QString(url.toEncoded()))); + + QSparqlResult *result = m_sparqlConnection->syncExec(query); + + if( result->hasError() ) + { + qWarning() << __PRETTY_FUNCTION__ << " surprising result"; + qWarning() << result->lastError().message(); + } + else if( result->first() ) + { + int height = result->stringValue(0).toInt(); + int width = result->stringValue(1).toInt(); + + if (height > MAX_SUPPORTED_HEIGHT || width > MAX_SUPPORTED_WIDTH) + { + errorCode = MafwError::RendererError_UnsupportedResolution; + } + } + delete result; + } + error.setCode(errorCode); +} + +/******************************************************************** + * MafwGstRenderer::setConfiguration + ********************************************************************/ +void MafwGstRenderer::setConfiguration(QSettings *settings) +{ + //if no settings use "factory" configuration + if( !settings ) + { + return; + } + + configuration *defaultconfig = mafw_gst_renderer_worker_create_default_configuration(m_worker); + + //pipeline settings + settings->beginGroup("pipeline"); + QVariant value = readSettingsValue(settings, "audio-sink", defaultconfig->asink); + qFree(defaultconfig->asink); + defaultconfig->asink = g_strdup(value.toString().toAscii()); + + value = readSettingsValue(settings, "video-sink", defaultconfig->vsink); + qFree(defaultconfig->vsink); + defaultconfig->vsink = g_strdup(value.toString().toAscii()); + + value = readSettingsValue(settings, "flags", defaultconfig->flags); + defaultconfig->flags = value.toInt(); + + value = readSettingsValue(settings, "use_dhmmixer", defaultconfig->use_dhmmixer); + defaultconfig->use_dhmmixer = value.toBool(); + + value = readSettingsValue(settings, "buffer-time", defaultconfig->buffer_time); + defaultconfig->buffer_time = value.toULongLong(); + + value = readSettingsValue(settings, "latency-time", defaultconfig->latency_time); + defaultconfig->latency_time = value.toULongLong(); + + value = readSettingsValue(settings, "autoload_subtitles", defaultconfig->autoload_subtitles); + defaultconfig->autoload_subtitles = value.toBool(); + + value = readSettingsValue(settings, "subtitle_encoding", defaultconfig->subtitle_encoding); + qFree(defaultconfig->subtitle_encoding); + defaultconfig->subtitle_encoding = g_strdup(value.toString().toAscii()); + + value = readSettingsValue(settings, "subtitle_font", defaultconfig->subtitle_font); + qFree(defaultconfig->subtitle_font); + defaultconfig->subtitle_font = g_strdup(value.toString().toAscii()); + settings->endGroup(); + + //timers + settings->beginGroup("timers"); + value = readSettingsValue(settings, "pause-frame", defaultconfig->milliseconds_to_pause_frame); + defaultconfig->milliseconds_to_pause_frame = value.toUInt(); + + value = readSettingsValue(settings, "pause-to-ready", defaultconfig->seconds_to_pause_to_ready); + defaultconfig->seconds_to_pause_to_ready = value.toUInt(); + settings->endGroup(); + + //dhmmixer + settings->beginGroup("dhmmixer"); + value = readSettingsValue(settings, "dhm-music-surround", defaultconfig->mobile_surround_music.state); + defaultconfig->mobile_surround_music.state = value.toUInt(); + + value = readSettingsValue(settings, "dhm-music-color", defaultconfig->mobile_surround_music.color); + defaultconfig->mobile_surround_music.color = value.toInt(); + + value = readSettingsValue(settings, "dhm-music-room-size", defaultconfig->mobile_surround_music.room); + defaultconfig->mobile_surround_music.room = value.toInt(); + + value = readSettingsValue(settings, "dhm-video-surround", defaultconfig->mobile_surround_video.state); + defaultconfig->mobile_surround_video.state = value.toUInt(); + + value = readSettingsValue(settings, "dhm-video-color", defaultconfig->mobile_surround_video.color); + defaultconfig->mobile_surround_video.color = value.toInt(); + + value = readSettingsValue(settings, "dhm-video-room-size", defaultconfig->mobile_surround_video.room); + defaultconfig->mobile_surround_video.room = value.toInt(); + settings->endGroup(); + + mafw_gst_renderer_worker_set_configuration(m_worker, defaultconfig); +} + +/******************************************************************** + * MafwGstRenderer::readSettingsValue + ********************************************************************/ +QVariant MafwGstRenderer::readSettingsValue(QSettings *settings, + const QString &valueName, + const QVariant &defaultValue) const +{ + QVariant value = settings->value(valueName, defaultValue); + if( !settings->contains(valueName) ) + { + qWarning() << "No value for: (" << valueName << ") in configuration file! Using factory default"; + } + return value; +} + +/******************************************************************** + * MafwGstRenderer::errorMap + ********************************************************************/ +const QHash& MafwGstRenderer::errorMap() +{ + + static QHash map; + + if (map.isEmpty()) + { + /* initialize error map */ + map[WORKER_ERROR_PLAYBACK] = + MafwError::RendererError_Playback; + map[WORKER_ERROR_VIDEO_CODEC_NOT_FOUND] = + MafwError::RendererError_VideoCodeNotFound; + map[WORKER_ERROR_AUDIO_CODEC_NOT_FOUND] = + MafwError::RendererError_AudioCodecNotFound; + map[WORKER_ERROR_CODEC_NOT_FOUND] = + MafwError::RendererError_CodecNotFound; + map[WORKER_ERROR_UNSUPPORTED_TYPE] = + MafwError::RendererError_UnsuppertedType; + map[WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE] = + MafwError::RendererError_UnsuppertedType; + map[WORKER_ERROR_UNABLE_TO_PERFORM] = + MafwError::RendererError_UnableToPerform; + map[WORKER_ERROR_CANNOT_SET_POSITION] = + MafwError::RendererError_CannotSetPosition; + map[WORKER_ERROR_PLAYLIST_PARSING] = + MafwError::RendererError_PlaylistParsing; + map[WORKER_ERROR_DRM_NO_LICENSE] = + MafwError::RendererError_DRMNoLicense; + map[WORKER_ERROR_DRM_NOT_ALLOWED] = + MafwError::RendererError_DRMNotAllowed; + map[WORKER_ERROR_DRM_OTHER] = + MafwError::RendererError_DRMOther; + map[WORKER_ERROR_STREAM_DISCONNECTED] = + MafwError::RendererError_StreamDisconnected; + map[WORKER_ERROR_INVALID_URI] = + MafwError::RendererError_InvalidURI; + map[WORKER_ERROR_MEDIA_NOT_FOUND] = + MafwError::RendererError_MediaNotFound; + map[WORKER_ERROR_CORRUPTED_FILE] = + MafwError::RendererError_CorruptedFile; + map[WORKER_ERROR_TYPE_NOT_AVAILABLE] = + MafwError::RendererError_TypeNotAvailable; + } + + return map; + +} + +/******************************************************************** + * MafwGstRenderer::metadataMap + ********************************************************************/ +const QHash& MafwGstRenderer::metadataMap() +{ + + static QHash map; + + if (map.isEmpty()) + { + /* initialize metadata key map */ + map[WORKER_METADATA_KEY_TITLE] = + MAFW_METADATA_KEY_TITLE; + map[WORKER_METADATA_KEY_ARTIST] = + MAFW_METADATA_KEY_ARTIST; + map[WORKER_METADATA_KEY_AUDIO_CODEC] = + MAFW_METADATA_KEY_AUDIO_CODEC; + map[WORKER_METADATA_KEY_VIDEO_CODEC] = + MAFW_METADATA_KEY_VIDEO_CODEC; + map[WORKER_METADATA_KEY_BITRATE] = + MAFW_METADATA_KEY_BITRATE; + map[WORKER_METADATA_KEY_ENCODING] = + MAFW_METADATA_KEY_ENCODING; + map[WORKER_METADATA_KEY_ALBUM] = + MAFW_METADATA_KEY_ALBUM; + map[WORKER_METADATA_KEY_GENRE] = + MAFW_METADATA_KEY_GENRE; + map[WORKER_METADATA_KEY_TRACK] = + MAFW_METADATA_KEY_TRACK; + map[WORKER_METADATA_KEY_ORGANIZATION] = + MAFW_METADATA_KEY_ORGANIZATION; + map[WORKER_METADATA_KEY_RENDERER_ART_URI] = + MAFW_METADATA_KEY_RENDERER_ART_URI; + map[WORKER_METADATA_KEY_RES_X] = + MAFW_METADATA_KEY_RES_X; + map[WORKER_METADATA_KEY_RES_Y] = + MAFW_METADATA_KEY_RES_Y; + map[WORKER_METADATA_KEY_VIDEO_FRAMERATE] = + MAFW_METADATA_KEY_VIDEO_FRAMERATE; + map[WORKER_METADATA_KEY_DURATION] = + MAFW_METADATA_KEY_DURATION; + map[WORKER_METADATA_KEY_IS_SEEKABLE] = + MAFW_METADATA_KEY_IS_SEEKABLE; + map[WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI] = + MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI; + map[WORKER_METADATA_KEY_URI] = + MAFW_METADATA_KEY_URI; + } + + return map; + +} + +/******************************************************************** + * MafwGstRenderer::audioRouteMap + ********************************************************************/ +const QHash >& MafwGstRenderer::audioRouteMap() +{ + + static QHash > map; + + if (map.isEmpty()) + { + map[AUDIO_ROUTE_NULL] = QList() << WORKER_OUTPUT_NULL; + map[AUDIO_ROUTE_IHF] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS; + map[AUDIO_ROUTE_FMRADIO] = QList() << WORKER_OUTPUT_FM_RADIO; + map[AUDIO_ROUTE_IHF_AND_FMRADIO] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_FM_RADIO; + + // earpiece is intentionally handled as builtdin speaker, well it kinda is + map[AUDIO_ROUTE_EARPIECE] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS; + map[AUDIO_ROUTE_EARPIECE_AND_TVOUT] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT; + + map[AUDIO_ROUTE_TV_OUT] = QList() << WORKER_OUTPUT_HEADPHONE_JACK; + map[AUDIO_ROUTE_IHF_AND_TV_OUT] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_TVOUT; + map[AUDIO_ROUTE_HEADPHONE] = QList() << WORKER_OUTPUT_HEADPHONE_JACK; + map[AUDIO_ROUTE_HEADSET] = QList() << WORKER_OUTPUT_HEADPHONE_JACK; + map[AUDIO_ROUTE_BTHSP] = QList() << WORKER_OUTPUT_BLUETOOTH_AUDIO; + map[AUDIO_ROUTE_BTA2DP] = QList() << WORKER_OUTPUT_BLUETOOTH_AUDIO; + map[AUDIO_ROUTE_IHF_AND_HEADSET] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK; + map[AUDIO_ROUTE_IHF_AND_HEADPHONE] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_HEADPHONE_JACK; + map[AUDIO_ROUTE_IHF_AND_BTHSP] = QList() << WORKER_OUTPUT_BUILTIN_SPEAKERS << WORKER_OUTPUT_BLUETOOTH_AUDIO; + map[AUDIO_ROUTE_TV_OUT_AND_BTHSP] = QList() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO; + map[AUDIO_ROUTE_TV_OUT_AND_BTA2DP] = QList() << WORKER_OUTPUT_HEADPHONE_JACK << WORKER_OUTPUT_BLUETOOTH_AUDIO; + } + + return map; + +} + +/******************************************************************** + * MafwGstRenderer::videoRouteMap + ********************************************************************/ +const QHash >& MafwGstRenderer::videoRouteMap() +{ + + static QHash > map; + + if (map.isEmpty()) + { + map[VIDEO_ROUTE_TV_OUT] = QList() << WORKER_OUTPUT_TVOUT; + map[VIDEO_ROUTE_BUILT_IN] = QList() << WORKER_OUTPUT_BUILTIN_DISPLAY; + map[VIDEO_ROUTE_BUILT_IN_AND_TV_OUT] = QList() << WORKER_OUTPUT_BUILTIN_DISPLAY << WORKER_OUTPUT_TVOUT; + } + + return map; + +} + diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererDolby.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererDolby.cpp new file mode 100644 index 0000000..91a6fa0 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererDolby.cpp @@ -0,0 +1,312 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwGstRendererDolby.h" + +#include + +const int DEFAULT_COLOR = 2; +const int DEFAULT_ROOM_SIZE = 2; +const int MAX_VALUE = 4; + +enum MafwDolbyStates +{ + MafwDolbyOff, + MafwDolbyOn, + MafwDolbyAuto +}; + +MafwGstRendererDolby::MafwGstRendererDolby( QObject* parent ): + QObject(parent), + m_dolbyConfMusic(0), + m_dolbyConfMusicRoom(0), + m_dolbyConfMusicColor(0), + m_dolbyConfVideo(0), + m_dolbyConfVideoRoom(0), + m_dolbyConfVideoColor(0) +{ + qDebug() << __PRETTY_FUNCTION__; + m_currentMusicDolbyState = MafwDolbyOff; + m_currentMusicDolbyRoom = DEFAULT_ROOM_SIZE; + m_currentMusicDolbyColor = DEFAULT_COLOR; + m_currentVideoDolbyState = MafwDolbyOff; + m_currentVideoDolbyRoom = DEFAULT_ROOM_SIZE; + m_currentVideoDolbyColor = DEFAULT_COLOR; +} + +void MafwGstRendererDolby::initialize() +{ + if (!m_dolbyConfMusic) + { + m_dolbyConfMusic = new GConfItem("/apps/Multimedia/music/dolbyConf", this); + } + if (!m_dolbyConfMusicRoom) + { + m_dolbyConfMusicRoom = new GConfItem("/apps/Multimedia/music/dolbyConfRoom", this); + } + if (!m_dolbyConfMusicColor) + { + m_dolbyConfMusicColor = new GConfItem("/apps/Multimedia/music/dolbyConfColor", this); + } + if (!m_dolbyConfVideo) + { + m_dolbyConfVideo = new GConfItem("/apps/Multimedia/video/dolbyConf", this); + } + if (!m_dolbyConfVideoRoom) + { + m_dolbyConfVideoRoom = new GConfItem("/apps/Multimedia/video/dolbyConfRoom", this); + } + if (!m_dolbyConfVideoColor) + { + m_dolbyConfVideoColor = new GConfItem("/apps/Multimedia/video/dolbyConfColor", this); + } + if (!m_dolbyConfMusic->value().toString().isEmpty()) + { + valueMusicChanged(); + connect(m_dolbyConfMusic, SIGNAL(valueChanged()), this, SLOT(valueMusicChanged())); + connect(m_dolbyConfMusicRoom, SIGNAL(valueChanged()), this, SLOT(valueMusicChanged())); + connect(m_dolbyConfMusicColor, SIGNAL(valueChanged()), this, SLOT(valueMusicChanged())); + } + if (!m_dolbyConfVideo->value().toString().isEmpty()) + { + valueVideoChanged(); + connect(m_dolbyConfVideo, SIGNAL(valueChanged()), this, SLOT(valueVideoChanged())); + connect(m_dolbyConfVideoRoom, SIGNAL(valueChanged()), this, SLOT(valueVideoChanged())); + connect(m_dolbyConfVideoColor, SIGNAL(valueChanged()), this, SLOT(valueVideoChanged())); + } +} + +MafwGstRendererDolby::~MafwGstRendererDolby() +{ + qDebug() << __PRETTY_FUNCTION__; +} + +bool MafwGstRendererDolby::setMusicDolbyState (uint value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value <= MafwDolbyAuto) + { + m_currentMusicDolbyState = value; + m_dolbyConfMusic->set(m_currentMusicDolbyState); + return true; + } + else + { + m_currentMusicDolbyState = MafwDolbyOff; + m_dolbyConfMusic->set(m_currentMusicDolbyState); + return false; + } +} + +bool MafwGstRendererDolby::setMusicDolbyRoom (int value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value < 0) + { + m_currentMusicDolbyRoom = 0; + m_dolbyConfMusicRoom->set(m_currentMusicDolbyRoom); + } + else if ( value > MAX_VALUE) + { + m_currentMusicDolbyRoom = MAX_VALUE; + m_dolbyConfMusicRoom->set(m_currentMusicDolbyRoom); + } + else + { + m_currentMusicDolbyRoom = value; + m_dolbyConfMusicRoom->set(m_currentMusicDolbyRoom); + } + return true; +} + +bool MafwGstRendererDolby::setMusicDolbyColor (int value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value < 0) + { + m_currentMusicDolbyColor = 0; + m_dolbyConfMusicColor->set(m_currentMusicDolbyColor); + } + else if ( value > MAX_VALUE) + { + m_currentMusicDolbyColor = MAX_VALUE; + m_dolbyConfMusicColor->set(m_currentMusicDolbyColor); + } + else + { + m_currentMusicDolbyColor = value; + m_dolbyConfMusicColor->set(m_currentMusicDolbyColor); + } + return true; +} + +bool MafwGstRendererDolby::setVideoDolbyState (uint value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value <= MafwDolbyAuto) + { + m_currentVideoDolbyState = value; + m_dolbyConfVideo->set(int(m_currentVideoDolbyState)); + return true; + } + else + { + m_currentVideoDolbyState = MafwDolbyOff; + m_dolbyConfVideo->set(int(m_currentVideoDolbyState)); + return false; + } +} + +bool MafwGstRendererDolby::setVideoDolbyRoom (int value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value < 0) + { + m_currentVideoDolbyRoom = 0; + m_dolbyConfVideoRoom->set(m_currentVideoDolbyRoom); + } + else if ( value > MAX_VALUE) + { + m_currentVideoDolbyRoom = MAX_VALUE; + m_dolbyConfVideoRoom->set(m_currentVideoDolbyRoom); + } + else + { + m_currentVideoDolbyRoom = value; + m_dolbyConfVideoRoom->set(m_currentVideoDolbyRoom); + } + return true; +} + +bool MafwGstRendererDolby::setVideoDolbyColor (int value) +{ + qDebug() << __PRETTY_FUNCTION__ << value; + if ( value < 0) + { + m_currentVideoDolbyColor = 0; + m_dolbyConfVideoColor->set(m_currentVideoDolbyColor); + } + else if ( value > MAX_VALUE) + { + m_currentVideoDolbyColor = MAX_VALUE; + m_dolbyConfVideoColor->set(m_currentVideoDolbyColor); + } + else + { + m_currentVideoDolbyColor = value; + m_dolbyConfVideoColor->set(m_currentVideoDolbyColor); + } + return true; +} + +void MafwGstRendererDolby::valueMusicChanged() +{ + m_currentMusicDolbyState = m_dolbyConfMusic->value().toUInt(); + if (!(m_currentMusicDolbyState <= MafwDolbyAuto)) + { + m_currentMusicDolbyState = MafwDolbyOff; + m_currentMusicDolbyRoom = m_dolbyConfMusicRoom->value().toInt(); + if (m_currentMusicDolbyRoom < 0) + { + m_currentMusicDolbyRoom = 0; + } + if (m_currentMusicDolbyRoom > MAX_VALUE) + { + m_currentMusicDolbyRoom = MAX_VALUE; + } + m_currentMusicDolbyColor = m_dolbyConfMusicColor->value().toInt(); + if (m_currentMusicDolbyColor < 0) + { + m_currentMusicDolbyColor = 0; + } + if (m_currentMusicDolbyColor > MAX_VALUE) + { + m_currentMusicDolbyColor = MAX_VALUE; + } + } + qDebug() << __PRETTY_FUNCTION__ << "state" << m_currentMusicDolbyState; + qDebug() << __PRETTY_FUNCTION__ << "room" << m_currentMusicDolbyRoom; + qDebug() << __PRETTY_FUNCTION__ << "color" << m_currentMusicDolbyColor; + Q_EMIT mafwDHMMusicPropertyChanged(); +} + +void MafwGstRendererDolby::valueVideoChanged() +{ + m_currentVideoDolbyState = m_dolbyConfVideo->value().toUInt(); + if (!(m_currentVideoDolbyState <= MafwDolbyAuto)) + { + m_currentVideoDolbyState = MafwDolbyOff; + m_currentVideoDolbyRoom = m_dolbyConfVideoRoom->value().toInt(); + if (m_currentVideoDolbyRoom < 0) + { + m_currentVideoDolbyRoom = 0; + } + if (m_currentVideoDolbyRoom > MAX_VALUE) + { + m_currentVideoDolbyRoom = MAX_VALUE; + } + m_currentVideoDolbyColor = m_dolbyConfVideoColor->value().toInt(); + if (m_currentVideoDolbyColor < 0) + { + m_currentVideoDolbyColor = 0; + } + if (m_currentVideoDolbyColor > MAX_VALUE) + { + m_currentVideoDolbyColor = MAX_VALUE; + } + } + qDebug() << __PRETTY_FUNCTION__ << "state" << m_currentVideoDolbyState; + qDebug() << __PRETTY_FUNCTION__ << "room" << m_currentVideoDolbyRoom; + qDebug() << __PRETTY_FUNCTION__ << "color" << m_currentVideoDolbyColor; + Q_EMIT mafwDHMVideoPropertyChanged(); +} + +uint MafwGstRendererDolby::getMusicDolbyState () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentMusicDolbyState; + return m_currentMusicDolbyState; +} + +int MafwGstRendererDolby::getMusicDolbyRoom () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentMusicDolbyRoom; + return m_currentMusicDolbyRoom; +} + +int MafwGstRendererDolby::getMusicDolbyColor () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentMusicDolbyColor; + return m_currentMusicDolbyColor; +} + +uint MafwGstRendererDolby::getVideoDolbyState () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentVideoDolbyState; + return m_currentVideoDolbyState; +} + +int MafwGstRendererDolby::getVideoDolbyRoom () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentVideoDolbyRoom; + return m_currentVideoDolbyRoom; +} + +int MafwGstRendererDolby::getVideoDolbyColor () +{ + qDebug() << __PRETTY_FUNCTION__ << m_currentVideoDolbyColor; + return m_currentVideoDolbyColor; +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererHaltState.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererHaltState.cpp new file mode 100644 index 0000000..8fbe2ef --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererHaltState.cpp @@ -0,0 +1,161 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwGstRendererHaltState.h" + +int MafwGstRendererHaltState::DECAY_TIME = 20; + +/******************************************************************** + * MafwGstRendererHaltState::MafwGstRendererHaltState + ********************************************************************/ +MafwGstRendererHaltState::MafwGstRendererHaltState() + : + QObject(), + m_state(MafwRenderer::Invalid), + m_position(-1) +{ + connect(&m_decayTimer, SIGNAL(timeout()), + this, SIGNAL(decayed())); +} + +/******************************************************************** + * MafwGstRendererHaltState::MafwGstRendererHaltState + ********************************************************************/ +MafwGstRendererHaltState::MafwGstRendererHaltState(const QString &uri, + MafwRenderer::State state, + int position) + : + QObject(), + m_uri(uri), + m_state(state), + m_position(position) +{ + connect(&m_decayTimer, SIGNAL(timeout()), + this, SIGNAL(decayed())); + initializeDecayTimer(); +} + +/******************************************************************** + * MafwGstRendererHaltState::MafwGstRendererHaltState + ********************************************************************/ +MafwGstRendererHaltState::MafwGstRendererHaltState(const MafwGstRendererHaltState &other) + : + QObject() +{ + *this = other; +} + +/******************************************************************** + * MafwGstRendererHaltState::operator = + ********************************************************************/ +MafwGstRendererHaltState& MafwGstRendererHaltState::operator =(const MafwGstRendererHaltState &other) +{ + if( this == &other ) + { + return *this; + } + + this->m_uri = other.m_uri; + this->m_position = other.m_position; + this->m_state = other.m_state; + + initializeDecayTimer(); + + return *this; +} + +/******************************************************************** + * MafwGstRendererHaltState::~MafwGstRendererHaltState + ********************************************************************/ +MafwGstRendererHaltState::~MafwGstRendererHaltState() +{ + +} + +/******************************************************************** + * MafwGstRendererHaltState::isSet + ********************************************************************/ +bool MafwGstRendererHaltState::isSet() const +{ + return ((m_uri.length() > 0) + && (m_state != MafwRenderer::Invalid) + && (m_decayTimer.isActive() || m_state == MafwRenderer::Paused)); +} + +/******************************************************************** + * MafwGstRendererHaltState::setState + ********************************************************************/ +void MafwGstRendererHaltState::clear() +{ + m_uri.clear(); + m_position = -1; + m_state = MafwRenderer::Invalid; + m_decayTimer.stop(); +} + +/******************************************************************** + * MafwGstRendererHaltState::setState + ********************************************************************/ +void MafwGstRendererHaltState::setState(MafwRenderer::State newState) +{ + m_state = newState; + if( newState == MafwRenderer::Paused ) + { + m_decayTimer.stop(); + } +} + +/******************************************************************** + * MafwGstRendererHaltState::uri + ********************************************************************/ +QString MafwGstRendererHaltState::uri() const +{ + return m_uri; +} + +/******************************************************************** + * MafwGstRendererHaltState::state + ********************************************************************/ +MafwRenderer::State MafwGstRendererHaltState::state() const +{ + return m_state; +} + +/******************************************************************** + * MafwGstRendererHaltState::position + ********************************************************************/ +int MafwGstRendererHaltState::position() const +{ + return m_position; +} + +/******************************************************************** + * MafwGstRendererHaltState::initializeDecayTimer + ********************************************************************/ +void MafwGstRendererHaltState::initializeDecayTimer() +{ + if( m_uri.length() > 0 && m_state != MafwRenderer::Invalid ) + { + m_decayTimer.setSingleShot(true); + m_decayTimer.setInterval(DECAY_TIME * 1000); + m_decayTimer.start(); + } + else + { + m_decayTimer.stop(); + } +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererNetworkMonitor.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererNetworkMonitor.cpp new file mode 100644 index 0000000..504676d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererNetworkMonitor.cpp @@ -0,0 +1,60 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwGstRendererNetworkMonitor.h" +#include "MafwGstRendererHaltState.h" + +#include +#include + +/******************************************************************** + * MafwGstRendererNetworkMonitor::MafwGstRendererNetworkMonitor + ********************************************************************/ +MafwGstRendererNetworkMonitor::MafwGstRendererNetworkMonitor() + : + m_networkManager(new QNetworkConfigurationManager(this)) +{ + connect(m_networkManager, SIGNAL(configurationChanged(QNetworkConfiguration)), + this, SLOT(handleConfigurationChange(QNetworkConfiguration))); +} + +/******************************************************************** + * MafwGstRendererNetworkMonitor::MafwGstRendererNetworkMonitor + ********************************************************************/ +MafwGstRendererNetworkMonitor::~MafwGstRendererNetworkMonitor() +{ + +} + +/******************************************************************** + * MafwGstRendererNetworkMonitor::handleConfigurationChange + ********************************************************************/ +void MafwGstRendererNetworkMonitor::handleConfigurationChange(const QNetworkConfiguration &config) +{ + qDebug() << __PRETTY_FUNCTION__ << "Configs status: " << config.name() << config.state(); + + QNetworkConfiguration::StateFlags flags = config.state(); + if( flags.testFlag(QNetworkConfiguration::Active) ) + { + Q_EMIT networkChangeFinished(); + m_currentConfiguration = config; + } + else if( !m_currentConfiguration.isValid() || config == m_currentConfiguration ) + { + Q_EMIT prepareNetworkChange(); + } +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlaylistFileUtility.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlaylistFileUtility.cpp new file mode 100644 index 0000000..eb70f10 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlaylistFileUtility.cpp @@ -0,0 +1,165 @@ +#include "MafwGstRendererPlaylistFileUtility.h" +#include +#include +#include +#include + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::MafwGstRendererPlaylistFileUtility + ********************************************************************/ +MafwGstRendererPlaylistFileUtility::MafwGstRendererPlaylistFileUtility(QObject* parent): + QObject(parent), m_parserId(0), m_firstItem(false) +{ + g_type_init(); +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::MafwGstRendererPlaylistFileUtility + ********************************************************************/ +MafwGstRendererPlaylistFileUtility::~MafwGstRendererPlaylistFileUtility() +{ + qDebug() << __PRETTY_FUNCTION__; +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::getUriList + ********************************************************************/ +QStringList MafwGstRendererPlaylistFileUtility::getUriList() +{ + return m_uriList; +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::playPlaylistFile + ********************************************************************/ +void MafwGstRendererPlaylistFileUtility::parsePlaylistFile(const QUrl& url) +{ + qDebug() << __PRETTY_FUNCTION__; + + if (url.isValid() && !url.scheme().isEmpty()) + { + m_uriList.clear(); + m_parserId = totem_pl_parser_new (); + g_object_set(m_parserId, "recurse", false, "disable-unsafe", + true, NULL); + g_signal_connect(G_OBJECT(m_parserId), "entry-parsed", G_CALLBACK(uriParsed), this); + totem_pl_parser_parse_async(m_parserId, + url.toString().toAscii().constData(), + false, + 0, + GAsyncReadyCallback(readyCb), + (void *)this); + g_object_unref(m_parserId); + m_firstItem = true; + } + else + { + Q_EMIT parsingReady(false); + } +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::takeFirstUri + ********************************************************************/ +QString MafwGstRendererPlaylistFileUtility::takeFirstUri() +{ + if (m_uriList.isEmpty()) + { + qDebug() << __PRETTY_FUNCTION__ << ": there are no more items parsed"; + return QString(); + } + else + { + return m_uriList.takeFirst(); + } +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::setPendingError + ********************************************************************/ +void MafwGstRendererPlaylistFileUtility::setPendingError(MafwError& error) +{ + m_pendingError = error; +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::takePendingError + ********************************************************************/ +MafwError MafwGstRendererPlaylistFileUtility::takePendingError() +{ + MafwError retMe = m_pendingError; + m_pendingError = MafwError(); + return retMe; +} + + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::uriParsed + ********************************************************************/ +void MafwGstRendererPlaylistFileUtility::uriParsed(TotemPlParser* parser, + gchar* uri, + gpointer /*metadata*/, + MafwGstRendererPlaylistFileUtility* self) +{ + qDebug() << __PRETTY_FUNCTION__ << parser << uri; + + if (uri && (parser == self->m_parserId)) + { + QString modifiedURI = self->manHandleURI(uri); + self->m_uriList.append(modifiedURI); + if (self->m_firstItem) + { + Q_EMIT self->firstItemParsed(); + self->m_firstItem = false; + } + } +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::readyCb + ********************************************************************/ +void MafwGstRendererPlaylistFileUtility::readyCb(TotemPlParser* parser, + GAsyncResult* async_result, + MafwGstRendererPlaylistFileUtility* self) +{ + qDebug() << __PRETTY_FUNCTION__ << parser; + if (parser == self->m_parserId) + { + GError *error = 0; + bool success = true; + + TotemPlParserResult result = totem_pl_parser_parse_finish(parser, + async_result, + &error); + qDebug() << __PRETTY_FUNCTION__ << result; + if (result != TOTEM_PL_PARSER_RESULT_SUCCESS) + { + success = false; + qWarning() << __PRETTY_FUNCTION__ << ": Playlist file parsing failed"; + if (error) + { + qWarning() << error->message; + g_error_free (error); + } + } + //Actually parsing is not ready yet, we might have no results yet. + Q_EMIT self->parsingReady(success); + } +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::manHandleURI + ********************************************************************/ +QString MafwGstRendererPlaylistFileUtility::manHandleURI(const QString &itemUri) const +{ + qDebug() << __FUNCTION__ << "Orig: " << itemUri; + QString modifiedUri = itemUri; + + if( itemUri.endsWith(".asf", Qt::CaseInsensitive) + && itemUri.startsWith("http://", Qt::CaseInsensitive) ) + { + modifiedUri.replace(0,4, "mmsh"); + } + qDebug() << __FUNCTION__ << "Handled: " << modifiedUri; + return modifiedUri; +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlugin.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlugin.cpp new file mode 100644 index 0000000..734ddd9 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererPlugin.cpp @@ -0,0 +1,145 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include +#include +#include + +#include + +#include "MafwGstRendererPlugin.h" +#include "MafwGstRenderer.h" + +#ifdef _VERSION_INFO +#include "version.h" +#endif + +const QString PLUGIN_NAME = "MafwGstRendererPlugin"; +const QString RENDERER_UUID = "mafw_gst_renderer"; +const QString DBUS_WRAPPER_NAME = "qmafw-dbus-wrapper"; +const QString RENDERER_PLUGIN_CONFIG_FILE = "/usr/share/qmafw/mafw-gst-renderer-plugin.conf"; + + +MafwGstRendererPlugin::~MafwGstRendererPlugin() +{ + qDebug() << __PRETTY_FUNCTION__; + for(int i = 0; i < m_rendererIds.count(); i++) + { + m_registry->removeExtension(m_rendererIds.at(i)); + } +} + +void MafwGstRendererPlugin::initialize(MafwInternalRegistry* registry) +{ +#ifdef _VERSION_INFO + qDebug() << "mafw-gst-renderer revision:" << revision; + qDebug() << "mafw-gst-renderer library builtime:" << build_time; +#endif + + Q_ASSERT(registry); + + m_registry = registry; + + QString rendererArrayKey; + QString appname = QCoreApplication::applicationName(); + // appname can contain full path to config file + if(appname.endsWith(DBUS_WRAPPER_NAME)) + { + // We are loading out-process renderers from config file + rendererArrayKey = "renderers"; + loadRenderers(rendererArrayKey); + } + else + { + // We are loading in-process renderers from config file + rendererArrayKey = "in-process-renderers"; + loadRenderers(rendererArrayKey); + } + + // if there are no gst-renderers in config file, we create a "basic" gst-renderer + if(m_rendererIds.isEmpty()) + { + MafwGstRenderer *rnd = new MafwGstRenderer(RENDERER_UUID, + PLUGIN_NAME, + "QMAFW GStreamer Renderer", + registry); + + QSettings settings(RENDERER_PLUGIN_CONFIG_FILE, QSettings::NativeFormat); + + if(rnd->initialize(&settings)) + { + m_registry->addRenderer(rnd); + m_rendererIds.append(RENDERER_UUID); + } + else + { + qCritical() << "Failed to initialize QMAFW GStreamer Renderer"; + delete rnd; + } + } +} + +void MafwGstRendererPlugin::loadRenderers(const QString& rendererArrayKey) +{ + QSettings settings(RENDERER_PLUGIN_CONFIG_FILE, QSettings::NativeFormat); + QString id; + QString friendlyname; + + QList rnds; + + // Configuration file contains the array of renderer names and uuids as string. + // beginReadArray returns size of the array. + int size = settings.beginReadArray(rendererArrayKey); + for(int i = 0; i < size; i++) + { + settings.setArrayIndex(i); + id = settings.value("Id").toString(); + friendlyname = settings.value("FriendlyName").toString(); + MafwGstRenderer *rnd = new MafwGstRenderer(id, + PLUGIN_NAME, + friendlyname, + m_registry); + rnds.append(rnd); + } + settings.endArray(); + + Q_FOREACH( MafwGstRenderer *rnd, rnds ) + { + if(rnd->initialize(&settings)) + { + m_registry->addRenderer(rnd); + m_rendererIds.append(rnd->uuid()); + } + else + { + qCritical() << "Failed to initialize" << rnd->name(); + delete rnd; + } + } +} + +QString MafwGstRendererPlugin::name() const +{ + return PLUGIN_NAME; +} + +/***************************************************************************** + * Plugin export + ****************************************************************************/ +Q_EXPORT_PLUGIN2(qmafw-gst-renderer-plugin, MafwGstRendererPlugin) diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstRendererVolume.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstRendererVolume.cpp new file mode 100644 index 0000000..daf3b95 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstRendererVolume.cpp @@ -0,0 +1,476 @@ +#include "MafwGstRendererVolume.h" + +#include +#include + +#include +#include + +// The default PulseAudioMainVolume DBus API socket +#define DEFAULT_ADDRESS "unix:path=/var/run/pulse/dbus-socket" +#define ROLE = "x-maemo"; + +#define PULSE_CORE_PATH "/org/pulseaudio/core1" +#define STREAM_RESTORE_PATH "/org/pulseaudio/stream_restore1" +#define STREAM_RESTORE_IF "org.PulseAudio.Ext.StreamRestore1" +#define GET_ENTRY_METHOD "GetEntryByName" +#define STREAM_RESTORE_IF_ENTRY STREAM_RESTORE_IF ".RestoreEntry" +#define STREAM_RESTORE_VOLUME_SIGNAL STREAM_RESTORE_IF_ENTRY ".VolumeUpdated" + +#define ENTRY_NAME "sink-input-by-media-role:x-maemo" +//# 100% volume in Pulseaudio's native volume units. +const uint VOLUME_NORM = 0x10000; +//Place of mono channel at pulse audio's channel position enumeration +const uint VOLUME_CHANNEL_MONO = 0; +//Delay for attempting to reconnect to pulseaudio +const uint PULSE_RESTART_DELAY = 2000; + +/******************************************************************** + * MafwGstRendererVolume::MafwGstRendererVolume + ********************************************************************/ +MafwGstRendererVolume::MafwGstRendererVolume(): m_currentVolume(0), m_pendingVolumeValue(0), + m_dbusConnection(0), m_objectPath(QString()), m_pendingCall(0) +{ + qDebug() << __PRETTY_FUNCTION__; + + connectToPulseAudio(); +} + +/******************************************************************** + * MafwGstRendererVolume::connectToPulseAudio + ********************************************************************/ +void MafwGstRendererVolume::connectToPulseAudio() +{ + qDebug() << __PRETTY_FUNCTION__; + DBusError error; + QByteArray address = qgetenv("PULSE_DBUS_SERVER"); + + if (address.isEmpty()) + { + address = QByteArray(DEFAULT_ADDRESS); + } + + dbus_error_init (&error); + + if (m_dbusConnection) + { + DBUSConnectionEventLoop::removeConnection(m_dbusConnection); + dbus_connection_unref(m_dbusConnection); + m_dbusConnection = 0; + } + + m_dbusConnection = dbus_connection_open (address.constData(), &error); + + if (dbus_error_is_set(&error)) + { + qCritical() << "Unable to open dbus connection to pulse audio:" << error.message; + dbus_error_free (&error); + QTimer::singleShot(PULSE_RESTART_DELAY, this, SLOT(connectToPulseAudio())); + } + else + { + if (DBUSConnectionEventLoop::addConnection(m_dbusConnection)) + { + dbus_connection_add_filter ( + m_dbusConnection, + (DBusHandleMessageFunction) handleIncomingMessages, + (void *) this, NULL); + + getRestoreEntryForMediaRole(); + } + else + { + qCritical() << "DBUSConnectionEventLoop failure"; + dbus_connection_unref(m_dbusConnection); + m_dbusConnection = 0; + } + } +} + +/******************************************************************** + * MafwGstRendererVolume::~MafwGstRendererVolume() + ********************************************************************/ +MafwGstRendererVolume::~MafwGstRendererVolume() +{ + if(m_pendingCall) + { + dbus_pending_call_cancel(m_pendingCall); + } + DBUSConnectionEventLoop::removeConnection(m_dbusConnection); + dbus_connection_unref(m_dbusConnection); +} +/******************************************************************** + * We need the object path for the RestoreEntry of the "x-maemo" role. + * GetEntryByName with parameter "sink-input-by-media-role:x-maemo" is used + * for that. + ********************************************************************/ +void MafwGstRendererVolume::getRestoreEntryForMediaRole() +{ + qDebug() << __PRETTY_FUNCTION__; + DBusMessage *msg; + DBusError error; + + dbus_error_init (&error); + + msg = dbus_message_new_method_call(0, + STREAM_RESTORE_PATH, + STREAM_RESTORE_IF, + GET_ENTRY_METHOD); + const char *name = ENTRY_NAME; + dbus_message_append_args (msg, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + + DBusPendingCall *pending = 0; + //Return value taken for satisfying coverity tool + bool outOfMemory = dbus_connection_send_with_reply( m_dbusConnection, msg, &pending, -1 ); + Q_UNUSED(outOfMemory); + m_pendingCall = pending; + + if (pending) + { + qDebug() << __PRETTY_FUNCTION__ << "pending call sent!"; + dbus_pending_call_set_notify( pending, + (DBusPendingCallNotifyFunction) getEntryReply, + (void *)this, + NULL ); + dbus_message_unref(msg); + } + qDebug() << __PRETTY_FUNCTION__ << "exit"; +} + +/******************************************************************** + * Now we have the RestoreEntry object path for "x-maemo". Next we just + * need to start listening for the VolumeUpdated signals from that object, + * and use the Volume property for controlling the role volume. + ********************************************************************/ +void MafwGstRendererVolume::getEntryReply(DBusPendingCall *pending, MafwGstRendererVolume *self) +{ + qDebug() << __PRETTY_FUNCTION__; + self->m_pendingCall = 0; + DBusMessage *reply; + DBusError error; + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) + { + qWarning() << "Unable to get volume from pulse audio:" << error.message; + dbus_error_free (&error); + //Try to reconnect + QTimer::singleShot(0, self, SLOT(connectToPulseAudio())); + } + else if (reply && (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)) + { + const char *object_path; + bool argError = dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID); + if (!argError) + { + qWarning() << "Unable to get volume from pulse audio:" << error.message; + dbus_error_free (&error); + //Try to reconnect + QTimer::singleShot(0, self, SLOT(connectToPulseAudio())); + } + + qDebug() << __PRETTY_FUNCTION__ << "Object path: " << object_path; + self->m_objectPath = object_path; + + if (self->m_pendingVolumeValue > 0) + { + qDebug() << __PRETTY_FUNCTION__ << "setting volume to level " << self->m_pendingVolumeValue; + self->listenVolumeSignals(); + self->setVolume(self->m_pendingVolumeValue); + self->m_pendingVolumeValue = 0; + } + else + { + qDebug() << __PRETTY_FUNCTION__ << "getting initial volume level."; + DBusMessage *msg; + DBusError error2; + dbus_error_init (&error2); + + msg = dbus_message_new_method_call(0, + object_path, + DBUS_INTERFACE_PROPERTIES, + "Get"); + const char* interface = STREAM_RESTORE_IF_ENTRY; + const char* property = "Volume"; + + dbus_message_append_args (msg, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID); + + DBusPendingCall *pending = 0; + //Return value taken for satisfying coverity tool + bool outOfMemory = dbus_connection_send_with_reply( self->m_dbusConnection, msg, &pending, -1 ); + Q_UNUSED(outOfMemory); + self->m_pendingCall = pending; + if (pending) + { + qDebug() << __PRETTY_FUNCTION__ << "pending call sent!"; + dbus_pending_call_set_notify( pending, + (DBusPendingCallNotifyFunction) volumeReply, + (void *)self, + NULL ); + dbus_message_unref(msg); + } + } + } + dbus_message_unref (reply); +} + +/******************************************************************** + * MafwGstRendererVolume::volumeReply + ********************************************************************/ +void MafwGstRendererVolume::volumeReply(DBusPendingCall *pending, MafwGstRendererVolume *self) +{ + self->m_pendingCall = 0; + Q_UNUSED (self); + qDebug() << __PRETTY_FUNCTION__; + + DBusMessage *reply; + reply = dbus_pending_call_steal_reply(pending); + + DBusError error; + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) + { + qWarning() << "MafwGstRendererVolume: Unable to get volume from pulse audio:" << error.message; + dbus_error_free (&error); + } + else + { + DBusMessageIter iter, array_iterator; + dbus_message_iter_init (reply, &iter); + if(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) + { + dbus_message_iter_recurse (&iter, &array_iterator); + } + + if (dbus_message_iter_get_arg_type (&array_iterator) == DBUS_TYPE_ARRAY) + { + self->readVolumeFromStruct(&array_iterator); + Q_EMIT self->volumeChanged(self->m_currentVolume); + } + else + { + qCritical("Unable to get initial volume from Pulse Audio!!"); + } + } + dbus_message_unref (reply); + self->listenVolumeSignals(); +} + +/******************************************************************** + * MafwGstRendererVolume::listenVolumeSignals + ********************************************************************/ +void MafwGstRendererVolume::listenVolumeSignals() +{ + qDebug() << __PRETTY_FUNCTION__; + + DBusMessage *message = 0; + char *signal = (char *) STREAM_RESTORE_VOLUME_SIGNAL; + char **emptyarray = { 0 }; + + message = dbus_message_new_method_call (0, + PULSE_CORE_PATH, + 0, + "ListenForSignal"); + + dbus_message_append_args (message, + DBUS_TYPE_STRING, &signal, + DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &emptyarray, 0, + DBUS_TYPE_INVALID); + + dbus_connection_send (m_dbusConnection, message, NULL); + dbus_connection_flush (m_dbusConnection); + dbus_message_unref (message); +} + +/******************************************************************** + * MafwGstRendererVolume::handleIncomingMessages + ********************************************************************/ +void MafwGstRendererVolume::handleIncomingMessages (DBusConnection* conn, + DBusMessage* message, + MafwGstRendererVolume* self) +{ + qDebug(__PRETTY_FUNCTION__); + Q_UNUSED (conn); + + if (message && + dbus_message_has_member (message, "VolumeUpdated") && + dbus_message_has_interface(message, STREAM_RESTORE_IF_ENTRY) && + dbus_message_has_path(message, self->m_objectPath.toAscii())) + { + qDebug() << "MafwGstRendererVolume: VolumeUpdated signal received."; + DBusError error; + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message)) + { + qWarning() << "Got volume error from pulse audio:" << error.message; + dbus_error_free (&error); + } + + DBusMessageIter iter; + dbus_message_iter_init (message, &iter); + + if (self->readVolumeFromStruct(&iter)) + { + Q_EMIT self->volumeChanged(self->m_currentVolume); + } + } + //When a connection is disconnected, you are guaranteed to get a signal "Disconnected" from the interface DBUS_INTERFACE_LOCAL, path DBUS_PATH_LOCAL. + else if (message && + dbus_message_has_member (message, "Disconnected") && + dbus_message_get_interface(message) == QString(DBUS_INTERFACE_LOCAL) && + dbus_message_get_path(message) == QString(DBUS_PATH_LOCAL)) + { + qWarning("MafwGstRendererVolume: Connection with pulse audio is disconnected!"); + QTimer::singleShot(PULSE_RESTART_DELAY, self, SLOT(connectToPulseAudio())); + qDebug("MafwGstRendererVolume: Trying to reconnect."); + } + +} + +/******************************************************************** + * There is a dbus variant containing array of structures. Each structure + * contains channels postion and the volume level of this position + ********************************************************************/ +bool MafwGstRendererVolume::readVolumeFromStruct(DBusMessageIter *iterator) +{ + qDebug(__PRETTY_FUNCTION__); + bool volumeChanged = false; + DBusMessageIter struct_iterator; + dbus_message_iter_recurse (iterator, &struct_iterator); + int volume = -1; + + while (dbus_message_iter_get_arg_type(&struct_iterator) == DBUS_TYPE_STRUCT) + { + DBusMessageIter variant; + dbus_message_iter_recurse (&struct_iterator, &variant); + int channel, value = 0; + + if (dbus_message_iter_get_arg_type (&variant) == DBUS_TYPE_UINT32) + { + dbus_message_iter_get_basic (&variant, &channel); + qDebug("Channel %d", channel); + dbus_message_iter_next (&variant); + dbus_message_iter_get_basic (&variant, &value); + + value = qRound((float)value / (float)VOLUME_NORM * 100); + + //We're interested in all the channels that stream-restore happens to give you. + //We have to somehow map between a single volume value and per-channel volume. + //The usual way to do the mapping is just to use the loudest channel as + //the overall volume + if (value > volume) + { + uint newVolume = value; + if (newVolume != m_currentVolume) + { + m_currentVolume = newVolume; + volumeChanged = true; + qDebug("MafwGstRendererVolume: current volume level has changed: %d", m_currentVolume); + } + } + + if (m_currentVolume > 100) //MAFW volume has range 0-100 + { + qWarning("MafwGstRendererVolume: Pulse audio signals volume level which is out-of range!"); + m_currentVolume = 100; + break; + } + } + else + { + qWarning("MafwGstRendererVolume: Invalid volume value from pulse audio!"); + } + dbus_message_iter_next (&struct_iterator); + } + return volumeChanged; +} + +/******************************************************************** + * MafwGstRendererVolume::getVolume + ********************************************************************/ +uint MafwGstRendererVolume::getVolume() +{ + qDebug(__PRETTY_FUNCTION__); + return m_currentVolume; +} + +/******************************************************************** + * Incoming value has range 0-99 pulseaudio uses values 0-VOLUME_NORM + ********************************************************************/ +bool MafwGstRendererVolume::setVolume (uint value) +{ + bool success = true; + qDebug("MafwGstRendererVolume::setVolume (uint %d)", value); + if (m_objectPath.isEmpty()) + { + qDebug() << "MafwGstRendererVolume: Can not set volume yet. Waiting for RestoreEntry object path"; + m_pendingVolumeValue = value; + return success; + } + + const char* interface = STREAM_RESTORE_IF_ENTRY; + const char* property = "Volume"; + if (value > 100) //MAFW volume has range 0-100 + { + qWarning("MafwGstRendererVolume: Trying to set volume level which is out-of range!"); + value = (uint)100; + } + uint nativeValue = (((float)value / (float)100) * VOLUME_NORM); + DBusMessage* message; + message = dbus_message_new_method_call(0, + m_objectPath.toAscii(), + DBUS_INTERFACE_PROPERTIES, + "Set"); + + if ( dbus_message_append_args(message, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID)) + { + //Compose the dbus variant containing an array of struct of pair + //of unsigned integers va(uu) + DBusMessageIter argument_iterator, variant_iterator, array_iterator, struct_iterator; + dbus_message_iter_init_append (message, &argument_iterator); + dbus_message_iter_open_container (&argument_iterator, + DBUS_TYPE_VARIANT, + "a(uu)", + &variant_iterator); + dbus_message_iter_open_container (&variant_iterator, + DBUS_TYPE_ARRAY, + "(uu)", + &array_iterator); + dbus_message_iter_open_container (&array_iterator, + DBUS_TYPE_STRUCT, + NULL, + &struct_iterator); + + dbus_message_iter_append_basic (&struct_iterator, DBUS_TYPE_UINT32, &VOLUME_CHANNEL_MONO); + dbus_message_iter_append_basic (&struct_iterator, DBUS_TYPE_UINT32, &nativeValue); + + dbus_message_iter_close_container (&array_iterator, &struct_iterator); + dbus_message_iter_close_container (&variant_iterator, &array_iterator); + dbus_message_iter_close_container (&argument_iterator, &variant_iterator); + + dbus_connection_send (m_dbusConnection, message, NULL); + dbus_connection_flush (m_dbusConnection); + } + else + { + qWarning("Cannot set volume!"); + success = false; + } + dbus_message_unref (message); + + return success; +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwGstScreenshot.cpp b/qmafw-gst-subtitles-renderer/src/MafwGstScreenshot.cpp new file mode 100644 index 0000000..610ab1d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwGstScreenshot.cpp @@ -0,0 +1,223 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwGstScreenshot.h" +#include + +MafwGstScreenshot::MafwGstScreenshot(QObject *parent) : QObject(parent) +{ + qDebug() << __PRETTY_FUNCTION__; + + m_src = NULL; + m_sink = NULL; + m_pipeline = NULL; + m_filter = NULL; + m_csp = NULL; + m_enc = NULL; + m_bus = NULL; + m_caps = NULL; + m_structure = NULL; + m_handler_id = 0; +} + +MafwGstScreenshot::~MafwGstScreenshot() +{ + qDebug() << __PRETTY_FUNCTION__; + if(m_pipeline) + { + gst_element_set_state(m_pipeline, GST_STATE_NULL); + gst_object_unref(m_pipeline); + } +} + +static void copyBufferToSource(GstElement *src, GstBuffer *buffer, GstPad *pad, + gpointer data) +{ + + Q_UNUSED(src); + Q_UNUSED(pad); + + GstBuffer *in_buf = GST_BUFFER(data); + + memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(in_buf), + GST_BUFFER_SIZE(in_buf)); + GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(in_buf); +} + +static void freeSourceBuffer(gpointer data) +{ + GstBuffer *in_buf = GST_BUFFER(data); + gst_buffer_unref(in_buf); +} + +static gboolean asyncBusHandler(GstBus *bus, GstMessage *msg, gpointer data) +{ + Q_UNUSED(bus); + + gboolean ret = TRUE; + + MafwGstScreenshot *self = static_cast(data); + + switch(GST_MESSAGE_TYPE(msg)) + { + case GST_MESSAGE_EOS: + { + ret = self->reportBack(NULL); + break; + } + case GST_MESSAGE_ERROR: + { + GError *error = NULL; + + gst_message_parse_error(msg, &error, NULL); + + ret = self->reportBack(error); + g_error_free(error); + break; + } + default: + break; + } + return ret; +} + +/******************************************************************** + * MafwGstScreenshot::savePauseFrame + ********************************************************************/ +bool MafwGstScreenshot::savePauseFrame(GstBuffer *buffer, const char *filename) +{ + qDebug() << __PRETTY_FUNCTION__; + + gint width = 0; + gint height = 0; + + if(!m_pipeline) + { + m_pipeline = gst_pipeline_new("screenshot-pipeline"); + if(!m_pipeline) + { + goto err_out; + } + m_src = gst_element_factory_make("fakesrc", NULL); + m_sink = gst_element_factory_make("filesink", NULL); + m_filter = gst_element_factory_make("capsfilter", NULL); + m_csp = gst_element_factory_make("ffmpegcolorspace", NULL); + m_enc = gst_element_factory_make("pngenc", NULL); + + if(!m_src || !m_sink || !m_filter || !m_csp || !m_enc) + { + goto err_out; + } + + gst_bin_add_many(GST_BIN(m_pipeline), m_src, m_filter, m_csp, m_enc, m_sink, NULL); + + if(!gst_element_link_many(m_src, m_filter, m_csp, m_enc, m_sink, NULL)) + { + goto err_out; + } + + m_bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)); + gst_bus_add_watch(m_bus, asyncBusHandler, this); + gst_object_unref(m_bus); + + g_object_set(m_sink, "preroll-queue-len", 1, NULL); + g_object_set(m_src, + "sizetype", 2, + "num-buffers", 1, + "signal-handoffs", TRUE, + NULL); + g_object_set(m_enc, "compression-level", 1, NULL); + } + + m_caps = gst_caps_copy(GST_BUFFER_CAPS(buffer)); + if(!m_caps) + { + goto err_out; + } + m_structure = gst_caps_get_structure(m_caps, 0); + gst_structure_remove_field(m_structure, "pixel-aspect-ratio"); + /* limit image size in case it exceeds the pre-determined size */ + if(gst_structure_get_int(m_structure, "width", &width) && + gst_structure_get_int(m_structure, "height", &height)) + { + gst_caps_set_simple(m_caps, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + } + g_object_set(m_filter, "caps", m_caps, NULL); + gst_caps_unref(m_caps); + + g_object_set(m_sink, "location", filename, NULL); + g_object_set(m_src, "sizemax", GST_BUFFER_SIZE(buffer), NULL); + + m_handler_id = g_signal_connect_data(m_src, "handoff", G_CALLBACK(copyBufferToSource), buffer, (GClosureNotify) freeSourceBuffer, G_CONNECT_AFTER); + + gst_element_set_state(m_pipeline, GST_STATE_PLAYING); + + return true; + +err_out: + if( m_pipeline ) + { + gst_object_unref(m_pipeline); + m_pipeline = NULL; + } + if( buffer ) + { + gst_buffer_unref(buffer); + } + + return false; +} + +/******************************************************************** + * MafwGstScreenshot::cancelPauseFrame + ********************************************************************/ +void MafwGstScreenshot::cancelPauseFrame() +{ + qDebug() << __PRETTY_FUNCTION__; + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + g_signal_handler_disconnect(m_src, m_handler_id); + + Q_EMIT screenshotCancelled(); +} + +/******************************************************************** + * MafwGstScreenshot::reportBack + ********************************************************************/ +bool MafwGstScreenshot::reportBack(GError *error) +{ + qDebug() << __PRETTY_FUNCTION__; + if(!error) + { + char *location; + g_object_get(m_sink, "location", &location, NULL); + Q_EMIT screenshotTaken(location, NULL); + g_free(location); + } + else + { + Q_EMIT screenshotTaken(NULL, error); + } + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + g_signal_handler_disconnect(m_src, m_handler_id); + + return true; +} diff --git a/qmafw-gst-subtitles-renderer/src/MafwMmcMonitor.cpp b/qmafw-gst-subtitles-renderer/src/MafwMmcMonitor.cpp new file mode 100644 index 0000000..94fd5b5 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/MafwMmcMonitor.cpp @@ -0,0 +1,139 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwMmcMonitor.h" +#include +#include + +#include +#include + +const QString MafwMmcMonitor::MMC_URI_PREFIX="file:///home/user/MyDocs"; + +MafwMmcMonitor::MafwMmcMonitor(QObject* parent) : QObject(parent), m_mounted(false) +{ + m_gVolMonitor=g_volume_monitor_get(); + + g_signal_connect(m_gVolMonitor, "mount-removed", + G_CALLBACK(unmountEvent), this); + g_signal_connect(m_gVolMonitor, "mount-added", + G_CALLBACK(mountEvent), this); + + GList* mounts=g_volume_monitor_get_mounts(m_gVolMonitor); + if( mounts ) + { + for( guint i=0; i(userData); + self->m_mounted = false; + } +} + +void MafwMmcMonitor::mountEvent(GVolumeMonitor * mon, + GMount * mount, + gpointer userData) +{ + Q_UNUSED(mon); + + qDebug() << "mountEvent"; + + if( isMyDocs(mount) ) + { + MafwMmcMonitor* self=static_cast(userData); + self->m_mounted = true; + } +} + +bool MafwMmcMonitor::isMyDocs(GMount* mount) +{ + bool isIt=false; + GFile *root=0; + root = g_mount_get_root(mount); + if( root ) + { + char* uri=g_file_get_uri(root); + if( uri && MMC_URI_PREFIX.compare(uri)==0 ) + { + isIt=true; + } + qDebug() << "MafwMmcMonitor::isMyDocs" << uri << isIt; + g_free(uri); + g_object_unref(root); + } + return isIt; +} diff --git a/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-seeker.c b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-seeker.c new file mode 100644 index 0000000..07d7fc6 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-seeker.c @@ -0,0 +1,201 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "mafw-gst-renderer-seeker.h" + +#include + +#define CLOSE_LIMIT 2 +#define MOVE_FORWARD 10 + +typedef struct { + gint64 required_pos; + gint64 starting_pos; + gint64 current_pos; +} seek_request; + +struct _MafwGstRendererSeeker { + GstElement *pipeline; + seek_request last_request; +}; + +gint64 _get_current_pos(GstElement* pipeline) +{ + GstFormat format = GST_FORMAT_TIME; + gint64 time = 0; + + if(pipeline && + gst_element_query_position(pipeline, &format, &time)) + { + return (time + (GST_SECOND/2)) / GST_SECOND; + } + else + { + return -1; + } +} + +gint64 _get_duration(GstElement *pipeline) +{ + gint64 value = -1; + GstFormat format = GST_FORMAT_TIME; + + gboolean success = gst_element_query_duration(pipeline, &format, &value); + if( success ) + { + return (value + (GST_SECOND/2)) / GST_SECOND; + } + else + { + return -1; + } +} + +gboolean _try_seek_required_pos(MafwGstRendererSeeker *seeker) +{ + gboolean ret; + gint64 spos; + GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; + + + spos = (seeker->last_request.required_pos) * GST_SECOND; + g_debug("seek target: %lld", spos); + + ret = gst_element_seek(seeker->pipeline, + 1.0, + GST_FORMAT_TIME, + flags, + GST_SEEK_TYPE_SET, + spos, + GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE); + + return ret; +} + +gboolean _is_position_close_enough(gint64 pos, gint64 required_pos) +{ + return ABS((pos - required_pos)) < CLOSE_LIMIT; +} + +gboolean _has_position_changed_enough(gint64 pos, gint64 required_pos) +{ + return !_is_position_close_enough(pos, required_pos); +} + +MafwGstRendererSeeker* mafw_gst_renderer_seeker_new() +{ + return g_new0(MafwGstRendererSeeker, 1); +} + +void mafw_gst_renderer_seeker_free(MafwGstRendererSeeker *seeker) +{ + g_free(seeker); +} + +void mafw_gst_renderer_seeker_set_pipeline(MafwGstRendererSeeker *seeker, GstElement *pipeline) +{ + seeker->pipeline = pipeline; + mafw_gst_renderer_seeker_cancel(seeker); +} + +gboolean mafw_gst_renderer_seeker_seek_to(MafwGstRendererSeeker *seeker, gint64 seek_pos) +{ + if( seeker == NULL ) + { + g_critical("Seeker is NULL!"); + return FALSE; + } + + seek_request *request = &(seeker->last_request); + request->required_pos = seek_pos; + request->starting_pos = _get_current_pos(seeker->pipeline); + request->current_pos = request->starting_pos; + + return _try_seek_required_pos(seeker); + +} + +void mafw_gst_renderer_seeker_cancel(MafwGstRendererSeeker *seeker) +{ + seek_request *request = &(seeker->last_request); + request->current_pos = -1; + request->required_pos = -1; + request->starting_pos = -1; +} + +gint64 mafw_gst_renderer_seeker_process(MafwGstRendererSeeker *seeker) +{ + if( seeker == NULL ) + { + g_critical("Seeker is NULL!"); + return -1; + } + + seek_request *request = &(seeker->last_request); + + if(request->required_pos < 0) + { + g_debug("[Seeker] No valid request set! Doing nothing,"); + return request->required_pos; + } + + request->current_pos = _get_current_pos(seeker->pipeline); + if( request->current_pos < 0 ) + { + mafw_gst_renderer_seeker_cancel(seeker); + g_warning("[Seeker] Could not get position! Cannot refine seek!"); + return seeker->last_request.current_pos; + } + + gboolean forward_seek = ( request->required_pos >= request->starting_pos ); + + if( _is_position_close_enough(request->current_pos, request->required_pos) + || + ((_has_position_changed_enough(request->current_pos, request->starting_pos) + && forward_seek + && request->current_pos > request->starting_pos)) ) + { + g_debug("Got good enough seek result: Current pos: %lld, Required pos: %lld", request->current_pos, request->required_pos); + mafw_gst_renderer_seeker_cancel(seeker); + } + else + { + if( forward_seek ) + { + request->required_pos += MOVE_FORWARD; + gint64 duration = _get_duration(seeker->pipeline); + if( request->required_pos > duration ) + { + g_debug("[Seeker] Cancelling increased seek target beyond media length!"); + mafw_gst_renderer_seeker_cancel(seeker); + } + } + else + { + g_debug("Backward seek done, cannot do better..."); + mafw_gst_renderer_seeker_cancel(seeker); + } + } + + if( request->required_pos >= 0 ) + { + _try_seek_required_pos(seeker); + } + + return request->required_pos; +} diff --git a/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-utils.c b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-utils.c new file mode 100644 index 0000000..49364fd --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-utils.c @@ -0,0 +1,324 @@ +/* + * This file is a part of MAFW + * + * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved. + * + * Contact: Visa Smolander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +#include + +#include "mafw-gst-renderer-utils.h" + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "mafw-gst-renderer-utils" + +/** + * convert_utf8: + * @src: string. + * @dst: location for utf8 version of @src. + * + * Tries to convert @src into UTF-8, placing it into @dst. + * + * Returns: TRUE on success. + */ +gboolean convert_utf8(const gchar *src, gchar **dst) +{ + GError *error; + + if (!src || !dst) + return FALSE; + if (g_utf8_validate(src, -1, NULL)) { + *dst = g_strdup(src); + return TRUE; + } + error = NULL; + *dst = g_locale_to_utf8(src, -1, NULL, NULL, &error); + if (error) { + g_warning("utf8 conversion failed '%s' (%d: %s)", + src, error->code, error->message); + g_error_free(error); + return FALSE; + } + return TRUE; +} + +/** + * uri_is_stream: + * @uri: the URI to be checked. + * + * Check if given URI is a stream (not a local resource). To not depend on + * gnomevfs for this, we assume everything that doesn't start with "file://" is + * a stream. + * + * Returns: TRUE if the URI is not local. + */ +gboolean uri_is_stream(const gchar *uri) +{ + if (uri == NULL) { + return FALSE; + } else { + return !g_str_has_prefix(uri, "file://"); + } +} + +/** remap_gst_error_code: + * + * @error: pointer to error + * + * Maps a Gst error to worker errror code, + * mapping follows roughly the one from FMAFW gst-renderer. + * + * Returns: possibly remapped ecode if the domain was certain Gst domain. +*/ +gint remap_gst_error_code(const GError *error) +{ + + gint new_err_code; + + if (error->domain == GST_RESOURCE_ERROR) + { + /* handle RESOURCE errors */ + switch (error->code) + { + case GST_RESOURCE_ERROR_READ: + new_err_code = WORKER_ERROR_STREAM_DISCONNECTED; + break; + case GST_RESOURCE_ERROR_NOT_FOUND: + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_OPEN_READ: + new_err_code = WORKER_ERROR_MEDIA_NOT_FOUND; + break; + case GST_RESOURCE_ERROR_NO_SPACE_LEFT: + new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM; + break; + case GST_RESOURCE_ERROR_WRITE: + /* DSP renderers send ERROR_WRITE when they find + corrupted data */ + new_err_code = WORKER_ERROR_CORRUPTED_FILE; + break; + case GST_RESOURCE_ERROR_SEEK: + new_err_code = WORKER_ERROR_CANNOT_SET_POSITION; + break; + default: + /* Unknown RESOURCE error */ + new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM; + break; + } + } + else if (error->domain == GST_STREAM_ERROR) + { + /* handle STREAM errors */ + switch (error->code) { + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + new_err_code = WORKER_ERROR_TYPE_NOT_AVAILABLE; + break; + case GST_STREAM_ERROR_FORMAT: + case GST_STREAM_ERROR_WRONG_TYPE: + case GST_STREAM_ERROR_FAILED: + new_err_code = WORKER_ERROR_UNSUPPORTED_TYPE; + break; + case GST_STREAM_ERROR_DECODE: + case GST_STREAM_ERROR_DEMUX: + new_err_code = WORKER_ERROR_CORRUPTED_FILE; + break; + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + new_err_code = WORKER_ERROR_CODEC_NOT_FOUND; + break; + case GST_STREAM_ERROR_DECRYPT: + case GST_STREAM_ERROR_DECRYPT_NOKEY: + new_err_code = WORKER_ERROR_DRM_NOT_ALLOWED; + break; + case WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE: + new_err_code = WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE; + break; + default: + /* Unknown STREAM error */ + new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM; + break; + } + } + else if( error->domain == GST_CORE_ERROR ) + { + switch( error->code ) { + case GST_CORE_ERROR_MISSING_PLUGIN: + new_err_code = WORKER_ERROR_UNSUPPORTED_TYPE; + break; + default: + new_err_code = error->code; + } + } + else + { + /* by default return the original code */ + new_err_code = error->code; + } + + return new_err_code; + +} + +/* + * Imported from totem-uri.c + * Copyright (C) 2004 Bastien Nocera + */ + +/* List from xine-lib's demux_sputext.c */ +static const char subtitle_ext[][4] = { + "sub", + "srt", + "smi", + "ssa", + "ass", + "asc" +}; + +static inline gboolean +uri_exists (const char *uri) +{ + GFile *file = g_file_new_for_uri (uri); + if (file != NULL) { + if (g_file_query_exists (file, NULL)) { + g_object_unref (file); + return TRUE; + } + g_object_unref (file); + } + return FALSE; +} + +static char * +uri_get_subtitle_for_uri (const char *uri) +{ + char *subtitle; + guint len, i; + gint suffix; + + /* Find the filename suffix delimiter */ + len = strlen (uri); + for (suffix = len - 1; suffix > 0; suffix--) { + if (uri[suffix] == G_DIR_SEPARATOR || + (uri[suffix] == '/')) { + /* This filename has no extension; we'll need to + * add one */ + suffix = len; + break; + } + if (uri[suffix] == '.') { + /* Found our extension marker */ + break; + } + } + if (suffix < 0) + return NULL; + + /* Generate a subtitle string with room at the end to store the + * 3 character extensions for which we want to search */ + subtitle = g_malloc0 (suffix + 4 + 1); + g_return_val_if_fail (subtitle != NULL, NULL); + g_strlcpy (subtitle, uri, suffix + 4 + 1); + g_strlcpy (subtitle + suffix, ".???", 5); + + /* Search for any files with one of our known subtitle extensions */ + for (i = 0; i < G_N_ELEMENTS (subtitle_ext) ; i++) { + char *subtitle_ext_upper; + memcpy (subtitle + suffix + 1, subtitle_ext[i], 3); + + if (uri_exists (subtitle)) + return subtitle; + + /* Check with upper-cased extension */ + subtitle_ext_upper = g_ascii_strup (subtitle_ext[i], -1); + memcpy (subtitle + suffix + 1, subtitle_ext_upper, 3); + g_free (subtitle_ext_upper); + + if (uri_exists (subtitle)) + return subtitle; + } + g_free (subtitle); + return NULL; +} + +static char * +uri_get_subtitle_in_subdir (GFile *file, const char *subdir) +{ + char *filename, *subtitle, *full_path_str; + GFile *parent, *full_path, *directory; + + /* Get the sibling directory @subdir of the file @file */ + parent = g_file_get_parent (file); + directory = g_file_get_child (parent, subdir); + g_object_unref (parent); + + /* Get the file of the same name as @file in the @subdir directory */ + filename = g_file_get_basename (file); + full_path = g_file_get_child (directory, filename); + g_object_unref (directory); + g_free (filename); + + /* Get the subtitles from that URI */ + full_path_str = g_file_get_uri (full_path); + g_object_unref (full_path); + subtitle = uri_get_subtitle_for_uri (full_path_str); + g_free (full_path_str); + + return subtitle; +} + +char * +uri_get_subtitle_uri (const char *uri) +{ + GFile *file; + char *subtitle; + + if (g_str_has_prefix (uri, "http") != FALSE) + return NULL; + + /* Has the user specified a subtitle file manually? */ + if (strstr (uri, "#subtitle:") != NULL) + return NULL; + + /* Does the file exist? */ + file = g_file_new_for_uri (uri); + if (g_file_query_exists (file, NULL) != TRUE) { + g_object_unref (file); + return NULL; + } + + /* Try in the current directory */ + subtitle = uri_get_subtitle_for_uri (uri); + if (subtitle != NULL) { + g_object_unref (file); + return subtitle; + } + + subtitle = uri_get_subtitle_in_subdir (file, "subtitles"); + g_object_unref (file); + + return subtitle; +} diff --git a/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-worker.c b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-worker.c new file mode 100644 index 0000000..eeceb39 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-worker.c @@ -0,0 +1,3105 @@ +/* + * This file is a part of MAFW + * + * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved. + * + * Contact: Visa Smolander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mafw-gst-renderer-worker.h" +#include "mafw-gst-renderer-utils.h" + +#define UNUSED(x) (void)(x) + +/* context provider DBus name must be the same as the .context file name without + * the .context suffix, service name in the .context file must be the same too */ +#define CONTEXT_PROVIDER_BUS_NAME "com.nokia.mafw.context_provider.libqmafw_gst_renderer" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING "Media.NowPlaying" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_TITLE "title" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_ALBUM "album" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_ARTIST "artist" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_GENRE "genre" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_RESOURCE "resource" +#define CONTEXT_PROVIDER_KEY_NOWPLAYING_DURATION "duration" + +#define WORKER_ERROR g_quark_from_static_string("com.nokia.mafw.error.renderer") + +#define MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_LAZY_TIMEOUT 4000 +#define MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_FAST_TIMEOUT 200 +#define MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_LOOP_LIMIT 10 +#define MAFW_GST_MISSING_TYPE_DECODER "decoder" +#define MAFW_GST_MISSING_TYPE_ENCODER "encoder" + +#define MAFW_TMP_URI_LEN 2048 + +#define STREAM_TYPE_MMS "mms://" +#define STREAM_TYPE_MMSH "mmsh://" +#define MAFW_GST_MMSH_CONNECTION_SPEED "2000" /* kbit/s */ +#define MAFW_GST_MMSH_TCP_TIMEOUT "30000000" /* microseconds */ + +/* struct needed when emitting renderer art/frames as image files */ +typedef struct { + MafwGstRendererWorker *worker; + gint metadata_key; + const gchar *filename; +} SaveGraphicData; + +/* Forward declarations. */ +static void _do_play(MafwGstRendererWorker *worker); + +static void _do_seek(MafwGstRendererWorker *worker, + GstSeekType seek_type, + gint position, + gboolean key_frame_seek, + GError **error); + +static gboolean _set_value(GValue *v, GType type, gconstpointer value); + +static void _emit_metadatas(MafwGstRendererWorker *worker); + +static gboolean _current_metadata_add(MafwGstRendererWorker *worker, + const gint key, + GType type, + const gpointer value); + +static gpointer _set_context_map_value(gpointer map, + const gchar *tag, + const gchar *value); + +/* + * Is used to prevent a critical log from context fw in case of multiple initialisations. + * Common to all renderers in the process. + */ +static gboolean _context_fw_initialised = FALSE; + +/* + * Sends @error to MafwGstRenderer. Only call this from the glib main thread, + * or face the consequences. @err is free'd. + */ +static void _send_error(MafwGstRendererWorker *worker, GError *err) +{ + worker->is_error = TRUE; + if (worker->notify_error_handler) + { + /* remap a possible gst ecode to worker ecode */ + err->code = remap_gst_error_code(err); + worker->notify_error_handler(worker, worker->owner, err); + } + g_error_free(err); +} + +configuration* _create_default_configuration() +{ + configuration *config = g_malloc0(sizeof(configuration)); + config->asink = g_strdup("pulsesink"); + config->vsink = g_strdup("omapxvsink"); + config->flags = 71; + config->buffer_time = 600000; /* microseconds */ + config->latency_time = 100000; /* microseconds */ + config->autoload_subtitles = TRUE; + config->subtitle_encoding = NULL; + config->subtitle_font = g_strdup("Sans Bold 18"); + + /* timers */ + config->milliseconds_to_pause_frame = 700; /* milliseconds */ + config->seconds_to_pause_to_ready = 3; /* seconds */ + + /* dhmmixer */ + config->use_dhmmixer = TRUE; + + config->mobile_surround_music.state = 0; + config->mobile_surround_music.room = 2; + config->mobile_surround_music.color = 2; + config->mobile_surround_video.state = 0; + config->mobile_surround_video.room = 2; + config->mobile_surround_video.color = 2; + + return config; +} + +void _free_configuration(configuration* config) +{ + g_free(config->asink); + g_free(config->vsink); + + g_free(config); +} + +/* + * Posts an @error on the gst bus. _async_bus_handler will then pick it up and + * forward to MafwGstRenderer. @err is free'd. + */ +static void _post_error(MafwGstRendererWorker *worker, GError *err) +{ + gst_bus_post(worker->bus, + gst_message_new_error(GST_OBJECT(worker->pipeline), + err, + NULL)); + g_error_free(err); +} + +static gboolean _set_value(GValue *v, GType type, gconstpointer value) +{ + + gboolean ret = TRUE; + + if (v && value) + { + memset(v, 0, sizeof(GValue)); + g_value_init(v, type); + + if (type == G_TYPE_STRING) { + g_value_set_string(v, (const gchar*)value); + } + else if (type == G_TYPE_INT) { + g_value_set_int(v, *(gint*)value); + } + else if (type == G_TYPE_UINT) { + g_value_set_uint(v, *(uint*)value); + } + else if (type == G_TYPE_DOUBLE) { + g_value_set_double(v, *(gdouble*)value); + } + else if (type == G_TYPE_BOOLEAN) { + g_value_set_boolean(v, *(gboolean*)value); + } + else if (type == G_TYPE_INT64) { + g_value_set_int64(v, *(gint64*)value); + } + else if (type == G_TYPE_FLOAT) { + g_value_set_float(v, *(gfloat*)value); + } + else if (type == G_TYPE_VALUE_ARRAY) { + g_value_copy((GValue*)value,v); + } + else { + g_warning("%s: unknown g_type", G_STRFUNC); + ret = FALSE; + } + } + else + { + ret = FALSE; + } + + return ret; + +} + +static void _emit_metadata(MafwGstRendererWorker *worker, + gint metadata_key, + GType type, + gconstpointer value) +{ + + GValue v; + + if (worker && worker->notify_metadata_handler && + _set_value(&v, type, value)) + { + GValueArray *array = g_value_array_new(0); + g_value_array_append(array, &v); + worker->notify_metadata_handler(worker, + worker->owner, + metadata_key, + G_TYPE_VALUE_ARRAY, + array); + g_value_array_free(array); + g_value_unset(&v); + } + +} + +static void _emit_property(MafwGstRendererWorker *worker, + gint property, + GType type, + gconstpointer value) +{ + + GValue v; + + if (worker && worker->notify_property_handler && + _set_value(&v, type, value)) + { + worker->notify_property_handler(worker, worker->owner, property, &v); + g_value_unset(&v); + } + +} + +static gchar *_init_tmp_file(void) +{ + gint fd; + gchar *path = NULL; + + fd = g_file_open_tmp("mafw-gst-renderer-XXXXXX.picture", &path, NULL); + if (fd >= 0 ) + { + close(fd); + } + + return path; +} + +static void _destroy_tmp_file(MafwGstRendererWorker *worker, guint index) +{ + g_unlink(worker->tmp_files_pool[index]); + g_free(worker->tmp_files_pool[index]); + worker->tmp_files_pool[index] = NULL; +} + +static void _init_tmp_files_pool(MafwGstRendererWorker *worker) +{ + guint8 i; + + worker->tmp_files_pool_index = 0; + + for (i = 0; i < MAFW_GST_RENDERER_MAX_TMP_FILES; i++) { + worker->tmp_files_pool[i] = NULL; + } +} + +static void _destroy_tmp_files_pool(MafwGstRendererWorker *worker) +{ + guint8 i; + + for (i = 0; (i < MAFW_GST_RENDERER_MAX_TMP_FILES) && + (worker->tmp_files_pool[i] != NULL); i++) { + g_unlink(worker->tmp_files_pool[i]); + g_free(worker->tmp_files_pool[i]); + } +} + +static const gchar *_get_tmp_file_from_pool(MafwGstRendererWorker *worker) +{ + gchar *path = worker->tmp_files_pool[worker->tmp_files_pool_index]; + + if (path == NULL) { + path = _init_tmp_file(); + worker->tmp_files_pool[worker->tmp_files_pool_index] = path; + } + else + { + _destroy_tmp_file(worker, worker->tmp_files_pool_index); + path = _init_tmp_file(); + worker->tmp_files_pool[worker->tmp_files_pool_index] = path; + } + + if (++(worker->tmp_files_pool_index) >= MAFW_GST_RENDERER_MAX_TMP_FILES) { + worker->tmp_files_pool_index = 0; + } + + return path; +} + +static void _emit_gst_buffer_as_graphic_file_cb(GError *error, + gpointer user_data) +{ + SaveGraphicData *sgd = user_data; + + if (error == NULL) { + /* Add the info to the current metadata. */ + _current_metadata_add(sgd->worker, + sgd->metadata_key, + G_TYPE_STRING, + (const gpointer)sgd->filename); + + /* Emit the metadata. */ + _emit_metadata(sgd->worker, + sgd->metadata_key, + G_TYPE_STRING, + sgd->filename); + } + else + { + g_warning("could not emit graphic file: %s", error->message); + } + + g_free(sgd); +} + +static void _emit_gst_buffer_as_graphic_file(MafwGstRendererWorker *worker, + GstBuffer *buffer, + const gint metadata_key) +{ + GstStructure *structure; + const gchar *mime = NULL; + GError *error = NULL; + SaveGraphicData *sgd; + + g_return_if_fail((buffer != NULL) && GST_IS_BUFFER(buffer)); + + structure = gst_caps_get_structure(GST_BUFFER_CAPS(buffer), 0); + mime = gst_structure_get_name(structure); + + /* video pause frame related branch */ + if (g_str_has_prefix(mime, "video/x-raw")) { + const gchar *filename = _get_tmp_file_from_pool(worker); + + if(worker->taking_screenshot) + { + worker->screenshot_handler(worker, worker->owner, NULL, NULL, TRUE); + } + worker->taking_screenshot = TRUE; + worker->screenshot_handler(worker, worker->owner, buffer, filename, FALSE); + + /* gst image tag related branch */ + } else if (g_str_has_prefix(mime, "image/")) { + + sgd = g_new0(SaveGraphicData, 1); + sgd->worker = worker; + sgd->metadata_key = metadata_key; + sgd->filename = _get_tmp_file_from_pool(worker); + + g_debug("dumping gst image %s directly to a file", mime); + g_file_set_contents(sgd->filename, + (const gchar*)GST_BUFFER_DATA(buffer), + GST_BUFFER_SIZE(buffer), + &error); + _emit_gst_buffer_as_graphic_file_cb(error, sgd); + if (error) { + g_error_free(error); + } + } else { + g_warning("Mime type not supported, will not create a thumbnail"); + gst_buffer_unref(buffer); + } +} + +static gboolean _go_to_gst_ready(gpointer user_data) +{ + g_debug("_go_to_gst_ready"); + MafwGstRendererWorker *worker = user_data; + + g_return_val_if_fail(worker->state == GST_STATE_PAUSED || + worker->prerolling, FALSE); + + worker->seek_position = mafw_gst_renderer_worker_get_position(worker); + + g_debug("going to GST_STATE_READY"); + gst_element_set_state(worker->pipeline, GST_STATE_READY); + worker->in_ready = TRUE; + return FALSE; +} + +static void _add_ready_timeout(MafwGstRendererWorker *worker) +{ + if( worker->ready_timeout == 0 ) + { + g_debug("Adding timeout to go to GST_STATE_READY"); + worker->ready_timeout = + g_timeout_add_seconds( + worker->config->seconds_to_pause_to_ready, + _go_to_gst_ready, + worker); + } +} + +static void _remove_ready_timeout(MafwGstRendererWorker *worker) +{ + if( worker->ready_timeout != 0 ) + { + g_debug("removing timeout for READY"); + g_source_remove(worker->ready_timeout); + worker->ready_timeout = 0; + } +} + +static gboolean _take_pause_frame(gpointer user_data) +{ + MafwGstRendererWorker *worker = user_data; + + if( worker->pause_frame_taken && worker->pause_frame_buffer ) + { + gst_buffer_unref(worker->pause_frame_buffer); + worker->pause_frame_buffer = NULL; + return FALSE; + } + + if (worker->pause_frame_buffer != NULL) { + worker->pause_frame_taken = TRUE; + _emit_gst_buffer_as_graphic_file( + worker, + worker->pause_frame_buffer, + WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI); + worker->pause_frame_buffer = NULL; + } + return FALSE; +} + +static void _add_pause_frame_timeout(MafwGstRendererWorker *worker) +{ + if (worker->media.has_visual_content && worker->current_frame_on_pause && worker->seek_position == -1) + { + if (!worker->pause_frame_timeout) + { + GstBuffer *buffer = NULL; + g_object_get(worker->pipeline, "frame", &buffer, NULL); + if( buffer ) + { + GstBuffer *copy = gst_buffer_copy(buffer); + gst_buffer_copy_metadata(copy, buffer, GST_BUFFER_COPY_ALL); + worker->pause_frame_buffer = copy; + gst_buffer_unref(buffer); + + g_debug("Adding timeout to go to current frame capture"); + worker->pause_frame_timeout = + g_timeout_add_full( + G_PRIORITY_DEFAULT, + worker->config->milliseconds_to_pause_frame, + _take_pause_frame, + worker, NULL); + } + else + { + g_warning("MafwGstRenderer Worker: Could not get buffer from pipeline! Maybe at EOS?"); + } + } + } else { + g_debug("Not adding timeout to take pause frame."); + worker->pause_frame_timeout = 0; + } +} + +static void _remove_pause_frame_timeout(MafwGstRendererWorker *worker) +{ + if (worker->pause_frame_timeout != 0) { + g_debug("removing timeout for pause frame!"); + g_source_remove(worker->pause_frame_timeout); + worker->pause_frame_timeout = 0; + } + + if(worker->taking_screenshot) + { + worker->screenshot_handler(worker, worker->owner, NULL, NULL, TRUE); + worker->taking_screenshot = FALSE; + } + else + { + /* in this case the buffer has not been given to the + * screenshot component to be processed */ + if(worker->pause_frame_buffer) + { + gst_buffer_unref(worker->pause_frame_buffer); + worker->pause_frame_buffer = NULL; + } + } +} + +static gboolean _emit_video_info(MafwGstRendererWorker *worker) +{ + + _emit_metadata(worker, + WORKER_METADATA_KEY_RES_X, + G_TYPE_INT, + &worker->media.video_width); + + _emit_metadata(worker, + WORKER_METADATA_KEY_RES_Y, + G_TYPE_INT, + &worker->media.video_height); + + _emit_metadata(worker, + WORKER_METADATA_KEY_VIDEO_FRAMERATE, + G_TYPE_DOUBLE, + &worker->media.fps); + + return FALSE; + +} + +/* + * Checks if the video details are supported. It also extracts other useful + * information (such as PAR and framerate) from the caps, if available. NOTE: + * this will be called from a different thread than glib's mainloop (when + * invoked via _stream_info_cb); don't call MafwGstRenderer directly. + * + * Returns: TRUE if video details are acceptable. + */ +static gboolean _handle_video_info(MafwGstRendererWorker *worker, + const GstStructure *structure) +{ + gint width, height; + gdouble fps; + + width = height = 0; + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + g_debug("video size: %d x %d", width, height); + if (gst_structure_has_field(structure, "pixel-aspect-ratio")) + { + gst_structure_get_fraction(structure, + "pixel-aspect-ratio", + &worker->media.par_n, + &worker->media.par_d); + g_debug("video PAR: %d:%d", worker->media.par_n, worker->media.par_d); + width = width * worker->media.par_n / worker->media.par_d; + } + + fps = 1.0; + if (gst_structure_has_field(structure, "framerate")) + { + gint fps_n, fps_d; + + gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d); + if (fps_d > 0) { + fps = (gdouble)fps_n / (gdouble)fps_d; + } + g_debug("video fps: %f", fps); + } + + worker->media.video_width = width; + worker->media.video_height = height; + worker->media.fps = fps; + + _current_metadata_add(worker, WORKER_METADATA_KEY_RES_X, G_TYPE_INT, + (const gpointer)&width); + _current_metadata_add(worker, WORKER_METADATA_KEY_RES_Y, G_TYPE_INT, + (const gpointer)&height); + _current_metadata_add(worker, WORKER_METADATA_KEY_VIDEO_FRAMERATE, + G_TYPE_DOUBLE, (const gpointer)&fps); + + /* Emit the metadata.*/ + g_idle_add((GSourceFunc)_emit_video_info, worker); + return TRUE; +} + +static void _parse_stream_info_item(MafwGstRendererWorker *worker, GObject *obj) +{ + GParamSpec *pspec; + GEnumValue *val; + gint type; + + g_object_get(obj, "type", &type, NULL); + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), "type"); + if(!pspec) + return; + val = g_enum_get_value(G_PARAM_SPEC_ENUM(pspec)->enum_class, type); + if (!val) + return; + if (!g_ascii_strcasecmp(val->value_nick, "video") || + !g_ascii_strcasecmp(val->value_name, "video")) + { + GstCaps *vcaps; + GstObject *object; + + object = NULL; + g_object_get(obj, "object", &object, NULL); + vcaps = NULL; + if (object) { + vcaps = gst_pad_get_caps(GST_PAD_CAST(object)); + } else { + g_object_get(obj, "caps", &vcaps, NULL); + gst_caps_ref(vcaps); + } + if (vcaps) { + if (gst_caps_is_fixed(vcaps)) + { + _handle_video_info(worker, gst_caps_get_structure(vcaps, 0)); + } + gst_caps_unref(vcaps); + } + } +} + +/* It always returns FALSE, because it is used as an idle callback as well. */ +static gboolean _parse_stream_info(MafwGstRendererWorker *worker) +{ + GList *stream_info, *s; + + stream_info = NULL; + if (g_object_class_find_property(G_OBJECT_GET_CLASS(worker->pipeline), + "stream-info")) + { + g_object_get(worker->pipeline, "stream-info", &stream_info, NULL); + } + for (s = stream_info; s; s = g_list_next(s)) + _parse_stream_info_item(worker, G_OBJECT(s->data)); + return FALSE; +} + +static void mafw_gst_renderer_worker_apply_xid(MafwGstRendererWorker *worker) +{ + /* Set sink to render on the provided XID if we have do have + a XID a valid video sink and we are rendering video content */ + if (worker->xid && + worker->vsink && + worker->media.has_visual_content) + { + g_debug ("Setting overlay, window id: %x", (gint) worker->xid); + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(worker->vsink), worker->xid); + + + /* Ask the gst to redraw the frame if we are paused */ + /* TODO: in MTG this works only in non-fs -> fs way. */ + if (worker->state == GST_STATE_PAUSED) + { + gst_x_overlay_expose(GST_X_OVERLAY(worker->vsink)); + } + } else { + g_debug("Not setting overlay for window id: %x", (gint) worker->xid); + } +} + +static void mafw_gst_renderer_worker_apply_render_rectangle(MafwGstRendererWorker *worker) +{ + /* Set sink to render on the provided XID if we have do have + a XID a valid video sink and we are rendering video content */ + if (worker->xid && + worker->vsink && + worker->media.has_visual_content + && + (worker->x_overlay_rectangle.x >= 0 && + worker->x_overlay_rectangle.y >= 0 && + worker->x_overlay_rectangle.width >= 0 && + worker->x_overlay_rectangle.height >= 0) ) + { + g_debug("Applying render rectangle: X:%d,Y:%d Width:%d, Height:%d", + worker->x_overlay_rectangle.x, + worker->x_overlay_rectangle.y, + worker->x_overlay_rectangle.width, + worker->x_overlay_rectangle.height); + + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(worker->vsink), + worker->x_overlay_rectangle.x, + worker->x_overlay_rectangle.y, + worker->x_overlay_rectangle.width, + worker->x_overlay_rectangle.height); + /* Ask the gst to redraw the frame if we are paused */ + /* TODO: in MTG this works only in non-fs -> fs way. */ + if (worker->state == GST_STATE_PAUSED) + { + gst_x_overlay_expose(GST_X_OVERLAY(worker->vsink)); + } + + } else { + g_debug("Not setting render rectangle for window id: %x", (gint) worker->xid); + } +} + +/* + * GstBus synchronous message handler. NOTE that this handler is NOT invoked + * from the glib thread, so be careful what you do here. + */ +static GstBusSyncReply _sync_bus_handler(GstBus *bus, + GstMessage *msg, + MafwGstRendererWorker *worker) +{ + + UNUSED(bus); + + if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ELEMENT && + gst_structure_has_name(msg->structure, "prepare-xwindow-id")) + { + g_debug("got prepare-xwindow-id"); + worker->media.has_visual_content = TRUE; + set_dolby_video_property(worker, worker->config->mobile_surround_video.state); + set_dolby_video_sound_property(worker, worker->config->mobile_surround_video.room, TRUE); + set_dolby_video_sound_property(worker, worker->config->mobile_surround_video.color, FALSE); + /* The user has to preset the XID, we don't create windows by + * ourselves. */ + if (!worker->xid || !worker->vsink) { + /* We must post an error message to the bus that will be picked up + * by _async_bus_handler. Calling the notification function + * directly from here (different thread) is not healthy. */ + g_warning("No video window or video-sink set!"); + _post_error(worker, + g_error_new_literal(WORKER_ERROR, + WORKER_ERROR_PLAYBACK, + "No video window XID or video-sink set")); + gst_message_unref (msg); + return GST_BUS_DROP; + } else { + g_debug ("Video window to use is: %x", (gint)worker->xid); + } + + /* Instruct vsink to use the client-provided window */ + mafw_gst_renderer_worker_apply_xid(worker); + /* Instruct vsink to use the required render rectangle */ + mafw_gst_renderer_worker_apply_render_rectangle(worker); + + /* Handle colorkey and autopaint */ + mafw_gst_renderer_worker_set_autopaint(worker, worker->autopaint); + g_object_get(worker->vsink, "colorkey", &worker->colorkey, NULL); + /* Defer the signal emission to the thread running the mainloop. */ + if (worker->colorkey != -1) { + gst_bus_post(worker->bus, + gst_message_new_application( + GST_OBJECT(worker->vsink), + gst_structure_empty_new("ckey"))); + } + gst_message_unref (msg); + return GST_BUS_DROP; + } + /* do not unref message when returning PASS */ + return GST_BUS_PASS; +} + +static void _free_taglist_item(GstMessage *msg, gpointer data) +{ + UNUSED(data); + + gst_message_unref(msg); +} + +static void _free_taglist(MafwGstRendererWorker *worker) +{ + if (worker->tag_list != NULL) + { + g_ptr_array_foreach(worker->tag_list, (GFunc)_free_taglist_item, NULL); + g_ptr_array_free(worker->tag_list, TRUE); + worker->tag_list = NULL; + } +} + +static gboolean _seconds_duration_equal(gint64 duration1, gint64 duration2) +{ + gint64 duration1_seconds, duration2_seconds; + + duration1_seconds = duration1 / GST_SECOND; + duration2_seconds = duration2 / GST_SECOND; + + return duration1_seconds == duration2_seconds; +} + +static void _check_duration(MafwGstRendererWorker *worker, gint64 value) +{ + gboolean right_query = TRUE; + + if (value == -1) { + GstFormat format = GST_FORMAT_TIME; + right_query = + gst_element_query_duration(worker->pipeline, &format, &value); + } + + if (right_query && value > 0 + && !_seconds_duration_equal(worker->media.length_nanos, value)) + { + gint64 duration = (value + (GST_SECOND/2)) / GST_SECOND; + + /* Add the duration to the current metadata. */ + if( _current_metadata_add(worker, + WORKER_METADATA_KEY_DURATION, + G_TYPE_INT64, + (const gpointer)&duration) ) + { + _emit_metadata(worker, + WORKER_METADATA_KEY_DURATION, + G_TYPE_INT64, + &duration); + } + + /* Publish to context FW */ + if( worker->context_nowplaying == NULL ) + { + worker->context_nowplaying = context_provider_map_new(); + } + context_provider_map_set_integer(worker->context_nowplaying, + CONTEXT_PROVIDER_KEY_NOWPLAYING_DURATION, + duration); + context_provider_set_map(CONTEXT_PROVIDER_KEY_NOWPLAYING, + worker->context_nowplaying, FALSE); + /* end of publishing to context FW */ + } + + if( right_query ) + { + worker->media.length_nanos = value; + } + + g_debug("media duration: %lld", worker->media.length_nanos); +} + +static void _check_seekability(MafwGstRendererWorker *worker) +{ + SeekabilityType seekable = SEEKABILITY_UNKNOWN; + if (worker->media.length_nanos >= 0 ) + { + g_debug("Quering GStreamer for seekability"); + GstQuery *seek_query; + GstFormat format = GST_FORMAT_TIME; + /* Query the seekability of the stream */ + seek_query = gst_query_new_seeking(format); + if (gst_element_query(worker->pipeline, seek_query)) { + gboolean renderer_seekable = FALSE; + gst_query_parse_seeking(seek_query, + NULL, + &renderer_seekable, + NULL, NULL); + g_debug("GStreamer seekability %d", renderer_seekable); + seekable = renderer_seekable ? SEEKABILITY_SEEKABLE : SEEKABILITY_NO_SEEKABLE; + } + else + { + g_debug("Could not query pipeline for seekability! Using old value!"); + seekable = worker->media.seekable; + } + gst_query_unref(seek_query); + } + else if( worker->media.length_nanos == DURATION_INDEFINITE ) + { + /* duration indefinite, "clearly" not seekable */ + seekable = SEEKABILITY_NO_SEEKABLE; + } + else + { + /* otherwise we'll use last known/guessed value */ + seekable = worker->media.seekable; + } + + g_debug("media seekable: %d", seekable); + + /* If the seekability is unknown it is set as false and sent. After that it is + sent only if it changes to true + */ + if( (seekable == SEEKABILITY_UNKNOWN && worker->media.seekable == SEEKABILITY_UNKNOWN) + || seekable != worker->media.seekable ) + { + if( seekable != SEEKABILITY_NO_SEEKABLE ) + { + worker->media.seekable = SEEKABILITY_SEEKABLE; + } + else + { + worker->media.seekable = SEEKABILITY_NO_SEEKABLE; + } + + gboolean is_seekable = (worker->media.seekable == SEEKABILITY_SEEKABLE); + _current_metadata_add(worker, + WORKER_METADATA_KEY_IS_SEEKABLE, + G_TYPE_BOOLEAN, + (const gpointer)&is_seekable); + _emit_metadata(worker, + WORKER_METADATA_KEY_IS_SEEKABLE, + G_TYPE_BOOLEAN, + &is_seekable); + } +} + +static gboolean _query_duration_and_seekability_timeout(gpointer data) +{ + MafwGstRendererWorker *worker = data; + + if (!worker->in_ready) + { + _check_duration(worker, -1); + worker->duration_seek_timeout_loop_count += 1; + + /* for worker's internal logic let's put the indefinite duration if loop limit has been reached */ + /* this affects the seekability resolution */ + if( worker->duration_seek_timeout_loop_count >= MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_LOOP_LIMIT + && worker->media.length_nanos == DURATION_UNQUERIED ) + { + worker->media.length_nanos = DURATION_INDEFINITE; + } + + _check_seekability(worker); + + if( worker->media.length_nanos >= DURATION_INDEFINITE ) + { + worker->duration_seek_timeout = 0; + /* we've got a valid duration value no need to ask for more */ + return FALSE; + } + else + { + return TRUE; + } + } + else + { + g_warning("_query_duration_and_seekability_timeout: We are in ready state, duration and seekability not checked."); + return FALSE; + } +} + +/* + * Resets the media information. + */ +static void _reset_media_info(MafwGstRendererWorker *worker) +{ + if (worker->media.location) { + g_free(worker->media.location); + worker->media.location = NULL; + } + worker->media.length_nanos = DURATION_UNQUERIED; + worker->media.has_visual_content = FALSE; + worker->media.seekable = SEEKABILITY_UNKNOWN; + worker->media.video_width = 0; + worker->media.video_height = 0; + worker->media.fps = 0.0; +} + +static void _reset_pipeline_and_worker(MafwGstRendererWorker *worker) +{ + + if (worker->pipeline) { + g_debug("destroying pipeline"); + if (worker->async_bus_id) { + g_source_remove(worker->async_bus_id); + worker->async_bus_id = 0; + } + gst_element_set_state(worker->pipeline, GST_STATE_NULL); + if (worker->bus) { + gst_bus_set_sync_handler(worker->bus, NULL, NULL); + gst_object_unref(GST_OBJECT_CAST(worker->bus)); + worker->bus = NULL; + } + gst_object_unref(worker->pipeline); + worker->pipeline = NULL; + } + + worker->report_statechanges = TRUE; + worker->state = GST_STATE_NULL; + worker->prerolling = FALSE; + worker->is_live = FALSE; + worker->buffering = FALSE; + worker->is_stream = FALSE; + worker->is_error = FALSE; + worker->eos = FALSE; + worker->seek_position = -1; + worker->stay_paused = FALSE; + worker->playback_speed = 1; + worker->in_ready = FALSE; + _remove_ready_timeout(worker); + _remove_pause_frame_timeout(worker); + _free_taglist(worker); + if (worker->current_metadata) { + g_hash_table_destroy(worker->current_metadata); + worker->current_metadata = NULL; + } + + if (worker->duration_seek_timeout != 0) { + g_source_remove(worker->duration_seek_timeout); + worker->duration_seek_timeout = 0; + } + worker->duration_seek_timeout_loop_count = 0; + + _reset_media_info(worker); + + /* removes all idle timeouts with this worker as data */ + while(g_idle_remove_by_data(worker)); +} + + +/* + * Called when the pipeline transitions into PAUSED state. It extracts more + * information from Gst. + */ +static void _finalize_startup(MafwGstRendererWorker *worker) +{ + /* Check video caps */ + if (worker->media.has_visual_content && worker->vsink) { + GstPad *pad = GST_BASE_SINK_PAD(worker->vsink); + GstCaps *caps = GST_PAD_CAPS(pad); + if (caps && gst_caps_is_fixed(caps)) { + GstStructure *structure; + structure = gst_caps_get_structure(caps, 0); + if (!_handle_video_info(worker, structure)) + return; + } + } + + /* Something might have gone wrong at this point already. */ + if (worker->is_error) { + g_debug("Error occured during preroll"); + return; + } + + /* Streaminfo might reveal the media to be unsupported. Therefore we + * need to check the error again. */ + _parse_stream_info(worker); + if (worker->is_error) { + g_debug("Error occured. Leaving"); + return; + } + + /* Check duration and seekability */ + if (worker->duration_seek_timeout != 0) { + g_source_remove(worker->duration_seek_timeout); + worker->duration_seek_timeout = 0; + } + + _check_duration(worker, -1); + _check_seekability(worker); +} + +static void _add_duration_seek_query_timeout(MafwGstRendererWorker *worker) +{ + if(worker->duration_seek_timeout == 0) + { + gint timeout = 0; + if( worker->duration_seek_timeout_loop_count >= MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_LOOP_LIMIT + || worker->media.length_nanos >= DURATION_INDEFINITE ) + { + /* this is just for verifying the duration later on if it was received in PAUSED state early on */ + timeout = MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_LAZY_TIMEOUT; + } + else + { + timeout = MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_FAST_TIMEOUT; + } + + worker->duration_seek_timeout = g_timeout_add( + timeout, + _query_duration_and_seekability_timeout, + worker); + } +} + +static void _do_pause_postprocessing(MafwGstRendererWorker *worker) +{ + if (worker->notify_pause_handler) { + worker->notify_pause_handler(worker, worker->owner); + } + + _add_pause_frame_timeout(worker); + _add_ready_timeout(worker); +} + +static void _report_playing_state(MafwGstRendererWorker * worker) +{ + if (worker->report_statechanges && worker->notify_play_handler) + { + worker->notify_play_handler( worker, + worker->owner); + } +} + +static void _handle_state_changed(GstMessage *msg, + MafwGstRendererWorker *worker) +{ + GstState newstate, oldstate; + GstStateChange statetrans; + + gst_message_parse_state_changed(msg, &oldstate, &newstate, NULL); + statetrans = GST_STATE_TRANSITION(oldstate, newstate); + g_debug("State changed: %d: %d -> %d", worker->state, oldstate, newstate); + + /* If the state is the same we do nothing, otherwise, we keep it */ + if (worker->state == newstate) + { + /* This is used for saving correct pause frame after pauseAt. + * If we doing normal seek we dont want to save pause frame. + * We use gst_element_get_state to check if the state change is completed. + * If gst_element_get_state returns GST_STATE_CHANGE_SUCCESS we know that + * it's save to do pause_postprocessing */ + if (newstate == GST_STATE_PAUSED && worker->stay_paused && + gst_element_get_state(worker->pipeline, NULL, NULL, 0) == GST_STATE_CHANGE_SUCCESS) + { + worker->seek_position = mafw_gst_renderer_seeker_process(worker->seeker); + + /* has seeking ended successfully? */ + if( worker->seek_position < 0 ) + { + /* we do pause_postprocessing for pauseAt */ + _do_pause_postprocessing(worker); + } + } + + /* the EOS flag should only be cleared if it has been set and seeking has been done + * paused -> paused transition should only happen when seeking + */ + if( newstate == GST_STATE_PAUSED && worker->eos ) + { + worker->eos = FALSE; + } + return; + } + + worker->state = newstate; + + switch (statetrans) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + if (worker->in_ready) { + /* Woken up from READY, resume stream position and playback */ + + /*live sources can be sought only in PLAYING state*/ + if( !worker->is_live ) { + _do_seek(worker, + GST_SEEK_TYPE_SET, + worker->seek_position, + FALSE, + NULL); + } + + /* While buffering, we have to wait in PAUSED until we reach 100% before + * doing anything */ + if (worker->buffering) { + return; + } else { + _do_play(worker); + } + } else if (worker->prerolling && worker->report_statechanges && !worker->buffering) { + /* PAUSED after pipeline has been constructed. We check caps, + * seek and duration and if staying in pause is needed, we + * perform operations for pausing, such as current frame on + * pause and signalling state change and adding the timeout to + * go to ready */ + g_debug ("Prerolling done, finalizaing startup"); + _finalize_startup(worker); + + if (worker->stay_paused) { + /* then we can tell we're paused */ + _do_pause_postprocessing(worker); + } + + if( worker->seek_position > 0 ) + { + g_debug("Immediate seek from READY state to: %d", worker->seek_position); + _do_seek(worker, GST_SEEK_TYPE_SET, + worker->seek_position, FALSE, NULL); + + if(worker->vsink) + { + g_object_set(worker->vsink, "show-preroll-frame", + TRUE, NULL); + } + + /* do_seek will set this to false, but we'll want to report state changes + when doing immediate seek from start */ + worker->report_statechanges = TRUE; + } + worker->prerolling = FALSE; + _do_play(worker); + } + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + /* When pausing we do the stuff, like signalling state, current + * frame on pause and timeout to go to ready */ + if (worker->report_statechanges) { + _do_pause_postprocessing(worker); + } + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + + /*live sources can be sought only in PLAYING state + This seek should happen only after READY to PAUSED to PLAYING + transitions + */ + if( worker->report_statechanges + && worker->seek_position > -1 + && worker->is_live ) + { + g_debug("Seeking live source in PLAYING state!"); + _do_seek(worker, + GST_SEEK_TYPE_SET, + worker->seek_position, + FALSE, + NULL); + /* this has to be set as do_seek sets statechanges to FALSE + but we still want to inform that we're in PLAYING state */ + worker->report_statechanges = TRUE; + /* seek position needs to be reset here for a live stream */ + worker->seek_position = -1; + } + + /* Because live streams are sought in PLAYING state, we reset + seek_position after all state transitions are completed. Normal + streams resetting seek_position here is OK. */ + if(worker->report_statechanges == FALSE || !worker->is_live) + { + /* if seek was called, at this point it is really ended */ + worker->seek_position = mafw_gst_renderer_seeker_process(worker->seeker); + } + + /* Signal state change if needed */ + _report_playing_state(worker); + + /* Prevent blanking if we are playing video */ + if (worker->media.has_visual_content && + worker->blanking__control_handler) + { + worker->blanking__control_handler(worker, worker->owner, TRUE); + } + + /* Back to playing no longer in_ready (if ever was) */ + worker->in_ready = FALSE; + + /* context framework adaptation starts */ + worker->context_nowplaying = + _set_context_map_value(worker->context_nowplaying, + GST_TAG_LOCATION, + worker->media.location); + context_provider_set_map(CONTEXT_PROVIDER_KEY_NOWPLAYING, + worker->context_nowplaying, FALSE); + /* context framework adaptation ends */ + + /* Emit metadata. We wait until we reach the playing state because + * this speeds up playback start time */ + _emit_metadatas(worker); + + /* in any case the duration is verified, it may change with VBR media */ + _add_duration_seek_query_timeout(worker); + + /* We've reached playing state, state changes are not reported + * unless explicitly requested (e.g. by PAUSE request) seeking + * in PLAYING does not cause state change reports + */ + worker->report_statechanges = FALSE; + + /* Delayed pause e.g. because of seek */ + if (worker->stay_paused) { + mafw_gst_renderer_worker_pause(worker); + } + + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + /* If we went to READY, we free the taglist and * deassign the + * timout it */ + if (worker->in_ready) { + g_debug("changed to GST_STATE_READY"); + worker->ready_timeout = 0; + _free_taglist(worker); + + if( worker->notify_ready_state_handler ) + { + worker->notify_ready_state_handler(worker, worker->owner); + } + } + break; + case GST_STATE_CHANGE_NULL_TO_READY: + if(g_str_has_prefix(worker->media.location, STREAM_TYPE_MMSH) || + g_str_has_prefix(worker->media.location, STREAM_TYPE_MMS)) + { + GstElement *source = NULL; + g_object_get(worker->pipeline, "source", &source, NULL); + if(source) + { + gst_util_set_object_arg(G_OBJECT(source), "tcp-timeout", MAFW_GST_MMSH_TCP_TIMEOUT); + gst_object_unref(source); + } + else + g_warning("Failed to get source element from pipeline"); + } + break; + default: + break; + } +} + +static void _handle_duration(MafwGstRendererWorker *worker) +{ + /* if we've got ongoing query timeout ignore this and in any case do it only in PAUSE/PLAYING */ + if( worker->duration_seek_timeout == 0 + && ( worker->state == GST_STATE_PAUSED || worker->state == GST_STATE_PLAYING) ) + { + /* We want to check this quickly but not immediately */ + g_timeout_add_full(G_PRIORITY_DEFAULT, + MAFW_GST_RENDERER_WORKER_DURATION_AND_SEEKABILITY_FAST_TIMEOUT, + _query_duration_and_seekability_timeout, + worker, + NULL); + } +} + +static void _emit_renderer_art(MafwGstRendererWorker *worker, + const GstTagList *list) +{ + GstBuffer *buffer = NULL; + const GValue *value = NULL; + + g_return_if_fail(gst_tag_list_get_tag_size(list, GST_TAG_IMAGE) > 0); + + value = gst_tag_list_get_value_index(list, GST_TAG_IMAGE, 0); + + g_return_if_fail((value != NULL) && G_VALUE_HOLDS(value, GST_TYPE_BUFFER)); + + buffer = g_value_peek_pointer(value); + + g_return_if_fail((buffer != NULL) && GST_IS_BUFFER(buffer)); + + _emit_gst_buffer_as_graphic_file(worker, + buffer, + WORKER_METADATA_KEY_RENDERER_ART_URI); +} + +static void value_dtor(gpointer value) +{ + + if (G_IS_VALUE(value)) { + g_value_unset(value); + g_free(value); + } else { + g_value_array_free(value); + } + +} + +static gboolean _current_metadata_add(MafwGstRendererWorker *worker, + const gint key, + GType type, + const gpointer value) +{ + GValue *new_gval; + gboolean was_updated = FALSE; + + if( value == NULL ) + { + g_warning("Null value for metadata was tried to be set!"); + return was_updated; + } + + if (!worker->current_metadata) { + worker->current_metadata = g_hash_table_new_full(g_direct_hash, + g_direct_equal, + NULL, + value_dtor); + } + + if (type == G_TYPE_VALUE_ARRAY) { + GValueArray *values = (GValueArray *) value; + + if (values->n_values == 1) { + GValue *gval = g_value_array_get_nth(values, 0); + new_gval = g_new0(GValue, 1); + g_value_init(new_gval, G_VALUE_TYPE(gval)); + g_value_copy(gval, new_gval); + + GValue *existing = (GValue*)g_hash_table_lookup(worker->current_metadata, (gpointer)key); + if(!existing || (GST_VALUE_EQUAL != gst_value_compare(existing, new_gval)) ) + { + was_updated = TRUE; + } + g_hash_table_insert(worker->current_metadata, + (gpointer)key, + new_gval); + } else { + GValueArray *new_gvalues = g_value_array_copy(values); + + GValueArray *existing = (GValueArray*)g_hash_table_lookup(worker->current_metadata, (gpointer)key); + + if( existing + && new_gvalues->n_values == existing->n_values ) + { + guint size = new_gvalues->n_values; + + guint i = 0; + for( ; i < size; ++i ) + { + GValue *newVal = g_value_array_get_nth(new_gvalues, i); + GValue *existingVal = g_value_array_get_nth(existing, i); + if( GST_VALUE_EQUAL != gst_value_compare(newVal, existingVal) ) + { + was_updated = TRUE; + break; + } + } + } + else + { + was_updated = TRUE; + } + + g_hash_table_insert(worker->current_metadata, + (gpointer)key, + new_gvalues); + } + + return was_updated; + } + + new_gval = g_new0(GValue, 1); + + if (_set_value(new_gval, type, value) == FALSE) + { + g_warning("Metadata type: %i is not being handled", type); + return was_updated; + } + + GValue *existing = (GValue*)g_hash_table_lookup(worker->current_metadata, (gpointer)key); + if(!existing || (GST_VALUE_EQUAL != gst_value_compare(existing, new_gval)) ) + { + was_updated = TRUE; + } + g_hash_table_insert(worker->current_metadata, (gpointer)key, new_gval); + + return was_updated; + +} + +static GHashTable* _build_tagmap(void) +{ + GHashTable *hash_table = NULL; + + hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + g_hash_table_insert(hash_table, g_strdup(GST_TAG_TITLE), + (gpointer)WORKER_METADATA_KEY_TITLE); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_ARTIST), + (gpointer)WORKER_METADATA_KEY_ARTIST); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_AUDIO_CODEC), + (gpointer)WORKER_METADATA_KEY_AUDIO_CODEC); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_VIDEO_CODEC), + (gpointer)WORKER_METADATA_KEY_VIDEO_CODEC); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_BITRATE), + (gpointer)WORKER_METADATA_KEY_BITRATE); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_LANGUAGE_CODE), + (gpointer)WORKER_METADATA_KEY_ENCODING); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_ALBUM), + (gpointer)WORKER_METADATA_KEY_ALBUM); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_GENRE), + (gpointer)WORKER_METADATA_KEY_GENRE); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_TRACK_NUMBER), + (gpointer)WORKER_METADATA_KEY_TRACK); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_ORGANIZATION), + (gpointer)WORKER_METADATA_KEY_ORGANIZATION); + g_hash_table_insert(hash_table, g_strdup(GST_TAG_IMAGE), + (gpointer)WORKER_METADATA_KEY_RENDERER_ART_URI); + + return hash_table; +} + +/* + * Sets values to given context framework map, allocates it when map is NULL. + */ +gpointer _set_context_map_value(gpointer map, + const gchar *tag, + const gchar *value) +{ + + if (map == NULL) + { + map = context_provider_map_new(); + } + + if (g_str_equal(tag, GST_TAG_LOCATION)) + { + context_provider_map_set_string(map, + CONTEXT_PROVIDER_KEY_NOWPLAYING_RESOURCE, + value); + } + else if (g_str_equal(tag, GST_TAG_TITLE)) + { + context_provider_map_set_string(map, + CONTEXT_PROVIDER_KEY_NOWPLAYING_TITLE, + value); + } + else if (g_str_equal(tag, GST_TAG_ARTIST)) + { + context_provider_map_set_string(map, + CONTEXT_PROVIDER_KEY_NOWPLAYING_ARTIST, + value); + } + else if (g_str_equal(tag, GST_TAG_ALBUM)) + { + context_provider_map_set_string(map, + CONTEXT_PROVIDER_KEY_NOWPLAYING_ALBUM, + value); + } + else if (g_str_equal(tag, GST_TAG_GENRE)) + { + context_provider_map_set_string(map, + CONTEXT_PROVIDER_KEY_NOWPLAYING_GENRE, + value); + } + + return map; + +} + +/* + * Emits metadata-changed signals for gst tags. + */ +static void _emit_tag(const GstTagList *list, + const gchar *tag, + MafwGstRendererWorker *worker) +{ + /* Mapping between Gst <-> MAFW metadata tags + * NOTE: This assumes that GTypes matches between GST and MAFW. */ + static GHashTable *tagmap = NULL; + gint i, count; + gint mafwtag; + GType type; + GValueArray *values; + + if (tagmap == NULL) { + tagmap = _build_tagmap(); + } + + g_debug("tag: '%s' (type: %s)", tag, g_type_name(gst_tag_get_type(tag))); + /* Is there a mapping for this tag? */ + mafwtag = (gint)g_hash_table_lookup(tagmap, tag); + if (!mafwtag) + return; + + if (mafwtag == WORKER_METADATA_KEY_RENDERER_ART_URI) { + _emit_renderer_art(worker, list); + return; + } + + /* Build a value array of this tag. We need to make sure that strings + * are UTF-8. GstTagList API says that the value is always UTF8, but it + * looks like the ID3 demuxer still might sometimes produce non-UTF-8 + * strings. */ + count = gst_tag_list_get_tag_size(list, tag); + + type = gst_tag_get_type(tag); + values = g_value_array_new(count); + for (i = 0; i < count; ++i) { + GValue *v = (GValue *) + gst_tag_list_get_value_index(list, tag, i); + if (type == G_TYPE_STRING) { + gchar *orig, *utf8; + + gboolean tagExists = gst_tag_list_get_string_index(list, tag, i, &orig); + UNUSED(tagExists); //TODO what if tag does not exists? + if (convert_utf8(orig, &utf8)) { + GValue utf8gval; + memset(&utf8gval, 0, sizeof(utf8gval)); + + g_value_init(&utf8gval, G_TYPE_STRING); + g_value_take_string(&utf8gval, utf8); + g_value_array_append(values, &utf8gval); + g_value_unset(&utf8gval); + } + /* context framework adaptation starts */ + worker->context_nowplaying = + _set_context_map_value(worker->context_nowplaying, + tag, + orig); + /* context framework adaptation ends */ + g_free(orig); + } else if (type == G_TYPE_UINT) { + GValue intgval; + memset(&intgval, 0, sizeof(intgval)); + + g_value_init(&intgval, G_TYPE_INT); + g_value_transform(v, &intgval); + g_value_array_append(values, &intgval); + g_value_unset(&intgval); + } else { + g_value_array_append(values, v); + } + } + + /* context framework adaptation starts */ + context_provider_set_map(CONTEXT_PROVIDER_KEY_NOWPLAYING, + worker->context_nowplaying, FALSE); + /* context framework adaptation ends */ + + /* Add the info to the current metadata. */ + gboolean changed = _current_metadata_add(worker, + mafwtag, + G_TYPE_VALUE_ARRAY, + (const gpointer) values); + + /* Emit the metadata. */ + if (changed && worker->notify_metadata_handler) + { + worker->notify_metadata_handler(worker, + worker->owner, + mafwtag, + G_TYPE_VALUE_ARRAY, + values); + } + + g_value_array_free(values); +} + +/** + * Collect tag-messages, parse it later, when playing is ongoing + */ +static void _handle_tag(MafwGstRendererWorker *worker, GstMessage *msg) +{ + /* Do not emit metadata until we get to PLAYING state to speed up playback + * start */ + if (worker->tag_list == NULL) + worker->tag_list = g_ptr_array_new(); + g_ptr_array_add(worker->tag_list, gst_message_ref(msg)); + + /* Some tags come in playing state, so in this case we have to emit them + * right away (example: radio stations) */ + if (worker->state == GST_STATE_PLAYING) { + _emit_metadatas(worker); + } +} + +/** + * Parses the list of tag-messages + */ +static void _parse_tagmsg(GstMessage *msg, MafwGstRendererWorker *worker) +{ + GstTagList *new_tags; + + gst_message_parse_tag(msg, &new_tags); + gst_tag_list_foreach(new_tags, (gpointer)_emit_tag, worker); + gst_tag_list_free(new_tags); + gst_message_unref(msg); +} + +/** + * Parses the collected tag messages, and emits the metadatas + */ +static void _emit_metadatas(MafwGstRendererWorker *worker) +{ + if (worker->tag_list != NULL) + { + g_ptr_array_foreach(worker->tag_list, (GFunc)_parse_tagmsg, worker); + g_ptr_array_free(worker->tag_list, TRUE); + worker->tag_list = NULL; + } +} + +static void _handle_buffering(MafwGstRendererWorker *worker, GstMessage *msg) +{ + /* We set smaller buffer for mms streams */ + if((g_str_has_prefix(worker->media.location, STREAM_TYPE_MMSH) || g_str_has_prefix(worker->media.location, STREAM_TYPE_MMS)) + && worker->state != GST_STATE_PLAYING && !worker->buffering) + { + if(worker->queue) + { + g_object_set(worker->queue, "high-percent", 30, NULL); + } + else + { + g_warning("Queue2 element doesn't exist!"); + } + } + + /* We can ignore buffering messages when we are in READY state or when going to it */ + if(worker->state == GST_STATE_READY || worker->ready_timeout != 0 ) + { + worker->buffering = TRUE; + return; + } + + gint percent; + gst_message_parse_buffering(msg, &percent); + g_debug("buffering: %d", percent); + + /* No state management needed for live pipelines */ + if (!worker->is_live) { + worker->buffering = TRUE; + if (percent < 100 && worker->state == GST_STATE_PLAYING) { + /* If we need to buffer more, we set larger buffer */ + if(g_str_has_prefix(worker->media.location, STREAM_TYPE_MMSH) || g_str_has_prefix(worker->media.location, STREAM_TYPE_MMS)) + { + if(worker->queue) + { + g_object_set(worker->queue, "high-percent", 100, NULL); + } + else + { + g_warning("Queue2 element doesn't exist!"); + } + } + g_debug("setting pipeline to PAUSED not to wolf the buffer down"); + + //if there's no requested state transitions i.e. resume/pause let's keep this quiet + if( gst_element_get_state(worker->pipeline, NULL, NULL, 0) == GST_STATE_CHANGE_SUCCESS ) + { + worker->report_statechanges = FALSE; + } + + /* We can't call _pause() here, since it sets the + * "report_statechanges" to TRUE. We don't want that, application + * doesn't need to know that internally the state changed to PAUSED. + */ + gst_element_set_state(worker->pipeline, GST_STATE_PAUSED); + } + + if (percent >= 100) { + /* On buffering we go to PAUSED, so here we move back to PLAYING */ + worker->buffering = FALSE; + if (worker->state == GST_STATE_PAUSED) + { + /* If buffering more than once, do this only the first time we + * are done with buffering */ + if (worker->prerolling) + { + g_debug("buffering concluded during prerolling"); + _finalize_startup(worker); + _do_play(worker); + /* Send the paused notification */ + if (worker->stay_paused && + worker->notify_pause_handler) + { + worker->notify_pause_handler(worker, worker->owner); + } + worker->prerolling = FALSE; + } + /* if eos has been reached no automatic playing should be done + only on resume request e.g. eos reached -> seek requested => stays paused after seek&buffering completed */ + else if (!worker->stay_paused && !worker->eos) + { + g_debug("buffering concluded, setting " + "pipeline to PLAYING again"); + worker->report_statechanges = TRUE; + gst_element_set_state(worker->pipeline, GST_STATE_PLAYING); + } + } + /* if there's no pending state changes and we're really in PLAYING state... */ + else if (gst_element_get_state(worker->pipeline, NULL, NULL, 0) == GST_STATE_CHANGE_SUCCESS + && worker->state == GST_STATE_PLAYING) + { + g_debug("buffering concluded, signalling state change"); + /* In this case we got a PLAY command while buffering, likely + * because it was issued before we got the first buffering + * signal. The UI should not do this, but if it does, we have + * to signal that we have executed the state change, since in + * _handle_state_changed we do not do anything if we are + * buffering */ + if (worker->report_statechanges && + worker->notify_play_handler) { + worker->notify_play_handler(worker, worker->owner); + } + _add_duration_seek_query_timeout(worker); + + } + /* has somebody requested pause transition? */ + else if( !worker->stay_paused ) + { + /* we're in PLAYING but pending for paused state change. + Let's request new state change to override the pause */ + gst_element_set_state(worker->pipeline, GST_STATE_PLAYING); + } + } + } + + /* Send buffer percentage */ + if (worker->notify_buffer_status_handler) + worker->notify_buffer_status_handler(worker, worker->owner, percent); +} + +static void _handle_element_msg(MafwGstRendererWorker *worker, GstMessage *msg) +{ + /* Only HelixBin sends "resolution" messages. */ + if (gst_structure_has_name(msg->structure, "resolution") && + _handle_video_info(worker, msg->structure)) + { + worker->media.has_visual_content = TRUE; + set_dolby_video_property(worker, worker->config->mobile_surround_video.state); + set_dolby_video_sound_property(worker, worker->config->mobile_surround_video.room, TRUE); + set_dolby_video_sound_property(worker, worker->config->mobile_surround_video.color, FALSE); + } + /* We do RTSP redirect when we try to play .sdp streams */ + else if(gst_structure_has_name(msg->structure, "redirect")) + { + /* "new-location" contains the rtsp uri what we are going to play */ + mafw_gst_renderer_worker_play(worker, gst_structure_get_string(msg->structure, "new-location")); + } + +} + +static GError * _get_specific_missing_plugin_error(GstMessage *msg) +{ + const GstStructure *gst_struct; + const gchar *type; + + GError *error; + gchar *desc; + + desc = gst_missing_plugin_message_get_description(msg); + + gst_struct = gst_message_get_structure(msg); + type = gst_structure_get_string(gst_struct, "type"); + + if ((type) && ((strcmp(type, MAFW_GST_MISSING_TYPE_DECODER) == 0) || + (strcmp(type, MAFW_GST_MISSING_TYPE_ENCODER) == 0))) { + + /* Missing codec error. */ + const GValue *val; + const GstCaps *caps; + GstStructure *caps_struct; + const gchar *mime; + + val = gst_structure_get_value(gst_struct, "detail"); + caps = gst_value_get_caps(val); + caps_struct = gst_caps_get_structure(caps, 0); + mime = gst_structure_get_name(caps_struct); + + if (g_strrstr(mime, "video")) { + error = g_error_new_literal(WORKER_ERROR, + WORKER_ERROR_VIDEO_CODEC_NOT_FOUND, + desc); + } else if (g_strrstr(mime, "audio")) { + error = g_error_new_literal(WORKER_ERROR, + WORKER_ERROR_AUDIO_CODEC_NOT_FOUND, + desc); + } else { + error = g_error_new_literal(WORKER_ERROR, + WORKER_ERROR_CODEC_NOT_FOUND, + desc); + } + } else { + /* Unsupported type error. */ + error = g_error_new(WORKER_ERROR, + WORKER_ERROR_UNSUPPORTED_TYPE, + "missing plugin: %s", desc); + } + + g_free(desc); + + return error; +} + +/* + * Asynchronous message handler. It gets removed from if it returns FALSE. + */ +static gboolean _async_bus_handler(GstBus *bus, + GstMessage *msg, + MafwGstRendererWorker *worker) +{ + + UNUSED(bus); + + /* No need to handle message if error has already occured. */ + if (worker->is_error) + return TRUE; + + /* Handle missing-plugin (element) messages separately, relaying more + * details. */ + if (gst_is_missing_plugin_message(msg)) { + GError *err = _get_specific_missing_plugin_error(msg); + /* FIXME?: for some reason, calling the error handler directly + * (_send_error) causes problems. On the other hand, turning + * the error into a new GstMessage and letting the next + * iteration handle it seems to work. */ + _post_error(worker, err); + return TRUE; + } + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: + if (!worker->is_error) { + gchar *debug; + GError *err; + debug = NULL; + gst_message_parse_error(msg, &err, &debug); + g_debug("gst error: domain = %s, code = %d, " + "message = '%s', debug = '%s'", + g_quark_to_string(err->domain), err->code, err->message, debug); + if (debug) + { + g_free(debug); + } + //decodebin2 uses the error only to report text files + if (err->code == GST_STREAM_ERROR_WRONG_TYPE && g_str_has_prefix(GST_MESSAGE_SRC_NAME(msg), "decodebin2")) + { + err->code = WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE; + } + + _send_error(worker, err); + } + break; + case GST_MESSAGE_EOS: + if (!worker->is_error) { + worker->eos = TRUE; + worker->seek_position = -1; + if (worker->notify_eos_handler) + { + worker->notify_eos_handler(worker, worker->owner); + } + } + break; + case GST_MESSAGE_TAG: + _handle_tag(worker, msg); + break; + case GST_MESSAGE_BUFFERING: + _handle_buffering(worker, msg); + break; + case GST_MESSAGE_DURATION: + /* in ready state we might not get correct seekability info */ + if (!worker->in_ready) + { + _handle_duration(worker); + } + break; + case GST_MESSAGE_ELEMENT: + _handle_element_msg(worker, msg); + break; + case GST_MESSAGE_STATE_CHANGED: + if ((GstElement *)GST_MESSAGE_SRC(msg) == worker->pipeline) + _handle_state_changed(msg, worker); + break; + case GST_MESSAGE_APPLICATION: + if (gst_structure_has_name(gst_message_get_structure(msg), "ckey")) + { + _emit_property(worker, + WORKER_PROPERTY_COLORKEY, + G_TYPE_INT, + &worker->colorkey); + } + default: + break; + } + return TRUE; +} + +/* NOTE this function will possibly be called from a different thread than the + * glib main thread. */ +static void _stream_info_cb(GstObject *pipeline, GParamSpec *unused, + MafwGstRendererWorker *worker) +{ + UNUSED(pipeline); + UNUSED(unused); + + g_debug("stream-info changed"); + _parse_stream_info(worker); +} + +static void _element_added_cb(GstBin *bin, GstElement *element, + MafwGstRendererWorker *worker) +{ + UNUSED(bin); + gchar *element_name; + + element_name = gst_element_get_name(element); + if(g_str_has_prefix(element_name, "uridecodebin") || + g_str_has_prefix(element_name, "decodebin2")) + { + g_signal_connect(element, "element-added", + G_CALLBACK(_element_added_cb), worker); + } + else if(g_str_has_prefix(element_name, "sdpdemux")) + { + g_object_set(element, "redirect", FALSE, NULL); + } + else if(g_str_has_prefix(element_name, "queue2")) + { + worker->queue = element; + } + g_free(element_name); +} + +/* + * Start to play the media + */ +static void _start_play(MafwGstRendererWorker *worker) +{ + GstStateChangeReturn state_change_info; + worker->stay_paused = FALSE; + char *autoload_sub = NULL; + + g_assert(worker->pipeline); + g_object_set(G_OBJECT(worker->pipeline), + "uri", worker->media.location, NULL); + + if (worker->config->autoload_subtitles) { + autoload_sub = uri_get_subtitle_uri(worker->media.location); + if (autoload_sub) { + g_debug("SUBURI: %s", autoload_sub); + g_object_set(G_OBJECT(worker->pipeline), + "suburi", autoload_sub, + "subtitle-font-desc", worker->config->subtitle_font, + "subtitle-encoding", worker->config->subtitle_encoding, + NULL); + + gst_element_set_state(worker->pipeline, GST_STATE_READY); + g_free(autoload_sub); + } + } else { + g_object_set(G_OBJECT(worker->pipeline), "suburi", NULL, NULL); + } + + g_debug("URI: %s", worker->media.location); + g_debug("setting pipeline to PAUSED"); + + worker->report_statechanges = TRUE; + state_change_info = gst_element_set_state(worker->pipeline, + GST_STATE_PAUSED); + if (state_change_info == GST_STATE_CHANGE_NO_PREROLL) { + /* FIXME: for live sources we may have to handle buffering and + * prerolling differently */ + g_debug ("Source is live!"); + worker->is_live = TRUE; + } + worker->prerolling = TRUE; + + worker->is_stream = uri_is_stream(worker->media.location); + +} + +/* + * Constructs gst pipeline + * + * FIXME: Could the same pipeline be used for playing all media instead of + * constantly deleting and reconstructing it again? + */ +static void _construct_pipeline(MafwGstRendererWorker *worker, configuration *config) +{ + g_debug("constructing pipeline"); + g_assert(worker != NULL); + + /* Return if we have already one */ + if (worker->pipeline) + return; + + _free_taglist(worker); + + g_debug("Creating a new instance of playbin2"); + worker->pipeline = gst_element_factory_make("playbin2", "playbin"); + if (worker->pipeline == NULL) + { + /* Let's try with playbin */ + g_warning ("playbin2 failed, falling back to playbin"); + worker->pipeline = gst_element_factory_make("playbin", "playbin"); + + if (worker->pipeline) { + /* Use nwqueue only for non-rtsp and non-mms(h) streams. */ + gboolean use_nw; + use_nw = worker->media.location && + !g_str_has_prefix(worker->media.location, "rtsp://") && + !g_str_has_prefix(worker->media.location, "mms://") && + !g_str_has_prefix(worker->media.location, "mmsh://"); + + g_debug("playbin using network queue: %d", use_nw); + + gst_object_ref_sink(worker->pipeline); + /* These need a modified version of playbin. */ + g_object_set(G_OBJECT(worker->pipeline), + "nw-queue", use_nw, + "no-video-transform", TRUE, + NULL); + + } + } + + if (!worker->pipeline) { + g_critical("failed to create playback pipeline"); + _send_error(worker, + g_error_new(WORKER_ERROR, + WORKER_ERROR_UNABLE_TO_PERFORM, + "Could not create pipeline")); + g_assert_not_reached(); + } + + worker->bus = gst_pipeline_get_bus(GST_PIPELINE(worker->pipeline)); + gst_bus_set_sync_handler(worker->bus, + (GstBusSyncHandler)_sync_bus_handler, + worker); + worker->async_bus_id = gst_bus_add_watch_full( + worker->bus,G_PRIORITY_HIGH, + (GstBusFunc)_async_bus_handler, + worker, NULL); + + /* Listen for changes in stream-info object to find out whether the media + * contains video and throw error if application has not provided video + * window. */ + g_signal_connect(worker->pipeline, "notify::stream-info", + G_CALLBACK(_stream_info_cb), worker); + + g_signal_connect(worker->pipeline, "element-added", + G_CALLBACK(_element_added_cb), worker); + + /* Set audio and video sinks ourselves. We create and configure them only + * once. */ + if (!worker->asink) { + const gchar *sink = g_getenv("AUDIO_SINK"); + worker->asink = gst_element_factory_make(sink?sink: worker->config->asink, NULL); + if (!worker->asink){ + worker->asink = gst_element_factory_make("alsasink", NULL); + } + if (!worker->asink) { + g_critical("Failed to create pipeline audio sink"); + _send_error(worker, + g_error_new(WORKER_ERROR, + WORKER_ERROR_UNABLE_TO_PERFORM, + "Could not create audio sink")); + g_assert_not_reached(); + } + g_debug("MafwGstRendererWorker: Using following buffer-time: %lld and latency-time: %lld", + config->buffer_time, + config->latency_time); + gst_object_ref_sink(worker->asink); + g_object_set(worker->asink, + "buffer-time", config->buffer_time, + "latency-time", config->latency_time, + NULL); + } + + if (worker->config->use_dhmmixer && !worker->amixer) + { + worker->amixer = gst_element_factory_make("nokiadhmmix", NULL); + if( !worker->amixer ) + { + g_warning("Could not create dhmmixer, falling back to basic audiosink!"); + } + } + + if( worker->config->use_dhmmixer && worker->amixer && !worker->audiobin ) + { + worker->audiobin = gst_bin_new("audiobin"); + if( worker->audiobin ) + { + gst_bin_add(GST_BIN (worker->audiobin), worker->amixer); + gst_bin_add(GST_BIN (worker->audiobin), worker->asink); + gst_element_link(worker->amixer, worker->asink); + GstPad *pad; + pad = gst_element_get_static_pad (worker->amixer, "sink"); + gst_element_add_pad (worker->audiobin, gst_ghost_pad_new ("sink", pad)); + gst_object_unref (GST_OBJECT (pad)); + + gst_object_ref(worker->audiobin); + + /* Use Dolby music settings by default */ + set_dolby_music_property(worker, worker->config->mobile_surround_music.state); + set_dolby_music_sound_property(worker, worker->config->mobile_surround_music.room, TRUE); + set_dolby_music_sound_property(worker, worker->config->mobile_surround_music.color, FALSE); + } + else + { + gst_object_ref_sink(worker->asink); + gst_object_sink(worker->amixer); + g_warning("Could not create audiobin! Falling back to basic audio-sink!"); + } + } + + + if( worker->config->use_dhmmixer && worker->amixer && worker->audiobin ) + { + g_object_set(worker->pipeline, + "audio-sink", worker->audiobin, + "flags", worker->config->flags, + NULL); + } + else + { + g_object_set(worker->pipeline, + "audio-sink", worker->asink, + "flags", worker->config->flags, + NULL); + } + + if( worker->pipeline ) + { + mafw_gst_renderer_seeker_set_pipeline(worker->seeker, worker->pipeline); + + if( worker->vsink && worker->xid != 0 ) + { + g_object_set(worker->pipeline, + "video-sink", worker->vsink, + NULL); + } + } + + if (!worker->tsink) { + worker->tsink = gst_element_factory_make("textoverlay", NULL); + if (!worker->tsink) { + g_critical("Failed to create pipeline text sink"); + _send_error(worker, + g_error_new(WORKER_ERROR, + WORKER_ERROR_UNABLE_TO_PERFORM, + "Could not create text sink")); + g_assert_not_reached(); + } + gst_object_ref(worker->tsink); + } + g_object_set(worker->pipeline, "text-sink", worker->tsink, NULL); +} + +guint check_dolby_audioroute(MafwGstRendererWorker *worker, guint prop) { + if (g_slist_find(worker->destinations, + GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO)) || + g_slist_find(worker->destinations, + GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))) + { + return prop; + } + else + { + return 0; + } +} + +void set_dolby_music_property(MafwGstRendererWorker *worker, guint prop) { + worker->config->mobile_surround_music.state = prop; + if (worker->amixer && !worker->media.has_visual_content) { + GValue a; + guint tempprop = check_dolby_audioroute(worker, prop); + if (_set_value(&a, G_TYPE_UINT, &tempprop)) + { + g_object_set_property(G_OBJECT(worker->amixer), "mobile-surround", &a); + g_value_unset (&a); + } + } +} + +void set_dolby_music_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty) { + if (isRoomProperty) { + worker->config->mobile_surround_music.room = prop; + } else { + worker->config->mobile_surround_music.color = prop; + } + if (worker->amixer && !worker->media.has_visual_content) { + GValue a; + + if (_set_value(&a, G_TYPE_UINT, &prop)) + { + if (isRoomProperty) { + g_object_set_property(G_OBJECT(worker->amixer), "room-size", &a); + } else { + g_object_set_property(G_OBJECT(worker->amixer), "brightness", &a); + } + g_value_unset (&a); + } + } +} + +void set_dolby_video_property(MafwGstRendererWorker *worker, guint prop) { + worker->config->mobile_surround_video.state = prop; + if (worker->amixer && worker->media.has_visual_content) { + GValue a; + guint tempprop = check_dolby_audioroute(worker, prop); + if (_set_value(&a, G_TYPE_UINT, &tempprop)) + { + g_object_set_property(G_OBJECT(worker->amixer), "mobile-surround", &a); + g_value_unset (&a); + } + } +} + +void set_dolby_video_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty) { + if (isRoomProperty) { + worker->config->mobile_surround_video.room = prop; + } else { + worker->config->mobile_surround_video.color = prop; + } + if (worker->amixer && worker->media.has_visual_content) { + GValue a; + + if (_set_value(&a, G_TYPE_UINT, &prop)) + { + if (isRoomProperty) { + g_object_set_property(G_OBJECT(worker->amixer), "room-size", &a); + } else { + g_object_set_property(G_OBJECT(worker->amixer), "brightness", &a); + } + g_value_unset (&a); + } + } +} + +/* + * @seek_type: GstSeekType + * @position: Time in seconds where to seek + * @key_frame_seek: True if this is a key frame based seek + * @error: Possible error that is set and returned + */ +static void _do_seek(MafwGstRendererWorker *worker, + GstSeekType seek_type, + gint position, + gboolean key_frame_seek, + GError **error) +{ + gboolean ret; + gint64 spos; + GstSeekFlags flags = GST_SEEK_FLAG_FLUSH; + + g_assert(worker != NULL); + + if (!worker->media.seekable == SEEKABILITY_SEEKABLE) + { + goto err; + } + + /* According to the docs, relative seeking is not so easy: + GST_SEEK_TYPE_CUR - change relative to currently configured segment. + This can't be used to seek relative to the current playback position - + do a position query, calculate the desired position and then do an + absolute position seek instead if that's what you want to do. */ + if (seek_type == GST_SEEK_TYPE_CUR) + { + gint curpos = mafw_gst_renderer_worker_get_position(worker); + position = curpos + position; + seek_type = GST_SEEK_TYPE_SET; + } + + if (position < 0) { + position = 0; + } + + worker->seek_position = position; + + if (worker->state != GST_STATE_PLAYING && worker->state != GST_STATE_PAUSED ) + { + g_debug("_do_seek: Not in playing or paused state, seeking delayed."); + return; + } + else if( worker->is_live && worker->state == GST_STATE_PAUSED ) + { + g_debug("_do_seek: Live source can be seeked only in playing state, seeking delayed!"); + return; + } + + worker->report_statechanges = FALSE; + + if (key_frame_seek == TRUE) + { + /* tries to do key frame seeks at least with some change */ + ret = mafw_gst_renderer_seeker_seek_to(worker->seeker, worker->seek_position); + } + else + { + spos = (gint64)position * GST_SECOND; + g_debug("seek: type = %d, offset = %lld", seek_type, spos); + + /* exact seek */ + ret = gst_element_seek(worker->pipeline, + 1.0, + GST_FORMAT_TIME, + flags, + seek_type, + spos, + GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE); + } + + if (ret) + { + /* Seeking is async, so seek_position should not be invalidated here */ + return; + } + +err: + g_set_error(error, + WORKER_ERROR, + WORKER_ERROR_CANNOT_SET_POSITION, + "Seeking to %d failed", position); + worker->report_statechanges = TRUE; + worker->seek_position = -1; + mafw_gst_renderer_seeker_cancel(worker->seeker); +} + +void mafw_gst_renderer_worker_set_current_frame_on_pause( + MafwGstRendererWorker *worker, + gboolean current_frame_on_pause) +{ + + worker->current_frame_on_pause = current_frame_on_pause; + + _emit_property(worker, + WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE, + G_TYPE_BOOLEAN, + &worker->current_frame_on_pause); +} + +gboolean mafw_gst_renderer_worker_get_current_frame_on_pause( + MafwGstRendererWorker *worker) +{ + return worker->current_frame_on_pause; +} + +configuration *mafw_gst_renderer_worker_create_default_configuration(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return _create_default_configuration(); +} + +void mafw_gst_renderer_worker_set_configuration(MafwGstRendererWorker *worker, + configuration *config) +{ + if( config == NULL ) + { + g_warning("NULL config was tried to be set!"); + return; + } + + if( worker->config ) + { + _free_configuration(worker->config); + } + worker->config = config; + + if( (worker->pipeline == NULL) + || (worker->state == GST_STATE_NULL && gst_element_get_state(worker->pipeline, NULL, NULL, 0) == GST_STATE_CHANGE_SUCCESS) ) + { + _reset_pipeline_and_worker(worker); + _construct_pipeline(worker, worker->config); + } +} + +/* + * Sets the pipeline PAUSED-to-READY timeout to given value (in seconds). If the + * pipeline is already in PAUSED state and this called with zero value the pipeline + * get immediately set to READY state. + */ +void mafw_gst_renderer_worker_set_ready_timeout(MafwGstRendererWorker *worker, + guint seconds) +{ + g_debug(G_STRFUNC); + + worker->config->seconds_to_pause_to_ready = seconds; + + /* zero is a special case: if we are already in PAUSED state, a pending + * ready timeout has not yet elapsed and we are asked to set the timeout + * value to zero --> remove the pending tmo and go immediately to READY. + * This forces GStreamer to release all pipeline resources and for the + * outsiders it looks like we are still in the PAUSED state. */ + if (seconds == 0 && worker->ready_timeout && worker->state == GST_STATE_PAUSED) + { + _remove_ready_timeout(worker); + _add_ready_timeout(worker); + } + +} + +void mafw_gst_renderer_worker_set_position(MafwGstRendererWorker *worker, + GstSeekType seek_type, + gint position, GError **error) +{ + _do_seek(worker, seek_type, position, TRUE, error); + if (worker->notify_seek_handler) + worker->notify_seek_handler(worker, worker->owner); +} + +static gint64 _get_duration(MafwGstRendererWorker *worker) +{ + gint64 value = DURATION_UNQUERIED; + GstFormat format = GST_FORMAT_TIME; + + gboolean right_query = gst_element_query_duration(worker->pipeline, &format, &value); + if( !right_query ) + { + /* just in case gstreamer messes with the value */ + value = DURATION_UNQUERIED; + } + return value; +} + +/* + * Gets current position, rounded down into precision of one second. If a seek + * is pending, returns the position we are going to seek. Returns -1 on + * failure. + */ +gint mafw_gst_renderer_worker_get_position(MafwGstRendererWorker *worker) +{ + GstFormat format; + gint64 time = 0; + g_assert(worker != NULL); + + /* If seek is ongoing, return the position where we are seeking. */ + if (worker->seek_position != -1) + { + return worker->seek_position; + } + + /* Otherwise query position from pipeline. */ + format = GST_FORMAT_TIME; + if (worker->pipeline && + gst_element_query_position(worker->pipeline, &format, &time)) + { + return (gint)(time / GST_SECOND); + } + /* lets return the duration if we're in eos and the pipeline cannot return position */ + else if( worker->pipeline && worker->eos ) + { + gint64 duration = _get_duration(worker); + if( duration > 0 ) + { + return (gint)(duration / GST_SECOND); + } + } + return -1; +} + +/* + * Returns the duration of the current media in seconds + */ +gint64 mafw_gst_renderer_worker_get_duration(MafwGstRendererWorker *worker) +{ + gint64 duration = _get_duration(worker); + if( duration >= 0 ) + { + gint64 second_precision = (duration + (GST_SECOND/2)) / GST_SECOND; + + if( !_seconds_duration_equal(duration, worker->media.length_nanos) ) + { + worker->media.length_nanos = duration; + + if( _current_metadata_add(worker, + WORKER_METADATA_KEY_DURATION, + G_TYPE_INT64, + (const gpointer)&second_precision) ) + { + _emit_metadata(worker, + WORKER_METADATA_KEY_DURATION, + G_TYPE_INT64, + &second_precision); + } + } + return second_precision; + } + else + { + return -1; + } +} + +gint64 mafw_gst_renderer_worker_get_last_known_duration(MafwGstRendererWorker *worker) +{ + if( worker->media.length_nanos <= 0 ) + { + return worker->media.length_nanos; + } + else + { + return (worker->media.length_nanos + (GST_SECOND/2)) / GST_SECOND; + } +} + +GHashTable *mafw_gst_renderer_worker_get_current_metadata( + MafwGstRendererWorker *worker) +{ + return worker->current_metadata; +} + +void mafw_gst_renderer_worker_set_xid(MafwGstRendererWorker *worker, XID xid) +{ + /* Store the target window id */ + g_debug("Setting xid: %x", (guint)xid); + worker->xid = xid; + + if( !worker->vsink ) + { + g_debug("Creating video-sink as XID has been set, %s", worker->config->vsink); + worker->vsink = gst_element_factory_make(worker->config->vsink, NULL); + if (!worker->vsink) { + worker->vsink = gst_element_factory_make("xvimagesink", NULL); + } + if (!worker->vsink) { + g_critical("Failed to create pipeline video sink"); + _send_error(worker, + g_error_new(WORKER_ERROR, + WORKER_ERROR_UNABLE_TO_PERFORM, + "Could not create video sink")); + g_assert_not_reached(); + } + gst_object_ref_sink(worker->vsink); + + //special case for xvimagesink + { + gchar* element_name = gst_element_get_name(worker->vsink); + g_object_set(G_OBJECT(worker->vsink), + "colorkey", 0x080810, + NULL); + if (g_str_has_prefix(element_name, "xvimagesink")) + { + g_object_set(G_OBJECT(worker->vsink), + "handle-events", TRUE, + "force-aspect-ratio", TRUE, + NULL); + } + g_free(element_name); + } + + //do not dare to set video-sink in any other state + if( worker->pipeline && worker->state == GST_STATE_NULL ) + { + g_object_set(worker->pipeline, + "video-sink", worker->vsink, + NULL); + } + } + + /* We don't want to set XID to video sink here when in READY state, because + it prevents "prepare-xwindow-id" message. Setting it when we are + PAUSED or PLAYING is fine, because we already got "prepare-xwindow-id". */ + if(worker->state == GST_STATE_PLAYING || + worker->state == GST_STATE_PAUSED) + { + /* Check if we should use it right away */ + mafw_gst_renderer_worker_apply_xid(worker); + } + + _emit_property(worker, WORKER_PROPERTY_XID, G_TYPE_UINT, &worker->xid); + +} + +XID mafw_gst_renderer_worker_get_xid(MafwGstRendererWorker *worker) +{ + return worker->xid; +} + +void mafw_gst_renderer_worker_set_render_rectangle(MafwGstRendererWorker *worker, render_rectangle *rect) +{ + /* Store the target window id */ + g_debug("Setting render rectangle: X:%d,Y:%d Width:%d, Height:%d", + rect->x, rect->y, rect->width, rect->height); + + worker->x_overlay_rectangle.x = rect->x; + worker->x_overlay_rectangle.y = rect->y; + worker->x_overlay_rectangle.width = rect->width; + worker->x_overlay_rectangle.height = rect->height; + + /* Check if we should use it right away */ + mafw_gst_renderer_worker_apply_render_rectangle(worker); + + GValueArray *rect_array = g_value_array_new(4); + GValue x; + GValue y; + GValue width; + GValue height; + + _set_value(&x, G_TYPE_INT, &(rect->x)); + _set_value(&y, G_TYPE_INT, &(rect->y)); + _set_value(&width, G_TYPE_INT, &(rect->width)); + _set_value(&height, G_TYPE_INT, &(rect->height)); + + g_value_array_insert(rect_array, 0, &x ); + g_value_array_insert(rect_array, 1, &y ); + g_value_array_insert(rect_array, 2, &width ); + g_value_array_insert(rect_array, 3, &height ); + + GValue value; + memset(&value, 0, sizeof(value)); + g_value_init(&value, G_TYPE_VALUE_ARRAY); + g_value_take_boxed(&value, rect_array); + + _emit_property(worker, WORKER_PROPERTY_RENDER_RECTANGLE, G_TYPE_VALUE_ARRAY, &value); + + g_value_unset(&value); +} + +const render_rectangle* mafw_gst_renderer_worker_get_render_rectangle(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return &worker->x_overlay_rectangle; +} + +gboolean mafw_gst_renderer_worker_get_autopaint(MafwGstRendererWorker *worker) +{ + return worker->autopaint; +} + +void mafw_gst_renderer_worker_set_autopaint(MafwGstRendererWorker *worker, + gboolean autopaint) +{ + /* TODO Is this a bug or a feature? */ + worker->autopaint = autopaint; + if (worker->vsink) + g_object_set(worker->vsink, "autopaint-colorkey", autopaint, NULL); + + _emit_property(worker, + WORKER_PROPERTY_AUTOPAINT, + G_TYPE_BOOLEAN, + &autopaint); + +} + +gboolean mafw_gst_renderer_worker_set_playback_speed(MafwGstRendererWorker* worker, + gfloat speed) +{ + gboolean retVal = FALSE; + + if (worker->state == GST_STATE_PLAYING) + { + worker->playback_speed = speed; + + gint64 current_position; + GstFormat format = GST_FORMAT_TIME; + + if (worker->pipeline && gst_element_query_position(worker->pipeline, + &format, + ¤t_position)) + { + + retVal = gst_element_seek(worker->pipeline, + speed, + GST_FORMAT_DEFAULT, + GST_SEEK_FLAG_SKIP | GST_SEEK_FLAG_KEY_UNIT, + GST_SEEK_TYPE_NONE, + current_position, + GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE); + + if(retVal) + { + _emit_property(worker, + WORKER_PROPERTY_PLAYBACK_SPEED, + G_TYPE_FLOAT, + &speed); + } + } + } + + return retVal; +} + +gfloat mafw_gst_renderer_worker_get_playback_speed(MafwGstRendererWorker* worker) +{ + return worker->playback_speed; +} + +void mafw_gst_renderer_worker_set_force_aspect_ratio(MafwGstRendererWorker *worker, gboolean force) +{ + + worker->force_aspect_ratio = force; + if (worker->vsink) + { + g_object_set(worker->vsink, "force-aspect-ratio", force, NULL); + } + _emit_property(worker, WORKER_PROPERTY_FORCE_ASPECT_RATIO, G_TYPE_BOOLEAN, &force); + +} + +gboolean mafw_gst_renderer_worker_get_force_aspect_ratio(MafwGstRendererWorker *worker) +{ + return worker->force_aspect_ratio; +} + +gint mafw_gst_renderer_worker_get_colorkey(MafwGstRendererWorker *worker) +{ + return worker->colorkey; +} + +gboolean mafw_gst_renderer_worker_get_seekable(MafwGstRendererWorker *worker) +{ + return worker->media.seekable == SEEKABILITY_SEEKABLE; +} + +gboolean mafw_gst_renderer_worker_get_streaming(MafwGstRendererWorker *worker) +{ + return uri_is_stream(worker->media.location); +} + +const char* mafw_gst_renderer_worker_get_uri(MafwGstRendererWorker *worker) +{ + return worker->media.location; +} + +static void _do_play(MafwGstRendererWorker *worker) +{ + g_assert(worker != NULL); + + if (worker->pipeline == NULL) { + g_debug("play without a pipeline!"); + return; + } + worker->report_statechanges = TRUE; + + /* If we have to stay paused, we do and add the ready timeout. Otherwise, we + * move the pipeline */ + if (!worker->stay_paused) { + /* If pipeline is READY, we move it to PAUSED, otherwise, to PLAYING */ + if (worker->state == GST_STATE_READY) { + gst_element_set_state(worker->pipeline, GST_STATE_PAUSED); + g_debug("setting pipeline to PAUSED"); + } else { + gst_element_set_state(worker->pipeline, GST_STATE_PLAYING); + g_debug("setting pipeline to PLAYING"); + } + } + else { + g_debug("staying in PAUSED state"); + _add_ready_timeout(worker); + } +} + +void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker, + const gchar *uri) +{ + g_assert(uri); + + mafw_gst_renderer_worker_stop(worker); + _reset_media_info(worker); + + /* Set the item to be played */ + worker->media.location = g_strdup(uri); + + _start_play(worker); +} + +/* + * Currently, stop destroys the Gst pipeline and resets the worker into + * default startup configuration. + */ +void mafw_gst_renderer_worker_stop(MafwGstRendererWorker *worker) +{ + g_debug("worker stop"); + g_assert(worker != NULL); + + /* If location is NULL, this is a pre-created pipeline */ + if (worker->async_bus_id && worker->pipeline && !worker->media.location) + return; + + _reset_pipeline_and_worker(worker); + + /* context framework adaptation starts */ + if (worker->context_nowplaying) { + context_provider_map_free(worker->context_nowplaying); + worker->context_nowplaying = NULL; + } + context_provider_set_null(CONTEXT_PROVIDER_KEY_NOWPLAYING); + /* context framework adaptation ends */ + + /* We are not playing, so we can let the screen blank */ + if (worker->blanking__control_handler) + { + worker->blanking__control_handler(worker, worker->owner, FALSE); + } + + /* And now get a fresh pipeline ready */ + _construct_pipeline(worker, worker->config); +} + +void mafw_gst_renderer_worker_pause(MafwGstRendererWorker *worker) +{ + g_assert(worker != NULL); + + if (worker->buffering && worker->state == GST_STATE_PAUSED && + !worker->prerolling) + { + /* If we are buffering and get a pause, we have to + * signal state change and stay_paused */ + g_debug("Pausing while buffering, signalling state change"); + + /* We need to make sure that we go into real PAUSE state */ + if (worker->blanking__control_handler) + { + worker->blanking__control_handler(worker, worker->owner, FALSE); + } + _do_pause_postprocessing(worker); + } + else + { + worker->report_statechanges = TRUE; + if (worker->seek_position == -1 && worker->state == GST_STATE_PLAYING ) + { + gst_element_set_state(worker->pipeline, GST_STATE_PAUSED); + if (worker->blanking__control_handler) + { + worker->blanking__control_handler(worker, worker->owner, FALSE); + } + } + } + + worker->stay_paused = TRUE; + worker->pause_frame_taken = FALSE; +} + +/* + * Notifier to call when audio/video routing changes + */ +void mafw_gst_renderer_worker_notify_media_destination( + MafwGstRendererWorker *worker, + GSList *destinations) +{ + g_assert(worker != NULL); + g_assert(destinations != NULL); + + /* 1. update our records of current destinations */ + g_slist_free(worker->destinations); + worker->destinations = g_slist_copy(destinations); + + /* 2. prevent blanking if we are playing video and outputting it on our own + * display, otherwise disable it */ + if (worker->blanking__control_handler && + worker->media.has_visual_content && + worker->state == GST_STATE_PLAYING && + g_slist_find(worker->destinations, + GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))) + { + worker->blanking__control_handler(worker, worker->owner, TRUE); + } + else + { + worker->blanking__control_handler(worker, worker->owner, FALSE); + } + + /* 3. disabling Dolby Headphone effect if not outputting to audio jack or + * bluetooth headphones, otherwise using the effect. Actual route check is done + * in set_dolby_*****_property function*/ + set_dolby_music_property(worker, worker->config->mobile_surround_music.state); + set_dolby_video_property(worker, worker->config->mobile_surround_video.state); + +} + +void mafw_gst_renderer_worker_pause_at(MafwGstRendererWorker *worker, guint position) +{ + /* the current implementation works only from ready i.e. stopped state */ + g_assert( worker != NULL); + worker->stay_paused = TRUE; + worker->pause_frame_taken = FALSE; + worker->seek_position = position; + + if( worker->vsink ) + { + g_object_set(worker->vsink, "show-preroll-frame", + FALSE, NULL); + } +} + +void mafw_gst_renderer_worker_resume(MafwGstRendererWorker *worker) +{ + worker->stay_paused = FALSE; + if (worker->buffering && worker->state == GST_STATE_PAUSED && + !worker->prerolling) { + /* If we are buffering we cannot resume, but we know that the pipeline + * will be moved to PLAYING as stay_paused is FALSE, so we just + * activate the state change report, this way as soon as buffering + * is finished the pipeline will be set to PLAYING and the state + * change will be reported */ + worker->report_statechanges = TRUE; + g_debug("Resumed while buffering, activating pipeline state changes"); + /* Notice though that we can receive the Resume before we get any + buffering information. In that case we go with the "else" branch + and set the pipeline to to PLAYING. However, it is possible that + in this case we get the fist buffering signal before the PAUSED -> + PLAYING state change. In that case, since we ignore state changes + while buffering we never signal the state change to PLAYING. We + can only fix this by checking, when we receive a PAUSED -> PLAYING + transition if we are buffering, and in that case signal the state + change (if we get that transition while buffering is on, it can + only mean that the client resumed playback while buffering, and + we must notify the state change) */ + } else { + _do_play(worker); + } + + /* we want to resume no use for these timers anymore */ + _remove_pause_frame_timeout(worker); + _remove_ready_timeout(worker); +} + +MafwGstRendererWorker *mafw_gst_renderer_worker_new(gpointer owner) +{ + MafwGstRendererWorker *worker; + + g_debug("%s", G_STRFUNC); + + worker = g_new0(MafwGstRendererWorker, 1); + worker->owner = owner; + worker->report_statechanges = TRUE; + worker->state = GST_STATE_NULL; + worker->seek_position = -1; + worker->ready_timeout = 0; + worker->pause_frame_timeout = 0; + worker->duration_seek_timeout = 0; + worker->duration_seek_timeout_loop_count = 0; + worker->in_ready = FALSE; + worker->xid = 0; + worker->x_overlay_rectangle.x = -1; + worker->x_overlay_rectangle.y = -1; + worker->x_overlay_rectangle.width = -1; + worker->x_overlay_rectangle.height = -1; + worker->autopaint = TRUE; + worker->playback_speed = 1; + worker->colorkey = -1; + worker->vsink = NULL; + worker->asink = NULL; + worker->tsink = NULL; + worker->amixer = NULL; + worker->audiobin = NULL; + worker->tag_list = NULL; + worker->current_metadata = NULL; + worker->media.seekable = SEEKABILITY_SEEKABLE; + + worker->destinations = NULL; + + worker->current_frame_on_pause = FALSE; + worker->taking_screenshot = FALSE; + worker->force_aspect_ratio = TRUE; + _init_tmp_files_pool(worker); + worker->notify_seek_handler = NULL; + worker->notify_pause_handler = NULL; + worker->notify_play_handler = NULL; + worker->notify_buffer_status_handler = NULL; + worker->notify_eos_handler = NULL; + worker->notify_metadata_handler = NULL; + worker->notify_error_handler = NULL; + worker->blanking__control_handler = NULL; + worker->screenshot_handler = NULL; + + worker->config = _create_default_configuration(); + + worker->seeker = mafw_gst_renderer_seeker_new(); + + if (!_context_fw_initialised) + { + /* context framework adaptation starts */ + if (context_provider_init(DBUS_BUS_SESSION, CONTEXT_PROVIDER_BUS_NAME)) { + _context_fw_initialised = TRUE; + context_provider_install_key(CONTEXT_PROVIDER_KEY_NOWPLAYING, FALSE, + NULL, NULL); + g_debug("Initialized context framework provider"); + } + else { + g_warning("Could not initialize context framework provider"); + } + } + /* context framework adaptation ends */ + + return worker; + +} + +void mafw_gst_renderer_worker_exit(MafwGstRendererWorker *worker) +{ + _destroy_tmp_files_pool(worker); + _reset_pipeline_and_worker(worker); + + /* We are not playing, so we can let the screen blank */ + if (worker->blanking__control_handler) + { + worker->blanking__control_handler(worker, worker->owner, FALSE); + } + + /* now finally sinks/bins are released */ + if( worker->audiobin ) + { + gst_object_unref(worker->audiobin); + worker->audiobin = NULL; + } + else if( worker->asink ) + { + gst_object_unref(worker->asink); + worker->asink = NULL; + } + + if( worker->vsink ) + { + gst_object_unref(worker->vsink); + worker->vsink = NULL; + } + + context_provider_stop(); + _context_fw_initialised = FALSE; + + if( worker->destinations ) + { + g_slist_free(worker->destinations); + worker->destinations = NULL; + } + + if( worker->config ) + { + _free_configuration(worker->config); + worker->config = NULL; + } + + if( worker->seeker ) + { + mafw_gst_renderer_seeker_free(worker->seeker); + worker->seeker = NULL; + } +} diff --git a/qmafw-gst-subtitles-renderer/unittests/common/LibCredsStub.cpp b/qmafw-gst-subtitles-renderer/unittests/common/LibCredsStub.cpp new file mode 100644 index 0000000..f372630 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/LibCredsStub.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include + +namespace Stub +{ + bool global_route_provider_trusted = true; +} + +creds_t creds_gettask(pid_t /*pid*/) +{ + return (creds_t)1; +} + +int creds_have_p(const creds_t creds, creds_type_t type, creds_value_t value) +{ + Q_UNUSED(creds); + Q_UNUSED(type); + Q_UNUSED(value); + + if( Stub::global_route_provider_trusted ) + { + return 1; + } + + return 0; +} + +long creds_str2creds(const char *credential, creds_value_t *value) +{ + Q_UNUSED(credential); + Q_UNUSED(value); + + return 1234; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwBasicRendererStub.cpp b/qmafw-gst-subtitles-renderer/unittests/common/MafwBasicRendererStub.cpp new file mode 100644 index 0000000..c3a1e3b --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwBasicRendererStub.cpp @@ -0,0 +1,42 @@ +#include +#include "MafwStubHelper.h" + +MafwStubHelper* m_stubHelper = 0; +MafwRendererPolicy* m_policyStub; + +void setStubHelper(MafwStubHelper* stubHlp) +{ + m_stubHelper = stubHlp; +} + +void setMafwRendererPolicy(MafwRendererPolicy *policy ) +{ + m_policyStub = policy; +} + +bool MafwBasicRenderer::initialize() +{ + return m_stubHelper->getReturn("initialize").toBool(); +} + +bool MafwBasicRenderer::setDefaultRendererPolicy(MafwRendererPolicy::PolicyGroup) +{ + return m_stubHelper->getReturn("setDefaultRendererPolicy").toBool(); +} + +MafwRendererPolicy* MafwBasicRenderer::rendererPolicy() const +{ + return m_policyStub; +} + +bool MafwBasicRenderer::setMafwProperty(const QString &name, const QVariant &value) +{ + return MafwRenderer::setMafwProperty(name, value); +} + +bool MafwBasicRenderer::pause() +{ + doPause(); + return true; +} + diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwPlaylistFileUtilityStub.cpp b/qmafw-gst-subtitles-renderer/unittests/common/MafwPlaylistFileUtilityStub.cpp new file mode 100644 index 0000000..129a1e9 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwPlaylistFileUtilityStub.cpp @@ -0,0 +1,66 @@ +#include "MafwGstRendererPlaylistFileUtility.h" +#include "MafwGstRenderer.h" +#include +#include +#include +#include "MafwStubHelper.h" + +MafwGstRenderer* m_rnd = 0; +QStringList stubPlaylistFileUtilityUris = QStringList() << "testUri1" << "testUri2"; + +MafwGstRendererPlaylistFileUtility::MafwGstRendererPlaylistFileUtility(QObject* parent): + QObject(parent) +{ + m_rnd = static_cast(parent); +} + +MafwGstRendererPlaylistFileUtility::~MafwGstRendererPlaylistFileUtility(){} + +void MafwGstRendererPlaylistFileUtility::parsePlaylistFile(const QUrl&) +{ + qDebug() << "MafwGstRendererPlaylistFileUtility::parsePlaylistFile"; + m_uriList.append(stubPlaylistFileUtilityUris); + Q_EMIT parsingReady(true); + Q_EMIT firstItemParsed(); +} + +QStringList MafwGstRendererPlaylistFileUtility::getUriList() +{ + return m_uriList; +} + +QString MafwGstRendererPlaylistFileUtility::takeFirstUri() +{ + if (m_uriList.isEmpty()) + { + return QString(); + } + else + { + return m_uriList.takeFirst(); + } +} + +void MafwGstRendererPlaylistFileUtility::uriParsed(TotemPlParser*, + gchar*, + gpointer, + MafwGstRendererPlaylistFileUtility*) +{} + +void MafwGstRendererPlaylistFileUtility::readyCb(TotemPlParser*, GAsyncResult*, MafwGstRendererPlaylistFileUtility*) +{} + +void MafwGstRendererPlaylistFileUtility::setPendingError(MafwError& error) +{ + m_pendingError = error; +} + +/******************************************************************** + * MafwGstRendererPlaylistFileUtility::takePendingError + ********************************************************************/ +MafwError MafwGstRendererPlaylistFileUtility::takePendingError() +{ + MafwError error = m_pendingError; + m_pendingError = MafwError(); + return error; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.cpp b/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.cpp new file mode 100644 index 0000000..7018be8 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.cpp @@ -0,0 +1,39 @@ +#include "MafwRendererPolicyStub.h" + +MafwRendererPolicyStub::MafwRendererPolicyStub() +{ +} + +MafwRendererPolicyStub::~MafwRendererPolicyStub() +{ + +} + +bool MafwRendererPolicyStub::initialize(MafwRendererPolicy::PolicyGroup group) +{ + return group == MafwRendererPolicy::MediaPlayer; +} + +void MafwRendererPolicyStub::setDefaultResources(MafwRendererPolicy::PolicyResourceFlags) +{ + //nothing to do here +} + +void MafwRendererPolicyStub::request(MafwRendererPolicy::PolicyResourceFlags) +{ + +} + +void MafwRendererPolicyStub::release(MafwRendererPolicy::PolicyResourceFlags flags) +{ + m_latestRelease = flags; +} + +MafwRendererPolicy::PolicyResourceFlags MafwRendererPolicyStub::latestReleaseFlags() +{ + MafwRendererPolicy::PolicyResourceFlags toReturn = m_latestRelease; + m_latestRelease = 0; + return toReturn; +} + + diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.h b/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.h new file mode 100644 index 0000000..5a476e9 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwRendererPolicyStub.h @@ -0,0 +1,21 @@ +#include + +class MafwRendererPolicyStub : public MafwRendererPolicy +{ + Q_OBJECT + +public: + MafwRendererPolicyStub(); + ~MafwRendererPolicyStub(); + + bool initialize(MafwRendererPolicy::PolicyGroup); + void setDefaultResources(QFlags); + void request(QFlags); + void release(QFlags); + + //testing functions + MafwRendererPolicy::PolicyResourceFlags latestReleaseFlags(); + +private: + MafwRendererPolicy::PolicyResourceFlags m_latestRelease; +}; diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwRoutingInfoHandlerStub.cpp b/qmafw-gst-subtitles-renderer/unittests/common/MafwRoutingInfoHandlerStub.cpp new file mode 100644 index 0000000..f33d822 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwRoutingInfoHandlerStub.cpp @@ -0,0 +1,67 @@ + +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwRoutingInfoHandler.h" + +#include +#include +#include + +#include +#include +#include + +bool routeTrusted = false; + +MafwRoutingInfoHandler::MafwRoutingInfoHandler(ContextProperty& property) : + m_property(property) +{ + +} + +MafwRoutingInfoHandler::~MafwRoutingInfoHandler() +{ +} + +void MafwRoutingInfoHandler::startProviderCheck() +{ + qDebug() << "startProviderCheck"; +} + + void MafwRoutingInfoHandler::callFinishedSlot(QDBusPendingCallWatcher*) + { + qDebug() << "callFinishedSlot"; + } + +void MafwRoutingInfoHandler::gotReply(int) +{ + Q_EMIT routeChanged(routeTrusted); +} + +void MafwRoutingInfoHandler::error() +{ + qDebug() << __PRETTY_FUNCTION__; + + Q_EMIT routeChanged(false); +} + +bool MafwRoutingInfoHandler::isPidTrusted (int) +{ + + return true; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.cpp b/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.cpp new file mode 100644 index 0000000..9e2d4fa --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.cpp @@ -0,0 +1,140 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + + +#include +#include + +#include "MafwStubHelper.h" + +MafwStubHelper::MafwStubHelper() +{ + m_expectedCalls = QQueue(); +} + +MafwStubHelper::~MafwStubHelper() +{ + clear(); +} + +void MafwStubHelper::printExpects() const +{ + QStringList expectedNames; + for(int i=0; iexpectedName; + } + qDebug() << "Expected calls enqueued (" << m_expectedCalls.size() << "): \n\t" << expectedNames.join(",\n\t "); +} + +void MafwStubHelper::expect(const QString& function, QVariant returnVal) +{ + QList emptyParams; + QList returnList; + returnList << returnVal; + expect(function, emptyParams, returnList); +} + + +void MafwStubHelper::expect(const QString function, const QList params, + const QList returns) +{ + qDebug() << "MafwStubHelper::expect, function = " << function << " " << returns.at(0); + + ExpectedItem* item = new ExpectedItem; + item->expectedName = function; + item->expectedParams = params; + item->returnValues = returns; + m_expectedCalls.enqueue(item); +} + +QVariant MafwStubHelper::getReturn(const QString& function) +{ + QList emptyParams; + QList returnList; + getReturn(function, emptyParams, returnList); + if (returnList.isEmpty()) + { + return QVariant(); + } + else + { + return returnList.first(); + } +} + +void MafwStubHelper::getReturn(const QString function, const QList params, + QList& returns) +{ + // Check if the call is expected + if ( m_expectedCalls.isEmpty() ) + { + qDebug() << "MafwStubHelper::getReturn, function = " << function <<", no expected calls"; + return; + } + if (!m_expectedCalls.isEmpty() && function.compare(m_expectedCalls.head()->expectedName)) + { + qDebug() << "MafwStubHelper::getReturn: " << function << ", not expected (2)"; + printExpects(); + return; + } + ExpectedItem* item = m_expectedCalls.dequeue(); + + // Check if the parameters match + if (!item->expectedParams.isEmpty()) + { + for (int i = 0; i < item->expectedParams.count() && item->expectedParams.count() == params.count(); ++i) + { + if (item->expectedParams.at(i) != params.at(i)) + { + qDebug() << "MafwStubHelper::getReturn: " << function <<", not expected (2)"; + return; + } + } + } + // Expected parameters list was empty but given was not + else if (!params.isEmpty()) + { + qDebug() << "MafwStubHelper::getReturn: " << function <<", not expected (3)"; + return; + } + else + { + } + + // Everything ok, let's find the return values + returns = item->returnValues; + + qDebug() << "MafwStubHelper::getReturn, function: " << function << ", returns: " << returns; + + delete item; +} + +bool MafwStubHelper::allCallsConsumed() const +{ + return m_expectedCalls.isEmpty(); +} + +void MafwStubHelper::clear() +{ + qDebug() << "MafwStubHelper::clear()"; + + qDeleteAll(m_expectedCalls); + m_expectedCalls.clear(); +} + +// End of file diff --git a/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.h b/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.h new file mode 100644 index 0000000..87a6871 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/MafwStubHelper.h @@ -0,0 +1,108 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef MAFWSTUBHELPER_H_ +#define MAFWSTUBHELPER_H_ + +#include +#include +#include +#include +#include + +/** + * This class is meant to help implementing stubs needed in unit testing. + * + * Usage: Create instance of MafwStubHelper and provide your stub access + * to it. Initialize MafwStubHelper with function calls the stub is + * expected to get. Implement your stub to ask for return values from + * MafwStubHelper. At the end of a test case, check if all expected + * calls are consumed. + */ + + +class MafwStubHelper +{ +public: + MafwStubHelper(); + ~MafwStubHelper(); + + /** + * expect - Adds call to expected calls + * + * @param function Name of the expected function call, without paranthesis. + * @param params List of expected parameters given to function call. + * @param returns List of return values to be given to the stub. + */ + void expect(const QString function, const QList params, const QList returns); + + /** + * expect - Adds call to expected calls + * + * @param function Name of the expected function call, without paranthesis. + * @param returnVal The return value to be given to the stub. + */ + void expect(const QString& function, QVariant returnVal); + + /** + * getReturn - Consumes call from expected calls + * + * @param function Name of the function call, without paranthesis. + * @param params List of parameters given to function call. + * @param returns Empty list for getting the return values. + * List is empty at return if function wasn't the next expected function call. + */ + void getReturn(const QString function, const QList params, QList& returns); + + /** + * getReturn - Consumes call from expected calls + * + * @param function Name of the function call, without paranthesis. + * @return return value is invalid if function wasn't the next expected function call. + */ + QVariant getReturn(const QString& function); + + /** + * allCallsConsumed - Checks if all expected calls are consumed + * + * @return true, if all expected calls are consumed + * false otherwise. + */ + bool allCallsConsumed() const; + + /** + * clear - Clears all data + */ + void clear(); + +private: + void printExpects() const; + + +private: + + struct ExpectedItem + { + QString expectedName; + QList expectedParams; + QList returnValues; + }; + + QQueue m_expectedCalls; +}; + +#endif /*MAFWSTUBHELPER_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.cpp b/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.cpp new file mode 100644 index 0000000..d97aa74 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.cpp @@ -0,0 +1,114 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "QNetworkStubs.h" + +#include +#include +#include +#include + + +NetworkStubHelper networkStub; +int NetworkStubHelper::networkConfigurationManagerInstances = 0; + +/** + + QNetworkConfiguration + + **/ + +bool NetworkStubHelper::currentCreatedConfigIsValid = false; + +static int staticCreationId = 0; +class QNetworkConfigurationPrivate : public QSharedData +{ +public: + int creationId; + bool isValid; +}; + +QNetworkConfiguration::QNetworkConfiguration() +{ + d = new QNetworkConfigurationPrivate; + d->creationId = ++staticCreationId; + d->isValid = networkStub.currentCreatedConfigIsValid; +} + +QNetworkConfiguration::~QNetworkConfiguration() +{ + +} + +QNetworkConfiguration::QNetworkConfiguration(const QNetworkConfiguration &other) +{ + d = new QNetworkConfigurationPrivate; + d->creationId = other.d->creationId; +} + +QNetworkConfiguration::StateFlags QNetworkConfiguration::state() const +{ + return networkStub.m_currentConfState; +} + +QString QNetworkConfiguration::name() const +{ + return "Test conf"; +} + +bool QNetworkConfiguration::isValid() const +{ + return d->isValid; +} + +QNetworkConfiguration& QNetworkConfiguration::operator=(QNetworkConfiguration const &other) +{ + d->creationId = other.d->creationId; + return *this; +} + +bool QNetworkConfiguration::operator==(const QNetworkConfiguration &other ) const +{ + return d->creationId == other.d->creationId; +} + +/** + + QNetworkConfigurationManager + + **/ + +QNetworkConfigurationManager::QNetworkConfigurationManager(QObject *parent) + : + QObject(parent) +{ + ++networkStub.networkConfigurationManagerInstances; + if( networkStub.networkConfigurationManagerInstances == 1) + { + connect( &networkStub, SIGNAL(configurationChange(QNetworkConfiguration)), + this, SIGNAL(configurationChanged(QNetworkConfiguration))); + } +} + +QNetworkConfigurationManager::~QNetworkConfigurationManager() +{ + --networkStub.networkConfigurationManagerInstances; + if( networkStub.networkConfigurationManagerInstances == 0 ) + { + networkStub.disconnect(this); + } +} diff --git a/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.h b/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.h new file mode 100644 index 0000000..4c31744 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/QNetworkStubs.h @@ -0,0 +1,53 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef QNETWORKSTUBS_H +#define QNETWORKSTUBS_H + +#include +#include + +class QNetworkConfigurationManager; + +class NetworkStubHelper : public QObject +{ + Q_OBJECT + + static int networkConfigurationManagerInstances; + + friend class QNetworkConfiguration; + friend class QNetworkConfigurationManager; +public: + static bool currentCreatedConfigIsValid; + + void emitConfigurationChange(const QNetworkConfiguration &config, + QNetworkConfiguration::StateFlags confState) + { + m_currentConfState = confState; + Q_EMIT configurationChange(config); + } + + void changeCurrentConfiguration(int id); + +Q_SIGNALS: + void configurationChange(QNetworkConfiguration config); + +private: + QNetworkConfiguration::StateFlags m_currentConfState; +}; + +#endif // QNETWORKSTUBS_H diff --git a/qmafw-gst-subtitles-renderer/unittests/common/renderer-worker-stub.c b/qmafw-gst-subtitles-renderer/unittests/common/renderer-worker-stub.c new file mode 100644 index 0000000..b8deb3d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/common/renderer-worker-stub.c @@ -0,0 +1,380 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include //memset +#include "mafw-gst-renderer-worker.h" +#include "mafw-gst-renderer-utils.h" + +GError* global_error = 0; +gint global_position = 0; +gint global_worker_audio_destination = -1; +gint global_worker_video_destination = -1; +gchar *global_worker_uri = 0; +gint global_worker_stop_called = 0; +gint global_worker_seek_request = 0; +GSList *global_worker_destinations = NULL; +guint global_ready_timeout = 99999; + +guint m_volume; +gboolean m_mute; +gboolean m_current_frame_on_pause; +gboolean m_force_aspect_ratio; +gfloat m_playback_speed = 1; +XID m_xid; + +render_rectangle m_render_rectangle; +configuration *current_worker_conf; + + +gboolean global_worker_playing = FALSE; + +#define UNUSED(x) (void)(x) + +void mafw_gst_renderer_worker_set_volume(MafwGstRendererWorker *worker, + guint volume) +{ + UNUSED(worker); + m_volume = volume; +} + +guint mafw_gst_renderer_worker_get_volume(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_volume; +} + +void mafw_gst_renderer_worker_set_mute(MafwGstRendererWorker *worker, + gboolean mute) +{ + UNUSED(worker); + m_mute = mute; +} + +gboolean mafw_gst_renderer_worker_get_mute(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_mute; +} + +gint64 mafw_gst_renderer_worker_get_last_known_duration(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return 10; +} + +const char* mafw_gst_renderer_worker_get_uri(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return global_worker_uri; +} + +gboolean mafw_gst_renderer_worker_get_seekable(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return TRUE; +} + +void _free_configuration(configuration *config) +{ + if( !config ) + { + return; + } + + if( config->asink ) + { + g_free(config->asink); + } + if( config->vsink ) + { + g_free(config->vsink); + } + + g_free(config); +} + +void mafw_gst_renderer_worker_set_current_frame_on_pause( + MafwGstRendererWorker *worker, + gboolean current_frame_on_pause) +{ + UNUSED(worker); + m_current_frame_on_pause = current_frame_on_pause; +} + +gboolean mafw_gst_renderer_worker_get_current_frame_on_pause( + MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_current_frame_on_pause; +} + +void mafw_gst_renderer_worker_set_position(MafwGstRendererWorker *worker, + GstSeekType seek_type, + gint position, GError **error) +{ + UNUSED(worker); + UNUSED(seek_type); + global_worker_seek_request = position; + *error = global_error; +} + +gint mafw_gst_renderer_worker_get_position(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return global_position; +} + +void mafw_gst_renderer_worker_set_xid(MafwGstRendererWorker *worker, XID xid) +{ + UNUSED(worker); + m_xid = xid; +} + +gboolean mafw_gst_renderer_worker_get_streaming(MafwGstRendererWorker *worker) +{ + return uri_is_stream(global_worker_uri); +} + +XID mafw_gst_renderer_worker_get_xid(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_xid; +} + + +void mafw_gst_renderer_worker_set_render_rectangle(MafwGstRendererWorker *worker, render_rectangle *rect) +{ + UNUSED(worker); + m_render_rectangle.x = rect->x; + m_render_rectangle.y = rect->y; + m_render_rectangle.width = rect->width; + m_render_rectangle.height = rect->height; +} + +const render_rectangle* mafw_gst_renderer_worker_get_render_rectangle(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return &m_render_rectangle; +} + + +gboolean mafw_gst_renderer_worker_get_autopaint(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return TRUE; +} + +void mafw_gst_renderer_worker_set_ready_timeout(MafwGstRendererWorker *worker, + guint seconds) +{ + UNUSED(worker); + global_ready_timeout = seconds; +} + +void mafw_gst_renderer_worker_set_autopaint(MafwGstRendererWorker *worker, + gboolean autopaint) +{ + UNUSED(worker); + UNUSED(autopaint); +} + +gint mafw_gst_renderer_worker_get_colorkey(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return 1; +} + +void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker, + const gchar *uri) +{ + UNUSED(worker); + UNUSED(uri); + global_worker_playing = TRUE; + g_free(global_worker_uri); + global_worker_uri = g_strdup(uri); + worker->notify_play_handler(worker, worker->owner); +} + +void mafw_gst_renderer_worker_stop(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + global_worker_playing = FALSE; + ++global_worker_stop_called; + + g_free(global_worker_uri); + global_worker_uri = NULL; +} + +void mafw_gst_renderer_worker_pause(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + global_worker_playing = FALSE; + worker->notify_pause_handler(worker, worker->owner); +} + +void mafw_gst_renderer_worker_pause_at(MafwGstRendererWorker *worker, guint position) +{ + UNUSED(worker); + UNUSED(position); +} + +void mafw_gst_renderer_worker_resume(MafwGstRendererWorker *worker) +{ + UNUSED(worker); +} + +MafwGstRendererWorker *mafw_gst_renderer_worker_new(gpointer owner) +{ + MafwGstRendererWorker *newWorker = g_new0(MafwGstRendererWorker, 1); + newWorker->owner = owner; + newWorker->config = g_new0(configuration, 1); + return newWorker; +} + +void mafw_gst_renderer_worker_exit(MafwGstRendererWorker *worker) +{ + if( worker ) + { + _free_configuration(worker->config); + worker->config = NULL; + } +} + +gboolean mafw_gst_renderer_worker_set_playback_speed(MafwGstRendererWorker *worker, gfloat speed) +{ + UNUSED(worker); + + if(!global_worker_playing) + { + return FALSE; + } + + m_playback_speed = speed; + + GValue v; + memset(&v, 0, sizeof(GValue)); + g_value_init(&v, G_TYPE_FLOAT); + g_value_set_float(&v, m_playback_speed); + + worker->notify_property_handler(worker, worker->owner, WORKER_PROPERTY_PLAYBACK_SPEED, &v); + g_value_unset(&v); + + return TRUE; +} + +gfloat mafw_gst_renderer_worker_get_playback_speed(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_playback_speed; +} + +void mafw_gst_renderer_worker_set_force_aspect_ratio(MafwGstRendererWorker *worker, gboolean force) +{ + UNUSED(worker); + m_force_aspect_ratio = force; +} + +gboolean mafw_gst_renderer_worker_get_force_aspect_ratio(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + return m_force_aspect_ratio; +} + +void mafw_gst_renderer_worker_notify_media_destination(MafwGstRendererWorker *worker, + GSList *destination) +{ + UNUSED(worker); + g_slist_free(global_worker_destinations); + global_worker_destinations = g_slist_copy(destination); +} + +configuration* mafw_gst_renderer_worker_create_default_configuration(MafwGstRendererWorker *worker) +{ + configuration *config = g_malloc0(sizeof(configuration)); + config->asink = g_strdup("pulsesink"); + config->vsink = g_strdup("omapxvsink"); + config->flags = 67; + config->buffer_time = 300000; + config->latency_time = 100000; + + /* timers */ + config->milliseconds_to_pause_frame = 1000; + config->seconds_to_pause_to_ready = 3; + + /* dhmmixer */ + config->use_dhmmixer = TRUE; + + config->mobile_surround_music.state = 0; + config->mobile_surround_music.room = 2; + config->mobile_surround_music.color = 2; + config->mobile_surround_video.state = 0; + config->mobile_surround_video.room = 2; + config->mobile_surround_video.color = 2; + + return config; +} + +void mafw_gst_renderer_worker_set_configuration(MafwGstRendererWorker *worker, configuration *config) +{ + if( worker->config ) + { + _free_configuration(worker->config); + } + worker->config = config; + current_worker_conf = config; +} + +void set_dolby_music_property(MafwGstRendererWorker *worker, guint prop) +{ + worker->config->mobile_surround_music.state = prop; +} + +void set_dolby_music_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty) +{ + if (isRoomProperty) + { + worker->config->mobile_surround_music.room = prop; + } + else + { + worker->config->mobile_surround_music.color = prop; + } +} + +void set_dolby_video_property(MafwGstRendererWorker *worker, guint prop) +{ + worker->config->mobile_surround_video.state = prop; +} + +void set_dolby_video_sound_property(MafwGstRendererWorker *worker, gint prop, gboolean isRoomProperty) +{ + if (isRoomProperty) + { + worker->config->mobile_surround_video.room = prop; + } + else + { + worker->config->mobile_surround_video.color = prop; + } +} + +gint64 mafw_gst_renderer_worker_get_duration(MafwGstRendererWorker *worker) +{ + UNUSED(worker); + + return 0; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/media b/qmafw-gst-subtitles-renderer/unittests/media new file mode 120000 index 0000000..11718d8 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/media @@ -0,0 +1 @@ +ut_MafwGstRendererWorker/media/ \ No newline at end of file diff --git a/qmafw-gst-subtitles-renderer/unittests/run_all_tests.sh b/qmafw-gst-subtitles-renderer/unittests/run_all_tests.sh new file mode 100755 index 0000000..d953d4d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/run_all_tests.sh @@ -0,0 +1,35 @@ +#!/bin/sh +STATUS=0 + +qmake -project SUBDIRS+=`find . -type d -name ut_\*` -t subdirs -nopwd +qmake +if [ $SINGLE_PROCESS == "yes" ]; then + make -B +else + make -B -j3 +fi +if [ $? -ne 0 ]; then + exit 1 +fi + +files=`find . -maxdepth 2 -name 'ut_*' -type f -perm -u+x -print` + +echo '' > result.xml +echo '' >> result.xml +for file in $files; do + echo "Running test $file" + $file -lightxml -o tmp_result.xml; + + if [ $? -ne 0 ]; then + STATUS=2 + fi + + cat tmp_result.xml >>result.xml +done +echo '' >> result.xml +rm -f tmp_result.xml +sh run_valgrind.sh + +echo "Done" +exit $STATUS + diff --git a/qmafw-gst-subtitles-renderer/unittests/run_valgrind.sh b/qmafw-gst-subtitles-renderer/unittests/run_valgrind.sh new file mode 100755 index 0000000..41136e9 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/run_valgrind.sh @@ -0,0 +1,6 @@ +#!/bin/sh +export G_SLICE=always-malloc G_DEBUG=gc-friendly +#WAIT_TIMEOUT is for worker test +export WAIT_TIMEOUT=25000 +find . -maxdepth 2 -name 'ut_*' -type f -perm -u+x -print | xargs -t -i{} valgrind --leak-check=full --xml=yes --suppressions=test.suppressions --xml-file={}.vg.xml {} + diff --git a/qmafw-gst-subtitles-renderer/unittests/test.suppressions b/qmafw-gst-subtitles-renderer/unittests/test.suppressions new file mode 100644 index 0000000..aa76012 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/test.suppressions @@ -0,0 +1,2744 @@ +{ + + Memcheck:Leak + ... + fun:_ZN5Maemo14QmDisplayStateC1EP7QObject + ... +} +{ + + Memcheck:Leak + ... + fun:_ZN15ContextPropertyC1ERK7QStringP7QObject +} +{ + + Memcheck:Leak + fun:malloc + fun:dbus_malloc + ... + obj:/targets/*/usr/lib/libdbus-1.so.* + fun:dbus_message_new_signal + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libQtDBus.so.* + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString + obj:/targets/*/usr/lib/libQtDBus.so.* + fun:_ZN15QDBusConnection10sessionBusEv +} +{ + + Memcheck:Leak + fun:calloc + fun:dbus_malloc0 + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + fun:dbus_parse_address + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libQtDBus.so.* + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString + obj:/targets/*/usr/lib/libQtDBus.so.* +} +{ + + Memcheck:Leak + fun:realloc + fun:dbus_realloc + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + fun:dbus_message_new_signal + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* + obj:/targets/*/usr/lib/libdbus-1.so.* +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_slice_alloc + ... + fun:g_main_context_new + fun:_ZN27QEventDispatcherGlibPrivateC1EP13_GMainContext + fun:_ZN20QEventDispatcherGlibC1EP7QObject + obj:/targets/*/usr/lib/libQtCore.so.* + obj:/targets/*/usr/lib/libQtCore.so.* + fun:start_thread +} +{ + + Memcheck:Leak + ... + obj:/targets/*/usr/lib/libgstreamer-0.1* + fun:g_option_context_parse +} +{ + + Memcheck:Leak + ... + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_object_newv + ... + fun:gst_element_register + obj:/targets/*/usr/lib/libgstreamer-0.1* + obj:/targets/*/usr/lib/libgstreamer-0.1* +} +{ + + Memcheck:Leak + fun:*alloc + fun:g_malloc* + ... + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_object_newv + fun:gst_task_pool_new + obj:/targets/*/usr/lib/libgstreamer-0.1* +} +{ + + Memcheck:Leak + ... + fun:realloc + fun:g_realloc + obj:/targets/*/lib/libglib-2.* + ... + fun:gst_caps_new_simple +} + +{ + + Memcheck:Leak + ... + fun:realloc + fun:g_realloc + obj:/targets/*/lib/libglib-2.* + ... + fun:gst_caps_copy + ... + fun:g_object_newv + fun:g_object_new_valist +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:gst_pad_set_caps + ... + obj:/targets/*/usr/lib/libgstreamer-0.1* +} + +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + ... + fun:gst_pad_start_task + ... + obj:/targets/*/usr/lib/libgstbase-0.1* +} + + +{ + + Memcheck:Leak + ... + obj:/targets/*/usr/lib/libgstreamer-0.1* + fun:gst_registry_binary_read_cache + fun:gst_update_registry +} + +{ + + Memcheck:Leak + fun:memalign + ... + fun:g_object_new + fun:gst_pad_new_from_template + obj:/targets/*/usr/lib/libgstbase-0.1* +} + + +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.* + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_type_create_instance + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_object_newv + fun:gst_task_pool_new + obj:/targets/*/usr/lib/libgstreamer-0.1* + fun:g_type_class_ref +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + ... + fun:gst_buffer_new_and_alloc +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.* + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_type_create_instance + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_object_newv + ... + fun:gst_element_factory_create + fun:gst_element_factory_make +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + ... + fun:gst_caps_subtract + fun:gst_caps_is_subset + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.25.0 +} +{ + + Memcheck:Leak + fun:memalign + ... + fun:gst_element_change_state + ... +} + + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + fun:g_realloc + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_ptr_array_add + fun:g_main_context_check + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_main_context_pending + fun:_ZN20QEventDispatcherGlib16hasPendingEventsEv + fun:_ZN16QCoreApplication16hasPendingEventsEv +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_slice_alloc + fun:g_array_sized_new + fun:g_array_new + fun:g_static_private_set + fun:g_get_filename_charsets + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_thread_init_glib + fun:g_thread_init + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext +} +{ + + Memcheck:Leak + ... + fun:g_get_language_names + fun:g_thread_init + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate21createEventDispatcherEv + fun:_ZN16QCoreApplication4initEv + fun:_ZN16QCoreApplicationC2ER23QCoreApplicationPrivate +} +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + ... + fun:g_get_filename_charsets + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_thread_init_glib + fun:g_thread_init + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate21createEventDispatcherEv +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + ... + fun:g_get_filename_charsets + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_thread_init_glib + fun:g_thread_init + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate21createEventDispatcherEv + fun:_ZN16QCoreApplication4initEv +} +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_array_set_size + fun:g_static_private_set + fun:g_get_language_names + fun:g_thread_init + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate21createEventDispatcherEv + fun:_ZN16QCoreApplication4initEv +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_slice_alloc + ... + ... + fun:_ZN27QEventDispatcherGlibPrivateC2EP13_GMainContext + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate21createEventDispatcherEv +} + +{ + + Memcheck:Leak + fun:_Znwj + obj:/targets/*/usr/lib/libQtCore.so.* + obj:/targets/*/usr/lib/libQtCore.so.* + obj:/targets/*/usr/lib/libQtCore.so.* + fun:_ZN9QSettingsC1ENS_5ScopeERK7QStringS3_P7QObject + fun:_ZN19QApplicationPrivate18x11_apply_settingsEv + obj:/targets/*/usr/lib/libQtGui.so.* + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libfontconfig.so.* + obj:/targets/*/usr/lib/libfontconfig.so.* + ... + obj:/targets/*/usr/lib/libexpat.so.* + obj:/targets/*/usr/lib/libexpat.so.* + ... + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcConfigParseAndLoad +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + fun:g_realloc + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_ptr_array_add + fun:g_main_context_check + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_main_context_iteration + fun:_ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_ZN16QCoreApplication13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEEi + fun:_ZN5QTestL5qWaitEi +} + +{ + + Memcheck:Cond + fun:_dl_relocate_object + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:*/ld-2.5.so +} +{ + + Memcheck:Cond + fun:_dl_relocate_object + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:do_dlopen + fun:_dl_catch_error + fun:dlerror_run + fun:__libc_dlopen_mode + fun:__gconv_find_shlib + fun:find_module + fun:__gconv_lookup_cache + fun:__gconv_find_transform + + obj:*/ld-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + fun:__libc_dlopen_mode + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + fun:__libc_dlopen_mode + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libc-2.5.so + fun:__libc_dlopen_mode + obj:/targets/*/lib/libc-2.5.so + obj:/targets/*/lib/libc-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + obj:/targets/*/usr/lib/libQtGui.so.4.6.0 + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv + fun:_ZN8QLibrary4loadEv + obj:/targets/*/usr/lib/libQtGui.so.* + fun:_Z7qt_initP19QApplicationPrivateiP9_XDisplaymm + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm +} +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + obj:/targets/*/lib/ld-2.5.so + obj:/targets/*/lib/libdl-2.5.so + fun:dlopen + fun:_ZN15QLibraryPrivate8load_sysEv + fun:_ZN15QLibraryPrivate4loadEv +} +{ + + Memcheck:Cond + fun:_ZN11QMetaObject16checkConnectArgsEPKcS1_ +} +{ + + Memcheck:Addr1 + fun:_ZN11QMetaObject16checkConnectArgsEPKcS1_ +} +{ + + Memcheck:Cond + fun:strlen + fun:_dl_init_paths + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/targets/*/lib/ld-2.*.so +} +{ + + Memcheck:Cond + fun:_dl_relocate_object + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/targets/*/lib/ld-2.*.so +} +{ + + Memcheck:Leak + fun:realloc + obj:/targets/*/usr/lib/libX11.so.* + obj:/targets/*/usr/lib/libX11.so.* + obj:/targets/*/usr/lib/libX11.so.* + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + obj:/targets/*/usr/lib/libX11.so.* + fun:XrmGetStringDatabase + obj:/targets/*/usr/lib/libX11.so.* + fun:XGetDefault +} +{ + + Memcheck:Leak + ... + fun:g_type_init_with_debug_flags + fun:g_type_init + ... +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + ... + fun:g_type_register_static + fun:g_boxed_type_register_static + fun:g_value_get_type + ... +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + ... + fun:g_type_register_static + fun:g_param_type_register_static + fun:gst_param_spec_mini_object_get_type + ... +} + + +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2.* + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_type_create_instance + fun:gst_mini_object_new + fun:gst_buffer_new + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so + obj:/targets/*/usr/lib/libgstbase-0.10* + obj:/targets/*/usr/lib/libgstbase-0.10* + obj:/targets/*/usr/lib/libgstreamer-0* +} + + + + +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2* + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:gst_poll_new + fun:gst_poll_new_timer + obj:/targets/*/usr/lib/libgstreamer-0.1* + fun:g_type_create_instance + obj:/targets/*/usr/lib/libgobject-2* + fun:g_object_newv + fun:g_object_new_valist +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error +} +{ + + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/targets/*/lib/libglib-2* + fun:g_slice_alloc + fun:g_slice_alloc0 + obj:/targets/*/usr/lib/libgstreamer-0.1* + fun:g_value_init + fun:gst_value_init_and_copy + fun:gst_structure_copy + fun:gst_ffmpegcsp_transform_caps + obj:/targets/*/usr/lib/libgstbase-0.1* + obj:/targets/*/usr/lib/libgstbase-0.1* +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + ... + obj:/targets/*/lib/libc-2.10.* + obj:/targets/*/lib/libc-2.10.* +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + ... + obj:/targets/*/usr/lib/libQtCore.so.4.7.0 + obj:/targets/*/usr/lib/libQtCore.so.4.7.0 +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + ... + obj:/targets/*/lib/libc-2.10.* +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + ... + obj:/targets/*/lib/libdl-2.10.* +} + +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/libdl-2.10.* + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/libdl-2.10.* + fun:dlopen + obj:/targets/*/usr/lib/libQtCore.so.4.7.0 + obj:/targets/*/usr/lib/libQtCore.so.4.7.0 + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 + fun:_ZN15QDBusConnection9systemBusEv +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + ... + fun:gst_plugin_feature_load + fun:gst_element_factory_create +} + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + obj:/targets/*/lib/ld-2.10.* + ... + fun:gst_plugin_load_file +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_strdupv + fun:gst_type_find_register + obj:/targets/*/usr/lib/gstreamer-0.10/libgsttypefindfunctions.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load + fun:gst_type_find_factory_call_function + fun:gst_type_find_helper_get_range_ext +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + ... + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name +} + + +{ + + Memcheck:Addr4 + obj:/targets/*/lib/ld-2.10.* + fun:gst_type_find_factory_call_function +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_prepare + fun:snd_pcm_hw_params + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_dmix_open + fun:_snd_pcm_dmix_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_softvol_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_mmap_writei + fun:snd_pcm_writei + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_delay + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + fun:gst_ring_buffer_delay + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_dmix_open + fun:_snd_pcm_dmix_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_softvol_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_plug_open +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_timer_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_start + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_mmap_writei + fun:snd_pcm_writei + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_poll_descriptors_revents + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_wait + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + obj:/targets/*/lib/libglib-2.0.so.0.2400.1 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_timer_stop + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_drop + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_drop + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + fun:gst_ring_buffer_pause + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_mmap_commit + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_mmap_commit + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_mmap_writei +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_class_ref + fun:g_object_newv + fun:gst_element_factory_create + fun:gst_element_factory_make + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + fun:gst_element_change_state +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + ... + fun:gst_element_factory_create + fun:gst_element_factory_make +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + ... + fun:gst_element_factory_make + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.* + fun:gst_element_provide_clock +} + + + + +{ + + Memcheck:Param + ioctl(arg) + fun:ioctl + fun:snd_pcm_hwsync + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_avail_update + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_poll_descriptors_revents + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_wait + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.* +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:snd_config_hook_load +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 + fun:gst_plugin_load_file +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + fun:gst_element_set_state +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + fun:g_io_modules_scan_all_in_directory +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + fun:g_vfs_get_file_for_uri +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_empty_open +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_search_definition +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 + fun:gst_plugin_load_file +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_softvol_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_plug_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:_snd_pcm_asym_open +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + fun:gst_tag_reader_add_interface_to_type + obj:/targets/*/usr/lib/gstreamer-0.10/libgstdecodebin2.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstdecodebin2.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstgio.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstgio.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstgio.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_search_definition + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_object_newv + fun:g_object_new + fun:g_io_module_new + fun:g_io_modules_scan_all_in_directory + obj:/targets/*/usr/lib/libgio-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgio-2.0.so.0.2400.1 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstvolume.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstvolume.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_rate_open + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_pcm_hw_params + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + fun:gst_ring_buffer_acquire +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_register_static + fun:g_boxed_type_register_static + fun:gst_tag_list_get_type + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + fun:g_type_class_ref + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstvolume.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstvolume.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 + fun:gst_plugin_load_file +} + +{ + + Memcheck:Leak + fun:calloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + obj:/targets/*/usr/lib/libasound.so.2.0.0 + fun:snd_config_search_definition + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so +} + +{ + + Memcheck:Leak + fun:calloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Leak + fun:calloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + fun:snd_config_* +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + fun:snd_config_searcha_hooks +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/usr/lib/libasound.so.2.0.0 + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstalsa.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_register_static + fun:g_type_register_static_simple + fun:g_desktop_app_info_lookup_get_type + obj:/targets/*/usr/lib/libgio-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgio-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgio-2.0.so.0.2400.1 + fun:g_once_impl + fun:g_vfs_get_default +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + fun:g_type_register_static + fun:g_type_register_static_simple + fun:g_input_stream_get_type + obj:/targets/*/usr/lib/gstreamer-0.10/libgstgio.so + obj:/targets/*/usr/lib/libgstbase-0.10.so.0.26.0 + obj:/targets/*/usr/lib/libgstbase-0.10.so.0.26.0 + fun:gst_pad_activate_pull + fun:gst_pad_activate_pull +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + fun:gst_ring_buffer_open_device +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + obj:/targets/*/lib/ld-2.10.1.so + ... + fun:snd_config_update_r +} + +{ + + Memcheck:Param + semctl(IPC_SET, arg.buf) + fun:semctl + obj:/targets/*/usr/lib/libasound.so.2.0.0 + ... + obj:/targets/*/usr/lib/libasound.so.2.0.0 +} + + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + fun:gst_element_change_state +} + + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + ... + fun:g_type_class_ref + fun:g_object_new_valist + fun:g_object_new +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + ... + fun:g_type_class_ref + fun:g_object_new_valist + fun:g_object_new +} + + + + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + ... + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + ... + obj:/targets/*/lib/libdl-2.10.1.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + ... + obj:/targets/*/usr/lib/gio/modules/libgio-playready-vfs.so + fun:g_vfs_get_file_for_uri +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + obj:/targets/*/lib/ld-2.10.1.so + ... + fun:gst_plugin_load_file +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + ... + obj:/targets/*/lib/libdl-2.10.1.so + fun:dlopen + fun:g_module_open +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/*/lib/ld-2.10.1.so + ... + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:/targets/*/usr/lib/libgstreamer-0.10.so.0.26.0 + ... + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 +} + +{ + + Memcheck:Leak + fun:calloc + obj:/targets/*/lib/ld-2.10.1.so + ... + obj:/targets/*/lib/ld-2.10.1.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + obj:/targets/*/usr/lib/libgstbase-0.10.so.0.26.0 + fun:gst_pad_get_range +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + ... + obj:/targets/*/usr/lib/libgstaudio-0.10.so.0.21.0 + fun:g_type_create_instance +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + ... + fun:gst_element_factory_create +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + fun:g_object_new + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slice_alloc0 + ... + fun:g_object_new + fun:gst_element_factory_create +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + fun:gst_plugin_load_by_name +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstwavparse.so +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstdecodebin2.so +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + obj:/targets/*/usr/lib/libgobject-2.0.so.0.2400.1 + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstdecodebin2.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstdecodebin2.so +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/targets/*/usr/lib/libgobject-2.0.so.0.* + ... + fun:_ZN24ut_MafwGstRendererWorker19rendererArtTestCaseEv + fun:_ZN24ut_MafwGstRendererWorker11qt_metacallEN11QMetaObject4CallEiPPv + fun:_ZN11QMetaObject8metacallEP7QObjectNS_4CallEiPPv +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_module_open + fun:gst_plugin_load_file + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + fun:g_type_class_ref + fun:g_object_new_valist +} + + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + ... + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:dbus_malloc + ... + fun:dbus_pending_call_block +} + +{ + + Memcheck:Leak + fun:realloc + ... + fun:dbus_connection_send_with_reply +} + +{ + + Memcheck:Leak + fun:realloc + ... + fun:dbus_connection_send_with_reply +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN17ContextSubscriber16DBusNameListener14startListeningEb + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString + fun:_ZN17ContextSubscriber14PropertyHandle8instanceERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + fun:dbus_malloc + ... + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + fun:dbus_malloc + ... + obj:/targets/*/usr/lib/libdbus-1.so.3.5.1 +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN17ContextSubscriber16DBusNameListener14startListeningEb + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString + fun:_ZN17ContextSubscriber14PropertyHandle8instanceERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + fun:g_realloc + obj:/targets/maemo6-i486/usr/lib/libgobject-2.0.so.* + obj:/targets/maemo6-i486/usr/lib/libgobject-2.0.so.* + fun:g_type_register_static + fun:gconf_client_get_type + fun:gconf_client_get_default + obj:/targets/*/usr/lib/libgq-gconf.so.* + ... +} + +{ + + Memcheck:Leak + fun:calloc + fun:dbus_malloc0 + ... + fun:_ZN9GConfItem12update_valueEb + fun:_ZN9GConfItemC1ERK7QStringP7QObject +} + +{ + + Memcheck:Leak + fun:realloc + fun:dbus_realloc + ... + fun:dbus_message_append_args +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN15QDBusConnection10sessionBusEv + fun:_ZN17ContextSubscriber16DBusNameListener14startListeningEb +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + ... + obj:/targets/maemo6-i486/usr/lib/libdbus-1.so.3.* +} + +{ + + Memcheck:Leak + fun:_Znwj + obj:/targets/*/usr/lib/libQtDBus.so.4.* + ... + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString + fun:_ZN17ContextSubscriber14PropertyHandle8instanceERK7QString +} + +{ + + Memcheck:Leak + fun:_Znwj + fun:_ZN14QObjectPrivate13addConnectionEiPNS_10ConnectionE + ... + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:_Znwj + ... + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN15QDBusConnection10sessionBusEv + fun:_ZN17ContextSubscriber16DBusNameListener14startListeningEb +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + ... + fun:_ZN11QMetaObject8metacallEP7QObjectNS_4CallEiPPv +} + +{ + + Memcheck:Leak + fun:realloc + fun:dbus_realloc + ... + obj:/targets/*/usr/lib/libdbus-1.so.3.5.1 +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + ... + fun:dbus_connection_set_watch_functions +} + +{ + + Memcheck:Leak + fun:_Znwj + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 +} + +{ + + Memcheck:Leak + fun:realloc + fun:dbus_realloc + ... + obj:/targets/*/usr/lib/libdbus-1.so.3.5.1 +} + +{ + + Memcheck:Leak + fun:_Znwj + ... + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString + fun:_ZN17ContextSubscriber14PropertyHandle8instanceERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + fun:_ZN9QListData11detach_growEPii + ... + fun:_ZN16QCoreApplication6notifyEP7QObjectP6QEvent + fun:_ZN16QCoreApplication14notifyInternalEP7QObjectP6QEvent +} + +{ + + Memcheck:Leak + fun:calloc + fun:dbus_malloc0 + ... + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString + obj:/targets/*/usr/lib/libQtDBus.so.4.* +} + +{ + + Memcheck:Leak + fun:realloc + fun:_Z8qReallocPvj + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.* +} + +{ + + Memcheck:Leak + fun:realloc + fun:_Z8qReallocPvj + ... + fun:_ZN22QDBusAbstractInterfaceC2ERK7QStringS2_PKcRK15QDBusConnectionP7QObject +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + ... + obj:/targets/*/lib/ld-2.*.so +} + +{ + + Memcheck:Leak + fun:malloc + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.* +} + +{ + + Memcheck:Leak + fun:_Znaj + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.* +} + +{ + + Memcheck:Leak + fun:_Znaj + ... + fun:_ZN17ContextSubscriber14PropertyHandleC1ERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN15QDBusConnection10sessionBusEv +} + +{ + + Memcheck:Leak + fun:malloc + fun:_Z7qMallocj + ... + fun:_ZN15QDBusConnection12connectToBusENS_7BusTypeERK7QString +} + +{ + + Memcheck:Leak + fun:malloc + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.* +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN17ContextSubscriber16DBusNameListener14startListeningEb +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + ... + fun:dbus_connection_send_with_reply_and_block + fun:dbus_bus_register +} + +{ + + Memcheck:Leak + fun:calloc + fun:dbus_malloc0 + ... + obj:/targets/*/usr/lib/libQtDBus.so.4.7.0 +} + +{ + + Memcheck:Leak + fun:malloc + obj:/targets/maemo6-i486/usr/lib/libfontconfig.so.1.* + ... + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad +} + +{ + + Memcheck:Leak + fun:malloc + ... + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} + +{ + + Memcheck:Leak + fun:calloc + ... + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} + +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.*.so + ... + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci + fun:main +} + +{ + + Memcheck:Cond + obj:/targets/*/lib/ld-2.10.1.so + ... + fun:_ZN19QApplicationPrivate9constructEP9_XDisplaymm + fun:_ZN12QApplicationC1ERiPPci +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + ... + fun:g_type_register_static + ... + fun:_ZN9GConfItemC1ERK7QStringP7QObject + fun:_ZN20MafwGstRendererDolby10initializeEv +} + +{ + + Memcheck:Leak + fun:malloc + fun:realloc + fun:g_realloc + fun:g_realloc_n + ... + fun:g_type_register_static + ... + fun:g_type_class_ref + fun:g_type_class_ref +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2*.so.* + obj:/targets/*/usr/lib/libgobject-2*.so.* + obj:/targets/*/usr/lib/libgobject-2*.so.* + obj:/targets/*/usr/lib/libgobject-2*.so.* + obj:/targets/*/usr/lib/libgobject-2*.so.* + fun:g_type_add_interface_static + ... +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_param_spec_flags + obj:/targets/*/usr/lib/libgio-2.*.so.* + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_io_extension_ref_class + obj:/targets/*/usr/lib/libgio-2.*.so.* + fun:g_once_impl + obj:/targets/*/usr/lib/libgio-2.*.so.* +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + ... + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_once_impl +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.* + ... + fun:g_type_register_static + fun:g_type_register_static_simple + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.0.so.* + fun:g_type_class_ref + fun:g_object_newv + fun:g_object_new + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_vfs_get_file_for_path + fun:g_file_new_for_path + obj:/targets/*/usr/lib/libgio-2.0.so.* +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + fun:g_type_add_interface_static + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_vfs_get_file_for_path +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + fun:g_type_register_static + fun:g_type_register_static_simple + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_vfs_get_file_for_path + fun:g_file_new_for_path +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_type_create_instance + fun:g_param_spec_internal + fun:g_param_spec_int + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_io_extension_ref_class +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.0.so.* + obj:/targets/*/usr/lib/libgobject-2.0.so.* + fun:g_type_register_static + fun:g_type_register_static_simple + fun:g_file_get_type + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + obj:/targets/*/usr/lib/libgio-2.0.so.* + fun:g_vfs_get_file_for_path +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 + obj:/targets/*/usr/lib/libgthread-2.0.so.* + fun:g_thread_create_full + obj:/targets/*/lib/libglib-2.0.so.* + fun:g_thread_pool_push + obj:/targets/*/usr/lib/libgstreamer-0.10.so.* + fun:gst_task_pool_push + fun:gst_task_set_state + fun:gst_pad_start_task + obj:/targets/*/usr/lib/libgstbase-0.10.so.* +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + fun:g_type_register_static_simple + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so + obj:/targets/*/usr/lib/gstreamer-0.10/libgstplaybin.so +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + fun:g_type_register_static_simple + fun:gst_data_queue_get_type + fun:gst_data_queue_new_full + obj:/targets/*/usr/lib/gstreamer-0.10/libgstcoreelements.so + obj:/targets/*/usr/lib/libgstreamer-0.10.so.* + fun:gst_element_get_request_pad +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + fun:gst_x_overlay_get_type + fun:mafw_gst_renderer_worker_apply_xid + fun:_sync_bus_handler + fun:gst_bus_post + fun:_ZN24ut_MafwGstRendererWorker18pauseFrameTestCaseEv + fun:_ZN24ut_MafwGstRendererWorker11qt_metacallEN11QMetaObject4CallEiPPv +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + fun:g_enum_register_static + obj:/targets/*/usr/lib/libgsttag-0.10.so.* + fun:g_once_impl + fun:gst_tag_image_type_get_type + fun:_ZN24ut_MafwGstRendererWorker19rendererArtTestCaseEv + fun:_ZN24ut_MafwGstRendererWorker11qt_metacallEN11QMetaObject4CallEiPPv +} + +{ + + Memcheck:Addr4 + obj:/targets/*/usr/lib/libqttracker.so.1~6.12.8 + ... + obj:/targets/*/usr/lib/libqttracker.so.1~6.12.8 + obj:/targets/*/usr/lib/libqttracker.so.1~6.12.8 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_add_interface_static + fun:g_type_module_get_type + fun:g_io_module_get_type + fun:g_io_module_new + fun:g_io_modules_scan_all_in_directory +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_object_newv + fun:g_object_new + fun:g_io_module_new + fun:g_io_modules_scan_all_in_directory + obj:/targets/*/usr/lib/libgio-2.* + obj:/targets/*/usr/lib/libgio-2.* +} + +{ + + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_realloc_n + obj:/targets/*/usr/lib/libgobject-2.* + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_register_static + fun:g_type_register_static_simple + obj:/targets/*/usr/lib/libgio-2.* + obj:/targets/*/usr/lib/libgio-2.* + obj:/targets/*/usr/lib/libgio-2.* + fun:g_vfs_get_file_for_path + obj:/targets/*/usr/lib/gio/modules/libprdrm-gio-vfs0.so +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_memdup + obj:/targets/*/usr/lib/libgobject-2.* + fun:g_type_class_ref + fun:g_object_newv + fun:g_object_new + obj:/targets/*/usr/lib/libgio-2.* + obj:/targets/*/usr/lib/libgio-2.* + fun:g_vfs_get_file_for_path + obj:/targets/*/usr/lib/gio/modules/libprdrm-gio-vfs0.so + fun:g_vfs_get_file_for_path +} + + + + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.cpp new file mode 100644 index 0000000..9bf94a4 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.cpp @@ -0,0 +1,209 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include + +#include +#include +#include + +#include "MafwGstScreenshot.h" +#include "ut_GstScreenshot.h" + +static gchar *global_failing_gst_element = NULL; + +/* START OF STUB DEFINITIONS */ +GstElement *gst_element_factory_make(const gchar *factoryname, const gchar *name) +{ + + GstElementFactory *factory; + + qDebug() << __PRETTY_FUNCTION__ << factoryname; + + if (global_failing_gst_element != NULL && + g_str_equal(factoryname, global_failing_gst_element)) + { + qDebug() << "SIMULATED FAIL OF gst_element_factory_make()"; + return NULL; + } + else + { + factory = gst_element_factory_find(factoryname); + return gst_element_factory_create(factory, name); + } + +} +/* END OF STUB DEFINITIONS */ + +void ut_GstScreenshot::testFailures() +{ + gint width = 1024; + gint height = 1024; + gint size = width * height + width * height / 2; + GstBuffer *buf = gst_buffer_new_and_alloc(size); + QCOMPARE(GST_OBJECT_REFCOUNT_VALUE(buf), 1); + + memset(GST_BUFFER_DATA(buf), 0, size); + + /* no caps set, returns false */ + QVERIFY(m_screenshot->savePauseFrame(buf, + "/dev/null") == FALSE); + + buf = gst_buffer_new_and_alloc(size); + memset(GST_BUFFER_DATA(buf), 0, size); + + GstCaps *caps; + caps = gst_caps_new_simple("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I','4','2','0'), + "framerate", GST_TYPE_FRACTION, 25, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + gst_buffer_set_caps(buf, caps); + + /* fakesrc creation fails, returns false */ + global_failing_gst_element = g_strdup("fakesrc"); + QVERIFY(m_screenshot->savePauseFrame(buf, + "/dev/null") == FALSE); + + gst_caps_unref(caps); + + /* TODO: Gst pipeline errors are difficult to test... */ +} + +void ut_GstScreenshot::testConvert() +{ + gint width = 1024; + gint height = 512; + gint size = width * height + width * height / 2; + GstBuffer *buf = gst_buffer_new_and_alloc(size); + memset(GST_BUFFER_DATA(buf), 0, size); + + /* set caps, returns true */ + GstCaps *caps; + caps = gst_caps_new_simple("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I','4','2','0'), + "framerate", GST_TYPE_FRACTION, 25, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + gst_buffer_set_caps(buf, caps); + QVERIFY(m_screenshot->savePauseFrame(buf, + "/dev/null") == TRUE); + + QTest::qWait(500); + QVERIFY(m_gotScreenshotSignal == TRUE); + + gst_caps_unref(caps); +} + + +void ut_GstScreenshot::testCancel() +{ + gint width = 1024; + gint height = 512; + gint size = width * height + width * height / 2; + GstBuffer *buf = gst_buffer_new_and_alloc(size); + memset(GST_BUFFER_DATA(buf), 0, size); + + QFETCH(uint, timeout); + + /* set caps, returns true */ + GstCaps *caps; + caps = gst_caps_new_simple("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I','4','2','0'), + "framerate", GST_TYPE_FRACTION, 25, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + gst_buffer_set_caps(buf, caps); + + QVERIFY(m_screenshot->savePauseFrame(buf, + "/dev/null") == TRUE); + QTest::qWait(timeout); + if (m_gotScreenshotSignal == false ) + { + m_screenshot->cancelPauseFrame(); + QVERIFY(m_gotCancelSignal == TRUE); + } +} + +void ut_GstScreenshot::testCancel_data() +{ + QTest::addColumn("timeout"); + QTest::newRow("0 ms") << (uint)0; + QTest::newRow("1 ms") << (uint)1; + QTest::newRow("5 ms") << (uint)5; + QTest::newRow("10 ms") << (uint)10; + QTest::newRow("20 ms") << (uint)20; + QTest::newRow("35 ms") << (uint)35; + QTest::newRow("50 ms") << (uint)50; + QTest::newRow("100 ms") << (uint)100; +} + +void ut_GstScreenshot::slotScreenshot(char *location, GError *error) +{ + qDebug() << __PRETTY_FUNCTION__; + Q_UNUSED(location); + Q_UNUSED(error); + m_gotScreenshotSignal = TRUE; +} + +void ut_GstScreenshot::slotCancelScreenshot() +{ + qDebug() << __PRETTY_FUNCTION__; + + m_gotCancelSignal = TRUE; +} + +void ut_GstScreenshot::init() +{ + + qDebug() << __PRETTY_FUNCTION__; + + gst_init(0, 0); + + m_gotScreenshotSignal = FALSE; + m_gotCancelSignal = FALSE; + + m_screenshot = new MafwGstScreenshot(this); + connect(m_screenshot, SIGNAL(screenshotTaken(char*,GError*)), this, SLOT(slotScreenshot(char*,GError*))); + connect(m_screenshot, SIGNAL(screenshotCancelled()), this, SLOT(slotCancelScreenshot())); + + global_failing_gst_element = NULL; + +} + +void ut_GstScreenshot::cleanup() +{ + + qDebug() << __PRETTY_FUNCTION__; + g_free(global_failing_gst_element); + + while(QCoreApplication::hasPendingEvents()) + { + QCoreApplication::sendPostedEvents(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + } + delete m_screenshot; +} + +QTEST_MAIN(ut_GstScreenshot) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.h b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.h new file mode 100644 index 0000000..b9fca86 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.h @@ -0,0 +1,52 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_GSTSCREENSHOT_H_ +#define UT_GSTSCREENSHOT_H_ + +#include +#include + +#include "MafwGstScreenshot.h" + +class MafwGstScreenshot; + +class ut_GstScreenshot: public QObject +{ + Q_OBJECT + +private slots: // tests, don't touch the test order + + void testFailures(); + void testConvert(); + void testCancel(); + void testCancel_data(); + + void init(); + void cleanup(); + +protected slots: + void slotScreenshot(char *location, GError *error); + void slotCancelScreenshot(); + +private: //data + MafwGstScreenshot *m_screenshot; + bool m_gotCancelSignal; + bool m_gotScreenshotSignal; +}; + +#endif diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.pro b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.pro new file mode 100644 index 0000000..3afb79c --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_GstScreenshot/ut_GstScreenshot.pro @@ -0,0 +1,29 @@ +TEMPLATE = app + +CONFIG -= gui +CONFIG += console + +isEmpty(PREFIX) { + PREFIX=/usr +} + +CONFIG += qt link_pkgconfig release +CONFIG += qtestlib +PKGCONFIG += glib-2.0 gobject-2.0 gstreamer-0.10 gstreamer-plugins-base-0.10 + +LIBS += -lgcov + +DEPENDPATH += . ../../inc ../../src +INCLUDEPATH += . ../../inc + +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g + +QMAKE_CLEAN += *.gcda *.gcno *.gcov ut_GstScreenshot *.vg.xml vgcore.* + +HEADERS += ut_GstScreenshot.h \ + MafwGstScreenshot.h + +SOURCES += ut_GstScreenshot.cpp \ + MafwGstScreenshot.cpp + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ContextFWStub.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ContextFWStub.cpp new file mode 100644 index 0000000..61e9da0 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ContextFWStub.cpp @@ -0,0 +1,127 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include +#include +#include +#include + +ContextProperty *global_video_route_property = 0; +ContextProperty *global_audio_route_property = 0; +QString global_audio_route(""); +QString global_video_route(""); +ContextPropertyInfo propertyInfo("key"); + +ContextProperty::ContextProperty(const QString& key, QObject*) +{ + if (key == "/com/nokia/policy/video_route" && global_video_route_property == 0) + { + global_video_route_property = this; + } + else if (key == "/com/nokia/policy/audio_route" && global_audio_route_property == 0) + { + global_audio_route_property = this; + } +} + +ContextProperty::~ContextProperty() +{ + qDebug() << __PRETTY_FUNCTION__; + if (this == global_video_route_property) + { + global_video_route_property = 0; + } + else if (this == global_audio_route_property) + { + global_audio_route_property = 0; + } +} + +// this non-const function is used to trigger the signal emissions +void ContextProperty::ignoreCommander() +{ + Q_EMIT global_video_route_property->valueChanged(); + Q_EMIT global_audio_route_property->valueChanged(); +} + +QString ContextProperty::key() const +{ + if (this == global_video_route_property) + { + return "/com/nokia/policy/video_route"; + } + else if (this == global_audio_route_property) + { + return "/com/nokia/policy/audio_route"; + } + else + { + return ""; + } +} + +QVariant ContextProperty::value() const +{ + if (this == global_video_route_property) + { + return QVariant(global_video_route); + } + else if (this == global_audio_route_property) + { + return QVariant(global_audio_route); + } + else + { + return QVariant(); + } +} + +const ContextPropertyInfo* ContextProperty::info() const +{ + return &propertyInfo; +} + +ContextPropertyInfo::ContextPropertyInfo(const QString &key, QObject *parent) +{ + Q_UNUSED(key); + Q_UNUSED(parent); +} + +const QList ContextPropertyInfo::providers() const +{ + QList list; + list << ContextProviderInfo("contextkit-dbus", "system:com.nokia.policy.pcfd"); + return list; +} + +// d-bus stub +bool QDBusError::isValid() const +{ + return false; +} + +QDBusMessage::MessageType QDBusMessage::type() const +{ + if( this->member()=="GetConnectionUnixProcessID" ) + { + return QDBusMessage::ReplyMessage; + } + + return QDBusMessage::SignalMessage; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwGstRendererDolbyStub.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwGstRendererDolbyStub.cpp new file mode 100644 index 0000000..8262b95 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwGstRendererDolbyStub.cpp @@ -0,0 +1,122 @@ +#include "MafwGstRendererDolby.h" + +#include + +const int DEFAULT_COLOR = 2; +const int DEFAULT_ROOM_SIZE = 2; +const int MAX_VALUE = 4; + +enum MafwDolbyStates +{ + MafwDolbyOff, + MafwDolbyOn, + MafwDolbyAuto +}; + +MafwGstRendererDolby::MafwGstRendererDolby( QObject* parent ): + QObject(parent), + m_dolbyConfMusic(0), + m_dolbyConfMusicRoom(0), + m_dolbyConfMusicColor(0), + m_dolbyConfVideo(0), + m_dolbyConfVideoRoom(0), + m_dolbyConfVideoColor(0) +{ + qDebug() << Q_FUNC_INFO; + m_currentMusicDolbyState = MafwDolbyOff; + m_currentMusicDolbyRoom = DEFAULT_ROOM_SIZE; + m_currentMusicDolbyColor = DEFAULT_COLOR; + m_currentVideoDolbyState = MafwDolbyOff; + m_currentVideoDolbyRoom = DEFAULT_ROOM_SIZE; + m_currentVideoDolbyColor = DEFAULT_COLOR; +} + +void MafwGstRendererDolby::initialize() +{ + qDebug() << Q_FUNC_INFO; +} + +MafwGstRendererDolby::~MafwGstRendererDolby() +{ + qDebug() << Q_FUNC_INFO; +} + +bool MafwGstRendererDolby::setMusicDolbyState (uint value) +{ +} + +bool MafwGstRendererDolby::setMusicDolbyRoom (int value) +{ + qDebug() << Q_FUNC_INFO; + return true; +} + +bool MafwGstRendererDolby::setMusicDolbyColor (int value) +{ + qDebug() << Q_FUNC_INFO; + return true; +} + +bool MafwGstRendererDolby::setVideoDolbyState (uint value) +{ + qDebug() << Q_FUNC_INFO; + return true; +} + +bool MafwGstRendererDolby::setVideoDolbyRoom (int value) +{ + qDebug() << Q_FUNC_INFO; + return true; +} + +bool MafwGstRendererDolby::setVideoDolbyColor (int value) +{ + qDebug() << Q_FUNC_INFO; + return true; +} + +void MafwGstRendererDolby::valueMusicChanged() +{ + qDebug() << Q_FUNC_INFO; +} + +void MafwGstRendererDolby::valueVideoChanged() +{ + qDebug() << Q_FUNC_INFO; +} + +uint MafwGstRendererDolby::getMusicDolbyState () +{ + qDebug() << Q_FUNC_INFO; + return m_currentMusicDolbyState; +} + +int MafwGstRendererDolby::getMusicDolbyRoom () +{ + qDebug() << Q_FUNC_INFO; + return m_currentMusicDolbyRoom; +} + +int MafwGstRendererDolby::getMusicDolbyColor () +{ + qDebug() << Q_FUNC_INFO; + return m_currentMusicDolbyColor; +} + +uint MafwGstRendererDolby::getVideoDolbyState () +{ + qDebug() << Q_FUNC_INFO; + return m_currentVideoDolbyState; +} + +int MafwGstRendererDolby::getVideoDolbyRoom () +{ + qDebug() << Q_FUNC_INFO; + return m_currentVideoDolbyRoom; +} + +int MafwGstRendererDolby::getVideoDolbyColor () +{ + qDebug() << Q_FUNC_INFO; + return m_currentVideoDolbyColor; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwMmcMonitorStub.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwMmcMonitorStub.cpp new file mode 100644 index 0000000..f34050a --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/MafwMmcMonitorStub.cpp @@ -0,0 +1,45 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "MafwMmcMonitor.h" +#include + +bool stubMmcMounted = true; +MafwMmcMonitor* stubMmcMonitor; + +const QString MafwMmcMonitor::MMC_URI_PREFIX="file:///home/user/MyDocs"; + +MafwMmcMonitor::MafwMmcMonitor(QObject* parent) : QObject(parent), m_mounted(false) +{ + stubMmcMonitor = this; +} + +MafwMmcMonitor::~MafwMmcMonitor() +{ + stubMmcMonitor = 0; +} + +bool MafwMmcMonitor::isMounted() +{ + return stubMmcMounted; +} + +void MafwMmcMonitor::preUnmountEvent(const QString &/*state*/) +{ + Q_EMIT stubMmcMonitor->preUnmount(); +} + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QSettingsStub.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QSettingsStub.cpp new file mode 100644 index 0000000..a8e4d06 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QSettingsStub.cpp @@ -0,0 +1,32 @@ +#include + +QMap globalSettingsMap; + +//QSettings stub +QSettings::QSettings( const QString&, const QString&, QObject* ){} +//Hope we will never need below ctor stub, because it is used somehow by unit test framework. +//QSettings::QSettings(QSettings::Scope, const QString&, const QString&, QObject*){} +QSettings::QSettings(QSettings::Format, QSettings::Scope, const QString&, const QString&, QObject*){} +QSettings::QSettings(const QString&, QSettings::Format, QObject*){} +QSettings::QSettings(QObject*){} +QSettings::~QSettings(){} + +QVariant QSettings::value(const QString& key, const QVariant& defaultValue) const +{ + return globalSettingsMap.value(key, defaultValue); +} + +bool QSettings::contains(const QString &key) const +{ + return true; +} + +void QSettings::beginGroup(const QString &prefix) +{ + +} + +void QSettings::endGroup() +{ + +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QmSystemStub.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QmSystemStub.cpp new file mode 100644 index 0000000..3b04019 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/QmSystemStub.cpp @@ -0,0 +1,39 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include + +int global_qmsystemstub_setBlankingPauseCalled; + +namespace MeeGo { + QmDisplayState::QmDisplayState(QObject* parent) : QObject(parent) + { + } + + QmDisplayState::~QmDisplayState(){} + + bool QmDisplayState::setBlankingPause(void) + { + global_qmsystemstub_setBlankingPauseCalled++; + return true; + } + bool QmDisplayState::cancelBlankingPause(void) + { + return true; + } +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.cpp new file mode 100644 index 0000000..dbbded0 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.cpp @@ -0,0 +1,1662 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "Ut_MafwGstRenderer.h" + +#include +#include +#include +#include +#include +#include "MafwGstRendererVolume.h" +#include "MafwMetadata.h" +#include "MafwGstRendererPlaylistFileUtility.h" +#include "MafwStubHelper.h" +#include "MafwRendererPolicyStub.h" +#include "mafw-gst-renderer-worker.h" +#include "MafwMediaInfo.h" + +#include "QNetworkStubs.h" +#include + +#define private public // access private members from unit tests +#include "MafwGstRenderer.h" +#include "MafwMmcMonitor.h" + +extern void setStubHelper(MafwStubHelper* stubHlp); +extern void setMafwRendererPolicy(MafwRendererPolicy *policy ); + +extern GError* global_error; +extern gint global_position; +extern int global_qmsystemstub_setBlankingPauseCalled; +extern ContextProperty *global_video_route_property; +extern ContextProperty *global_audio_route_property; +extern QString global_audio_route; +extern QString global_video_route; +extern gboolean global_worker_playing; +extern const gchar* global_worker_uri; +extern int global_worker_stop_called; +extern int global_worker_seek_request; +extern guint global_ready_timeout; +extern GSList *global_worker_destinations; +extern NetworkStubHelper networkStub; +extern configuration *current_worker_conf; +extern QMap globalSettingsMap; + +extern bool stubMmcMounted; +extern MafwMmcMonitor* stubMmcMonitor; +extern QStringList stubPlaylistFileUtilityUris; + +void Ut_MafwGstRenderer::initTestCase() +{ + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + g_type_init(); + + m_stubHelper = new MafwStubHelper; + setStubHelper(m_stubHelper); + m_rendererPolicy = new MafwRendererPolicyStub(); + setMafwRendererPolicy(m_rendererPolicy); + + m_metadataCount = 0; + + /* Section to test initialization */ + MafwGstRenderer *renderer = new MafwGstRenderer("renderer_uuid", "renderer-plugin", "rendere_name"); + //Basic renderer initialize fails + m_stubHelper->expect("initialize", false); + QVERIFY(renderer->initialize(0) == false); + // Let setDefaultRendererPolicy fail now to get more complete unittesting. + // Failure in loading policy is not considered fatal at this point. + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("setDefaultRendererPolicy", false); + QVERIFY(renderer->initialize(0) == true); + delete renderer; + /* Section End */ + + m_renderer = new MafwGstRenderer("renderer_uuid", "renderer-plugin", "rendere_name"); + + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("setDefaultRendererPolicy", true); + QVERIFY(m_renderer->initialize(0) == true); + QVERIFY(m_renderer->m_worker); + + //redundant initialize call + QVERIFY(m_renderer->initialize(0) == true); + + global_qmsystemstub_setBlankingPauseCalled = 0; +} + +void Ut_MafwGstRenderer::testPlayURI() +{ + //rendererPlaying signal not emitted there + MafwMediaInfo content(""); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); +} + +/** + * PlaylistFileUtilityStub gives always two uris to play + */ +void Ut_MafwGstRenderer::testPlayPlaylistFile() +{ + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + + MafwMediaInfo mediaInfo; + QMap testUri; + QMap testMimeType; + testUri.insert(MAFW_METADATA_KEY_URI, "file:///var/tmp/tunein-station.pls"); + testMimeType.insert(MAFW_METADATA_KEY_MIME, "audio/x-scpls"); + + mediaInfo.setMetaData(testUri); + mediaInfo.setMetaData(testMimeType); + + m_renderer->doPlay(mediaInfo); + QTest::qWait(10); + QCOMPARE(playSpy.count(), 1); + QList arguments = playSpy.takeFirst(); + QCOMPARE(arguments.count(), 1); + QCOMPARE(arguments.at(0).toInt(), 1); //MafwRendererPlayingUri::CurrentUri + +//Test that next uri is started to play if playing first stops because of an error + GError* error = g_error_new_literal(1, 2, "Playlist uri playback error"); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, error); + QTest::qWait(10); + QCOMPARE(playSpy.count(), 0); + QVERIFY(global_worker_playing); + QCOMPARE(QString(global_worker_uri), QString("testUri2")); + +//Test that renderer does not go playing state anymore when all uris is used + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, error); + QTest::qWait(10); + QCOMPARE(playSpy.count(), 0); + + g_error_free(error); +} + +void Ut_MafwGstRenderer::testStop() +{ + //@TODO doStop needs to be tested for all the states the renderer can be in. + QSignalSpy spy(m_renderer, SIGNAL(rendererStopped())); + m_renderer->doStop(); + QCOMPARE(spy.count(), 1); + //Not clear that should signal be emitted when calling doStop at stopped state + m_renderer->doStop(); + m_renderer->doStop(); +} + +void Ut_MafwGstRenderer::testPause() +{ + m_renderer->doPause(); +} + +void Ut_MafwGstRenderer::testResume() +{ + m_renderer->doResume(); +} + +void Ut_MafwGstRenderer::testSeek() +{ + QSignalSpy errorSpy(m_renderer, SIGNAL(rendererError(MafwError))); + global_error = g_error_new_literal(1, 2, "The seek error"); + m_renderer->doSeek(1, MafwRenderer::SeekAbsolute); + QCOMPARE(errorSpy.count(), 1); + + global_error = 0; + m_renderer->doSeek(100, MafwRenderer::SeekRelative); +} + +void Ut_MafwGstRenderer::testDefaultConfiguration() +{ + QVERIFY2(sizeof(configuration) == 64, "You've (or somebody else) most likely changed the configuration struct! Update the unittests also!"); + + MafwGstRenderer *rnd = new MafwGstRenderer("tesssssst", "conf-test-plug", "conf-test-rnd"); + QSettings settings("test-set", QSettings::NativeFormat); + + m_stubHelper->expect("initialize", true); + + rnd->initialize(&settings); + + QCOMPARE(current_worker_conf->asink, "pulsesink"); + QCOMPARE(current_worker_conf->vsink, "omapxvsink"); + QCOMPARE(current_worker_conf->buffer_time, 300000LL); + QCOMPARE(current_worker_conf->latency_time, 100000LL); + QCOMPARE(current_worker_conf->flags, 67); + + QCOMPARE(current_worker_conf->mobile_surround_music.state, 0U); + QCOMPARE(current_worker_conf->mobile_surround_music.color, 2); + QCOMPARE(current_worker_conf->mobile_surround_music.room, 2); + QCOMPARE(current_worker_conf->mobile_surround_video.state, 0U); + QCOMPARE(current_worker_conf->mobile_surround_video.color, 2); + QCOMPARE(current_worker_conf->mobile_surround_video.room, 2); + + QCOMPARE(current_worker_conf->milliseconds_to_pause_frame, 1000U); + QCOMPARE(current_worker_conf->seconds_to_pause_to_ready, 3U); + QCOMPARE(current_worker_conf->use_dhmmixer, 1); + + delete rnd; + +} + +void Ut_MafwGstRenderer::testConfiguration() +{ + globalSettingsMap.clear(); + globalSettingsMap.insert("audio-sink", "no-audio"); + globalSettingsMap.insert("video-sink", "no-video"); + globalSettingsMap.insert("flags", 67); + globalSettingsMap.insert("use_dhmmixer", false); + globalSettingsMap.insert("buffer-time", 313); + globalSettingsMap.insert("latency-time", 007); + + globalSettingsMap.insert("pause-frame", 13000); + globalSettingsMap.insert("pause-to-ready", 7); + + globalSettingsMap.insert("dhm-music-surround", 6); + globalSettingsMap.insert("dhm-music-color", 5); + globalSettingsMap.insert("dhm-music-room-size", 4); + globalSettingsMap.insert("dhm-video-surround", 3); + globalSettingsMap.insert("dhm-video-color", 12); + globalSettingsMap.insert("dhm-video-room-size", 1); + + MafwGstRenderer *rnd = new MafwGstRenderer("tesst", "conf-test-plug", "conf-test-rnd"); + QSettings settings("test-set", QSettings::NativeFormat); + m_stubHelper->expect("initialize", true); + rnd->initialize(&settings); + + QCOMPARE(current_worker_conf->asink, "no-audio"); + QCOMPARE(current_worker_conf->vsink, "no-video"); + QCOMPARE(current_worker_conf->buffer_time, 313LL); + QCOMPARE(current_worker_conf->latency_time, 007LL); + QCOMPARE(current_worker_conf->flags, 67); + + QCOMPARE(current_worker_conf->mobile_surround_music.state, 6U); + QCOMPARE(current_worker_conf->mobile_surround_music.color, 5); + QCOMPARE(current_worker_conf->mobile_surround_music.room, 4); + + // for some reason video values are overwritten via gconf in unittests + QCOMPARE(current_worker_conf->mobile_surround_video.state, 3U); + QCOMPARE(current_worker_conf->mobile_surround_video.color, 12); + QCOMPARE(current_worker_conf->mobile_surround_video.room, 1); + + QCOMPARE(current_worker_conf->milliseconds_to_pause_frame, 13000U); + QCOMPARE(current_worker_conf->seconds_to_pause_to_ready, 7U); + QCOMPARE(current_worker_conf->use_dhmmixer, 0); + + globalSettingsMap.clear(); + + delete rnd; +} + +void Ut_MafwGstRenderer::testNextHint() +{ + MafwMediaInfo content(""); + QMap >map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.next_uri"; + content.setMetaData(map); + + m_renderer->doNextHint(content); +} + +void Ut_MafwGstRenderer::testPosition() +{ + QVERIFY(connect(m_renderer, SIGNAL(rendererError(MafwError)), this, SLOT(positionError(MafwError)))); + //set renderer to playing state first + MafwMediaInfo content(""); + QMap >map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + + // Normal case + m_position = 0; + global_position = 157; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 157, "Wrong position"); + + //repeated call with same value + m_position = 0; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 157, "Wrong position"); + + // Normal case, maxint position + m_position = 0; + int maxint = 2147483647; + global_position = maxint; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == (uint)maxint, "Wrong position"); + + // Normal case, position to 0 + global_position = 0; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 0, "Wrong position"); + + // Errorenuous position case + m_position = 0; + global_position = -1; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 0, "Wrong position"); + QVERIFY2(m_error.code() == MafwError::RendererError_CannotGetPosition, "Wrong error code"); + + //Errorenuous position case, -maxint + m_position = 0; + global_position = -maxint; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 0, "Wrong position"); + + //NULL result slot + global_position = 1; + m_renderer->getPosition(0, SLOT(positionChanged(uint))); + QTest::qWait(10); + + //Not existing error slot + global_position = -1; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + + // Stopped case when 0 should be returned + m_renderer->doStop(); + m_position = 0; + global_position = -1; + m_renderer->getPosition(this, SLOT(positionChanged(uint))); + QTest::qWait(10); + QVERIFY2(m_position == 0, "Wrong position"); +} + +void Ut_MafwGstRenderer::testProperty() +{ + QFETCH(QString, name); + QFETCH(QVariant, value); + bool success = m_renderer->setMafwProperty(name, value); + QVERIFY2(success, "Unable to set property"); + + m_renderer->mafwProperty(name, this, SLOT(propertyChanged(const QString&, const QVariant&))); + QTest::qWait(10); + + //@TODO getter for current-frame-on-pause needs to be implemented + if (name == "colorkey") + { + QCOMPARE(m_value, QVariant(1)); //value comes from worker stub + + //Test unexisting slot case + m_renderer->mafwProperty(name, this, SLOT(propertyChanged2(const QString&, const QVariant&))); + QTest::qWait(10); + } + else if (name != "unknown" + && name!= "current-frame-on-pause" + && name != MafwRenderer::MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE ) + { + QCOMPARE(m_name, name); + QCOMPARE(m_value, value); + } +} + +void Ut_MafwGstRenderer::testProperty_data() +{ + QTest::addColumn("name"); + QTest::addColumn("value"); + + QTest::newRow("volume") << "volume" << QVariant(1); + QTest::newRow("force-aspect-ratio") << "force-aspect-ratio" << QVariant(false); + QTest::newRow("autopaint") << "autopaint" << QVariant(true); + QTest::newRow("xid") << "xid" << QVariant(12345); + QTest::newRow("current-frame-on-pause") << "current-frame-on-pause" << QVariant(true); + QTest::newRow("colorkey") << "colorkey" << QVariant(23456); + QTest::newRow("render-rectangle") << "render-rectangle" << QVariant(QString("%1,%2,%3,%4").arg(1).arg(2).arg(3).arg(4)); + QTest::newRow("unknown property") << "unknown" << QVariant(true); +} + +void Ut_MafwGstRenderer::testPlaybackSpeedProperty() +{ + QString propertyName = "playback-speed"; + + QSignalSpy propertyChangedSpy(m_renderer, SIGNAL(mafwPropertyChanged(const QString&, const QVariant&))); + + // + //Stopped - won't accept the property + // + m_renderer->setMafwProperty(propertyName, 0); + m_renderer->setMafwProperty(propertyName, 1); + m_renderer->setMafwProperty(propertyName, -1); + QCOMPARE(propertyChangedSpy.size(), 0); + + // + //Playing + // + //then test in playing state + MafwMediaInfo content(""); + QMap >map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + + //no change in playback, just expect the signal + m_renderer->setMafwProperty(propertyName, 1); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + QList arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(1)); + + m_renderer->setMafwProperty(propertyName, 2); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(2)); + + m_renderer->setMafwProperty(propertyName, 2); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(2)); + + m_renderer->setMafwProperty(propertyName, -1); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(-1)); + + m_renderer->setMafwProperty(propertyName, 0.3); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(0.3)); + + m_renderer->setMafwProperty(propertyName, 1.3); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(1.3)); + + m_renderer->setMafwProperty(propertyName, -0.3); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(-0.3)); + + m_renderer->setMafwProperty(propertyName, -1.3); + QTest::qWait(20); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(-1.3)); + //check that mafwProperty() returns the correct value + m_value = QVariant(0); + QVERIFY(m_renderer->mafwProperty(propertyName, this, SLOT(propertyChanged(const QString&, const QVariant&)))); + QTest::qWait(20); + QCOMPARE(m_value.toFloat(), float(-1.3)); + + //TODO what does 0 mean? + m_renderer->setMafwProperty(propertyName, 0); + QCOMPARE(propertyChangedSpy.size(), 1); + arguments = propertyChangedSpy.takeFirst(); + QCOMPARE(arguments.count(), 2); + QCOMPARE(arguments.at(0).toString(), propertyName); + //There is a QVariant inside QVariant + QCOMPARE(arguments.at(1).value().toFloat(), float(0)); + + // + //Paused - won't accept the property + // + m_renderer->doPause(); + m_renderer->setMafwProperty(propertyName, 3); + //check that mafwProperty() returns the correct value + m_value = QVariant(-1); //not same as the last value set in playing state + QVERIFY(m_renderer->mafwProperty(propertyName, this, SLOT(propertyChanged(const QString&, const QVariant&)))); + QTest::qWait(20); + QCOMPARE(m_value, QVariant(0)); //the value that was last set in playing state + + //TODO test property value after resume + + // + //Stopped - won't accept the property + // + m_renderer->doStop(); + + m_renderer->setMafwProperty(propertyName, 3); + //check that mafwProperty() returns the correct value + m_value = QVariant(-1); //not same as the last value set in playing state + QVERIFY(m_renderer->mafwProperty(propertyName, this, SLOT(propertyChanged(const QString&, const QVariant&)))); + QTest::qWait(20); + QCOMPARE(m_value, QVariant(0)); //the value that was last set in playing state + +} + +void Ut_MafwGstRenderer::cleanupTestCase() +{ + delete m_renderer; + g_slist_free(global_worker_destinations); + + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + while(QCoreApplication::hasPendingEvents()) + { + QCoreApplication::sendPostedEvents(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + } +} + +/** + * Pointers to callback functions after are set to renderer worker at + * MafwGstRenderer::initialize + */ +void Ut_MafwGstRenderer::testCallbacks() +{ + GValue intValue; + GValue uintValue; + GValue boolValue; + GValue stringValue; + GValue uninitValue; + GValue objectValue; + GValue doubleValue; + GValue int64Value; + + memset(&intValue, 0, sizeof(GValue)); + memset(&uintValue, 0, sizeof(GValue)); + memset(&boolValue, 0, sizeof(GValue)); + memset(&stringValue, 0, sizeof(GValue)); + memset(&uninitValue, 0, sizeof(GValue)); + memset(&objectValue, 0, sizeof(GValue)); + memset(&doubleValue, 0, sizeof(GValue)); + memset(&int64Value, 0, sizeof(GValue)); + + g_value_init(&intValue, G_TYPE_INT); + g_value_init(&uintValue, G_TYPE_UINT); + g_value_init(&boolValue, G_TYPE_BOOLEAN); + g_value_init(&stringValue, G_TYPE_STRING); + g_value_init(&objectValue, G_TYPE_OBJECT); + g_value_init(&doubleValue, G_TYPE_DOUBLE); + g_value_init(&int64Value, G_TYPE_INT64); + + g_value_set_int(&intValue, -123); + g_value_set_uint(&uintValue, (uint)-1); + g_value_set_boolean(&boolValue, TRUE); + g_value_set_string(&stringValue, "The test property"); + g_value_set_double(&doubleValue, 1.01); + g_value_set_int64(&int64Value, 1234567890); + +//playCallback + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + m_renderer->m_worker->notify_play_handler(m_renderer->m_worker, m_renderer); + QCOMPARE(playSpy.count(), 1); + +//pauseCallback + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + m_renderer->m_worker->notify_pause_handler(m_renderer->m_worker, m_renderer); + QCOMPARE(pauseSpy.count(), 1); + +//errorCallback + QSignalSpy errorSpy(m_renderer, SIGNAL(rendererError(MafwError))); + GError* error = g_error_new_literal(1, 2, "The unit test error"); + GError* error2 = g_error_new_literal(1, -1, "Another unit test error"); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, error); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, error2); + QCOMPARE(errorSpy.count(), 2); + g_error_free(error); + g_error_free(error2); + +//eosCallback + QSignalSpy eosSpy(m_renderer, SIGNAL(rendererEos())); + m_renderer->m_worker->notify_eos_handler(m_renderer->m_worker, m_renderer); + QTest::qWait(10); //renderer paused will be emitted asynchronously + QCOMPARE(eosSpy.count(), 1); + +//metadataCallback + QSignalSpy metadataSpy(m_renderer, SIGNAL(metadataChanged(const QString&, const QList&))); + GValueArray *array = g_value_array_new(0); + g_value_array_append(array, &stringValue); + g_value_array_append(array, &doubleValue); + g_value_array_append(array, &int64Value); + + //unknown metadata key + m_renderer->m_worker->notify_metadata_handler(m_renderer->m_worker, m_renderer, -1, G_TYPE_VALUE_ARRAY, array); + //invalid type + m_renderer->m_worker->notify_metadata_handler(m_renderer->m_worker, m_renderer, 1, G_TYPE_VALUE, &stringValue); + //valid case + m_renderer->m_worker->notify_metadata_handler(m_renderer->m_worker, m_renderer, 1, G_TYPE_VALUE_ARRAY, array); + + QCOMPARE(metadataSpy.count(), 1); + g_value_array_free(array); + +//propertyCallback + int count = 0; + QSignalSpy propertySpy(m_renderer, SIGNAL(mafwPropertyChanged(const QString&, const QVariant&))); + + //auto paint + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_AUTOPAINT, &boolValue); + QCOMPARE(propertySpy.count(), ++count); + + //color key + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_COLORKEY, &intValue); + QCOMPARE(propertySpy.count(), ++count); + + //xid + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_XID, &uintValue); + QCOMPARE(propertySpy.count(), ++count); + + //pause frame + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE, &boolValue); + QCOMPARE(propertySpy.count(), ++count); + + //force aspect ratio + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_FORCE_ASPECT_RATIO, &boolValue); + QCOMPARE(propertySpy.count(), ++count); + + //playback speed + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_PLAYBACK_SPEED, &doubleValue); + QCOMPARE(propertySpy.count(), ++count); + + //unknown property id + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, 6, &uintValue); + QCOMPARE(propertySpy.count(), ++count); + + //!G_IS_VALUE + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE, &uninitValue); + QCOMPARE(propertySpy.count(), count); + + //unsupported value g_type + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_MUTE, &objectValue); + QCOMPARE(propertySpy.count(), count); + + //boolean property with string value, currently there is no check -> emits mafwPropertyChanged( "mute", "The test property" ) + m_renderer->m_worker->notify_property_handler(m_renderer->m_worker, m_renderer, WORKER_PROPERTY_MUTE, &intValue); + + +//bufferStatusCallback + QSignalSpy bufferSpy(m_renderer, SIGNAL(bufferingInfo(float))); + m_renderer->m_worker->notify_buffer_status_handler(m_renderer->m_worker, m_renderer, (gdouble)1.001); + m_renderer->m_worker->notify_buffer_status_handler(m_renderer->m_worker, m_renderer, (gdouble)-1.001); + m_renderer->m_worker->notify_buffer_status_handler(m_renderer->m_worker, m_renderer, (gdouble)1001); + QCOMPARE(bufferSpy.count(), 3); + + g_value_unset(&intValue); + g_value_unset(&uintValue); + g_value_unset(&boolValue); + g_value_unset(&stringValue); + g_value_unset(&int64Value); + g_value_unset(&doubleValue); +} + +void Ut_MafwGstRenderer::testGetCurrentMediaInfo() +{ + QFETCH(QString, name); + QFETCH(QList, values); + + qDebug() << "values.size():" << values.size(); + + MafwMediaInfo content(""); + MafwMediaInfo mediaInfo; + QMap > map; + QMap >old_map; + + bool success = false; + m_name = name; + + GValueArray *array = g_value_array_new(0); + + if(name == "all") + { + QList valueList; + valueList.append("http://test.play.uri"); + map[MAFW_METADATA_KEY_URI] = valueList; + old_map[MAFW_METADATA_KEY_URI] = valueList; + mediaInfo.setMetaData(map); + content.setMetaData(old_map); + + GValue geevalue; + memset(&geevalue, 0, sizeof(GValue)); + g_value_init(&geevalue, G_TYPE_STRING); + g_value_set_string(&geevalue, "http://test.play.uri"); + g_value_array_append(array, &geevalue); + g_value_unset(&geevalue); + + m_renderer->doPlay(content); + m_renderer->m_worker->notify_metadata_handler(m_renderer->m_worker, m_renderer, 18, G_TYPE_VALUE_ARRAY, array); + success = m_renderer->getCurrentMediaInfo(this, SLOT(media_info_result(const MafwMediaInfo& ))); + QTest::qWait(10); + + if(success) + { + QCOMPARE(m_media_values.at(0), mediaInfo.firstMetaData(MAFW_METADATA_KEY_URI)); + } + else if(!success) + { + QVERIFY(success); + } + } + else + { + //URI must be set + QMap onlyURI; + onlyURI[MAFW_METADATA_KEY_URI] = "http://2222.222.22"; + content.setMetaData(onlyURI); + m_renderer->doPlay(content); + + map[name] = values; + old_map[name] = values; + mediaInfo.setMetaData(map); + content.setMetaData(old_map); + m_metadataCount++; + + Q_FOREACH(QVariant value, values) + { + GValue geevalue; + memset(&geevalue, 0, sizeof(GValue)); + QString type = value.typeName(); + + if(type == "QString") + { + g_value_init(&geevalue, G_TYPE_STRING); + g_value_set_string(&geevalue, value.toByteArray()); + } + else if(type == "int") + { + g_value_init(&geevalue, G_TYPE_INT); + g_value_set_int(&geevalue, value.toInt()); + } + else if(type == "float") + { + g_value_init(&geevalue, G_TYPE_DOUBLE); + g_value_set_double(&geevalue, value.toDouble()); + } + else if(type == "bool") + { + g_value_init(&geevalue, G_TYPE_BOOLEAN); + g_value_set_boolean(&geevalue, value.toBool()); + } + + g_value_array_append(array, &geevalue); + g_value_unset(&geevalue); + } + qDebug() << "array.size:" << array->n_values; + m_renderer->m_worker->notify_metadata_handler(m_renderer->m_worker, m_renderer, m_metadataCount, G_TYPE_VALUE_ARRAY, array); + + success = m_renderer->getCurrentMediaInfo(this, SLOT(media_info_result(const MafwMediaInfo& )), name); + QTest::qWait(10); + + if(success) + { + //TODO rethink this and do the test properly if more metadata start to have related info attached + //Related metadata is returned with paused-thumbnail-uri. + if(name == "paused-thumbnail-uri") + { + values.append(QVariant(QString("http://2222.222.22"))); + values.append(QVariant(0)); + } + qDebug() << m_media_values; + qDebug() << values; + QCOMPARE(m_media_values, values); + } + else if(!success) + { + QVERIFY(success); + } + } + + g_value_array_free(array); +} + +void Ut_MafwGstRenderer::testGetCurrentMediaInfo_data() +{ + QTest::addColumn("name"); + QTest::addColumn >("values"); + + QTest::newRow("all") << "all" << QList(); + QTest::newRow("title") << MAFW_METADATA_KEY_TITLE << ( QList() << QVariant("test-title") ); + QTest::newRow("artist") << MAFW_METADATA_KEY_ARTIST << ( QList() << QVariant("test-artist") << QVariant("test-artist 2") ); + QTest::newRow("audio-codec") << MAFW_METADATA_KEY_AUDIO_CODEC << ( QList() << QVariant("test-audio-codec") ); + QTest::newRow("video-codec") << MAFW_METADATA_KEY_VIDEO_CODEC << ( QList() << QVariant("test-video-codec") ); + QTest::newRow("bitrate") << MAFW_METADATA_KEY_BITRATE << ( QList() << QVariant(256) ); + QTest::newRow("encoding") << MAFW_METADATA_KEY_ENCODING << ( QList() << QVariant("test-encoding") ); + QTest::newRow("album") << MAFW_METADATA_KEY_ALBUM << ( QList() << QVariant("test-album") ); + QTest::newRow("genre") << MAFW_METADATA_KEY_GENRE << ( QList() << QVariant("test-genre") ); + QTest::newRow("track") << MAFW_METADATA_KEY_TRACK << ( QList() << QVariant(1) ); + QTest::newRow("organization") << MAFW_METADATA_KEY_ORGANIZATION << ( QList() << QVariant("test-organization") ); + QTest::newRow("renderer-art-uri") << MAFW_METADATA_KEY_RENDERER_ART_URI << ( QList() << QVariant("http://test.renderer.art.uri") ); + QTest::newRow("res-x") << MAFW_METADATA_KEY_RES_X << ( QList() << QVariant(480) ); + QTest::newRow("res-y") << MAFW_METADATA_KEY_RES_Y << ( QList() << QVariant(640) ); + QTest::newRow("video-framerate") << MAFW_METADATA_KEY_VIDEO_FRAMERATE << ( QList() << QVariant(float(30/1)) ); + QTest::newRow("duration") << MAFW_METADATA_KEY_DURATION << ( QList() << QVariant(5) ); + QTest::newRow("is-seekable") << MAFW_METADATA_KEY_IS_SEEKABLE << ( QList() << QVariant(true) ); + QTest::newRow("paused-thumbnail-uri") << MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI << ( QList() << QVariant("file:///test.thumbnail.paused.uri") );// << QVariant("http://test.play.uri") << QVariant(666) ); + QTest::newRow("uri") << MAFW_METADATA_KEY_URI << ( QList() << QVariant("http://test.play.uri") ); +} + +void Ut_MafwGstRenderer::testErrorCodeScenarios() +{ + m_renderer->m_playingPlaylistFile = false; + + QFETCH(QString, uri); + QFETCH(int, workerError); + QFETCH(MafwError::Code, emittedError); + + global_worker_uri = g_strdup(uri.toAscii().constData()); + + QSignalSpy errorSpy(m_renderer, SIGNAL(rendererError(MafwError))); + + GError* gerror = g_error_new_literal(1, workerError, "Media not found"); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, gerror); + + QCOMPARE(errorSpy.size(), 1); + + QVariantList params = errorSpy.takeFirst(); + MafwError mafwError = params.at(0).value(); + + QCOMPARE(mafwError.code(), MafwError::Code(emittedError)); + + g_error_free(gerror); +} + +void Ut_MafwGstRenderer::testErrorCodeScenarios_data() +{ + QTest::addColumn("uri"); + QTest::addColumn("workerError"); + QTest::addColumn("emittedError"); + + QTest::newRow("Local file not found") << "file:///donotexits.mp3" << int(WORKER_ERROR_MEDIA_NOT_FOUND) << MafwError::RendererError_MediaNotFound; + QTest::newRow("Stream could not be connected") << "mms:///donotexits.mp3" << int(WORKER_ERROR_MEDIA_NOT_FOUND) << MafwError::RendererError_URINotAvailable; +} + +void Ut_MafwGstRenderer::testBlankingPreventer() +{ + m_renderer->m_worker->blanking__control_handler(m_renderer->m_worker, m_renderer, TRUE ); + QCOMPARE( global_qmsystemstub_setBlankingPauseCalled, 1 ); + QTest::qWait( 50*1000 ); // >45 secs + QCOMPARE( global_qmsystemstub_setBlankingPauseCalled, 2 ); + global_qmsystemstub_setBlankingPauseCalled = 0; + + m_renderer->m_worker->blanking__control_handler(m_renderer->m_worker, m_renderer, FALSE ); + QTest::qWait( 50*1000 ); // >45 secs + // no more calls arrived + QCOMPARE( global_qmsystemstub_setBlankingPauseCalled, 0 ); +} + +void Ut_MafwGstRenderer::testPolicyPropertyHandler() +{ + m_renderer->setMafwProperty(MafwRenderer::MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE, true); + QVERIFY(global_ready_timeout == 0); + + m_renderer->setMafwProperty(MafwRenderer::MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE, false); + QCOMPARE(global_ready_timeout, (guint)MAFW_GST_RENDERER_WORKER_READY_TIMEOUT); + + m_renderer->setMafwProperty(MafwRenderer::MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE, true); + QVERIFY(global_ready_timeout == 0); + + m_renderer->setMafwProperty(MafwRenderer::MAFW_RENDERER_PROPERTY_POLICY_OVERRIDE, false); + QCOMPARE(global_ready_timeout, (guint)MAFW_GST_RENDERER_WORKER_READY_TIMEOUT); + +} + +void Ut_MafwGstRenderer::testMediaRouting() +{ + + QVERIFY(global_audio_route_property); + QVERIFY(global_video_route_property); + + global_audio_route = "tvout"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 3); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "tvout"; + global_video_route = "tvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "null"; + global_video_route = "builtin"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_NULL))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + + global_audio_route = "headset"; + global_video_route = "kjkjkjfg"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_NULL))); + + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + m_renderer->doPlay(content); + QVERIFY(global_worker_playing == TRUE); //should be playing now + global_audio_route = "ihf"; + global_video_route = "builtin"; + m_renderer->m_audioRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + + global_audio_route = "earpiece"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 3); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "bthsp"; + global_video_route = "kjkjkjfg"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_NULL))); + + global_audio_route = "bta2dp"; + global_video_route = "builtin"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 2); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + + global_audio_route = "lkglklkgh"; + global_video_route = "bugvfdd"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 1); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_NULL))); + + global_audio_route = "fmtx"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 3); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_FM_RADIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "ihfandfmtx"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_FM_RADIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "earpieceandtvout"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 3); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "headphone"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 3); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "ihfandheadset"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "ihfandheadphone"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "ihfandbthsp"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "tvoutandbthsp"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + global_audio_route = "tvoutandbta2dp"; + global_video_route = "builtinandtvout"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(global_worker_destinations); + QVERIFY(g_slist_length(global_worker_destinations) == 4); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BLUETOOTH_AUDIO))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_TVOUT))); + + // provider dies + global_audio_route = "earpiece"; + global_video_route = "builtin"; + m_renderer->m_audioRoute->ignoreCommander(); + m_renderer->m_videoRoute->ignoreCommander(); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + QList args; + args << "name" << "old" << ""; + QDBusMessage dbusMsg; + dbusMsg.setArguments(args); + m_renderer->handleContextProviderRemoval( dbusMsg ); + QVERIFY(g_slist_find(global_worker_destinations, GINT_TO_POINTER(WORKER_OUTPUT_NULL))); +} + +void Ut_MafwGstRenderer::testStamping() +{ + // start playing + MafwMediaInfo content("MafwTrackerSource::test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "file:///home/user/MyDocs/test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + + QVERIFY( m_renderer->m_playedStamped==false ); + QTest::qWait(5200); + QVERIFY( m_renderer->m_playedStamped==true ); + m_renderer->doStop(); + + //http uri + MafwMediaInfo content2("MafwTrackerSource::test_uuid2"); + QMap > map2; + map2[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content2.setMetaData(map2); + + m_renderer->doPlay(content2); + + QVERIFY( m_renderer->m_playedStamped==false ); + QTest::qWait(5200); + QVERIFY( m_renderer->m_playedStamped==false ); + m_renderer->doStop(); + + // play uri case (no uuid) + MafwMediaInfo content3; + QMap > map3; + map3[MAFW_METADATA_KEY_URI] = QList() << "file://test.play.uri"; + content3.setMetaData(map3); + + m_renderer->doPlay(content3); + + QVERIFY( m_renderer->m_playedStamped==false ); + QTest::qWait(5200); + QVERIFY( m_renderer->m_playedStamped==true ); + m_renderer->doStop(); +} + +void Ut_MafwGstRenderer::testNetworkChangesWhenPlaying() +{ + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + NetworkStubHelper::currentCreatedConfigIsValid = true; + QNetworkConfiguration config; + + global_worker_stop_called = 0; + networkStub.emitConfigurationChange(config, + QNetworkConfiguration::Active); + QVERIFY(global_worker_playing); + QCOMPARE(global_worker_uri, "http://test.play.uri"); + QCOMPARE(global_worker_stop_called, 1); + + map[MAFW_METADATA_KEY_URI] = QList() << "file://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + //another network config is activated + QNetworkConfiguration config2; + networkStub.emitConfigurationChange(config2, + QNetworkConfiguration::Active); + + QVERIFY(global_worker_playing); //should keep playing as URI is file:// + + m_renderer->doStop(); + QVERIFY(!global_worker_playing); + + //checks that activating new network config stops play when streaming + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); + + QNetworkConfiguration config3; + global_worker_stop_called = 0; + networkStub.emitConfigurationChange(config3, QNetworkConfiguration::Active); + QCOMPARE(global_worker_uri, "http://test.play.uri"); + QCOMPARE(global_worker_stop_called, 1); + QVERIFY(global_worker_playing); + + //checks that deactivating the current configuration stops playback + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); + networkStub.emitConfigurationChange(config3, QNetworkConfiguration::Discovered); + QVERIFY(!global_worker_playing); +} + +void Ut_MafwGstRenderer::testNetworkChangesWithNoPlaylistFileUtil() +{ + delete m_renderer->m_playlistFileUtil; + m_renderer->m_playlistFileUtil = 0; + testNetworkChangesWhenPlaying(); +} + +void Ut_MafwGstRenderer::testNetworkChangesWhenPaused() +{ + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + QSignalSpy stopSpy(m_renderer, SIGNAL(rendererStopped())); + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + QSignalSpy resumeSpy(m_renderer, SIGNAL(rendererResumed())); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + m_renderer->doPause(); + + QCOMPARE(playSpy.size(), 1); + playSpy.clear(); + QCOMPARE(pauseSpy.size(), 1); + pauseSpy.clear(); + QVERIFY(!global_worker_playing); //should be playing now + + global_position = 313; + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Active); + + QVERIFY(!global_worker_playing); + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::CurrentUri); + + QCOMPARE(m_renderer->m_haltState.m_state, MafwRenderer::Paused); + QCOMPARE(m_renderer->m_haltState.m_position, 313); + QCOMPARE(m_renderer->m_haltState.m_uri, QString("http://test.play.uri")); + + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + global_worker_seek_request = 0; + + m_renderer->doResume(); + + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 1); + + QVERIFY(global_worker_playing); + + QCOMPARE(QString(global_worker_uri), QString("http://test.play.uri")); + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::CurrentUri); + QVERIFY(!m_renderer->m_haltState.isSet()); + + QCOMPARE(global_worker_seek_request, 313); +} + +void Ut_MafwGstRenderer::testNetworkChangesWhenPausedAndRendererStopped() +{ + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.play.uri"; + content.setMetaData(map); + + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + QSignalSpy stopSpy(m_renderer, SIGNAL(rendererStopped())); + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + m_renderer->doPause(); + + QCOMPARE(playSpy.size(), 1); + playSpy.clear(); + QCOMPARE(pauseSpy.size(), 1); + pauseSpy.clear(); + QVERIFY(!global_worker_playing); //should be playing now + + global_position = 313; + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Active); + + m_renderer->doStop(); + QCOMPARE(stopSpy.size(), 1); + QVERIFY(!m_renderer->m_haltState.isSet()); +} + +void Ut_MafwGstRenderer::testNetworkChangesToInactiveAndPauseResumeRequested() +{ + QFETCH(int, resumeDelay); + MafwGstRendererHaltState::DECAY_TIME = 3; + + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.resume-pause.uri"; + content.setMetaData(map); + + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + QSignalSpy stopSpy(m_renderer, SIGNAL(rendererStopped())); + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + QCOMPARE(playSpy.size(), 1); + playSpy.clear(); + + global_position = 999; + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + m_renderer->doPause(); + QCOMPARE(pauseSpy.size(), 1); + pauseSpy.clear(); + + QVERIFY(m_renderer->m_haltState.isSet()); + QCOMPARE(m_renderer->m_haltState.m_state, MafwRenderer::Paused); + QCOMPARE(m_renderer->m_haltState.m_position, 999); + QCOMPARE(m_renderer->m_haltState.m_uri, QString("http://test.resume-pause.uri")); + + global_worker_seek_request = 0; + + QTest::qWait(resumeDelay); + + m_renderer->doResume(); + QCOMPARE(global_worker_seek_request, 999); + QVERIFY(global_worker_playing); //should be playing yeah there's no network but it will try + QVERIFY(!m_renderer->m_haltState.isSet()); +} + +void Ut_MafwGstRenderer::testNetworkChangesToInactiveAndPauseResumeRequested_data() +{ + QTest::addColumn("resumeDelay"); + QTest::newRow("short delay") << 1000; + QTest::newRow("same as decay") << 3000; + QTest::newRow("longer than decay") << 5000; +} + +void Ut_MafwGstRenderer::testNetworkChangesWithPlaylistURI() +{ + QStringList playlistUris = QStringList() << "http://test.uriplaylist.item/1" << "http://test.uriplaylist.item/2"; + stubPlaylistFileUtilityUris.clear(); + stubPlaylistFileUtilityUris = playlistUris; + + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.playlist.m3u"; //does not matter + map[MAFW_METADATA_KEY_MIME] = QList() << "audio/x-scpls"; + content.setMetaData(map); + + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + QSignalSpy stopSpy(m_renderer, SIGNAL(rendererStopped())); + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + QSignalSpy resumeSpy(m_renderer, SIGNAL(rendererResumed())); + + m_renderer->doPlay(content); + + //time to parse the playlist + QTest::qWait(75); + + QVERIFY(global_worker_playing); //should be playing now + + QCOMPARE(playSpy.size(), 1); + playSpy.clear(); + + global_position = 007; + global_worker_stop_called = 0; + + NetworkStubHelper::currentCreatedConfigIsValid = false; + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + QVERIFY(!global_worker_playing); + QCOMPARE(global_worker_stop_called, 1); + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::CurrentUri); + + QCOMPARE(m_renderer->m_haltState.m_state, MafwRenderer::Playing); + QCOMPARE(m_renderer->m_haltState.m_position, 007); + QCOMPARE(m_renderer->m_haltState.m_uri, playlistUris.at(0)); + + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + global_worker_seek_request = 0; + + NetworkStubHelper::currentCreatedConfigIsValid = true; + QNetworkConfiguration configActive; + networkStub.emitConfigurationChange(configActive, QNetworkConfiguration::Active); + + QVERIFY(global_worker_playing); + QCOMPARE(global_worker_seek_request, 007); + + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + QCOMPARE(QString(global_worker_uri), playlistUris.at(0)); + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::CurrentUri); + QVERIFY(!m_renderer->m_haltState.isSet()); + + //Test that next uri is started to play if playing first stops because of an error + GError* error = g_error_new_literal(1, 2, "Playlist uri playback error"); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, m_renderer, error); + QTest::qWait(10); + + QVERIFY(global_worker_playing); + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + QCOMPARE(QString(global_worker_uri), playlistUris.at(1)); + + m_renderer->doStop(); + QVERIFY(!global_worker_playing); + QCOMPARE(stopSpy.size(), 1); + + g_error_free(error); +} + +void Ut_MafwGstRenderer::testNetworkChangesHaltStateDecay() +{ + MafwGstRendererHaltState::DECAY_TIME = 4; + + MafwMediaInfo content("test_uuid"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "http://test.decay.uri"; + content.setMetaData(map); + + QSignalSpy pauseSpy(m_renderer, SIGNAL(rendererPaused())); + QSignalSpy stopSpy(m_renderer, SIGNAL(rendererStopped())); + QSignalSpy playSpy(m_renderer, SIGNAL(rendererPlaying(int))); + QSignalSpy resumeSpy(m_renderer, SIGNAL(rendererResumed())); + + m_renderer->doPlay(content); + QVERIFY(global_worker_playing); //should be playing now + + QCOMPARE(playSpy.size(), 1); + playSpy.clear(); + + global_position = 313; + NetworkStubHelper::currentCreatedConfigIsValid = false; + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + QVERIFY(!global_worker_playing); + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::CurrentUri); + + QCOMPARE(m_renderer->m_haltState.m_state, MafwRenderer::Playing); + QCOMPARE(m_renderer->m_haltState.m_position, 313); + QCOMPARE(m_renderer->m_haltState.m_uri, QString("http://test.decay.uri")); + + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + global_worker_stop_called = 0; + QTest::qWait(MafwGstRendererHaltState::DECAY_TIME * 1000 + 1000); + + global_worker_stop_called = 1; + QCOMPARE(stopSpy.size(), 1); + stopSpy.clear(); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + QVERIFY(!m_renderer->m_haltState.isSet()); + + global_worker_seek_request = 0; + global_worker_stop_called = 0; + NetworkStubHelper::currentCreatedConfigIsValid = true; + QNetworkConfiguration config2; + networkStub.emitConfigurationChange(config2, QNetworkConfiguration::Active); + + QCOMPARE(stopSpy.size(), 0); + QCOMPARE(pauseSpy.size(), 0); + QCOMPARE(playSpy.size(), 0); + QCOMPARE(resumeSpy.size(), 0); + + QVERIFY(!global_worker_playing); + + global_worker_stop_called = 0; + QCOMPARE(m_renderer->m_playingItem, MafwBasicRenderer::UnknownUri); + QVERIFY(!m_renderer->m_haltState.isSet()); + + QCOMPARE(global_worker_seek_request, 0); +} + +void Ut_MafwGstRenderer::testMmc() +{ + QVERIFY(!global_worker_playing); + + MafwGstRenderer *rnd = new MafwGstRenderer("renderer_uuid", "renderer-plugin", "rendere_name"); + m_stubHelper->expect("initialize", true); + QVERIFY(rnd->initialize(0) == true); + + // MMC not mounted at first case + + QSignalSpy errorSpy( rnd, SIGNAL( rendererError(const MafwError&) ) ); + stubMmcMounted = false; + MafwMediaInfo content("test_uuid_xyz"); + QMap > map; + map[MAFW_METADATA_KEY_URI] = QList() << "file:///home/user/MyDocs/rock.mp3"; + content.setMetaData(map); + + rnd->doPlay(content); + QVERIFY(!global_worker_playing); + QCOMPARE( errorSpy.size(), 1 ); + MafwError err=errorSpy[0][0].value(); + QVERIFY( err.code()==MafwError::RendererError_MmcNotAvailable ); + + // MMC unmounted during play + + stubMmcMounted = true; + errorSpy.clear(); + + rnd->doPlay(content); + QVERIFY(global_worker_playing); + + Q_EMIT stubMmcMonitor->preUnmountEvent("pre-unmount"); + QTest::qWait(100); + QVERIFY(!global_worker_playing); + QVERIFY( errorSpy.size()==1 ); + + // Playlist first not available + + stubPlaylistFileUtilityUris.clear(); + stubPlaylistFileUtilityUris << "file:///home/user/MyDocs/rock.mp3"; + stubPlaylistFileUtilityUris << "file:///home/user/MyDocs/rock2.mp3"; + errorSpy.clear(); + stubMmcMounted = false; + + MafwMediaInfo mediaInfo; + QMap testUri; + QMap testMimeType; + testUri.insert(MAFW_METADATA_KEY_URI, "file:///var/tmp/tunein-station.pls"); + testMimeType.insert(MAFW_METADATA_KEY_MIME, "audio/x-scpls"); + mediaInfo.setMetaData(testUri); + mediaInfo.setMetaData(testMimeType); + + rnd->doPlay(mediaInfo); + QTest::qWait(10); + QVERIFY(!global_worker_playing); + QCOMPARE( errorSpy.size(), 1 ); + err=errorSpy[0][0].value(); + QVERIFY( err.code()==MafwError::RendererError_MmcNotAvailable ); + + // Playlist play first, second not available + + errorSpy.clear(); + stubMmcMounted = true; + + rnd->doPlay(mediaInfo); + QTest::qWait(10); + QVERIFY(global_worker_playing); + + stubMmcMounted = false; + // cause next + GError* error = g_error_new_literal(1, 2, "Playlist uri playback error"); + m_renderer->m_worker->notify_error_handler(m_renderer->m_worker, rnd, error); + errorSpy.clear(); + + QTest::qWait(10); + QCOMPARE( errorSpy.size(), 1 ); + err=errorSpy[0][0].value(); + QVERIFY( err.code()==MafwError::RendererError_MmcNotAvailable ); + QVERIFY(!global_worker_playing); + + g_error_free(error); + + delete rnd; +} + +void Ut_MafwGstRenderer::play_result(const MafwError& /*error*/, MafwRenderer& /*rndr*/) +{ + qDebug() << "Ut_MafwGstRenderer::play_result"; + +} + +void Ut_MafwGstRenderer::positionChanged(uint position) +{ + m_position = position; +} + +void Ut_MafwGstRenderer::positionError(const MafwError& error) +{ + m_error = error; +} + +void Ut_MafwGstRenderer::propertyChanged(const QString& name, const QVariant& value) +{ + m_name = name; + m_value = value; +} + +void Ut_MafwGstRenderer::media_info_result(const MafwMediaInfo& mediaInfo) +{ + qDebug() << __PRETTY_FUNCTION__; + qDebug() << "m_name:" << m_name; + + m_media_values.clear(); + + if(m_name == "all") + { + m_media_values = mediaInfo.metaData(MAFW_METADATA_KEY_URI); + } + else + { + m_media_values = mediaInfo.metaData(m_name); + } + + qDebug() << "m_media_values.size():" << m_media_values.size(); + Q_FOREACH(QVariant v, m_media_values) + { + qDebug() << "value:" << v; + } +} + +void gst_init(int *argc, char **argv[]) +{ + Q_UNUSED(argc); + Q_UNUSED(argv); +} + +QTEST_MAIN(Ut_MafwGstRenderer) + +//Volume stub +MafwGstRendererVolume::MafwGstRendererVolume() +{ + qDebug() << "Volume stub ctor"; +} + +void MafwGstRendererVolume::connectToPulseAudio() +{ +} + +MafwGstRendererVolume::~MafwGstRendererVolume() +{ +} + +uint MafwGstRendererVolume::getVolume() +{ + qDebug(__PRETTY_FUNCTION__); + return (uint)1; +} + +bool MafwGstRendererVolume::setVolume (uint value) +{ + Q_UNUSED(value); + return true; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.h new file mode 100644 index 0000000..f464304 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/Ut_MafwGstRenderer.h @@ -0,0 +1,102 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERER_H_ +#define UT_MAFWGSTRENDERER_H_ + +#include +#include +#include + +class MafwInternalRegistry; +class MafwGstRenderer; +class MafwRenderer; +class MafwStubHelper; +class MafwRendererPolicyStub; +class MafwMediaInfo; + +Q_DECLARE_METATYPE(QVariant) +Q_DECLARE_METATYPE(MafwError::Code) + +class Ut_MafwGstRenderer: public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void testPlayURI(); + void testPlayPlaylistFile(); + void testStop(); + void testPause(); + void testResume(); + void testSeek(); + void testErrorCodeScenarios(); + void testErrorCodeScenarios_data(); + void testNextHint(); + void testPosition(); + void testProperty(); + void testProperty_data(); + void testPlaybackSpeedProperty(); + void testCallbacks(); + void testDefaultConfiguration(); + void testConfiguration(); + void testGetCurrentMediaInfo(); + void testGetCurrentMediaInfo_data(); + void testBlankingPreventer(); + void testPolicyPropertyHandler(); + void testMediaRouting(); + void testStamping(); + void testNetworkChangesWhenPlaying(); + void testNetworkChangesWithNoPlaylistFileUtil(); + void testNetworkChangesWhenPaused(); + void testNetworkChangesWhenPausedAndRendererStopped(); + void testNetworkChangesToInactiveAndPauseResumeRequested(); + void testNetworkChangesToInactiveAndPauseResumeRequested_data(); + void testNetworkChangesHaltStateDecay(); + void testNetworkChangesWithPlaylistURI(); + void testMmc(); + + /** + * @param error The status of the completed request. + * @param rndr Reference to instance of MafwRenderer invoked the callback slot + */ + void play_result(const MafwError& error, MafwRenderer& rndr); + + void positionChanged(uint position); + void positionError(const MafwError& error); + void media_info_result(const MafwMediaInfo& mediaInfo); + +protected Q_SLOTS: + void propertyChanged(const QString& name, const QVariant& value); + +private: + + MafwGstRenderer* m_renderer; + MafwStubHelper* m_stubHelper; + MafwRendererPolicyStub* m_rendererPolicy; + MafwError m_error; + uint m_position; + QVariant m_value; + QString m_name; + QList m_media_values; + int m_metadataCount; + ContextProperty *m_videoRoute; +}; + +#endif /*UT_MAFWGSTRENDERER_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ut_MafwGstRenderer.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ut_MafwGstRenderer.pro new file mode 100644 index 0000000..e5f2342 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRenderer/ut_MafwGstRenderer.pro @@ -0,0 +1,63 @@ +TEMPLATE = app +TARGET = +INCLUDEPATH += . +QT += network +QT -= gui + +CONFIG = console + +MAFW_GST_INCDIR = ../../inc +UT_COMMONDIR = ../common + +INCLUDEPATH += $$MAFW_GST_INCDIR \ + $$UT_COMMONDIR +DEPENDPATH += . ../../inc ../../src + +CONFIG += qtestlib no_keywords +CONFIG += qt link_pkgconfig debug + +PKGCONFIG += qmafw glib-2.0 gobject-2.0 +PKGCONFIG += contextprovider-1.0 x11 gq-gconf gstreamer-tag-0.10 libpulse-mainloop-glib +PKGCONFIG += qmsystem2 contextsubscriber-1.0 + +LIBS += -lgcov +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -O0 -Werror $$system(pkg-config --cflags-only-I QtSparql) +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -O0 -Werror + +# Input +HEADERS += Ut_MafwGstRenderer.h \ + MafwGstRenderer.h \ + MafwGstRendererVolume.h \ + MafwGstRendererDolby.h \ + MafwBlankingPreventer.h \ + MafwGstRendererNetworkMonitor.h \ + mafw-gst-renderer-worker.h \ + mafw-gst-renderer-utils.h \ + MafwGstRendererPlaylistFileUtility.h \ + $$UT_COMMONDIR/MafwStubHelper.h \ + $$UT_COMMONDIR/MafwRendererPolicyStub.h \ + $$UT_COMMONDIR/QNetworkStubs.h \ + /usr/include/qt4/QtNetwork/qnetworkconfigmanager.h \ + MafwMmcMonitor.h \ + MafwGstScreenshot.h \ + MafwGstRendererHaltState.h + +SOURCES += QmSystemStub.cpp \ + QSettingsStub.cpp \ + Ut_MafwGstRenderer.cpp \ + MafwGstRenderer.cpp \ + MafwGstRendererDolbyStub.cpp \ + MafwBlankingPreventer.cpp \ + MafwGstRendererNetworkMonitor.cpp \ + mafw-gst-renderer-utils.c \ + $$UT_COMMONDIR/MafwStubHelper.cpp \ + $$UT_COMMONDIR/renderer-worker-stub.c \ + $$UT_COMMONDIR/MafwBasicRendererStub.cpp \ + $$UT_COMMONDIR/MafwRendererPolicyStub.cpp \ + $$UT_COMMONDIR/LibCredsStub.cpp \ + $$UT_COMMONDIR/MafwPlaylistFileUtilityStub.cpp \ + ContextFWStub.cpp \ + $$UT_COMMONDIR/QNetworkStubs.cpp \ + MafwMmcMonitorStub.cpp \ + MafwGstScreenshot.cpp \ + MafwGstRendererHaltState.cpp diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.cpp new file mode 100644 index 0000000..1038e43 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.cpp @@ -0,0 +1,120 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ +#include "ut_MafwGstRendererDolby.h" + +#include +#include + +#include "MafwGstRendererDolby.h" + +void Ut_MafwGstRendererDolby::initTestCase() +{ + m_dolby = new MafwGstRendererDolby(this); + m_dolby->initialize(); + delete m_dolby; + m_dolby = new MafwGstRendererDolby(this); + m_dolby->initialize(); +} + +void Ut_MafwGstRendererDolby::cleanupTestCase() +{ + delete m_dolby; +} + +void Ut_MafwGstRendererDolby::testDolby() +{ + m_dolby->setMusicDolbyState(0); + QCOMPARE(m_dolby->getMusicDolbyState(), (uint)0); + m_dolby->setMusicDolbyState(1); + QCOMPARE(m_dolby->getMusicDolbyState(), (uint)1); + m_dolby->setMusicDolbyState(2); + QCOMPARE(m_dolby->getMusicDolbyState(), (uint)2); + m_dolby->setMusicDolbyState(3); + QCOMPARE(m_dolby->getMusicDolbyState(), (uint)0); + + m_dolby->setMusicDolbyRoom(-1); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)0); + m_dolby->setMusicDolbyRoom(0); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)0); + m_dolby->setMusicDolbyRoom(1); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)1); + m_dolby->setMusicDolbyRoom(2); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)2); + m_dolby->setMusicDolbyRoom(3); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)3); + m_dolby->setMusicDolbyRoom(4); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)4); + m_dolby->setMusicDolbyRoom(5); + QCOMPARE(m_dolby->getMusicDolbyRoom(), (int)4); + + m_dolby->setMusicDolbyColor(-1); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)0); + m_dolby->setMusicDolbyColor(0); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)0); + m_dolby->setMusicDolbyColor(1); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)1); + m_dolby->setMusicDolbyColor(2); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)2); + m_dolby->setMusicDolbyColor(3); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)3); + m_dolby->setMusicDolbyColor(4); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)4); + m_dolby->setMusicDolbyColor(5); + QCOMPARE(m_dolby->getMusicDolbyColor(), (int)4); + + m_dolby->setVideoDolbyState(0); + QCOMPARE(m_dolby->getVideoDolbyState(), (uint)0); + m_dolby->setVideoDolbyState(1); + QCOMPARE(m_dolby->getVideoDolbyState(), (uint)1); + m_dolby->setVideoDolbyState(2); + QCOMPARE(m_dolby->getVideoDolbyState(), (uint)2); + m_dolby->setVideoDolbyState(3); + QCOMPARE(m_dolby->getVideoDolbyState(), (uint)0); + + m_dolby->setVideoDolbyRoom(-1); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)0); + m_dolby->setVideoDolbyRoom(0); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)0); + m_dolby->setVideoDolbyRoom(1); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)1); + m_dolby->setVideoDolbyRoom(2); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)2); + m_dolby->setVideoDolbyRoom(3); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)3); + m_dolby->setVideoDolbyRoom(4); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)4); + m_dolby->setVideoDolbyRoom(5); + QCOMPARE(m_dolby->getVideoDolbyRoom(), (int)4); + + m_dolby->setVideoDolbyColor(-1); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)0); + m_dolby->setVideoDolbyColor(0); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)0); + m_dolby->setVideoDolbyColor(1); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)1); + m_dolby->setVideoDolbyColor(2); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)2); + m_dolby->setVideoDolbyColor(3); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)3); + m_dolby->setVideoDolbyColor(4); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)4); + m_dolby->setVideoDolbyColor(5); + QCOMPARE(m_dolby->getVideoDolbyColor(), (int)4); +} + +QTEST_MAIN(Ut_MafwGstRendererDolby) + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.h new file mode 100644 index 0000000..3071730 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.h @@ -0,0 +1,39 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERERDOLBY_H_ +#define UT_MAFWGSTRENDERERDOLBY_H_ + +#include + +class MafwGstRendererDolby; + +class Ut_MafwGstRendererDolby: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + void testDolby(); + +private: + + MafwGstRendererDolby* m_dolby; +}; + +#endif /*UT_MAFWGSTRENDERERDOLBY_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.pro new file mode 100644 index 0000000..b01065c --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererDolby/ut_MafwGstRendererDolby.pro @@ -0,0 +1,33 @@ +TEMPLATE = app +TARGET = +QT -= gui +CONFIG = console +INCLUDEPATH += . +MAFW_GST_INCDIR = ../../inc +UT_COMMONDIR = ../common +INCLUDEPATH += $$MAFW_GST_INCDIR \ + $$UT_COMMONDIR +DEPENDPATH += . \ + ../../inc \ + ../../src +CONFIG += qtestlib \ + qt \ + link_pkgconfig \ + debug +PKGCONFIG += qmafw \ + gq-gconf \ + libpulse-mainloop-glib +LIBS += -lgcov \ + -ldbus-qeventloop +QMAKE_CXXFLAGS += -fprofile-arcs \ + -ftest-coverage \ + -O0 -Werror +QMAKE_CFLAGS += -fprofile-arcs \ + -ftest-coverage \ + -O0 -Werror + +# Input +HEADERS += ut_MafwGstRendererDolby.h \ + MafwGstRendererDolby.h +SOURCES += ut_MafwGstRendererDolby.cpp \ + MafwGstRendererDolby.cpp diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.cpp new file mode 100644 index 0000000..6686401 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.cpp @@ -0,0 +1,90 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ +#include "ut_MafwGstRendererNetworkMonitor.h" +#include "MafwGstRendererNetworkMonitor.h" +#include "QNetworkStubs.h" + +#include +#include + +extern NetworkStubHelper networkStub; + +void Ut_MafwGstRendererNetworkMonitor::initTestCase() +{ + +} + +void Ut_MafwGstRendererNetworkMonitor::cleanupTestCase() +{ + +} + +void Ut_MafwGstRendererNetworkMonitor::testPrepareNetworkChangeSignal() +{ + MafwGstRendererNetworkMonitor monitor; + QNetworkConfiguration config; + + QSignalSpy networkChangeFinished(&monitor, SIGNAL(networkChangeFinished())); + + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Active); + + QCOMPARE(networkChangeFinished.size(), 1); +} + +void Ut_MafwGstRendererNetworkMonitor::testOfflineSignal() +{ + networkStub.currentCreatedConfigIsValid = false; + MafwGstRendererNetworkMonitor monitor; + networkStub.currentCreatedConfigIsValid = true; + + QSignalSpy prepareNetworkChangeSpy(&monitor, SIGNAL(prepareNetworkChange())); + + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + QCOMPARE(prepareNetworkChangeSpy.size(), 1); + + //first activate + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Active); + //then set it not active + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + QCOMPARE(prepareNetworkChangeSpy.size(), 2); + +} + +void Ut_MafwGstRendererNetworkMonitor::testConfigChanges() +{ + MafwGstRendererNetworkMonitor monitor; + QSignalSpy networkChangeSpy(&monitor, SIGNAL(prepareNetworkChange())); + QSignalSpy networkChangeFinished(&monitor, SIGNAL(networkChangeFinished())); + + QNetworkConfiguration config; + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Active); + QNetworkConfiguration config2; + networkStub.emitConfigurationChange(config2, QNetworkConfiguration::Active); + networkStub.emitConfigurationChange(config, QNetworkConfiguration::Discovered); + + QCOMPARE(networkChangeFinished.size(), 2); + QCOMPARE(networkChangeSpy.size(), 0); + + networkStub.emitConfigurationChange(config2, QNetworkConfiguration::Discovered); + QCOMPARE(networkChangeSpy.size(), 1); +} + +QTEST_MAIN(Ut_MafwGstRendererNetworkMonitor) + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.h new file mode 100644 index 0000000..86dabaa --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.h @@ -0,0 +1,37 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERERNETWORKMONITOR_H_ +#define UT_MAFWGSTRENDERERNETWORKMONITOR_H_ + +#include + + +class Ut_MafwGstRendererNetworkMonitor: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void testPrepareNetworkChangeSignal(); + void testOfflineSignal(); + void testConfigChanges(); +}; + +#endif /*UT_MAFWGSTRENDERERNETWORKMONITOR_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.pro new file mode 100644 index 0000000..4204b01 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererNetworkMonitor/ut_MafwGstRendererNetworkMonitor.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = +CONFIG = console +QT -= gui + +INCLUDEPATH += . +MAFW_GST_INCDIR = ../../inc +UT_COMMONDIR = ../common + +INCLUDEPATH += $$MAFW_GST_INCDIR $$UT_COMMONDIR +DEPENDPATH += . ../../inc ../../src + +CONFIG += qtestlib qt link_pkgconfig debug +PKGCONFIG += qmafw +LIBS += -lgcov + +QMAKE_CXXFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Wall -Werror +QMAKE_CFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Wall -Werror + +# Input +HEADERS += ut_MafwGstRendererNetworkMonitor.h \ + MafwGstRendererNetworkMonitor.h \ + /usr/include/qt4/QtNetwork/qnetworkconfigmanager.h \ + $$UT_COMMONDIR/QNetworkStubs.h + +SOURCES += ut_MafwGstRendererNetworkMonitor.cpp \ + MafwGstRendererNetworkMonitor.cpp \ + $$UT_COMMONDIR/QNetworkStubs.cpp diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.cpp new file mode 100644 index 0000000..f6d7174 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.cpp @@ -0,0 +1,285 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "Ut_MafwGstRendererPlugin.h" +#include "MafwGstRendererPlugin.h" +#include "MafwGstRenderer.h" +#include "MafwGstRendererVolume.h" +#include "MafwGstRendererDolby.h" +#include "../common/MafwStubHelper.h" + +Q_DECLARE_METATYPE(MafwRenderer*) + +extern void setStubHelper(MafwStubHelper* stubHlp); +QMap renderers; +int renderer_index = 0; + +void Ut_MafwGstRendererPlugin::initTestCase() +{ + qRegisterMetaType(); + m_stubHelper = new MafwStubHelper; + setStubHelper(m_stubHelper); + + m_plugin = new MafwGstRendererPlugin(); +} + +void Ut_MafwGstRendererPlugin::testInProcess() +{ + QSignalSpy addedSpy( MafwRegistry::instance(), SIGNAL(rendererAdded(const QString&, const QString&)) ); + QSignalSpy removedSpy( MafwRegistry::instance(), SIGNAL(rendererRemoved(const QString&, const QString&)) ); + //MafwBasicRenderer::initialize is called twice: + //from its own constructor and from MafwGstRenderer::initialize + + //Basic renderer initialize fails + m_stubHelper->expect("initialize", false); + m_stubHelper->expect("initialize", false); + m_plugin->initialize( MafwInternalRegistry::internalInstance() ); + QCOMPARE( addedSpy.size(), 0 ); + addedSpy.clear(); + removedSpy.clear(); + + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + m_plugin->initialize( MafwInternalRegistry::internalInstance() ); + QCOMPARE( addedSpy.size(), 1 ); + QCOMPARE( removedSpy.size(), 0 ); + QVariantList arguments = addedSpy.takeFirst(); + + QString uuid = arguments.at(0).toString(); + QCOMPARE(uuid, QString("mafw_gst_renderer")); + QCOMPARE(arguments.at(1).toString(), QString("QMAFW GStreamer Renderer")); + + MafwRenderer* rnd = MafwRegistry::instance()->renderer(uuid); + QVERIFY(rnd != 0); + QCOMPARE(rnd->pluginName(), m_plugin->name()); + + MafwInternalRegistry::internalInstance()->removeExtension(uuid); + QCOMPARE( removedSpy.size(), 1 ); +} + +void Ut_MafwGstRendererPlugin::testOutProcess() +{ + QCoreApplication::setApplicationName("qmafw-dbus-wrapper"); + //TODO empty settings case + + renderers.insert("mafw-gst-renderer", "Mafw-GStreamer-Renderer"); + renderers.insert("mafw-gst-video-suite-renderer", "Mafw-GStreamer-Renderer-For-Video"); + + QSignalSpy addedSpy( MafwRegistry::instance(), SIGNAL(rendererAdded(const QString&, const QString&)) ); + QSignalSpy removedSpy( MafwRegistry::instance(), SIGNAL(rendererRemoved(const QString&, const QString&)) ); + //MafwBasicRenderer::initialize is called twice: + //from its own constructor and from MafwGstRenderer::initialize + + //Basic renderer initialize fails + m_stubHelper->expect("initialize", false); + m_stubHelper->expect("initialize", false); + m_stubHelper->expect("initialize", false); + m_stubHelper->expect("initialize", false); + m_plugin->initialize( MafwInternalRegistry::internalInstance() ); + QCOMPARE( addedSpy.size(), 0 ); + addedSpy.clear(); + removedSpy.clear(); + + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + m_plugin->initialize( MafwInternalRegistry::internalInstance() ); + QCOMPARE( addedSpy.size(), 2 ); + QCOMPARE( removedSpy.size(), 0 ); + + QVariantList arguments = addedSpy.takeFirst(); + QString uuid1 = arguments.at(0).toString(); + QString name1 = arguments.at(1).toString(); + arguments = addedSpy.takeFirst(); + QString uuid2 = arguments.at(0).toString(); + QString name2 = arguments.at(1).toString(); + + MafwRenderer* rnd1 = MafwRegistry::instance()->renderer(uuid1); + QVERIFY(rnd1 != 0); + QCOMPARE(rnd1->pluginName(), m_plugin->name()); + MafwRenderer* rnd2 = MafwRegistry::instance()->renderer(uuid2); + QVERIFY(rnd2 != 0); + QCOMPARE(rnd2->pluginName(), m_plugin->name()); + + QCOMPARE(uuid1, rnd1->uuid()); + QCOMPARE(name1, rnd1->name()); + QCOMPARE(uuid2, rnd2->uuid()); + QCOMPARE(name2, rnd2->name()); + + MafwInternalRegistry::internalInstance()->removeExtension(uuid1); + MafwInternalRegistry::internalInstance()->removeExtension(uuid2); + + // Test huge amount of renderers + renderers.clear(); + addedSpy.clear(); + removedSpy.clear(); + for(int i = 0; i < 100; i++) + { + QString rndId = QString("rndId %1").arg(i); + QString rndName = QString("rndName %1").arg(i); + renderers.insert(rndId, rndName); + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + } + m_plugin->initialize( MafwInternalRegistry::internalInstance()); + QCOMPARE(removedSpy.size(), 0); + QCOMPARE(addedSpy.size(), 100); + + // Let's only remove 99 renderers + for(int i = 0; i < 99; i++) + { + QString rndId = QString("rndId %1").arg(i); + MafwInternalRegistry::internalInstance()->removeExtension(rndId); + } + QCOMPARE(removedSpy.size(), 99); + // Check that there is still one renderer left + MafwRenderer* rnd99 = MafwRegistry::instance()->renderer("rndId 99"); + QVERIFY(rnd99 != 0); + MafwInternalRegistry::internalInstance()->removeExtension("rndId 99"); + + addedSpy.clear(); + removedSpy.clear(); + + //Test no renderers + renderers.clear(); + m_plugin->initialize(MafwInternalRegistry::internalInstance()); + QCOMPARE(addedSpy.size(), 0); + + //Test 2 renderers with same uuid and name + renderers.insert("rndId1", "rndName1"); + renderers.insert("rndId1", "rndName1"); + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", true); + m_stubHelper->expect("initialize", false); + m_stubHelper->expect("initialize", false); + m_plugin->initialize( MafwInternalRegistry::internalInstance()); + QCOMPARE(addedSpy.size(), 1); + +} + +void Ut_MafwGstRendererPlugin::cleanupTestCase() +{ + delete m_plugin; + while(QCoreApplication::hasPendingEvents()) + { + QCoreApplication::sendPostedEvents(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + } +} + +void gst_init(int *argc, char **argv[]) +{ + Q_UNUSED(argc); + Q_UNUSED(argv); +} + +QTEST_MAIN(Ut_MafwGstRendererPlugin) + +//Volume stub +MafwGstRendererVolume::MafwGstRendererVolume() +{ + qDebug() << "Volume stub ctor"; +} + +void MafwGstRendererVolume::connectToPulseAudio() +{ +} + +MafwGstRendererVolume::~MafwGstRendererVolume() +{ +} + +uint MafwGstRendererVolume::getVolume() +{ + qDebug(__PRETTY_FUNCTION__); + return (uint)1; +} + +bool MafwGstRendererVolume::setVolume (uint value) +{ + Q_UNUSED(value); + return true; +} + +//QSettings stub +QSettings::QSettings( const QString&, const QString&, QObject* ){} +//Hope we will never need below ctor stub, because it is used somehow by unit test framework. +//QSettings::QSettings(QSettings::Scope, const QString&, const QString&, QObject*){} +QSettings::QSettings(QSettings::Format, QSettings::Scope, const QString&, const QString&, QObject*){} +QSettings::QSettings(const QString&, QSettings::Format, QObject*){} +QSettings::QSettings(QObject*){} +QSettings::~QSettings(){} + +QVariant QSettings::value(const QString& key, const QVariant& ) const +{ + if(renderers.size() == 0) + { + return QString(); + } + QMap::const_iterator renderers_iterator = renderers.constBegin(); + for(int i = 0; i < renderer_index; i++) + { + renderers_iterator++; + } + + if(key == "Id") + { + return renderers_iterator.key(); + } + else + { + return renderers_iterator.value(); + } +} + +int QSettings::beginReadArray(const QString&) +{ + return renderers.count(); +} + +void QSettings::setArrayIndex(int i) +{ + renderer_index = i; +} + +void QSettings::endArray() +{ +} + +void QSettings::beginGroup(const QString &prefix) +{ + Q_UNUSED(prefix); +} + +void QSettings::endGroup() +{ + +} + +bool QSettings::contains(const QString &key) const +{ + return true; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.h new file mode 100644 index 0000000..3a04214 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/Ut_MafwGstRendererPlugin.h @@ -0,0 +1,45 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERERPLUGIN_H +#define UT_MAFWGSTRENDERERPLUGIN_H + +#include + +class MafwBasicRenderer; +class MafwGstRendererPlugin; +class MafwRenderer; +class MafwStubHelper; + +class Ut_MafwGstRendererPlugin: public QObject +{ + Q_OBJECT + +private Q_SLOTS: // tests + + void initTestCase(); + void testInProcess(); + void testOutProcess(); + void cleanupTestCase(); + +private: + MafwGstRendererPlugin* m_plugin; + MafwStubHelper* m_stubHelper; + +}; + +#endif // UT_MAFWGSTRENDERERPLUGIN_H diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/ut_MafwGstRendererPlugin.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/ut_MafwGstRendererPlugin.pro new file mode 100644 index 0000000..b736c3e --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererPlugin/ut_MafwGstRendererPlugin.pro @@ -0,0 +1,57 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Thu Nov 19 11:32:17 2009 +###################################################################### + +TEMPLATE = app +QT += network +QT -=gui + +CONFIG = console + +TARGET = +MAFW_GST_INCDIR = ../../inc +DEPENDPATH += . $$MAFW_GST_INCDIR ../../src +INCLUDEPATH += . $$MAFW_GST_INCDIR /usr/include/qmafw + +CONFIG += qtestlib no_keywords +CONFIG += qt link_pkgconfig debug +PKGCONFIG += qmafw glib-2.0 gobject-2.0 gio-2.0 gio-unix-2.0 usb_moded QtSparql +PKGCONFIG += contextprovider-1.0 x11 gstreamer-tag-0.10 gq-gconf libpulse-mainloop-glib qmsystem2 contextsubscriber-1.0 +LIBS += -lgcov + +QMAKE_CXXFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Werror +QMAKE_CFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Werror + +# Input +HEADERS += Ut_MafwGstRendererPlugin.h \ + MafwGstRendererPlugin.h \ + MafwGstRenderer.h \ + MafwGstRendererVolume.h \ + MafwGstRendererDolby.h \ + MafwBlankingPreventer.h \ + MafwGstRendererNetworkMonitor.h \ + MafwGstRendererPlaylistFileUtility.h \ + MafwMmcMonitor.h \ + MafwGstScreenshot.h \ + MafwGstRendererHaltState.h \ + mafw-gst-renderer-worker.h \ + mafw-gst-renderer-utils.h \ + ../common/MafwStubHelper.h \ + ../common/MafwRendererPolicyStub.h + +SOURCES += Ut_MafwGstRendererPlugin.cpp \ + MafwGstRendererPlugin.cpp \ + MafwGstRenderer.cpp \ + MafwGstRendererDolby.cpp \ + MafwGstRendererNetworkMonitor.cpp \ + MafwBlankingPreventer.cpp \ + MafwMmcMonitor.cpp \ + MafwGstScreenshot.cpp \ + MafwGstRendererHaltState.cpp \ + mafw-gst-renderer-utils.c \ + ../common/renderer-worker-stub.c \ + ../common/MafwStubHelper.cpp \ + ../common/MafwBasicRendererStub.cpp \ + ../common/MafwRendererPolicyStub.cpp \ + ../common/MafwPlaylistFileUtilityStub.cpp + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.cpp new file mode 100644 index 0000000..8d34d64 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.cpp @@ -0,0 +1,196 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "ut_MafwGstRendererSeeker.h" + +#include + +Q_DECLARE_METATYPE(QList); + +extern gint64 g_currentPosition; +extern gint64 g_duration; +extern gint64 g_seekRequested; +extern gint g_seeksCalled; + +void Ut_MafwGstRendererSeeker::initTestCase() +{ + g_type_init(); +} + +void Ut_MafwGstRendererSeeker::cleanupTestCase() +{ +} + +void Ut_MafwGstRendererSeeker::init() +{ + m_seeker = mafw_gst_renderer_seeker_new(); + mafw_gst_renderer_seeker_set_pipeline(m_seeker, (GstElement*)(313)); +} + +void Ut_MafwGstRendererSeeker::cleanup() +{ + mafw_gst_renderer_seeker_free(m_seeker); + + g_currentPosition = -1; + g_duration = -1; + g_seekRequested = -1; + g_seeksCalled = 0; +} + + + +void Ut_MafwGstRendererSeeker::testSeekSuccess() +{ + QFETCH(qint64, startPosition); + QFETCH(qint64, seekTo); + QFETCH(qint64, seekGoesTo); + QFETCH(qint64, mediaDuration); + + g_duration = mediaDuration; + g_currentPosition = startPosition; + + mafw_gst_renderer_seeker_seek_to(m_seeker, seekTo); + QCOMPARE(g_seekRequested, seekTo); + + g_currentPosition = seekGoesTo; + + gint64 newSeekPos = mafw_gst_renderer_seeker_process(m_seeker); + + // only one seek operation should be called when successful + QCOMPARE(g_seeksCalled, 1); + QCOMPARE(newSeekPos, -1ll); +} + +void Ut_MafwGstRendererSeeker::testSeekSuccess_data() +{ + QTest::addColumn("startPosition"); + QTest::addColumn("seekTo"); + QTest::addColumn("seekGoesTo"); + QTest::addColumn("mediaDuration"); + + QTest::newRow("1") << 0ll << 20ll << 21ll << 30ll; + QTest::newRow("1a") << 0ll << 19ll << 21ll << 30ll; + QTest::newRow("2") << 5ll << 1ll << 2ll << 10ll; + QTest::newRow("3") << 100ll << 150ll << 119ll << 120ll; + + //intentionally messed values + QTest::newRow("weird1") << 4ll << 1ll << 1ll << 2ll; + QTest::newRow("weird2") << -13ll << 13ll << 12ll << 0ll; + QTest::newRow("weird2") << 10ll << 5ll << 4ll << 1ll; +} + + +void Ut_MafwGstRendererSeeker::testSeekFails() +{ + QFETCH(qint64, startPosition); + QFETCH(qint64, seekTo); + QFETCH(QList, processedSeekRequests); + QFETCH(QList, seekGoesTo); + QFETCH(qint64, mediaDuration); + + g_duration = mediaDuration; + g_currentPosition = startPosition; + + mafw_gst_renderer_seeker_seek_to(m_seeker, seekTo); + QCOMPARE(g_seekRequested, seekTo); + + qint64 newSeekPos = 0; + int i = 0; + + while( true ) + { + g_currentPosition = seekGoesTo.at(i); + newSeekPos = mafw_gst_renderer_seeker_process(m_seeker); + + if( newSeekPos == -1 ) + { + break; + } + + QCOMPARE(newSeekPos, processedSeekRequests.at(i)); + QCOMPARE(g_seekRequested, processedSeekRequests.at(i)); + ++i; + } + + qint64 lastSeekPos = mafw_gst_renderer_seeker_process(m_seeker); + QCOMPARE( lastSeekPos, -1ll); + QCOMPARE( g_seeksCalled, seekGoesTo.size()); +} + +void Ut_MafwGstRendererSeeker::testSeekFails_data() +{ + QTest::addColumn("startPosition"); + QTest::addColumn("seekTo"); + QTest::addColumn >("processedSeekRequests"); + QTest::addColumn >("seekGoesTo"); + QTest::addColumn("mediaDuration"); + + QTest::newRow("Second seek is close enough") + << 0ll // position where seeking start + << 20ll // the seek request + << (QList() << 30 ) // list of processed seek request affected by the seekGoesTo list + << (QList() << 1 << 31 ) // list of resulting seeks to gst_element_seek() + << 35ll; //affects when seek processing should stop + + QTest::newRow("Fourth seek forward required") + << 5ll // position where seeking start + << 20ll // the seek request + << (QList() << 30 << 40 << 50 ) // list of processed seek request affected by the seekGoesTo list + << (QList() << 1 << 2 << 6 << 15 ) // list of resulting positions after calling gst_element_seek() + << 70ll; //affects when seek processing should stop + + // backward seeks assume that key_frame seeks will always seek at least to the requested position most likely earlier + // such backward seeks that would not reach at least the required position succeed anyway + QTest::newRow("backward seek fails") + << 20ll // position where seeking start + << 10ll // the seek request + << (QList() ) // list of processed seek request affected by the seekGoesTo list + << (QList() << 0 ) // list of resulting positions after calling gst_element_seek() + << 70ll; //affects when seek processing should stop + + QTest::newRow("backward seek fails 2") + << 20ll // position where seeking start + << 10ll // the seek request + << (QList() ) // list of processed seek request affected by the seekGoesTo list + << (QList() << 15 ) // list of resulting positions after calling gst_element_seek() + << 70ll; //affects when seek processing should stop + + QTest::newRow("Seek over media duration cancelled when processing") + << 5ll // position where seeking start + << 20ll // the seek request + << (QList()) // list of processed seek request affected by the seekGoesTo list + << (QList() << 5 ) // list of resulting positions after calling gst_element_seek() + << 25ll; //affects when seek processing should stop + + QTest::newRow("Test accuracy, first fails just by an inch") + << 5ll // position where seeking start + << 20ll // the seek request + << (QList() << 30) // list of processed seek request affected by the seekGoesTo list + << (QList() << 6 << 7) // list of resulting positions after calling gst_element_seek() + << 35ll; //affects when seek processing should stop + + QTest::newRow("Test accuracy 1, first fails just by an inch") + << 5ll // position where seeking start + << 20ll // the seek request + << (QList() << 30) // list of processed seek request affected by the seekGoesTo list + << (QList() << 6 << 7) // list of resulting seeks to gst_element_seek() + << 35ll; //affects when seek processing should stop + +} + + +QTEST_MAIN(Ut_MafwGstRendererSeeker) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.h new file mode 100644 index 0000000..93eb2c8 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.h @@ -0,0 +1,45 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERERSEEKER_H_ +#define UT_MAFWGSTRENDERERSEEKER_H_ + +#include + +#include "mafw-gst-renderer-seeker.h" + +class Ut_MafwGstRendererSeeker : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void testSeekSuccess(); + void testSeekSuccess_data(); + void testSeekFails(); + void testSeekFails_data(); + + +private: + MafwGstRendererSeeker *m_seeker; +}; + +#endif /*UT_MAFWGSTRENDERERSEEKER_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.pro new file mode 100644 index 0000000..f56967a --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +QT -= gui +CONFIG = console + +isEmpty(PREFIX) { + PREFIX=/usr +} + +CONFIG += qt link_pkgconfig debug +CONFIG += qtestlib +PKGCONFIG += glib-2.0 gobject-2.0 + +LIBS += -lgcov + +DEPENDPATH += . ../../src ../../inc +INCLUDEPATH += . ../../inc $$system(pkg-config --variable=includedir gstreamer-0.10) + +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g $$system(pkg-config --cflags gstreamer-0.10) +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g $$system(pkg-config --cflags gstreamer-0.10) + +QMAKE_CLEAN += *.gcda *.gcno *.gcov ut_MafwGstRendererSeeker *.vg.xml vgcore.* + +HEADERS += mafw-gst-renderer-seeker.h \ + ut_MafwGstRendererSeeker.h + +SOURCES += mafw-gst-renderer-seeker.c \ + ut_MafwGstRendererSeeker_stubs.c \ + ut_MafwGstRendererSeeker.cpp diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker_stubs.c b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker_stubs.c new file mode 100644 index 0000000..04d3cde --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererSeeker/ut_MafwGstRendererSeeker_stubs.c @@ -0,0 +1,55 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include + +#include + +gint64 g_currentPosition; +gint64 g_duration; +gint64 g_seekRequested; +gint g_seeksCalled; + +gboolean gst_element_query_position(GstElement *element, + GstFormat *format, + gint64 *value) +{ + *value = g_currentPosition * GST_SECOND; + return TRUE; +} + +gboolean gst_element_query_duration(GstElement *element, + GstFormat *format, + gint64 *value) +{ + *value = g_duration * GST_SECOND; + return TRUE; +} + +gboolean gst_element_seek(GstElement *element, + gdouble rate, + GstFormat format, + GstSeekFlags flags, + GstSeekType cur_type, + gint64 cur, + GstSeekType stop_type, + gint64 stop) +{ + g_seekRequested = cur / GST_SECOND; + ++g_seeksCalled; + return TRUE; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/MafwVolumeStubs.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/MafwVolumeStubs.cpp new file mode 100644 index 0000000..6715ea9 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/MafwVolumeStubs.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include "MafwStubHelper.h" + +char obj_path[] = "/org/pulseaudio/stream_restore1/entry7"; + +MafwStubHelper* m_stubHelper = 0; +void* m_user_data; +DBusHandleMessageFunction m_signalCb; +DBusPendingCallNotifyFunction m_restoreObjectCb = 0; +DBusPendingCallNotifyFunction m_volumeCb = 0; +DBusMessage* m_getVolumeMethodCall = 0; +DBusMessage* m_setVolumeMethod = 0; + +QMap m_volumes; + +void setStubHelper(MafwStubHelper* stubHlp) +{ + m_stubHelper = stubHlp; +} + +dbus_bool_t dbus_error_is_set(const DBusError* error) +{ + Q_UNUSED(error); + return m_stubHelper->getReturn("dbus_error_is_set").toBool(); +} + +struct DBusConnection +{ + int aField; +}; + +DBusConnection* dbus_connection_open(const char *address, DBusError *error) +{ + DBusConnection* conn = 0; + + if (m_stubHelper->getReturn("dbus_connection_open").toBool()) + { + conn = static_cast( malloc(sizeof(DBusConnection)) ); + } + Q_UNUSED(address); + Q_UNUSED(error); + return conn; +} + +void dbus_connection_unref(DBusConnection* conn) +{ + if (conn) + { + free(conn); + } +} + +bool DBUSConnectionEventLoop::addConnection(DBusConnection* conn) +{ + Q_UNUSED(conn); + + return m_stubHelper->getReturn("addConnection").toBool(); +} + +void DBUSConnectionEventLoop::removeConnection(DBusConnection* conn) +{ + Q_UNUSED(conn); + + m_stubHelper->getReturn("removeConnection"); +} + +dbus_bool_t dbus_connection_add_filter(DBusConnection* connection, + DBusHandleMessageFunction function, + void* user_data, + DBusFreeFunction free_data_function) +{ + Q_UNUSED(connection); + Q_UNUSED(free_data_function); + m_signalCb = function; + m_user_data = user_data; + return true; +} + +void dbus_pending_call_cancel(DBusPendingCall* pending) +{ + Q_UNUSED(pending); +} + +dbus_bool_t dbus_set_error_from_message(DBusError* error, DBusMessage* message) +{ + Q_UNUSED(error); + Q_UNUSED(message); + return m_stubHelper->getReturn("dbus_set_error_from_message").toBool(); +} + +void signalVolumeUpdated(uint channel, uint value) +{ + DBusMessage* message = dbus_message_new_signal(obj_path, "org.PulseAudio.Ext.StreamRestore1.RestoreEntry", "VolumeUpdated"); + + DBusMessageIter argument_iterator, variant_iterator, struct_iterator; + dbus_message_iter_init_append (message, &argument_iterator); + dbus_message_iter_open_container (&argument_iterator, + DBUS_TYPE_VARIANT, + "(uu)", + &variant_iterator); + dbus_message_iter_open_container (&variant_iterator, + DBUS_TYPE_STRUCT, + NULL, + &struct_iterator); + + dbus_message_iter_append_basic (&struct_iterator, DBUS_TYPE_UINT32, &channel); + dbus_message_iter_append_basic (&struct_iterator, DBUS_TYPE_UINT32, &value); + + dbus_message_iter_close_container (&variant_iterator, &struct_iterator); + dbus_message_iter_close_container (&argument_iterator, &variant_iterator); + + DBusConnection* conn = 0; + (*m_signalCb)(conn, message, m_user_data); + dbus_message_unref(message); +} + +struct DBusPendingCall +{ + uint a; +}; + +dbus_bool_t dbus_connection_send_with_reply(DBusConnection* connection, + DBusMessage* message, + DBusPendingCall ** pending_return, + int timeout_milliseconds) +{ + DBusPendingCall pending; + *pending_return = &pending; + Q_UNUSED(connection); + m_getVolumeMethodCall = message; + Q_UNUSED(pending_return); + Q_UNUSED(timeout_milliseconds); + return true; +} + +// Saves callback function pointer. Assumes that first call gives callback for +// GetEntryByName and the second one gives callback for Get Volume +dbus_bool_t dbus_pending_call_set_notify( DBusPendingCall* pending, + DBusPendingCallNotifyFunction function, + void* user_data, + DBusFreeFunction free_user_data) +{ + if (!m_restoreObjectCb) + { + m_restoreObjectCb = function; + } + else + { + m_volumeCb = function; + } + + Q_UNUSED(pending); + Q_UNUSED(user_data); + Q_UNUSED(free_user_data); + return true; +} + +void giveRestoreEntryReply() +{ + DBusPendingCall pending; + (*m_restoreObjectCb) (&pending, m_user_data); +} + +void giveVolumeReply(QMap volumes) +{ + DBusPendingCall pending; + m_volumes = volumes; + (*m_volumeCb) (&pending, m_user_data); +} + +DBusMessage* dbus_pending_call_steal_reply(DBusPendingCall* pending) +{ + Q_UNUSED(pending); + bool replyForGetVolume = dbus_message_has_member (m_getVolumeMethodCall, "Get"); + DBusMessage* message = dbus_message_new_method_return(m_getVolumeMethodCall); + + qDebug() << "replyForGetVolume= " << replyForGetVolume; + qDebug() << "m_volumes.count()= " << m_volumes.count(); + if (replyForGetVolume) + { + qDebug() << "Jee"; + DBusMessageIter argument_iterator, variant_iterator, array_iterator; + dbus_message_iter_init_append (message, &argument_iterator); + dbus_message_iter_open_container (&argument_iterator, + DBUS_TYPE_VARIANT, + "a(uu)", + &variant_iterator); + dbus_message_iter_open_container (&variant_iterator, + DBUS_TYPE_ARRAY, + "(uu)", + &array_iterator); + if (m_volumes.isEmpty()) + { + qDebug() << "Stub is giving an invalid reply"; + } + else + { + QMapIterator i(m_volumes); + i.toBack(); + while (i.hasPrevious()) + { + DBusMessageIter iterator; + dbus_message_iter_open_container (&array_iterator, + DBUS_TYPE_STRUCT, + NULL, + &iterator); + i.previous(); + dbus_message_iter_append_basic (&iterator, DBUS_TYPE_UINT32, &i.key()); + dbus_message_iter_append_basic (&iterator, DBUS_TYPE_UINT32, &i.value()); + dbus_message_iter_close_container (&array_iterator, &iterator); + } + } + dbus_message_iter_close_container (&variant_iterator, &array_iterator); + dbus_message_iter_close_container (&argument_iterator, &variant_iterator); + } + return message; +} + +dbus_uint32_t dbus_message_get_serial(DBusMessage* message) +{ + Q_UNUSED(message); + return 1; +} + +dbus_bool_t dbus_message_get_args (DBusMessage* message, + DBusError* error, + int first_arg_type, + ...) +{ + qDebug() << "dbus_message_get_args"; + va_list var_args; + va_start (var_args, first_arg_type); + + while (first_arg_type != DBUS_TYPE_INVALID) + { + if (first_arg_type == DBUS_TYPE_OBJECT_PATH) + { + char** str_p; + str_p = va_arg (var_args, char**); + *str_p = obj_path; + } + first_arg_type = va_arg(var_args, int); + } + va_end(var_args); + Q_UNUSED(error); + Q_UNUSED(message); + return true; +} + +dbus_bool_t dbus_connection_send( DBusConnection* connection, + DBusMessage* message, + dbus_uint32_t* serial) +{ + Q_UNUSED(connection); + Q_UNUSED(serial); + + if (dbus_message_has_member (m_getVolumeMethodCall, "Set")) + { + m_setVolumeMethod = message; + } + + return true; +} + +void dbus_connection_flush( DBusConnection* connection) +{ + Q_UNUSED(connection); +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.cpp new file mode 100644 index 0000000..1558361 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.cpp @@ -0,0 +1,223 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ +#include "ut_MafwGstRendererVolume.h" + +#include +#include +#include + +#include "MafwGstRendererVolume.h" +#include "MafwStubHelper.h" + +extern void setStubHelper(MafwStubHelper* stubHlp); +extern void signalVolumeUpdated(uint channel, uint value); +extern void giveRestoreEntryReply(); +extern void giveVolumeReply(QMap volumes); +extern DBusMessage* m_setVolumeMethod; + +void Ut_MafwGstRendererVolume::initTestCase() +{ + m_stubHelper = new MafwStubHelper; + setStubHelper(m_stubHelper); + + //Tests the case where first pulseaudio connect fails and + //DBUSConnectionEventLoop::addConnection fails. + m_stubHelper->expect("dbus_connection_open", false); + m_stubHelper->expect("dbus_error_is_set", true); + m_volume = new MafwGstRendererVolume(); + QVERIFY(m_stubHelper->allCallsConsumed()); + //Wait that connecting to pulseaudio is retried + + m_stubHelper->expect("dbus_connection_open", true); + m_stubHelper->expect("dbus_error_is_set", false); + m_stubHelper->expect("addConnection", false); + QTest::qWait(3000); + QVERIFY(m_stubHelper->allCallsConsumed()); + + delete m_volume; + //Tests the successfull case + m_stubHelper->expect("dbus_connection_open", true); + m_stubHelper->expect("dbus_error_is_set", false); + m_stubHelper->expect("addConnection", true); + m_volume = new MafwGstRendererVolume(); + QVERIFY(m_stubHelper->allCallsConsumed()); +} + +void Ut_MafwGstRendererVolume::cleanupTestCase() +{ + m_stubHelper->expect("removeConnection", false); + delete m_volume; + QVERIFY(m_stubHelper->allCallsConsumed()); + delete m_stubHelper; +} + +void Ut_MafwGstRendererVolume::testVolumeReply() +{ + QMap map; +//Error reply for "GetEntryByName" + m_stubHelper->expect("dbus_set_error_from_message", true); + + //Pulseaudio reconnect is done + m_stubHelper->expect("removeConnection", false); + m_stubHelper->expect("dbus_connection_open", true); + m_stubHelper->expect("dbus_error_is_set", false); + m_stubHelper->expect("addConnection", true); + giveRestoreEntryReply(); + QTest::qWait(500); + QVERIFY(m_stubHelper->allCallsConsumed()); + QCOMPARE(m_volume->getVolume(), (uint)0); +//Error reply for "Get Volume" + m_stubHelper->expect("dbus_set_error_from_message", false); + m_stubHelper->expect("dbus_set_error_from_message", true); + giveRestoreEntryReply(); + giveVolumeReply(map); + QVERIFY(m_stubHelper->allCallsConsumed()); + QCOMPARE(m_volume->getVolume(), (uint)0); +//Invalid reply for "Get Volume" + m_stubHelper->expect("dbus_set_error_from_message", false); + m_stubHelper->expect("dbus_set_error_from_message", false); + giveRestoreEntryReply(); + giveVolumeReply(map); + QVERIFY(m_stubHelper->allCallsConsumed()); + QCOMPARE(m_volume->getVolume(), (uint)0); + +//Maximum value + giveRestoreEntryReply(); + map[0] = 0x10000; + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)100); +//Maximum value-1 + giveRestoreEntryReply(); + map[0] = 0x10000; + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)100); +//Value above range + giveRestoreEntryReply(); + map[0] = 0x10001; + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)100); +//Huge value + map[0] = 0xFF000; + giveRestoreEntryReply(); + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)100); +//Zero + map[0] = 0; + giveRestoreEntryReply(); + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)0); +//Many channels, containing mono channel + map[0] = 0x10000/2; + map[1] = 20; + map[2] = 30; + map[3] = 40; + giveRestoreEntryReply(); + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)50); +//Many channels, without mono channel + map.remove(0); + map[1] = 0x10000/3; + map[2] = 0x10000/4; + map[3] = 0x10000/5; + giveRestoreEntryReply(); + giveVolumeReply(map); + QCOMPARE(m_volume->getVolume(), (uint)(100/3)); +} + +void Ut_MafwGstRendererVolume::testSignal() +{ + QSignalSpy spy(m_volume, SIGNAL(volumeChanged(uint))); + QFETCH(uint, volume); + QFETCH(uint, channel); + // Volume updated signal gives volume level as pulse audio's native value + // Which has range 0 - 0x10000 + signalVolumeUpdated(channel, 0x10000*volume/100); + + QCOMPARE(spy.count(), 1); + QList arguments = spy.takeFirst(); + + if (volume > 100) //Volume must not be set out of range + { + volume = 100; + } + QCOMPARE(arguments.at(0).toUInt(), volume); + QCOMPARE(m_volume->getVolume(), volume); +} + +void Ut_MafwGstRendererVolume::testSignal_data() +{ + QTest::addColumn("volume"); + QTest::addColumn("channel"); + + QTest::newRow("Maximum value") << (uint)100 << (uint)0; + QTest::newRow("Maximum value -1") << (uint)99 << (uint)0; + QTest::newRow("Value above range") << (uint)101 << (uint)0; + QTest::newRow("Huge value") << (uint)-1 << (uint)0; + QTest::newRow("Zero") << (uint)0 << (uint)0; + QTest::newRow("One") << (uint)1 << (uint)0; + QTest::newRow("Another channel") << (uint)2 << (uint)1; +} + +//one MAFW volume step is 0x10000/100 = 655,36 native volume steps +void Ut_MafwGstRendererVolume::testSetVolume() +{ + QFETCH(uint, volume); + quint32 value = 1; + + m_volume->setVolume(volume); + QVERIFY(m_setVolumeMethod != 0); + DBusMessageIter iter, array_iterator, struct_iterator, value_iterator; + dbus_message_iter_init (m_setVolumeMethod, &iter); + QCOMPARE(dbus_message_iter_get_arg_type(&iter), DBUS_TYPE_STRING);//interface + dbus_message_iter_next(&iter); + QCOMPARE(dbus_message_iter_get_arg_type(&iter), DBUS_TYPE_STRING);//property + dbus_message_iter_next(&iter); + dbus_message_iter_recurse (&iter, &array_iterator); + QCOMPARE(dbus_message_iter_get_arg_type(&array_iterator), DBUS_TYPE_ARRAY); + dbus_message_iter_recurse (&array_iterator, &struct_iterator); + QCOMPARE(dbus_message_iter_get_arg_type(&struct_iterator), DBUS_TYPE_STRUCT); + + dbus_message_iter_recurse (&struct_iterator, &value_iterator); + QCOMPARE(dbus_message_iter_get_arg_type (&value_iterator), DBUS_TYPE_UINT32); + dbus_message_iter_get_basic (&value_iterator, &value); + QCOMPARE(value, (quint32)0); //mono channel + dbus_message_iter_next (&value_iterator); + QCOMPARE(dbus_message_iter_get_arg_type (&value_iterator), DBUS_TYPE_UINT32); + dbus_message_iter_get_basic (&value_iterator, &value); + + if (volume > 100) //Volume must not be set out of range + { + volume = 100; + } + + QCOMPARE(value, (quint32)(volume*0x10000/100)); +} + + +void Ut_MafwGstRendererVolume::testSetVolume_data() +{ + QTest::addColumn("volume"); + + QTest::newRow("Set volume to 0") << (uint)0; + QTest::newRow("Set volume to 1") << (uint)1; + QTest::newRow("Set volume to 99") << (uint)99; + QTest::newRow("Set volume to 100") << (uint)100; + QTest::newRow("Set volume to huge value") << (uint)-1; +} + +QTEST_MAIN(Ut_MafwGstRendererVolume) + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.h new file mode 100644 index 0000000..7ad1de6 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.h @@ -0,0 +1,46 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWGSTRENDERERVOLUME_H_ +#define UT_MAFWGSTRENDERERVOLUME_H_ + +#include + +class MafwGstRendererVolume; +class MafwStubHelper; + +class Ut_MafwGstRendererVolume: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void testVolumeReply(); + void testSignal(); + void testSignal_data(); + void testSetVolume(); + void testSetVolume_data(); + +private: + + MafwGstRendererVolume* m_volume; + MafwStubHelper* m_stubHelper; +}; + +#endif /*UT_MAFWGSTRENDERERVOLUME_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.pro new file mode 100644 index 0000000..f6f5a81 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererVolume/ut_MafwGstRendererVolume.pro @@ -0,0 +1,29 @@ +TEMPLATE = app +TARGET = +QT -= gui +CONFIG = console + +INCLUDEPATH += . +MAFW_GST_INCDIR = ../../inc +UT_COMMONDIR = ../common + +INCLUDEPATH += $$MAFW_GST_INCDIR $$UT_COMMONDIR +DEPENDPATH += . ../../inc ../../src + +CONFIG += qtestlib qt link_pkgconfig debug qdbus +PKGCONFIG += qmafw dbus-1 libpulse-mainloop-glib +LIBS += -lgcov -ldbus-qeventloop + +QMAKE_CXXFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Werror +QMAKE_CFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Werror + +# Input +HEADERS += ut_MafwGstRendererVolume.h \ + MafwGstRendererVolume.h \ + $$UT_COMMONDIR/MafwStubHelper.h + +SOURCES += ut_MafwGstRendererVolume.cpp \ + MafwVolumeStubs.cpp \ + MafwGstRendererVolume.cpp \ + $$UT_COMMONDIR/MafwStubHelper.cpp \ + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.avi b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.avi new file mode 100644 index 0000000..f868c62 Binary files /dev/null and b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.avi differ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.wav b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.wav new file mode 100644 index 0000000..943b040 Binary files /dev/null and b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/test.wav differ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/testframe.png b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/testframe.png new file mode 100644 index 0000000..a0db335 Binary files /dev/null and b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/media/testframe.png differ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.cpp new file mode 100644 index 0000000..b881ef7 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.cpp @@ -0,0 +1,1432 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "ut_MafwGstRendererWorker.h" +#include "mafw-gst-renderer-worker.h" +#include "mafw-gst-renderer-utils.h" + +static QUrl AUDIO_URI(QDir::currentPath() + QDir::separator() + + QString("media") + QDir::separator() + + QString("test.wav")); + +static QUrl VIDEO_URI(QDir::currentPath() + QDir::separator() + + QString("media") + QDir::separator() + + QString("test.avi")); + +static QUrl IMAGE_URI(QDir::currentPath() + QDir::separator() + + QString("media") + QDir::separator() + + QString("testframe.png")); + +static int WAIT_TIMEOUT = 3500; +static int EOS_TIMEOUT = 7000; +static int READY_DELAY = 65000; + +static bool NEVER_HAPPENING_EVENT = false; + +static int global_context_duration = 0; + +static QStringList globalGstFactoryRequests; +static GstElement *globalGstPipeline; + + +const gchar* g_getenv(const gchar *variable) +{ + Q_UNUSED(variable); + return NULL; +} + +gboolean convert_utf8(const gchar *src, gchar **dst) +{ + *dst = g_strdup(src); + return TRUE; +} + +gboolean uri_is_playlist(const gchar *uri) +{ + Q_UNUSED(uri); + return FALSE; +} + +gboolean uri_is_stream(const gchar *uri) +{ + Q_UNUSED(uri); + return FALSE; +} + +gint remap_gst_error_code(const GError *error) +{ + return error->code; +} + +void context_provider_set_map(const char* key, void* map, int free_map) +{ + Q_UNUSED(key); + Q_UNUSED(map); + Q_UNUSED(free_map); +} + +void *context_provider_map_new(void) +{ + + return NULL; +} + +void context_provider_map_free(void* map) +{ + Q_UNUSED(map); +} + +void context_provider_map_set_integer(void* map, const char* key, int value) +{ + Q_UNUSED(map); + + if( strcmp( key, "duration" )==0 ) + { + global_context_duration = value; + } +} + +void context_provider_map_set_double(void* map, const char* key, double value) +{ + Q_UNUSED(map); + Q_UNUSED(key); + Q_UNUSED(value); +} + +void context_provider_map_set_boolean(void* map, const char* key, int value) +{ + Q_UNUSED(map); + Q_UNUSED(key); + Q_UNUSED(value); +} + +void context_provider_map_set_string(void* map, const char* key, const char* value) +{ + Q_UNUSED(map); + Q_UNUSED(key); + Q_UNUSED(value); +} + +void context_provider_map_set_map(void* map, const char* key, void* value) +{ + Q_UNUSED(map); + Q_UNUSED(key); + Q_UNUSED(value); +} + +void context_provider_set_null(const char* key) +{ + Q_UNUSED(key); +} + +gboolean context_provider_init(DBusBusType bus_type, const char* bus_name) +{ + + Q_UNUSED(bus_type); + Q_UNUSED(bus_name); + + return TRUE; + +} + +void context_provider_stop(void) +{ +} + +void context_provider_install_key( + const char* key, + gboolean clear_values_on_subscribe, + ContextProviderSubscriptionChangedCallback subscription_changed_cb, + void* subscription_changed_cb_target) +{ + Q_UNUSED(key); + Q_UNUSED(clear_values_on_subscribe); + Q_UNUSED(subscription_changed_cb); + Q_UNUSED(subscription_changed_cb_target); +} + +GstElement *gst_element_factory_make(const gchar *factoryname, const gchar *name) +{ + GstElementFactory *factory; + GstElement *element; + const gchar *use_factoryname; + + g_return_val_if_fail(factoryname != NULL, NULL); + + globalGstFactoryRequests.append(factoryname); + + /* For testing, use playbin instead of playbin2 */ + if (g_str_equal(factoryname, "playbin2")) + { + use_factoryname = "playbin"; + } + else + { + use_factoryname = factoryname; + } + + GST_LOG("gstelementfactory: make \"%s\" \"%s\"", + use_factoryname, GST_STR_NULL (name)); + + factory = gst_element_factory_find(use_factoryname); + if (factory == NULL) + { + /* No factory */ + GST_INFO("no such element factory \"%s\"!", use_factoryname); + return NULL; + } + + GST_LOG_OBJECT(factory, "found factory %p", factory); + if (g_str_equal(use_factoryname, "pulsesink")) + { + element = gst_element_factory_make("fakesink", "pulsesink"); + g_object_set(G_OBJECT(element), "sync", TRUE, NULL); + } + else if (g_str_equal(use_factoryname, "alsasink")) + { + element = gst_element_factory_make("fakesink", "alsasink"); + g_object_set(G_OBJECT(element), "sync", TRUE, NULL); + } + else if (g_str_equal(use_factoryname, "xvimagesink") + || g_str_equal(use_factoryname, "omapxvsink")) + { + element = gst_element_factory_make("fakesink", "xvimagesink"); + g_object_set(G_OBJECT(element), "sync", TRUE, NULL); + } + else + { + element = gst_element_factory_create(factory, name); + if( !g_strcmp0(use_factoryname, "playbin") ) + { + globalGstPipeline = element; + } + } + gst_object_unref(factory); + + if (element == NULL) + { + /* Create failed */ + GST_INFO_OBJECT(factory, "couldn't create instance!"); + return NULL; + } + + GST_LOG("gstelementfactory: make \"%s\" \"%s\"",use_factoryname, + GST_STR_NULL(name)); + + /* Playbin will use fake renderer */ + if (g_str_equal(use_factoryname, "playbin")) + { + GstElement *audiorenderer = gst_element_factory_make("fakesink", + "audiorenderer"); + g_object_set(G_OBJECT(audiorenderer), "sync", TRUE, NULL); + g_object_set(G_OBJECT(element), "audio-sink", audiorenderer, NULL); + g_object_set(G_OBJECT(element), "video-sink", audiorenderer, NULL); + } + + return element; + +} +/* END OF STUB DEFINITIONS */ + +void ut_MafwGstRendererWorker::playCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + + Q_UNUSED(worker); + Q_UNUSED(owner); + qDebug() << __PRETTY_FUNCTION__; + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_gotPlayCallback = true; + +} + +void ut_MafwGstRendererWorker::pauseCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_gotPauseCallback = true; +} + +void ut_MafwGstRendererWorker::bufferingCallback(MafwGstRendererWorker *worker, + gpointer owner, + gdouble percent) +{ + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_receivedBufferStatus = percent; + self->m_gotBufferStatusCallback = true; +} + +void ut_MafwGstRendererWorker::eosCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_gotEosCallback = true; + +} + +void ut_MafwGstRendererWorker::seekCallback(MafwGstRendererWorker *worker, + gpointer owner) +{ + + Q_UNUSED(worker); + + qDebug() << __PRETTY_FUNCTION__; + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_gotSeekCallback = true; + +} + +void ut_MafwGstRendererWorker::errorCallback(MafwGstRendererWorker *worker, + gpointer owner, + const GError *error) +{ + + Q_UNUSED(worker); + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_receivedErrorCode = error->code; + + if (error) + { + qCritical() << "error code: " << error->code << " message: " << + error->message; + } + self->m_gotErrorCallback = true; + +} + +void ut_MafwGstRendererWorker::propertyCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint id, + GValue *value) +{ + + Q_UNUSED(worker); + Q_UNUSED(value); + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_receivedPropertyId = id; + self->m_gotPropertyCallback = true; + +} + +void ut_MafwGstRendererWorker::metadataCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint key, + GType type, + gpointer value) +{ + + Q_UNUSED(worker); + Q_UNUSED(type); + Q_UNUSED(value); + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_receivedMetadata.append(key); + self->m_gotMetadataCallback = true; + +} + +void ut_MafwGstRendererWorker::blankingControlCallback(MafwGstRendererWorker *worker, + gpointer owner, gboolean prohibit) +{ + Q_UNUSED(worker); + + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_blankingProhibited = prohibit; +} + +void ut_MafwGstRendererWorker::screenshotCallback(MafwGstRendererWorker *worker, + gpointer owner, GstBuffer *buffer, + const char *filename, gboolean cancel) +{ + Q_UNUSED(worker); + Q_UNUSED(buffer); + Q_UNUSED(filename); + if(!cancel) + { + ut_MafwGstRendererWorker* self = + static_cast(owner); + self->m_receivedMetadata.append(WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI); + self->m_gotMetadataCallback = true; + } +} + +void ut_MafwGstRendererWorker::basicPlaybackTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + QCOMPARE( global_context_duration, 3 ); // 2.5 seconds is duration of test.wav + QVERIFY(m_blankingProhibited == false); + + //video-sink should not be created unless XID has been set + QVERIFY(!m_worker->vsink); +} + +void ut_MafwGstRendererWorker::basicVideoPlaybackTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + QVERIFY(!m_worker->vsink); + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + QVERIFY(m_worker->vsink); + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + m_worker->media.has_visual_content = true; // normally gst sets this but not in unittest for some reason + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(m_blankingProhibited == true); +} + +void ut_MafwGstRendererWorker::pauseFrameTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_metadata_handler = &metadataCallback; + m_worker->notify_property_handler = &propertyCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + m_worker->screenshot_handler = screenshotCallback; + + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_current_frame_on_pause(m_worker) == + TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE); + + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + QVERIFY(mafw_gst_renderer_worker_get_xid(m_worker) == 0xffff); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_XID); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + + /* post xwindow-id on bus since we are using fakesink instead of + * xvimagesink */ + GstBus *bus; + GstStructure *structure; + GstMessage *message; + structure = gst_structure_new("prepare-xwindow-id", "width", + G_TYPE_INT, 64, "height", G_TYPE_INT, 32, + NULL); + message = gst_message_new_element(NULL, structure); + bus = m_worker->bus; + gst_bus_post(bus, message); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, NEVER_HAPPENING_EVENT); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotMetadataCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(m_receivedMetadata.contains(WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI)); + +} + +void ut_MafwGstRendererWorker::pauseFrameCancelTestCase() +{ + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_metadata_handler = &metadataCallback; + m_worker->notify_property_handler = &propertyCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + m_worker->screenshot_handler = screenshotCallback; + + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_current_frame_on_pause(m_worker) == + TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE); + + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + QVERIFY(mafw_gst_renderer_worker_get_xid(m_worker) == 0xffff); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_XID); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + + /* post xwindow-id on bus since we are using fakesink instead of + * xvimagesink */ + GstBus *bus; + GstStructure *structure; + GstMessage *message; + structure = gst_structure_new("prepare-xwindow-id", "width", + G_TYPE_INT, 64, "height", G_TYPE_INT, 32, + NULL); + message = gst_message_new_element(NULL, structure); + bus = m_worker->bus; + gst_bus_post(bus, message); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + mafw_gst_renderer_worker_resume(m_worker); + QTest::qWait(10); + + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotMetadataCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(!m_receivedMetadata.contains(WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI)); + + +} + +void ut_MafwGstRendererWorker::redirectMessageTestCase() +{ + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + /* We just give random uri to renderer, because we ignore the error */ + /* We don't have to test with real RTSP stream, we just use local content */ + char *control = qstrdup(VIDEO_URI.toString().toAscii()); + + GstStructure *structure; + GstMessage *message; + structure = gst_structure_new("redirect", "new-location", + G_TYPE_STRING, control, NULL); + + // reset and construct the pipeline + mafw_gst_renderer_worker_stop(m_worker); + + // when worker receives "redirect" message, it should start playing the uri contained in the message. + message = gst_message_new_element(GST_OBJECT_CAST(m_worker->pipeline), structure); + gst_element_post_message(m_worker->pipeline, message); + + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(strcmp(control, m_worker->media.location) == 0); + QVERIFY(m_gotErrorCallback == false); + + delete[] control; +} + +void ut_MafwGstRendererWorker::slotTimeOut() +{ + qDebug() << "TIMEOUT!"; +} + +void ut_MafwGstRendererWorker::waitForEvent(gint ms, bool &hasEventOccurred) + +{ + qDebug() << __PRETTY_FUNCTION__; + + if (hasEventOccurred) + { + return; + } + + QTimer timer(this); + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(slotTimeOut())); + timer.setSingleShot(true); + timer.start(ms); + + while (!hasEventOccurred && timer.isActive()) + { + g_main_context_iteration(NULL, TRUE); + } +} + +void ut_MafwGstRendererWorker::bufferingTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_buffer_status_handler = &bufferingCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + /* post the buffering msg on bus */ + GstBus *bus = 0; + GstMessage *message = 0; + + message = gst_message_new_buffering(NULL, 50); + bus = m_worker->bus; + gst_bus_post(bus, message); + + waitForEvent(WAIT_TIMEOUT, m_gotBufferStatusCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_receivedBufferStatus == 50); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::rendererArtTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_metadata_handler = &metadataCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + + /* post the renderer art tag on bus */ + gsize image_length = 0; + gchar *image = 0; + GstCaps *caps = 0; + GstBuffer *buffer = 0; + GstMessage *message = 0; + GstTagList *list = 0; + + QVERIFY(g_file_get_contents(IMAGE_URI.toLocalFile().toAscii(), + &image, + &image_length, + NULL)); + buffer = gst_buffer_new(); + gst_buffer_set_data(buffer, (guint8*)image, image_length); + caps = gst_caps_new_simple("image/png", "image-type", + GST_TYPE_TAG_IMAGE_TYPE, + GST_TAG_IMAGE_TYPE_FRONT_COVER, NULL); + gst_buffer_set_caps(buffer, caps); + + list = gst_tag_list_new(); + gst_tag_list_add(list, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, buffer, NULL); + + message = gst_message_new_tag(NULL, list); + gst_bus_post(m_worker->bus, message); + mafw_gst_renderer_worker_resume(m_worker); + + waitForEvent(WAIT_TIMEOUT, NEVER_HAPPENING_EVENT); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotMetadataCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(m_receivedMetadata.contains(WORKER_METADATA_KEY_RENDERER_ART_URI)); + + gst_buffer_unref(buffer); + gst_caps_unref(caps); + g_free(image); + +} + +void ut_MafwGstRendererWorker::eosTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_eos_handler = &eosCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(EOS_TIMEOUT, m_gotEosCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotEosCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::seekTestCase() +{ + + GError *error = 0; + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_seek_handler = &seekCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + + mafw_gst_renderer_worker_set_position(m_worker, + GST_SEEK_TYPE_SET, + 1, + &error); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotSeekCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(error == 0); + QVERIFY(mafw_gst_renderer_worker_get_position(m_worker) == 1); + +} + +void ut_MafwGstRendererWorker::invalidUriTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, "vjmksbhdfghrejggv"); + + waitForEvent(WAIT_TIMEOUT, m_gotErrorCallback); + + QVERIFY(m_gotPlayCallback == false); + QVERIFY(m_gotErrorCallback == true); + /* FIXME: new code for Gst errors? */ + /*QVERIFY(m_receivedErrorCode == WORKER_ERROR_UNABLE_TO_PERFORM);*/ + +} + +void ut_MafwGstRendererWorker::playAndStopTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + + mafw_gst_renderer_worker_stop(m_worker); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::playAndPauseTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + m_worker->media.has_visual_content = true; // normally gst sets this but not in unittest for some reason + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == false); + QVERIFY(m_blankingProhibited == true); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(m_blankingProhibited == false); +} + +void ut_MafwGstRendererWorker::pauseQuicklyAfterPlayTestCase() +{ + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + m_worker->media.has_visual_content = true; // normally gst sets this but not in unittest for some reason + mafw_gst_renderer_worker_pause(m_worker); + + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + QVERIFY(m_gotPlayCallback == false); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_blankingProhibited == false); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + waitForEvent(WAIT_TIMEOUT, m_blankingProhibited); + QCOMPARE(m_gotPlayCallback, true); + QCOMPARE(m_blankingProhibited, true); +} + +void ut_MafwGstRendererWorker::pauseAtTestCase() +{ + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + m_worker->media.has_visual_content = true; // normally gst sets this but not in unittest for some reason + //the video is only two seconds long + mafw_gst_renderer_worker_pause_at(m_worker, 1); + + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + QVERIFY(m_gotPlayCallback == false); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_blankingProhibited == false); + + QVERIFY(mafw_gst_renderer_worker_get_position(m_worker) == 1); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + waitForEvent(WAIT_TIMEOUT, m_blankingProhibited); + QCOMPARE(m_gotPlayCallback, true); + QCOMPARE(m_blankingProhibited, true); +} + +void ut_MafwGstRendererWorker::playAndPauseAndResumeTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == false); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + + m_gotPlayCallback = false; + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + + +void ut_MafwGstRendererWorker::resumeDelayedTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == false); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + /* pipeline goes to ready after 60 seconds */ + waitForEvent(READY_DELAY, NEVER_HAPPENING_EVENT); + + m_gotPlayCallback = false; + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::getCurrentMetadataTestCase() +{ + + GHashTable *metadata = 0; + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == false); + + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + + metadata = mafw_gst_renderer_worker_get_current_metadata(m_worker); + QVERIFY(metadata); + QVERIFY(g_hash_table_size(metadata)); + + mafw_gst_renderer_worker_stop(m_worker); + metadata = mafw_gst_renderer_worker_get_current_metadata(m_worker); + QVERIFY(!metadata); + + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::defaultConfigurationTestCase() +{ + QVERIFY2(sizeof(configuration) == 64, "You've (or somebody else) most likely changed the configuration struct! Update the unittests also!"); + + configuration * current_worker_conf = mafw_gst_renderer_worker_create_default_configuration(m_worker); + + QCOMPARE(current_worker_conf->asink, "pulsesink"); + QCOMPARE(current_worker_conf->vsink, "omapxvsink"); + QCOMPARE(current_worker_conf->buffer_time, 600000LL); + QCOMPARE(current_worker_conf->latency_time, 100000LL); + QCOMPARE(current_worker_conf->flags, 67); + + QCOMPARE(current_worker_conf->mobile_surround_music.state, 0U); + QCOMPARE(current_worker_conf->mobile_surround_music.color, 2); + QCOMPARE(current_worker_conf->mobile_surround_music.room, 2); + QCOMPARE(current_worker_conf->mobile_surround_video.state, 0U); + QCOMPARE(current_worker_conf->mobile_surround_video.color, 2); + QCOMPARE(current_worker_conf->mobile_surround_video.room, 2); + + QCOMPARE(current_worker_conf->milliseconds_to_pause_frame, 700U); + QCOMPARE(current_worker_conf->seconds_to_pause_to_ready, 3U); + QCOMPARE(current_worker_conf->use_dhmmixer, 1); + + //this well make valgrind happy. i.e. worker will handle memory cleanupping + mafw_gst_renderer_worker_set_configuration(m_worker, current_worker_conf); +} + +void ut_MafwGstRendererWorker::configurabilityTestCase() +{ + MafwGstRendererWorker *configWorker = mafw_gst_renderer_worker_new(this); + + configuration *config = mafw_gst_renderer_worker_create_default_configuration(configWorker); + + g_free(config->asink); + config->asink = g_strdup("test-sink"); + + //audio sink + QVERIFY(!globalGstFactoryRequests.contains("test-sink")); + mafw_gst_renderer_worker_set_configuration(configWorker, config); + mafw_gst_renderer_worker_stop(configWorker); + QVERIFY(globalGstFactoryRequests.contains("test-sink")); + globalGstFactoryRequests.clear(); + + mafw_gst_renderer_worker_exit(configWorker); + g_free(configWorker); + + + //video sink + configWorker = mafw_gst_renderer_worker_new(this); + config = mafw_gst_renderer_worker_create_default_configuration(configWorker); + g_free(config->vsink); + config->vsink = g_strdup("test-video-sink"); + + QVERIFY(!globalGstFactoryRequests.contains("test-video-sink")); + + mafw_gst_renderer_worker_set_configuration(configWorker, config); + //video-sink is not created unless xid has been set + mafw_gst_renderer_worker_set_xid(configWorker, 0xffff); + + mafw_gst_renderer_worker_stop(configWorker); + QVERIFY(globalGstFactoryRequests.contains("test-video-sink")); + + globalGstFactoryRequests.clear(); + mafw_gst_renderer_worker_exit(configWorker); + g_free(configWorker); + + + //NO dhmmixer + configWorker = mafw_gst_renderer_worker_new(this); + config = mafw_gst_renderer_worker_create_default_configuration(configWorker); + config->use_dhmmixer = 0; + + QVERIFY(!globalGstFactoryRequests.contains("nokiadhmmix")); + mafw_gst_renderer_worker_set_configuration(configWorker, config); + mafw_gst_renderer_worker_stop(configWorker); + QVERIFY(!globalGstFactoryRequests.contains("nokiadhmmix")); + + globalGstFactoryRequests.clear(); + mafw_gst_renderer_worker_exit(configWorker); + g_free(configWorker); + + //YES dhmmixer + configWorker = mafw_gst_renderer_worker_new(this); + config = mafw_gst_renderer_worker_create_default_configuration(configWorker); + config->use_dhmmixer = 1; + + QVERIFY(!globalGstFactoryRequests.contains("nokiadhmmix")); + mafw_gst_renderer_worker_set_configuration(configWorker, config); + mafw_gst_renderer_worker_stop(configWorker); + QVERIFY(globalGstFactoryRequests.contains("nokiadhmmix")); + + globalGstFactoryRequests.clear(); + mafw_gst_renderer_worker_exit(configWorker); + g_free(configWorker); +} + +void ut_MafwGstRendererWorker::pauseFrameConfigurabilityTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_metadata_handler = &metadataCallback; + m_worker->notify_property_handler = &propertyCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + m_worker->screenshot_handler = screenshotCallback; + + //let's change timeout values + configuration *config = mafw_gst_renderer_worker_create_default_configuration(m_worker); + config->milliseconds_to_pause_frame = 3000; + config->seconds_to_pause_to_ready = 6; + mafw_gst_renderer_worker_set_configuration(m_worker, config); + + + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_current_frame_on_pause(m_worker) == + TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE); + + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + QVERIFY(mafw_gst_renderer_worker_get_xid(m_worker) == 0xffff); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_XID); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + + /* post xwindow-id on bus since we are using fakesink instead of + * xvimagesink */ + GstBus *bus; + GstStructure *structure; + GstMessage *message; + structure = gst_structure_new("prepare-xwindow-id", "width", + G_TYPE_INT, 64, "height", G_TYPE_INT, 32, + NULL); + message = gst_message_new_element(NULL, structure); + bus = m_worker->bus; + gst_bus_post(bus, message); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + + mafw_gst_renderer_worker_pause(m_worker); + QTest::qWait(2000); + + //no pause frame yet, let's make sure + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == true); + QVERIFY(m_gotMetadataCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(!m_receivedMetadata.contains(WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI)); + + waitForEvent(WAIT_TIMEOUT, NEVER_HAPPENING_EVENT); + QVERIFY(m_receivedMetadata.contains(WORKER_METADATA_KEY_PAUSED_THUMBNAIL_URI)); + + mafw_gst_renderer_worker_stop(m_worker); + QTest::qWait(100); + config = mafw_gst_renderer_worker_create_default_configuration(m_worker); + mafw_gst_renderer_worker_set_configuration(m_worker, config); + +} + +void ut_MafwGstRendererWorker::setAndGetPropertiesTestCase() +{ + + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_property_handler = &propertyCallback; + m_worker->notify_play_handler = &playCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + QVERIFY(mafw_gst_renderer_worker_get_xid(m_worker) == 0xffff); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_XID); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_set_force_aspect_ratio(m_worker, FALSE); + QVERIFY(mafw_gst_renderer_worker_get_force_aspect_ratio(m_worker) == FALSE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_FORCE_ASPECT_RATIO); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_force_aspect_ratio(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_force_aspect_ratio(m_worker) == TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_FORCE_ASPECT_RATIO); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_current_frame_on_pause(m_worker) == + TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_current_frame_on_pause(m_worker, FALSE); + QVERIFY(mafw_gst_renderer_worker_get_current_frame_on_pause(m_worker) == + FALSE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_CURRENT_FRAME_ON_PAUSE); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_set_autopaint(m_worker, TRUE); + QVERIFY(mafw_gst_renderer_worker_get_autopaint(m_worker) == TRUE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_AUTOPAINT); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_autopaint(m_worker, FALSE); + QVERIFY(mafw_gst_renderer_worker_get_autopaint(m_worker) == FALSE); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_AUTOPAINT); + + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotPauseCallback == false); + + mafw_gst_renderer_worker_set_playback_speed(m_worker, 2); + QVERIFY(mafw_gst_renderer_worker_get_playback_speed(m_worker) == 2); + QVERIFY(m_gotPropertyCallback == true); + QVERIFY(m_receivedPropertyId == WORKER_PROPERTY_PLAYBACK_SPEED); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_playback_speed(m_worker, float(-1)); + QCOMPARE(mafw_gst_renderer_worker_get_playback_speed(m_worker), float(-1)); + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + mafw_gst_renderer_worker_set_playback_speed(m_worker, float(2.5)); + QCOMPARE(mafw_gst_renderer_worker_get_playback_speed(m_worker), float(2.5)); + + render_rectangle rect = {1,2,3,4}; + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + mafw_gst_renderer_worker_set_render_rectangle(m_worker, &rect); + QVERIFY(m_gotPropertyCallback); + QVERIFY(m_receivedPropertyId != -1); + const render_rectangle *storedRect = mafw_gst_renderer_worker_get_render_rectangle(m_worker); + //the pointer value should not be used, copy must be made + QVERIFY(&rect != storedRect ); + QCOMPARE(rect.x, storedRect->x); + QCOMPARE(rect.y, storedRect->y); + QCOMPARE(rect.width, storedRect->width); + QCOMPARE(rect.height, storedRect->height); + + m_gotPropertyCallback = false; + m_receivedPropertyId = -1; + + QVERIFY(m_gotErrorCallback == false); +} + +void ut_MafwGstRendererWorker::gettersTestCase() +{ + + m_worker->notify_error_handler = &errorCallback; + + QVERIFY(mafw_gst_renderer_worker_get_colorkey(m_worker) == -1); + QVERIFY(mafw_gst_renderer_worker_get_seekable(m_worker) == TRUE); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::mediaRouteTestCase() +{ + + GSList *list = NULL; + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_eos_handler = &eosCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + mafw_gst_renderer_worker_set_xid(m_worker, 0xffff); + + /* normal audio playback */ + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + + list = g_slist_append(list, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS)); + list = g_slist_append(list, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY)); + mafw_gst_renderer_worker_notify_media_destination(m_worker, list); + g_slist_free(list); + list = NULL; + QVERIFY(g_slist_length(m_worker->destinations) == 2); + QVERIFY(g_slist_find(m_worker->destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_SPEAKERS))); + QVERIFY(g_slist_find(m_worker->destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + + waitForEvent(EOS_TIMEOUT, m_gotEosCallback); + + QVERIFY(m_gotEosCallback == true); + QVERIFY(m_gotErrorCallback == false); + + /* normal video playback */ + m_gotPlayCallback = false; + m_gotEosCallback = false; + m_gotErrorCallback = false; + QVERIFY(m_blankingProhibited == false); + mafw_gst_renderer_worker_play(m_worker, VIDEO_URI.toString().toAscii()); + m_worker->media.has_visual_content = true; // normally gst sets this but not in unittest for some reason + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + QVERIFY(m_blankingProhibited == true); + + list = g_slist_append(list, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK)); + list = g_slist_append(list, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY)); + mafw_gst_renderer_worker_notify_media_destination(m_worker, list); + g_slist_free(list); + list = NULL; + QVERIFY(g_slist_length(m_worker->destinations) == 2); + QVERIFY(g_slist_find(m_worker->destinations, GINT_TO_POINTER(WORKER_OUTPUT_HEADPHONE_JACK))); + QVERIFY(g_slist_find(m_worker->destinations, GINT_TO_POINTER(WORKER_OUTPUT_BUILTIN_DISPLAY))); + + waitForEvent(WAIT_TIMEOUT, m_gotEosCallback); + QVERIFY(m_gotEosCallback == true); + QVERIFY(m_gotErrorCallback == false); + +} + +void ut_MafwGstRendererWorker::setReadyTimeoutTestCase() +{ + + m_worker->notify_play_handler = &playCallback; + m_worker->notify_error_handler = &errorCallback; + m_worker->notify_pause_handler = &pauseCallback; + m_worker->notify_eos_handler = &eosCallback; + m_worker->blanking__control_handler = &blankingControlCallback; + + /* do some basic set calls first */ + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 0); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 0); + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 60); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 60); + + /* set timeout to 0, pause in the middle of the playback */ + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 0); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 0); + QTest::qWait(1500); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + QVERIFY(m_worker->state == GST_STATE_PAUSED); + QTest::qWait(500); + QVERIFY(m_worker->state == GST_STATE_READY); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + waitForEvent(WAIT_TIMEOUT, m_gotEosCallback); + QVERIFY(m_gotEosCallback == true); + + /* set timeout to 3, pause in the middle of the playback */ + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 3); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 3); + QTest::qWait(1500); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + QVERIFY(m_worker->state == GST_STATE_PAUSED); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + QTest::qWait(4000); + QVERIFY(m_worker->state == GST_STATE_READY); + + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + waitForEvent(WAIT_TIMEOUT, m_gotEosCallback); + QVERIFY(m_gotEosCallback == true); + + /* set timeout to 0, pause in the middle of the playback after setting the + * timeout value --> we should go to ready immediately */ + mafw_gst_renderer_worker_play(m_worker, AUDIO_URI.toString().toAscii()); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_gotErrorCallback == false); + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 60); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 60); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + QTest::qWait(1500); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + mafw_gst_renderer_worker_pause(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPauseCallback); + QVERIFY(m_worker->state == GST_STATE_PAUSED); + mafw_gst_renderer_worker_set_ready_timeout(m_worker, 0); + QVERIFY(m_worker->config->seconds_to_pause_to_ready == 0); + QTest::qWait(500); + QVERIFY(m_worker->state == GST_STATE_READY); + + m_gotPlayCallback = false; + m_gotPauseCallback = false; + + mafw_gst_renderer_worker_resume(m_worker); + waitForEvent(WAIT_TIMEOUT, m_gotPlayCallback); + QVERIFY(m_gotPlayCallback == true); + QVERIFY(m_worker->state == GST_STATE_PLAYING); + waitForEvent(WAIT_TIMEOUT, m_gotEosCallback); + QVERIFY(m_gotEosCallback == true); + +} + +void ut_MafwGstRendererWorker::initTestCase() +{ + gst_init(0,0); +} + +void ut_MafwGstRendererWorker::init() +{ + + qDebug() << __PRETTY_FUNCTION__; + + m_worker = 0; + m_receivedErrorCode = -1; + m_receivedPropertyId = -1; + m_receivedBufferStatus = -1.0; + m_receivedMetadata.clear(); + m_gotPlayCallback = false; + m_gotEosCallback = false; + m_gotErrorCallback = false; + m_gotPauseCallback = false; + m_gotSeekCallback = false; + m_gotMetadataCallback = false; + m_gotPropertyCallback = false; + m_gotBufferStatusCallback = false; + m_blankingProhibited = false; + + global_context_duration = 0; + + bool ok; + QByteArray tmo = qgetenv("WAIT_TIMEOUT"); + int val = tmo.toInt(&ok, 10); + if (ok) + { + WAIT_TIMEOUT = val; + qDebug() << "WAIT_TIMEOUT is set to" << WAIT_TIMEOUT; + } + else + { + qDebug() << "Using default WAIT_TIMEOUT" << WAIT_TIMEOUT; + } + + const QString scheme("file"); + AUDIO_URI.setScheme(scheme); + VIDEO_URI.setScheme(scheme); + IMAGE_URI.setScheme(scheme); + + m_worker = mafw_gst_renderer_worker_new(this); + + QVERIFY(m_worker != 0); + + globalGstFactoryRequests.clear(); +} + +void ut_MafwGstRendererWorker::cleanup() +{ + QVERIFY(m_worker != 0); + + mafw_gst_renderer_worker_exit(m_worker); + g_free(m_worker); + + QVERIFY(m_blankingProhibited == false); + + m_gotPlayCallback = false; + m_gotErrorCallback = false; +} + +QTEST_MAIN(ut_MafwGstRendererWorker) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.h new file mode 100644 index 0000000..df7e87d --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.h @@ -0,0 +1,111 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFW_GST_RENDERER_WORKER_H_ +#define UT_MAFW_GST_RENDERER_WORKER_H_ + +#include +#include + +#include "mafw-gst-renderer-worker.h" + +class ut_MafwGstRendererWorker: public QObject +{ + Q_OBJECT + +private slots: // tests + + void basicPlaybackTestCase(); + void basicVideoPlaybackTestCase(); + void eosTestCase(); + void playAndPauseTestCase(); + void playAndStopTestCase(); + void setAndGetPropertiesTestCase(); + void gettersTestCase(); + void playAndPauseAndResumeTestCase(); + void pauseQuicklyAfterPlayTestCase(); + void pauseAtTestCase(); + void resumeDelayedTestCase(); + void getCurrentMetadataTestCase(); + void invalidUriTestCase(); + void seekTestCase(); + void defaultConfigurationTestCase(); + void configurabilityTestCase(); + void pauseFrameTestCase(); + void pauseFrameConfigurabilityTestCase(); + void pauseFrameCancelTestCase(); + void rendererArtTestCase(); + void bufferingTestCase(); + void mediaRouteTestCase(); + void setReadyTimeoutTestCase(); + void redirectMessageTestCase(); + + void initTestCase(); + void init(); + void cleanup(); + +protected slots: + void slotTimeOut(); + +protected: + static void playCallback(MafwGstRendererWorker *worker, gpointer owner); + static void eosCallback(MafwGstRendererWorker *worker, gpointer owner); + static void errorCallback(MafwGstRendererWorker *worker, + gpointer owner, + const GError *error); + static void pauseCallback(MafwGstRendererWorker *worker, gpointer owner); + static void propertyCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint id, + GValue *value); + static void seekCallback(MafwGstRendererWorker *worker, gpointer owner); + static void metadataCallback(MafwGstRendererWorker *worker, + gpointer owner, + gint key, + GType type, + gpointer value); + static void bufferingCallback(MafwGstRendererWorker *worker, + gpointer owner, + gdouble percent); + static void blankingControlCallback(MafwGstRendererWorker *worker, + gpointer owner, gboolean prohibit); + static void screenshotCallback(MafwGstRendererWorker *worker, + gpointer owner, + GstBuffer *buffer, + const char *filename, + gboolean cancel); + + void waitForEvent(gint ms, bool &hasEventOccurred); + +private: //data + MafwGstRendererWorker *m_worker; + bool m_gotPlayCallback; + bool m_gotEosCallback; + bool m_gotErrorCallback; + bool m_gotPauseCallback; + bool m_gotSeekCallback; + bool m_gotMetadataCallback; + bool m_gotPropertyCallback; + bool m_gotBufferStatusCallback; + bool m_blankingProhibited; + int m_receivedErrorCode; + int m_receivedPropertyId; + gdouble m_receivedBufferStatus; + QList m_receivedMetadata; +}; + +#endif diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.pro new file mode 100644 index 0000000..8e4a2ac --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwGstRendererWorker/ut_MafwGstRendererWorker.pro @@ -0,0 +1,31 @@ +TEMPLATE = app +QT -= gui +CONFIG = console + +isEmpty(PREFIX) { + PREFIX=/usr +} + +CONFIG += qt link_pkgconfig debug +CONFIG += qtestlib +PKGCONFIG += glib-2.0 gobject-2.0 gstreamer-0.10 gstreamer-plugins-base-0.10 +PKGCONFIG += contextprovider-1.0 x11 gstreamer-tag-0.10 + +LIBS += -lgstinterfaces-0.10 -lgstpbutils-0.10 -lgcov + +DEPENDPATH += . ../../inc ../../src +INCLUDEPATH += . ../../inc + +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g + +QMAKE_CLEAN += *.gcda *.gcno *.gcov ut_MafwGstRendererWorker *.vg.xml vgcore.* + +HEADERS += ut_MafwGstRendererWorker.h \ + mafw-gst-renderer-worker.h \ + mafw-gst-renderer-seeker.c + +SOURCES += ut_MafwGstRendererWorker.cpp \ + mafw-gst-renderer-worker.c \ + mafw-gst-renderer-seeker.c + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.cpp new file mode 100644 index 0000000..80fb7f3 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.cpp @@ -0,0 +1,97 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include "ut_MafwMmcMonitor.h" + +#include + +#include +#include + +#define private public // access private slots +#include "MafwMmcMonitor.h" + +extern QStringList stubMounts; +extern QStringList g_dbusConnectionParams; + +void Ut_MafwMmcMonitor::initTestCase() +{ +} + +void Ut_MafwMmcMonitor::cleanupTestCase() +{ +} + +void Ut_MafwMmcMonitor::testConstruction() +{ + QFETCH(QStringList, mounts); + QFETCH(bool, mmcMounted); + + stubMounts = mounts; + + MafwMmcMonitor monitor(this); + + QVERIFY( monitor.isMounted()==mmcMounted ); + + QCOMPARE(g_dbusConnectionParams.at(0), QString(USB_MODE_SERVICE)); + QCOMPARE(g_dbusConnectionParams.at(1), QString(USB_MODE_OBJECT)); + QCOMPARE(g_dbusConnectionParams.at(2), QString(USB_MODE_INTERFACE)); + QCOMPARE(g_dbusConnectionParams.at(3), QString(USB_MODE_SIGNAL_NAME)); + QVERIFY(g_dbusConnectionParams.at(4).toUInt() > static_cast(0)); + QVERIFY(g_dbusConnectionParams.at(5).length() > 0); + +} + +void Ut_MafwMmcMonitor::testConstruction_data() +{ + QTest::addColumn("mounts"); + QTest::addColumn("mmcMounted"); + + QTest::newRow("none") << (QStringList()) << false; + QTest::newRow("nommc") << (QStringList() << "file:///home/user/.mms/private" << "file:///home/user/.nokiamessaging/IM") << false; + QTest::newRow("mmc") << (QStringList() << "file:///home/user/MyDocs" << "file:///home/user/.nokiamessaging/IM") << true; +} + +void Ut_MafwMmcMonitor::testMounts() +{ + stubMounts.clear(); + MafwMmcMonitor monitor(this); + + QVERIFY( !monitor.isMounted() ); + + stubMounts << "file:///home/user/.mms/private" << "file:///home/user/MyDocs"; + monitor.mountEvent( 0, (GMount*)1, &monitor ); + QVERIFY( !monitor.isMounted() ); + monitor.mountEvent( 0, (GMount*)2, &monitor ); + QVERIFY( monitor.isMounted() ); + + monitor.unmountEvent( 0, (GMount*)1, &monitor ); + QVERIFY( monitor.isMounted() ); + monitor.unmountEvent( 0, (GMount*)2, &monitor ); + QVERIFY( !monitor.isMounted() ); +} + +void Ut_MafwMmcMonitor::testPreUnmount() +{ + MafwMmcMonitor monitor(this); + QSignalSpy spy( &monitor, SIGNAL( preUnmount() ) ); + + monitor.preUnmountEvent("pre-unmount"); + QVERIFY( spy.size()==1 ); +} + +QTEST_MAIN(Ut_MafwMmcMonitor) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.h b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.h new file mode 100644 index 0000000..9b840db --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.h @@ -0,0 +1,44 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_MAFWMMCMONITOR_H_ +#define UT_MAFWMMCMONITOR_H_ + +#include +#include +#include + +#include + + +class Ut_MafwMmcMonitor : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void testConstruction(); + void testConstruction_data(); + + void testMounts(); + void testPreUnmount(); + +}; + +#endif /*UT_MAFWMMCMONITOR_H_*/ diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.pro b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.pro new file mode 100644 index 0000000..ccc537f --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitor.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = +QT -= gui +CONFIG = console + +INCLUDEPATH += . +MAFW_GST_INCDIR = ../../inc +#UT_COMMONDIR = ../common + +INCLUDEPATH += $$MAFW_GST_INCDIR +DEPENDPATH += . ../../inc ../../src + +CONFIG += qtestlib +CONFIG += qt qdbus link_pkgconfig debug + +PKGCONFIG += glib-2.0 gio-2.0 gio-unix-2.0 usb_moded dbus-1 + +LIBS += -lgcov +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -O0 -Werror +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -O0 -Werror + +# Input +HEADERS += MafwMmcMonitor.h \ + ut_MafwMmcMonitor.h + +SOURCES += MafwMmcMonitor.cpp \ + ut_MafwMmcMonitor.cpp \ + ut_MafwMmcMonitorStubs.cpp diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitorStubs.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitorStubs.cpp new file mode 100644 index 0000000..507b144 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_MafwMmcMonitor/ut_MafwMmcMonitorStubs.cpp @@ -0,0 +1,111 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include + +QStringList stubMounts; + +QStringList g_dbusConnectionParams; + +// GVolumeMonitor + +GVolumeMonitor *g_volume_monitor_get(void) +{ + return (GVolumeMonitor*)1; +} + +GList * g_volume_monitor_get_mounts(GVolumeMonitor *volume_monitor) +{ + return (GList*)1; +} + +// GObject + +gulong g_signal_connect_data (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags) +{ + return 0; +} + +void g_object_unref(gpointer object) +{ +} + +// GList + +guint g_list_length(GList *list) +{ + return stubMounts.size(); +} + +gpointer g_list_nth_data(GList *list, guint n) +{ + return (void*)(n+1); +} + +void g_list_free(GList *list) +{ +} + +// GMount + +GFile * g_mount_get_root(GMount *mount) +{ + return (GFile*)mount; +} + +// GFile + +char* g_file_get_uri(GFile *file) +{ + return g_strdup(stubMounts[(int)file-1].toAscii().constData()); +} + + +//QDBusConnection + +QDBusConnection::QDBusConnection(const QString& /*name*/) +{ +} + +QDBusConnection QDBusConnection::sessionBus() +{ + return QDBusConnection("..."); +} + +bool QDBusConnection::connect(const QString &service, + const QString &path, + const QString &interface, + const QString &name, + QObject *receiver, + const char *slot) +{ + g_dbusConnectionParams << service; + g_dbusConnectionParams << path; + g_dbusConnectionParams << interface; + g_dbusConnectionParams << name; + g_dbusConnectionParams << QString::number(reinterpret_cast(receiver)); + g_dbusConnectionParams << slot; + + return true; +} diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.cpp new file mode 100644 index 0000000..a820cc1 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.cpp @@ -0,0 +1,150 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include + +#include +#include +#include + +#include "ut_Others.h" +#include "mafw-gst-renderer-utils.h" +#include "mafw-gst-renderer-worker.h" + +#define UNUSED(x) (void)(x) + +/* START OF STUB DEFINITIONS */ +gboolean g_utf8_validate(const gchar *str, + gssize max_len, + const gchar **end) +{ + + UNUSED(max_len); + UNUSED(end); + + if (g_str_equal("valid", str)) + { + return TRUE; + } + else + { + return FALSE; + } + +} + +gchar* g_locale_to_utf8(const gchar *opsysstring, + gssize len, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + + UNUSED(len); + UNUSED(bytes_read); + UNUSED(bytes_written); + + if (g_str_equal("non-valid", opsysstring)) + { + return g_strdup(opsysstring); + } + else + { + g_set_error(error, + g_quark_from_string("test"), + 100, + "%s", "SIMULATED ERROR"); + return NULL; + } +} + + +/* END OF STUB DEFINITIONS */ + +void ut_Others::testUtils() +{ + QVERIFY(uri_is_stream("file:///file.m3u") == FALSE); + QVERIFY(uri_is_stream("http:///joojoo.com") == TRUE); + QVERIFY(uri_is_stream(NULL) == FALSE); + + gchar *dst = NULL; + QVERIFY(convert_utf8(NULL, NULL) == FALSE); + QVERIFY(convert_utf8("valid", NULL) == FALSE); + QVERIFY(convert_utf8(NULL, &dst) == FALSE); + QVERIFY(convert_utf8("valid", &dst) == TRUE); + g_free(dst); + QVERIFY(convert_utf8("non-valid", &dst) == TRUE); + QVERIFY(dst); + QVERIFY(g_str_equal(dst, "non-valid") == TRUE); + g_free(dst); + QVERIFY(convert_utf8("error", &dst) == FALSE); + +} + +void ut_Others::testGstErrorRemapping() +{ + + GQuark domain = g_quark_from_string("test_error_domain"); + + GError* error = g_error_new_literal(domain, 999, "error_message"); + QVERIFY(remap_gst_error_code(error) == 999); + + error->domain = GST_RESOURCE_ERROR; + error->code = GST_RESOURCE_ERROR_READ; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_STREAM_DISCONNECTED); + error->code = GST_RESOURCE_ERROR_NOT_FOUND; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_MEDIA_NOT_FOUND); + error->code = GST_RESOURCE_ERROR_OPEN_READ_WRITE; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_MEDIA_NOT_FOUND); + error->code = GST_RESOURCE_ERROR_NO_SPACE_LEFT; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_UNABLE_TO_PERFORM); + error->code = GST_RESOURCE_ERROR_WRITE; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_CORRUPTED_FILE); + error->code = GST_RESOURCE_ERROR_SEEK; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_CANNOT_SET_POSITION); + error->code = 999999; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_UNABLE_TO_PERFORM); + + error->domain = GST_STREAM_ERROR; + error->code = GST_STREAM_ERROR_TYPE_NOT_FOUND; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_TYPE_NOT_AVAILABLE); + error->code = GST_STREAM_ERROR_FORMAT; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_UNSUPPORTED_TYPE); + error->code = GST_STREAM_ERROR_DECODE; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_CORRUPTED_FILE); + error->code = GST_STREAM_ERROR_CODEC_NOT_FOUND; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_CODEC_NOT_FOUND); + error->code = GST_STREAM_ERROR_DECRYPT; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_DRM_NOT_ALLOWED); + error->code = 999999; + QVERIFY(remap_gst_error_code(error) == WORKER_ERROR_UNABLE_TO_PERFORM); + + g_error_free(error); + +} + +void ut_Others::init() +{ + +} + +void ut_Others::cleanup() +{ + +} + +QTEST_APPLESS_MAIN(ut_Others) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.h b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.h new file mode 100644 index 0000000..1b42c02 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.h @@ -0,0 +1,44 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_OTHERS_H_ +#define UT_OTHERS_H_ + +#include +#include + +class ut_Others: public QObject +{ + Q_OBJECT + +private slots: // tests + + void testUtils(); + void testGstErrorRemapping(); + + void init(); + void cleanup(); + +protected slots: + +protected: + +private: //data + +}; + +#endif diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.pro b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.pro new file mode 100644 index 0000000..e204160 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_Others/ut_Others.pro @@ -0,0 +1,26 @@ +TEMPLATE = app + +isEmpty(PREFIX) { + PREFIX=/usr +} + +CONFIG += qt link_pkgconfig release +CONFIG += qtestlib +PKGCONFIG += glib-2.0 gobject-2.0 gstreamer-0.10 + +LIBS += -lgcov + +DEPENDPATH += . ../../inc ../../src +INCLUDEPATH += . ../../inc + +QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g +QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -Wall -Werror -g + +QMAKE_CLEAN += *.gcda *.gcno *.gcov ut_Others *.vg.xml vgcore.* + +HEADERS += ut_Others.h \ + mafw-gst-renderer-utils.h + +SOURCES += ut_Others.cpp \ + mafw-gst-renderer-utils.c + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.cpp b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.cpp new file mode 100644 index 0000000..46029c2 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.cpp @@ -0,0 +1,149 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#include +#include +#include + +#include "Ut_PlaylistFileUtility.h" +#include "../common/MafwStubHelper.h" +#include "MafwGstRendererPlaylistFileUtility.h" + +void Ut_PlaylistFileUtility::initTestCase() +{ + m_stubHelper = new MafwStubHelper; + m_utility = new MafwGstRendererPlaylistFileUtility(this); +} + +void Ut_PlaylistFileUtility::testParsing() +{ + QString file("/test-station.pls"); + file.prepend(QDir::currentPath()); + file.prepend("file://"); + + QSignalSpy readySpy(m_utility, SIGNAL(parsingReady(bool))); + QSignalSpy parsingSpy(m_utility, SIGNAL(firstItemParsed())); + m_utility->parsePlaylistFile(QUrl(file)); + QTest::qWait(1000); + + QCOMPARE(readySpy.count(), 1); + QList arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == true); + QCOMPARE(parsingSpy.count(), 1); + + //There is 19 entries in test-station.pls file + for (int i=0; i<19; i++) + { + QVERIFY(m_utility->takeFirstUri().length() > 0); + } + + QVERIFY(m_utility->takeFirstUri().length() == 0); +} + +void Ut_PlaylistFileUtility::testParsingForNotExistingFile() +{ + QString file("/not-existing.pls"); + file.prepend(QDir::currentPath()); + file.prepend("file://"); + QSignalSpy readySpy(m_utility, SIGNAL(parsingReady(bool))); + QSignalSpy parsingSpy(m_utility, SIGNAL(firstItemParsed())); + + m_utility->parsePlaylistFile(QUrl(file)); + QTest::qWait(1000); + QCOMPARE(readySpy.count(), 1); + QCOMPARE(parsingSpy.count(), 0); + QList arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == false); +} + +void Ut_PlaylistFileUtility::testParsingInvalidFileUri() +{ +//No scheme + QString file("/test-station.pls"); + file.prepend(QDir::currentPath()); + QSignalSpy parsingSpy(m_utility, SIGNAL(firstItemParsed())); + QSignalSpy readySpy(m_utility, SIGNAL(parsingReady(bool))); + m_utility->parsePlaylistFile(QUrl(file)); + QTest::qWait(1000); + QCOMPARE(parsingSpy.count(), 0); + QCOMPARE(readySpy.count(), 1); + QList arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == false); + +//Contains only path + QString file2(QDir::currentPath()); + file2.prepend("file://"); + m_utility->parsePlaylistFile(file2); + QTest::qWait(1000); + QCOMPARE(parsingSpy.count(), 0); + QCOMPARE(readySpy.count(), 1); + arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == false); +} + +void Ut_PlaylistFileUtility::testParsingInvalidFile() +{ + QString file("/test-station_invalid.pls"); + file.prepend(QDir::currentPath()); + file.prepend("file://"); + + QSignalSpy readySpy(m_utility, SIGNAL(parsingReady(bool))); + QSignalSpy parsingSpy(m_utility, SIGNAL(firstItemParsed())); + m_utility->parsePlaylistFile(QUrl(file)); + QTest::qWait(1000); + + QCOMPARE(readySpy.count(), 1); + QList arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == true); + QCOMPARE(parsingSpy.count(), 0); + + QVERIFY(m_utility->takeFirstUri().length() == 0); +} + +void Ut_PlaylistFileUtility::testParsingASFFile() +{ + QString file("/test.asf"); + file.prepend(QDir::currentPath()); + file.prepend("file://"); + + QSignalSpy readySpy(m_utility, SIGNAL(parsingReady(bool))); + QSignalSpy parsingSpy(m_utility, SIGNAL(firstItemParsed())); + m_utility->parsePlaylistFile(QUrl(file)); + QTest::qWait(1000); + + QCOMPARE(readySpy.count(), 1); + QList arguments = readySpy.takeFirst(); + QVERIFY(arguments.at(0).toBool() == true); + QCOMPARE(parsingSpy.count(), 1); + + for (int i=0; i < 1; i++) + { + QString test = m_utility->takeFirstUri(); + QVERIFY(test.length() > 0); + QVERIFY(test.startsWith("mmsh://195")); + QVERIFY(test.endsWith(".asf")); + } + + QVERIFY(m_utility->takeFirstUri().length() == 0); +} + +void Ut_PlaylistFileUtility::cleanupTestCase() +{ + delete m_stubHelper; +} + +QTEST_MAIN(Ut_PlaylistFileUtility) diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.h b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.h new file mode 100644 index 0000000..eeaea93 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.h @@ -0,0 +1,46 @@ +/* + * This file is part of QMAFW + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All rights + * reserved. + * + * Contact: Visa Smolander + * + * This software, including documentation, is protected by copyright controlled + * by Nokia Corporation. All rights are reserved. Copying, including + * reproducing, storing, adapting or translating, any or all of this material + * requires the prior written consent of Nokia Corporation. This material also + * contains confidential information which may not be disclosed to others + * without the prior written consent of Nokia. + * + */ + +#ifndef UT_PLAYLISTFILEUTILITY_H +#define UT_PLAYLISTFILEUTILITY_H + +#include + +class MafwStubHelper; +class MafwGstRendererPlaylistFileUtility; + +class Ut_PlaylistFileUtility: public QObject +{ + Q_OBJECT + +private Q_SLOTS: // tests + + void initTestCase(); + void testParsing(); + void testParsingForNotExistingFile(); + void testParsingInvalidFileUri(); + void testParsingInvalidFile(); + void testParsingASFFile(); + void cleanupTestCase(); + +private: + MafwStubHelper* m_stubHelper; + MafwGstRendererPlaylistFileUtility* m_utility; + +}; + +#endif // UT_PLAYLISTFILEUTILITY_H diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.pro b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.pro new file mode 100644 index 0000000..c75d957 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/Ut_PlaylistFileUtility.pro @@ -0,0 +1,31 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Mon Aug 23 09:32:17 2010 +###################################################################### +TEMPLATE = app +TARGET = +QT -= gui +CONFIG = console + +MAFW_GST_INCDIR = ../../inc +DEPENDPATH += . $$MAFW_GST_INCDIR ../../src +INCLUDEPATH += . $$MAFW_GST_INCDIR /usr/include/qmafw + +CONFIG += qtestlib no_keywords +CONFIG += qt link_pkgconfig debug +PKGCONFIG += qmafw glib-2.0 gobject-2.0 +PKGCONFIG += contextprovider-1.0 x11 libpulse-mainloop-glib contextsubscriber-1.0 +LIBS += -lgcov -ltotem-plparser + +QMAKE_CXXFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Wall -Werror +QMAKE_CFLAGS +=-fprofile-arcs -ftest-coverage -O0 -Wall -Werror + +# Input +HEADERS += Ut_PlaylistFileUtility.h \ + ../common/MafwStubHelper.h \ + MafwGstRendererPlaylistFileUtility.h + +SOURCES += Ut_PlaylistFileUtility.cpp \ + ../common/MafwStubHelper.cpp \ + MafwGstRendererPlaylistFileUtility.cpp \ + #totemParserStub.c + diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station.pls b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station.pls new file mode 100644 index 0000000..572e215 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station.pls @@ -0,0 +1,60 @@ +[playlist] +numberofentries=19 +File1=http://188.165.211.147:8002 +Title1=(#1 - 7/19) RMF FM +Length1=-1 +File2=http://188.165.12.66:8006 +Title2=(#2 - 524/950) RMF FM +Length1=-1 +File3=http://91.121.124.91:8002 +Title3=(#3 - 543/950) RMF FM +Length1=-1 +File4=http://188.165.12.67:8004 +Title4=(#4 - 547/950) RMF FM +Length1=-1 +File5=http://188.165.12.67:8000 +Title5=(#5 - 554/950) RMF FM +Length1=-1 +File6=http://188.165.12.66:8002 +Title6=(#6 - 562/950) RMF FM +Length1=-1 +File7=http://188.165.12.66:8000 +Title7=(#7 - 573/950) RMF FM +Length1=-1 +File8=http://188.165.12.66:8004 +Title8=(#8 - 596/950) RMF FM +Length1=-1 +File9=http://91.121.125.91:8000 +Title9=(#9 - 614/950) RMF FM +Length1=-1 +File10=http://188.165.12.67:8002 +Title10=(#10 - 647/950) RMF FM +Length1=-1 +File11=http://188.165.12.66:8008 +Title11=(#11 - 655/950) RMF FM +Length1=-1 +File12=http://188.165.12.67:8006 +Title12=(#12 - 658/950) RMF FM +Length1=-1 +File13=http://91.121.125.91:8002 +Title13=(#13 - 670/950) RMF FM +Length1=-1 +File14=http://91.121.124.91:8000 +Title14=(#14 - 714/950) RMF FM +Length1=-1 +File15=http://87.98.222.167:8000 +Title15=(#15 - 779/950) RMF FM +Length1=-1 +File16=http://87.98.223.167:8000 +Title16=(#16 - 869/950) RMF FM +Length1=-1 +File17=http://188.165.12.67:8008 +Title17=(#17 - 887/950) RMF FM +Length1=-1 +File18=http://87.98.222.167:8002 +Title18=(#18 - 896/950) RMF FM +Length1=-1 +File19=http://87.98.223.167:8002 +Title19=(#19 - 901/950) RMF FM +Length1=-1 +Version=2 diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station_invalid.pls b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station_invalid.pls new file mode 100644 index 0000000..ae759ad --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test-station_invalid.pls @@ -0,0 +1,3 @@ +[playlist] +numberofentries=19 +Version=2 diff --git a/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test.asf b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test.asf new file mode 100644 index 0000000..3d20a2c --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/ut_PlaylistFileUtility/test.asf @@ -0,0 +1,3 @@ +[Reference] +Ref1=http://195.134.228.177:443/data/ByContainer/Video/ASF/VC1/CIF/WMA/ASF_VC-1_CIF_29.7FPS_356Kbps_WMA8_44.1KHz_64Kbps_60sec(3Mb)_BBB.asf +Ref2=http://195.134.228.177:443/data/ByContainer/Video/ASF/VC1/CIF/WMA/ASF_VC-1_CIF_29.7FPS_356Kbps_WMA8_44.1KHz_64Kbps_60sec(3Mb)_BBB.asf diff --git a/qmafw-gst-subtitles-renderer/unittests/valgrind.xsl b/qmafw-gst-subtitles-renderer/unittests/valgrind.xsl new file mode 100644 index 0000000..543816f --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/valgrind.xsl @@ -0,0 +1,80 @@ + + + + + +

Executed Test Programs

+ + +
+
+ +

Errors

+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+

+ +

Stack frames

+ +
+ call stack (): + + + + + + + + + + + + + + + + + + + + + + + + +
functionfilelinedirectory
+

+ + + + (call stack): + + diff --git a/qmafw-gst-subtitles-renderer/unittests/valgrind_report.sh b/qmafw-gst-subtitles-renderer/unittests/valgrind_report.sh new file mode 100755 index 0000000..9f71d00 --- /dev/null +++ b/qmafw-gst-subtitles-renderer/unittests/valgrind_report.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +valgrind_results_file=valgrind.results + +files=`find . -name "*.vg.xml"` + +rm -f $valgrind_results_file + +if [ -z "$files" ] +then + echo "Valgrind results not generated." + exit 0 +fi + +echo '' > $valgrind_results_file +echo '' >> $valgrind_results_file +for file in $files; do + grep -v \<\/\valgrindoutput\> $file | tail --quiet --lines=+2 >> $valgrind_results_file; + echo '' >> $valgrind_results_file; +done +echo '' >> $valgrind_results_file