LCOV - code coverage report
Current view: top level - src/plugins/mpris - valent-mpris-plugin.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 96.0 % 329 316
Test Date: 2024-12-21 23:29:11 Functions: 100.0 % 21 21
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 62.3 % 212 132

             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-mpris-plugin"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <math.h>
       9                 :             : 
      10                 :             : #include <glib/gi18n.h>
      11                 :             : #include <gio/gio.h>
      12                 :             : #include <json-glib/json-glib.h>
      13                 :             : #include <valent.h>
      14                 :             : 
      15                 :             : #include "vdp-mpris-adapter.h"
      16                 :             : #include "vdp-mpris-player.h"
      17                 :             : #include "valent-mpris-utils.h"
      18                 :             : 
      19                 :             : #include "valent-mpris-plugin.h"
      20                 :             : 
      21                 :             : struct _ValentMprisPlugin
      22                 :             : {
      23                 :             :   ValentDevicePlugin  parent_instance;
      24                 :             : 
      25                 :             :   ValentMedia        *media;
      26                 :             :   unsigned int        media_watch : 1;
      27                 :             :   ValentMediaAdapter *adapter;
      28                 :             :   GPtrArray          *players;
      29                 :             : 
      30                 :             :   GHashTable         *transfers;
      31                 :             :   GHashTable         *pending;
      32                 :             :   unsigned int        pending_list : 1;
      33                 :             :   unsigned int        flush_id;
      34                 :             : };
      35                 :             : 
      36   [ +  +  +  - ]:          93 : G_DEFINE_FINAL_TYPE (ValentMprisPlugin, valent_mpris_plugin, VALENT_TYPE_DEVICE_PLUGIN)
      37                 :             : 
      38                 :             : static void valent_mpris_plugin_send_player_info    (ValentMprisPlugin *self,
      39                 :             :                                                      ValentMediaPlayer *player,
      40                 :             :                                                      gboolean           now_playing,
      41                 :             :                                                      gboolean           volume);
      42                 :             : static void valent_mpris_plugin_send_player_list    (ValentMprisPlugin *self);
      43                 :             : 
      44                 :             : 
      45                 :             : static gpointer
      46                 :          11 : valent_mpris_plugin_lookup_player (ValentMprisPlugin *self,
      47                 :             :                                    const char        *name)
      48                 :             : {
      49         [ +  - ]:          11 :   for (unsigned int i = 0; i < self->players->len; i++)
      50                 :             :     {
      51                 :          11 :       ValentMediaPlayer *player = g_ptr_array_index (self->players, i);
      52         [ -  + ]:          11 :       if (g_strcmp0 (valent_media_player_get_name (player), name) == 0)
      53                 :             :         return player;
      54                 :             :     }
      55                 :             : 
      56                 :             :   return NULL;
      57                 :             : }
      58                 :             : 
      59                 :             : /*
      60                 :             :  * Local Players
      61                 :             :  */
      62                 :             : static void
      63                 :           1 : send_album_art_cb (ValentTransfer    *transfer,
      64                 :             :                    GAsyncResult      *result,
      65                 :             :                    ValentMprisPlugin *self)
      66                 :             : {
      67                 :           2 :   g_autoptr (GError) error = NULL;
      68         [ -  + ]:           1 :   g_autofree char *id = NULL;
      69                 :             : 
      70         [ +  - ]:           1 :   g_assert (VALENT_IS_TRANSFER (transfer));
      71                 :             : 
      72         [ -  + ]:           1 :   if (!valent_transfer_execute_finish (transfer, result, &error))
      73                 :           0 :     g_debug ("%s(): %s", G_STRFUNC, error->message);
      74                 :             : 
      75                 :           1 :   id = valent_transfer_dup_id (transfer);
      76                 :           1 :   g_hash_table_remove (self->transfers, id);
      77                 :           1 : }
      78                 :             : 
      79                 :             : static void
      80                 :           1 : valent_mpris_plugin_send_album_art (ValentMprisPlugin *self,
      81                 :             :                                     ValentMediaPlayer *player,
      82                 :             :                                     const char        *requested_uri)
      83                 :             : {
      84                 :           1 :   g_autoptr (GVariant) metadata = NULL;
      85                 :           1 :   const char *real_uri;
      86         [ -  - ]:           1 :   g_autoptr (GFile) real_file = NULL;
      87   [ +  -  -  - ]:           1 :   g_autoptr (GFile) requested_file = NULL;
      88   [ +  -  -  - ]:           1 :   g_autoptr (JsonBuilder) builder = NULL;
      89   [ -  +  -  - ]:           1 :   g_autoptr (JsonNode) packet = NULL;
      90   [ +  -  -  - ]:           1 :   g_autoptr (ValentTransfer) transfer = NULL;
      91                 :           1 :   ValentDevice *device;
      92                 :             : 
      93         [ +  - ]:           1 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
      94                 :             : 
      95                 :             :   /* Ignore concurrent requests */
      96         [ +  - ]:           1 :   if (g_hash_table_contains (self->transfers, requested_uri))
      97                 :             :     return;
      98                 :             : 
      99                 :             :   /* Check player and URL are safe */
     100   [ +  -  -  + ]:           2 :   if ((metadata = valent_media_player_get_metadata (player)) == NULL ||
     101                 :           1 :       !g_variant_lookup (metadata, "mpris:artUrl", "&s", &real_uri))
     102                 :             :     {
     103                 :           0 :       g_warning ("Album art request \"%s\" for track without album art",
     104                 :             :                  requested_uri);
     105                 :           0 :       return;
     106                 :             :     }
     107                 :             : 
     108                 :             :   /* Compare normalized URLs */
     109                 :           1 :   requested_file = g_file_new_for_uri (requested_uri);
     110                 :           1 :   real_file = g_file_new_for_uri (real_uri);
     111                 :             : 
     112         [ -  + ]:           1 :   if (!g_file_equal (requested_file, real_file))
     113                 :             :     {
     114                 :           0 :       g_warning ("Album art request \"%s\" doesn't match current track \"%s\"",
     115                 :             :                  requested_uri, real_uri);
     116                 :           0 :       return;
     117                 :             :     }
     118                 :             : 
     119                 :             :   /* Build the payload packet */
     120                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris");
     121                 :           1 :   json_builder_set_member_name (builder, "player");
     122                 :           1 :   json_builder_add_string_value (builder, valent_media_player_get_name (player));
     123                 :           1 :   json_builder_set_member_name (builder, "albumArtUrl");
     124                 :           1 :   json_builder_add_string_value (builder, requested_uri);
     125                 :           1 :   json_builder_set_member_name (builder, "transferringAlbumArt");
     126                 :           1 :   json_builder_add_boolean_value (builder, TRUE);
     127                 :           1 :   packet = valent_packet_end (&builder);
     128                 :             : 
     129                 :             :   /* Start the transfer */
     130                 :           1 :   device = valent_resource_get_source (VALENT_RESOURCE (self));
     131                 :           1 :   transfer = valent_device_transfer_new (device, packet, real_file);
     132                 :             : 
     133         [ -  + ]:           1 :   g_hash_table_insert (self->transfers,
     134                 :           1 :                        g_strdup (requested_uri),
     135                 :             :                        g_object_ref (transfer));
     136                 :             : 
     137         [ +  - ]:           1 :   valent_transfer_execute (transfer,
     138                 :             :                            NULL,
     139                 :             :                            (GAsyncReadyCallback)send_album_art_cb,
     140                 :             :                            self);
     141                 :             : }
     142                 :             : 
     143                 :             : static gboolean
     144                 :          11 : valent_mpris_plugin_flush (gpointer data)
     145                 :             : {
     146                 :          11 :   ValentMprisPlugin *self = VALENT_MPRIS_PLUGIN (data);
     147                 :          11 :   GHashTableIter iter;
     148                 :          11 :   ValentMediaPlayer *player;
     149                 :             : 
     150                 :          11 :   g_hash_table_iter_init (&iter, self->pending);
     151         [ +  + ]:          20 :   while (g_hash_table_iter_next (&iter, (void **)&player, NULL))
     152                 :             :     {
     153                 :           9 :       valent_mpris_plugin_send_player_info (self, player, TRUE, TRUE);
     154                 :           9 :       g_hash_table_iter_remove (&iter);
     155                 :             :     }
     156                 :             : 
     157         [ +  + ]:          11 :   if (self->pending_list)
     158                 :             :     {
     159                 :           2 :       valent_mpris_plugin_send_player_list (self);
     160                 :           2 :       self->pending_list = FALSE;
     161                 :             :     }
     162                 :             : 
     163                 :          11 :   self->flush_id = 0;
     164                 :             : 
     165                 :          11 :   return G_SOURCE_REMOVE;
     166                 :             : }
     167                 :             : 
     168                 :             : static void
     169                 :           2 : on_player_seeked (ValentMediaPlayer *player,
     170                 :             :                   double             position,
     171                 :             :                   ValentMprisPlugin *self)
     172                 :             : {
     173                 :           2 :   const char *name;
     174                 :           4 :   g_autoptr (JsonBuilder) builder = NULL;
     175         [ -  + ]:           2 :   g_autoptr (JsonNode) packet = NULL;
     176                 :             : 
     177         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     178                 :             : 
     179                 :           2 :   name = valent_media_player_get_name (player);
     180                 :             : 
     181                 :             :   /* Convert seconds to milliseconds */
     182                 :           2 :   valent_packet_init (&builder, "kdeconnect.mpris");
     183                 :           2 :   json_builder_set_member_name (builder, "player");
     184                 :           2 :   json_builder_add_string_value (builder, name);
     185                 :           2 :   json_builder_set_member_name (builder, "pos");
     186                 :           2 :   json_builder_add_int_value (builder, (int64_t)(position * 1000L));
     187                 :           2 :   packet = valent_packet_end (&builder);
     188                 :             : 
     189         [ +  - ]:           2 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     190                 :           2 : }
     191                 :             : 
     192                 :             : static void
     193                 :          21 : on_player_changed (ValentMediaPlayer *player,
     194                 :             :                    GParamSpec        *pspec,
     195                 :             :                    ValentMprisPlugin *self)
     196                 :             : {
     197         [ +  - ]:          21 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     198                 :             : 
     199         [ +  + ]:          21 :   if (g_str_equal (pspec->name, "position"))
     200                 :             :     {
     201                 :           2 :       double position = 0.0;
     202                 :             : 
     203                 :           2 :       position = valent_media_player_get_position (player);
     204                 :           2 :       on_player_seeked (player, position, self);
     205                 :             :     }
     206                 :             :   else
     207                 :             :     {
     208                 :          19 :       g_hash_table_add (self->pending, player);
     209         [ +  + ]:          19 :       if (self->flush_id == 0)
     210                 :           9 :         self->flush_id = g_idle_add (valent_mpris_plugin_flush, self);
     211                 :             :     }
     212                 :          21 : }
     213                 :             : 
     214                 :             : static void
     215                 :           1 : on_player_destroy (ValentMediaPlayer *player,
     216                 :             :                    ValentMprisPlugin *self)
     217                 :             : {
     218                 :           1 :   g_hash_table_remove (self->pending, player);
     219                 :           1 :   g_ptr_array_remove (self->players, player);
     220                 :             : 
     221                 :           1 :   self->pending_list = TRUE;
     222         [ -  + ]:           1 :   if (self->flush_id == 0)
     223                 :           0 :     self->flush_id = g_idle_add (valent_mpris_plugin_flush, self);
     224                 :           1 : }
     225                 :             : 
     226                 :             : static void
     227                 :           4 : on_players_changed (GListModel        *list,
     228                 :             :                     unsigned int       position,
     229                 :             :                     unsigned int       removed,
     230                 :             :                     unsigned int       added,
     231                 :             :                     ValentMprisPlugin *self)
     232                 :             : {
     233         [ +  + ]:           5 :   for (unsigned int i = 0; i < added; i++)
     234                 :             :     {
     235                 :           1 :       g_autoptr (ValentMediaPlayer) player = NULL;
     236                 :             : 
     237                 :           1 :       player = g_list_model_get_item (list, position + i);
     238                 :           1 :       g_signal_connect_object (player,
     239                 :             :                                "notify",
     240                 :             :                                G_CALLBACK (on_player_changed),
     241                 :             :                                self,
     242                 :             :                                G_CONNECT_DEFAULT);
     243                 :           1 :       g_signal_connect_object (player,
     244                 :             :                                "destroy",
     245                 :             :                                G_CALLBACK (on_player_destroy),
     246                 :             :                                self,
     247                 :             :                                G_CONNECT_DEFAULT);
     248         [ +  - ]:           1 :       g_ptr_array_add (self->players, player);
     249                 :             :     }
     250                 :             : 
     251                 :           4 :   self->pending_list = TRUE;
     252         [ +  - ]:           4 :   if (self->flush_id == 0)
     253                 :           4 :     self->flush_id = g_idle_add (valent_mpris_plugin_flush, self);
     254                 :           4 : }
     255                 :             : 
     256                 :             : static void
     257                 :           6 : on_adapters_changed (GListModel        *list,
     258                 :             :                      unsigned int       position,
     259                 :             :                      unsigned int       removed,
     260                 :             :                      unsigned int       added,
     261                 :             :                      ValentMprisPlugin *self)
     262                 :             : {
     263         [ +  - ]:           6 :   g_assert (VALENT_IS_MEDIA (list));
     264         [ +  - ]:           6 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     265                 :             : 
     266         [ +  + ]:          12 :   for (unsigned int i = 0; i < added; i++)
     267                 :             :     {
     268                 :           6 :       g_autoptr (ValentMediaAdapter) adapter = NULL;
     269                 :             : 
     270                 :           6 :       adapter = g_list_model_get_item (list, position + i);
     271         [ +  + ]:           6 :       if (VDP_IS_MPRIS_ADAPTER (adapter))
     272         [ +  - ]:           3 :         continue;
     273                 :             : 
     274                 :           3 :       g_signal_connect_object (adapter,
     275                 :             :                                "items-changed",
     276                 :             :                                G_CALLBACK (on_players_changed),
     277                 :             :                                self,
     278                 :             :                                G_CONNECT_DEFAULT);
     279         [ +  - ]:           3 :       on_players_changed (G_LIST_MODEL (adapter),
     280                 :             :                           0,
     281                 :             :                           0,
     282                 :             :                           g_list_model_get_n_items (G_LIST_MODEL (adapter)),
     283                 :             :                           self);
     284                 :             :     }
     285                 :           6 : }
     286                 :             : 
     287                 :             : static void
     288                 :          14 : valent_mpris_plugin_watch_media (ValentMprisPlugin *self,
     289                 :             :                                  gboolean           watch)
     290                 :             : {
     291                 :          14 :   ValentMedia *media = valent_media_get_default ();
     292                 :             : 
     293         [ +  + ]:          14 :   if (self->media_watch == watch)
     294                 :             :     return;
     295                 :             : 
     296         [ +  + ]:           6 :   if (watch)
     297                 :             :     {
     298                 :           3 :       g_signal_connect_object (media,
     299                 :             :                                "items-changed",
     300                 :             :                                G_CALLBACK (on_adapters_changed),
     301                 :             :                                self,
     302                 :             :                                G_CONNECT_DEFAULT);
     303                 :           3 :       on_adapters_changed (G_LIST_MODEL (media),
     304                 :             :                            0,
     305                 :             :                            0,
     306                 :             :                            g_list_model_get_n_items (G_LIST_MODEL (media)),
     307                 :             :                            self);
     308                 :             : 
     309         [ +  - ]:           3 :       if (self->adapter == NULL)
     310                 :             :         {
     311                 :           3 :           ValentDevice *device = NULL;
     312                 :             : 
     313                 :           3 :           device = valent_resource_get_source (VALENT_RESOURCE (self));
     314                 :           3 :           self->adapter = vdp_mpris_adapter_new (device);
     315                 :           3 :           valent_component_export_adapter (VALENT_COMPONENT (media),
     316                 :             :                                            VALENT_EXTENSION (self->adapter));
     317                 :             :         }
     318                 :             :     }
     319                 :             :   else
     320                 :             :     {
     321                 :           3 :       unsigned int n_adapters = 0;
     322                 :             : 
     323                 :           3 :       n_adapters = g_list_model_get_n_items (G_LIST_MODEL (media));
     324         [ +  + ]:           9 :       for (unsigned int i = 0; i < n_adapters; i++)
     325                 :             :         {
     326                 :           6 :           g_autoptr (ValentMediaAdapter) adapter = NULL;
     327                 :             : 
     328                 :           6 :           adapter = g_list_model_get_item (G_LIST_MODEL (media), i);
     329         [ +  - ]:           6 :           g_signal_handlers_disconnect_by_data (adapter, self);
     330                 :             :         }
     331                 :             : 
     332         [ -  + ]:           3 :       for (unsigned int i = 0; i < self->players->len; i++)
     333                 :             :         {
     334                 :           0 :           ValentMediaPlayer *player = NULL;
     335                 :             : 
     336                 :           0 :           player = g_ptr_array_index (self->players, i);
     337                 :           0 :           g_signal_handlers_disconnect_by_data (player, self);
     338                 :             :         }
     339                 :             : 
     340                 :           3 :       g_hash_table_remove_all (self->pending);
     341                 :           3 :       g_ptr_array_remove_range (self->players, 0, self->players->len);
     342         [ +  + ]:           3 :       g_clear_handle_id (&self->flush_id, g_source_remove);
     343                 :           3 :       g_signal_handlers_disconnect_by_data (media, self);
     344                 :             : 
     345         [ +  - ]:           3 :       if (self->adapter != NULL)
     346                 :             :         {
     347                 :           3 :           valent_component_unexport_adapter (VALENT_COMPONENT (media),
     348                 :             :                                              VALENT_EXTENSION (self->adapter));
     349         [ +  - ]:           3 :           g_clear_object (&self->adapter);
     350                 :             :         }
     351                 :             :     }
     352                 :             : 
     353                 :           6 :   self->media_watch = watch;
     354                 :             : }
     355                 :             : 
     356                 :             : static void
     357                 :           5 : valent_mpris_plugin_handle_action (ValentMprisPlugin *self,
     358                 :             :                                    ValentMediaPlayer *player,
     359                 :             :                                    const char        *action)
     360                 :             : {
     361         [ +  - ]:           5 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     362         [ -  + ]:           5 :   g_assert (VALENT_IS_MEDIA_PLAYER (player));
     363   [ +  -  -  + ]:           5 :   g_assert (action && *action);
     364                 :             : 
     365         [ +  + ]:           5 :   if (g_str_equal (action, "Next"))
     366                 :           1 :     valent_media_player_next (player);
     367                 :             : 
     368         [ +  + ]:           4 :   else if (g_str_equal (action, "Pause"))
     369                 :           1 :     valent_media_player_pause (player);
     370                 :             : 
     371         [ +  + ]:           3 :   else if (g_str_equal (action, "Play"))
     372                 :           1 :     valent_media_player_play (player);
     373                 :             : 
     374         [ -  + ]:           2 :   else if (g_str_equal (action, "PlayPause"))
     375   [ #  #  #  #  :           0 :     valent_mpris_play_pause (player);
                   #  # ]
     376                 :             : 
     377         [ +  + ]:           2 :   else if (g_str_equal (action, "Previous"))
     378                 :           1 :     valent_media_player_previous (player);
     379                 :             : 
     380         [ +  - ]:           1 :   else if (g_str_equal (action, "Stop"))
     381                 :           1 :     valent_media_player_stop (player);
     382                 :             : 
     383                 :             :   else
     384                 :           0 :     g_warning ("%s(): Unknown action: %s", G_STRFUNC, action);
     385                 :           5 : }
     386                 :             : 
     387                 :             : static void
     388                 :          12 : valent_mpris_plugin_handle_mpris_request (ValentMprisPlugin *self,
     389                 :             :                                           JsonNode          *packet)
     390                 :             : {
     391                 :          12 :   ValentMediaPlayer *player = NULL;
     392                 :          12 :   const char *name;
     393                 :          12 :   const char *action;
     394                 :          12 :   const char *url;
     395                 :          12 :   int64_t offset_us;
     396                 :          12 :   int64_t position;
     397                 :          12 :   gboolean request_now_playing;
     398                 :          12 :   gboolean request_volume;
     399                 :          12 :   const char *loop_status;
     400                 :          12 :   ValentMediaRepeat repeat;
     401                 :          12 :   gboolean shuffle;
     402                 :          12 :   int64_t volume;
     403                 :             : 
     404         [ +  - ]:          12 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     405                 :             : 
     406                 :             :   /* Start by checking for a player */
     407         [ +  + ]:          12 :   if (valent_packet_get_string (packet, "player", &name))
     408                 :          11 :     player = valent_mpris_plugin_lookup_player (self, name);
     409                 :             : 
     410   [ +  -  -  + ]:          11 :   if (player == NULL || valent_packet_check_field (packet, "requestPlayerList"))
     411                 :             :     {
     412                 :           1 :       valent_mpris_plugin_send_player_list (self);
     413                 :           1 :       return;
     414                 :             :     }
     415                 :             : 
     416                 :             :   /* A request for a player's status */
     417                 :          11 :   request_now_playing = valent_packet_check_field (packet, "requestNowPlaying");
     418                 :          11 :   request_volume = valent_packet_check_field (packet, "requestVolume");
     419                 :             : 
     420         [ +  + ]:          11 :   if (request_now_playing || request_volume)
     421                 :           1 :     valent_mpris_plugin_send_player_info (self,
     422                 :             :                                           player,
     423                 :             :                                           request_now_playing,
     424                 :             :                                           request_volume);
     425                 :             : 
     426         [ +  + ]:          11 :   if (valent_packet_get_string (packet, "action", &action))
     427                 :           5 :     valent_mpris_plugin_handle_action (self, player, action);
     428                 :             : 
     429                 :             :   /* A request to change the relative position (microseconds to seconds) */
     430         [ +  + ]:          11 :   if (valent_packet_get_int (packet, "Seek", &offset_us))
     431                 :           1 :     valent_media_player_seek (player, offset_us / G_TIME_SPAN_SECOND);
     432                 :             : 
     433                 :             :   /* A request to change the absolute position (milliseconds to seconds) */
     434         [ -  + ]:          11 :   if (valent_packet_get_int (packet, "SetPosition", &position))
     435                 :           0 :     valent_media_player_set_position (player, position / 1000L);
     436                 :             : 
     437         [ +  + ]:          11 :   if (valent_packet_get_string (packet, "setLoopStatus", &loop_status))
     438                 :             :     {
     439                 :           1 :       repeat = valent_mpris_repeat_from_string (loop_status);
     440                 :           1 :       valent_media_player_set_repeat (player, repeat);
     441                 :             :     }
     442                 :             : 
     443         [ +  + ]:          11 :   if (valent_packet_get_boolean (packet, "setShuffle", &shuffle))
     444                 :           1 :     valent_media_player_set_shuffle (player, shuffle);
     445                 :             : 
     446         [ +  + ]:          11 :   if (valent_packet_get_int (packet, "setVolume", &volume))
     447                 :           1 :     valent_media_player_set_volume (player, volume / 100.0);
     448                 :             : 
     449         [ +  + ]:          11 :   if (valent_packet_get_string (packet, "albumArtUrl", &url))
     450                 :           1 :     valent_mpris_plugin_send_album_art (self, player, url);
     451                 :             : }
     452                 :             : 
     453                 :             : static void
     454                 :          10 : valent_mpris_plugin_send_player_info (ValentMprisPlugin *self,
     455                 :             :                                       ValentMediaPlayer *player,
     456                 :             :                                       gboolean           request_now_playing,
     457                 :             :                                       gboolean           request_volume)
     458                 :             : {
     459                 :          20 :   g_autoptr (JsonBuilder) builder = NULL;
     460         [ -  + ]:          10 :   g_autoptr (JsonNode) response = NULL;
     461                 :          10 :   const char *name;
     462                 :             : 
     463         [ +  - ]:          10 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     464         [ -  + ]:          10 :   g_assert (VALENT_IS_MEDIA_PLAYER (player));
     465                 :             : 
     466                 :          10 :   name = valent_media_player_get_name (player);
     467                 :             : 
     468                 :          10 :   valent_packet_init (&builder, "kdeconnect.mpris");
     469                 :          10 :   json_builder_set_member_name (builder, "player");
     470                 :          10 :   json_builder_add_string_value (builder, name);
     471                 :             : 
     472                 :             :   /* Player State & Metadata */
     473         [ +  - ]:          10 :   if (request_now_playing)
     474                 :             :     {
     475                 :          10 :       ValentMediaActions flags;
     476                 :          10 :       ValentMediaRepeat repeat;
     477                 :          10 :       gboolean is_playing;
     478                 :          10 :       double position;
     479                 :          10 :       gboolean shuffle;
     480                 :          10 :       const char *loop_status = "None";
     481                 :          10 :       g_autoptr (GVariant) metadata = NULL;
     482         [ +  - ]:          10 :       g_autofree char *artist = NULL;
     483                 :          10 :       const char *title = NULL;
     484                 :             : 
     485                 :             :       /* Player State */
     486                 :          10 :       flags = valent_media_player_get_flags (player);
     487                 :          10 :       json_builder_set_member_name (builder, "canPause");
     488                 :          10 :       json_builder_add_boolean_value (builder, (flags & VALENT_MEDIA_ACTION_PAUSE) != 0);
     489                 :          10 :       json_builder_set_member_name (builder, "canPlay");
     490                 :          10 :       json_builder_add_boolean_value (builder, (flags & VALENT_MEDIA_ACTION_PLAY) != 0);
     491                 :          10 :       json_builder_set_member_name (builder, "canGoNext");
     492                 :          10 :       json_builder_add_boolean_value (builder, (flags & VALENT_MEDIA_ACTION_NEXT) != 0);
     493                 :          10 :       json_builder_set_member_name (builder, "canGoPrevious");
     494                 :          10 :       json_builder_add_boolean_value (builder,(flags & VALENT_MEDIA_ACTION_PREVIOUS) != 0);
     495                 :          10 :       json_builder_set_member_name (builder, "canSeek");
     496                 :          10 :       json_builder_add_boolean_value (builder, (flags & VALENT_MEDIA_ACTION_SEEK) != 0);
     497                 :             : 
     498                 :          10 :       repeat = valent_media_player_get_repeat (player);
     499                 :          10 :       loop_status = valent_mpris_repeat_to_string (repeat);
     500                 :          10 :       json_builder_set_member_name (builder, "loopStatus");
     501                 :          10 :       json_builder_add_string_value (builder, loop_status);
     502                 :             : 
     503                 :          10 :       shuffle = valent_media_player_get_shuffle (player);
     504                 :          10 :       json_builder_set_member_name (builder, "shuffle");
     505                 :          10 :       json_builder_add_boolean_value (builder, shuffle);
     506                 :             : 
     507                 :          10 :       is_playing = valent_media_player_get_state (player) == VALENT_MEDIA_STATE_PLAYING;
     508                 :          10 :       json_builder_set_member_name (builder, "isPlaying");
     509                 :          10 :       json_builder_add_boolean_value (builder, is_playing);
     510                 :             : 
     511                 :             :       /* Convert seconds to milliseconds */
     512                 :          10 :       position = valent_media_player_get_position (player);
     513                 :          10 :       json_builder_set_member_name (builder, "pos");
     514                 :          10 :       json_builder_add_int_value (builder, (int64_t)(position * 1000L));
     515                 :             : 
     516                 :             :       /* Track Metadata
     517                 :             :        *
     518                 :             :        * See: https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/
     519                 :             :        */
     520         [ +  - ]:          10 :       if ((metadata = valent_media_player_get_metadata (player)) != NULL)
     521                 :             :         {
     522                 :          10 :           g_autofree const char **artists = NULL;
     523                 :          10 :           int64_t length_us;
     524                 :          10 :           const char *art_url;
     525                 :          10 :           const char *album;
     526                 :             : 
     527         [ +  + ]:          10 :           if (g_variant_lookup (metadata, "xesam:artist", "^a&s", &artists) &&
     528   [ +  -  +  - ]:           4 :               artists[0] != NULL && *artists[0] != '\0')
     529                 :             :             {
     530                 :           4 :               artist = g_strjoinv (", ", (char **)artists);
     531                 :           4 :               json_builder_set_member_name (builder, "artist");
     532                 :           4 :               json_builder_add_string_value (builder, artist);
     533                 :             :             }
     534                 :             : 
     535         [ +  + ]:          10 :           if (g_variant_lookup (metadata, "xesam:title", "&s", &title) &&
     536         [ +  - ]:           4 :               *title != '\0')
     537                 :             :             {
     538                 :           4 :               json_builder_set_member_name (builder, "title");
     539                 :           4 :               json_builder_add_string_value (builder, title);
     540                 :             :             }
     541                 :             : 
     542         [ +  + ]:          10 :           if (g_variant_lookup (metadata, "xesam:album", "&s", &album) &&
     543         [ +  - ]:           4 :               *album != '\0')
     544                 :             :             {
     545                 :           4 :               json_builder_set_member_name (builder, "album");
     546                 :           4 :               json_builder_add_string_value (builder, album);
     547                 :             :             }
     548                 :             : 
     549                 :             :           /* Convert microseconds to milliseconds */
     550         [ +  + ]:          10 :           if (g_variant_lookup (metadata, "mpris:length", "x", &length_us))
     551                 :             :             {
     552                 :           4 :               json_builder_set_member_name (builder, "length");
     553                 :           4 :               json_builder_add_int_value (builder, length_us / 1000L);
     554                 :             :             }
     555                 :             : 
     556         [ +  + ]:          10 :           if (g_variant_lookup (metadata, "mpris:artUrl", "&s", &art_url))
     557                 :             :             {
     558                 :           1 :               json_builder_set_member_name (builder, "albumArtUrl");
     559                 :           1 :               json_builder_add_string_value (builder, art_url);
     560                 :             :             }
     561                 :             :         }
     562                 :             :     }
     563                 :             : 
     564                 :             :   /* Volume Level */
     565         [ +  - ]:          10 :   if (request_volume)
     566                 :             :     {
     567                 :          10 :       int64_t level;
     568                 :             : 
     569                 :          10 :       level = (int64_t)floor (valent_media_player_get_volume (player) * 100);
     570                 :          10 :       json_builder_set_member_name (builder, "volume");
     571                 :          10 :       json_builder_add_int_value (builder, level);
     572                 :             :     }
     573                 :             : 
     574                 :             :   /* Send Response */
     575                 :          10 :   response = valent_packet_end (&builder);
     576         [ +  - ]:          10 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), response);
     577                 :          10 : }
     578                 :             : 
     579                 :             : static void
     580                 :           3 : valent_mpris_plugin_send_player_list (ValentMprisPlugin *self)
     581                 :             : {
     582                 :           6 :   g_autoptr (JsonBuilder) builder = NULL;
     583         [ -  + ]:           3 :   g_autoptr (JsonNode) packet = NULL;
     584                 :             : 
     585         [ +  - ]:           3 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     586                 :             : 
     587                 :           3 :   valent_packet_init (&builder, "kdeconnect.mpris");
     588                 :             : 
     589                 :             :   /* Player List */
     590                 :           3 :   json_builder_set_member_name (builder, "playerList");
     591                 :           3 :   json_builder_begin_array (builder);
     592                 :             : 
     593         [ +  + ]:           5 :   for (unsigned int i = 0; i < self->players->len; i++)
     594                 :             :     {
     595                 :           2 :       ValentMediaPlayer *player = g_ptr_array_index (self->players, i);
     596                 :           2 :       const char *name = valent_media_player_get_name (player);
     597                 :             : 
     598         [ +  - ]:           2 :       if (name != NULL)
     599                 :           2 :         json_builder_add_string_value (builder, name);
     600                 :             :     }
     601                 :             : 
     602                 :           3 :   json_builder_end_array (builder);
     603                 :             : 
     604                 :             :   /* Indicate that the remote device may send us album art payloads */
     605                 :           3 :   json_builder_set_member_name (builder, "supportAlbumArtPayload");
     606                 :           3 :   json_builder_add_boolean_value (builder, TRUE);
     607                 :             : 
     608                 :           3 :   packet = valent_packet_end (&builder);
     609         [ +  - ]:           3 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     610                 :           3 : }
     611                 :             : 
     612                 :             : /*
     613                 :             :  * ValentDevicePlugin
     614                 :             :  */
     615                 :             : static void
     616                 :          10 : valent_mpris_plugin_update_state (ValentDevicePlugin *plugin,
     617                 :             :                                   ValentDeviceState   state)
     618                 :             : {
     619                 :          10 :   ValentMprisPlugin *self = VALENT_MPRIS_PLUGIN (plugin);
     620                 :          10 :   gboolean available;
     621                 :             : 
     622         [ +  - ]:          10 :   g_assert (VALENT_IS_MPRIS_PLUGIN (self));
     623                 :             : 
     624                 :          10 :   available = (state & VALENT_DEVICE_STATE_CONNECTED) != 0 &&
     625                 :             :               (state & VALENT_DEVICE_STATE_PAIRED) != 0;
     626                 :             : 
     627                 :          10 :   valent_mpris_plugin_watch_media (self, available);
     628                 :          10 : }
     629                 :             : 
     630                 :             : static void
     631                 :          17 : valent_mpris_plugin_handle_packet (ValentDevicePlugin *plugin,
     632                 :             :                                    const char         *type,
     633                 :             :                                    JsonNode           *packet)
     634                 :             : {
     635                 :          17 :   ValentMprisPlugin *self = VALENT_MPRIS_PLUGIN (plugin);
     636                 :             : 
     637         [ +  - ]:          17 :   g_assert (VALENT_IS_MPRIS_PLUGIN (plugin));
     638         [ -  + ]:          17 :   g_assert (type != NULL);
     639         [ -  + ]:          17 :   g_assert (VALENT_IS_PACKET (packet));
     640                 :             : 
     641         [ +  + ]:          17 :   if (g_str_equal (type, "kdeconnect.mpris"))
     642                 :           5 :     vdp_mpris_adapter_handle_packet (VDP_MPRIS_ADAPTER (self->adapter), packet);
     643         [ +  - ]:          12 :   else if (g_str_equal (type, "kdeconnect.mpris.request"))
     644                 :          12 :     valent_mpris_plugin_handle_mpris_request (self, packet);
     645                 :             :   else
     646                 :           0 :     g_assert_not_reached ();
     647                 :          17 : }
     648                 :             : 
     649                 :             : /*
     650                 :             :  * ValentObject
     651                 :             :  */
     652                 :             : static void
     653                 :           4 : valent_mpris_plugin_destroy (ValentObject *object)
     654                 :             : {
     655                 :           4 :   ValentMprisPlugin *self = VALENT_MPRIS_PLUGIN (object);
     656                 :             : 
     657                 :           4 :   valent_mpris_plugin_watch_media (self, FALSE);
     658         [ +  + ]:           4 :   g_clear_pointer (&self->players, g_ptr_array_unref);
     659         [ +  + ]:           4 :   g_clear_pointer (&self->pending, g_hash_table_unref);
     660         [ +  + ]:           4 :   g_clear_pointer (&self->transfers, g_hash_table_unref);
     661                 :             : 
     662                 :           4 :   VALENT_OBJECT_CLASS (valent_mpris_plugin_parent_class)->destroy (object);
     663                 :           4 : }
     664                 :             : 
     665                 :             : /*
     666                 :             :  * GObject
     667                 :             :  */
     668                 :             : static void
     669                 :           2 : valent_mpris_plugin_class_init (ValentMprisPluginClass *klass)
     670                 :             : {
     671                 :           2 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     672                 :           2 :   ValentDevicePluginClass *plugin_class = VALENT_DEVICE_PLUGIN_CLASS (klass);
     673                 :             : 
     674                 :           2 :   vobject_class->destroy = valent_mpris_plugin_destroy;
     675                 :             : 
     676                 :           2 :   plugin_class->handle_packet = valent_mpris_plugin_handle_packet;
     677                 :           2 :   plugin_class->update_state = valent_mpris_plugin_update_state;
     678                 :             : }
     679                 :             : 
     680                 :             : static void
     681                 :           3 : valent_mpris_plugin_init (ValentMprisPlugin *self)
     682                 :             : {
     683                 :           3 :   self->transfers = g_hash_table_new_full (g_str_hash,
     684                 :             :                                            g_str_equal,
     685                 :             :                                            g_free,
     686                 :             :                                            g_object_unref);
     687                 :           3 :   self->players = g_ptr_array_new ();
     688                 :           3 :   self->pending = g_hash_table_new (NULL, NULL);
     689                 :           3 : }
     690                 :             : 
        

Generated by: LCOV version 2.0-1