[Merge] lp:~thomas-voss/media-hub/add-tests-and-testing-infrastructure into lp:media-hub

Jim Hodapp jim.hodapp at canonical.com
Wed Jun 3 16:33:33 UTC 2015


Review: Needs Information

Which branch or branches have your tests that you refactored and want to land? I'll have more comments for this MR after you sync your branches with trunk.

Diff comments:

> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt	2015-01-23 13:00:36 +0000
> +++ CMakeLists.txt	2015-04-17 14:35:22 +0000
> @@ -29,6 +29,8 @@
>  pkg_check_modules(PROCESS_CPP process-cpp REQUIRED)
>  pkg_check_modules(GIO gio-2.0 REQUIRED)
>  pkg_check_modules(HYBRIS_MEDIA libmedia REQUIRED)
> +pkg_check_modules(GSTREAMER_1_0 REQUIRED gstreamer-1.0)
> +pkg_check_modules(PULSE_AUDIO REQUIRED libpulse)
>  
>  add_definitions(-DMEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER)
>  
> @@ -57,8 +59,11 @@
>    ${DBUS_INCLUDE_DIRS}
>    ${DBUS_CPP_INCLUDE_DIRS}
>    ${GLog_INCLUDE_DIR}
> +  ${GSTREAMER_1_0_INCLUDE_DIRS}
> +  ${HYBRIS_MEDIA_CFLAGS}
>    ${PROCESS_CPP_INCLUDE_DIRS}
>    ${PROPERTIES_CPP_INCLUDE_DIRS}
> +  ${PULSE_AUDIO_INCLUDE_DIRS}
>  
>    include/
>  )
> 
> === added file 'memcheck.suppressions'
> --- memcheck.suppressions	1970-01-01 00:00:00 +0000
> +++ memcheck.suppressions	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,4016 @@
> +### this file contains suppressions for valgrind when running
> +### the gstreamer unit tests
> +### it might be useful for wider use as well
> +
> +### syscall suppressions
> +
> +{
> +   <clone on Wim's Debian>
> +   Memcheck:Param
> +   clone(parent_tidptr)
> +   fun:clone
> +   fun:clone
> +}
> +
> +{
> +   <clone on Wim's Debian>
> +   Memcheck:Param
> +   clone(child_tidptr)
> +   fun:clone
> +   fun:clone
> +}
> +
> +{
> +   <clone on Wim's Debian>
> +   Memcheck:Param
> +   clone(tlsinfo)
> +   fun:clone
> +   fun:clone
> +}
> +
> +### glibc suppressions
> +
> +{
> +   <conditional jump on wim's debian 2/2/06>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.*.so
> +   fun:_dlerror_run
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +}
> +
> +{
> +   <Conditional jump>
> +   Memcheck:Cond
> +   fun:strlen
> +   fun:fillin_rpath
> +   fun:_dl_init_paths
> +   fun:dl_main
> +   fun:_dl_sysdep_start
> +   fun:_dl_start
> +   obj:/lib64/ld-2.*.so
> +   obj:*
> +   obj:*
> +}
> +
> +{
> +   <Conditional jump>
> +   Memcheck:Cond
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +   fun:_dl_sysdep_start
> +   fun:_dl_start
> +}
> +
> +{
> +   <insert a suppression name here>
> +   Memcheck:Cond
> +   fun:*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +# glibc does not deallocate thread-local storage
> +
> +{
> +   <tls>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@*
> +}
> +
> +{
> +   <tls>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:allocate_dtv
> +   fun:_dl_allocate_tls
> +}
> +
> +# I get an extra stack entry on x86/dapper
> +{
> +   <tls>
> +   Memcheck:Leak
> +   fun:calloc
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@*
> +}
> +
> +
> +{
> +   <pthread strstr>
> +   Memcheck:Cond
> +   fun:strstr
> +   fun:__pthread_initialize_minimal
> +   obj:/lib/libpthread-*.so
> +   obj:/lib/libpthread-*.so
> +   fun:call_init
> +   fun:_dl_init
> +   obj:/lib/ld-*.so
> +}
> +
> +# a thread-related free problem in glibc from Edgard
> +{
> +   __libc_freeres_rw_acess
> +   Memcheck:Addr4
> +   obj:*
> +   obj:*
> +   obj:*
> +   obj:*
> +   obj:*
> +   fun:__libc_freeres
> +}
> +
> +{
> +   <a conditional jump on wim's debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +}
> +
> +# g_module_open-related problems
> +{
> +   <started showing up on fc4-quick>
> +   Memcheck:Addr2
> +   fun:memcpy
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +   fun:gst_registry_scan_path_level
> +   fun:gst_registry_scan_path_level
> +   fun:gst_registry_scan_path_level
> +   fun:init_post
> +   fun:g_option_context_parse
> +   fun:gst_init_check
> +   fun:gst_init
> +   fun:gst_check_init
> +   fun:main
> +}
> +
> +{
> +   <started showing up on fc4-quick>
> +   Memcheck:Addr4
> +   fun:memcpy
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +   fun:gst_registry_scan_path_level
> +   fun:gst_registry_scan_path_level
> +   fun:gst_registry_scan_path_level
> +   fun:init_post
> +   fun:g_option_context_parse
> +   fun:gst_init_check
> +   fun:gst_init
> +   fun:gst_check_init
> +   fun:main
> +}
> +
> +{
> +   <g_module_open on wim's debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:do_sym
> +   fun:_dl_sym
> +   fun:dlsym_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlsym
> +   fun:g_module_symbol
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +}
> +
> +{
> +   <g_module_open on wim's debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +}
> +{
> +   <g_module_open on wim's debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +   fun:gst_plugin_load_by_name
> +   fun:gst_plugin_feature_load
> +}
> +
> +{
> +   <leak on wim's debian in g_module_open>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +   fun:gst_plugin_load_by_name
> +}
> +
> +{
> +   <invalid read on wim's debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +}
> +
> +{
> +   <invalid read on wim's debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +}
> +
> +{
> +   <invalid read on wim's debian - 2006-02-02>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read on wim's debian - 2006-02-02>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:dl_open_worker
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read on wim's debian - 2006-02-02>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:do_sym
> +   fun:_dl_sym
> +   fun:dlsym_doit
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dlerror_run
> +   fun:dlsym
> +   fun:g_module_symbol
> +   fun:g_module_open
> +}
> +
> +{
> +   <futex on Andy's 64-bit ubuntu>
> +   Memcheck:Param
> +   futex(uaddr2)
> +   fun:pthread_once
> +   obj:/lib/libc-2.3.*.so
> +   obj:/lib/libc-2.3.*.so
> +   fun:mbsnrtowcs
> +   fun:vfprintf
> +   fun:vsprintf
> +   fun:sprintf
> +   obj:/lib/libc-2.3.*.so
> +   fun:tmpfile
> +   fun:setup_pipe
> +   fun:setup_messaging_with_key
> +   fun:setup_messaging
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   fun:_dl_sym
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlsym
> +   fun:g_module_symbol
> +   fun:g_module_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   fun:iconv_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   obj:/lib/i686/cmov/libc-2.7.so
> +   fun:iconv_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on Ubunty Hardy 64-bit>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   fun:iconv_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on Ubunty Hardy 64-bit>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libc-2.7.so
> +   fun:iconv_open
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on Ubunty Hardy 64-bit>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +{
> +   <suppression for glibc 2.7 on debian>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +}
> +
> +# suppression for a glibc bug:
> +# http://valgrind.org/docs/manual/faq.html#faq.exit_errors>
> +{
> +   <Workaround for a glibc bug>
> +   Memcheck:Free
> +   fun:free
> +   obj:*libc-*.so
> +   fun:__libc_freeres
> +   fun:*
> +   fun:_Exit
> +}
> +
> +# same as above, just so it works for tpm on gutsy/x86-64
> +{
> +   <workaround glibc bug on gutsy x86-64>
> +   Memcheck:Free
> +   fun:free
> +   fun:free_mem
> +   fun:__libc_freeres
> +}
> +
> +# valgrind doesn't allow me to specify a suppression for Addr1, Addr2, Addr4
> +# as Addr*, so 3 copies for that; and then 2 of each for that pesky memcpy
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr1
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr2
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr4
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr1
> +   fun:memcpy
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr2
> +   fun:memcpy
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +{
> +   <Invalid read of size 1, 2, 4 on thomas's FC4>
> +   Memcheck:Addr4
> +   fun:memcpy
> +   fun:_dl_signal_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +   fun:g_module_open
> +}
> +
> +{
> +   <Addr8 on Andy's AMD64 ubuntu in dl_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/libc-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   obj:/lib/libdl-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +}
> +
> +{
> +   <Conditional jump on Andy's AMD64 ubuntu>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/libc-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   fun:_dl_open
> +   obj:/lib/libdl-2.3.*.so
> +   obj:/lib/ld-2.3.*.so
> +   obj:/lib/libdl-2.3.*.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +   fun:gst_plugin_load_by_name
> +   fun:gst_plugin_feature_load
> +}
> +
> +{
> +   <Mike's x86 dapper>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libc-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   fun:_dl_open
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   fun:dlopen
> +}
> +
> +{
> +   <Mike's x86 dapper>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libc-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   fun:_dl_open
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   fun:dlopen
> +}
> +
> +{
> +   <Another dapper one>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libc-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   fun:_dl_open
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/tls/i686/cmov/libdl-2.3.6.so
> +   fun:dlopen
> +}
> +
> +### glib suppressions
> +{
> +   <g_parse_debug_string>
> +   Memcheck:Cond
> +   fun:g_parse_debug_string
> +   obj:/usr/lib*/libglib-2.0.so.*
> +   fun:g_slice_alloc
> +   fun:g_slice_alloc0
> +}
> +
> +{
> +   <g_type_init leaks>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:g_type_init*
> +   fun:init_pre*
> +}
> +
> +{
> +   <g_type_register_fundamental leaks>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:g_type_register_fundamental
> +}
> +
> +{
> +   <glib 2.21 static type data>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:type_node_any_new_W
> +}
> +
> +{
> +   <glib 2.21 static type data>
> +   Memcheck:Leak
> +   fun:realloc
> +   fun:g_realloc
> +   fun:type_node_any_new_W
> +}
> +
> +{
> +   <glib 2.21 static type data>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:g_type_class_ref
> +}
> +
> +{
> +   <glib 2.21 static type data>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:type_add_flags_W
> +}
> +
> +{
> +   <glib 2.21 static type data>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:type_add_flags_W
> +}
> +
> +#pthread memleaks
> +
> +{
> +   Thread creation leak
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:allocate_dtv
> +   fun:_dl_allocate*
> +   fun:_dl_allocate*
> +   fun:__pthread_initialize_minimal
> +}
> +
> +{
> +   Thread management leak
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:allocate_dtv
> +   fun:_dl_allocate*
> +   fun:_dl_allocate*
> +   fun:__pthread_*
> +}
> +
> +{
> +   Thread management leak 2
> +   Memcheck:Leak
> +   fun:memalign
> +   fun:_dl_allocate*
> +   fun:_dl_allocate*
> +   fun:__pthread_*
> +}
> +
> +{
> +   pthread_create Syscall param write(buf) points to uninitialised byte(s)
> +   Memcheck:Param
> +   write(buf)
> +   fun:pthread_create@@GLIBC_2.2.5
> +   fun:g_thread_create*
> +
> +}
> +
> +# nss_parse_* memleak (used by g_option_context_parse)
> +{
> +   nss_parse_* memleak
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:nss_parse_service_list
> +   fun:__nss_database_lookup
> +}
> +
> +# liboil suppressions
> +{
> +   <liboil cpu_fault_check_try>
> +   Memcheck:Value8
> +   obj:/usr/lib/liboil-0.3.so.0.1.0
> +   obj:/usr/lib/liboil-0.3.so.0.1.0
> +   obj:/usr/lib/liboil-0.3.so.0.1.0
> +   fun:oil_cpu_fault_check_try
> +   fun:oil_test_check_impl
> +   fun:oil_class_optimize
> +   fun:oil_optimize_all
> +   fun:oil_init
> +}
> +
> +{
> +   <annoying read error inside dlopen stuff on Ubuntu Dapper x86_64>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.3.6.so
> +}
> +
> +{
> +   <Ubuntu Dapper x86_64>
> +   Memcheck:Param
> +   futex(uaddr2)
> +   fun:pthread_once
> +   obj:/lib/libc-2.3.6.so
> +   obj:/lib/libc-2.3.6.so
> +   fun:setlocale
> +   fun:init_pre
> +   fun:g_option_context_parse
> +   fun:gst_init_check
> +   fun:gst_init
> +   fun:gst_check_init
> +   fun:main
> +}
> +
> +{
> +   <Ubuntu Dapper x86_64 dlopen stuff again>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   fun:_dl_open
> +   obj:/lib/libdl-2.3.6.so
> +   obj:/lib/ld-2.3.6.so
> +   obj:/lib/libdl-2.3.6.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_file
> +}
> +# this exists in a bunch of different variations, hence the short tail/trace
> +{
> +   <dlopen invalid read of size 4 suppression on tpm's Ubuntu edgy/x86>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +}
> +{
> +   <and the same for 64bit systems>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +}
> +
> +# More edgy suppressions (Mike)
> +{
> +   <dlopen Condition jump suppressions for Ubuntu Edgy/x86>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.4.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +}
> +
> +{
> +   <dlopen Condition jump suppressions for Ubuntu Edgy/x86>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   fun:dlopen_doit
> +   obj:/lib/ld-2.4.so
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.1
> +}
> +
> +{
> +   <dlopen Condition jump suppressions for Ubuntu Edgy/x86>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   fun:do_sym
> +   fun:_dl_sym
> +}
> +
> +# This one's overly general, but there's zero other information in the stack
> +# trace - just these five lines!
> +{
> +   <dlopen Condition jump suppressions for Ubuntu Edgy/x86>
> +   Memcheck:Cond
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +   obj:/lib/ld-2.4.so
> +}
> +
> +{
> +   <tls leaks on Edgy/x86>
> +   Memcheck:Leak
> +   fun:calloc
> +   obj:/lib/ld-2.4.so
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@GLIBC_2.1
> +}
> +
> +# TLS leaks for feisty/x86
> +{
> +   <tls leaks on Feisty/x86>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:allocate_dtv
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@GLIBC_2.1
> +}
> +
> +{
> +   <libcdio 0.76 leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   obj:/usr/lib/libcdio.so.6.0.1
> +   fun:cdio_open_am_linux
> +   obj:/usr/lib/libcdio.so.6.0.1
> +   fun:cdio_open_am
> +}
> +
> +{
> +   <Addr8 on Jan's AMD64 ubuntu Feisty in dl_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.5.so
> +}
> +
> +{
> +   <First of many Alsa errors>
> +   Memcheck:Cond
> +   fun:snd_pcm_direct_shm_create_or_connect
> +   fun:snd_pcm_dsnoop_open
> +   fun:_snd_pcm_dsnoop_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_plug_open
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_asym_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +}
> +
> +{
> +   <alsa error>
> +   Memcheck:Cond
> +   fun:snd*_pcm_hw_param_set_near
> +}
> +
> +{
> +   <alsa error>
> +   Memcheck:Cond
> +   ...
> +   fun:snd*_pcm_hw_param_set_near
> +}
> +
> +{
> +   <alsa error>
> +   Memcheck:Cond
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_close
> +   obj:/*lib/libasound.so.2.0.0
> +}
> +{
> +   <alsa error>
> +   Memcheck:Cond
> +   fun:snd_pcm_direct_shm_create_or_connect
> +   fun:snd_pcm_dmix_open
> +   fun:_snd_pcm_dmix_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_softvol_open
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_plug_open
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_asym_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +}
> +{
> +   <alsa error>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:strdup
> +   fun:snd_dlobj_cache_add
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:snd_pcm_dsnoop_open
> +   fun:_snd_pcm_dsnoop_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_plug_open
> +   obj:/*lib/libasound.so.2.0.0
> +   fun:snd_pcm_open_slave
> +   fun:_snd_pcm_asym_open
> +   obj:/*lib/libasound.so.2.0.0
> +   obj:/*lib/libasound.so.2.0.0
> +}
> +# Catch about 15 variations on inserting info into an ALSA
> +# internal cache
> +{
> +   <alsa error>
> +   Memcheck:Leak
> +   fun:malloc
> +   ...
> +   fun:snd*_dlobj_cache_add
> +   obj:/*lib*/libasound.so.2.0.0
> +}
> +
> +{
> +   <alsa leak in loading configuration>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:snd_pcm_open_conf
> +}
> +
> +{
> +   <alsa leak snd_config_hook_load>
> +   Memcheck:Leak
> +   fun:*alloc
> +   obj:/*lib*/libasound.so.2.0.0
> +   ...
> +   fun:snd_config_hook_load
> +}
> +
> +{
> +   <alsa leak snd_config_update_r>
> +   Memcheck:Leak
> +   fun:*alloc
> +   obj:/*lib*/libasound.so.2.0.0
> +   ...
> +   fun:snd_config_update_r
> +   fun:snd_config_update
> +}
> +{
> +   <alsa leak snd_config_update_r>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:strdup
> +   ...
> +   fun:snd_config_update_r
> +   fun:snd_config_update
> +}
> +{
> +   <alsa leak snd_config_searcha_hooks>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:_dl_close_worker
> +   ...
> +   fun:snd_config_searcha_hooks
> +}
> +
> +{
> +   <nss lookup within ALSA>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:/lib/libc*.so
> +   fun:__nss_database_lookup
> +   obj:*
> +   obj:*
> +   fun:getgrnam_r
> +   fun:getgrnam
> +   fun:snd_pcm_direct_parse_open_conf
> +}
> +
> +{
> +   <libxcb leak on Ubuntu Feisty>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_XCBInitDisplayLock
> +   fun:XOpenDisplay
> +}
> +
> +# GConf internal initialisations related to getting the default client.
> +{
> +   <Orbit something or other>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_tcval
> +   obj:/usr/lib/libORBit-2.so.*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:CORBA_ORB_string_to_object
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_get_current_lock_holder
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so.*
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_tcval
> +   obj:*
> +   fun:PortableServer_POA_servant_to_reference
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_tcval
> +   obj:/usr/lib/libORBit-2.so.*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:CORBA_ORB_string_to_object
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_get_current_lock_holder
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so.*
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal initialisation>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:ORBit_demarshal_value
> +   fun:*
> +   fun:ORBit_small_invoke_stub
> +   fun:ConfigServer_get_default_database
> +   fun:*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:*
> +   fun:IOP_generate_profiles
> +   fun:ORBit_marshal_object
> +   fun:ORBit_marshal_value
> +   fun:*
> +   fun:ORBit_small_invoke_stub
> +   fun:ConfigServer_add_client
> +   fun:*
> +   fun:*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_by_tc
> +   fun:*
> +   fun:PortableServer_POA_servant_to_reference
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf internal init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_by_tc
> +   obj:/usr/lib/libORBit-2.so.*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:CORBA_ORB_string_to_object
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_get_current_lock_holder
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so.*
> +   obj:/usr/lib/libgconf-2.so.*
> +   fun:gconf_engine_get_default
> +}
> +
> +{
> +   <insert a suppression name here>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:*
> +   fun:*
> +   fun:gconf_activate_server
> +}
> +
> +# Some libORBit/bonobo initialisation stuff
> +{
> +   <bonobo init>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:ORBit_alloc_string
> +   fun:CORBA_string_dup
> +   fun:Bonobo_ActivationEnvValue_set
> +   fun:bonobo_activation_init_activation_env
> +   fun:bonobo_activation_orb_init
> +   fun:bonobo_activation_init
> +}
> +{
> +   <bonobo init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc*
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:PortableServer_POA_servant_to_reference
> +   obj:/usr/lib/libbonobo-2.so*
> +}
> +{
> +   <bonobo init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_tcval
> +   fun:ORBit_small_allocbuf
> +   fun:ORBit_adaptor_setup
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_POA_setup_root
> +   fun:ORBit_init_internals
> +   fun:CORBA_ORB_init
> +}
> +{
> +   <bonobo init - more recent variant of above>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc_tcval
> +   fun:ORBit_adaptor_setup
> +   fun:*
> +   fun:ORBit_POA_setup_root
> +   fun:ORBit_init_internals
> +   fun:CORBA_ORB_init
> +}
> +{
> +   <bonobo init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_allocbuf
> +   fun:bonobo_activation_init_activation_env
> +   fun:bonobo_activation_orb_init
> +   fun:bonobo_activation_init
> +}
> +
> +# More GConf stuff from the FC5 buildbot, mostly variations on the
> +# above stack traces
> +{
> +   <incompletely initialised ORBit buffer>
> +   Memcheck:Param
> +   writev(vector[...])
> +   fun:writev
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:link_connection_writev
> +   fun:giop_send_buffer_write
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_small_invoke_stub
> +   fun:ORBit_small_invoke_stub_n
> +   fun:ORBit_c_stub_invoke
> +   fun:ConfigServer_ping
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc*
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:PortableServer_POA_servant_to_reference
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:CORBA_ORB_string_to_object
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_get_current_lock_holder
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc*
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:CORBA_ORB_string_to_object
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_get_current_lock_holder
> +   fun:gconf_activate_server
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <bonobo init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc*
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_demarshal_IOR
> +   fun:ORBit_demarshal_object
> +   fun:ORBit_demarshal_value
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_small_invoke_stub
> +   fun:ORBit_small_invoke_stub_n
> +   fun:ORBit_c_stub_invoke
> +   fun:ConfigServer_get_default_database
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <gconf init>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:ORBit_alloc*
> +   fun:ORBit_small_alloc*
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_OAObject_object_to_objkey
> +   fun:IOP_generate_profiles
> +   fun:ORBit_marshal_object
> +   fun:ORBit_marshal_value
> +   obj:/usr/lib/libORBit-2.so*
> +   fun:ORBit_small_invoke_stub
> +   fun:ORBit_small_invoke_stub_n
> +   fun:ORBit_c_stub_invoke
> +   fun:ConfigServer_add_client
> +   obj:/usr/lib/libgconf-2.so*
> +   obj:/usr/lib/libgconf-2.so*
> +   fun:gconf_engine_get_default
> +}
> +{
> +   <GLib caching the home dir>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:*libc-*.so
> +   fun:__nss_database_lookup
> +   obj:*
> +   obj:*
> +   fun:getpwnam_r
> +   obj:/usr/lib*/libglib-2.0.so.*
> +   fun:g_get_home_dir
> +}
> +{
> +   <GLib caching the user name>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:*libc-*.so
> +   fun:__nss_database_lookup
> +   obj:*
> +   obj:*
> +   fun:getpwnam_r
> +   obj:/usr/lib*/libglib-2.0.so.*
> +   fun:g_get_user_name
> +}
> +{
> +   <GLib caching the tmp dir>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:*libc-*.so
> +   fun:__nss_database_lookup
> +   obj:*
> +   obj:*
> +   fun:getpwnam_r
> +   obj:/usr/lib*/libglib-2.0.so.*
> +   fun:g_get_tmp_dir
> +}
> +
> +{
> +   <GLib caching the host name>
> +   Memcheck:Leak
> +   fun:malloc
> +   obj:*libc-*.so
> +   fun:__nss_database_lookup
> +   obj:*
> +   obj:*
> +   fun:getpwnam_r
> +   obj:/usr/lib*/libglib-2.0.so.0.*
> +   fun:g_get_host_name
> +}
> +
> +
> +## Some Fontconfig errors.
> +{
> +   <First time load of a font - feisty x86_64>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:FcPatternObjectInsertElt
> +   fun:FcPatternObjectAddWithBinding
> +   fun:FcPatternAppend
> +   fun:FcEndElement
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   fun:XML_ParseBuffer
> +   fun:FcConfigParseAndLoad
> +   fun:FcConfigParseAndLoad
> +   fun:FcParseInclude
> +   fun:FcEndElement
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   obj:/usr/lib/libexpat.so.*
> +   fun:XML_ParseBuffer
> +   fun:FcConfigParseAndLoad
> +}
> +{
> +   <First time load of a font - generic>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:FcInitLoadConfig
> +}
> +
> +# Issues with ubuntu Hardy, same crack as for previous ubuntus
> +{
> +   <tls leak generic ubuntu hardy x86>
> +   Memcheck:Leak
> +   fun:calloc
> +   obj:*
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@*
> +   obj:/usr/lib/libgthread*
> +   fun:g_thread_*
> +}
> +
> +# I've made this version generic, so that it covers future modifications
> +# of library names
> +{
> +   <tls leak generic>
> +   Memcheck:Leak
> +   fun:calloc
> +   obj:*
> +   fun:_dl_allocate_tls
> +   fun:pthread_create@@*
> +   fun:g_thread_*
> +}
> +
> +# series of invalid read of size 4 in g_module_open for ubuntu
> +# hardy x86/32bit
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_*
> +}
> +
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_*
> +}
> +
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_*
> +}
> +
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load_*
> +}
> +
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +   fun:gst_plugin_load*
> +}
> +
> +{
> +   <invalid read of size 4 within <g_module_open>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   fun:_dl_sym
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libdl-2.7.so
> +   fun:dlsym
> +   fun:g_module_symbol
> +   fun:g_module_open
> +   fun:gst_plugin_load_*
> +}
> +
> +# series of invalid read of size 8 in g_module_open for ubuntu
> +# hardy x86/64bit
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlopen
> +   fun:g_module_open
> +}
> +
> +{
> +   <invalid read of size 8 within <g_module_open>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libdl-2.7.so
> +   fun:dlsym
> +   fun:g_module_symbol
> +   fun:g_module_open
> +}
> +
> +{
> +   <GLib caching>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   fun:__nss_lookup_function
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   fun:__nss_passwd_lookup
> +   fun:getpwnam_r
> +}
> +
> +{
> +   <GLib caching>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   fun:__nss_lookup_function
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   fun:__nss_passwd_lookup
> +   fun:getpwnam_r
> +}
> +
> +{
> +   <GLib caching>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   fun:__nss_lookup_function
> +   obj:/lib/tls/i686/cmov/libnss_compat-2.7.so
> +   fun:_nss_compat_getpwnam_r
> +   fun:getpwnam_r
> +}
> +
> +{
> +   <GLib caching>
> +   Memcheck:Addr4
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/tls/i686/cmov/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   fun:__nss_lookup_function
> +   obj:/lib/tls/i686/cmov/libnss_compat-2.7.so
> +   fun:_nss_compat_getpwnam_r
> +   fun:getpwnam_r
> +}
> +
> +{
> +   <GLib caching>
> +   Memcheck:Addr8
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/ld-2.7.so
> +   obj:/lib/libc-2.7.so
> +   obj:/lib/ld-2.7.so
> +   fun:__libc_dlopen_mode
> +   fun:__nss_lookup_function
> +   obj:/lib/libc-2.7.so
> +   fun:getpwnam_r
> +}
> +
> +## Leaks in ALSA (variations of leak from snd_config_load1)
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:_snd_config_make
> +   fun:_snd_config_make_add
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:snd1_dlobj_cache_add
> +   fun:snd_ctl_open_noupdate
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:*
> +   fun:snd1_dlobj_cache_add
> +   fun:snd_ctl_open_noupdate
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +{
> +   <Alsa leak>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:snd_config_load1
> +}
> +
> +
> +# The following are leaks of caps that need to be created dynamically
> +# in the type registration of the plugin (used for pad templates).
> +
> +{
> +   <Leak in ogmparsers>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_new_simple
> +   fun:*
> +   fun:g_type_class_ref
> +   fun:gst_element_register
> +}
> +
> +{
> +   <Leak in ogmparsers>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:*
> +   fun:*
> +   fun:g_type_class_ref
> +   fun:gst_element_register
> +   fun:gst_ogm_parse_plugin_init
> +   fun:plugin_init
> +}
> +
> +{
> +   <Leak in videotestsrc>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_copy
> +   fun:gst_video_test_src_base_init
> +   fun:g_type_class_ref
> +   fun:gst_element_register
> +}
> +
> +{
> +   <Leak in videotestsrc>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_copy
> +   fun:gst_video_test_src_getcaps
> +   fun:gst_video_test_src_base_init
> +   fun:g_type_class_ref
> +   fun:gst_element_register
> +}
> +
> +{
> +   <Leak in ffmpegcolorspace>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_ffmpegcsp_codectype_to_caps
> +   fun:gst_ffmpegcolorspace_register
> +   fun:plugin_init
> +}
> +
> +{
> +   <Leak in ffmpegocolorspace>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_copy
> +   fun:gst_ffmpegcolorspace_register
> +   fun:plugin_init
> +}
> +
> +{
> +   <Leak in gstffmpegdemux>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_new_any
> +   fun:gst_ffmpegdemux_register
> +   fun:plugin_init
> +}
> +
> +{
> +   <Leak in GstAudioFilter subclasses>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +
> +{
> +   <Leak in GstAudioFilter subclasses, variant>
> +   Memcheck:Leak
> +   fun:realloc
> +   fun:g_realloc
> +   fun:g_ptr_array_maybe_expand
> +   fun:g_ptr_array_add
> +   fun:gst_caps_append
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +
> +{
> +   <Leak in GstAudioFilter subclasses, variant>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:g_ptr_array_maybe_expand
> +   fun:g_ptr_array_add
> +   fun:gst_caps_append
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +
> +{
> +   <Leak in GstAudioFilter subclasses, variant>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:g_ptr_array_maybe_expand
> +   fun:g_ptr_array_add
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +
> +{
> +   <Leak in GstAudioFilter subclasses, variant2>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:g_ptr_array_sized_new
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +{
> +   <Leak in GstAudioFilter subclasses, variant3>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:g_array_maybe_expand
> +   fun:g_array_sized_new
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:gst_value_init_and_copy
> +   fun:gst_structure_copy
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +{
> +   <Leak in GstAudioFilter subclasses, variant4>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:g_array_maybe_expand
> +   fun:g_array_sized_new
> +   fun:*
> +   fun:gst_structure_copy
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +{
> +   <Leak in GstAudioFilter subclasses, variant5>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:g_array_sized_new
> +   fun:*
> +   fun:gst_structure_copy
> +   fun:gst_caps_copy
> +   fun:gst_audio_filter_class_add_pad_templates
> +}
> +
> +{
> +   <Leak in riff-media>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_riff_create_*_template_caps
> +}
> +{
> +   <Leak in riff-media>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:realloc
> +   fun:g_realloc
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:gst_structure_copy
> +   fun:gst_caps_copy
> +   fun:gst_caps_append
> +   fun:gst_riff_create_*_template_caps
> +}
> +{
> +   <Leak in riff-media>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:g_array_sized_new
> +   fun:*
> +   fun:gst_structure_copy
> +   fun:gst_caps_copy
> +   fun:gst_caps_append
> +   fun:gst_riff_create_*_template_caps
> +}
> +
> +## Leaks in pango (bilboed: gentoo unstable amd64)
> +
> +{
> +   <Pango leak - generic>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:pango_layout_get_pixel_extents
> +}
> +{
> +   <insert a suppression name here>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:pango_language_from_string
> +   fun:pango_language_get_default
> +   fun:pango_context_init
> +   fun:g_type_create_instance
> +   fun:g_object_constructor
> +   fun:g_object_newv
> +   fun:g_object_new_valist
> +   fun:g_object_new
> +   fun:pango_font_map_create_context
> +}
> +
> +{
> +   <PangoLanguage can never be freed>
> +   Memcheck:Leak
> +   fun:calloc
> +   fun:g_malloc0
> +   fun:pango_language_from_string
> +}
> +
> +
> +## Leak of everything allocated by gst-libav plugin init
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:gst_ffmpeg_cfg_init
> +}
> +
> +## Leak of GIO module through gnomevfs
> +
> +{
> +   <gio leak>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:*
> +   fun:*
> +   fun:g_type_create_instance
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:g_io_module_new
> +   fun:g_io_modules_load_all_in_directory
> +   fun:*
> +   fun:get_default_vfs
> +}
> +
> +## Conditional jump in getaddrinfo (bilboed, gentoo ~amd64, Dec 13 2008)
> +{
> +   <Leak of addrinfo in esd>
> +   Memcheck:Cond
> +   fun:gaih_inet
> +   fun:getaddrinfo
> +}
> +
> +## Dynamic pad templates in mxfmux
> +{
> +   <Dynamic pad templates in mxfmux>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_slice_alloc
> +   fun:gst_caps_new_empty
> +   fun:gst_caps_from_string
> +   fun:mxf_*_init
> +   fun:plugin_init
> +}
> +
> +## We don't know if ffmpeg frees this or not and better pass a copy for safety
> +{
> +   <insert a suppression name here>
> +   Memcheck:Leak
> +   fun:malloc
> +   fun:g_malloc
> +   fun:g_strdup
> +   fun:gst_ffmpeg_cfg_fill_context
> +   fun:gst_ffmpegenc_setcaps
> +   fun:gst_pad_set_caps
> +}
> +
> +## Leak/overreads with glibc-2.10
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:do_sym
> +   fun:dlsym_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlsym
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:do_sym
> +   fun:dlsym_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlsym
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_relocate_object
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_check_map_versions
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_relocate_object
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_check_map_versions
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_map_object*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_map_object*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_check_caller
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_check_caller
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen*
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   obj:/lib*/libc-2.10.*.so
> +   obj:/lib*/libc-2.10.*.so
> +   fun:_vgnU_freeres
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   obj:/lib*/libc-2.10.*.so
> +   obj:/lib*/libc-2.10.*.so
> +   fun:_vgnU_freeres
> +}
> +{
> +   <glibc-2.10 mysterious invalid free on exit>
> +   Memcheck:Free
> +   fun:free
> +   obj:/lib*/libc-2.10.*.so
> +   obj:/lib*/libc-2.10.*.so
> +   fun:_vgnU_freeres
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_fini
> +   fun:__run_exit_handlers
> +   fun:exit
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_fini
> +   fun:__run_exit_handlers
> +   fun:exit
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_sort_fini
> +   fun:_dl_fini
> +   fun:__run_exit_handlers
> +   fun:exit
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_sort_fini
> +   fun:_dl_fini
> +   fun:__run_exit_handlers
> +   fun:exit
> +}
> +
> +# glibc-2.10 dl overreads
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_fixup
> +   fun:_dl_runtime_resolve
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_fixup
> +   fun:_dl_runtime_resolve
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_fixup
> +   fun:_dl_runtime_resolve
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_fixup
> +   fun:_dl_runtime_resolve
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:call_init
> +   fun:_dl_init
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_init
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:dl_main
> +   fun:_dl_sysdep_start
> +   fun:_dl_start
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:dl_main
> +   fun:_dl_sysdep_start
> +   fun:_dl_start
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_check_map_versions
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_check_map_versions
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_check_map_versions
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_check_map_versions
> +   fun:_dl_check_all_versions
> +   fun:version_check_doit
> +   fun:_dl_receive_error
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:init_tls
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:init_tls
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_protect_relro
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_setup_hash
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_new_object
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_new_object
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:open_path
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:open_path
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_new_object
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_new_object
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_new_object
> +   fun:_dl_map_object_from_fd
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:*
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_name_match_p
> +   fun:_dl_check_map_versions
> +   fun:_dl_check_all_versions
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:do_lookup_x
> +   fun:_dl_lookup_symbol_x
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +   fun:dl_open_worker
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +   fun:dl_open_worker
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +   fun:dl_open_worker
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +   fun:dl_open_worker
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_lookup_symbol_x
> +   fun:_dl_relocate_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:_dl_check_map_versions
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_check_map_versions
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:*
> +   fun:_dl_check_map_versions
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_check_map_versions
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:openaux
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_name_match_p
> +   fun:_dl_map_object
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_close_worker
> +   fun:_dl_close
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_close_worker
> +   fun:_dl_close
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_close_worker
> +   fun:_dl_close
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_close_worker
> +   fun:_dl_close
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:fillin_rpath
> +   fun:_dl_init_paths
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:fillin_rpath
> +   fun:_dl_init_paths
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:fillin_rpath
> +   fun:_dl_init_paths
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:fillin_rpath
> +   fun:_dl_init_paths
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_map_object
> +   fun:map_doit
> +   fun:_dl_catch_error
> +   fun:do_preload
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_map_object
> +   fun:map_doit
> +   fun:_dl_catch_error
> +   fun:do_preload
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Param
> +   open(filename)
> +   fun:open
> +   fun:open_verify
> +   fun:_dl_map_object
> +   fun:map_doit
> +   fun:_dl_catch_error
> +   fun:do_preload
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Param
> +   stat(file_name)
> +   fun:_xstat
> +   fun:open_path
> +   fun:_dl_map_object
> +   fun:openaux
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_catch_error
> +   fun:_dl_map_object_deps
> +   fun:dl_open_worker
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:_dl_map_object_deps
> +   fun:dl_main
> +}
> +
> +# glibc-2.10 tls issues
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:init_tls
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:init_tls
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:*
> +   fun:init_tls
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:init_tls
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:_dl_allocate_tls_init
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:_dl_allocate_tls_init
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:*
> +   fun:_dl_allocate_tls_init
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Value8
> +   fun:*
> +   fun:_dl_allocate_tls_init
> +   fun:dl_main
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Cond
> +   fun:__tls*
> +   obj:*
> +   obj:*
> +   fun:_vgnU_freeres
> +}
> +
> +{
> +   <glibc-2.10 overreads/conditionals>
> +   Memcheck:Param
> +   arch_prctl(arg2)
> +   fun:init_tls
> +}
> +# GLib caching tmp/home directories (glibc-2.10 variants)
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Cond
> +   fun:*
> +   fun:dl_open_worker
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +   fun:*
> +   fun:__nss_lookup_function
> +   fun:__nss_lookup
> +   fun:getpwnam*
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:dl_open_worker
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:_dl_catch_error
> +   fun:dlerror_run
> +   fun:*
> +   fun:__nss_lookup_function
> +   fun:__nss_lookup
> +   fun:getpwnam*
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Cond
> +   fun:dl_open_worker
> +   fun:*
> +   fun:*
> +   fun:do_dlopen
> +   fun:*
> +   fun:dlerror_run
> +   fun:*
> +   fun:__nss_lookup_function
> +   fun:__nss_lookup
> +   fun:getpwnam*
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:dl_open_worker
> +   fun:*
> +   fun:*
> +   fun:do_dlopen
> +   fun:*
> +   fun:dlerror_run
> +   fun:*
> +   fun:__nss_lookup_function
> +   fun:__nss_lookup
> +   fun:getpwnam*
> +}
> +
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:_dl_add_to_slotinfo
> +   fun:dl_main
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Param
> +   open(filename)
> +   fun:open
> +   fun:open_verify
> +   fun:open_path
> +   fun:_dl_map_object
> +}
> +
> +
> +
> +# GModule issues with glibc-2.10
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:dlsym
> +   fun:g_module_symbol
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:g_module_*
> +   fun:gst_plugin*
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:g_module_*
> +   fun:gst_plugin*
> +}
> +
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:dlopen*
> +   fun:g_module_open
> +}
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:dlsym
> +   fun:g_module_symbol
> +}
> +
> +{
> +   <glibc-2.10 GLIB leaks>
> +   Memcheck:Value8
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:*
> +   fun:dlopen*
> +   fun:g_module_open
> +}
> +
> +# Leak in GSlice
> +{
> +   <insert a suppression name here>
> +   Memcheck:Value8
> +   fun:g_parse_debug_string
> +   fun:slice_config_init
> +   fun:g_slice_init_nomessage
> +   fun:_g_slice_thread_init_nomessage
> +   fun:g_thread_init_glib
> +}
> +
> +# 2.10 pthread issues
> +{
> +   <insert a suppression name here>
> +   Memcheck:Value8
> +   fun:__pthread_initialize_minimal
> +}
> +
> +# glibc 2.11 conditional
> +{
> +   <glibc-2.11 conditional>
> +   Memcheck:Cond
> +   fun:_dl_relocate_object
> +   fun:dl_main
> +   fun:_dl_sysdep_start
> +   fun:_dl_start
> +   obj:/lib64/ld-2.11.so
> +}
> +
> +# glibc 2.11 Leak
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:_dl_*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:_dl_*
> +   fun:_dl_*
> +   fun:_dl_*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:_dl_*
> +   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
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:_dl_map_object
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   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
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:_dl_*
> +   fun:_dl_*
> +   fun:_dl_*
> +   fun:dl_open_worker
> +   fun:_dl_catch_error
> +   fun:_dl_open
> +   fun:dlopen_doit
> +   fun:_dl_catch_error
> +   fun:_dlerror_run
> +   fun:dlopen@@GLIBC_2.2.5
> +}
> +
> +# glib type leaks
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:g_type_register_static
> +}
> +
> +# new registry system
> +# all of this will only be created once when loading registry.
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:_priv_gst_registry_chunks_load_plugin
> +}
> +
> +# system-wide tags
> +# these tags are registered once
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:*
> +   fun:*
> +   fun:gst_tag_register
> +   fun:_gst_tag_initialize
> +}
> +
> +# system-wide type classes that we keep referenced
> +
> +{
> +   <g_type_class_ref leaks>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:g_type_class_ref
> +}
> +
> +# leaking cached queries which are only initialized once
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:_gst_query_initialize
> +   fun:init_post
> +}
> +
> +# macosx (leopard) library loader leak
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:_Znwm
> +   fun:_ZNSs4_Rep9_S_createEmmRKSaIcE
> +   fun:_ZNSs12_S_constructIPKcEEPcT_S3_RKSaIcESt20forward_iterator_tag
> +   fun:_ZNSsC2EPKcRKSaIcE
> +   fun:_Z41__static_initialization_and_destruction_0ii
> +   fun:_ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE
> +}
> +
> +# GObject type registration
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:g_param_type_register_static
> +   ...
> +}
> +
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:_g_atomic_array_copy
> +}
> +
> +{
> +   <getdelim one-time inits called from libselinux>
> +   Memcheck:Leak
> +   fun:*alloc
> +   fun:getdelim
> +   obj:*libselinux*
> +}
> +
> +{
> +   <weird one when re-reading registry>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   obj:*/sed
> +}
> +
> +{
> +   <weird one when re-reading registry>
> +   Memcheck:Addr8
> +   ...
> +   obj:*/sed
> +}
> +
> +# GLib 2.23 interface vtable
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:g_type_add_interface_static
> +}
> +
> +{
> +   <leak in dash on debian sid>
> +   Memcheck:Leak
> +   fun:*alloc
> +   obj:*/dash
> +}
> +
> +# libtool/gentoo fake leak
> +# it actually runs bash and valgrind complains
> +{
> +   <insert_a_suppression_name_here>
> +   Memcheck:Leak
> +   fun:*alloc
> +   obj:/bin/bash
> +}
> +
> +{
> +   <ignore possbly-lost leaks in the plugin scanner which doesn't clean up properly>
> +   Memcheck:Leak
> +   fun:*alloc
> +   ...
> +   fun:_gst_plugin_loader_client_run
> +   fun:main
> +}
> +
> +{
> +   <warning with libc 2.13-2 as in Debian/unstable on amd64>
> +   Memcheck:Cond
> +   fun:*strcasecmp*
> +   ...
> +   fun:__dcigettext
> +}
> +
> +{
> +   <warning with libc 2.13-2 as in Debian/unstable on amd64>
> +   Memcheck:Value8
> +   fun:*strcasecmp*
> +   ...
> +   fun:__dcigettext
> +}
> +
> +{
> +   <GstSystemClock is a singleton and does not leak>
> +   Memcheck:Leak
> +   fun:malloc
> +   ...
> +   fun:gst_poll_new
> +   fun:gst_poll_new_timer
> +   fun:gst_system_clock_init
> +}
> +
> +{
> +   <glib types are singletons>
> +   Memcheck:Leak
> +   fun:calloc
> +   ...
> +   fun:gobject_init_ctor
> +}
> +
> +{
> +   <quark table is leaked on purpose if it grows too big>
> +   Memcheck:Leak
> +   fun:malloc
> +   ...
> +   fun:g_quark_from*_string
> +}
> +
> +{
> +  <timer_create suppressions for earlier valgrind versions that complain>
> +  Memcheck:Param
> +  timer_create(evp)
> +  fun:timer_create@@GLIBC_2.3.3
> +}
> +
> +{
> +   closures aren't valgrind friendly (bgo#739850)
> +   Memcheck:Leak
> +   match-leak-kinds: possible
> +   fun:calloc
> +   ...
> +   fun:g_cclosure_new
> +}
> +
> +{
> +   closures aren't valgrind friendly (bgo#739850)
> +   Memcheck:Leak
> +   match-leak-kinds: possible
> +   fun:malloc
> +   ...
> +   fun:g_closure_add_invalidate_notifier
> +}
> +
> +{
> +   closures aren't valgrind friendly (bgo#739850)
> +   Memcheck:Leak
> +   match-leak-kinds: possible
> +   fun:calloc
> +   ...
> +   fun:g_closure_new_simple
> +}
> +
> +{
> +   glib/giomodules2 (from libsoup.supp)
> +   Memcheck:Leak
> +   ...
> +   fun:_g_io_module_get_default
> +}
> \ No newline at end of file
> 
> === modified file 'src/core/media/CMakeLists.txt'
> --- src/core/media/CMakeLists.txt	2015-02-24 15:22:19 +0000
> +++ src/core/media/CMakeLists.txt	2015-04-17 14:35:22 +0000
> @@ -1,7 +1,3 @@
> -pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0)
> -pkg_check_modules(PC_PULSE_AUDIO REQUIRED libpulse)
> -include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} ${HYBRIS_MEDIA_CFLAGS} ${PC_PULSE_AUDIO_INCLUDE_DIRS})
> -
>  # We compile with all symbols visible by default. For the shipping library, we strip
>  # out all symbols that are not in core::ubuntu::media*
>  set(symbol_map "${CMAKE_SOURCE_DIR}/symbols.map")
> @@ -109,7 +105,7 @@
>      gstreamer/playbin.cpp
>  
>      player_skeleton.cpp
> -    player_implementation.cpp
> +#    player_implementation.cpp

