LCOV - code coverage report
Current view: top level - src/plugins/mpris - valent-mpris-device.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 92.5 % 348 322
Test Date: 2024-04-16 07:28:14 Functions: 97.4 % 38 37
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55.3 % 170 94

             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-device"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <math.h>
       9                 :             : 
      10                 :             : #include <gio/gio.h>
      11                 :             : #include <valent.h>
      12                 :             : 
      13                 :             : #include "valent-mpris-device.h"
      14                 :             : #include "valent-mpris-utils.h"
      15                 :             : 
      16                 :             : 
      17                 :             : struct _ValentMprisDevice
      18                 :             : {
      19                 :             :   ValentMediaPlayer   parent_instance;
      20                 :             : 
      21                 :             :   ValentDevice       *device;
      22                 :             : 
      23                 :             :   ValentMediaActions  flags;
      24                 :             :   char               *name;
      25                 :             :   GVariant           *metadata;
      26                 :             :   double              position;
      27                 :             :   double              position_time;
      28                 :             :   ValentMediaRepeat   repeat;
      29                 :             :   unsigned int        shuffle : 1;
      30                 :             :   ValentMediaState    state;
      31                 :             :   double              volume;
      32                 :             : };
      33                 :             : 
      34   [ +  +  +  - ]:          23 : G_DEFINE_FINAL_TYPE (ValentMprisDevice, valent_mpris_device, VALENT_TYPE_MEDIA_PLAYER)
      35                 :             : 
      36                 :             : 
      37                 :             : enum {
      38                 :             :   PROP_0,
      39                 :             :   PROP_DEVICE,
      40                 :             :   N_PROPERTIES
      41                 :             : };
      42                 :             : 
      43                 :             : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      44                 :             : 
      45                 :             : 
      46                 :             : /*
      47                 :             :  * ValentMediaPlayer
      48                 :             :  */
      49                 :             : static ValentMediaActions
      50                 :           7 : valent_mpris_device_get_flags (ValentMediaPlayer *player)
      51                 :             : {
      52                 :           7 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
      53                 :             : 
      54                 :           7 :   return self->flags;
      55                 :             : }
      56                 :             : 
      57                 :             : static GVariant *
      58                 :           4 : valent_mpris_device_get_metadata (ValentMediaPlayer *player)
      59                 :             : {
      60                 :           4 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
      61                 :             : 
      62         [ +  + ]:           4 :   if (self->metadata)
      63                 :           3 :     return g_variant_ref (self->metadata);
      64                 :             : 
      65                 :             :   return NULL;
      66                 :             : }
      67                 :             : 
      68                 :             : static const char *
      69                 :           6 : valent_mpris_device_get_name (ValentMediaPlayer *player)
      70                 :             : {
      71                 :           6 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
      72                 :             : 
      73                 :           6 :   return self->name;
      74                 :             : }
      75                 :             : 
      76                 :             : static double
      77                 :           3 : valent_mpris_device_get_position (ValentMediaPlayer *player)
      78                 :             : {
      79                 :           3 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
      80                 :             : 
      81         [ -  + ]:           3 :   if (self->state == VALENT_MEDIA_STATE_PLAYING)
      82                 :           0 :     return self->position + (valent_mpris_get_time () - self->position_time);
      83                 :             : 
      84                 :           3 :   return self->position;
      85                 :             : }
      86                 :             : 
      87                 :             : static void
      88                 :           1 : valent_mpris_device_set_position (ValentMediaPlayer *player,
      89                 :             :                                   double             position)
      90                 :             : {
      91                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
      92                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
      93         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
      94                 :             : 
      95                 :             :   /* Convert seconds to milliseconds */
      96                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
      97                 :           1 :   json_builder_set_member_name (builder, "player");
      98                 :           1 :   json_builder_add_string_value (builder, self->name);
      99                 :           1 :   json_builder_set_member_name (builder, "SetPosition");
     100                 :           1 :   json_builder_add_int_value (builder, position * 1000L);
     101                 :           1 :   packet = valent_packet_end (&builder);
     102                 :             : 
     103         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     104                 :           1 : }
     105                 :             : 
     106                 :             : static ValentMediaRepeat
     107                 :           1 : valent_mpris_device_get_repeat (ValentMediaPlayer *player)
     108                 :             : {
     109                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     110                 :             : 
     111                 :           1 :   return self->repeat;
     112                 :             : }
     113                 :             : 
     114                 :             : static void
     115                 :           1 : valent_mpris_device_set_repeat (ValentMediaPlayer *player,
     116                 :             :                                 ValentMediaRepeat  repeat)
     117                 :             : {
     118                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     119                 :           1 :   const char *loop_status = NULL;
     120                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     121         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     122                 :             : 
     123                 :           1 :   loop_status = valent_mpris_repeat_to_string (repeat);
     124                 :             : 
     125                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     126                 :           1 :   json_builder_set_member_name (builder, "player");
     127                 :           1 :   json_builder_add_string_value (builder, self->name);
     128                 :           1 :   json_builder_set_member_name (builder, "setLoopStatus");
     129                 :           1 :   json_builder_add_string_value (builder, loop_status);
     130                 :           1 :   packet = valent_packet_end (&builder);
     131                 :             : 
     132         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     133                 :           1 : }
     134                 :             : 
     135                 :             : static gboolean
     136                 :           1 : valent_mpris_device_get_shuffle (ValentMediaPlayer *player)
     137                 :             : {
     138                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     139                 :             : 
     140                 :           1 :   return self->shuffle;
     141                 :             : }
     142                 :             : 
     143                 :             : static void
     144                 :           1 : valent_mpris_device_set_shuffle (ValentMediaPlayer *player,
     145                 :             :                                  gboolean           shuffle)
     146                 :             : {
     147                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     148                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     149         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     150                 :             : 
     151                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     152                 :           1 :   json_builder_set_member_name (builder, "player");
     153                 :           1 :   json_builder_add_string_value (builder, self->name);
     154                 :           1 :   json_builder_set_member_name (builder, "setShuffle");
     155                 :           1 :   json_builder_add_boolean_value (builder, shuffle);
     156                 :           1 :   packet = valent_packet_end (&builder);
     157                 :             : 
     158         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     159                 :           1 : }
     160                 :             : 
     161                 :             : static ValentMediaState
     162                 :           3 : valent_mpris_device_get_state (ValentMediaPlayer *player)
     163                 :             : {
     164                 :           3 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     165                 :             : 
     166                 :           3 :   return self->state;
     167                 :             : }
     168                 :             : 
     169                 :             : static double
     170                 :           1 : valent_mpris_device_get_volume (ValentMediaPlayer *player)
     171                 :             : {
     172                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     173                 :             : 
     174                 :           1 :   return self->volume;
     175                 :             : }
     176                 :             : 
     177                 :             : static void
     178                 :           1 : valent_mpris_device_set_volume (ValentMediaPlayer *player,
     179                 :             :                                 double             volume)
     180                 :             : {
     181                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     182                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     183         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     184                 :             : 
     185                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     186                 :           1 :   json_builder_set_member_name (builder, "player");
     187                 :           1 :   json_builder_add_string_value (builder, self->name);
     188                 :           1 :   json_builder_set_member_name (builder, "setVolume");
     189                 :           1 :   json_builder_add_int_value (builder, floor (volume * 100));
     190                 :           1 :   packet = valent_packet_end (&builder);
     191                 :             : 
     192         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     193                 :           1 : }
     194                 :             : 
     195                 :             : static void
     196                 :           1 : valent_mpris_device_next (ValentMediaPlayer *player)
     197                 :             : {
     198                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     199                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     200         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     201                 :             : 
     202                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     203                 :           1 :   json_builder_set_member_name (builder, "player");
     204                 :           1 :   json_builder_add_string_value (builder, self->name);
     205                 :           1 :   json_builder_set_member_name (builder, "action");
     206                 :           1 :   json_builder_add_string_value (builder, "Next");
     207                 :           1 :   packet = valent_packet_end (&builder);
     208                 :             : 
     209         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     210                 :           1 : }
     211                 :             : 
     212                 :             : static void
     213                 :           1 : valent_mpris_device_pause (ValentMediaPlayer *player)
     214                 :             : {
     215                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     216                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     217         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     218                 :             : 
     219                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     220                 :           1 :   json_builder_set_member_name (builder, "player");
     221                 :           1 :   json_builder_add_string_value (builder, self->name);
     222                 :           1 :   json_builder_set_member_name (builder, "action");
     223                 :           1 :   json_builder_add_string_value (builder, "Pause");
     224                 :           1 :   packet = valent_packet_end (&builder);
     225                 :             : 
     226         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     227                 :           1 : }
     228                 :             : 
     229                 :             : static void
     230                 :           1 : valent_mpris_device_play (ValentMediaPlayer *player)
     231                 :             : {
     232                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     233                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     234         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     235                 :             : 
     236                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     237                 :           1 :   json_builder_set_member_name (builder, "player");
     238                 :           1 :   json_builder_add_string_value (builder, self->name);
     239                 :           1 :   json_builder_set_member_name (builder, "action");
     240                 :           1 :   json_builder_add_string_value (builder, "Play");
     241                 :           1 :   packet = valent_packet_end (&builder);
     242                 :             : 
     243         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     244                 :           1 : }
     245                 :             : 
     246                 :             : #if 0
     247                 :             : static void
     248                 :             : valent_mpris_device_play_pause (ValentMediaPlayer *player)
     249                 :             : {
     250                 :             :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     251                 :             :   g_autoptr (JsonBuilder) builder = NULL;
     252                 :             :   g_autoptr (JsonNode) packet = NULL;
     253                 :             : 
     254                 :             :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     255                 :             :   json_builder_set_member_name (builder, "player");
     256                 :             :   json_builder_add_string_value (builder, self->name);
     257                 :             :   json_builder_set_member_name (builder, "action");
     258                 :             :   json_builder_add_string_value (builder, "PlayPause");
     259                 :             :   packet = valent_packet_end (&builder);
     260                 :             : 
     261                 :             :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     262                 :             : }
     263                 :             : #endif
     264                 :             : 
     265                 :             : static void
     266                 :           1 : valent_mpris_device_previous (ValentMediaPlayer *player)
     267                 :             : {
     268                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     269                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     270         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     271                 :             : 
     272                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     273                 :           1 :   json_builder_set_member_name (builder, "player");
     274                 :           1 :   json_builder_add_string_value (builder, self->name);
     275                 :           1 :   json_builder_set_member_name (builder, "action");
     276                 :           1 :   json_builder_add_string_value (builder, "Previous");
     277                 :           1 :   packet = valent_packet_end (&builder);
     278                 :             : 
     279         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     280                 :           1 : }
     281                 :             : 
     282                 :             : static void
     283                 :           1 : valent_mpris_device_seek (ValentMediaPlayer *player,
     284                 :             :                           double             offset)
     285                 :             : {
     286                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     287                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     288         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     289                 :             : 
     290                 :             :   /* Convert seconds to microseconds */
     291                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     292                 :           1 :   json_builder_set_member_name (builder, "player");
     293                 :           1 :   json_builder_add_string_value (builder, self->name);
     294                 :           1 :   json_builder_set_member_name (builder, "Seek");
     295                 :           1 :   json_builder_add_int_value (builder, offset * G_TIME_SPAN_SECOND);
     296                 :           1 :   packet = valent_packet_end (&builder);
     297                 :             : 
     298         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     299                 :           1 : }
     300                 :             : 
     301                 :             : static void
     302                 :           1 : valent_mpris_device_stop (ValentMediaPlayer *player)
     303                 :             : {
     304                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (player);
     305                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     306         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     307                 :             : 
     308                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     309                 :           1 :   json_builder_set_member_name (builder, "player");
     310                 :           1 :   json_builder_add_string_value (builder, self->name);
     311                 :           1 :   json_builder_set_member_name (builder, "action");
     312                 :           1 :   json_builder_add_string_value (builder, "Stop");
     313                 :           1 :   packet = valent_packet_end (&builder);
     314                 :             : 
     315         [ +  - ]:           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     316                 :           1 : }
     317                 :             : 
     318                 :             : static void
     319                 :           1 : valent_mpris_device_request_album_art (ValentMprisDevice *self,
     320                 :             :                                        const char        *url,
     321                 :             :                                        GVariantDict      *metadata)
     322                 :             : {
     323                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     324   [ -  -  -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     325                 :           1 :   ValentContext *context = NULL;
     326   [ -  -  +  - ]:           1 :   g_autoptr (GFile) file = NULL;
     327   [ -  -  +  - ]:           1 :   g_autofree char *filename = NULL;
     328                 :             : 
     329         [ +  - ]:           1 :   g_assert (VALENT_IS_MPRIS_DEVICE (self));
     330   [ +  -  -  + ]:           1 :   g_assert (url != NULL && *url != '\0');
     331         [ -  + ]:           1 :   g_assert (metadata != NULL);
     332                 :             : 
     333                 :           1 :   context = valent_device_get_context (self->device);
     334                 :           1 :   filename = g_compute_checksum_for_string (G_CHECKSUM_MD5, url, -1);
     335                 :           1 :   file = valent_context_get_cache_file (context, filename);
     336                 :             : 
     337                 :             :   /* If the album art has been cached, update the metadata dictionary */
     338         [ -  + ]:           1 :   if (g_file_query_exists (file, NULL))
     339                 :             :     {
     340                 :           0 :       g_autofree char *art_url = NULL;
     341                 :             : 
     342                 :           0 :       art_url = g_file_get_uri (file);
     343                 :           0 :       g_variant_dict_insert (metadata, "mpris:artUrl", "s", art_url);
     344                 :             : 
     345                 :           0 :       return;
     346                 :             :     }
     347                 :             : 
     348                 :             :   /* Request the album art payload */
     349                 :           1 :   valent_packet_init (&builder, "kdeconnect.mpris.request");
     350                 :           1 :   json_builder_set_member_name (builder, "player");
     351                 :           1 :   json_builder_add_string_value (builder, self->name);
     352                 :           1 :   json_builder_set_member_name (builder, "albumArtUrl");
     353                 :           1 :   json_builder_add_string_value (builder, url);
     354                 :           1 :   packet = valent_packet_end (&builder);
     355                 :             : 
     356                 :           1 :   valent_device_send_packet (self->device, packet, NULL, NULL, NULL);
     357                 :             : }
     358                 :             : 
     359                 :             : /*
     360                 :             :  * Private
     361                 :             :  */
     362                 :             : static void
     363                 :           2 : valent_mpris_device_update_flags (ValentMprisDevice  *player,
     364                 :             :                                   ValentMediaActions  flags)
     365                 :             : {
     366         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     367                 :             : 
     368         [ +  + ]:           2 :   if ((player->flags ^ flags) == 0)
     369                 :             :     return;
     370                 :             : 
     371                 :           1 :   player->flags = flags;
     372                 :           1 :   g_object_notify (G_OBJECT (player), "flags");
     373                 :             : }
     374                 :             : 
     375                 :             : static void
     376                 :           3 : valent_mpris_device_update_metadata (ValentMprisDevice *player,
     377                 :             :                                      GVariant          *value)
     378                 :             : {
     379                 :           6 :   g_autoptr (GVariant) metadata = NULL;
     380                 :             : 
     381         [ +  - ]:           3 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     382         [ -  + ]:           3 :   g_assert (value != NULL);
     383                 :             : 
     384         [ +  - ]:           3 :   if (player->metadata == value)
     385                 :             :     return;
     386                 :             : 
     387                 :           3 :   metadata = g_steal_pointer (&player->metadata);
     388                 :           3 :   player->metadata = g_variant_ref_sink (value);
     389         [ +  + ]:           3 :   g_object_notify (G_OBJECT (player), "metadata");
     390                 :             : }
     391                 :             : 
     392                 :             : static void
     393                 :           2 : valent_mpris_device_update_position (ValentMprisDevice *player,
     394                 :             :                                      int64_t            position)
     395                 :             : {
     396         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     397                 :             : 
     398                 :             :   /* Convert milliseconds to seconds */
     399                 :           2 :   player->position = position / 1000L;
     400                 :           2 :   player->position_time = valent_mpris_get_time ();
     401                 :           2 :   g_object_notify (G_OBJECT (player), "position");
     402                 :           2 : }
     403                 :             : 
     404                 :             : static void
     405                 :           2 : valent_mpris_device_update_repeat (ValentMprisDevice *player,
     406                 :             :                                    const char        *loop_status)
     407                 :             : {
     408                 :           2 :   ValentMediaRepeat repeat = VALENT_MEDIA_REPEAT_NONE;
     409                 :             : 
     410         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     411         [ -  + ]:           2 :   g_assert (loop_status != NULL);
     412                 :             : 
     413                 :           2 :   repeat = valent_mpris_repeat_from_string (loop_status);
     414                 :             : 
     415         [ -  + ]:           2 :   if (player->repeat == repeat)
     416                 :             :     return;
     417                 :             : 
     418                 :           0 :   player->repeat = repeat;
     419                 :           0 :   g_object_notify (G_OBJECT (player), "repeat");
     420                 :             : }
     421                 :             : 
     422                 :             : static void
     423                 :           2 : valent_mpris_device_update_shuffle (ValentMprisDevice *player,
     424                 :             :                                     gboolean           shuffle)
     425                 :             : {
     426         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     427                 :             : 
     428         [ -  + ]:           2 :   if (player->shuffle == shuffle)
     429                 :             :     return;
     430                 :             : 
     431                 :           0 :   player->shuffle = shuffle;
     432                 :           0 :   g_object_notify (G_OBJECT (player), "shuffle");
     433                 :             : }
     434                 :             : 
     435                 :             : static void
     436                 :           2 : valent_mpris_device_update_state (ValentMprisDevice *player,
     437                 :             :                                   const char        *playback_status)
     438                 :             : {
     439                 :           2 :   ValentMediaState state = VALENT_MEDIA_STATE_STOPPED;
     440                 :             : 
     441         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     442         [ -  + ]:           2 :   g_assert (playback_status != NULL);
     443                 :             : 
     444                 :           2 :   state = valent_mpris_state_from_string (playback_status);
     445                 :             : 
     446         [ +  - ]:           2 :   if (player->state == state)
     447                 :             :     return;
     448                 :             : 
     449                 :           2 :   player->state = state;
     450                 :             : 
     451         [ -  + ]:           2 :   if (player->state == VALENT_MEDIA_STATE_STOPPED)
     452                 :             :     {
     453                 :           0 :       player->position = 0.0;
     454                 :           0 :       player->position_time = 0;
     455                 :           0 :       g_object_notify (G_OBJECT (player), "position");
     456                 :             :     }
     457                 :             : 
     458                 :           2 :   g_object_notify (G_OBJECT (player), "state");
     459                 :             : }
     460                 :             : 
     461                 :             : static void
     462                 :           2 : valent_mpris_device_update_volume (ValentMprisDevice *player,
     463                 :             :                                    int64_t            volume)
     464                 :             : {
     465         [ +  - ]:           2 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     466                 :             : 
     467   [ -  +  -  + ]:           2 :   if (G_APPROX_VALUE (player->volume, volume / 100.0, 0.01))
     468                 :             :     return;
     469                 :             : 
     470         [ #  # ]:           0 :   player->volume = CLAMP ((volume / 100.0), 0.0, 1.0);
     471                 :           0 :   g_object_notify (G_OBJECT (player), "volume");
     472                 :             : }
     473                 :             : 
     474                 :             : /*
     475                 :             :  * GObject
     476                 :             :  */
     477                 :             : static void
     478                 :           1 : valent_mpris_device_finalize (GObject *object)
     479                 :             : {
     480                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (object);
     481                 :             : 
     482         [ +  - ]:           1 :   g_clear_object (&self->device);
     483         [ +  - ]:           1 :   g_clear_pointer (&self->name, g_free);
     484         [ +  - ]:           1 :   g_clear_pointer (&self->metadata, g_variant_unref);
     485                 :             : 
     486                 :           1 :   G_OBJECT_CLASS (valent_mpris_device_parent_class)->finalize (object);
     487                 :           1 : }
     488                 :             : 
     489                 :             : static void
     490                 :           0 : valent_mpris_device_get_property (GObject    *object,
     491                 :             :                                   guint       prop_id,
     492                 :             :                                   GValue     *value,
     493                 :             :                                   GParamSpec *pspec)
     494                 :             : {
     495                 :           0 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (object);
     496                 :             : 
     497         [ #  # ]:           0 :   switch (prop_id)
     498                 :             :     {
     499                 :           0 :     case PROP_DEVICE:
     500                 :           0 :       g_value_set_object (value, self->device);
     501                 :           0 :       break;
     502                 :             : 
     503                 :           0 :     default:
     504                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     505                 :             :     }
     506                 :           0 : }
     507                 :             : 
     508                 :             : static void
     509                 :           1 : valent_mpris_device_set_property (GObject      *object,
     510                 :             :                                   guint         prop_id,
     511                 :             :                                   const GValue *value,
     512                 :             :                                   GParamSpec   *pspec)
     513                 :             : {
     514                 :           1 :   ValentMprisDevice *self = VALENT_MPRIS_DEVICE (object);
     515                 :             : 
     516         [ +  - ]:           1 :   switch (prop_id)
     517                 :             :     {
     518                 :           1 :     case PROP_DEVICE:
     519                 :           1 :       self->device = g_value_dup_object (value);
     520                 :           1 :       break;
     521                 :             : 
     522                 :           0 :     default:
     523                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     524                 :             :     }
     525                 :           1 : }
     526                 :             : 
     527                 :             : static void
     528                 :           1 : valent_mpris_device_class_init (ValentMprisDeviceClass *klass)
     529                 :             : {
     530                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     531                 :           1 :   ValentMediaPlayerClass *player_class = VALENT_MEDIA_PLAYER_CLASS (klass);
     532                 :             : 
     533                 :           1 :   object_class->finalize = valent_mpris_device_finalize;
     534                 :           1 :   object_class->get_property = valent_mpris_device_get_property;
     535                 :           1 :   object_class->set_property = valent_mpris_device_set_property;
     536                 :             : 
     537                 :           1 :   player_class->get_flags = valent_mpris_device_get_flags;
     538                 :           1 :   player_class->get_metadata = valent_mpris_device_get_metadata;
     539                 :           1 :   player_class->get_name = valent_mpris_device_get_name;
     540                 :           1 :   player_class->get_position = valent_mpris_device_get_position;
     541                 :           1 :   player_class->set_position = valent_mpris_device_set_position;
     542                 :           1 :   player_class->get_repeat = valent_mpris_device_get_repeat;
     543                 :           1 :   player_class->set_repeat = valent_mpris_device_set_repeat;
     544                 :           1 :   player_class->get_shuffle = valent_mpris_device_get_shuffle;
     545                 :           1 :   player_class->set_shuffle = valent_mpris_device_set_shuffle;
     546                 :           1 :   player_class->get_state = valent_mpris_device_get_state;
     547                 :           1 :   player_class->get_volume = valent_mpris_device_get_volume;
     548                 :           1 :   player_class->set_volume = valent_mpris_device_set_volume;
     549                 :             : 
     550                 :           1 :   player_class->next = valent_mpris_device_next;
     551                 :           1 :   player_class->pause = valent_mpris_device_pause;
     552                 :           1 :   player_class->play = valent_mpris_device_play;
     553                 :           1 :   player_class->previous = valent_mpris_device_previous;
     554                 :           1 :   player_class->seek = valent_mpris_device_seek;
     555                 :           1 :   player_class->stop = valent_mpris_device_stop;
     556                 :             : 
     557                 :             :   /**
     558                 :             :    * ValentMprisDevice:device:
     559                 :             :    *
     560                 :             :    * The [class@Valent.Device] this player is for.
     561                 :             :    */
     562                 :           2 :   properties [PROP_DEVICE] =
     563                 :           1 :     g_param_spec_object ("device", NULL, NULL,
     564                 :             :                          VALENT_TYPE_DEVICE,
     565                 :             :                          (G_PARAM_READWRITE |
     566                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     567                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     568                 :             :                           G_PARAM_STATIC_STRINGS));
     569                 :             : 
     570                 :           1 :   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
     571                 :           1 : }
     572                 :             : 
     573                 :             : static void
     574                 :           1 : valent_mpris_device_init (ValentMprisDevice *self)
     575                 :             : {
     576                 :           1 :   self->name = g_strdup ("Media Player");
     577                 :           1 :   self->volume = 1.0;
     578                 :           1 :   self->state = VALENT_MEDIA_STATE_STOPPED;
     579                 :           1 : }
     580                 :             : 
     581                 :             : /**
     582                 :             :  * valent_mpris_device_new:
     583                 :             :  * @device: a `ValentDevice`
     584                 :             :  *
     585                 :             :  * Get the `ValentMprisDevice` instance.
     586                 :             :  *
     587                 :             :  * Returns: (transfer full) (nullable): a `ValentMprisDevice`
     588                 :             :  */
     589                 :             : ValentMprisDevice *
     590                 :           1 : valent_mpris_device_new (ValentDevice *device)
     591                 :             : {
     592                 :           1 :   return g_object_new (VALENT_TYPE_MPRIS_DEVICE,
     593                 :             :                        "device", device,
     594                 :             :                        NULL);
     595                 :             : }
     596                 :             : 
     597                 :             : /**
     598                 :             :  * valent_media_player_update_packet:
     599                 :             :  * @player: a `ValentMprisDevice`
     600                 :             :  * @packet: a KDE Connect packet
     601                 :             :  *
     602                 :             :  * A convenience method for updating the internal state of the player from a
     603                 :             :  * `kdeconnect.mpris` packet.
     604                 :             :  */
     605                 :             : void
     606                 :           2 : valent_mpris_device_handle_packet (ValentMprisDevice  *player,
     607                 :             :                                    JsonNode           *packet)
     608                 :             : {
     609                 :           2 :   const char *url;
     610                 :           2 :   ValentMediaActions flags = VALENT_MEDIA_ACTION_NONE;
     611                 :           2 :   GVariantDict metadata;
     612                 :           2 :   const char *artist, *title, *album;
     613                 :           2 :   int64_t length, position;
     614                 :           2 :   const char *loop_status = NULL;
     615                 :           2 :   gboolean shuffle = FALSE;
     616                 :           2 :   gboolean is_playing;
     617                 :           2 :   int64_t volume;
     618                 :             : 
     619                 :             :   /* Flags (available actions) */
     620         [ +  + ]:           2 :   if (valent_packet_check_field (packet, "canGoNext"))
     621                 :           1 :     flags |= VALENT_MEDIA_ACTION_NEXT;
     622                 :             : 
     623         [ -  + ]:           2 :   if (valent_packet_check_field (packet, "canGoPrevious"))
     624                 :           0 :     flags |= VALENT_MEDIA_ACTION_PREVIOUS;
     625                 :             : 
     626         [ +  + ]:           2 :   if (valent_packet_check_field (packet, "canPause"))
     627                 :           1 :     flags |= VALENT_MEDIA_ACTION_PAUSE;
     628                 :             : 
     629         [ +  + ]:           2 :   if (valent_packet_check_field (packet, "canPlay"))
     630                 :           1 :     flags |= VALENT_MEDIA_ACTION_PLAY;
     631                 :             : 
     632         [ +  + ]:           2 :   if (valent_packet_check_field (packet, "canSeek"))
     633                 :           1 :     flags |= VALENT_MEDIA_ACTION_SEEK;
     634                 :             : 
     635                 :           2 :   valent_mpris_device_update_flags (player, flags);
     636                 :             : 
     637                 :             :   /* Metadata */
     638                 :           2 :   g_variant_dict_init (&metadata, NULL);
     639                 :             : 
     640         [ +  + ]:           2 :   if (valent_packet_get_string (packet, "artist", &artist))
     641                 :             :     {
     642                 :           3 :       g_auto (GStrv) artists = NULL;
     643                 :           1 :       GVariant *value;
     644                 :             : 
     645                 :           1 :       artists = g_strsplit (artist, ",", -1);
     646                 :           1 :       value = g_variant_new_strv ((const char * const *)artists, -1);
     647         [ +  - ]:           1 :       g_variant_dict_insert_value (&metadata, "xesam:artist", value);
     648                 :             :     }
     649                 :             : 
     650         [ +  + ]:           2 :   if (valent_packet_get_string (packet, "title", &title))
     651                 :           1 :     g_variant_dict_insert (&metadata, "xesam:title", "s", title);
     652                 :             : 
     653         [ +  + ]:           2 :   if (valent_packet_get_string (packet, "album", &album))
     654                 :           1 :     g_variant_dict_insert (&metadata, "xesam:album", "s", album);
     655                 :             : 
     656                 :             :   /* Convert milliseconds to microseconds */
     657         [ +  + ]:           2 :   if (valent_packet_get_int (packet, "length", &length))
     658                 :           1 :     g_variant_dict_insert (&metadata, "mpris:length", "x", length * 1000L);
     659                 :             : 
     660         [ +  + ]:           2 :   if (valent_packet_get_string (packet, "albumArtUrl", &url))
     661                 :           1 :     valent_mpris_device_request_album_art (player, url, &metadata);
     662                 :             : 
     663                 :           2 :   valent_mpris_device_update_metadata (player, g_variant_dict_end (&metadata));
     664                 :             : 
     665                 :             :   /* Playback Status */
     666         [ +  - ]:           2 :   if (valent_packet_get_int (packet, "pos", &position))
     667                 :           2 :     valent_mpris_device_update_position (player, position);
     668                 :             : 
     669         [ +  - ]:           2 :   if (valent_packet_get_string (packet, "loopStatus", &loop_status))
     670                 :           2 :     valent_mpris_device_update_repeat (player, loop_status);
     671                 :             : 
     672         [ +  - ]:           2 :   if (valent_packet_get_boolean (packet, "isPlaying", &is_playing))
     673         [ +  + ]:           3 :     valent_mpris_device_update_state (player, is_playing ? "Playing" : "Paused");
     674                 :             : 
     675         [ +  - ]:           2 :   if (valent_packet_get_boolean (packet, "shuffle", &shuffle))
     676                 :           2 :     valent_mpris_device_update_shuffle (player, shuffle);
     677                 :             : 
     678         [ +  - ]:           2 :   if (valent_packet_get_int (packet, "volume", &volume))
     679                 :           2 :     valent_mpris_device_update_volume (player, volume);
     680                 :           2 : }
     681                 :             : 
     682                 :             : /**
     683                 :             :  * valent_mpris_device_update_art:
     684                 :             :  * @player: a `ValentMprisDevice`
     685                 :             :  * @file: a `GFile`
     686                 :             :  *
     687                 :             :  * Update the `mpris:artUrl` metadata field from @file.
     688                 :             :  */
     689                 :             : void
     690                 :           1 : valent_mpris_device_update_art (ValentMprisDevice *player,
     691                 :             :                                 GFile             *file)
     692                 :             : {
     693                 :           1 :   GVariantDict dict;
     694                 :           1 :   GVariant *metadata;
     695                 :           2 :   g_autofree char *uri = NULL;
     696                 :             : 
     697         [ +  - ]:           1 :   g_assert (VALENT_IS_MPRIS_DEVICE (player));
     698   [ +  -  +  -  :           1 :   g_assert (G_IS_FILE (file));
             +  -  -  + ]
     699                 :             : 
     700                 :           1 :   uri = g_file_get_uri (file);
     701                 :             : 
     702                 :           1 :   g_variant_dict_init (&dict, player->metadata);
     703                 :           1 :   g_variant_dict_insert (&dict, "mpris:artUrl", "s", uri);
     704                 :           1 :   metadata = g_variant_dict_end (&dict);
     705                 :             : 
     706                 :           1 :   valent_mpris_device_update_metadata (player, metadata);
     707                 :           1 : }
     708                 :             : 
     709                 :             : /**
     710                 :             :  * valent_media_player_update_name:
     711                 :             :  * @player: a `ValentMprisDevice`
     712                 :             :  * @name: a name
     713                 :             :  *
     714                 :             :  * Set the user-visible name of the player to @identity.
     715                 :             :  */
     716                 :             : void
     717                 :           1 : valent_mpris_device_update_name (ValentMprisDevice *player,
     718                 :             :                                  const char        *name)
     719                 :             : {
     720         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_MPRIS_DEVICE (player));
     721         [ -  + ]:           1 :   g_return_if_fail (name != NULL);
     722                 :             : 
     723         [ +  - ]:           1 :   if (g_set_str (&player->name, name))
     724                 :           1 :     g_object_notify (G_OBJECT (player), "name");
     725                 :             : }
        

Generated by: LCOV version 2.0-1