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

Generated by: LCOV version 2.0-1