Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-media-adapter"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <libvalent-core.h>
9 : :
10 : : #include "valent-media-player.h"
11 : :
12 : : #include "valent-media-adapter.h"
13 : :
14 : : /**
15 : : * ValentMediaAdapter:
16 : : *
17 : : * An abstract base class for media player adapters.
18 : : *
19 : : * `ValentMediaAdapter` is a base class for plugins that provide an interface to
20 : : * manage media players. This usually means monitoring and querying instances of
21 : : * [class@Valent.MediaPlayer].
22 : : *
23 : : * ## `.plugin` File
24 : : *
25 : : * Implementations may define the following extra fields in the `.plugin` file:
26 : : *
27 : : * - `X-MediaAdapterPriority`
28 : : *
29 : : * An integer indicating the adapter priority. The implementation with the
30 : : * lowest value will be used as the primary adapter.
31 : : *
32 : : * Since: 1.0
33 : : */
34 : : typedef struct
35 : : {
36 : : GPtrArray *items;
37 : : } ValentMediaAdapterPrivate;
38 : :
39 : : static void g_list_model_iface_init (GListModelInterface *iface);
40 : :
41 [ + + + - ]: 558 : G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ValentMediaAdapter, valent_media_adapter, VALENT_TYPE_EXTENSION,
42 : : G_ADD_PRIVATE (ValentMediaAdapter)
43 : : G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
44 : :
45 : : static inline void
46 : 22 : _valent_object_deref (gpointer data)
47 : : {
48 [ + + ]: 22 : if (!valent_object_in_destruction (VALENT_OBJECT (data)))
49 : 9 : valent_object_destroy (VALENT_OBJECT (data));
50 : :
51 : 22 : g_object_unref (data);
52 : 22 : }
53 : :
54 : : /*
55 : : * GListModel
56 : : */
57 : : static gpointer
58 : 27 : valent_media_adapter_get_item (GListModel *list,
59 : : unsigned int position)
60 : : {
61 : 27 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (list);
62 : 27 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
63 : :
64 [ - + ]: 27 : g_assert (VALENT_IS_MEDIA_ADAPTER (self));
65 : :
66 [ + - ]: 27 : if G_UNLIKELY (position >= priv->items->len)
67 : : return NULL;
68 : :
69 : 27 : return g_object_ref (g_ptr_array_index (priv->items, position));
70 : : }
71 : :
72 : : static GType
73 : 1 : valent_media_adapter_get_item_type (GListModel *list)
74 : : {
75 : 1 : return VALENT_TYPE_MEDIA_PLAYER;
76 : : }
77 : :
78 : : static unsigned int
79 : 18 : valent_media_adapter_get_n_items (GListModel *list)
80 : : {
81 : 18 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (list);
82 : 18 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
83 : :
84 [ - + ]: 18 : g_assert (VALENT_IS_MEDIA_ADAPTER (self));
85 : :
86 : 18 : return priv->items->len;
87 : : }
88 : :
89 : : static void
90 : 53 : g_list_model_iface_init (GListModelInterface *iface)
91 : : {
92 : 53 : iface->get_item = valent_media_adapter_get_item;
93 : 53 : iface->get_item_type = valent_media_adapter_get_item_type;
94 : 53 : iface->get_n_items = valent_media_adapter_get_n_items;
95 : 53 : }
96 : :
97 : : /* LCOV_EXCL_START */
98 : : static void
99 : : valent_media_adapter_real_export_player (ValentMediaAdapter *adapter,
100 : : ValentMediaPlayer *player)
101 : : {
102 : : g_assert (VALENT_IS_MEDIA_ADAPTER (adapter));
103 : : g_assert (VALENT_IS_MEDIA_PLAYER (player));
104 : : }
105 : :
106 : : static void
107 : : valent_media_adapter_real_unexport_player (ValentMediaAdapter *adapter,
108 : : ValentMediaPlayer *player)
109 : : {
110 : : g_assert (VALENT_IS_MEDIA_ADAPTER (adapter));
111 : : g_assert (VALENT_IS_MEDIA_PLAYER (player));
112 : : }
113 : : /* LCOV_EXCL_STOP */
114 : :
115 : : /*
116 : : * GObject
117 : : */
118 : : static void
119 : 18 : valent_media_adapter_finalize (GObject *object)
120 : : {
121 : 18 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (object);
122 : 18 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
123 : :
124 [ + - ]: 18 : g_clear_pointer (&priv->items, g_ptr_array_unref);
125 : :
126 : 18 : G_OBJECT_CLASS (valent_media_adapter_parent_class)->finalize (object);
127 : 18 : }
128 : :
129 : : static void
130 : 53 : valent_media_adapter_class_init (ValentMediaAdapterClass *klass)
131 : : {
132 : 53 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
133 : :
134 : 53 : object_class->finalize = valent_media_adapter_finalize;
135 : :
136 : 53 : klass->export_player = valent_media_adapter_real_export_player;
137 : 53 : klass->unexport_player = valent_media_adapter_real_unexport_player;
138 : : }
139 : :
140 : : static void
141 : 21 : valent_media_adapter_init (ValentMediaAdapter *self)
142 : : {
143 : 21 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
144 : :
145 : 21 : priv->items = g_ptr_array_new_with_free_func (_valent_object_deref);
146 : 21 : }
147 : :
148 : : /**
149 : : * valent_media_adapter_player_added:
150 : : * @adapter: a `ValentMediaAdapter`
151 : : * @player: a `ValentMediaPlayer`
152 : : *
153 : : * Called when @player has been added to @adapter.
154 : : *
155 : : * This method should only be called by implementations of
156 : : * [class@Valent.MediaAdapter]. @adapter will hold a reference on @player and
157 : : * emit [signal@Gio.ListModel::items-changed].
158 : : *
159 : : * Since: 1.0
160 : : */
161 : : void
162 : 22 : valent_media_adapter_player_added (ValentMediaAdapter *adapter,
163 : : ValentMediaPlayer *player)
164 : : {
165 : 22 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (adapter);
166 : 22 : unsigned int position = 0;
167 : :
168 [ - + ]: 22 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
169 [ + - ]: 22 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
170 : :
171 [ - + ]: 22 : if (g_ptr_array_find (priv->items, player, &position))
172 : : {
173 : 0 : g_warning ("Player \"%s\" (%s) already exported",
174 : : valent_media_player_get_name (player),
175 : : G_OBJECT_TYPE_NAME (player));
176 : 0 : return;
177 : : }
178 : :
179 : 22 : g_signal_connect_object (player,
180 : : "destroy",
181 : : G_CALLBACK (valent_media_adapter_player_removed),
182 : : adapter,
183 : : G_CONNECT_SWAPPED);
184 : :
185 : 22 : position = priv->items->len;
186 : 22 : g_ptr_array_add (priv->items, g_object_ref (player));
187 : 22 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 0, 1);
188 : : }
189 : :
190 : : /**
191 : : * valent_media_adapter_player_removed:
192 : : * @adapter: a `ValentMediaAdapter`
193 : : * @player: a `ValentMediaPlayer`
194 : : *
195 : : * Called when @player has been removed from @adapter.
196 : : *
197 : : * This method should only be called by implementations of
198 : : * [class@Valent.MediaAdapter]. @adapter will drop its reference on @player
199 : : * and emit [signal@Gio.ListModel::items-changed].
200 : : *
201 : : * Since: 1.0
202 : : */
203 : : void
204 : 19 : valent_media_adapter_player_removed (ValentMediaAdapter *adapter,
205 : : ValentMediaPlayer *player)
206 : : {
207 : 19 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (adapter);
208 : 19 : unsigned int position = 0;
209 : :
210 [ - + ]: 19 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
211 [ + - ]: 19 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
212 : :
213 [ - + ]: 19 : if (!g_ptr_array_find (priv->items, player, &position))
214 : : {
215 : 0 : g_warning ("No such player \"%s\" found in \"%s\"",
216 : : G_OBJECT_TYPE_NAME (player),
217 : : G_OBJECT_TYPE_NAME (adapter));
218 : 0 : return;
219 : : }
220 : :
221 : 19 : g_signal_handlers_disconnect_by_func (player, valent_media_adapter_player_removed, adapter);
222 : 19 : g_ptr_array_remove_index (priv->items, position);
223 : 19 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 1, 0);
224 : : }
225 : :
226 : : /**
227 : : * valent_media_adapter_export_player: (virtual export_player)
228 : : * @adapter: an `ValentMediaAdapter`
229 : : * @player: a `ValentMediaPlayer`
230 : : *
231 : : * Export @player on @adapter.
232 : : *
233 : : * This method is intended to allow device plugins to expose remote media
234 : : * players to the host system. Usually this means exporting an interface on
235 : : * D-Bus or an mDNS service.
236 : : *
237 : : * Implementations must automatically unexport any players when destroyed.
238 : : *
239 : : * Since: 1.0
240 : : */
241 : : void
242 : 3 : valent_media_adapter_export_player (ValentMediaAdapter *adapter,
243 : : ValentMediaPlayer *player)
244 : : {
245 : 3 : VALENT_ENTRY;
246 : :
247 [ - + ]: 3 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
248 [ + - ]: 3 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
249 : :
250 : 3 : VALENT_MEDIA_ADAPTER_GET_CLASS (adapter)->export_player (adapter, player);
251 : :
252 : 3 : VALENT_EXIT;
253 : : }
254 : :
255 : : /**
256 : : * valent_media_adapter_unexport_player: (virtual unexport_player)
257 : : * @adapter: an `ValentMediaAdapter`
258 : : * @player: a `ValentMediaPlayer`
259 : : *
260 : : * Unexport @player from @adapter.
261 : : *
262 : : * Since: 1.0
263 : : */
264 : : void
265 : 3 : valent_media_adapter_unexport_player (ValentMediaAdapter *adapter,
266 : : ValentMediaPlayer *player)
267 : : {
268 : 3 : VALENT_ENTRY;
269 : :
270 [ - + ]: 3 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
271 [ + - ]: 3 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
272 : :
273 : 3 : VALENT_MEDIA_ADAPTER_GET_CLASS (adapter)->unexport_player (adapter, player);
274 : :
275 : 3 : VALENT_EXIT;
276 : : }
277 : :
|