Why is this commented out?

>      service_skeleton.cpp
>      service_implementation.cpp
>      track_list_skeleton.cpp
> @@ -125,11 +121,11 @@
>    ${DBUS_LIBRARIES}
>    ${DBUS_CPP_LDFLAGS}
>    ${GLog_LIBRARY}
> -  ${PC_GSTREAMER_1_0_LIBRARIES}
> +  ${GSTREAMER_1_0_LIBRARIES}
>    ${PROCESS_CPP_LDFLAGS}
>    ${GIO_LIBRARIES}
>    ${HYBRIS_MEDIA_LIBRARIES}
> -  ${PC_PULSE_AUDIO_LIBRARIES}
> +  ${PULSE_AUDIO_LIBRARIES}
>  )
>  
>  include_directories(${PROJECT_SOURCE_DIR}/src/ ${HYBRIS_MEDIA_CFLAGS})
> @@ -150,7 +146,7 @@
>    ${DBUS_LIBRARIES}
>    ${DBUS_CPP_LDFLAGS}
>    ${GLog_LIBRARY}
> -  ${PC_GSTREAMER_1_0_LIBRARIES}
> +  ${GSTREAMER_1_0_LIBRARIES}
>    ${HYBRIS_MEDIA_LIBRARIES}
>  )
>  
> 
> === modified file 'src/core/media/gstreamer/engine.cpp'
> --- src/core/media/gstreamer/engine.cpp	2015-03-11 16:17:23 +0000
> +++ src/core/media/gstreamer/engine.cpp	2015-04-17 14:35:22 +0000
> @@ -33,18 +33,29 @@
>  
>  namespace gstreamer
>  {
> -struct Init
> +struct GlobalState
>  {
> -    Init()
> +    GlobalState()
>      {
>          gst_init(nullptr, nullptr);
>      }
>  
> -    ~Init()
> +    ~GlobalState()
>      {
>          gst_deinit();
>      }
> -} init;
> +
> +    bool is_initialized() const
> +    {
> +        return true;
> +    }
> +};
> +
> +bool init()
> +{
> +    static const GlobalState state;
> +    return state.is_initialized();
> +}
>  }
>  
>  struct gstreamer::Engine::Private
> @@ -181,7 +192,8 @@
>      }
>  
>      Private()
> -        : meta_data_extractor(new gstreamer::MetaDataExtractor()),
> +        : ensure_gstreamer_is_initialized(init()),
> +          meta_data_extractor(new gstreamer::MetaDataExtractor()),
>            volume(media::Engine::Volume(1.)),
>            orientation(media::Player::Orientation::rotate0),
>            is_video_source(false),
> @@ -270,6 +282,8 @@
>      {
>      }
>  
> +    // Make sure that gstreamer setup procedures are called.
> +    bool ensure_gstreamer_is_initialized;
>      // Ensure the playbin is the last item destroyed
>      // otherwise properties could try to access a dead playbin object
>      gstreamer::Playbin playbin;
> @@ -312,6 +326,7 @@
>  
>  gstreamer::Engine::Engine() : d(new Private{})
>  {
> +    gstreamer::init();
>      cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
>      d->state = media::Engine::State::ready;
>  }
> 
> === modified file 'src/core/media/gstreamer/meta_data_extractor.h'
> --- src/core/media/gstreamer/meta_data_extractor.h	2014-10-14 20:05:20 +0000
> +++ src/core/media/gstreamer/meta_data_extractor.h	2015-04-17 14:35:22 +0000
> @@ -147,7 +147,7 @@
>      MetaDataExtractor()
>          : pipe(gst_pipeline_new("meta_data_extractor_pipeline")),
>            decoder(gst_element_factory_make ("uridecodebin", NULL)),
> -          bus(GST_ELEMENT_BUS(pipe))
> +          bus(gst_element_get_bus(pipe))
>      {
>          gst_bin_add(GST_BIN(pipe), decoder);
>  
> @@ -157,10 +157,48 @@
>          g_signal_connect (decoder, "pad-added", G_CALLBACK (on_new_pad), sink);
>      }
>  
> +    MetaDataExtractor(const MetaDataExtractor&) = delete;
> +    MetaDataExtractor(MetaDataExtractor&&) = delete;
> +
>      ~MetaDataExtractor()
>      {
> -        gst_element_set_state(pipe, GST_STATE_NULL);
> -        // gst_object_unref(pipe);
> +        set_state_and_wait(GST_STATE_NULL);
> +        gst_object_unref(pipe);
> +    }
> +
> +    MetaDataExtractor& operator=(const MetaDataExtractor&) = delete;
> +    MetaDataExtractor& operator=(const MetaDataExtractor&&) = delete;
> +
> +    bool set_state_and_wait(GstState new_state)
> +    {
> +        static const std::chrono::nanoseconds state_change_timeout
> +        {
> +            // We choose a quite high value here as tests are run under valgrind
> +            // and gstreamer pipeline setup/state changes take longer in that scenario.
> +            // The value does not negatively impact runtime performance.
> +            std::chrono::milliseconds{5000}
> +        };
> +
> +        auto ret = gst_element_set_state(pipe, new_state);
> +
> +        bool result = false; GstState current, pending;
> +        switch(ret)
> +        {
> +            case GST_STATE_CHANGE_FAILURE:
> +                result = false; break;
> +            case GST_STATE_CHANGE_NO_PREROLL:
> +            case GST_STATE_CHANGE_SUCCESS:
> +                result = true; break;
> +            case GST_STATE_CHANGE_ASYNC:
> +                result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state(
> +                    pipe,
> +                    &current,
> +                    &pending,
> +                    state_change_timeout.count());
> +                break;
> +        }
> +
> +        return result;
>      }
>  
>      core::ubuntu::media::Track::MetaData meta_data_for_track_with_uri(const core::ubuntu::media::Track::UriType& uri)
> @@ -189,15 +227,18 @@
>          };
>  
>          g_object_set(decoder, "uri", uri.c_str(), NULL);
> -        gst_element_set_state(pipe, GST_STATE_PAUSED);
> +        if (not set_state_and_wait(GST_STATE_PAUSED))
> +        {
> +            // TODO: This error condition should be handled and at least reported here.
> +        }
>  
>          if (std::future_status::ready != future.wait_for(std::chrono::seconds(2)))
>          {
> -            gst_element_set_state(pipe, GST_STATE_NULL);
> +            set_state_and_wait(GST_STATE_NULL);
>              throw std::runtime_error("Problem extracting meta data for track");
>          } else
>          {
> -            gst_element_set_state(pipe, GST_STATE_NULL);
> +            set_state_and_wait(GST_STATE_NULL);
>          }
>  
>          return future.get();
> 
> === modified file 'src/core/media/gstreamer/playbin.cpp'
> --- src/core/media/gstreamer/playbin.cpp	2015-03-11 16:17:23 +0000
> +++ src/core/media/gstreamer/playbin.cpp	2015-04-17 14:35:22 +0000
> @@ -127,6 +127,7 @@
>  
>  gstreamer::Playbin::~Playbin()
>  {
> +    std::cout << pipeline << std::endl;
>      if (pipeline)
>          gst_object_unref(pipeline);
>  }
> 
> === modified file 'src/core/media/mpris/player.h'
> --- src/core/media/mpris/player.h	2015-03-11 16:17:23 +0000
> +++ src/core/media/mpris/player.h	2015-04-17 14:35:22 +0000
> @@ -173,6 +173,32 @@
>          DBUS_CPP_READABLE_PROPERTY_DEF(CanControl, Player, bool)
>      };
>  
> +    // Default values for properties
> +    struct Defaults
> +    {
> +        Properties::CanPlay::ValueType can_play{true};
> +        Properties::CanPause::ValueType can_pause{true};
> +        Properties::CanSeek::ValueType can_seek{true};
> +        Properties::CanControl::ValueType can_control{true};
> +        Properties::CanGoNext::ValueType can_go_next{true};
> +        Properties::CanGoPrevious::ValueType can_go_previous{true};
> +        Properties::IsVideoSource::ValueType is_video_source{false};
> +        Properties::IsAudioSource::ValueType is_audio_source{true};
> +        Properties::PlaybackStatus::ValueType playback_status{PlaybackStatus::stopped};
> +        Properties::TypedPlaybackStatus::ValueType typed_playback_status{core::ubuntu::media::Player::PlaybackStatus::null};
> +        Properties::LoopStatus::ValueType loop_status{LoopStatus::none};
> +        Properties::TypedLoopStatus::ValueType typed_loop_status{core::ubuntu::media::Player::LoopStatus::none};
> +        Properties::PlaybackRate::ValueType playback_rate{1.f};
> +        Properties::Shuffle::ValueType shuffle{false};
> +        Properties::TypedMetaData::ValueType typed_meta_data{};
> +        Properties::Volume::ValueType volume{0.f};
> +        Properties::Position::ValueType position{0};
> +        Properties::Duration::ValueType duration{0};
> +        Properties::MinimumRate::ValueType minimum_rate{1.f};
> +        Properties::MaximumRate::ValueType maximum_rate{1.f};
> +        Properties::Orientation::ValueType orientation{core::ubuntu::media::Player::Orientation::rotate0};
> +    };
> +
>      // Convenience struct to create a skeleton implementation for org.mpris.MediaPlayer2.Player
>      struct Skeleton
>      {
> @@ -188,32 +214,8 @@
>              core::dbus::Bus::Ptr bus;
>              // The dbus object that should implement org.mpris.MediaPlayer2
>              core::dbus::Object::Ptr object;
> -
>              // Default values for properties
> -            struct Defaults
> -            {
> -                Properties::CanPlay::ValueType can_play{true};
> -                Properties::CanPause::ValueType can_pause{true};
> -                Properties::CanSeek::ValueType can_seek{true};
> -                Properties::CanControl::ValueType can_control{true};
> -                Properties::CanGoNext::ValueType can_go_next{true};
> -                Properties::CanGoPrevious::ValueType can_go_previous{true};
> -                Properties::IsVideoSource::ValueType is_video_source{false};
> -                Properties::IsAudioSource::ValueType is_audio_source{true};
> -                Properties::PlaybackStatus::ValueType playback_status{PlaybackStatus::stopped};
> -                Properties::TypedPlaybackStatus::ValueType typed_playback_status{core::ubuntu::media::Player::PlaybackStatus::null};
> -                Properties::LoopStatus::ValueType loop_status{LoopStatus::none};
> -                Properties::TypedLoopStatus::ValueType typed_loop_status{core::ubuntu::media::Player::LoopStatus::none};
> -                Properties::PlaybackRate::ValueType playback_rate{1.f};
> -                Properties::Shuffle::ValueType shuffle{false};
> -                Properties::TypedMetaData::ValueType typed_meta_data{};
> -                Properties::Volume::ValueType volume{0.f};
> -                Properties::Position::ValueType position{0};
> -                Properties::Duration::ValueType duration{0};
> -                Properties::MinimumRate::ValueType minimum_rate{1.f};
> -                Properties::MaximumRate::ValueType maximum_rate{1.f};
> -                Properties::Orientation::ValueType orientation{core::ubuntu::media::Player::Orientation::rotate0};
> -            } defaults;
> +            Defaults defaults;
>          };
>  
>          Skeleton(const Configuration& configuration)
> @@ -278,35 +280,84 @@
>              properties.maximum_playback_rate->set(configuration.defaults.maximum_rate);
>  
>              // Make sure the Orientation Property gets sent over DBus to the client
> +            properties.can_play->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanPlay>(value);
> +            });
> +            properties.can_pause->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanPause>(value);
> +            });
> +            properties.can_seek->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanSeek>(value);
> +            });
> +            properties.can_control->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanControl>(value);
> +            });
> +            properties.can_go_next->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanGoNext>(value);
> +            });
> +            properties.can_go_previous->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::CanGoPrevious>(value);
> +            });
> +            properties.is_video_source->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::IsVideoSource>(value);
> +            });
> +            properties.is_audio_source->changed().connect([this](bool value)
> +            {
> +                on_property_value_changed<Properties::IsAudioSource>(value);
> +            });
>              properties.orientation->changed().connect([this](const core::ubuntu::media::Player::Orientation& o)
>              {
>                  on_property_value_changed<Properties::Orientation>(o);
>              });
> -
>              properties.position->changed().connect([this](std::int64_t position)
>              {
>                  on_property_value_changed<Properties::Position>(position);
>              });
> -
>              properties.duration->changed().connect([this](std::int64_t duration)
>              {
>                  on_property_value_changed<Properties::Duration>(duration);
>              });
> -
>              properties.playback_status->changed().connect([this](const std::string& status)
>              {
>                  on_property_value_changed<Properties::PlaybackStatus>(status);
>              });
> -
>              properties.loop_status->changed().connect([this](const std::string& status)
>              {
>                  on_property_value_changed<Properties::LoopStatus>(status);
>              });
> +            properties.audio_stream_role->changed().connect([this](core::ubuntu::media::Player::AudioStreamRole role)
> +            {
> +                on_property_value_changed<Properties::AudioStreamRole>(role);
> +            });
> +            properties.lifetime->changed().connect([this](core::ubuntu::media::Player::Lifetime lt)
> +            {
> +                on_property_value_changed<Properties::Lifetime>(lt);
> +            });
> +            properties.playback_rate->changed().connect([this](double rate)
> +            {
> +                on_property_value_changed<Properties::PlaybackRate>(rate);
> +            });
> +            properties.minimum_playback_rate->changed().connect([this](double rate)
> +            {
> +                on_property_value_changed<Properties::MinimumRate>(rate);
> +            });
> +            properties.maximum_playback_rate->changed().connect([this](double rate)
> +            {
> +                on_property_value_changed<Properties::MaximumRate>(rate);
> +            });
>          }
>  
>          template<typename Property>
>          void on_property_value_changed(const typename Property::ValueType& value)
>          {
> +            std::cout << __PRETTY_FUNCTION__ << std::endl;
>              Dictionary dict; dict[Property::name()] = dbus::types::Variant::encode(value);
>  
>              signals.properties_changed->emit(std::make_tuple(
> 
> === added file 'src/core/media/player_base.h'
> --- src/core/media/player_base.h	1970-01-01 00:00:00 +0000
> +++ src/core/media/player_base.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,332 @@
> +/*
> + * Copyright © 2013-2015 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef CORE_UBUNTU_MEDIA_PLAYER_BASE_H_
> +#define CORE_UBUNTU_MEDIA_PLAYER_BASE_H_
> +
> +#include <core/media/player.h>
> +
> +namespace core
> +{
> +namespace ubuntu
> +{
> +namespace media
> +{
> +// PlayerBase is a helper class that helps with testing.
> +class PlayerBase : public Player
> +{
> +public:
> +    // Empty on purpose
> +    struct Configuration {};
> +
> +    PlayerBase(const Configuration&) {}
> +
> +    // All properties go here
> +    const core::Property<Lifetime>& lifetime() const
> +    {
> +        return properties.lifetime;
> +    }
> +
> +    core::Property<Lifetime>& lifetime()
> +    {
> +        return properties.lifetime;
> +    }
> +
> +    const core::Property<bool>& can_play() const
> +    {
> +        return properties.can_play;
> +    }
> +
> +    const core::Property<bool>& can_pause() const
> +    {
> +        return properties.can_pause;
> +    }
> +
> +    const core::Property<bool>& can_seek() const
> +    {
> +        return properties.can_seek;
> +    }
> +
> +    const core::Property<bool>& can_go_previous() const
> +    {
> +        return properties.can_go_previous;
> +    }
> +
> +    const core::Property<bool>& can_go_next() const
> +    {
> +        return properties.can_go_next;
> +    }
> +
> +    const core::Property<bool>& is_video_source() const
> +    {
> +        return properties.is_video_source;
> +    }
> +
> +    const core::Property<bool>& is_audio_source() const
> +    {
> +        return properties.is_audio_source;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::PlaybackStatus>& playback_status() const
> +    {
> +        return properties.playback_status;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::LoopStatus>& loop_status() const
> +    {
> +        return properties.loop_status;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::PlaybackRate>& playback_rate() const
> +    {
> +        return properties.playback_rate;
> +    }
> +
> +    const core::Property<bool>& is_shuffle() const
> +    {
> +        return properties.is_shuffle;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Track::MetaData>& meta_data_for_current_track() const
> +    {
> +        return properties.meta_data_for_current_track;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::Volume>& volume() const
> +    {
> +        return properties.volume;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::PlaybackRate>& minimum_playback_rate() const
> +    {
> +        return properties.minimum_playback_rate;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::PlaybackRate>& maximum_playback_rate() const
> +    {
> +        return properties.maximum_playback_rate;
> +    }
> +
> +    const core::Property<int64_t>& position() const
> +    {
> +        return properties.position;
> +    }
> +
> +    const core::Property<int64_t>& duration() const
> +    {
> +        return properties.duration;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::AudioStreamRole>& audio_stream_role() const
> +    {
> +        return properties.audio_stream_role;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::Orientation>& orientation() const
> +    {
> +        return properties.orientation;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::LoopStatus>& loop_status()
> +    {
> +        return properties.loop_status;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::PlaybackRate>& playback_rate()
> +    {
> +        return properties.playback_rate;
> +    }
> +
> +    core::Property<bool>& is_shuffle()
> +    {
> +        return properties.is_shuffle;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::Volume>& volume()
> +    {
> +        return properties.volume;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::AudioStreamRole>& audio_stream_role()
> +    {
> +        return properties.audio_stream_role;
> +    }
> +
> +    const core::Signal<int64_t>& seeked_to() const
> +    {
> +        return sigs.seeked_to;
> +    }
> +
> +    const core::Signal<void>& end_of_stream() const
> +    {
> +        return sigs.end_of_stream;
> +    }
> +
> +    const core::Signal<void>& about_to_finish() const
> +    {
> +        return sigs.about_to_finish;
> +    }
> +
> +    core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed()
> +    {
> +        return sigs.playback_status_changed;
> +    }
> +
> +    const core::Signal<core::ubuntu::media::video::Dimensions>& video_dimension_changed() const
> +    {
> +        return sigs.video_dimension_changed;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::PlaybackStatus>& playback_status()
> +    {
> +        return properties.playback_status;
> +    }
> +
> +    core::Property<bool>& can_play()
> +    {
> +        return properties.can_play;
> +    }
> +
> +    core::Property<bool>& can_pause()
> +    {
> +        return properties.can_pause;
> +    }
> +
> +    core::Property<bool>& can_seek()
> +    {
> +        return properties.can_seek;
> +    }
> +
> +    core::Property<bool>& can_go_previous()
> +    {
> +        return properties.can_go_previous;
> +    }
> +
> +    core::Property<bool>& can_go_next()
> +    {
> +        return properties.can_go_next;
> +    }
> +
> +    core::Property<bool>& is_video_source()
> +    {
> +        return properties.is_video_source;
> +    }
> +
> +    core::Property<bool>& is_audio_source()
> +    {
> +        return properties.is_audio_source;
> +    }
> +
> +    core::Property<core::ubuntu::media::Track::MetaData>& meta_data_for_current_track()
> +    {
> +        return properties.meta_data_for_current_track;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::PlaybackRate>& minimum_playback_rate()
> +    {
> +        return properties.minimum_playback_rate;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::PlaybackRate>& maximum_playback_rate()
> +    {
> +        return properties.maximum_playback_rate;
> +    }
> +
> +    core::Property<int64_t>& position()
> +    {
> +        return properties.position;
> +    }
> +
> +    core::Property<int64_t>& duration()
> +    {
> +        return properties.duration;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::Orientation>& orientation()
> +    {
> +        return properties.orientation;
> +    }
> +
> +    core::Signal<int64_t>& seeked_to()
> +    {
> +        return sigs.seeked_to;
> +    }
> +
> +    core::Signal<void>& end_of_stream()
> +    {
> +        return sigs.end_of_stream;
> +    }
> +
> +    core::Signal<core::ubuntu::media::video::Dimensions>& video_dimension_changed()
> +    {
> +        return sigs.video_dimension_changed;
> +    }
> +
> +    const core::Signal<Error>& error() const
> +    {
> +        return sigs.error;
> +    }
> +
> +    core::Signal<Error>& error()
> +    {
> +        return sigs.error;
> +    }
> +
> +    core::Signal<void>& about_to_finish()
> +    {
> +        return sigs.about_to_finish;
> +    }
> +
> +    struct
> +    {
> +        core::Property<Lifetime> lifetime;
> +        core::Property<bool> can_play;
> +        core::Property<bool> can_pause;
> +        core::Property<bool> can_seek;
> +        core::Property<bool> can_go_previous;
> +        core::Property<bool> can_go_next;
> +        core::Property<bool> is_video_source;
> +        core::Property<bool> is_audio_source;
> +        core::Property<PlaybackStatus> playback_status;
> +        core::Property<LoopStatus> loop_status;
> +        core::Property<PlaybackRate> playback_rate;
> +        core::Property<bool> is_shuffle;
> +        core::Property<core::ubuntu::media::Track::MetaData> meta_data_for_current_track;
> +        core::Property<Volume> volume;
> +        core::Property<PlaybackRate> minimum_playback_rate;
> +        core::Property<PlaybackRate> maximum_playback_rate;
> +        core::Property<int64_t> position;
> +        core::Property<int64_t> duration;
> +        core::Property<AudioStreamRole> audio_stream_role;
> +        core::Property<Orientation> orientation;
> +    } properties;
> +
> +    struct
> +    {
> +        core::Signal<int64_t> seeked_to;
> +        core::Signal<void> end_of_stream;
> +        core::Signal<PlaybackStatus> playback_status_changed;
> +        core::Signal<core::ubuntu::media::video::Dimensions> video_dimension_changed;
> +        core::Signal<Error> error;
> +        core::Signal<void> about_to_finish;
> +    } sigs;
> +};
> +}
> +}
> +}
> +#endif // CORE_UBUNTU_MEDIA_PLAYER_BASE_H_
> 
> === modified file 'src/core/media/player_implementation.cpp'
> --- src/core/media/player_implementation.cpp	2015-04-17 14:35:22 +0000
> +++ src/core/media/player_implementation.cpp	2015-04-17 14:35:22 +0000
> @@ -36,8 +36,6 @@
>  namespace media = core::ubuntu::media;
>  namespace dbus = core::dbus;
>  
> -using namespace std;
> -
>  template<typename Parent>
>  struct media::PlayerImplementation<Parent>::Private :
>          public std::enable_shared_from_this<Private>
> @@ -204,7 +202,7 @@
>  
>      void clear_wakelock(const wakelock_clear_t &wakelock)
>      {
> -        cout << __PRETTY_FUNCTION__ << endl;
> +        std::cout << __PRETTY_FUNCTION__ << std::endl;
>          try
>          {
>              switch (wakelock)
> @@ -229,7 +227,7 @@
>                      break;
>                  case wakelock_clear_t::WAKELOCK_CLEAR_INVALID:
>                  default:
> -                    cerr << "Can't clear invalid wakelock type" << endl;
> +                    std::cerr << "Can't clear invalid wakelock type" << std::endl;
>              }
>          }
>          catch(const std::exception& e)
> @@ -274,11 +272,6 @@
>          };
>      }
>  
> -    void on_client_died()
> -    {
> -        config.engine->reset();
> -    }
> -
>      // Our link back to our parent.
>      media::PlayerImplementation<Parent>* parent;
>      // We just store the parameters passed on construction.
> @@ -420,11 +413,11 @@
>                  return;
>  
>              static const std::chrono::milliseconds timeout{1000};
> -            media::timeout(timeout.count(), true, [wp]()
> +
> +            media::timeout(timeout.count(), true, [](const std::shared_ptr<media::Engine>& engine)
>              {
> -                if (auto sp = wp.lock())
> -                    sp->on_client_died();
> -            });
> +                engine->reset();
> +            }, sp->config.engine);
>          }
>      });
>  }
> @@ -538,8 +531,3 @@
>  {
>      Parent::playback_status_changed()(status);
>  }
> -
> -#include <core/media/player_skeleton.h>
> -
> -// For linking purposes, we have to make sure that we have all symbols included within the dso.
> -template class media::PlayerImplementation<media::PlayerSkeleton>;
> 
> === modified file 'src/core/media/player_implementation.h'
> --- src/core/media/player_implementation.h	2015-04-17 14:35:22 +0000
> +++ src/core/media/player_implementation.h	2015-04-17 14:35:22 +0000
> @@ -84,5 +84,8 @@
>  }
>  }
>  }
> +
> +#include "player_implementation.cpp"
> +
>  #endif // CORE_UBUNTU_MEDIA_PLAYER_IMPLEMENTATION_H_
>  
> 
> === modified file 'src/core/media/player_skeleton.cpp'
> --- src/core/media/player_skeleton.cpp	2015-03-11 16:17:23 +0000
> +++ src/core/media/player_skeleton.cpp	2015-04-17 14:35:22 +0000
> @@ -23,7 +23,7 @@
>  #include "player_skeleton.h"
>  #include "player_traits.h"
>  #include "property_stub.h"
> -#include "the_session_bus.h"
> +
>  #include "xesam.h"
>  
>  #include "apparmor/ubuntu.h"
> @@ -54,7 +54,7 @@
>            object(session),
>            request_context_resolver{request_context_resolver},
>            request_authenticator{request_authenticator},
> -          skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}},
> +          skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Defaults{}}},
>            signals
>            {
>                skeleton.signals.seeked_to,
> @@ -179,10 +179,16 @@
>              Track::UriType uri;
>              in->reader() >> uri;
>  
> -            auto result = request_authenticator->authenticate_open_uri_request(context, uri);
> -
>              auto reply = dbus::Message::make_method_return(in);
> -            reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false);
> +
> +            try
> +            {
> +                auto result = request_authenticator->authenticate_open_uri_request(context, uri);
> +                reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false);
> +            } catch(...)
> +            {
> +                reply->writer() << false;
> +            }
>  
>              bus->send(reply);
>          });
> @@ -197,9 +203,16 @@
>  
>              in->reader() >> uri >> headers;
>  
> -            auto result = request_authenticator->authenticate_open_uri_request(context, uri);
>              auto reply = dbus::Message::make_method_return(in);
> -            reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false);
> +
> +            try
> +            {
> +                auto result = request_authenticator->authenticate_open_uri_request(context, uri);
> +                reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false);
> +            } catch(...)
> +            {
> +                reply->writer() << false;
> +            }
>  
>              bus->send(reply);
>          });
> 
> === modified file 'src/core/media/player_stub.cpp'
> --- src/core/media/player_stub.cpp	2015-03-16 14:54:47 +0000
> +++ src/core/media/player_stub.cpp	2015-04-17 14:35:22 +0000
> @@ -42,45 +42,41 @@
>  
>  struct media::PlayerStub::Private
>  {
> -    Private(const std::shared_ptr<Service>& parent,
> -            const std::shared_ptr<core::dbus::Object>& object
> -            ) : parent(parent),
> -                object(object),
> -                key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()),
> -                sink_factory(media::video::make_platform_default_sink_factory(key)),
> +    Private(const media::PlayerStub::Configuration& config)
> +              : configuration(config),
>                  properties
>                  {
>                      // Link the properties from the server side to the client side over the bus
> -                    object->get_property<mpris::Player::Properties::CanPlay>(),
> -                    object->get_property<mpris::Player::Properties::CanPause>(),
> -                    object->get_property<mpris::Player::Properties::CanSeek>(),
> -                    object->get_property<mpris::Player::Properties::CanControl>(),
> -                    object->get_property<mpris::Player::Properties::CanGoNext>(),
> -                    object->get_property<mpris::Player::Properties::CanGoPrevious>(),
> -                    object->get_property<mpris::Player::Properties::IsVideoSource>(),
> -                    object->get_property<mpris::Player::Properties::IsAudioSource>(),
> -                    object->get_property<mpris::Player::Properties::TypedPlaybackStatus>(),
> -                    object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
> -                    object->get_property<mpris::Player::Properties::PlaybackRate>(),
> -                    object->get_property<mpris::Player::Properties::Shuffle>(),
> -                    object->get_property<mpris::Player::Properties::TypedMetaData>(),
> -                    object->get_property<mpris::Player::Properties::Volume>(),
> -                    object->get_property<mpris::Player::Properties::Position>(),
> -                    object->get_property<mpris::Player::Properties::Duration>(),
> -                    object->get_property<mpris::Player::Properties::AudioStreamRole>(),
> -                    object->get_property<mpris::Player::Properties::Orientation>(),
> -                    object->get_property<mpris::Player::Properties::Lifetime>(),
> -                    object->get_property<mpris::Player::Properties::MinimumRate>(),
> -                    object->get_property<mpris::Player::Properties::MaximumRate>()
> +                    configuration.object->get_property<mpris::Player::Properties::CanPlay>(),
> +                    configuration.object->get_property<mpris::Player::Properties::CanPause>(),
> +                    configuration.object->get_property<mpris::Player::Properties::CanSeek>(),
> +                    configuration.object->get_property<mpris::Player::Properties::CanControl>(),
> +                    configuration.object->get_property<mpris::Player::Properties::CanGoNext>(),
> +                    configuration.object->get_property<mpris::Player::Properties::CanGoPrevious>(),
> +                    configuration.object->get_property<mpris::Player::Properties::IsVideoSource>(),
> +                    configuration.object->get_property<mpris::Player::Properties::IsAudioSource>(),
> +                    configuration.object->get_property<mpris::Player::Properties::TypedPlaybackStatus>(),
> +                    configuration.object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
> +                    configuration.object->get_property<mpris::Player::Properties::PlaybackRate>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Shuffle>(),
> +                    configuration.object->get_property<mpris::Player::Properties::TypedMetaData>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Volume>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Position>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Duration>(),
> +                    configuration.object->get_property<mpris::Player::Properties::AudioStreamRole>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Orientation>(),
> +                    configuration.object->get_property<mpris::Player::Properties::Lifetime>(),
> +                    configuration.object->get_property<mpris::Player::Properties::MinimumRate>(),
> +                    configuration.object->get_property<mpris::Player::Properties::MaximumRate>()
>                  },
>                  signals
>                  {
> -                    object->get_signal<mpris::Player::Signals::Seeked>(),
> -                    object->get_signal<mpris::Player::Signals::AboutToFinish>(),
> -                    object->get_signal<mpris::Player::Signals::EndOfStream>(),
> -                    object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(),
> -                    object->get_signal<mpris::Player::Signals::VideoDimensionChanged>(),
> -                    object->get_signal<mpris::Player::Signals::Error>()
> +                    configuration.object->get_signal<mpris::Player::Signals::Seeked>(),
> +                    configuration.object->get_signal<mpris::Player::Signals::AboutToFinish>(),
> +                    configuration.object->get_signal<mpris::Player::Signals::EndOfStream>(),
> +                    configuration.object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(),
> +                    configuration.object->get_signal<mpris::Player::Signals::VideoDimensionChanged>(),
> +                    configuration.object->get_signal<mpris::Player::Signals::Error>()
>                  }
>      {
>      }
> @@ -89,11 +85,9 @@
>      {
>      }
>  
> -    std::shared_ptr<Service> parent;
> +    media::PlayerStub::Configuration configuration;
>      std::shared_ptr<TrackList> track_list;
> -    dbus::Object::Ptr object;
> -    media::Player::PlayerKey key;
> -    media::video::SinkFactory sink_factory;
> +
>      struct
>      {
>          std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
> @@ -207,10 +201,7 @@
>      } signals;
>  };
>  
> -media::PlayerStub::PlayerStub(
> -    const std::shared_ptr<Service>& parent,
> -    const std::shared_ptr<core::dbus::Object>& object)
> -        : d(new Private{parent, object})
> +media::PlayerStub::PlayerStub(const media::PlayerStub::Configuration& config) : d(new Private{config})
>  {
>  }
>  
> @@ -224,19 +215,19 @@
>      {
>          d->track_list = std::make_shared<media::TrackListStub>(
>                      shared_from_this(),
> -                    dbus::types::ObjectPath(d->object->path().as_string() + "/TrackList"));
> +                    dbus::types::ObjectPath(d->configuration.object->path().as_string() + "/TrackList"));
>      }
>      return d->track_list;
>  }
>  
>  media::Player::PlayerKey media::PlayerStub::key() const
>  {
> -    return d->key;
> +    return d->configuration.key;
>  }
>  
>  bool media::PlayerStub::open_uri(const media::Track::UriType& uri)
>  {
> -    auto op = d->object->transact_method<mpris::Player::OpenUri, bool>(uri);
> +    auto op = d->configuration.object->transact_method<mpris::Player::OpenUri, bool>(uri);
>  
>      return op.value();
>  }
> @@ -244,14 +235,14 @@
>  
>  bool media::PlayerStub::open_uri(const Track::UriType& uri, const Player::HeadersType& headers)
>  {
> -    auto op = d->object->transact_method<mpris::Player::OpenUriExtended, bool>(uri, headers);
> +    auto op = d->configuration.object->transact_method<mpris::Player::OpenUriExtended, bool>(uri, headers);
>  
>      return op.value();
>  }
>  
>  media::video::Sink::Ptr media::PlayerStub::create_gl_texture_video_sink(std::uint32_t texture_id)
>  {
> -    auto op = d->object->transact_method<mpris::Player::CreateVideoSink, void>(texture_id);
> +    auto op = d->configuration.object->transact_method<mpris::Player::CreateVideoSink, void>(texture_id);
>  
>      if (op.is_error())
>      {
> @@ -261,12 +252,12 @@
>              throw std::runtime_error{op.error().print()};
>      }
>  
> -    return d->sink_factory(texture_id);
> +    return d->configuration.sink_factory(texture_id);
>  }
>  
>  void media::PlayerStub::next()
>  {
> -    auto op = d->object->transact_method<mpris::Player::Next, void>();
> +    auto op = d->configuration.object->transact_method<mpris::Player::Next, void>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem switching to next track on remote object");
> @@ -274,7 +265,7 @@
>  
>  void media::PlayerStub::previous()
>  {
> -    auto op = d->object->transact_method<mpris::Player::Previous, void>();
> +    auto op = d->configuration.object->transact_method<mpris::Player::Previous, void>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem switching to previous track on remote object");
> @@ -282,7 +273,7 @@
>  
>  void media::PlayerStub::play()
>  {
> -    auto op = d->object->transact_method<mpris::Player::Play, void>();
> +    auto op = d->configuration.object->transact_method<mpris::Player::Play, void>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem starting playback on remote object");
> @@ -290,7 +281,7 @@
>  
>  void media::PlayerStub::pause()
>  {
> -    auto op = d->object->transact_method<mpris::Player::Pause, void>();
> +    auto op = d->configuration.object->transact_method<mpris::Player::Pause, void>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem pausing playback on remote object");
> @@ -298,7 +289,7 @@
>  
>  void media::PlayerStub::seek_to(const std::chrono::microseconds& offset)
>  {
> -    auto op = d->object->transact_method<mpris::Player::Seek, void, uint64_t>(offset.count());
> +    auto op = d->configuration.object->transact_method<mpris::Player::Seek, void, uint64_t>(offset.count());
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem seeking on remote object");
> @@ -306,7 +297,7 @@
>  
>  void media::PlayerStub::stop()
>  {
> -    auto op = d->object->transact_method<mpris::Player::Stop, void>();
> +    auto op = d->configuration.object->transact_method<mpris::Player::Stop, void>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem stopping playback on remote object");
> 
> === modified file 'src/core/media/player_stub.h'
> --- src/core/media/player_stub.h	2015-03-11 16:17:23 +0000
> +++ src/core/media/player_stub.h	2015-04-17 14:35:22 +0000
> @@ -22,8 +22,11 @@
>  
>  #include <core/media/player.h>
>  
> +#include <core/media/video/platform_default_sink.h>
> +
>  #include <core/dbus/stub.h>
>  
> +#include <functional>
>  #include <memory>
>  
>  namespace core
> @@ -37,9 +40,18 @@
>  class PlayerStub : public Player
>  {
>    public:
> -    explicit PlayerStub(
> -        const std::shared_ptr<Service>& parent,
> -        const std::shared_ptr<core::dbus::Object>& object);
> +    // All creation time properties go here.
> +    struct Configuration
> +    {
> +        std::shared_ptr<core::dbus::Object> object;
> +
> +        // The key identifying this instance.
> +        media::Player::PlayerKey key;
> +        // sink_factory is a functor to create video sink instances.
> +        media::video::SinkFactory sink_factory;
> +    };
> +
> +    explicit PlayerStub(const Configuration& configuration);
>  
>      ~PlayerStub();
>  
> 
> === modified file 'src/core/media/server/server.cpp'
> --- src/core/media/server/server.cpp	2015-04-17 14:35:22 +0000
> +++ src/core/media/server/server.cpp	2015-04-17 14:35:22 +0000
> @@ -144,8 +144,10 @@
>          session,
>          service,
>          object,
> -        impl,
> -        player_store
> +        impl,                                                                 
> +        player_store,
> +        media::ServiceSkeleton::default_player_key_sampler(),
> +        media::ServiceSkeleton::default_player_path_sampler()
>      });
>  
>      std::thread service_worker
> 
> === modified file 'src/core/media/service.cpp'
> --- src/core/media/service.cpp	2014-04-09 14:05:55 +0000
> +++ src/core/media/service.cpp	2015-04-17 14:35:22 +0000
> @@ -19,12 +19,34 @@
>  #include <core/media/service.h>
>  
>  #include "service_stub.h"
> +#include "service_traits.h"
> +
> +#include <core/dbus/asio/executor.h>
>  
>  namespace media = core::ubuntu::media;
>  
> +namespace
> +{
> +core::dbus::Bus::Ptr make_session_bus_with_executor()
> +{
> +    core::dbus::Bus::Ptr bus{std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session)};
> +    bus->install_executor(core::dbus::asio::make_executor(bus));
> +
> +    return bus;
> +}
> +
> +core::dbus::types::ObjectPath default_object_path()
> +{
> +    return core::dbus::types::ObjectPath{core::dbus::traits::Service<core::ubuntu::media::Service>::object_path()};
> +}
> +}
> +
>  const std::shared_ptr<media::Service> media::Service::Client::instance()
>  {
>      std::cout << "Creating a new static Service instance" << std::endl;
> -    static std::shared_ptr<media::Service> instance{new media::ServiceStub()};
> -    return instance;
> +    auto session_bus = make_session_bus_with_executor();
> +    auto service = core::dbus::Service::use_service<core::ubuntu::media::Service>(session_bus);
> +    auto object = service->object_for_path(default_object_path());
> +
> +    return std::make_shared<media::ServiceStub>(media::ServiceStub::Configuration{session_bus, service, object, [](media::Player::PlayerKey key) { return media::video::make_platform_default_sink_factory(key); }});
>  }
> 
> === modified file 'src/core/media/service_implementation.cpp'
> --- src/core/media/service_implementation.cpp	2015-04-17 14:35:22 +0000
> +++ src/core/media/service_implementation.cpp	2015-04-17 14:35:22 +0000
> @@ -78,7 +78,7 @@
>  {
>      d->configuration.battery_observer->level().changed().connect([this](const media::power::Level& level)
>      {
> -        const bool resume_play_after_phonecall = false;
> +        const bool resume_play_after_notification = true;
>          // When the battery level hits 10% or 5%, pause all multimedia sessions.
>          // Playback will resume when the user clears the presented notification.
>          switch (level)
> @@ -87,7 +87,7 @@
>          case media::power::Level::very_low:
>              // Whatever player session is currently playing, make sure it is NOT resumed after
>              // a phonecall is hung up
> -            pause_all_multimedia_sessions(resume_play_after_phonecall);
> +            pause_all_multimedia_sessions(resume_play_after_notification);
>              break;
>          default:
>              break;
> @@ -99,7 +99,7 @@
>          // If the low battery level notification is no longer being displayed,
>          // resume what the user was previously playing
>          if (!active)
> -            resume_multimedia_session();
> +          resume_paused_multimedia_sessions(true);
>      });
>  
>      d->configuration.audio_output_observer->external_output_state().changed().connect([this](audio::OutputState state)
> @@ -120,20 +120,19 @@
>              std::cout << "AudioOutputObserver reports that output is now External." << std::endl;
>              break;
>          }
> -        d->audio_output_state = state;
>      });
>  
>      d->configuration.call_monitor->on_call_state_changed().connect([this](media::telephony::CallMonitor::State state)
>      {
>          const bool resume_play_after_phonecall = true;
>          switch (state) {
> -        case media::telephony::CallMonitor::State::OffHook:
> +        case media::telephony::CallMonitor::State::OnHook:
>              std::cout << "Got call started signal, pausing all multimedia sessions" << std::endl;
>              // Whatever player session is currently playing, make sure it gets resumed after
>              // a phonecall is hung up
>              pause_all_multimedia_sessions(resume_play_after_phonecall);
>              break;
> -        case media::telephony::CallMonitor::State::OnHook:
> +        case media::telephony::CallMonitor::State::OffHook:
>              std::cout << "Got call ended signal, resuming paused multimedia sessions" << std::endl;
>              resume_paused_multimedia_sessions(false);
>              break;
> 
> === modified file 'src/core/media/service_skeleton.cpp'
> --- src/core/media/service_skeleton.cpp	2015-04-17 14:35:22 +0000
> +++ src/core/media/service_skeleton.cpp	2015-04-17 14:35:22 +0000
> @@ -76,37 +76,23 @@
>                          std::placeholders::_1));
>      }
>  
> -    std::pair<std::string, media::Player::PlayerKey> create_session_info()
> -    {
> -        static unsigned int session_counter = 0;
> -
> -        unsigned int current_session = session_counter++;
> -
> -        std::stringstream ss;
> -        ss << "/core/ubuntu/media/Service/sessions/" << current_session;
> -
> -        return std::make_pair(ss.str(), media::Player::PlayerKey(current_session));
> -    }
> -
>      void handle_create_session(const core::dbus::Message::Ptr& msg)
>      {
> -        auto session_info = create_session_info();
> -
> -        dbus::types::ObjectPath op{session_info.first};
> -        media::Player::PlayerKey key{session_info.second};
> +        auto key = configuration.player_key_sampler();
> +        auto path = configuration.player_path_sampler(key);
>  
>          media::Player::Configuration config
>          {
>              key,
>              configuration.bus,
> -            configuration.service->add_object_for_path(op)
> +            configuration.service->add_object_for_path(path)
>          };
>  
>          try
>          {
>              configuration.player_store->add_player_for_key(key, impl->create_session(config));
>              auto reply = dbus::Message::make_method_return(msg);
> -            reply->writer() << op;
> +            reply->writer() << path;
>  
>              configuration.bus->send(reply);
>          } catch(const std::runtime_error& e)
> @@ -127,17 +113,14 @@
>              msg->reader() >> name;
>  
>              if (named_player_map.count(name) == 0) {
> -                // Create new session
> -                auto  session_info = create_session_info();
> -
> -                dbus::types::ObjectPath op{session_info.first};
> -                media::Player::PlayerKey key{session_info.second};
> +                auto key = configuration.player_key_sampler();
> +                auto path = configuration.player_path_sampler(key);
>  
>                  media::Player::Configuration config
>                  {
>                      key,
>                      configuration.bus,
> -                    configuration.service->add_object_for_path(op)
> +                    configuration.service->add_object_for_path(path)
>                  };
>  
>                  auto session = impl->create_session(config);
> @@ -145,11 +128,10 @@
>  
>                  configuration.player_store->add_player_for_key(key, session);
>  
> -
>                  named_player_map.insert(std::make_pair(name, key));
>  
>                  auto reply = dbus::Message::make_method_return(msg);
> -                reply->writer() << op;
> +                reply->writer() << path;
>  
>                  configuration.bus->send(reply);
>              }
> @@ -165,12 +147,8 @@
>                      return;
>                  }
>  
> -                std::stringstream ss;
> -                ss << "/core/ubuntu/media/Service/sessions/" << key;
> -                dbus::types::ObjectPath op{ss.str()};
> -
>                  auto reply = dbus::Message::make_method_return(msg);
> -                reply->writer() << op;
> +                reply->writer() << configuration.player_path_sampler(key);
>  
>                  configuration.bus->send(reply);
>              }
> @@ -200,12 +178,8 @@
>                  return;
>              }
>  
> -            std::stringstream ss;
> -            ss << "/core/ubuntu/media/Service/sessions/" << key;
> -            dbus::types::ObjectPath op{ss.str()};
> -
>              auto reply = dbus::Message::make_method_return(msg);
> -            reply->writer() << op;
> +            reply->writer() << configuration.player_path_sampler(key);
>  
>              configuration.bus->send(reply);
>          } catch(const std::runtime_error& e)
> @@ -250,9 +224,9 @@
>              return defaults;
>          }
>  
> -        static mpris::Player::Skeleton::Configuration::Defaults player_defaults()
> +        static mpris::Player::Defaults player_defaults()
>          {
> -            mpris::Player::Skeleton::Configuration::Defaults defaults;
> +            mpris::Player::Defaults defaults;
>  
>              // Disabled as track list is not fully implemented yet.
>              defaults.can_go_next = false;
> @@ -504,6 +478,26 @@
>      } exported;
>  };
>  
> +media::ServiceSkeleton::PlayerKeySampler media::ServiceSkeleton::default_player_key_sampler()
> +{
> +    return []()
> +    {
> +        static std::atomic<media::Player::PlayerKey> counter{0};
> +        return ++counter;
> +    };
> +}
> +
> +media::ServiceSkeleton::PlayerPathSampler media::ServiceSkeleton::default_player_path_sampler()
> +{
> +    return [](media::Player::PlayerKey key)
> +    {
> +        std::stringstream ss;
> +        ss << "/core/ubuntu/media/Service/sessions/" << key;
> +
> +        return core::dbus::types::ObjectPath{ss.str()};
> +    };
> +}
> +
>  media::ServiceSkeleton::ServiceSkeleton(const Configuration& configuration)
>      : d(new Private(this, configuration))
>  {
> 
> === modified file 'src/core/media/service_skeleton.h'
> --- src/core/media/service_skeleton.h	2015-04-17 14:35:22 +0000
> +++ src/core/media/service_skeleton.h	2015-04-17 14:35:22 +0000
> @@ -38,6 +38,19 @@
>  class ServiceSkeleton : public core::ubuntu::media::Service
>  {
>  public:
> +    // PlayerKeySampler creates a new key uniquely identifying a player for the lifetime
> +    // of a media-hub instance.
> +    typedef std::function<Player::PlayerKey()> PlayerKeySampler;
> +
> +    // PlayerPathSampler maps a given key to a DBus object path.
> +    typedef std::function<core::dbus::types::ObjectPath(Player::PlayerKey)> PlayerPathSampler;
> +
> +    // default_player_key_sampler() returns the default setup of a PlayerKeySampler.
> +    static PlayerKeySampler default_player_key_sampler();
> +
> +    // default_player_path_sampler() returns the default setup of a PlayerPathSampler.
> +    static PlayerPathSampler default_player_path_sampler();
> +
>      // Creation time arguments go here.
>      struct Configuration
>      {
> @@ -46,6 +59,8 @@
>          core::dbus::Object::Ptr object;
>          std::shared_ptr<Service> impl;
>          KeyedPlayerStore::Ptr player_store;
> +        PlayerKeySampler player_key_sampler;
> +        PlayerPathSampler player_path_sampler;
>          CoverArtResolver cover_art_resolver;
>      };
>  
> 
> === modified file 'src/core/media/service_stub.cpp'
> --- src/core/media/service_stub.cpp	2014-10-23 14:42:59 +0000
> +++ src/core/media/service_stub.cpp	2015-04-17 14:35:22 +0000
> @@ -20,91 +20,111 @@
>  #include "service_traits.h"
>  
>  #include "player_stub.h"
> -#include "the_session_bus.h"
>  
>  #include "mpris/service.h"
> +#include "mpris/player.h"
>  
>  namespace dbus = core::dbus;
>  namespace media = core::ubuntu::media;
>  
> -struct media::ServiceStub::Private
> -{
> -    dbus::Object::Ptr object;
> -};
> -
> -media::ServiceStub::ServiceStub()
> -    : core::dbus::Stub<media::Service>(the_session_bus()),
> -      d(new Private{
> -        access_service()->object_for_path(
> -            dbus::types::ObjectPath(
> -                dbus::traits::Service<media::Service>::object_path()))})
> -{
> -    auto bus = the_session_bus();
> -    worker = std::move(std::thread([bus]()
> +media::ServiceStub::ServiceStub(const ServiceStub::Configuration& configuration)
> +    : configuration(configuration), shutdown_requested(false)
> +{
> +    worker = std::move(std::thread([this]()
>      {
> -        bus->run();
> +        while (!this->shutdown_requested)
> +        {
> +            try
> +            {
> +                this->configuration.bus->run();
> +            }
> +            catch (const std::exception& e)
> +            {
> +                std::cerr << "Caught exception originating from the bus: " << e.what() << std::endl;
> +            }
> +            catch (...)
> +            {
> +                std::cerr << "Caught an unknown exception originating from the bus." << std::endl;
> +            }
> +        }
>      }));
>  }
>  
>  media::ServiceStub::~ServiceStub()
>  {
> -    auto bus = the_session_bus();
> -    bus->stop();
> -
> +    // We request the overall execution to stop.
> +    shutdown_requested = true;
> +    // Gracefully shutdown the bus connection.
> +    configuration.bus->stop();
> +    // And wait for all outstanding operations to complete.
>      if (worker.joinable())
>          worker.join();
>  }
>  
>  std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&)
>  {
> -    auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession,
> -         dbus::types::ObjectPath>();
> +    auto op = configuration.object->invoke_method_synchronously<mpris::Service::CreateSession, dbus::types::ObjectPath>();
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem creating session: " + op.error());
>  
> +    auto object = configuration.service->object_for_path(op.value());
> +    auto key = object->transact_method<mpris::Player::Key, std::uint32_t>();
> +
>      return std::shared_ptr<media::Player>(new media::PlayerStub
>      {
> -        shared_from_this(),
> -        access_service()->object_for_path(op.value())
> +        media::PlayerStub::Configuration
> +        {
> +            object,
> +            key.value(),
> +            configuration.sink_factory(key.value())
> +        }
>      });
>  }
>  
>  std::shared_ptr<media::Player> media::ServiceStub::create_fixed_session(const std::string& name, const media::Player::Configuration&)
>  {
> -    auto op = d->object->invoke_method_synchronously<mpris::Service::CreateFixedSession,
> -         dbus::types::ObjectPath>(name);
> +    auto op = configuration.object->invoke_method_synchronously<mpris::Service::CreateFixedSession, dbus::types::ObjectPath>(name);
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem creating session: " + op.error());
>  
> +    auto object = configuration.service->object_for_path(op.value());
> +    auto key = object->transact_method<mpris::Player::Key, std::uint32_t>().value();
> +
>      return std::shared_ptr<media::Player>(new media::PlayerStub
>      {
> -        shared_from_this(),
> -        access_service()->object_for_path(op.value())
> +        media::PlayerStub::Configuration
> +        {
> +            object,
> +            key,
> +            configuration.sink_factory(key)
> +        }
>      });
>  }
>  
>  std::shared_ptr<media::Player> media::ServiceStub::resume_session(media::Player::PlayerKey key)
>  {
> -    auto op = d->object->invoke_method_synchronously<mpris::Service::ResumeSession,
> -         dbus::types::ObjectPath>(key);
> +    auto op = configuration.object->invoke_method_synchronously<mpris::Service::ResumeSession, dbus::types::ObjectPath>(key);
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem resuming session: " + op.error());
>  
>      return std::shared_ptr<media::Player>(new media::PlayerStub
>      {
> -        shared_from_this(),
> -        access_service()->object_for_path(op.value())
> +        media::PlayerStub::Configuration
> +        {
> +            configuration.service->object_for_path(op.value()),
> +            key,
> +            configuration.sink_factory(key)
> +        }
>      });
>  }
>  
>  void media::ServiceStub::pause_other_sessions(media::Player::PlayerKey key)
>  {
>      std::cout << __PRETTY_FUNCTION__ << std::endl;
> -    auto op = d->object->invoke_method_synchronously<mpris::Service::PauseOtherSessions,
> -         void>(key);
> +    auto op = configuration.object->invoke_method_synchronously<mpris::Service::PauseOtherSessions, void>(key);
>  
>      if (op.is_error())
>          throw std::runtime_error("Problem pausing other sessions: " + op.error());
> 
> === modified file 'src/core/media/service_stub.h'
> --- src/core/media/service_stub.h	2014-10-23 14:42:59 +0000
> +++ src/core/media/service_stub.h	2015-04-17 14:35:22 +0000
> @@ -20,6 +20,7 @@
>  #define CORE_UBUNTU_MEDIA_SERVICE_STUB_H_
>  
>  #include <core/media/service.h>
> +#include <core/media/video/platform_default_sink.h>
>  
>  #include "service_traits.h"
>  
> @@ -33,10 +34,20 @@
>  {
>  namespace media
>  {
> -class ServiceStub : public core::dbus::Stub<core::ubuntu::media::Service>
> +class ServiceStub : public core::ubuntu::media::Service
>  {
>    public:
> -    ServiceStub();
> +    // Creation time arguments go here
> +    struct Configuration
> +    {
> +        core::dbus::Bus::Ptr bus;
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +        // sink_factory is a functor to create video sink instances.
> +        std::function<media::video::SinkFactory(media::Player::PlayerKey)> sink_factory;
> +    };
> +
> +    ServiceStub(const Configuration& configuration);
>      ~ServiceStub();
>  
>      std::shared_ptr<Player> create_session(const Player::Configuration&);
> @@ -45,9 +56,12 @@
>      void pause_other_sessions(Player::PlayerKey key);
>  
>    private:
> -    struct Private;
> -    std::unique_ptr<Private> d;
> +    // We just store creation time arguments here.
> +    Configuration configuration;
> +    // Our separate thread for the bus connection.
>      std::thread worker;
> +    // Indicates whether a shutdown was requested.
> +    bool shutdown_requested;
>  };
>  }
>  }
> 
> === modified file 'tests/CMakeLists.txt'
> --- tests/CMakeLists.txt	2014-11-26 11:04:57 +0000
> +++ tests/CMakeLists.txt	2015-04-17 14:35:22 +0000
> @@ -1,14 +1,8 @@
>  find_package(Threads)
>  
> -add_definitions(-DBOOST_NO_CXX11_SCOPED_ENUMS)
> -
> -include_directories(${CMAKE_SOURCE_DIR}/include)
> -
> -option(
> -    MEDIA_HUB_ENABLE_DBUS_TEST_RUNNER 
> -    "Rely on dbus test runner to start a private session for testing purposes" 
> -    ON
> -)
> +file(GLOB_RECURSE MEDIA_HUB_TESTING_HEADERS ${CMAKE_SOURCE_DIR}/tests/*.h)
> +
> +add_definitions(-DBOOST_NO_CXX11_SCOPED_ENUMS -DCORE_DBUS_ENABLE_GOOGLE_TEST_FIXTURE)
>  
>  if (MEDIA_HUB_ENABLE_DBUS_TEST_RUNNER)
>      find_program(DBUS_TEST_RUNNER_EXECUTABLE dbus-test-runner)
> @@ -23,8 +17,8 @@
>  add_subdirectory(${GMOCK_SOURCE_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gmock")
>  
>  include_directories (
> -  .
> -  
> +  ${CMAKE_CURRENT_SOURCE_DIR}
> +  ${CMAKE_SOURCE_DIR}/src
>    ${GMOCK_INCLUDE_DIR}
>    ${GTEST_INCLUDE_DIR}
>  )
> @@ -37,7 +31,9 @@
>  add_library(
>      media-hub-test-framework
>  
> -    ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp
> +    unit-tests/mongoose.c
> +
> +    ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp    
>  )
>  
>  target_link_libraries(
> @@ -50,5 +46,32 @@
>      "COM_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME=fakesink"
>  )
>  
> -# add_subdirectory(acceptance-tests)
> +macro(MEDIA_HUB_ADD_TEST test_name src)
> +  add_executable(
> +    ${test_name}
> +    ${src} ${MEDIA_HUB_TESTING_HEADERS})
> +
> +  target_link_libraries(
> +    ${test_name}
> +
> +    media-hub-client
> +    media-hub-common
> +    media-hub-service
> +    media-hub-test-framework
> +
> +    ${GLESv2_LDFLAGS}
> +    ${EGL_LDFLAGS}
> +    ${UBUNTU_PLATFORM_API_LDFLAGS}
> +
> +    gmock
> +    gmock_main
> +    gtest
> +  )
> +
> +  add_test(${test_name} ${CMAKE_CURRENT_BINARY_DIR}/${test_name} --gtest_filter=*-*requires*)
> +endmacro(MEDIA_HUB_ADD_TEST)
> +
> +
> +#add_subdirectory(acceptance-tests)
> +add_subdirectory(integration-tests)
>  add_subdirectory(unit-tests)
> 
> === modified file 'tests/acceptance-tests/service.cpp'
> --- tests/acceptance-tests/service.cpp	2015-03-03 22:41:22 +0000
> +++ tests/acceptance-tests/service.cpp	2015-04-17 14:35:22 +0000
> @@ -21,6 +21,8 @@
>  #include <core/media/track_list.h>
>  
>  #include "core/media/service_implementation.h"
> +#include "core/media/gstreamer/engine_factory.h"
> +#include "core/media/audio/pulse_audio_output_observer.h"
>  
>  #include "../waitable_state_transition.h"
>  
> @@ -68,6 +70,49 @@
>      timespec ts{ 0, static_cast<long int>(ms.count()) * 1000 * 1000};
>      ::nanosleep(&ts, nullptr);
>  }
> +
> +std::thread make_external_services_worker(bool shutdown_requested, media::helper::ExternalServices& es)
> +{
> +    return std::thread
> +    {
> +        [&shutdown_requested, &es]()
> +        {
> +            while (not shutdown_requested)
> +            {
> +                try
> +                {
> +                    es.io_service.run();
> +                }
> +                catch (const std::exception& e)
> +                {
> +                    std::cerr << "Error while executing the underlying io_service: " << e.what() << std::endl;
> +                }
> +                catch (...)
> +                {
> +                    std::cerr << "Error while executing the underlying io_service." << std::endl;
> +                }
> +            }
> +        }
> +    };
> +}
> +
> +media::ServiceImplementation::Configuration make_default_service_configuration(media::helper::ExternalServices& es)
> +{
> +    return media::ServiceImplementation::Configuration
> +    {
> +        [&es](media::Task task)
> +        {
> +            es.io_service.post(task);
> +        },
> +        media::platform_default_client_death_observer(),
> +        media::gstreamer::engine_factory(),
> +        media::make_platform_default_recorder_observer(),
> +        media::audio::make_platform_default_output_observer(),
> +        media::power::make_platform_default_state_controller(es),
> +        media::power::make_platform_default_battery_observer(es),
> +        media::telephony::make_platform_default_call_monitor()
> +    };
> +}
>  }
>  
>  TEST(MusicService, DISABLED_accessing_and_creating_a_session_works)
> @@ -78,105 +123,37 @@
>      {
>          SigTermCatcher sc;
>  
> -        auto service = std::make_shared<media::ServiceImplementation>();
> -        std::thread t([&service](){service->run();});
> -
> -        sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        sc.wait_for_signal(); service->stop();
> -
> -        if (t.joinable())
> -            t.join();
> -
> -        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> -    };
> -
> -    auto client = [this, &sync_service_start]()
> -    {
> -        sync_service_start.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        auto service = media::Service::Client::instance();
> -        auto session = service->create_session(media::Player::Client::default_configuration());
> -
> -        EXPECT_TRUE(session != nullptr);
> -
> -        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> -    };
> -
> -    EXPECT_EQ(core::testing::ForkAndRunResult::empty,
> -              core::testing::fork_and_run(service, client));
> -}
> -
> -TEST(MusicService, DISABLED_accessing_and_creating_a_fixed_session_works)
> -{
> -    core::testing::CrossProcessSync sync_service_start;
> -
> -    auto service = [this, &sync_service_start]()
> -    {
> -        SigTermCatcher sc;
> -
> -        auto service = std::make_shared<media::ServiceImplementation>();
> -        std::thread t([&service](){service->run();});
> -
> -        sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        sc.wait_for_signal(); service->stop();
> -
> -        if (t.joinable())
> -            t.join();
> -
> -        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> -    };
> -
> -    auto client = [this, &sync_service_start]()
> -    {
> -        sync_service_start.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        auto service = media::Service::Client::instance();
> -        auto session = service->create_fixed_session("com.ubuntu.test-session", media::Player::Client::default_configuration());
> -
> -        EXPECT_TRUE(session != nullptr);
> -
> -        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> -    };
> -
> -    EXPECT_EQ(core::testing::ForkAndRunResult::empty,
> -              core::testing::fork_and_run(service, client));
> -}
> -
> -TEST(MusicService, DISABLED_resuming_a_session_works)
> -{
> -    core::testing::CrossProcessSync sync_service_start;
> -
> -    auto service = [this, &sync_service_start]()
> -    {
> -        SigTermCatcher sc;
> -
> -        auto service = std::make_shared<media::ServiceImplementation>();
> -        std::thread t([&service](){service->run();});
> -
> -        sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        sc.wait_for_signal(); service->stop();
> -
> -        if (t.joinable())
> -            t.join();
> -
> -        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> -    };
> -
> -    auto client = [this, &sync_service_start]()
> -    {
> -        sync_service_start.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> -
> -        auto service = media::Service::Client::instance();
> -        auto session = service->create_session(media::Player::Client::default_configuration());
> -
> -        EXPECT_TRUE(session != nullptr);
> -
> -        auto resumed_session = service->resume_session(session->key());
> -
> -        EXPECT_TRUE(resumed_session != nullptr);
> +        // We keep track of our state.
> +        bool shutdown_requested{false};
> +
> +        // Our helper for connecting to external services.
> +        media::helper::ExternalServices external_services;
> +        std::thread external_services_worker
> +        {
> +            make_external_services_worker(shutdown_requested, external_services)
> +        };
> +
> +        auto service = std::make_shared<media::ServiceImplementation>(make_default_service_configuration(external_services));
> +        std::thread t([&service](){service->run();});
> +
> +        sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        sc.wait_for_signal(); service->stop();
> +
> +        if (t.joinable())
> +            t.join();
> +
> +        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
> +    };
> +
> +    auto client = [this, &sync_service_start]()
> +    {
> +        sync_service_start.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        auto service = media::Service::Client::instance();
> +        auto session = service->create_session(media::Player::Client::default_configuration());
> +
> +        EXPECT_TRUE(session != nullptr);
>  
>          return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure : core::posix::exit::Status::success;
>      };
> @@ -198,7 +175,16 @@
>      {
>          SigTermCatcher sc;
>  
> -        auto service = std::make_shared<media::ServiceImplementation>();
> +        // We keep track of our state.
> +        bool shutdown_requested{false};
> +
> +        media::helper::ExternalServices external_services;
> +        std::thread external_services_worker
> +        {
> +            make_external_services_worker(shutdown_requested, external_services)
> +        };
> +
> +        auto service = std::make_shared<media::ServiceImplementation>(make_default_service_configuration(external_services));
>          std::thread t([&service](){service->run();});
>  
>          sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> @@ -251,7 +237,16 @@
>      {
>          SigTermCatcher sc;
>  
> -        auto service = std::make_shared<media::ServiceImplementation>();
> +        // We keep track of our state.
> +        bool shutdown_requested{false};
> +
> +        media::helper::ExternalServices external_services;
> +        std::thread external_services_worker
> +        {
> +            make_external_services_worker(shutdown_requested, external_services)
> +        };
> +
> +        auto service = std::make_shared<media::ServiceImplementation>(make_default_service_configuration(external_services));
>          std::thread t([&service](){service->run();});
>  
>          sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> @@ -330,7 +325,16 @@
>      {
>          SigTermCatcher sc;
>  
> -        auto service = std::make_shared<media::ServiceImplementation>();
> +        // We keep track of our state.
> +        bool shutdown_requested{false};
> +
> +        media::helper::ExternalServices external_services;
> +        std::thread external_services_worker
> +        {
> +            make_external_services_worker(shutdown_requested, external_services)
> +        };
> +
> +        auto service = std::make_shared<media::ServiceImplementation>(make_default_service_configuration(external_services));
>          std::thread t([&service](){service->run();});
>  
>          sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> @@ -389,7 +393,16 @@
>      {
>          SigTermCatcher sc;
>  
> -        auto service = std::make_shared<media::ServiceImplementation>();
> +        // We keep track of our state.
> +        bool shutdown_requested{false};
> +
> +        media::helper::ExternalServices external_services;
> +        std::thread external_services_worker
> +        {
> +            make_external_services_worker(shutdown_requested, external_services)
> +        };
> +
> +        auto service = std::make_shared<media::ServiceImplementation>(make_default_service_configuration(external_services));
>          std::thread t([&service](){service->run();});
>  
>          sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
> 
> === added directory 'tests/integration-tests'
> === added file 'tests/integration-tests/CMakeLists.txt'
> --- tests/integration-tests/CMakeLists.txt	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/CMakeLists.txt	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,6 @@
> +# MEDIA_HUB_ADD_TEST(hybris_gl_sink_test hybris_gl_sink_test.cpp)
> +MEDIA_HUB_ADD_TEST(player_implementation_test player_implementation_test.cpp)
> +MEDIA_HUB_ADD_TEST(player_skeleton_test player_skeleton_test.cpp)
> +MEDIA_HUB_ADD_TEST(service_implementation_test service_implementation_test.cpp)
> +MEDIA_HUB_ADD_TEST(service_skeleton_test service_skeleton_test.cpp)
> +
> 
> === added directory 'tests/integration-tests/fixtures'
> === added file 'tests/integration-tests/fixtures/player_skeleton.h'
> --- tests/integration-tests/fixtures/player_skeleton.h	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/fixtures/player_skeleton.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,139 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef FIXTURES_PLAYER_SKELETON_H_
> +#define FIXTURES_PLAYER_SKELETON_H_
> +
> +#include "tools/a_trap_stopping_itself.h"
> +#include "tools/gdb_barrier.h"
> +
> +#include <core/dbus/fixture.h>
> +#include <core/dbus/object.h>
> +#include <core/dbus/service.h>
> +#include <core/dbus/asio/executor.h>
> +
> +#include <core/posix/exit.h>
> +#include <core/posix/process.h>
> +#include <core/posix/this_process.h>
> +
> +#include <thread>
> +
> +namespace fixtures
> +{
> +// Our custom fixture that provides us with private session and system
> +// bus instances. In addition, we define a custom service name and object
> +// path to enable maximum test isolation.
> +struct PlayerSkeleton : public core::dbus::testing::Fixture
> +{
> +    static constexpr const char* service_name_for_testing
> +    {
> +        "this.is.the.media.service.for.testing"
> +    };
> +
> +    static constexpr const char* object_path_for_testing
> +    {
> +        "/this/is/the/media/player/skeleton/for/testing"
> +    };
> +
> +    // A simple fixture that can be used by service processes
> +    // to expose an mpris::Player instance to the bus, or, in general
> +    // interact with dbus. It is not recommended to instantiate instances
> +    // of this class in the testing process.
> +    struct ServiceFixture
> +    {
> +        ServiceFixture(PlayerSkeleton* skeleton)
> +            : parent{skeleton},
> +              signal_trap{tools::a_trap_stopping_itself()},
> +              session_bus{skeleton->session_bus()},
> +              service{core::dbus::Service::add_service(session_bus, service_name_for_testing)},
> +              object{service->add_object_for_path(core::dbus::types::ObjectPath{object_path_for_testing})}
> +        {
> +            session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
> +            worker = std::move(std::thread{[this]() { session_bus->run();}});
> +
> +            tools::wait_for_user_to_attach_with_gdb_if_enabled("Service");
> +        }
> +
> +        ~ServiceFixture()
> +        {
> +            session_bus->stop();
> +            if (worker.joinable())
> +                worker.join();
> +        }
> +
> +        core::posix::exit::Status run()
> +        {
> +            signal_trap->run();
> +            return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                                 : core::posix::exit::Status::success;
> +        }
> +
> +        PlayerSkeleton* parent;
> +        std::shared_ptr<core::posix::SignalTrap> signal_trap;
> +        core::dbus::Bus::Ptr session_bus;
> +        std::thread worker;
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +    };
> +
> +    // A simple fixture that can be used by client processes
> +    // to connect to an mpris::Player instance on the bus, or, in general
> +    // interact with dbus. It is not recommended to instantiate instances
> +    // of this class in the testing process.
> +    struct ClientFixture
> +    {
> +        ClientFixture(PlayerSkeleton* skeleton)
> +            : parent{skeleton},
> +              session_bus{skeleton->session_bus()},
> +              service{core::dbus::Service::use_service(session_bus, service_name_for_testing)},
> +              object{service->object_for_path(core::dbus::types::ObjectPath{object_path_for_testing})}
> +        {
> +            session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
> +            worker = std::move(std::thread{[this]() { session_bus->run();}});
> +
> +            tools::wait_for_user_to_attach_with_gdb_if_enabled("Client");
> +        }
> +
> +        ~ClientFixture()
> +        {
> +            session_bus->stop();
> +            if (worker.joinable())
> +                worker.join();
> +        }
> +
> +        core::posix::exit::Status run()
> +        {
> +            return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                                 : core::posix::exit::Status::success;
> +        }
> +
> +        PlayerSkeleton* parent;
> +        core::dbus::Bus::Ptr session_bus;
> +        std::thread worker;
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +    };
> +
> +    PlayerSkeleton() : pid{core::posix::this_process::instance().pid()}
> +    {
> +    }
> +
> +    pid_t pid;
> +};
> +}
> +
> +#endif // FIXTURES_PLAYER_SKELETON_H_
> 
> === added file 'tests/integration-tests/hybris_gl_sink.cpp'
> === added file 'tests/integration-tests/hybris_gl_sink_test.cpp'
> --- tests/integration-tests/hybris_gl_sink_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/hybris_gl_sink_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/player_configuration.h>
> +#include <core/media/player_implementation.h>
> +#include <core/media/player_skeleton.h>
> +#include <core/media/player_stub.h>
> +#include <core/media/gstreamer/engine.h>
> +#include <core/media/video/hybris_gl_sink.h>
> +
> +#include "test_data.h"
> +
> +#include "fixtures/player_skeleton.h"
> +
> +#include "mock/client_death_observer.h"
> +#include "mock/media_service.h"
> +#include "mock/power_state_controller.h"
> +#include "mock/request_context_resolver.h"
> +#include "mock/request_authenticator.h"
> +
> +#include "tools/did_finish_successfully.h"
> +#include "tools/event_sink.h"
> +
> +#include <core/dbus/fixture.h>
> +
> +#include <core/posix/exit.h>
> +#include <core/posix/fork.h>
> +#include <core/testing/cross_process_sync.h>
> +
> +#include <ubuntu/application/ui/window.h>
> +#include <ubuntu/application/ui/options.h>
> +#include <ubuntu/application/ui/display.h>
> +#include <ubuntu/application/ui/session.h>
> +
> +#include <cstdio>
> +#include <cstdlib>
> +
> +// This has to be the last include.
> +// Apparently, <EGL/egl.h> pollutes the global
> +// namespace and causes issues with <functional>.
> +#include "tools/gles_egl_helper.h"
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +// Relies on Ubuntu's platform api to acquire a native window,
> +// and translating it to an EGLNativeWindowType that is subsequently
> +// used to bootstrap an EGL context.
> +EGLNativeWindowType acquire_native_window()
> +{
> +    auto options = u_application_options_new_from_cmd_line(0, nullptr);
> +    auto desc = u_application_description_new();
> +    auto id = u_application_id_new_from_stringn("UbuntuApplicationCAPI", 21);
> +    u_application_description_set_application_id(desc, id);
> +    auto instance = u_application_instance_new_from_description_with_options(desc, options);
> +    auto props = ua_ui_session_properties_new();
> +    ua_ui_session_properties_set_type(props, U_USER_SESSION);
> +
> +    auto wprops = ua_ui_window_properties_new_for_normal_window();
> +    ua_ui_window_properties_set_titlen(wprops, "Window 1", 8);
> +    ua_ui_window_properties_set_role(wprops, U_MAIN_ROLE);
> +    ua_ui_window_properties_set_event_cb_and_ctx(wprops, nullptr, nullptr);
> +
> +    return ua_ui_window_get_native_type(ua_ui_window_new_for_application_with_properties(instance, wprops));
> +}
> +
> +// We have to shutdown the actual media hub instance
> +// running on target systems to make sure that access
> +// to the decoding subsystems pulled over from the android
> +// world via hybris are available to the test case.
> +void ensure_that_media_hub_is_not_running()
> +{
> +    std::system("stop media-hub");
> +}
> +
> +// Our fixture for the actual test case.
> +struct HybrisGlSinkTest : public fixtures::PlayerSkeleton
> +{
> +    static bool timeouts_are_async()
> +    {
> +        return true;
> +    }
> +
> +    static std::chrono::milliseconds timeout()
> +    {
> +        return std::chrono::milliseconds{1000};
> +    }
> +
> +    HybrisGlSinkTest()
> +    {
> +        ensure_that_media_hub_is_not_running();
> +    }
> +};
> +
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +}
> +
> +// An integration test that exercises the out-of-process buffer streaming
> +// functionality available via media::video::HybrisGlSink.
> +TEST_F(HybrisGlSinkTest, creation_of_hybris_gl_sink_succeeds_for_video_source_requires_device)
> +{
> +    struct Sync
> +    {
> +        core::testing::CrossProcessSync service_is_ready;
> +    } sync;
> +
> +    auto service = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        HybrisGlSinkTest::ServiceFixture sf{this};
> +
> +        auto request_context_resolver = std::make_shared<NiceMock<MockRequestContextResolver>>();
> +        auto request_authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +        ON_CALL(*request_authenticator, authenticate_open_uri_request(_, _))
> +                .WillByDefault(
> +                    Return(media::apparmor::ubuntu::RequestAuthenticator::Result{true, ""}));
> +
> +        typedef media::PlayerImplementation<media::PlayerSkeleton> Player;
> +
> +        auto impl = std::make_shared<Player>(Player::Configuration
> +        {
> +            media::PlayerSkeleton::Configuration
> +            {
> +                sf.session_bus,
> +                sf.object,
> +                request_context_resolver,
> +                request_authenticator
> +            },
> +            the_player_key,
> +            std::make_shared<gstreamer::Engine>(),
> +            request_context_resolver,
> +            request_authenticator,
> +            std::make_shared<NiceMock<MockClientDeathObserver>>(),
> +            std::make_shared<NiceMock<MockPowerStateController>>()
> +        });
> +
> +        // Announce that we are good to go.
> +        sync.service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +        // Run until sigterm or sigint.
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        const std::string test_file{"/tmp/h264.avi"};
> +        const std::string test_file_uri{"file:///tmp/h264.avi"};
> +        std::remove(test_file.c_str());
> +        EXPECT_TRUE(test::copy_test_avi_file_to(test_file));
> +
> +        sync.service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        HybrisGlSinkTest::ClientFixture cf{this};
> +        media::PlayerStub stub{std::make_shared<NiceMock<MockMediaService>>(), cf.object};
> +
> +        tools::glesv2::Helper helper{acquire_native_window()};
> +        auto texture = helper.gen_texture();
> +        auto gl_texture_sink = stub.create_gl_texture_video_sink(texture);
> +
> +        tools::EventSink<void> es_frame_available{gl_texture_sink->frame_available()};
> +        EXPECT_CALL(es_frame_available, on_new_event()).Times(AtLeast(2));
> +
> +        gl_texture_sink->frame_available().connect([&helper, gl_texture_sink]()
> +        {
> +            helper.egl.make_current(); gl_texture_sink->swap_buffers();
> +        });
> +
> +        EXPECT_TRUE(stub.open_uri(test_file_uri));
> +        stub.play();
> +        EXPECT_TRUE(es_frame_available.wait_for_event_for(std::chrono::seconds{5}));
> +        stub.stop();
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> 
> === added file 'tests/integration-tests/player_implementation_test.cpp'
> --- tests/integration-tests/player_implementation_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/player_implementation_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,296 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/player_implementation.h>
> +
> +#include "mock/client_death_observer.h"
> +#include "mock/engine.h"
> +#include "mock/player.h"
> +#include "mock/power_state_controller.h"
> +#include "mock/request_authenticator.h"
> +#include "mock/request_context_resolver.h"
> +
> +#include <gmock/gmock.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +// Our default texture handle we use in testing.
> +constexpr const std::uint32_t the_texture_id{13};
> +// Constructs a PlayerImplementation::Configuration instance containing mocked
> +// instances for the functional dependencies.
> +media::PlayerImplementation<media::PlayerBase>::Configuration make_player_configuration_for_testing()
> +{
> +    using namespace ::testing;
> +
> +    return media::PlayerImplementation<media::PlayerBase>::Configuration
> +    {
> +        media::PlayerBase::Configuration{},
> +        the_player_key,
> +        std::make_shared<NiceMock<MockEngine>>(),
> +        std::make_shared<NiceMock<MockRequestContextResolver>>(),
> +        std::make_shared<NiceMock<MockRequestAuthenticator>>(),
> +        std::make_shared<NiceMock<MockClientDeathObserver>>(),
> +        std::make_shared<NiceMock<MockPowerStateController>>()
> +    };
> +}
> +}
> +
> +TEST(PlayerImplementation, forwards_calls_to_engine_instance)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    const media::Track::UriType the_uri{"file:///does/not/exist"};
> +    const std::chrono::microseconds the_timestamp{42};
> +
> +    auto config = make_player_configuration_for_testing();
> +    auto engine = std::make_shared<NiceMock<MockEngine>>();
> +    config.engine = engine;
> +
> +    EXPECT_CALL(*engine, read_duration()).Times(1);
> +    EXPECT_CALL(*engine, read_is_audio()).Times(1);
> +    EXPECT_CALL(*engine, read_is_video()).Times(1);
> +
> +    EXPECT_CALL(*engine, open_resource_for_uri(the_uri)).Times(1);
> +    EXPECT_CALL(*engine, create_video_sink(the_texture_id)).Times(1);
> +    EXPECT_CALL(*engine, play()).Times(1);
> +    EXPECT_CALL(*engine, stop()).Times(1);
> +    EXPECT_CALL(*engine, pause()).Times(1);
> +    EXPECT_CALL(*engine, seek_to(the_timestamp)).Times(1);
> +
> +    Player impl{config};
> +
> +    static_cast<const Player&>(impl).is_audio_source().get();
> +    static_cast<const Player&>(impl).is_video_source().get();
> +    static_cast<const Player&>(impl).duration().get();
> +
> +    impl.open_uri(the_uri);
> +    impl.create_gl_texture_video_sink(the_texture_id);
> +    impl.play();
> +    impl.stop();
> +    impl.pause();
> +    impl.seek_to(the_timestamp);
> +}
> +
> +TEST(PlayerImplementation, subscribes_to_client_death_notifications_on_construction)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +    auto client_death_observer = std::make_shared<NiceMock<MockClientDeathObserver>>();
> +    EXPECT_CALL(*client_death_observer, register_for_death_notifications_with_key(the_player_key))
> +            .Times(1);
> +    config.client_death_observer = client_death_observer;
> +
> +    Player impl{config};
> +}
> +
> +TEST(PlayerImplementation, unsubscribes_from_client_death_notifications_on_destruction)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +    auto client_death_observer = std::make_shared<NiceMock<MockClientDeathObserver>>();
> +    EXPECT_CALL(*client_death_observer, register_for_death_notifications_with_key(the_player_key))
> +            .Times(1);
> +    config.client_death_observer = client_death_observer;
> +
> +    // We scope the instance to force destruction.
> +    {
> +        Player impl{config};
> +    }
> +
> +    // We assume that the implementation correctly unsubscribed
> +    // and that we are free to report death here.
> +    client_death_observer->signals.on_client_with_key_died(the_player_key);
> +}
> +
> +TEST(PlayerImplementation, resets_engine_when_client_with_correct_key_dies)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +    auto engine = std::make_shared<NiceMock<MockEngine>>(); 
> +    // Allowing the engine to leak as it is reset asynchronously and handed down
> +    // to the timeout as a shared_ptr. The timeout happens on a detached thread, and
> +    // happens post Google Mock verifying the state of mock objects.
> +    ::testing::Mock::AllowLeak(engine.get());
> +    auto client_death_observer = std::make_shared<NiceMock<MockClientDeathObserver>>();
> +
> +    EXPECT_CALL(*engine, reset())
> +            .Times(1);
> +    EXPECT_CALL(*client_death_observer, register_for_death_notifications_with_key(the_player_key))
> +            .Times(1);
> +
> +    config.engine = engine;
> +    config.client_death_observer = client_death_observer;
> +
> +    Player impl{config};
> +
> +    // Signal death of known client.
> +    client_death_observer->signals.on_client_with_key_died(the_player_key);
> +    // Signal death of unknown client.
> +    client_death_observer->signals.on_client_with_key_died(2*the_player_key);
> +}
> +
> +TEST(PlayerImplementation, acquires_display_and_system_power_state_locks_on_construction)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +    auto power_state_controller = std::make_shared<NiceMock<MockPowerStateController>>();
> +    EXPECT_CALL(*power_state_controller, display_state_lock())
> +            .Times(1);
> +    EXPECT_CALL(*power_state_controller, system_state_lock())
> +            .Times(1);
> +    config.power_state_controller = power_state_controller;
> +
> +    Player impl{config};
> +}
> +
> +namespace
> +{
> +// A fixture that helps in testing for multiple different engine states.
> +struct PlayerImplementationEngineState : public ::testing::TestWithParam<media::Engine::State>
> +{
> +};
> +}
> +
> +TEST(PlayerImplementation, acquires_display_power_state_on_when_video_playback_starts)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +
> +    auto engine = std::make_shared<NiceMock<MockEngine>>();
> +    ON_CALL(*engine, read_is_video()).WillByDefault(Return(true));
> +    auto power_state_controller = std::make_shared<NiceMock<MockPowerStateController>>();
> +
> +    EXPECT_CALL(*power_state_controller->system_lock, request_acquire(media::power::SystemState::active))
> +            .Times(0);
> +    EXPECT_CALL(*power_state_controller->display_lock, request_acquire(media::power::DisplayState::on))
> +            .Times(1);
> +
> +    config.engine = engine;
> +    config.power_state_controller = power_state_controller;
> +
> +    Player impl{config};
> +
> +    // And switch our state.
> +    engine->mutable_state() = media::Engine::State::playing;
> +}
> +
> +TEST_P(PlayerImplementationEngineState, releases_display_power_state_on_when_engine_state_changes_away_from_playing)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +
> +    auto engine = std::make_shared<NiceMock<MockEngine>>();
> +    ON_CALL(*engine, read_is_video()).WillByDefault(Return(true));
> +    auto power_state_controller = std::make_shared<NiceMock<MockPowerStateController>>();
> +
> +    EXPECT_CALL(*power_state_controller->system_lock, request_release(media::power::SystemState::active))
> +            .Times(0);
> +    EXPECT_CALL(*power_state_controller->display_lock, request_release(media::power::DisplayState::on))
> +            .Times(1);
> +
> +    config.engine = engine;
> +    config.power_state_controller = power_state_controller;
> +
> +    Player impl{config};
> +
> +    // And switch our state.
> +    engine->mutable_state() = media::Engine::State::playing;
> +    engine->mutable_state() = GetParam();
> +}
> +
> +TEST(PlayerImplementation, acquires_system_power_state_active_when_audio_playback_starts)
> +{
> +    using namespace ::testing;
> +
> +    auto config = make_player_configuration_for_testing();
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto engine = std::make_shared<NiceMock<MockEngine>>();
> +    ON_CALL(*engine, read_is_audio()).WillByDefault(Return(true));
> +    auto power_state_controller = std::make_shared<NiceMock<MockPowerStateController>>();
> +
> +    EXPECT_CALL(*power_state_controller->system_lock, request_acquire(media::power::SystemState::active))
> +            .Times(1);
> +    EXPECT_CALL(*power_state_controller->display_lock, request_acquire(media::power::DisplayState::on))
> +            .Times(0);
> +
> +    config.engine = engine;
> +    config.power_state_controller = power_state_controller;
> +
> +    Player impl{config};
> +
> +    // And switch our state.
> +    engine->mutable_state() = media::Engine::State::playing;
> +}
> +
> +TEST_P(PlayerImplementationEngineState, releases_system_power_state_active_when_engine_state_changes_away_from_playing)
> +{
> +    using namespace ::testing;
> +
> +    typedef media::PlayerImplementation<media::PlayerBase> Player;
> +
> +    auto config = make_player_configuration_for_testing();
> +
> +    auto engine = std::make_shared<NiceMock<MockEngine>>();
> +    ON_CALL(*engine, read_is_audio()).WillByDefault(Return(true));
> +    auto power_state_controller = std::make_shared<NiceMock<MockPowerStateController>>();
> +
> +    EXPECT_CALL(*power_state_controller->system_lock, request_release(media::power::SystemState::active))
> +            .Times(1);
> +    EXPECT_CALL(*power_state_controller->display_lock, request_release(media::power::DisplayState::on))
> +            .Times(0);
> +
> +    config.engine = engine;
> +    config.power_state_controller = power_state_controller;
> +
> +    Player impl{config};
> +
> +    // And switch our state.
> +    engine->mutable_state() = media::Engine::State::playing;
> +    engine->mutable_state() = GetParam();
> +}
> +
> +INSTANTIATE_TEST_CASE_P(
> +        Power,
> +        PlayerImplementationEngineState,
> +        ::testing::Values(media::Engine::State::stopped, media::Engine::State::paused, media::Engine::State::ready));
> 
> === added file 'tests/integration-tests/player_skeleton_test.cpp'
> --- tests/integration-tests/player_skeleton_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/player_skeleton_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,517 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/player_implementation.h>
> +#include <core/media/player_skeleton.h>
> +
> +#include <core/media/player_configuration.h>
> +#include <core/media/player_stub.h>
> +#include <core/media/track.h>
> +#include <core/media/service.h>
> +
> +#include "fixtures/player_skeleton.h"
> +
> +#include "mock/client_death_observer.h"
> +#include "mock/engine.h"
> +#include "mock/player.h"
> +#include "mock/media_service.h"
> +#include "mock/power_state_controller.h"
> +#include "mock/request_context_resolver.h"
> +#include "mock/request_authenticator.h"
> +
> +#include "tools/a_trap_stopping_itself.h"
> +#include "tools/did_finish_successfully.h"
> +#include "tools/event_sink.h"
> +#include "tools/gdb_barrier.h"
> +
> +#include <core/dbus/asio/executor.h>
> +#include <core/dbus/fixture.h>
> +
> +#include <core/testing/cross_process_sync.h>
> +#include <core/testing/fork_and_run.h>
> +
> +#include <gmock/gmock.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +using namespace fixtures;
> +
> +namespace
> +{
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +// Our default texture handle we use in testing.
> +constexpr const std::uint32_t the_texture_id{13};
> +// Our default uri we use in testing.
> +const media::Track::UriType the_uri{"file:///does/not/exist"};
> +// Our default timestamp we use in testing.
> +const std::chrono::microseconds the_timestamp{42};
> +// A helper return our default track meta data we use in testing.
> +media::Track::MetaData the_track_meta_data()
> +{
> +    media::Track::MetaData md;
> +    md.set("key1", "value1");
> +    md.set("key2", "value2");
> +
> +    return md;
> +}
> +
> +// Constructs a PlayerSkeleton::Configuration instance containing mocked instances for the functional dependencies.
> +media::PlayerSkeleton::Configuration make_skeleton_configuration_for_testing(const PlayerSkeleton::ServiceFixture& sf)
> +{
> +    using namespace ::testing;
> +
> +    return media::PlayerSkeleton::Configuration
> +    {
> +        sf.session_bus,
> +        sf.object,
> +        std::make_shared<NiceMock<MockRequestContextResolver>>(),
> +        std::make_shared<NiceMock<MockRequestAuthenticator>>()
> +    };
> +}
> +
> +// Constructs a PlayerImplementation::Configuration instance containing mocked
> +// instances for the functional dependencies.
> +media::PlayerImplementation<media::PlayerSkeleton>::Configuration make_player_configuration_for_testing(const PlayerSkeleton::ServiceFixture& sf)
> +{
> +    using namespace ::testing;
> +
> +    auto resolver = std::make_shared<NiceMock<MockRequestContextResolver>>();
> +    auto authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +
> +    return media::PlayerImplementation<media::PlayerSkeleton>::Configuration
> +    {
> +        media::PlayerSkeleton::Configuration
> +        {
> +            sf.session_bus,
> +            sf.object,
> +            resolver,
> +            authenticator
> +        },
> +        the_player_key,
> +        std::make_shared<NiceMock<MockEngine>>(),
> +        resolver,
> +        authenticator,
> +        std::make_shared<NiceMock<MockClientDeathObserver>>(),
> +        std::make_shared<NiceMock<MockPowerStateController>>()
> +    };
> +}
> +}
> +
> +// Please make sure that tests are executed in child processes
> +// to ensure maximum test isolation.
> +TEST_F(PlayerSkeleton, request_for_open_uri_is_authenticated)
> +{
> +    core::testing::CrossProcessSync service_is_ready;
> +
> +    auto service = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +
> +        auto resolver = std::make_shared<NiceMock<MockRequestContextResolver>>();
> +        EXPECT_CALL(*resolver, resolve_context_for_dbus_name_async(_, _)).Times(1);
> +        auto authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +        EXPECT_CALL(*authenticator, authenticate_open_uri_request(_, _)).Times(1);        
> +
> +        auto config = make_player_configuration_for_testing(sf);
> +        config.parent.request_context_resolver = resolver;
> +        config.parent.request_authenticator = authenticator;
> +
> +        media::PlayerImplementation<media::PlayerSkeleton> impl{config};
> +
> +        service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &service_is_ready]()
> +    {
> +        PlayerSkeleton::ClientFixture cf{this};
> +        service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        auto result = cf.object->transact_method<mpris::Player::OpenUri, bool>(std::string{"file:///does/not/exist"});
> +        EXPECT_FALSE(result.is_error());
> +        EXPECT_FALSE(result.value());
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +TEST_F(PlayerSkeleton, open_uri_is_exception_safe_for_throwing_authenticator_and_returns_false_in_case_of_exception)
> +{
> +    core::testing::CrossProcessSync service_is_ready;
> +
> +    auto service = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +        auto authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +        EXPECT_CALL(*authenticator, authenticate_open_uri_request(_, _))
> +                .Times(1)
> +                .WillRepeatedly(Throw(std::runtime_error{"Just an error"}));
> +
> +        auto config = make_player_configuration_for_testing(sf);
> +        config.parent.request_authenticator = authenticator;
> +
> +        media::PlayerImplementation<media::PlayerSkeleton> impl{config};
> +
> +        service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &service_is_ready]()
> +    {
> +        PlayerSkeleton::ClientFixture cf{this};
> +        service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        auto result = cf.object->transact_method<mpris::Player::OpenUri, bool>(std::string{"file:///does/not/exist"});
> +        EXPECT_FALSE(result.is_error());
> +        EXPECT_FALSE(result.value());
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +TEST_F(PlayerSkeleton, open_uri_is_exception_safe_for_throwing_player_implementation_and_returns_false_in_case_of_exception)
> +{
> +    ::testing::FLAGS_gmock_verbose = "info";
> +    core::testing::CrossProcessSync service_is_ready;
> +
> +    auto service = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +        auto authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +        ON_CALL(*authenticator, authenticate_open_uri_request(_, _))
> +                .WillByDefault(
> +                    Return(media::apparmor::ubuntu::RequestAuthenticator::Result{true, ""}));   
> +
> +        MockPlayer<media::PlayerSkeleton>::Configuration config{make_skeleton_configuration_for_testing(sf)};
> +        config.parent.request_authenticator = authenticator;
> +        NiceMock<MockPlayer<media::PlayerSkeleton>> player{config};
> +
> +        EXPECT_CALL(player, open_uri(_))
> +                .Times(1)
> +                .WillRepeatedly(Throw(std::runtime_error{""}));
> +
> +        service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &service_is_ready]()
> +    {
> +        PlayerSkeleton::ClientFixture cf{this};
> +        service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        auto result = cf.object->transact_method<mpris::Player::OpenUri, bool>(std::string{"file:///does/not/exist"});
> +
> +        EXPECT_FALSE(result.is_error());
> +        EXPECT_FALSE(result.value());
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +TEST_F(PlayerSkeleton, dbus_forwards_calls_to_impl)
> +{
> +    core::testing::CrossProcessSync service_is_ready;
> +
> +    auto service = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +        auto authenticator = std::make_shared<NiceMock<MockRequestAuthenticator>>();
> +        ON_CALL(*authenticator, authenticate_open_uri_request(_, _))
> +                .WillByDefault(
> +                    Return(media::apparmor::ubuntu::RequestAuthenticator::Result{true, ""}));
> +
> +        MockPlayer<media::PlayerSkeleton>::Configuration config{make_skeleton_configuration_for_testing(sf)};
> +        config.parent.request_authenticator = authenticator;
> +        NiceMock<MockPlayer<media::PlayerSkeleton>> player{config};
> +
> +        EXPECT_CALL(player, key()).Times(1);
> +        // EXPECT_CALL(player, create_gl_texture_video_sink(the_texture_id)).Times(1);
> +        EXPECT_CALL(player, open_uri(the_uri)).Times(1);
> +        EXPECT_CALL(player, next()).Times(1);
> +        EXPECT_CALL(player, previous()).Times(1);
> +        EXPECT_CALL(player, play()).Times(1);
> +        EXPECT_CALL(player, pause()).Times(1);
> +        EXPECT_CALL(player, stop()).Times(1);
> +        EXPECT_CALL(player, seek_to(the_timestamp)).Times(1);
> +
> +        service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ClientFixture cf{this};
> +        service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        media::PlayerStub stub{media::PlayerStub::Configuration{cf.object,the_player_key,[](std::uint32_t) { return media::video::Sink::Ptr{}; }}};
> +
> +        stub.key();
> +        // TODO(tvoss): On platforms supporting hybris, calling into this results
> +        // in a segfault.
> +        //EXPECT_THROW(stub.create_gl_texture_video_sink(the_texture_id), media::Player::Error::OutOfProcessBufferStreamingNotSupported);
> +        stub.open_uri(the_uri);
> +        stub.next();
> +        stub.previous();
> +        stub.play();
> +        stub.pause();
> +        stub.stop();
> +        stub.seek_to(the_timestamp);
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +// TODO(tvoss): We should re-enable this test case once we have a good way of initializing properties
> +// to the correct values in a straightforward way.
> +TEST_F(PlayerSkeleton, DISABLED_dbus_property_changes_and_signals_are_forwarded_from_impl)
> +{
> +    // Synchronization of an event driven test is somwhat complex and we rely
> +    // on three different synchronization points between the client and the service.
> +    //   (1.) The service signals to the client when everything is setup.
> +    //        (1.client) Starts setting up event sinks for testing purposes.
> +    //   (2.) The client signals to the service when the event sink setup procedure is done.
> +    //        (2.service) Adjusts property values and triggers dbus signal emissions.
> +    //   (3.) The service signals to the client when all events have been emitted.
> +    //        (3.client) The client waits for another second before verifying its expectations.
> +    struct Sync
> +    {
> +        core::testing::CrossProcessSync
> +            service_is_ready,
> +            event_sinks_are_set_up,
> +            events_emitted;
> +    } sync;
> +
> +    static const mpris::Player::Defaults defaults;
> +
> +    auto service = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +
> +        MockPlayer<media::PlayerSkeleton>::Configuration config{make_skeleton_configuration_for_testing(sf)};
> +        NiceMock<MockPlayer<media::PlayerSkeleton>> player{config};
> +
> +        sync.service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +        sync.event_sinks_are_set_up.wait_for_signal_ready_for(std::chrono::milliseconds{500});        
> +
> +        (player.can_play() = not defaults.can_play) = defaults.can_play;
> +        (player.can_pause() = not defaults.can_pause) = defaults.can_pause;
> +        (player.can_seek() = not defaults.can_seek) = defaults.can_seek;
> +        (player.can_go_previous() = not defaults.can_go_previous) = defaults.can_go_previous;
> +        (player.can_go_next() = not defaults.can_go_next) = defaults.can_go_next;
> +        (player.is_video_source() = not defaults.is_video_source) = defaults.is_video_source;
> +        (player.is_audio_source() = not defaults.is_audio_source) = defaults.is_audio_source;
> +        player.playback_status() = media::Player::PlaybackStatus::playing;
> +        player.loop_status() = media::Player::LoopStatus::track;
> +        player.playback_rate() = media::Player::PlaybackRate{42};
> +        (player.is_shuffle() = not defaults.shuffle) = defaults.shuffle;
> +        player.meta_data_for_current_track() = the_track_meta_data();
> +        player.volume() = media::Player::Volume{42};
> +        player.minimum_playback_rate() = media::Player::PlaybackRate{42};
> +        player.maximum_playback_rate() = media::Player::PlaybackRate{42};
> +        player.position() = 42;
> +        player.duration() = 42;
> +        player.audio_stream_role() = media::Player::AudioStreamRole::phone;
> +        player.orientation() = media::Player::Orientation::rotate180;
> +
> +        player.seeked_to()(42);
> +        player.end_of_stream()();
> +        player.playback_status_changed()(media::Player::PlaybackStatus::playing);
> +        player.video_dimension_changed()(std::make_tuple(media::video::Height{42}, media::video::Width{84}));
> +
> +        sync.events_emitted.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        sync.service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        PlayerSkeleton::ClientFixture cf{this};
> +
> +        media::PlayerStub stub{media::PlayerStub::Configuration{cf.object,the_player_key,[](std::uint32_t) { return media::video::Sink::Ptr{}; }}};
> +
> +        // We have to scope our expectations to make sure we catch them at exit
> +        {
> +            tools::EventSink<bool> es_can_play{stub.can_play()};
> +            EXPECT_CALL(es_can_play, on_new_event(not defaults.can_play)).Times(1);
> +            tools::EventSink<bool> es_can_pause{stub.can_pause()};
> +            EXPECT_CALL(es_can_pause, on_new_event(not defaults.can_pause)).Times(1);
> +            tools::EventSink<bool> es_can_seek{stub.can_seek()};
> +            EXPECT_CALL(es_can_seek, on_new_event(not defaults.can_seek)).Times(1);
> +            tools::EventSink<bool> es_can_go_previous{stub.can_go_previous()};
> +            EXPECT_CALL(es_can_go_previous, on_new_event(not defaults.can_go_previous)).Times(1);
> +            tools::EventSink<bool> es_can_go_next{stub.can_go_next()};
> +            EXPECT_CALL(es_can_go_next, on_new_event(not defaults.can_go_next)).Times(1);
> +            tools::EventSink<bool> es_is_video_source{stub.is_video_source()};
> +            EXPECT_CALL(es_is_video_source, on_new_event(not defaults.is_video_source)).Times(1);
> +            tools::EventSink<bool> es_is_audio_source{stub.is_audio_source()};
> +            EXPECT_CALL(es_is_audio_source, on_new_event(not defaults.is_audio_source)).Times(1);
> +
> +            tools::EventSink<media::Player::PlaybackStatus> es_playback_status{stub.playback_status()};
> +            EXPECT_CALL(es_playback_status, on_new_event(media::Player::PlaybackStatus::playing)).Times(1);
> +            tools::EventSink<media::Player::LoopStatus> es_loop_status{stub.loop_status()};
> +            EXPECT_CALL(es_loop_status, on_new_event(media::Player::LoopStatus::track)).Times(1);
> +            tools::EventSink<media::Player::PlaybackRate> es_playback_rate{stub.playback_rate()};
> +            EXPECT_CALL(es_playback_rate, on_new_event(media::Player::PlaybackRate{42})).Times(1);
> +            tools::EventSink<bool> es_is_shuffle{stub.is_shuffle()};
> +            EXPECT_CALL(es_is_shuffle, on_new_event(true)).Times(1);
> +            tools::EventSink<media::Track::MetaData> es_meta_data{stub.meta_data_for_current_track()};
> +            EXPECT_CALL(es_meta_data, on_new_event(the_track_meta_data())).Times(1);
> +            tools::EventSink<media::Player::Volume> es_volume{stub.volume()};
> +            EXPECT_CALL(es_volume, on_new_event(media::Player::Volume{42})).Times(1);
> +            tools::EventSink<media::Player::PlaybackRate> es_minimum_playback_rate{stub.minimum_playback_rate()};
> +            EXPECT_CALL(es_minimum_playback_rate, on_new_event(media::Player::PlaybackRate{42})).Times(1);
> +            tools::EventSink<media::Player::PlaybackRate> es_maximum_playback_rate{stub.maximum_playback_rate()};
> +            EXPECT_CALL(es_maximum_playback_rate, on_new_event(media::Player::PlaybackRate{42})).Times(1);
> +            tools::EventSink<std::int64_t> es_position{stub.position()};
> +            EXPECT_CALL(es_position, on_new_event(42)).Times(1);
> +            tools::EventSink<std::int64_t> es_duration{stub.duration()};
> +            EXPECT_CALL(es_duration, on_new_event(42)).Times(1);
> +            tools::EventSink<media::Player::AudioStreamRole> es_audio_stream_role{stub.audio_stream_role()};
> +            EXPECT_CALL(es_audio_stream_role, on_new_event(media::Player::AudioStreamRole::phone)).Times(1);
> +            tools::EventSink<media::Player::Orientation> es_orientation{stub.orientation()};
> +            EXPECT_CALL(es_orientation, on_new_event(media::Player::Orientation::rotate180)).Times(1);
> +
> +            tools::EventSink<int64_t> es_seeked_to{stub.seeked_to()};
> +            EXPECT_CALL(es_seeked_to, on_new_event(42)).Times(1);
> +            tools::EventSink<void> es_end_of_stream{stub.end_of_stream()};
> +            EXPECT_CALL(es_end_of_stream, on_new_event()).Times(1);
> +            tools::EventSink<media::Player::PlaybackStatus> es_playback_status_changed{stub.playback_status_changed()};
> +            EXPECT_CALL(es_playback_status_changed, on_new_event(media::Player::PlaybackStatus::playing)).Times(1);
> +            tools::EventSink<media::video::Dimensions> es_video_dimension_changed{stub.video_dimension_changed()};
> +            EXPECT_CALL(es_video_dimension_changed, on_new_event(std::make_tuple(media::video::Height{42}, media::video::Width{84}))).Times(1);
> +
> +            // We tell the service that we are good to go.
> +            sync.event_sinks_are_set_up.try_signal_ready_for(std::chrono::milliseconds{500});
> +            // And wait for all events to be emitted service side.
> +            sync.events_emitted.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +            std::this_thread::sleep_for(std::chrono::milliseconds{500});
> +        }
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +TEST_F(PlayerSkeleton, dbus_property_changes_and_signals_are_forwarded_from_skeleton_to_impl)
> +{
> +    // Synchronization is a little simpler here. We only need to tell the
> +    // client when event sinks are setup, and wait for events to be emitted before
> +    // tearing down.
> +    struct Sync
> +    {
> +        core::testing::CrossProcessSync
> +            event_sinks_are_set_up,
> +            events_emitted;
> +    } sync;
> +
> +    auto service = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        PlayerSkeleton::ServiceFixture sf{this};
> +
> +        MockPlayer<media::PlayerSkeleton>::Configuration config{make_skeleton_configuration_for_testing(sf)};
> +        NiceMock<MockPlayer<media::PlayerSkeleton>> player{config};
> +
> +        // We have to scope our expectations to make sure we catch them at exit
> +        {
> +            tools::EventSink<media::Player::LoopStatus> es_loop_status{player.loop_status()};
> +            EXPECT_CALL(es_loop_status, on_new_event(media::Player::LoopStatus::track)).Times(1);
> +            tools::EventSink<media::Player::PlaybackRate> es_playback_rate{player.playback_rate()};
> +            EXPECT_CALL(es_playback_rate, on_new_event(media::Player::PlaybackRate{42})).Times(1);
> +            tools::EventSink<bool> es_is_shuffle{player.is_shuffle()};
> +            EXPECT_CALL(es_is_shuffle, on_new_event(true)).Times(1);
> +            tools::EventSink<media::Player::Volume> es_volume{player.volume()};
> +            EXPECT_CALL(es_volume, on_new_event(media::Player::Volume{42})).Times(1);
> +
> +            // We tell the service that we are good to go.
> +            sync.event_sinks_are_set_up.try_signal_ready_for(std::chrono::milliseconds{500});
> +            // And wait for all events to be emitted service side.
> +            sync.events_emitted.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +            // And wait a little further
> +            std::this_thread::sleep_for(std::chrono::milliseconds{500});
> +        }
> +
> +        return sf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &sync]()
> +    {
> +        using namespace ::testing;
> +
> +        sync.event_sinks_are_set_up.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        PlayerSkeleton::ClientFixture cf{this};
> +        media::PlayerStub stub{media::PlayerStub::Configuration{cf.object,the_player_key,[](std::uint32_t) { return media::video::Sink::Ptr{}; }}};
> +
> +        stub.loop_status() = media::Player::LoopStatus::track;
> +        stub.playback_rate() = media::Player::PlaybackRate{42};
> +        stub.is_shuffle() = true;
> +        stub.volume() = media::Player::Volume{42};
> +
> +        sync.events_emitted.try_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> 
> === added file 'tests/integration-tests/service_implementation_test.cpp'
> --- tests/integration-tests/service_implementation_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/service_implementation_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,463 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/service_implementation.h>
> +#include <core/media/player_configuration.h>
> +
> +#include "mock/audio_output_observer.h"
> +#include "mock/battery_observer.h"
> +#include "mock/call_monitor.h"
> +#include "mock/client_death_observer.h"
> +#include "mock/engine_factory.h"
> +#include "mock/keyed_player_store.h"
> +#include "mock/player.h"
> +#include "mock/power_state_controller.h"
> +#include "mock/recorder_observer.h"
> +#include "mock/request_authenticator.h"
> +#include "mock/request_context_resolver.h"
> +#include "mock/engine.h"
> +
> +#include "tools/did_finish_successfully.h"
> +
> +#include "../test_data.h"
> +
> +#include <core/dbus/fixture.h>
> +#include <core/posix/fork.h>
> +#include <core/posix/wait.h>
> +#include <gmock/gmock.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +struct ServiceImplementation : public core::dbus::testing::Fixture
> +{
> +    struct Service
> +    {
> +        static constexpr const char* service_name_for_testing
> +        {
> +            "this.is.the.media.service.for.testing"
> +        };
> +
> +        static constexpr const char* object_path_for_testing
> +        {
> +            "/this/is/the/media/player/skeleton/for/testing"
> +        };
> +
> +        Service(ServiceImplementation* impl)
> +            : service{core::dbus::Service::add_service(impl->session_bus(), service_name_for_testing)},
> +              object{service->add_object_for_path(core::dbus::types::ObjectPath{object_path_for_testing})}
> +        {}
> +
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +    };
> +
> +    ServiceImplementation() : es{session_bus(), system_bus()}
> +    {
> +    }
> +
> +    media::helper::ExternalServices es;
> +
> +};
> +
> +// We use a tuple to pass around mocked instances
> +// and to allow for setting up expectations.
> +typedef std::tuple
> +<
> +    std::shared_ptr<MockKeyedPlayerStore>,
> +    std::shared_ptr<MockClientDeathObserver>,
> +    std::shared_ptr<MockEngineFactory>,
> +    std::shared_ptr<MockAudioOutputObserver>,
> +    std::shared_ptr<MockRecorderObserver>,
> +    std::shared_ptr<MockPowerStateController>,
> +    std::shared_ptr<MockBatteryObserver>,
> +    std::shared_ptr<MockRequestContextResolver>,
> +    std::shared_ptr<MockRequestAuthenticator>,
> +    std::shared_ptr<MockCallMonitor>
> +> MockedConfiguration;
> +
> +enum Idx
> +{
> +    keyed_player_store,
> +    death_observer,
> +    engine_factory,
> +    audio_output_observer,
> +    recorder_observer,
> +    power_state_controller,
> +    battery_observer,
> +    request_context_resolver,
> +    request_authenticator,
> +    call_monitor
> +};
> +
> +MockedConfiguration make_mocked_configuration()
> +{
> +    return std::make_tuple(
> +        std::make_shared<testing::NiceMock<MockKeyedPlayerStore>>(),
> +        std::make_shared<testing::NiceMock<MockClientDeathObserver>>(),
> +        std::make_shared<testing::NiceMock<MockEngineFactory>>(),
> +        std::make_shared<testing::NiceMock<MockAudioOutputObserver>>(),
> +        std::make_shared<testing::NiceMock<MockRecorderObserver>>(),
> +        std::make_shared<testing::NiceMock<MockPowerStateController>>(),
> +        std::make_shared<testing::NiceMock<MockBatteryObserver>>(),
> +        std::make_shared<testing::NiceMock<MockRequestContextResolver>>(),
> +        std::make_shared<testing::NiceMock<MockRequestAuthenticator>>(),
> +        std::make_shared<testing::NiceMock<MockCallMonitor>>());
> +}
> +
> +media::ServiceImplementation::Configuration tie_to_mocked_configuration(MockedConfiguration& mc, media::helper::ExternalServices& es)
> +{
> +    return media::ServiceImplementation::Configuration
> +    {
> +        std::get<Idx::engine_factory>(mc)->to_engine_factory(),
> +        std::get<Idx::keyed_player_store>(mc),
> +        std::get<Idx::battery_observer>(mc),
> +        std::get<Idx::power_state_controller>(mc),
> +        std::get<Idx::death_observer>(mc),
> +        std::get<Idx::recorder_observer>(mc),
> +        std::get<Idx::audio_output_observer>(mc),
> +        std::get<Idx::request_context_resolver>(mc),
> +        std::get<Idx::request_authenticator>(mc),
> +        std::get<Idx::call_monitor>(mc),
> +        es
> +    };
> +}
> +
> +std::shared_ptr<::testing::NiceMock<MockPlayer<media::PlayerBase>>> make_alarm_player()
> +{
> +    auto player = std::make_shared<::testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +    player->playback_status() = media::Player::PlaybackStatus::playing;
> +    player->audio_stream_role() = media::Player::AudioStreamRole::alarm;
> +    return player;
> +}
> +
> +std::shared_ptr<::testing::NiceMock<MockPlayer<media::PlayerBase>>> make_multimedia_player()
> +{
> +    auto player = std::make_shared<::testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +    player->playback_status() = media::Player::PlaybackStatus::playing;
> +    player->is_audio_source() = true;
> +    player->is_video_source() = false;
> +    player->audio_stream_role() = media::Player::AudioStreamRole::multimedia;
> +    return player;
> +}
> +
> +std::shared_ptr<::testing::NiceMock<KeyedMockPlayer<media::PlayerBase>>> make_keyed_playing_multimedia_player()
> +{
> +    auto player = std::make_shared<::testing::NiceMock<KeyedMockPlayer<media::PlayerBase>>>();
> +    player->playback_status() = media::Player::PlaybackStatus::playing;
> +    player->audio_stream_role() = media::Player::AudioStreamRole::multimedia;
> +    return player;
> +}
> +
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +}
> +
> +TEST_F(ServiceImplementation, requests_display_state_on_when_recording_starts)
> +{
> +    auto mc = make_mocked_configuration();
> +
> +    auto recorder_observer = std::get<Idx::recorder_observer>(mc);
> +    auto power_state_controller = std::get<Idx::power_state_controller>(mc);
> +
> +    EXPECT_CALL(*power_state_controller->display_lock, request_acquire(media::power::DisplayState::on)).Times(1);
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report that the recording started.
> +    recorder_observer->properties.recording_state = media::RecordingState::started;
> +}
> +
> +TEST_F(ServiceImplementation, releases_display_state_on_when_recording_starts)
> +{
> +    auto mc = make_mocked_configuration();
> +
> +    auto recorder_observer = std::get<Idx::recorder_observer>(mc);
> +    auto power_state_controller = std::get<Idx::power_state_controller>(mc);
> +
> +    EXPECT_CALL(*power_state_controller->display_lock, request_release(media::power::DisplayState::on)).Times(1);
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report that the recording started ...
> +    recorder_observer->properties.recording_state = media::RecordingState::started;
> +    // prior to stopping it.
> +    recorder_observer->properties.recording_state = media::RecordingState::stopped;
> +}
> +
> +TEST_F(ServiceImplementation, pauses_all_multimedia_session_if_battery_level_reaches_low)
> +{
> +    auto multimedia_player = make_multimedia_player();
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player, pause()).Times(1);
> +    EXPECT_CALL(*alarm_player, pause()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto battery_observer = std::get<Idx::battery_observer>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player;
> +    keyed_player_store->properties.map[1] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report the battery reaching low.
> +    battery_observer->properties.level = media::power::Level::low;
> +}
> +
> +TEST_F(ServiceImplementation, pauses_all_multimedia_session_if_battery_level_reaches_very_low)
> +{
> +    auto multimedia_player = make_multimedia_player();
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player, pause()).Times(1);
> +    EXPECT_CALL(*alarm_player, pause()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto battery_observer = std::get<Idx::battery_observer>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player;
> +    keyed_player_store->properties.map[1] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report the battery reaching low.
> +    battery_observer->properties.level = media::power::Level::very_low;
> +}
> +
> +TEST_F(ServiceImplementation, resumes_all_multimedia_sessions_when_battery_critical_notification_is_gone)
> +{
> +    auto multimedia_player = make_multimedia_player();
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player, play()).Times(1);
> +    EXPECT_CALL(*alarm_player, play()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto battery_observer = std::get<Idx::battery_observer>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player;
> +    keyed_player_store->properties.map[1] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report the battery reaching low.
> +    battery_observer->properties.level = media::power::Level::very_low;
> +    // We show a notification.
> +    battery_observer->properties.is_warning_active = true;
> +    // Which is acknowledged by the user, and we subsequently resume playback.
> +    battery_observer->properties.is_warning_active = false;
> +}
> +
> +TEST_F(ServiceImplementation, pauses_all_multimedia_sessions_only_when_an_external_output_is_disconnected)
> +{
> +    auto multimedia_player = make_multimedia_player();
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player, pause()).Times(1);
> +    EXPECT_CALL(*alarm_player, pause()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto audio_output_observer = std::get<Idx::audio_output_observer>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player;
> +    keyed_player_store->properties.map[1] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report an external output to be connected and don't expect any reaction to that.
> +    audio_output_observer->properties.external_output_state = media::audio::OutputState::Earpiece;
> +    // We report an external output to be disconnected.
> +    audio_output_observer->properties.external_output_state = media::audio::OutputState::Speaker;
> +}
> +
> +TEST_F(ServiceImplementation, pauses_first_multimedia_session_when_second_multimedia_session_plays)
> +{
> +    using namespace ::testing;
> +
> +    const std::string test_file{"/tmp/test.ogg"};
> +    const std::string test_file_uri{"file:///tmp/test.ogg"};
> +    std::remove(test_file.c_str());
> +    ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));
> +
> +    // Create 2 mocked player instances
> +    auto multimedia_player1 = make_keyed_playing_multimedia_player();
> +    auto multimedia_player2 = make_keyed_playing_multimedia_player();
> +
> +    // Layout the test expectations. Player 1 will first play test.ogg,
> +    // and player 2 will play test.ogg. Player 1 should automatically
> +    // be paused when we call pause_other_session with key 2.
> +    EXPECT_CALL(*multimedia_player1, pause()).Times(1);
> +    EXPECT_CALL(*multimedia_player2, pause()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +
> +    keyed_player_store->properties.map[multimedia_player1->key()] = multimedia_player1;
> +    keyed_player_store->properties.map[multimedia_player2->key()] = multimedia_player2;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    multimedia_player1->open_uri(test_file_uri);
> +    multimedia_player1->play();
> +
> +    // multimedia_player1 should pause before multimedia_player2 starts playing
> +    multimedia_player2->open_uri(test_file_uri);
> +    impl->pause_other_sessions(multimedia_player2->key());
> +    multimedia_player2->play();
> +}
> +
> +TEST_F(ServiceImplementation, pauses_all_multimedia_sessions_when_accepting_a_call)
> +{
> +    auto multimedia_player = make_multimedia_player();
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player, pause()).Times(1);
> +    EXPECT_CALL(*alarm_player, pause()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto call_monitor = std::get<Idx::call_monitor>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player;
> +    keyed_player_store->properties.map[1] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report an incoming call.
> +    call_monitor->signals.on_call_state_changed(media::telephony::CallMonitor::State::OnHook);
> +}
> +
> +TEST_F(ServiceImplementation, resumes_all_paused_multimedias_session_when_ending_a_call)
> +{
> +    auto multimedia_player1 = make_multimedia_player();
> +    auto multimedia_player2 = make_multimedia_player();
> +    multimedia_player2->playback_status() = media::Player::PlaybackStatus::stopped;
> +    auto alarm_player = make_alarm_player();
> +
> +    EXPECT_CALL(*multimedia_player1, pause()).Times(1);
> +    EXPECT_CALL(*multimedia_player2, pause()).Times(0);
> +    EXPECT_CALL(*alarm_player, pause()).Times(0);
> +
> +    EXPECT_CALL(*multimedia_player1, play()).Times(1);
> +    EXPECT_CALL(*multimedia_player2, play()).Times(0);
> +    EXPECT_CALL(*alarm_player, play()).Times(0);
> +
> +    auto mc = make_mocked_configuration();
> +
> +    auto keyed_player_store = std::get<Idx::keyed_player_store>(mc);
> +    auto call_monitor = std::get<Idx::call_monitor>(mc);
> +
> +    keyed_player_store->properties.map[0] = multimedia_player1;
> +    keyed_player_store->properties.map[1] = multimedia_player2;
> +    keyed_player_store->properties.map[2] = alarm_player;
> +
> +    auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +    // We report an incoming call.
> +    call_monitor->signals.on_call_state_changed(media::telephony::CallMonitor::State::OnHook);
> +    // That is terminated afterwards.
> +    call_monitor->signals.on_call_state_changed(media::telephony::CallMonitor::State::OffHook);
> +}
> +
> +TEST_F(ServiceImplementation, calls_into_engine_factory_when_creating_a_session)
> +{
> +    using namespace ::testing;
> +
> +    auto child = core::posix::fork([this]()
> +    {
> +        ServiceImplementation::Service fixture{this};
> +
> +        auto engine = std::make_shared<MockEngine>();
> +
> +        auto mc = make_mocked_configuration();
> +        auto engine_factory = std::get<Idx::engine_factory>(mc);
> +
> +        EXPECT_CALL(*engine_factory, make_engine())
> +                .Times(1).WillRepeatedly(Return(engine));
> +
> +        auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +
> +        impl->create_session(media::Player::Configuration{42, session_bus(), fixture.object});
> +
> +        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                             : core::posix::exit::Status::success;
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(child.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +TEST_F(ServiceImplementation, hands_down_correct_player_key_when_creating_a_session)
> +{
> +    using namespace ::testing;
> +
> +    auto child = core::posix::fork([this]()
> +    {
> +        ServiceImplementation::Service fixture{this};
> +        auto mc = make_mocked_configuration();
> +        auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +        auto session = impl->create_session(media::Player::Configuration{42, session_bus(), fixture.object});
> +        EXPECT_EQ(42, session->key());
> +
> +        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                             : core::posix::exit::Status::success;
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(child.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +// Fails right now, thus disabling it. We have to investigate why the player is not correctly removed from
> +// the player store.
> +TEST_F(ServiceImplementation, DISABLED_subscribes_to_on_client_disconnected_signal_and_removes_disconnected_clients_from_store)
> +{
> +    using namespace ::testing;
> +
> +    auto child = core::posix::fork([this]()
> +    {
> +        ServiceImplementation::Service fixture{this};
> +
> +        {
> +            auto mc = make_mocked_configuration();
> +            auto player_store = std::get<Idx::keyed_player_store>(mc);
> +            auto client_death_observer = std::get<Idx::death_observer>(mc);
> +
> +            EXPECT_CALL(*player_store, remove_player_for_key(the_player_key)).Times(1);
> +
> +            auto impl = std::make_shared<media::ServiceImplementation>(tie_to_mocked_configuration(mc, es));
> +            impl->create_session(media::Player::Configuration{the_player_key, session_bus(), fixture.object});
> +
> +            client_death_observer->signals.on_client_with_key_died(the_player_key);
> +        }
> +
> +        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                             : core::posix::exit::Status::success;
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(child.wait_for(core::posix::wait::Flags::untraced)));
> +}
> 
> === added file 'tests/integration-tests/service_skeleton_test.cpp'
> --- tests/integration-tests/service_skeleton_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/integration-tests/service_skeleton_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,344 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/service_skeleton.h>
> +#include <core/media/service_stub.h>
> +
> +#include <core/media/hashed_keyed_player_store.h>
> +#include <core/media/player_configuration.h>
> +#include <core/media/player_skeleton.h>
> +
> +#include "mock/keyed_player_store.h"
> +#include "mock/player.h"
> +#include "mock/request_authenticator.h"
> +#include "mock/request_context_resolver.h"
> +
> +#include "tools/a_trap_stopping_itself.h"
> +#include "tools/did_finish_successfully.h"
> +#include "tools/gdb_barrier.h"
> +
> +#include <core/dbus/fixture.h>
> +#include <core/dbus/asio/executor.h>
> +
> +#include <core/posix/exit.h>
> +#include <core/posix/fork.h>
> +#include <core/posix/process.h>
> +#include <core/posix/this_process.h>
> +
> +#include <core/testing/cross_process_sync.h>
> +
> +#include <gmock/gmock.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +struct MockCoverArtResolver : public std::enable_shared_from_this<MockCoverArtResolver>
> +{
> +    // Save us some typing.
> +    typedef std::shared_ptr<MockCoverArtResolver> Ptr;
> +
> +    MOCK_METHOD3(resolve_cover_art, std::string(const std::string&, const std::string&, const std::string&));
> +
> +    media::CoverArtResolver to_functional()
> +    {
> +        auto sp = shared_from_this();
> +        return [sp](const std::string& track, const std::string& album, const std::string& artist)
> +        {
> +            return sp->resolve_cover_art(track, album, artist);
> +        };
> +    }
> +};
> +
> +struct MockService : public media::Service
> +{
> +    // Save us some typing.
> +    typedef std::shared_ptr<MockService> Ptr;
> +
> +    MockService() = default;
> +
> +    MOCK_METHOD1(create_session, std::shared_ptr<media::Player>(const media::Player::Configuration&));
> +    MOCK_METHOD2(create_fixed_session, std::shared_ptr<media::Player>(const std::string& name, const media::Player::Configuration&));
> +    MOCK_METHOD1(pause_other_sessions, void(media::Player::PlayerKey));
> +    MOCK_METHOD1(resume_session, std::shared_ptr<media::Player>(media::Player::PlayerKey));
> +};
> +
> +typedef std::tuple
> +<
> +    MockService::Ptr,
> +    MockKeyedPlayerStore::Ptr,
> +    MockCoverArtResolver::Ptr
> +> MockedConfiguration;
> +
> +enum Idx
> +{
> +    service,
> +    keyed_player_store,
> +    cover_art_resolver
> +};
> +
> +MockedConfiguration make_mock_configuration()
> +{
> +    return std::make_tuple(
> +                std::make_shared<testing::NiceMock<MockService>>(),
> +                std::make_shared<testing::NiceMock<MockKeyedPlayerStore>>(),
> +                std::make_shared<testing::NiceMock<MockCoverArtResolver>>());
> +}
> +
> +// Our custom fixture that provides us with private session and system
> +// bus instances. In addition, we define a custom service name and object
> +// path to enable maximum test isolation.
> +struct ServiceSkeleton : public core::dbus::testing::Fixture
> +{
> +    static constexpr const char* service_name_for_testing
> +    {
> +        "this.is.the.media.service.for.testing"
> +    };
> +
> +    static constexpr const char* object_path_for_testing
> +    {
> +        "/this/is/the/media/service/skeleton/for/testing"
> +    };
> +
> +    static constexpr const char* player_path_for_testing
> +    {
> +        "/this/is/the/media/service/player/path/for/testing"
> +    };
> +
> +    // A simple fixture that can be used by service processes
> +    // to expose an mpris::Player instance to the bus, or, in general
> +    // interact with dbus. It is not recommended to instantiate instances
> +    // of this class in the testing process.
> +    struct ServiceFixture
> +    {
> +        ServiceFixture(ServiceSkeleton* skeleton)
> +            : parent{skeleton},
> +              signal_trap{tools::a_trap_stopping_itself()},
> +              session_bus{skeleton->session_bus()},
> +              service{core::dbus::Service::add_service(session_bus, service_name_for_testing)},
> +              object{service->add_object_for_path(core::dbus::types::ObjectPath{object_path_for_testing})},
> +              player{service->add_object_for_path(core::dbus::types::ObjectPath{player_path_for_testing})}
> +        {
> +            session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
> +            worker = std::move(std::thread{[this]() { session_bus->run();}});
> +
> +            tools::wait_for_user_to_attach_with_gdb_if_enabled("Service");
> +        }
> +
> +        ~ServiceFixture()
> +        {
> +            session_bus->stop();
> +            if (worker.joinable())
> +                worker.join();
> +        }
> +
> +        core::posix::exit::Status run(std::function<void()> post_trap = [](){})
> +        {
> +            signal_trap->run();
> +            post_trap();
> +            return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                                 : core::posix::exit::Status::success;
> +        }
> +
> +        ServiceSkeleton* parent;
> +        std::shared_ptr<core::posix::SignalTrap> signal_trap;
> +        core::dbus::Bus::Ptr session_bus;
> +        std::thread worker;
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +        core::dbus::Object::Ptr player;
> +    };
> +
> +    // A simple fixture that can be used by client processes
> +    // to connect to an mpris::Player instance on the bus, or, in general
> +    // interact with dbus. It is not recommended to instantiate instances
> +    // of this class in the testing process.
> +    struct ClientFixture
> +    {
> +        ClientFixture(ServiceSkeleton* skeleton)
> +            : parent{skeleton},
> +              session_bus{skeleton->session_bus()},
> +              service{core::dbus::Service::use_service(session_bus, service_name_for_testing)},
> +              object{service->object_for_path(core::dbus::types::ObjectPath{object_path_for_testing})}
> +        {
> +            session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
> +            tools::wait_for_user_to_attach_with_gdb_if_enabled("Client");
> +        }
> +
> +        ~ClientFixture()
> +        {
> +        }
> +
> +        core::posix::exit::Status run()
> +        {
> +            return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure
> +                                                 : core::posix::exit::Status::success;
> +        }
> +
> +        ServiceSkeleton* parent;
> +        core::dbus::Bus::Ptr session_bus;
> +        core::dbus::Service::Ptr service;
> +        core::dbus::Object::Ptr object;
> +    };
> +
> +    ServiceSkeleton() : pid{core::posix::this_process::instance().pid()}
> +    {
> +    }
> +
> +    pid_t pid;
> +};
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +// Our default player name we use in testing.
> +const std::string the_player_name{"the_player_name"};
> +// Our default uri we use in testing.
> +const media::Track::UriType the_uri{"file:///does/not/exist"};
> +}
> +
> +TEST_F(ServiceSkeleton, forwards_calls_to_implementation)
> +{
> +    auto child = core::posix::fork([this]()
> +    {
> +        using namespace ::testing;
> +
> +        ServiceSkeleton::ServiceFixture sf{this};
> +
> +        auto instance = std::make_shared<NiceMock<MockPlayer<media::PlayerBase>>>();
> +        auto mc = make_mock_configuration();
> +
> +        EXPECT_CALL(*std::get<Idx::service>(mc), create_session(_)).Times(1).WillRepeatedly(Return(instance));
> +        EXPECT_CALL(*std::get<Idx::service>(mc), create_fixed_session(the_player_name, _)).Times(1).WillRepeatedly(Return(instance));
> +        EXPECT_CALL(*std::get<Idx::service>(mc), pause_other_sessions(the_player_key)).Times(1);
> +        EXPECT_CALL(*std::get<Idx::service>(mc), resume_session(the_player_key)).Times(1).WillRepeatedly(Return(instance));
> +
> +        media::ServiceSkeleton skeleton
> +        {
> +            media::ServiceSkeleton::Configuration
> +            {
> +                sf.session_bus,
> +                sf.service,
> +                sf.object,
> +                std::get<Idx::service>(mc),
> +                std::get<Idx::keyed_player_store>(mc),
> +                media::ServiceSkeleton::default_player_key_sampler(),
> +                media::ServiceSkeleton::default_player_path_sampler(),
> +                std::get<Idx::cover_art_resolver>(mc)->to_functional()
> +            }
> +        };
> +
> +        skeleton.create_session(media::Player::Configuration{the_player_key, sf.session_bus, sf.player});
> +        skeleton.create_fixed_session(the_player_name, media::Player::Configuration{the_player_key, sf.session_bus, sf.player});
> +        skeleton.pause_other_sessions(the_player_key);
> +        skeleton.resume_session(the_player_key);
> +
> +        return HasFailure() ? core::posix::exit::Status::failure
> +                            : core::posix::exit::Status::success;
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(child.wait_for(core::posix::wait::Flags::untraced)));
> +}
> +
> +namespace
> +{
> +std::shared_ptr<media::Player> make_mock_player_exposed_to_bus(const media::Player::Configuration& config)
> +{
> +    using namespace ::testing;
> +
> +    auto player = std::make_shared<NiceMock<MockPlayer<media::PlayerSkeleton>>>(MockPlayer<media::PlayerSkeleton>::Configuration
> +    {
> +        media::PlayerSkeleton::Configuration
> +        {
> +            config.bus, config.session,
> +            std::make_shared<NiceMock<MockRequestContextResolver>>(), std::make_shared<NiceMock<MockRequestAuthenticator>>()
> +        }
> +    });
> +
> +    ON_CALL(*player, key()).WillByDefault(Return(config.key));
> +    return player;
> +}
> +}
> +
> +TEST_F(ServiceSkeleton, dbus_forwards_calls_to_implementation)
> +{
> +    core::testing::CrossProcessSync service_is_ready;
> +
> +    auto service = core::posix::fork([this, &service_is_ready]()
> +    {
> +        using namespace ::testing;
> +
> +        ServiceSkeleton::ServiceFixture sf{this};
> +
> +        auto mc = make_mock_configuration();
> +        EXPECT_CALL(*std::get<Idx::service>(mc), create_session(_)).Times(2).WillRepeatedly(Invoke(make_mock_player_exposed_to_bus));
> +        EXPECT_CALL(*std::get<Idx::service>(mc), pause_other_sessions(_)).Times(1);
> +        // Both these calls are entirely handled by the skeleton right now.
> +        // That's not necessarily how things should work as the skeleton's responsibility should be
> +        // limited to communication.
> +        // EXPECT_CALL(*std::get<Idx::service>(mc), create_fixed_session(the_player_name, _)).Times(1).WillRepeatedly(Return(second_instance));
> +        // EXPECT_CALL(*std::get<Idx::service>(mc), resume_session(_)).Times(1);
> +
> +        media::ServiceSkeleton skeleton
> +        {
> +            media::ServiceSkeleton::Configuration
> +            {
> +                sf.session_bus,
> +                sf.service,
> +                sf.object,
> +                std::get<Idx::service>(mc),
> +                std::make_shared<media::HashedKeyedPlayerStore>(),
> +                media::ServiceSkeleton::default_player_key_sampler(),
> +                media::ServiceSkeleton::default_player_path_sampler(),
> +                std::get<Idx::cover_art_resolver>(mc)->to_functional()
> +            }
> +        };
> +
> +        service_is_ready.try_signal_ready_for(std::chrono::milliseconds{500});
> +        return sf.run([&mc](){Mock::VerifyAndClearExpectations(std::get<Idx::service>(mc).get());});
> +    }, core::posix::StandardStream::empty);
> +
> +    auto client = core::posix::fork([this, &service_is_ready]()
> +    {
> +        ServiceSkeleton::ClientFixture cf{this};
> +        service_is_ready.wait_for_signal_ready_for(std::chrono::milliseconds{500});
> +
> +        media::ServiceStub::Configuration config
> +        {
> +            cf.session_bus,
> +            cf.service,
> +            cf.object,
> +            [](std::uint32_t)
> +            {
> +                return [](media::Player::PlayerKey)
> +                {
> +                    return media::video::Sink::Ptr{};
> +                };
> +            }
> +        };
> +        auto stub = std::make_shared<media::ServiceStub>(config);
> +        auto session = stub->create_session(media::Player::Client::default_configuration());
> +        auto fixed_session = stub->create_fixed_session(the_player_name, media::Player::Client::default_configuration());
> +        stub->pause_other_sessions(session->key());
> +        auto resumed_session = stub->resume_session(fixed_session->key());
> +
> +        return cf.run();
> +    }, core::posix::StandardStream::empty);
> +
> +    EXPECT_TRUE(tools::did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
> +    service.send_signal_or_throw(core::posix::Signal::sig_term);
> +    EXPECT_TRUE(tools::did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
> +}
> 
> === added directory 'tests/mock'
> === added file 'tests/mock/audio_output_observer.h'
> --- tests/mock/audio_output_observer.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/audio_output_observer.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_AUDIO_OUTPUT_OBSERVER_H_
> +#define MOCK_AUDIO_OUTPUT_OBSERVER_H_
> +
> +#include <core/media/audio/output_observer.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct MockAudioOutputObserver : public core::ubuntu::media::audio::OutputObserver
> +{
> +    MockAudioOutputObserver()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, external_output_state())
> +                .WillByDefault(ReturnRef(properties.external_output_state));
> +    }
> +
> +    MOCK_CONST_METHOD0(external_output_state, const core::Property<core::ubuntu::media::audio::OutputState>&());
> +
> +    struct
> +    {
> +        core::Property<core::ubuntu::media::audio::OutputState> external_output_state;
> +    } properties;
> +};
> +
> +#endif // MOCK_AUDIO_OUTPUT_OBSERVER_H_
> 
> === added file 'tests/mock/battery_observer.h'
> --- tests/mock/battery_observer.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/battery_observer.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_BATTERY_OBSERVER_H_
> +#define MOCK_BATTERY_OBSERVER_H_
> +
> +#include <core/media/power/battery_observer.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct MockBatteryObserver : public core::ubuntu::media::power::BatteryObserver
> +{
> +    MockBatteryObserver()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, level())
> +                .WillByDefault(ReturnRef(properties.level));
> +        ON_CALL(*this, is_warning_active())
> +                .WillByDefault(ReturnRef(properties.is_warning_active));
> +    }
> +
> +    // A getable/observable property reporting the current power-level
> +    // of the system.
> +    MOCK_CONST_METHOD0(level, const core::Property<core::ubuntu::media::power::Level>&());
> +    // A getable/observable property indicating whether a power-level
> +    // warning is currently presented to the user.
> +    MOCK_CONST_METHOD0(is_warning_active, const core::Property<bool>&());
> +
> +    struct
> +    {
> +        core::Property<core::ubuntu::media::power::Level> level;
> +        core::Property<bool> is_warning_active;
> +    } properties;
> +};
> +
> +#endif // MOCK_BATTERY_OBSERVER_H_
> 
> === added file 'tests/mock/call_monitor.h'
> --- tests/mock/call_monitor.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/call_monitor.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_CALL_MONITOR_H_
> +#define MOCK_CALL_MONITOR_H_
> +
> +#include <core/media/telephony/call_monitor.h>
> +
> +struct MockCallMonitor : public core::ubuntu::media::telephony::CallMonitor
> +{
> +    MockCallMonitor()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, on_call_state_changed())
> +                .WillByDefault(ReturnRef(signals.on_call_state_changed));
> +    }
> +
> +    MOCK_CONST_METHOD0(on_call_state_changed, const core::Signal<core::ubuntu::media::telephony::CallMonitor::State>&());
> +
> +    struct
> +    {
> +        core::Signal<core::ubuntu::media::telephony::CallMonitor::State> on_call_state_changed;
> +    } signals;
> +};
> +
> +#endif // MOCK_CALL_MONITOR_H_
> 
> === added file 'tests/mock/client_death_observer.h'
> --- tests/mock/client_death_observer.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/client_death_observer.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_CLIENT_DEATH_OBSERVER_H_
> +#define MOCK_CLIENT_DEATH_OBSERVER_H_
> +
> +#include <core/media/client_death_observer.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct MockClientDeathObserver : public core::ubuntu::media::ClientDeathObserver
> +{
> +    MockClientDeathObserver()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, on_client_with_key_died())
> +                .WillByDefault(ReturnRef(signals.on_client_with_key_died));
> +    }
> +
> +    // Registers the client with the given key for death notifications.
> +    MOCK_METHOD1(register_for_death_notifications_with_key, void(const core::ubuntu::media::Player::PlayerKey&));
> +    // Emitted whenver a client dies, reporting the key under which the
> +    // respective client was known.
> +    MOCK_CONST_METHOD0(on_client_with_key_died, const core::Signal<core::ubuntu::media::Player::PlayerKey>&());
> +
> +    struct
> +    {
> +        core::Signal<core::ubuntu::media::Player::PlayerKey> on_client_with_key_died;
> +    } signals;
> +};
> +
> +#endif // MOCK_CLIENT_DEATH_OBSERVER_H_
> 
> === added file 'tests/mock/engine.h'
> --- tests/mock/engine.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/engine.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,231 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_ENGINE_H_
> +#define MOCK_ENGINE_H_
> +
> +#include <core/media/engine.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <chrono>
> +
> +struct MockEngine : public core::ubuntu::media::Engine
> +{
> +    MockEngine()
> +    {
> +        using namespace ::testing;
> +
> +        mutable_is_audio_source().install([this]() -> bool
> +        {
> +            return read_is_audio();
> +        });
> +
> +        mutable_is_video_source().install([this]() -> bool
> +        {
> +            return read_is_video();
> +        });
> +
> +        mutable_duration().install([this]() -> std::uint64_t
> +        {
> +            return read_duration();
> +        });
> +
> +        ON_CALL(*this, reset())
> +                .WillByDefault(Invoke(this, &MockEngine::do_reset));
> +    }
> +
> +    MOCK_METHOD0(read_duration, std::uint64_t());
> +    MOCK_METHOD0(read_is_audio, bool());
> +    MOCK_METHOD0(read_is_video, bool());
> +
> +    // Mutable properties for testing purposes go here.
> +    // Pull out to make accessible to test cases.
> +    core::Property<State>& mutable_state()
> +    {
> +        return properties.state;
> +    }
> +
> +    core::Property<bool>& mutable_is_audio_source()
> +    {
> +        return properties.is_audio_source;
> +    }
> +
> +    core::Property<bool>& mutable_is_video_source()
> +    {
> +        return properties.is_video_source;
> +    }
> +
> +    core::Property<uint64_t>& mutable_duration()
> +    {
> +        return properties.duration;
> +    }
> +
> +    core::Signal<void>& mutable_client_disconnected_signal()
> +    {
> +        return sigs.client_disconnected;
> +    }
> +
> +    // Properties and signals of the base class go here.
> +    const core::Property<State>& state() const
> +    {
> +        return properties.state;
> +    }
> +
> +    const core::Property<bool>& is_video_source() const
> +    {
> +        return properties.is_video_source;
> +    }
> +
> +    const core::Property<bool>& is_audio_source() const
> +    {
> +        return properties.is_audio_source;
> +    }
> +
> +    const core::Property<uint64_t>& position() const
> +    {
> +        return properties.position;
> +    }
> +
> +    const core::Property<uint64_t>& duration() const
> +    {
> +        return properties.duration;
> +    }
> +
> +    const core::Property<Volume>& volume() const
> +    {
> +        return properties.volume;
> +    }
> +
> +    core::Property<Volume>& volume()
> +    {
> +        return properties.volume;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::AudioStreamRole>& audio_stream_role() const
> +    {
> +        return properties.audio_stream_role;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::AudioStreamRole>& audio_stream_role()
> +    {
> +        return properties.audio_stream_role;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::Orientation>& orientation() const
> +    {
> +        return properties.orientation;
> +    }
> +
> +    const core::Property<core::ubuntu::media::Player::Lifetime>& lifetime() const
> +    {
> +        return properties.lifetime;
> +    }
> +
> +    core::Property<core::ubuntu::media::Player::Lifetime>& lifetime()
> +    {
> +        return properties.lifetime;
> +    }
> +
> +    const core::Property<std::tuple<core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData>>& track_meta_data() const
> +    {
> +        return properties.track_meta_data;
> +    }
> +
> +    const core::Signal<void>& about_to_finish_signal() const
> +    {
> +        return sigs.about_to_finish;
> +    }
> +
> +    const core::Signal<uint64_t>& seeked_to_signal() const
> +    {
> +        return sigs.seeked_to;
> +    }
> +
> +    const core::Signal<void>& client_disconnected_signal() const
> +    {
> +        return sigs.client_disconnected;
> +    }
> +
> +    const core::Signal<void>& end_of_stream_signal() const
> +    {
> +        return sigs.end_of_stream;
> +    }
> +
> +    const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const
> +    {
> +        return sigs.playback_status_changed;
> +    }
> +
> +    const core::Signal<core::ubuntu::media::video::Dimensions>& video_dimension_changed_signal() const
> +    {
> +        return sigs.video_dimension_changed;
> +    }
> +
> +    const core::Signal<core::ubuntu::media::Player::Error>& error_signal() const
> +    {
> +        return sigs.error;
> +    }
> +
> +    // Dependency resolving
> +    MOCK_CONST_METHOD0(meta_data_extractor, const std::shared_ptr<core::ubuntu::media::Engine::MetaDataExtractor>&());
> +    // Functional part of the interface.
> +    MOCK_METHOD2(open_resource_for_uri, bool(const core::ubuntu::media::Track::UriType&, const core::ubuntu::media::Player::HeadersType&));
> +    MOCK_METHOD1(open_resource_for_uri, bool(const core::ubuntu::media::Track::UriType&));
> +    MOCK_METHOD1(create_video_sink, void(uint32_t));
> +    MOCK_METHOD0(play, bool());
> +    MOCK_METHOD0(stop, bool());
> +    MOCK_METHOD0(pause, bool());
> +    MOCK_METHOD1(seek_to, bool(const std::chrono::microseconds&));
> +    MOCK_METHOD0(reset, void());
> +
> +    void do_reset()
> +    {
> +        // This is ugly and relies on implementation-specific behavior.
> +        // We should refactor PlayerImplementation to manually emit the
> +        // signal.
> +        mutable_client_disconnected_signal();
> +    }
> +
> +    struct
> +    {
> +        core::Property<core::ubuntu::media::Engine::State> state;
> +        core::Property<bool> is_video_source;
> +        core::Property<bool> is_audio_source;
> +        core::Property<uint64_t> position;
> +        core::Property<uint64_t> duration;
> +        core::Property<Volume> volume;
> +        core::Property<core::ubuntu::media::Player::AudioStreamRole> audio_stream_role;
> +        core::Property<core::ubuntu::media::Player::Orientation> orientation;
> +        core::Property<core::ubuntu::media::Player::Lifetime> lifetime;
> +        core::Property<std::tuple<core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData>> track_meta_data;
> +    } properties;
> +
> +    struct
> +    {
> +        core::Signal<void> about_to_finish;
> +        core::Signal<uint64_t> seeked_to;
> +        core::Signal<void> client_disconnected;
> +        core::Signal<void> end_of_stream;
> +        core::Signal<core::ubuntu::media::Player::PlaybackStatus> playback_status_changed;
> +        core::Signal<core::ubuntu::media::video::Dimensions> video_dimension_changed;
> +        core::Signal<core::ubuntu::media::Player::Error> error;
> +    } sigs;
> +};
> +
> +#endif // MOCK_ENGINE_H_
> 
> === added file 'tests/mock/engine_factory.h'
> --- tests/mock/engine_factory.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/engine_factory.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_ENGINE_FACTORY_H_
> +#define MOCK_ENGINE_FACTORY_H_
> +
> +#include "engine.h"
> +
> +#include <gmock/gmock.h>
> +
> +struct MockEngineFactory : public std::enable_shared_from_this<MockEngineFactory>
> +{
> +    MockEngineFactory()
> +    {
> +        using namespace ::testing;
> +        ON_CALL(*this, make_engine())
> +                .WillByDefault(Return(std::make_shared<MockEngine>()));
> +    }
> +
> +    std::function<std::shared_ptr<core::ubuntu::media::Engine>()> to_engine_factory()
> +    {
> +        auto sp = shared_from_this();
> +        return [sp]()
> +        {
> +            return sp->make_engine();
> +        };
> +    }
> +
> +    MOCK_METHOD0(make_engine, std::shared_ptr<core::ubuntu::media::Engine>());
> +};
> +
> +#endif // MOCK_ENGINE_FACTORY_H_
> 
> === added file 'tests/mock/keyed_player_store.h'
> --- tests/mock/keyed_player_store.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/keyed_player_store.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_KEYED_PLAYER_STORE_H_
> +#define MOCK_KEYED_PLAYER_STORE_H_
> +
> +#include <core/media/keyed_player_store.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct MockKeyedPlayerStore : public core::ubuntu::media::KeyedPlayerStore
> +{
> +    // Save us some typing.
> +    typedef std::shared_ptr<MockKeyedPlayerStore> Ptr;
> +
> +    MockKeyedPlayerStore()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, current_player())
> +                .WillByDefault(ReturnRef(properties.current_player));
> +        ON_CALL(*this, enumerate_players(_))
> +                .WillByDefault(Invoke(this, &MockKeyedPlayerStore::do_enumerate));
> +        ON_CALL(*this, player_for_key(_))
> +                .WillByDefault(Invoke(this, &MockKeyedPlayerStore::do_player_for_key));
> +        ON_CALL(*this, has_player_for_key(_))
> +                .WillByDefault(Invoke(this, &MockKeyedPlayerStore::do_has_player_for_key));
> +    }
> +
> +    MOCK_CONST_METHOD0(current_player, const core::Property<std::shared_ptr<core::ubuntu::media::Player>>&());
> +    MOCK_CONST_METHOD1(has_player_for_key, bool(const core::ubuntu::media::Player::PlayerKey& key));
> +    MOCK_CONST_METHOD1(player_for_key, std::shared_ptr<core::ubuntu::media::Player>(const core::ubuntu::media::Player::PlayerKey&));
> +    MOCK_CONST_METHOD1(enumerate_players, void(const core::ubuntu::media::KeyedPlayerStore::PlayerEnumerator&));
> +    MOCK_METHOD2(add_player_for_key, void(const core::ubuntu::media::Player::PlayerKey&, const std::shared_ptr<core::ubuntu::media::Player>&));
> +    MOCK_METHOD1(remove_player_for_key, void(const core::ubuntu::media::Player::PlayerKey&));
> +    MOCK_METHOD1(set_current_player_for_key, void(const core::ubuntu::media::Player::PlayerKey&));
> +
> +    void do_enumerate(PlayerEnumerator enumerator) const
> +    {
> +        for (const auto& pair : properties.map)
> +            enumerator(pair.first, pair.second);
> +    }
> +
> +    std::shared_ptr<core::ubuntu::media::Player> do_player_for_key(const core::ubuntu::media::Player::PlayerKey& key)
> +    {
> +        return properties.map.at(key);
> +    }
> +
> +    bool do_has_player_for_key(const core::ubuntu::media::Player::PlayerKey& key)
> +    {
> +        return properties.map.count(key) > 0;
> +    }
> +
> +    struct
> +    {
> +        std::map<core::ubuntu::media::Player::PlayerKey, std::shared_ptr<core::ubuntu::media::Player>> map;
> +        core::Property<std::shared_ptr<core::ubuntu::media::Player>> current_player;
> +    } properties;
> +};
> +
> +#endif // MOCK_KEYED_PLAYER_STORE_H_
> 
> === added file 'tests/mock/media_service.h'
> --- tests/mock/media_service.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/media_service.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,37 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_MEDIA_SERVICE_H_
> +#define MOCK_MEDIA_SERVICE_H_
> +
> +#include <core/media/service.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <memory>
> +
> +struct MockMediaService : public core::ubuntu::media::Service
> +{
> +    MockMediaService() = default;
> +
> +    MOCK_METHOD1(create_session, std::shared_ptr<core::ubuntu::media::Player>(const core::ubuntu::media::Player::Configuration&));
> +    MOCK_METHOD2(create_fixed_session, std::shared_ptr<core::ubuntu::media::Player>(const std::string&, const core::ubuntu::media::Player::Configuration&));
> +    MOCK_METHOD1(resume_session, std::shared_ptr<core::ubuntu::media::Player>(const core::ubuntu::media::Player::PlayerKey));
> +    MOCK_METHOD1(pause_other_sessions, void(core::ubuntu::media::Player::PlayerKey));
> +};
> +#endif // MOCK_MEDIA_SERVICE_H_
> 
> === added file 'tests/mock/player.h'
> --- tests/mock/player.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/player.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_PLAYER_H_
> +#define MOCK_PLAYER_H_
> +
> +#include <core/media/engine.h>
> +#include <core/media/player_base.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <chrono>
> +
> +template<typename Parent>
> +struct MockPlayer : public Parent
> +{
> +    struct Configuration { typename Parent::Configuration parent; };
> +
> +    MockPlayer(const Configuration& config = Configuration{}) : Parent{config.parent}
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, track_list())
> +                .WillByDefault(Return(std::shared_ptr<core::ubuntu::media::TrackList>{}));
> +        ON_CALL(*this, key())
> +                .WillByDefault(Return(std::numeric_limits<core::ubuntu::media::Player::PlayerKey>::max()));
> +        ON_CALL(*this, create_gl_texture_video_sink(_))
> +                .WillByDefault(Return(core::ubuntu::media::video::Sink::Ptr{}));
> +    }
> +
> +    // Functional part of the interface
> +    MOCK_METHOD0(track_list, std::shared_ptr<core::ubuntu::media::TrackList>());
> +    MOCK_CONST_METHOD0(key, core::ubuntu::media::Player::PlayerKey());
> +    MOCK_METHOD1(create_gl_texture_video_sink, core::ubuntu::media::video::Sink::Ptr(std::uint32_t));
> +
> +    MOCK_METHOD1(open_uri, bool(const core::ubuntu::media::Track::UriType&));
> +    MOCK_METHOD2(open_uri, bool(const core::ubuntu::media::Track::UriType&, const core::ubuntu::media::Player::HeadersType&));
> +    MOCK_METHOD0(next, void());
> +    MOCK_METHOD0(previous, void());
> +    MOCK_METHOD0(play, void());
> +    MOCK_METHOD0(pause, void());
> +    MOCK_METHOD0(stop, void());
> +    MOCK_METHOD1(seek_to, void(const std::chrono::microseconds&));
> +};
> +
> +// Provide a version of the MockPlayer that has a useful key instead of
> +// only having one static value for all instances.
> +template<typename Parent>
> +struct KeyedMockPlayer : public MockPlayer<Parent>
> +{
> +    using MockPlayer<Parent>::Configuration;
> +
> +    KeyedMockPlayer()
> +    {
> +        using namespace ::testing;
> +        static unsigned int the_key = 0;
> +        ON_CALL(*this, key()).WillByDefault(Return(the_key++));
> +    }
> +};
> +
> +#endif // MOCK_PLAYER_H_
> 
> === added file 'tests/mock/power_state_controller.h'
> --- tests/mock/power_state_controller.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/power_state_controller.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,127 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_POWER_STATE_CONTROLLER_H
> +#define MOCK_POWER_STATE_CONTROLLER_H
> +
> +#include <core/media/power/state_controller.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct MockPowerStateController : public core::ubuntu::media::power::StateController
> +{
> +    // We really would like to use a templated approach here. However, Google Mock lacks
> +    // a typename and the resulting error message for resolving the result type is:
> +    //   player_implementation_test.cpp:70:9: error: need 'typename' before 'testing::internal::Function<void(State)>::Result' because 'testing::internal::Function<void(State)>' is a dependent scope
> +    //   MOCK_METHOD1(request_acquire, void(State));
> +    // With that, just replicate the class.
> +    struct DisplayStateLock : public core::ubuntu::media::power::StateController::Lock<core::ubuntu::media::power::DisplayState>
> +    {
> +        // Save us some typing here.
> +        typedef std::shared_ptr<MockPowerStateController::DisplayStateLock> Ptr;
> +
> +        DisplayStateLock()
> +        {
> +            using namespace ::testing;
> +
> +            ON_CALL(*this, acquired())
> +                    .WillByDefault(ReturnRef(signals.acquired));
> +            ON_CALL(*this, released())
> +                    .WillByDefault(ReturnRef(signals.released));
> +        }
> +
> +        // Informs the system that the caller would like
> +        // the system to stay active.
> +        MOCK_METHOD1(request_acquire, void(core::ubuntu::media::power::DisplayState));
> +        // Informs the system that the caller does not
> +        // require the system to stay active anymore.
> +        MOCK_METHOD1(request_release, void(core::ubuntu::media::power::DisplayState));
> +
> +        // Emitted whenever the acquire request completes.
> +        MOCK_CONST_METHOD0(acquired, const core::Signal<core::ubuntu::media::power::DisplayState>&());
> +        // Emitted whenever the release request completes.
> +        MOCK_CONST_METHOD0(released, const core::Signal<core::ubuntu::media::power::DisplayState>&());
> +
> +        struct
> +        {
> +            core::Signal<core::ubuntu::media::power::DisplayState> acquired;
> +            core::Signal<core::ubuntu::media::power::DisplayState> released;
> +        } signals;
> +    };
> +
> +    struct SystemStateLock : public core::ubuntu::media::power::StateController::Lock<core::ubuntu::media::power::SystemState>
> +    {
> +        // Save us some typing here.
> +        typedef std::shared_ptr<MockPowerStateController::SystemStateLock> Ptr;
> +
> +        SystemStateLock()
> +        {
> +            using namespace ::testing;
> +
> +            ON_CALL(*this, acquired())
> +                    .WillByDefault(ReturnRef(signals.acquired));
> +            ON_CALL(*this, released())
> +                    .WillByDefault(ReturnRef(signals.released));
> +        }
> +
> +        // Informs the system that the caller would like
> +        // the system to stay active.
> +        MOCK_METHOD1(request_acquire, void(core::ubuntu::media::power::SystemState));
> +        // Informs the system that the caller does not
> +        // require the system to stay active anymore.
> +        MOCK_METHOD1(request_release, void(core::ubuntu::media::power::SystemState));
> +
> +        // Emitted whenever the acquire request completes.
> +        MOCK_CONST_METHOD0(acquired, const core::Signal<core::ubuntu::media::power::SystemState>&());
> +        // Emitted whenever the release request completes.
> +        MOCK_CONST_METHOD0(released, const core::Signal<core::ubuntu::media::power::SystemState>&());
> +
> +        struct
> +        {
> +            core::Signal<core::ubuntu::media::power::SystemState> acquired;
> +            core::Signal<core::ubuntu::media::power::SystemState> released;
> +        } signals;
> +    };
> +
> +    MockPowerStateController()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, display_state_lock())
> +                .WillByDefault(Return(display_lock));
> +        ON_CALL(*this, system_state_lock())
> +                .WillByDefault(Return(system_lock));
> +    }
> +
> +    // Returns a power::StateController::Lock<DisplayState> instance.
> +    MOCK_METHOD0(display_state_lock, Lock<core::ubuntu::media::power::DisplayState>::Ptr());
> +    // Returns a power::StateController::Lock<SystemState> instance.
> +    MOCK_METHOD0(system_state_lock, Lock<core::ubuntu::media::power::SystemState>::Ptr());
> +
> +    DisplayStateLock::Ptr display_lock
> +    {
> +        new testing::NiceMock<DisplayStateLock>{}
> +    };
> +
> +    SystemStateLock::Ptr system_lock
> +    {
> +        new testing::NiceMock<SystemStateLock>{}
> +    };
> +};
> +
> +#endif // MOCK_POWER_STATE_CONTROLLER_H
> 
> === added file 'tests/mock/recorder_observer.h'
> --- tests/mock/recorder_observer.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/recorder_observer.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,43 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_RECORDER_OBSERVER_H_
> +#define MOCK_RECORDER_OBSERVER_H_
> +
> +#include <core/media/recorder_observer.h>
> +
> +struct MockRecorderObserver : public core::ubuntu::media::RecorderObserver
> +{
> +    MockRecorderObserver()
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, recording_state())
> +                .WillByDefault(ReturnRef(properties.recording_state));
> +    }
> +
> +    // Getable/observable property describing the recording state of the system.
> +    MOCK_CONST_METHOD0(recording_state, const core::Property<core::ubuntu::media::RecordingState>&());
> +
> +    struct
> +    {
> +        core::Property<core::ubuntu::media::RecordingState> recording_state;
> +    } properties;
> +};
> +
> +#endif // MOCK_RECORDER_OBSERVER_H_
> 
> === added file 'tests/mock/request_authenticator.h'
> --- tests/mock/request_authenticator.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/request_authenticator.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_REQUEST_AUTHENTICATOR_H_
> +#define MOCK_REQUEST_AUTHENTICATOR_H_
> +
> +#include <core/media/apparmor/ubuntu.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <string>
> +
> +struct MockRequestAuthenticator : public core::ubuntu::media::apparmor::ubuntu::RequestAuthenticator
> +{
> +    typedef std::shared_ptr<MockRequestAuthenticator> Ptr;
> +
> +    MockRequestAuthenticator()
> +    {
> +        using namespace ::testing;
> +        ON_CALL(*this, authenticate_open_uri_request(_, _))
> +                .WillByDefault(Return(Result{false, ""}));
> +    }
> +
> +    MOCK_METHOD2(authenticate_open_uri_request, Result(const core::ubuntu::media::apparmor::ubuntu::Context&, const std::string&));
> +};
> +
> +#endif // MOCK_REQUEST_AUTHENTICATOR_H_
> 
> === added file 'tests/mock/request_context_resolver.h'
> --- tests/mock/request_context_resolver.h	1970-01-01 00:00:00 +0000
> +++ tests/mock/request_context_resolver.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#ifndef MOCK_REQUEST_CONTEXT_RESOLVER_H_
> +#define MOCK_REQUEST_CONTEXT_RESOLVER_H_
> +
> +#include <core/media/apparmor/ubuntu.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <string>
> +
> +struct MockRequestContextResolver: public core::ubuntu::media::apparmor::ubuntu::RequestContextResolver
> +{
> +    typedef std::shared_ptr<MockRequestContextResolver> Ptr;
> +
> +    MockRequestContextResolver()
> +    {
> +        using namespace ::testing;
> +        ON_CALL(*this, resolve_context_for_dbus_name_async(_,_))
> +                .WillByDefault(Invoke(this, &MockRequestContextResolver::do_resolve));
> +    }
> +
> +    MOCK_METHOD2(resolve_context_for_dbus_name_async, void(const std::string&, core::ubuntu::media::apparmor::ubuntu::RequestContextResolver::ResolveCallback));
> +
> +    void do_resolve(const std::string&, core::ubuntu::media::apparmor::ubuntu::RequestContextResolver::ResolveCallback cb)
> +    {
> +        cb(core::ubuntu::media::apparmor::ubuntu::Context{"unconfined"});
> +    }
> +};
> +
> +#endif // MOCK_REQUEST_AUTHENTICATOR_H_
> 
> === modified file 'tests/test-video.ogg'
> Binary files tests/test-video.ogg	2015-03-03 22:41:22 +0000 and tests/test-video.ogg	2015-04-17 14:35:22 +0000 differ
> === modified file 'tests/test_data.cpp.in'
> --- tests/test_data.cpp.in	2015-03-03 22:41:22 +0000
> +++ tests/test_data.cpp.in	2015-04-17 14:35:22 +0000
> @@ -22,7 +22,7 @@
>  
>  bool test::copy_test_media_file_to(const std::string& media, const std::string& dest)
>  {
> -    static const std::string file{"@CMAKE_CURRENT_SOURCE_DIR@/" + media};
> +    const std::string file{"@CMAKE_CURRENT_SOURCE_DIR@/" + media};
>  
>      try
>      {
> 
> === added directory 'tests/tools'
> === added file 'tests/tools/a_trap_stopping_itself.h'
> --- tests/tools/a_trap_stopping_itself.h	1970-01-01 00:00:00 +0000
> +++ tests/tools/a_trap_stopping_itself.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef TOOLS_A_TRAP_STOPPING_ITSELF_H_
> +#define TOOLS_A_TRAP_STOPPING_ITSELF_H_
> +
> +#include <core/posix/signal.h>
> +
> +namespace tools
> +{
> +// A helper creating a signal trap that stops itself
> +std::shared_ptr<core::posix::SignalTrap> a_trap_stopping_itself()
> +{
> +    auto trap = core::posix::trap_signals_for_all_subsequent_threads(
> +    {
> +        core::posix::Signal::sig_int, core::posix::Signal::sig_term
> +    });
> +
> +    trap->signal_raised().connect([trap](core::posix::Signal)
> +    {
> +        trap->stop();
> +    });
> +
> +    return trap;
> +}
> +}
> +
> +#endif // TOOLS_A_TRAP_STOPPING_ITSELF_H_
> 
> === added file 'tests/tools/did_finish_successfully.h'
> --- tests/tools/did_finish_successfully.h	1970-01-01 00:00:00 +0000
> +++ tests/tools/did_finish_successfully.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef TOOLS_DID_FINISH_SUCCESSFULLY_H_
> +#define TOOLS_DID_FINISH_SUCCESSFULLY_H_
> +
> +#include <core/posix/wait.h>
> +
> +#include <gtest/gtest.h>
> +
> +namespace tools
> +{
> +// Custom predicate to help asserting that a child process in a test finished successfully.
> +::testing::AssertionResult did_finish_successfully(const core::posix::wait::Result& result)
> +{
> +    if (result.status != core::posix::wait::Result::Status::exited)
> +        return ::testing::AssertionFailure() << "Process did not exit, but: " << (int)result.status;
> +    if (result.detail.if_exited.status != core::posix::exit::Status::success)
> +        return ::testing::AssertionFailure() << "Process did exit with failure.";
> +
> +    return ::testing::AssertionSuccess();
> +}
> +}
> +
> +#endif // TOOLS_DID_FINISH_SUCCESSFULLY_H_
> 
> === added file 'tests/tools/event_sink.h'
> --- tests/tools/event_sink.h	1970-01-01 00:00:00 +0000
> +++ tests/tools/event_sink.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,145 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef TOOLS_EVENT_SINK_H_
> +#define TOOLS_EVENT_SINK_H_
> +
> +#include <core/property.h>
> +#include <core/signal.h>
> +
> +#include <gmock/gmock.h>
> +
> +#include <atomic>
> +#include <condition_variable>
> +#include <mutex>
> +
> +namespace tools
> +{
> +// A helper to track changed signal emissions on properties.
> +template<typename T>
> +struct EventSink
> +{
> +    typedef T Expected;
> +    typedef std::size_t Cardinality;
> +
> +    EventSink(const core::Signal<T>& sig, Cardinality cardinality = Cardinality{1})
> +        : expected_cardinality{cardinality},
> +          events_received{0},
> +          event_connection
> +          {
> +              sig.connect([this](const T& value)
> +              {
> +                  on_new_event(value);
> +              })
> +          }
> +    {
> +        using namespace ::testing;
> +        ON_CALL(*this, on_new_event(_)).WillByDefault(InvokeWithoutArgs(this, &EventSink<T>::notify_all));
> +    }
> +
> +    EventSink(const core::Property<T>& property, Cardinality cardinality = Cardinality{1})
> +        : EventSink{property.changed(), cardinality}
> +    {
> +    }
> +
> +    void notify_all()
> +    {
> +        events_received++;
> +        wait_condition.notify_all();
> +    }
> +
> +    bool wait_for_event_for(const std::chrono::milliseconds& ms)
> +    {
> +        if (events_received >= expected_cardinality)
> +            return true;
> +
> +        std::unique_lock<std::mutex> ul{wait_guard};
> +        return wait_condition.wait_for(ul, ms, [this]() {return events_received >= expected_cardinality;});
> +    }
> +
> +    // Invoked for every changed signal emission.
> +    MOCK_METHOD1_T(on_new_event, void(const T&));
> +
> +    // Expected Cardinality.
> +    Cardinality expected_cardinality;
> +    // Initially 0, incremented for every event
> +    std::atomic<std::uint32_t> events_received;
> +    // We keep track of the event connection here.
> +    // On destruction, the connection is automatically cut.
> +    core::ScopedConnection event_connection;
> +    // We use a condition variable to allow clients to synchronize
> +    // to events.
> +    std::mutex wait_guard;
> +    std::condition_variable wait_condition;
> +};
> +// And a void overload
> +template<>
> +struct EventSink<void>
> +{
> +    typedef std::size_t Cardinality;
> +
> +    EventSink(const core::Signal<void>& sig, Cardinality cardinality = Cardinality{1})
> +        : expected_cardinality{cardinality},
> +          events_received{0},
> +          event_connection
> +          {
> +              sig.connect([this]()
> +              {
> +                  on_new_event();
> +              })
> +          }
> +    {
> +        using namespace ::testing;
> +
> +        ON_CALL(*this, on_new_event())
> +                .WillByDefault(InvokeWithoutArgs(this, &EventSink<void>::notify_all));
> +    }
> +
> +    // Notify all waiting clients
> +    void notify_all()
> +    {
> +        events_received++;
> +        wait_condition.notify_all();
> +    }
> +
> +    // Wait for an event to happen for at most ms milliseconds.
> +    bool wait_for_event_for(const std::chrono::milliseconds& ms)
> +    {
> +        if (events_received >= expected_cardinality)
> +            return true;
> +
> +        std::unique_lock<std::mutex> ul{wait_guard};
> +        return wait_condition.wait_for(ul, ms, [this]() {return events_received >= expected_cardinality;});
> +    }
> +
> +    // Invoked for every changed signal emission.
> +    MOCK_METHOD0_T(on_new_event, void());
> +
> +    // Expected Cardinality.
> +    Cardinality expected_cardinality;
> +    // Initially 0, incremented for every event
> +    std::atomic<std::uint32_t> events_received;
> +    // We keep track of the event connection here.
> +    // On destruction, the connection is automatically cut.
> +    core::ScopedConnection event_connection;
> +    // We use a condition variable to allow clients to synchronize
> +    // to events.
> +    std::mutex wait_guard;
> +    std::condition_variable wait_condition;
> +};
> +}
> +#endif // TOOLS_EVENT_SINK_H_
> 
> === added file 'tests/tools/gdb_barrier.h'
> --- tests/tools/gdb_barrier.h	1970-01-01 00:00:00 +0000
> +++ tests/tools/gdb_barrier.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef TOOLS_GDB_BARRIER_H_
> +#define TOOLS_GDB_BARRIER_H_
> +
> +#include <core/posix/this_process.h>
> +
> +#include <chrono>
> +#include <string>
> +#include <thread>
> +
> +namespace tools
> +{
> +struct GdbBarrier
> +{
> +    static constexpr const char* env_key{"MEDIA_HUB_GDB_BARRIER_ENABLE"};
> +    static constexpr const char* enable{"1"};
> +    static constexpr const char* disable{"0"};
> +
> +    GdbBarrier(const std::string& name)
> +    {
> +        if (core::posix::this_process::env::get(env_key, "0") == enable)
> +        {
> +            std::cout << "GdbBarrier for " << name << ": sudo gdb -p " << ::getpid() << std::endl;
> +            std::this_thread::sleep_for(std::chrono::seconds{10});
> +        }
> +    }
> +};
> +
> +void wait_for_user_to_attach_with_gdb_if_enabled(const std::string& name)
> +{
> +    GdbBarrier{name};
> +}
> +}
> +
> +#endif // TOOLS_GDB_BARRIER_H_
> +
> 
> === added file 'tests/tools/gles_egl_helper.h'
> --- tests/tools/gles_egl_helper.h	1970-01-01 00:00:00 +0000
> +++ tests/tools/gles_egl_helper.h	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,187 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +#ifndef TOOLS_GLES_EGL_HELPER_H_
> +#define TOOLS_GLES_EGL_HELPER_H_
> +
> +#include <functional>
> +#include <stdexcept>
> +#include <string>
> +
> +#include <EGL/egl.h>
> +#include <GLES2/gl2.h>
> +
> +namespace tools
> +{
> +namespace egl
> +{
> +// We wrap egl calls to ease error reporting
> +struct Error : public std::runtime_error
> +{
> +    Error(const std::string& what)
> +        : std::runtime_error{what},
> +          error{eglGetError()}
> +    {
> +    }
> +
> +    EGLint error;
> +};
> +
> +// An egl resource wrapper that throws if constructed with an
> +// invalid value.
> +template<typename T, T invalid>
> +class Resource
> +{
> +public:
> +
> +    static Resource empty()
> +    {
> +        return Resource{};
> +    }
> +
> +    explicit Resource(T value) : value{value}
> +    {
> +        if (value == invalid) throw egl::Error
> +        {
> +            __PRETTY_FUNCTION__ + std::string{" was given an invalid raw resource."}
> +        };
> +    }
> +
> +    operator T() const
> +    {
> +        return value;
> +    }
> +
> +private:
> +    Resource() : value{invalid}
> +    {
> +    }
> +
> +    // The raw EGL value.
> +    T value;
> +};
> +
> +typedef Resource<EGLConfig, nullptr> Config;
> +typedef Resource<EGLContext, EGL_NO_CONTEXT> Context;
> +typedef Resource<EGLDisplay, EGL_NO_DISPLAY> Display;
> +typedef Resource<EGLSurface, EGL_NO_SURFACE> Surface;
> +
> +// The version tuple (major, minor) describing the EGL version.
> +typedef std::tuple<EGLint, EGLint> Version;
> +
> +// Initializes the egl implementation for the given display
> +// or throws an egl::Error.
> +Version must_initialize(Display display)
> +{
> +    Version result{-1, -1};
> +    if (EGL_FALSE == eglInitialize(display, &std::get<0>(result), &std::get<1>(result)))
> +        throw egl::Error{"Could not initialize EGL."};
> +
> +    return result;
> +}
> +
> +// Chooses a config for the given display, satisfying the given
> +// attribute list. Throws egl::Error in case of issues.
> +Config must_choose_config(Display display, const EGLint *attrib_list)
> +{
> +    EGLConfig config{nullptr};
> +    if (EGL_FALSE == eglChooseConfig(display, attrib_list, &config, 1, nullptr))
> +        throw egl::Error{"Could not choose appropriate EGLConfig."};
> +    return Config{config};
> +}
> +
> +// Creates an EGL context for the given display, with the given context
> +// sharing with shared. Throws egl::Error in case of issues.
> +Context must_create_context(Display display, Config config, Context shared, const EGLint* attribute_list)
> +{
> +    return Context{eglCreateContext(display, config, shared, attribute_list)};
> +}
> +
> +// Creates a window surface for the given display, config and native window.
> +// Throws egl::Error in case of issues.
> +Surface must_create_window_surface(Display display, Config config, EGLNativeWindowType win, const EGLint *attribute_list)
> +{
> +    return Surface{eglCreateWindowSurface(display, config, win, attribute_list)};
> +}
> +
> +// Makes the given EGL context current or throws egl::Error.
> +void must_make_current(Display display, Surface draw, Surface read, Context context)
> +{
> +    if (EGL_FALSE == eglMakeCurrent(display, draw, read, context))
> +        throw egl::Error{"Could not make context with surfaces current."};
> +}
> +
> +static constexpr const EGLint config_attributes[]
> +{
> +    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
> +    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
> +    EGL_NONE
> +};
> +
> +static constexpr const EGLint context_attributes[]
> +{
> +    EGL_CONTEXT_CLIENT_VERSION, 2,
> +    EGL_NONE
> +};
> +
> +struct Helper
> +{
> +    Helper(EGLNativeWindowType window)
> +        : egl_display{eglGetDisplay(EGL_DEFAULT_DISPLAY)},
> +          egl_version{egl::must_initialize(egl_display)},
> +          egl_config{egl::must_choose_config(egl_display, config_attributes)},
> +          egl_context{egl::must_create_context(egl_display, egl_config, egl::Context::empty(), context_attributes)},
> +          egl_surface{egl::must_create_window_surface(egl_display, egl_config, window, nullptr)}
> +    {
> +        egl::must_make_current(egl_display, egl_surface, egl_surface, egl_context);
> +    }
> +
> +    void make_current()
> +    {
> +        egl::must_make_current(egl_display, egl_surface, egl_surface, egl_context);
> +    }
> +
> +    egl::Display egl_display;
> +    egl::Version egl_version;
> +    egl::Config egl_config;
> +    egl::Context egl_context;
> +    egl::Surface egl_surface;
> +};
> +}
> +
> +namespace glesv2
> +{
> +struct Helper
> +{
> +    Helper(EGLNativeWindowType window) : egl{window}
> +    {
> +    }
> +
> +    GLuint gen_texture()
> +    {
> +        egl.make_current();
> +        GLuint texture{std::numeric_limits<GLuint>::max()};
> +        glGenTextures(1, &texture);
> +        return texture;
> +    }
> +
> +    egl::Helper egl;
> +};
> +}
> +}
> +
> +#endif // TOOLS_GL_VIEW_H_
> 
> === modified file 'tests/unit-tests/CMakeLists.txt'
> --- tests/unit-tests/CMakeLists.txt	2014-12-09 16:00:00 +0000
> +++ tests/unit-tests/CMakeLists.txt	2015-04-17 14:35:22 +0000
> @@ -1,46 +1,4 @@
> -include_directories(
> -    .
> -    ${CMAKE_SOURCE_DIR}/src
> -    ${PC_GSTREAMER_1_0_INCLUDE_DIRS}
> -)
> -
> -add_library(mongoose mongoose.c)
> -set_target_properties(
> -    mongoose
> -    PROPERTIES COMPILE_FLAGS "-std=c99")
> -
> -add_executable(
> -    test-gstreamer-engine
> -
> -    libmedia-mock.cpp
> -    test-gstreamer-engine.cpp
> -)
> -
> -target_link_libraries(
> -    test-gstreamer-engine
> -
> -    media-hub-common
> -    media-hub-client
> -    media-hub-service
> -    call-monitor
> -    media-hub-test-framework
> -
> -    ${CMAKE_THREAD_LIBS_INIT}
> -    ${Boost_LIBRARIES}
> -    ${DBUS_LIBRARIES}
> -    ${DBUS_CPP_LDFLAGS}
> -    ${GLog_LIBRARY}
> -    ${PC_GSTREAMER_1_0_LIBRARIES}
> -    ${PROCESS_CPP_LDFLAGS}
> -    ${GIO_LIBRARIES}
> -    ${PROCESS_CPP_LIBRARIES}
> -    ${PC_PULSE_AUDIO_LIBRARIES}
> -
> -    gmock
> -    gmock_main
> -    gtest
> -
> -    mongoose
> -)
> -
> -add_test(test-gstreamer-engine ${CMAKE_CURRENT_BINARY_DIR}/test-gstreamer-engine)
> +MEDIA_HUB_ADD_TEST(existing_request_authenticator_test existing_request_authenticator_test.cpp)
> +MEDIA_HUB_ADD_TEST(hashed_keyed_player_store_test hashed_keyed_player_store_test.cpp)
> +MEDIA_HUB_ADD_TEST(pulseaudio_audio_output_observer_test pulseaudio_audio_output_observer_test.cpp)
> +MEDIA_HUB_ADD_TEST(test-gstreamer-engine test-gstreamer-engine.cpp)
> 
> === added file 'tests/unit-tests/existing_request_authenticator_test.cpp'
> --- tests/unit-tests/existing_request_authenticator_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/unit-tests/existing_request_authenticator_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/apparmor/ubuntu.h>
> +
> +#include <gtest/gtest.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +const media::apparmor::ubuntu::Context the_unconfined_context{"unconfined"};
> +const media::apparmor::ubuntu::Context camera{"com.ubuntu.camera_camera"};
> +const media::apparmor::ubuntu::Context browser{"com.ubuntu.browser_browser_1.x.x"};
> +const media::apparmor::ubuntu::Context music{"com.ubuntu.music_music"};
> +const media::apparmor::ubuntu::Context gallery{"com.ubuntu.gallery_gallery"};
> +}
> +
> +TEST(UbuntuContext, throws_for_empty_name_on_construction)
> +{
> +    EXPECT_ANY_THROW(media::apparmor::ubuntu::Context{std::string{}});
> +    EXPECT_ANY_THROW(media::apparmor::ubuntu::Context{""});
> +}
> +
> +TEST(UbuntuContext, throws_for_invalid_name_on_construction)
> +{
> +    // Any name that is not "unconfined" or a valid app id should throw.
> +    std::string name{"adsfdsafasdfasdfasdfsadf"};
> +    EXPECT_ANY_THROW(media::apparmor::ubuntu::Context{name});
> +}
> +
> +TEST(UbuntuContext, correctly_reports_unconfined)
> +{
> +    media::apparmor::ubuntu::Context ctx1{the_unconfined_context.str()};
> +    EXPECT_TRUE(ctx1.is_unconfined());
> +    media::apparmor::ubuntu::Context ctx2{"com.ubuntu.camera_camera"};
> +    EXPECT_FALSE(ctx2.is_unconfined());
> +}
> +
> +TEST(UbuntuContext, correctly_extracts_package_name_for_long_and_short_app_id)
> +{
> +    const std::string short_app_id{"com.ubuntu.camera_camera"};
> +    const std::string long_app_id{"com.ubuntu.browser_browser_1.x.x"};
> +
> +    media::apparmor::ubuntu::Context ctx1{short_app_id};
> +    media::apparmor::ubuntu::Context ctx2{long_app_id};
> +
> +    EXPECT_TRUE(ctx1.has_package_name());
> +    EXPECT_TRUE(ctx2.has_package_name());
> +    EXPECT_EQ("com.ubuntu.camera", ctx1.package_name());
> +    EXPECT_EQ("com.ubuntu.browser", ctx2.package_name());
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_a_request_by_unconfined)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(the_unconfined_context, "whatever")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_a_request_for_an_apps_user_specific_private_directory)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///home/user/.local/share/" + browser.package_name() + "/")));
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///home/user/.local/share/" + camera.package_name() + "/")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_a_request_for_an_apps_shared_private_directory)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///opt/click.ubuntu.com/" + browser.package_name() + "/")));
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///opt/click.ubuntu.com/" + camera.package_name() + "/")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_a_request_by_camera_app_for_ui_sounds)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(camera, "file:///system/media/audio/ui/")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(camera, "file:///android/system/media/audio/ui/")));
> +
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///system/media/audio/ui/")));
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///android/system/media/audio/ui/")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_request_to_shared_directories_by_gallery_and_music_app)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "file:///home/user/Music/")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "file:///home/user/Videos/")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "file:///media")));
> +
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(gallery, "file:///home/user/Music/")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(gallery, "file:///home/user/Videos/")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(gallery, "file:///media")));
> +
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///home/user/Music/")));
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///home/user/Videos/")));
> +    EXPECT_FALSE(std::get<0>(authenticator.authenticate_open_uri_request(browser, "file:///media")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_request_to_usr_share_sounds)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "file:///usr/share/sounds")));
> +}
> +
> +TEST(ExistingAuthenticator, authenticates_request_for_streaming_content)
> +{
> +    media::apparmor::ubuntu::ExistingAuthenticator authenticator;
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "http://whatever")));
> +    EXPECT_TRUE(std::get<0>(authenticator.authenticate_open_uri_request(music, "rtsp://whatever")));
> +}
> 
> === added file 'tests/unit-tests/hashed_keyed_player_store_test.cpp'
> --- tests/unit-tests/hashed_keyed_player_store_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/unit-tests/hashed_keyed_player_store_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,97 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/hashed_keyed_player_store.h>
> +
> +#include "mock/player.h"
> +
> +#include <gtest/gtest.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +namespace
> +{
> +// Our default player key we use in testing.
> +constexpr const media::Player::PlayerKey the_player_key{42};
> +}
> +
> +TEST(HashedKeyedPlayerStore, has_player_for_key_returns_true_after_player_has_been_added)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    auto the_player = std::make_shared<MockPlayer<media::PlayerBase>>();
> +
> +    EXPECT_FALSE(store.has_player_for_key(the_player_key));
> +    store.add_player_for_key(the_player_key, the_player);
> +    EXPECT_TRUE(store.has_player_for_key(the_player_key));
> +    EXPECT_EQ(the_player, store.player_for_key(the_player_key));
> +}
> +
> +TEST(HashedKeyedPlayerStore, has_player_for_key_returns_true_after_player_has_been_removed)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    auto the_player = std::make_shared<testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +
> +    store.add_player_for_key(the_player_key, the_player);
> +    EXPECT_TRUE(store.has_player_for_key(the_player_key));
> +    store.remove_player_for_key(the_player_key);
> +    EXPECT_FALSE(store.has_player_for_key(the_player_key));
> +    EXPECT_ANY_THROW(store.player_for_key(the_player_key));
> +}
> +
> +TEST(HashedKeyedPlayerStore, enumeration_finds_players)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    auto the_player = std::make_shared<testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +    store.add_player_for_key(the_player_key, the_player); bool player_found{false};
> +    store.enumerate_players([the_player, &player_found](media::Player::PlayerKey key, std::shared_ptr<media::Player> player)
> +    {
> +        player_found = (the_player_key == key) && (player == the_player);
> +    });
> +    EXPECT_TRUE(player_found);
> +}
> +
> +TEST(HashedKeyedPlayerStore, current_player_is_null_after_construction)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    EXPECT_FALSE(store.current_player().get());
> +}
> +
> +TEST(HashedKeyedPlayerStore, current_player_throws_for_unknown_player)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    EXPECT_ANY_THROW(store.set_current_player_for_key(the_player_key));
> +}
> +
> +TEST(HashedKeyedPlayerStore, setting_the_current_player_adjusts_current_player)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    auto the_player = std::make_shared<testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +    store.add_player_for_key(the_player_key, the_player);
> +    store.set_current_player_for_key(the_player_key);
> +    EXPECT_EQ(the_player, store.current_player().get());
> +}
> +
> +TEST(HashedKeyedPlayerStore, removing_the_current_player_resets_current_player)
> +{
> +    media::HashedKeyedPlayerStore store;
> +    auto the_player = std::make_shared<testing::NiceMock<MockPlayer<media::PlayerBase>>>();
> +    store.add_player_for_key(the_player_key, the_player);
> +    store.set_current_player_for_key(the_player_key);
> +    store.remove_player_for_key(the_player_key);
> +    EXPECT_FALSE(store.current_player().get());
> +}
> 
> === added file 'tests/unit-tests/pulseaudio_audio_output_observer_test.cpp'
> --- tests/unit-tests/pulseaudio_audio_output_observer_test.cpp	1970-01-01 00:00:00 +0000
> +++ tests/unit-tests/pulseaudio_audio_output_observer_test.cpp	2015-04-17 14:35:22 +0000
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: Thomas Voß <thomas.voss at canonical.com>
> + */
> +
> +#include <core/media/audio/pulse_audio_output_observer.h>
> +
> +#include "tools/event_sink.h"
> +
> +#include <gtest/gtest.h>
> +
> +namespace media = core::ubuntu::media;
> +
> +TEST(PulseAudioAudioOutputObserver, construction_and_deconstruction_works)
> +{
> +    media::audio::PulseAudioOutputObserver observer{media::audio::PulseAudioOutputObserver::Configuration{}};
> +}
> +
> +TEST(PulseAudioAudioOutputObserver, head_phone_and_set_connect_disconnect_are_correctly_reported_requires_tester)
> +{
> +    media::audio::PulseAudioOutputObserver::Configuration config;
> +    media::audio::PulseAudioOutputObserver observer{config};
> +
> +    tools::EventSink<media::audio::OutputState> es_external_output_state{observer.external_output_state(), 2};
> +    testing::NiceMock<tools::EventSink<std::string>> es_sink{observer.sink()};
> +    testing::NiceMock<tools::EventSink<std::set<media::audio::PulseAudioOutputObserver::Reporter::Port>>> es_available_ports{observer.known_ports()};
> +
> +    // Connect has to happen prior to disconnect.
> +    testing::Sequence connect_disconnect_sequence;
> +    EXPECT_CALL(es_external_output_state, on_new_event(media::audio::OutputState::Earpiece)).Times(1);
> +    EXPECT_CALL(es_external_output_state, on_new_event(media::audio::OutputState::Speaker)).Times(1);
> +
> +    // We need to know about the sink and its ports for the test to work.
> +    ASSERT_TRUE(es_sink.wait_for_event_for(std::chrono::milliseconds{500}));
> +    ASSERT_TRUE(es_available_ports.wait_for_event_for(std::chrono::milliseconds{500}));
> +
> +    // Once we reach here, we request the tester to plug and unplug a headphone or headset.
> +    std::cout << "Please attach a headphone/headset to the device, and disconnect it again." << std::endl;
> +    ASSERT_TRUE(es_external_output_state.wait_for_event_for(std::chrono::seconds{10}));
> +}
> +
> +TEST(PulseAudioAudioOutputObserver, bluetooth_devices_connect_disconnect_are_correctly_reported_requires_tester)
> +{
> +    media::audio::PulseAudioOutputObserver::Configuration config;
> +    media::audio::PulseAudioOutputObserver observer{config};
> +
> +    tools::EventSink<media::audio::OutputState> es_external_output_state{observer.external_output_state(), 2};
> +    testing::NiceMock<tools::EventSink<std::string>> es_sink{observer.sink()};
> +    testing::NiceMock<tools::EventSink<std::set<media::audio::PulseAudioOutputObserver::Reporter::Port>>> es_available_ports{observer.known_ports()};
> +
> +    // Connect has to happen prior to disconnect.
> +    testing::Sequence connect_disconnect_sequence;
> +    EXPECT_CALL(es_external_output_state, on_new_event(media::audio::OutputState::Earpiece)).Times(1);
> +    EXPECT_CALL(es_external_output_state, on_new_event(media::audio::OutputState::Speaker)).Times(1);
> +
> +    // We need to know about the sink and its ports for the test to work.
> +    ASSERT_TRUE(es_sink.wait_for_event_for(std::chrono::milliseconds{500}));
> +    ASSERT_TRUE(es_available_ports.wait_for_event_for(std::chrono::milliseconds{500}));
> +
> +    // Once we reach here, we request the tester to connect a bluetooth headphone or headset.
> +    std::cout << "Please connect a bluetooth headphone/headset to the device, and disconnect it again." << std::endl;
> +    ASSERT_TRUE(es_external_output_state.wait_for_event_for(std::chrono::seconds{10}));
> +}
> 
> === modified file 'tests/unit-tests/test-gstreamer-engine.cpp'
> --- tests/unit-tests/test-gstreamer-engine.cpp	2015-03-03 22:41:22 +0000
> +++ tests/unit-tests/test-gstreamer-engine.cpp	2015-04-17 14:35:22 +0000
> @@ -20,15 +20,17 @@
>  #include <core/media/player.h>
>  #include <core/media/track_list.h>
>  
> -#include <core/posix/fork.h>
> -
>  #include "core/media/xesam.h"
>  #include "core/media/gstreamer/engine.h"
> +#include "core/media/gstreamer/playbin.h"
>  
>  #include "../test_data.h"
>  #include "../waitable_state_transition.h"
>  #include "web_server.h"
>  
> +#include <core/posix/fork.h>
> +#include <core/testing/cross_process_sync.h>
> +
>  #include <gtest/gtest.h>
>  
>  #include <cstdio>
> @@ -68,12 +70,12 @@
>      gstreamer::Engine engine;
>  }
>  
> -TEST(GStreamerEngine, DISABLED_setting_uri_and_starting_audio_only_playback_works)
> +TEST(GStreamerEngine, setting_uri_and_starting_audio_only_playback_works)
>  {
> -    const std::string test_file{"/tmp/test-audio.ogg"};
> -    const std::string test_file_uri{"file:///tmp/test-audio.ogg"};
> +    const std::string test_file{"/tmp/test-audio-1.ogg"};
> +    const std::string test_file_uri{"file:///tmp/test-audio-1.ogg"};
>      std::remove(test_file.c_str());
> -    ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));
> +    ASSERT_TRUE(test::copy_test_media_file_to("test-audio-1.ogg", test_file));
>  
>      core::testing::WaitableStateTransition<core::ubuntu::media::Engine::State> wst(
>                  core::ubuntu::media::Engine::State::ready);
> @@ -113,7 +115,7 @@
>                      std::chrono::seconds{10}));
>  }
>  
> -TEST(GStreamerEngine, DISABLED_setting_uri_and_starting_video_playback_works)
> +TEST(GStreamerEngine, setting_uri_and_starting_video_playback_works)
>  {
>      const std::string test_file{"/tmp/test-video.ogg"};
>      const std::string test_file_uri{"file:///tmp/test-video.ogg"};
> @@ -167,7 +169,7 @@
>      // test server
>      core::testing::CrossProcessSync cps; // server - ready -> client
>  
> -    testing::web::server::Configuration configuration
> +    ::testing::web::server::Configuration configuration
>      {
>          5000,
>          [test_file](mg_connection* conn)
> @@ -262,7 +264,7 @@
>                      std::chrono::seconds{40}));
>  }
>  
> -TEST(GStreamerEngine, DISABLED_stop_pause_play_seek_video_works)
> +TEST(GStreamerEngine, stop_pause_play_seek_video_works)
>  {
>      const std::string test_file{"/tmp/test-video.ogg"};
>      const std::string test_file_uri{"file:///tmp/test-video.ogg"};
> @@ -399,10 +401,10 @@
>  
>  TEST(GStreamerEngine, meta_data_extractor_provides_correct_tags)
>  {
> -    const std::string test_file{"/tmp/test.mp3"};
> -    const std::string test_file_uri{"file:///tmp/test.mp3"};
> +    const std::string test_file{"/tmp/test-audio.ogg"};
> +    const std::string test_file_uri{"file:///tmp/test-audio.ogg"};
>      std::remove(test_file.c_str());
> -    ASSERT_TRUE(test::copy_test_media_file_to("test.mp3", test_file));
> +    ASSERT_TRUE(test::copy_test_media_file_to("test-audio.ogg", test_file));
>  
>      gstreamer::Engine engine;
>      auto md = engine.meta_data_extractor()->meta_data_for_track_with_uri(test_file_uri);
> @@ -412,9 +414,9 @@
>      if (0 < md.count(xesam::AlbumArtist::name))
>          EXPECT_EQ("Test", md.get(xesam::AlbumArtist::name));
>      if (0 < md.count(xesam::Artist::name))
> -        EXPECT_EQ("Ezwa", md.get(xesam::Artist::name));
> +        EXPECT_EQ("Test", md.get(xesam::Artist::name));
>      if (0 < md.count(xesam::DiscNumber::name))
> -        EXPECT_EQ("1", md.get(xesam::DiscNumber::name));
> +        EXPECT_EQ("42", md.get(xesam::DiscNumber::name));
>      if (0 < md.count(xesam::Genre::name))
>          EXPECT_EQ("Test", md.get(xesam::Genre::name));
>      if (0 < md.count(xesam::TrackNumber::name))
> 


-- 
https://code.launchpad.net/~thomas-voss/media-hub/add-tests-and-testing-infrastructure/+merge/252104
Your team Ubuntu Phablet Team is subscribed to branch lp:media-hub.



More information about the Ubuntu-reviews mailing list