LCOV - code coverage report
Current view: top level - src/libvalent/media - valent-media.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 92.6 % 149 138
Test Date: 2024-03-22 06:22:29 Functions: 94.4 % 18 17
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 60.5 % 76 46

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-media"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <gio/gio.h>
       9                 :             : #include <libpeas.h>
      10                 :             : #include <libvalent-core.h>
      11                 :             : 
      12                 :             : #include "valent-media.h"
      13                 :             : #include "valent-media-adapter.h"
      14                 :             : #include "valent-media-player.h"
      15                 :             : 
      16                 :             : 
      17                 :             : /**
      18                 :             :  * ValentMedia:
      19                 :             :  *
      20                 :             :  * A class for monitoring and controlling media players.
      21                 :             :  *
      22                 :             :  * `ValentMedia` is an aggregator of media players, intended for use by
      23                 :             :  * [class@Valent.DevicePlugin] implementations.
      24                 :             :  *
      25                 :             :  * Plugins can implement [class@Valent.MediaAdapter] to provide an
      26                 :             :  * interface to manage instances of [class@Valent.MediaPlayer].
      27                 :             :  *
      28                 :             :  * Since: 1.0
      29                 :             :  */
      30                 :             : 
      31                 :             : struct _ValentMedia
      32                 :             : {
      33                 :             :   ValentComponent  parent_instance;
      34                 :             : 
      35                 :             :   GPtrArray       *adapters;
      36                 :             :   GListModel      *exports;
      37                 :             :   GPtrArray       *players;
      38                 :             :   GPtrArray       *paused;
      39                 :             : };
      40                 :             : 
      41                 :             : static void   g_list_model_iface_init (GListModelInterface *iface);
      42                 :             : 
      43   [ +  +  +  - ]:         320 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentMedia, valent_media, VALENT_TYPE_COMPONENT,
      44                 :             :                                G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
      45                 :             : 
      46                 :             : static ValentMedia *default_media = NULL;
      47                 :             : 
      48                 :             : 
      49                 :             : static void
      50                 :          47 : on_items_changed (GListModel   *list,
      51                 :             :                   unsigned int  position,
      52                 :             :                   unsigned int  removed,
      53                 :             :                   unsigned int  added,
      54                 :             :                   ValentMedia  *self)
      55                 :             : {
      56                 :          47 :   unsigned int real_position = 0;
      57                 :             : 
      58                 :          47 :   VALENT_ENTRY;
      59                 :             : 
      60         [ +  - ]:          47 :   g_assert (G_IS_LIST_MODEL (list));
      61         [ +  - ]:          47 :   g_assert (VALENT_IS_MEDIA (self));
      62                 :             : 
      63                 :             :   /* Translate the adapter position */
      64         [ +  - ]:          89 :   for (unsigned int i = 0; i < self->adapters->len; i++)
      65                 :             :     {
      66                 :          89 :       GListModel *adapter = g_ptr_array_index (self->adapters, i);
      67                 :             : 
      68         [ +  + ]:          89 :       if (adapter == list)
      69                 :             :         break;
      70                 :             : 
      71                 :          42 :       real_position += g_list_model_get_n_items (adapter);
      72                 :             :     }
      73                 :             : 
      74                 :          47 :   real_position += position;
      75                 :             : 
      76                 :             :   /* Propagate the changes */
      77         [ +  + ]:          55 :   for (unsigned int i = 0; i < removed; i++)
      78                 :             :     {
      79                 :           8 :       g_autoptr (ValentMediaPlayer) player = NULL;
      80                 :             : 
      81                 :           8 :       player = g_ptr_array_steal_index (self->players, real_position);
      82                 :           8 :       g_ptr_array_remove (self->paused, player);
      83                 :             : 
      84         [ +  - ]:           8 :       VALENT_NOTE ("removed %s (%s)",
      85                 :             :                    G_OBJECT_TYPE_NAME (player),
      86                 :             :                    valent_media_player_get_name (player));
      87                 :             :     }
      88                 :             : 
      89         [ +  + ]:          55 :   for (unsigned int i = 0; i < added; i++)
      90                 :             :     {
      91                 :           8 :       ValentMediaPlayer *player = NULL;
      92                 :             : 
      93                 :           8 :       player = g_list_model_get_item (list, position + i);
      94                 :           8 :       g_ptr_array_insert (self->players, real_position + i, player);
      95                 :             : 
      96                 :           8 :       VALENT_NOTE ("added %s (%s)",
      97                 :             :                    G_OBJECT_TYPE_NAME (player),
      98                 :             :                    valent_media_player_get_name (player));
      99                 :             :     }
     100                 :             : 
     101                 :          47 :   g_list_model_items_changed (G_LIST_MODEL (self), real_position, removed, added);
     102                 :             : 
     103                 :          47 :   VALENT_EXIT;
     104                 :             : }
     105                 :             : 
     106                 :             : /*
     107                 :             :  * GListModel
     108                 :             :  */
     109                 :             : static gpointer
     110                 :          19 : valent_media_get_item (GListModel   *list,
     111                 :             :                        unsigned int  position)
     112                 :             : {
     113                 :          19 :   ValentMedia *self = VALENT_MEDIA (list);
     114                 :             : 
     115         [ +  - ]:          19 :   g_assert (VALENT_IS_MEDIA (self));
     116                 :             : 
     117         [ +  - ]:          19 :   if G_UNLIKELY (position >= self->players->len)
     118                 :             :     return NULL;
     119                 :             : 
     120                 :          19 :   return g_object_ref (g_ptr_array_index (self->players, position));
     121                 :             : }
     122                 :             : 
     123                 :             : static GType
     124                 :           0 : valent_media_get_item_type (GListModel *list)
     125                 :             : {
     126                 :           0 :   return VALENT_TYPE_MEDIA_PLAYER;
     127                 :             : }
     128                 :             : 
     129                 :             : static unsigned int
     130                 :          25 : valent_media_get_n_items (GListModel *list)
     131                 :             : {
     132                 :          25 :   ValentMedia *self = VALENT_MEDIA (list);
     133                 :             : 
     134         [ +  - ]:          25 :   g_assert (VALENT_IS_MEDIA (self));
     135                 :             : 
     136                 :          25 :   return self->players->len;
     137                 :             : }
     138                 :             : 
     139                 :             : static void
     140                 :           5 : g_list_model_iface_init (GListModelInterface *iface)
     141                 :             : {
     142                 :           5 :   iface->get_item = valent_media_get_item;
     143                 :           5 :   iface->get_item_type = valent_media_get_item_type;
     144                 :           5 :   iface->get_n_items = valent_media_get_n_items;
     145                 :           5 : }
     146                 :             : 
     147                 :             : /*
     148                 :             :  * ValentComponent
     149                 :             :  */
     150                 :             : static void
     151                 :          13 : valent_media_bind_extension (ValentComponent *component,
     152                 :             :                              GObject         *extension)
     153                 :             : {
     154                 :          13 :   ValentMedia *self = VALENT_MEDIA (component);
     155                 :          13 :   GListModel *list = G_LIST_MODEL (extension);
     156                 :          13 :   unsigned int n_exports = 0;
     157                 :             : 
     158                 :          13 :   VALENT_ENTRY;
     159                 :             : 
     160         [ +  - ]:          13 :   g_assert (VALENT_IS_MEDIA (self));
     161         [ -  + ]:          13 :   g_assert (VALENT_IS_MEDIA_ADAPTER (extension));
     162                 :             : 
     163                 :          13 :   g_ptr_array_add (self->adapters, g_object_ref (extension));
     164                 :          13 :   on_items_changed (list, 0, 0, g_list_model_get_n_items (list), self);
     165                 :          13 :   g_signal_connect_object (list,
     166                 :             :                            "items-changed",
     167                 :             :                            G_CALLBACK (on_items_changed),
     168                 :             :                            self,
     169                 :             :                            0);
     170                 :             : 
     171                 :          13 :   n_exports = g_list_model_get_n_items (G_LIST_MODEL (self->exports));
     172                 :             : 
     173         [ -  + ]:          13 :   for (unsigned int i = 0; i < n_exports; i++)
     174                 :             :     {
     175                 :           0 :       g_autoptr (ValentMediaPlayer) player = NULL;
     176                 :             : 
     177                 :           0 :       player = g_list_model_get_item (G_LIST_MODEL (self->exports), i);
     178         [ #  # ]:           0 :       valent_media_adapter_export_player (VALENT_MEDIA_ADAPTER (extension),
     179                 :             :                                           player);
     180                 :             :     }
     181                 :             : 
     182                 :          13 :   VALENT_EXIT;
     183                 :             : }
     184                 :             : 
     185                 :             : static void
     186                 :          10 : valent_media_unbind_extension (ValentComponent *component,
     187                 :             :                                GObject         *extension)
     188                 :             : {
     189                 :          10 :   ValentMedia *self = VALENT_MEDIA (component);
     190                 :          10 :   GListModel *list = G_LIST_MODEL (extension);
     191                 :             : 
     192                 :          10 :   VALENT_ENTRY;
     193                 :             : 
     194         [ +  - ]:          10 :   g_assert (VALENT_IS_MEDIA (self));
     195         [ -  + ]:          10 :   g_assert (VALENT_IS_MEDIA_ADAPTER (extension));
     196                 :             : 
     197         [ -  + ]:          10 :   if (!g_ptr_array_find (self->adapters, extension, NULL))
     198                 :             :     {
     199                 :           0 :       g_warning ("No such adapter \"%s\" found in \"%s\"",
     200                 :             :                  G_OBJECT_TYPE_NAME (extension),
     201                 :             :                  G_OBJECT_TYPE_NAME (component));
     202                 :           0 :       return;
     203                 :             :     }
     204                 :             : 
     205                 :          10 :   g_signal_handlers_disconnect_by_func (list, on_items_changed, self);
     206                 :          10 :   on_items_changed (list, 0, g_list_model_get_n_items (list), 0, self);
     207                 :          10 :   g_ptr_array_remove (self->adapters, extension);
     208                 :             : 
     209                 :          10 :   VALENT_EXIT;
     210                 :             : }
     211                 :             : 
     212                 :             : /*
     213                 :             :  * ValentObject
     214                 :             :  */
     215                 :             : static void
     216                 :           8 : valent_media_destroy (ValentObject *object)
     217                 :             : {
     218                 :           8 :   ValentMedia *self = VALENT_MEDIA (object);
     219                 :             : 
     220                 :           8 :   g_list_store_remove_all (G_LIST_STORE (self->exports));
     221                 :             : 
     222                 :           8 :   VALENT_OBJECT_CLASS (valent_media_parent_class)->destroy (object);
     223                 :           8 : }
     224                 :             : 
     225                 :             : /*
     226                 :             :  * GObject
     227                 :             :  */
     228                 :             : static void
     229                 :           8 : valent_media_finalize (GObject *object)
     230                 :             : {
     231                 :           8 :   ValentMedia *self = VALENT_MEDIA (object);
     232                 :             : 
     233         [ +  - ]:           8 :   g_clear_object (&self->exports);
     234         [ +  - ]:           8 :   g_clear_pointer (&self->adapters, g_ptr_array_unref);
     235         [ +  - ]:           8 :   g_clear_pointer (&self->players, g_ptr_array_unref);
     236         [ +  - ]:           8 :   g_clear_pointer (&self->paused, g_ptr_array_unref);
     237                 :             : 
     238                 :           8 :   G_OBJECT_CLASS (valent_media_parent_class)->finalize (object);
     239                 :           8 : }
     240                 :             : 
     241                 :             : static void
     242                 :           5 : valent_media_class_init (ValentMediaClass *klass)
     243                 :             : {
     244                 :           5 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     245                 :           5 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     246                 :           5 :   ValentComponentClass *component_class = VALENT_COMPONENT_CLASS (klass);
     247                 :             : 
     248                 :           5 :   object_class->finalize = valent_media_finalize;
     249                 :             : 
     250                 :           5 :   vobject_class->destroy = valent_media_destroy;
     251                 :             : 
     252                 :           5 :   component_class->bind_extension = valent_media_bind_extension;
     253                 :           5 :   component_class->unbind_extension = valent_media_unbind_extension;
     254                 :             : }
     255                 :             : 
     256                 :             : static void
     257                 :          10 : valent_media_init (ValentMedia *self)
     258                 :             : {
     259                 :          10 :   self->adapters = g_ptr_array_new_with_free_func (g_object_unref);
     260                 :          10 :   self->exports = G_LIST_MODEL (g_list_store_new (VALENT_TYPE_MEDIA_PLAYER));
     261                 :          10 :   self->players = g_ptr_array_new_with_free_func (g_object_unref);
     262                 :          10 :   self->paused = g_ptr_array_new ();
     263                 :             : 
     264                 :          10 :   g_ptr_array_add (self->adapters, g_object_ref (self->exports));
     265                 :          10 :   g_signal_connect_object (self->exports,
     266                 :             :                            "items-changed",
     267                 :             :                            G_CALLBACK (on_items_changed),
     268                 :             :                            self, 0);
     269                 :          10 : }
     270                 :             : 
     271                 :             : /**
     272                 :             :  * valent_media_get_default:
     273                 :             :  *
     274                 :             :  * Get the default [class@Valent.Media].
     275                 :             :  *
     276                 :             :  * Returns: (transfer none) (not nullable): a `ValentMedia`
     277                 :             :  *
     278                 :             :  * Since: 1.0
     279                 :             :  */
     280                 :             : ValentMedia *
     281                 :          23 : valent_media_get_default (void)
     282                 :             : {
     283         [ +  + ]:          23 :   if (default_media == NULL)
     284                 :             :     {
     285                 :          10 :       default_media = g_object_new (VALENT_TYPE_MEDIA,
     286                 :             :                                     "plugin-domain", "media",
     287                 :             :                                     "plugin-type",   VALENT_TYPE_MEDIA_ADAPTER,
     288                 :             :                                     NULL);
     289                 :             : 
     290                 :          10 :       g_object_add_weak_pointer (G_OBJECT (default_media),
     291                 :             :                                  (gpointer)&default_media);
     292                 :             :     }
     293                 :             : 
     294                 :          23 :   return default_media;
     295                 :             : }
     296                 :             : 
     297                 :             : /**
     298                 :             :  * valent_media_export_player:
     299                 :             :  * @media: a `ValentMedia`
     300                 :             :  * @player: a `ValentMediaPlayer`
     301                 :             :  *
     302                 :             :  * Export @player on all adapters that support it.
     303                 :             :  *
     304                 :             :  * Since: 1.0
     305                 :             :  */
     306                 :             : void
     307                 :           1 : valent_media_export_player (ValentMedia       *media,
     308                 :             :                             ValentMediaPlayer *player)
     309                 :             : {
     310                 :           1 :   VALENT_ENTRY;
     311                 :             : 
     312         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_MEDIA (media));
     313         [ -  + ]:           1 :   g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
     314                 :             : 
     315         [ -  + ]:           1 :   if (g_ptr_array_find (media->players, player, NULL))
     316                 :             :     {
     317                 :           0 :       g_critical ("%s(): known player %s (%s)",
     318                 :             :                   G_STRFUNC,
     319                 :             :                   G_OBJECT_TYPE_NAME (player),
     320                 :             :                   valent_media_player_get_name (player));
     321                 :           0 :       VALENT_EXIT;
     322                 :             :     }
     323                 :             : 
     324                 :             :   // Starting at index `1` skips the exports GListModel
     325         [ +  + ]:           3 :   for (unsigned int i = 1; i < media->adapters->len; i++)
     326                 :             :     {
     327                 :           2 :       ValentMediaAdapter *adapter = NULL;
     328                 :             : 
     329                 :           2 :       adapter = g_ptr_array_index (media->adapters, i);
     330                 :           2 :       valent_media_adapter_export_player (adapter, player);
     331                 :             :     }
     332                 :             : 
     333                 :           1 :   g_list_store_append (G_LIST_STORE (media->exports), player);
     334                 :             : 
     335                 :           1 :   VALENT_EXIT;
     336                 :             : }
     337                 :             : 
     338                 :             : /**
     339                 :             :  * valent_media_unexport_player:
     340                 :             :  * @media: a `ValentMedia`
     341                 :             :  * @player: a `ValentMediaPlayer`
     342                 :             :  *
     343                 :             :  * Unexport @player from all adapters that support it.
     344                 :             :  *
     345                 :             :  * Since: 1.0
     346                 :             :  */
     347                 :             : void
     348                 :           1 : valent_media_unexport_player (ValentMedia       *media,
     349                 :             :                               ValentMediaPlayer *player)
     350                 :             : {
     351                 :           1 :   unsigned int position = 0;
     352                 :             : 
     353                 :           1 :   VALENT_ENTRY;
     354                 :             : 
     355         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_MEDIA (media));
     356         [ -  + ]:           1 :   g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
     357                 :             : 
     358         [ -  + ]:           1 :   if (!g_list_store_find (G_LIST_STORE (media->exports), player, &position))
     359                 :             :     {
     360                 :           0 :       g_critical ("%s(): unknown player %s (%s)",
     361                 :             :                   G_STRFUNC,
     362                 :             :                   G_OBJECT_TYPE_NAME (player),
     363                 :             :                   valent_media_player_get_name (player));
     364                 :           0 :       VALENT_EXIT;
     365                 :             :     }
     366                 :             : 
     367                 :             :   // Starting at index `1` skips the exports GListModel
     368         [ +  + ]:           3 :   for (unsigned int i = 1; i < media->adapters->len; i++)
     369                 :             :     {
     370                 :           2 :       ValentMediaAdapter *adapter = NULL;
     371                 :             : 
     372                 :           2 :       adapter = g_ptr_array_index (media->adapters, i);
     373                 :           2 :       valent_media_adapter_unexport_player (adapter, player);
     374                 :             :     }
     375                 :             : 
     376                 :           1 :   g_list_store_remove (G_LIST_STORE (media->exports), position);
     377                 :             : 
     378                 :           1 :   VALENT_EXIT;
     379                 :             : }
     380                 :             : 
     381                 :             : /**
     382                 :             :  * valent_media_pause:
     383                 :             :  * @media: a `ValentMedia`
     384                 :             :  *
     385                 :             :  * Pause any playing media players. Any player whose playback status is changed
     386                 :             :  * will be tracked so that playback may be resumed with valent_media_play().
     387                 :             :  *
     388                 :             :  * Since: 1.0
     389                 :             :  */
     390                 :             : void
     391                 :           3 : valent_media_pause (ValentMedia *media)
     392                 :             : {
     393                 :           3 :   ValentMediaPlayer *player;
     394                 :             : 
     395                 :           3 :   VALENT_ENTRY;
     396                 :             : 
     397         [ -  + ]:           3 :   g_return_if_fail (VALENT_IS_MEDIA (media));
     398                 :             : 
     399         [ +  + ]:           4 :   for (unsigned int i = 0; i < media->players->len; i++)
     400                 :             :     {
     401                 :           1 :       player = g_ptr_array_index (media->players, i);
     402                 :             : 
     403         [ +  - ]:           1 :       if (valent_media_player_get_state (player) == VALENT_MEDIA_STATE_PLAYING)
     404                 :             :         {
     405                 :           1 :           valent_media_player_pause (player);
     406                 :           1 :           g_ptr_array_add (media->paused, player);
     407                 :             :         }
     408                 :             :     }
     409                 :             : 
     410                 :           3 :   VALENT_EXIT;
     411                 :             : }
     412                 :             : 
     413                 :             : /**
     414                 :             :  * valent_media_unpause:
     415                 :             :  * @media: a `ValentMedia`
     416                 :             :  *
     417                 :             :  * Unpause any media players we previously paused.
     418                 :             :  *
     419                 :             :  * Since: 1.0
     420                 :             :  */
     421                 :             : void
     422                 :           3 : valent_media_unpause (ValentMedia *media)
     423                 :             : {
     424                 :           3 :   ValentMediaPlayer *player;
     425                 :             : 
     426                 :           3 :   VALENT_ENTRY;
     427                 :             : 
     428         [ -  + ]:           3 :   g_return_if_fail (VALENT_IS_MEDIA (media));
     429                 :             : 
     430         [ +  + ]:           4 :   for (unsigned int i = 0; i < media->players->len; i++)
     431                 :             :     {
     432                 :           1 :       player = g_ptr_array_index (media->players, i);
     433                 :             : 
     434         [ +  - ]:           1 :       if (valent_media_player_get_state (player) == VALENT_MEDIA_STATE_PAUSED)
     435                 :           1 :         valent_media_player_play (player);
     436                 :             :     }
     437                 :             : 
     438                 :           3 :   g_ptr_array_remove_range (media->paused, 0, media->paused->len);
     439                 :             : 
     440                 :           3 :   VALENT_EXIT;
     441                 :             : }
     442                 :             : 
        

Generated by: LCOV version 2.0-1