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-player"
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-utils.h"
14 : :
15 : :
16 : : /*
17 : : * DBus Interfaces
18 : : */
19 : : static const char mpris_xml[] =
20 : : "<node name='/org/mpris/MediaPlayer2'>"
21 : : " <interface name='org.mpris.MediaPlayer2'>"
22 : : " <method name='Raise'/>"
23 : : " <method name='Quit'/>"
24 : : " <property name='CanQuit' type='b' access='read'/>"
25 : : " <property name='Fullscreen' type='b' access='readwrite'/>"
26 : : " <property name='CanSetFullscreen' type='b' access='read'/>"
27 : : " <property name='CanRaise' type='b' access='read'/>"
28 : : " <property name='HasTrackList' type='b' access='read'/>"
29 : : " <property name='Identity' type='s' access='read'/>"
30 : : " <property name='DesktopEntry' type='s' access='read'/>"
31 : : " <property name='SupportedUriSchemes' type='as' access='read'/>"
32 : : " <property name='SupportedMimeTypes' type='as' access='read'/>"
33 : : " </interface>"
34 : : " <interface name='org.mpris.MediaPlayer2.Player'>"
35 : : " <method name='Next'/>"
36 : : " <method name='Previous'/>"
37 : : " <method name='Pause'/>"
38 : : " <method name='PlayPause'/>"
39 : : " <method name='Stop'/>"
40 : : " <method name='Play'/>"
41 : : " <method name='Seek'>"
42 : : " <arg direction='in' type='x' name='Offset'/>"
43 : : " </method>"
44 : : " <method name='SetPosition'>"
45 : : " <arg direction='in' type='o' name='TrackId'/>"
46 : : " <arg direction='in' type='x' name='Position'/>"
47 : : " </method>"
48 : : " <method name='OpenUri'>"
49 : : " <arg direction='in' type='s' name='Uri'/>"
50 : : " </method>"
51 : : " <property name='PlaybackStatus' type='s' access='read'/>"
52 : : " <property name='LoopStatus' type='s' access='readwrite'/>"
53 : : " <property name='Rate' type='d' access='readwrite'/>"
54 : : " <property name='Shuffle' type='b' access='readwrite'/>"
55 : : " <property name='Metadata' type='a{sv}' access='read'/>"
56 : : " <property name='Volume' type='d' access='readwrite'/>"
57 : : " <property name='Position' type='x' access='read'/>"
58 : : " <property name='MinimumRate' type='d' access='read'/>"
59 : : " <property name='MaximumRate' type='d' access='read'/>"
60 : : " <property name='CanGoNext' type='b' access='read'/>"
61 : : " <property name='CanGoPrevious' type='b' access='read'/>"
62 : : " <property name='CanPlay' type='b' access='read'/>"
63 : : " <property name='CanPause' type='b' access='read'/>"
64 : : " <property name='CanSeek' type='b' access='read'/>"
65 : : " <property name='CanControl' type='b' access='read'/>"
66 : : " <signal name='Seeked'>"
67 : : " <arg name='Position' type='x'/>"
68 : : " </signal>"
69 : : " </interface>"
70 : : "</node>";
71 : :
72 : :
73 : : static inline GDBusNodeInfo *
74 : 20 : valent_mpris_get_info (void)
75 : : {
76 : 20 : static GDBusNodeInfo *mpris_info = NULL;
77 : 20 : static size_t guard = 0;
78 : :
79 [ + + + - ]: 20 : if (g_once_init_enter (&guard))
80 : : {
81 : 2 : mpris_info = g_dbus_node_info_new_for_xml (mpris_xml, NULL);
82 : 2 : g_dbus_interface_info_cache_build (mpris_info->interfaces[0]);
83 : 2 : g_dbus_interface_info_cache_build (mpris_info->interfaces[1]);
84 : :
85 : 2 : g_once_init_leave (&guard, 1);
86 : : }
87 : :
88 : 20 : return mpris_info;
89 : : }
90 : :
91 : : /**
92 : : * valent_mpris_get_application_iface:
93 : : *
94 : : * Get a `GDBusInterfaceInfo` for the `org.mpris.MediaPlayer2` interface.
95 : : *
96 : : * Returns: (transfer none): a `GDBusInterfaceInfo`
97 : : */
98 : : GDBusInterfaceInfo *
99 : 10 : valent_mpris_get_application_iface (void)
100 : : {
101 : 10 : GDBusNodeInfo *mpris_info = valent_mpris_get_info ();
102 : :
103 : 10 : return mpris_info->interfaces[0];
104 : : }
105 : :
106 : : /**
107 : : * valent_mpris_get_player_iface:
108 : : *
109 : : * Get a `GDBusInterfaceInfo` for the `org.mpris.MediaPlayer2.Player` interface.
110 : : *
111 : : * Returns: (transfer none): a `GDBusInterfaceInfo`
112 : : */
113 : : GDBusInterfaceInfo *
114 : 10 : valent_mpris_get_player_iface (void)
115 : : {
116 : 10 : GDBusNodeInfo *mpris_info = valent_mpris_get_info ();
117 : :
118 : 10 : return mpris_info->interfaces[1];
119 : : }
120 : :
121 : : /**
122 : : * valent_mpris_repeat_from_string:
123 : : * @loop_status: repeat mode to translate
124 : : *
125 : : * Translate an MPRIS `LoopStatus` string to a `ValentMediaRepeat`.
126 : : *
127 : : * Returns: (transfer none): a repeat mode
128 : : */
129 : : ValentMediaRepeat
130 : 18 : valent_mpris_repeat_from_string (const char *loop_status)
131 : : {
132 [ + - ]: 18 : g_return_val_if_fail (loop_status != NULL, VALENT_MEDIA_REPEAT_NONE);
133 : :
134 [ + + ]: 18 : if (g_str_equal (loop_status, "None"))
135 : : return VALENT_MEDIA_REPEAT_NONE;
136 : :
137 [ + + ]: 9 : if (g_str_equal (loop_status, "Playlist"))
138 : : return VALENT_MEDIA_REPEAT_ALL;
139 : :
140 [ - + ]: 6 : if (g_str_equal (loop_status, "Track"))
141 : : return VALENT_MEDIA_REPEAT_ONE;
142 : :
143 : : return VALENT_MEDIA_REPEAT_NONE;
144 : : }
145 : :
146 : : /**
147 : : * valent_mpris_repeat_to_string:
148 : : * @repeat: repeat mode to translate
149 : : *
150 : : * Translate a `ValentMediaRepeat` enum to an MPRIS `LoopStatus` string.
151 : : *
152 : : * Returns: (transfer none): a status string
153 : : */
154 : : const char *
155 : 22 : valent_mpris_repeat_to_string (ValentMediaRepeat repeat)
156 : : {
157 [ + - ]: 22 : g_return_val_if_fail (repeat <= VALENT_MEDIA_REPEAT_ONE, "None");
158 : :
159 [ + + ]: 22 : if (repeat == VALENT_MEDIA_REPEAT_NONE)
160 : : return "None";
161 : :
162 [ + + ]: 11 : if (repeat == VALENT_MEDIA_REPEAT_ALL)
163 : : return "Playlist";
164 : :
165 : 6 : if (repeat == VALENT_MEDIA_REPEAT_ONE)
166 : 6 : return "Track";
167 : :
168 : : return "None";
169 : : }
170 : :
171 : : /**
172 : : * valent_mpris_state_from_string:
173 : : * @playback_status: playback mode to translate
174 : : *
175 : : * Translate an MPRIS `PlaybackStatus` string to a `ValentMediaState`.
176 : : *
177 : : * Returns: (transfer none): a playback state
178 : : */
179 : : ValentMediaState
180 : 42 : valent_mpris_state_from_string (const char *playback_status)
181 : : {
182 [ + - ]: 42 : g_return_val_if_fail (playback_status != NULL, VALENT_MEDIA_STATE_STOPPED);
183 : :
184 [ + + ]: 42 : if (g_str_equal (playback_status, "Stopped"))
185 : : return VALENT_MEDIA_STATE_STOPPED;
186 : :
187 [ + + ]: 20 : if (g_str_equal (playback_status, "Playing"))
188 : : return VALENT_MEDIA_STATE_PLAYING;
189 : :
190 [ - + ]: 7 : if (g_str_equal (playback_status, "Paused"))
191 : : return VALENT_MEDIA_STATE_PAUSED;
192 : :
193 : : return VALENT_MEDIA_STATE_STOPPED;
194 : : }
195 : :
196 : : /**
197 : : * valent_mpris_state_to_string:
198 : : * @state: playback mode to translate
199 : : *
200 : : * Translate a `ValentMediaState` enum to an MPRIS `PlaybackStatus` string.
201 : : *
202 : : * Returns: (transfer none): a status string
203 : : */
204 : : const char *
205 : 31 : valent_mpris_state_to_string (ValentMediaState state)
206 : : {
207 [ + - ]: 31 : g_return_val_if_fail (state <= VALENT_MEDIA_STATE_PAUSED, "Stopped");
208 : :
209 [ + + ]: 31 : if (state == VALENT_MEDIA_STATE_STOPPED)
210 : : return "Stopped";
211 : :
212 [ + + ]: 16 : if (state == VALENT_MEDIA_STATE_PLAYING)
213 : : return "Playing";
214 : :
215 : 7 : if (state == VALENT_MEDIA_STATE_PAUSED)
216 : 7 : return "Paused";
217 : :
218 : : return "Stopped";
219 : : }
220 : :
221 : : /**
222 : : * valent_mpris_get_time:
223 : : *
224 : : * Get a monotonic timestamp, in seconds.
225 : : *
226 : : * Returns: a timestamp in seconds
227 : : */
228 : : double
229 : 14 : valent_mpris_get_time (void)
230 : : {
231 : 14 : return floor (g_get_real_time () / G_TIME_SPAN_SECOND);
232 : : }
233 : :
|