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 [ + + + - ]: 524 : 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 : : /*
46 : : * GListModel
47 : : */
48 : : static gpointer
49 : 14 : valent_media_adapter_get_item (GListModel *list,
50 : : unsigned int position)
51 : : {
52 : 14 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (list);
53 : 14 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
54 : :
55 [ + - ]: 14 : g_assert (VALENT_IS_MEDIA_ADAPTER (self));
56 : :
57 [ + - ]: 14 : if G_UNLIKELY (position >= priv->items->len)
58 : : return NULL;
59 : :
60 : 14 : return g_object_ref (g_ptr_array_index (priv->items, position));
61 : : }
62 : :
63 : : static GType
64 : 1 : valent_media_adapter_get_item_type (GListModel *list)
65 : : {
66 : 1 : return VALENT_TYPE_MEDIA_PLAYER;
67 : : }
68 : :
69 : : static unsigned int
70 : 16 : valent_media_adapter_get_n_items (GListModel *list)
71 : : {
72 : 16 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (list);
73 : 16 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
74 : :
75 [ + - ]: 16 : g_assert (VALENT_IS_MEDIA_ADAPTER (self));
76 : :
77 : 16 : return priv->items->len;
78 : : }
79 : :
80 : : static void
81 : 58 : g_list_model_iface_init (GListModelInterface *iface)
82 : : {
83 : 58 : iface->get_item = valent_media_adapter_get_item;
84 : 58 : iface->get_item_type = valent_media_adapter_get_item_type;
85 : 58 : iface->get_n_items = valent_media_adapter_get_n_items;
86 : 58 : }
87 : :
88 : : /* LCOV_EXCL_START */
89 : : static void
90 : : valent_media_adapter_real_export_player (ValentMediaAdapter *adapter,
91 : : ValentMediaPlayer *player)
92 : : {
93 : : g_assert (VALENT_IS_MEDIA_ADAPTER (adapter));
94 : : g_assert (VALENT_IS_MEDIA_PLAYER (player));
95 : : }
96 : :
97 : : static void
98 : : valent_media_adapter_real_unexport_player (ValentMediaAdapter *adapter,
99 : : ValentMediaPlayer *player)
100 : : {
101 : : g_assert (VALENT_IS_MEDIA_ADAPTER (adapter));
102 : : g_assert (VALENT_IS_MEDIA_PLAYER (player));
103 : : }
104 : : /* LCOV_EXCL_STOP */
105 : :
106 : : /*
107 : : * GObject
108 : : */
109 : : static void
110 : 17 : valent_media_adapter_finalize (GObject *object)
111 : : {
112 : 17 : ValentMediaAdapter *self = VALENT_MEDIA_ADAPTER (object);
113 : 17 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
114 : :
115 [ + - ]: 17 : g_clear_pointer (&priv->items, g_ptr_array_unref);
116 : :
117 : 17 : G_OBJECT_CLASS (valent_media_adapter_parent_class)->finalize (object);
118 : 17 : }
119 : :
120 : : static void
121 : 58 : valent_media_adapter_class_init (ValentMediaAdapterClass *klass)
122 : : {
123 : 58 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
124 : :
125 : 58 : object_class->finalize = valent_media_adapter_finalize;
126 : :
127 : 58 : klass->export_player = valent_media_adapter_real_export_player;
128 : 58 : klass->unexport_player = valent_media_adapter_real_unexport_player;
129 : : }
130 : :
131 : : static void
132 : 19 : valent_media_adapter_init (ValentMediaAdapter *self)
133 : : {
134 : 19 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (self);
135 : :
136 : 19 : priv->items = g_ptr_array_new_with_free_func (g_object_unref);
137 : 19 : }
138 : :
139 : : /**
140 : : * valent_media_adapter_player_added:
141 : : * @adapter: a `ValentMediaAdapter`
142 : : * @player: a `ValentMediaPlayer`
143 : : *
144 : : * Called when @player has been added to @adapter.
145 : : *
146 : : * This method should only be called by implementations of
147 : : * [class@Valent.MediaAdapter]. @adapter will hold a reference on @player and
148 : : * emit [signal@Gio.ListModel::items-changed].
149 : : *
150 : : * Since: 1.0
151 : : */
152 : : void
153 : 23 : valent_media_adapter_player_added (ValentMediaAdapter *adapter,
154 : : ValentMediaPlayer *player)
155 : : {
156 : 23 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (adapter);
157 : 23 : unsigned int position = 0;
158 : :
159 [ + - ]: 23 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
160 [ - + ]: 23 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
161 : :
162 [ - + ]: 23 : if (g_ptr_array_find (priv->items, player, &position))
163 : : {
164 : 0 : g_warning ("Player \"%s\" (%s) already exported",
165 : : valent_media_player_get_name (player),
166 : : G_OBJECT_TYPE_NAME (player));
167 : 0 : return;
168 : : }
169 : :
170 : 23 : g_signal_connect_object (player,
171 : : "destroy",
172 : : G_CALLBACK (valent_media_adapter_player_removed),
173 : : adapter,
174 : : G_CONNECT_SWAPPED);
175 : :
176 : 23 : position = priv->items->len;
177 : 23 : g_ptr_array_add (priv->items, g_object_ref (player));
178 : 23 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 0, 1);
179 : : }
180 : :
181 : : /**
182 : : * valent_media_adapter_player_removed:
183 : : * @adapter: a `ValentMediaAdapter`
184 : : * @player: a `ValentMediaPlayer`
185 : : *
186 : : * Called when @player has been removed from @adapter.
187 : : *
188 : : * This method should only be called by implementations of
189 : : * [class@Valent.MediaAdapter]. @adapter will drop its reference on @player
190 : : * and emit [signal@Gio.ListModel::items-changed].
191 : : *
192 : : * Since: 1.0
193 : : */
194 : : void
195 : 8 : valent_media_adapter_player_removed (ValentMediaAdapter *adapter,
196 : : ValentMediaPlayer *player)
197 : : {
198 : 8 : ValentMediaAdapterPrivate *priv = valent_media_adapter_get_instance_private (adapter);
199 : 8 : g_autoptr (ValentMediaPlayer) item = NULL;
200 : 8 : unsigned int position = 0;
201 : :
202 [ + - ]: 8 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
203 [ - + ]: 8 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
204 : :
205 [ - + ]: 8 : if (!g_ptr_array_find (priv->items, player, &position))
206 : : {
207 : 0 : g_warning ("No such player \"%s\" found in \"%s\"",
208 : : G_OBJECT_TYPE_NAME (player),
209 : : G_OBJECT_TYPE_NAME (adapter));
210 : 0 : return;
211 : : }
212 : :
213 : 8 : g_signal_handlers_disconnect_by_func (player, valent_media_adapter_player_removed, adapter);
214 : 8 : item = g_ptr_array_steal_index (priv->items, position);
215 [ + - ]: 8 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 1, 0);
216 : : }
217 : :
218 : : /**
219 : : * valent_media_adapter_export_player: (virtual export_player)
220 : : * @adapter: an `ValentMediaAdapter`
221 : : * @player: a `ValentMediaPlayer`
222 : : *
223 : : * Export @player on @adapter.
224 : : *
225 : : * This method is intended to allow device plugins to expose remote media
226 : : * players to the host system. Usually this means exporting an interface on
227 : : * D-Bus or an mDNS service.
228 : : *
229 : : * Implementations must automatically unexport any players when destroyed.
230 : : *
231 : : * Since: 1.0
232 : : */
233 : : void
234 : 4 : valent_media_adapter_export_player (ValentMediaAdapter *adapter,
235 : : ValentMediaPlayer *player)
236 : : {
237 : 4 : VALENT_ENTRY;
238 : :
239 [ + - ]: 4 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
240 [ - + ]: 4 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
241 : :
242 : 4 : VALENT_MEDIA_ADAPTER_GET_CLASS (adapter)->export_player (adapter, player);
243 : :
244 : 4 : VALENT_EXIT;
245 : : }
246 : :
247 : : /**
248 : : * valent_media_adapter_unexport_player: (virtual unexport_player)
249 : : * @adapter: an `ValentMediaAdapter`
250 : : * @player: a `ValentMediaPlayer`
251 : : *
252 : : * Unexport @player from @adapter.
253 : : *
254 : : * Since: 1.0
255 : : */
256 : : void
257 : 4 : valent_media_adapter_unexport_player (ValentMediaAdapter *adapter,
258 : : ValentMediaPlayer *player)
259 : : {
260 : 4 : VALENT_ENTRY;
261 : :
262 [ + - ]: 4 : g_return_if_fail (VALENT_IS_MEDIA_ADAPTER (adapter));
263 [ - + ]: 4 : g_return_if_fail (VALENT_IS_MEDIA_PLAYER (player));
264 : :
265 : 4 : VALENT_MEDIA_ADAPTER_GET_CLASS (adapter)->unexport_player (adapter, player);
266 : :
267 : 4 : VALENT_EXIT;
268 : : }
269 : :
|