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-mixer-adapter"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libvalent-core.h>
10 : :
11 : : #include "valent-mixer.h"
12 : : #include "valent-mixer-adapter.h"
13 : :
14 : :
15 : : /**
16 : : * ValentMixerAdapter
17 : : *
18 : : * An abstract base class for audio mixers.
19 : : *
20 : : * `ValentMixerAdapter` is a base class for plugins that provide an interface to
21 : : * audio mixers and volume control. This usually means monitoring the available
22 : : * input and output streams, changing properties on those streams, and selecting
23 : : * which are the active input and output.
24 : : *
25 : : * ## `.plugin` File
26 : : *
27 : : * Implementations may define the following extra fields in the `.plugin` file:
28 : : *
29 : : * - `X-MixerAdapterPriority`
30 : : *
31 : : * An integer indicating the adapter priority. The implementation with the
32 : : * lowest value will be used as the primary adapter.
33 : : *
34 : : * Since: 1.0
35 : : */
36 : :
37 : : typedef struct
38 : : {
39 : : GPtrArray *streams;
40 : : } ValentMixerAdapterPrivate;
41 : :
42 : : static void g_list_model_iface_init (GListModelInterface *iface);
43 : :
44 [ + + + - ]: 626 : G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ValentMixerAdapter, valent_mixer_adapter, VALENT_TYPE_EXTENSION,
45 : : G_ADD_PRIVATE (ValentMixerAdapter)
46 : : G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
47 : :
48 : : typedef enum {
49 : : PROP_DEFAULT_INPUT = 1,
50 : : PROP_DEFAULT_OUTPUT,
51 : : } ValentMixerAdapterProperty;
52 : :
53 : : static GParamSpec *properties[PROP_DEFAULT_OUTPUT + 1] = { NULL, };
54 : :
55 : :
56 : : /*
57 : : * GListModel
58 : : */
59 : : static gpointer
60 : 39 : valent_mixer_adapter_get_item (GListModel *list,
61 : : unsigned int position)
62 : : {
63 : 39 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (list);
64 : 39 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
65 : :
66 [ - + ]: 39 : g_assert (VALENT_IS_MIXER_ADAPTER (self));
67 : :
68 [ + - ]: 39 : if G_UNLIKELY (position >= priv->streams->len)
69 : : return NULL;
70 : :
71 : 39 : return g_object_ref (g_ptr_array_index (priv->streams, position));
72 : : }
73 : :
74 : : static GType
75 : 1 : valent_mixer_adapter_get_item_type (GListModel *list)
76 : : {
77 : 1 : return VALENT_TYPE_MIXER_STREAM;
78 : : }
79 : :
80 : : static unsigned int
81 : 18 : valent_mixer_adapter_get_n_items (GListModel *list)
82 : : {
83 : 18 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (list);
84 : 18 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
85 : :
86 [ - + ]: 18 : g_assert (VALENT_IS_MIXER_ADAPTER (self));
87 : :
88 : 18 : return priv->streams->len;
89 : : }
90 : :
91 : : static void
92 : 53 : g_list_model_iface_init (GListModelInterface *iface)
93 : : {
94 : 53 : iface->get_item = valent_mixer_adapter_get_item;
95 : 53 : iface->get_item_type = valent_mixer_adapter_get_item_type;
96 : 53 : iface->get_n_items = valent_mixer_adapter_get_n_items;
97 : 53 : }
98 : :
99 : : /* LCOV_EXCL_START */
100 : : static ValentMixerStream *
101 : : valent_mixer_adapter_real_get_default_input (ValentMixerAdapter *adapter)
102 : : {
103 : : g_assert (VALENT_IS_MIXER_ADAPTER (adapter));
104 : :
105 : : return NULL;
106 : : }
107 : :
108 : : static void
109 : : valent_mixer_adapter_real_set_default_input (ValentMixerAdapter *adapter,
110 : : ValentMixerStream *stream)
111 : : {
112 : : g_assert (VALENT_IS_MIXER_ADAPTER (adapter));
113 : : g_assert (VALENT_IS_MIXER_STREAM (stream));
114 : : }
115 : :
116 : : static ValentMixerStream *
117 : : valent_mixer_adapter_real_get_default_output (ValentMixerAdapter *adapter)
118 : : {
119 : : g_assert (VALENT_IS_MIXER_ADAPTER (adapter));
120 : :
121 : : return NULL;
122 : : }
123 : :
124 : : static void
125 : : valent_mixer_adapter_real_set_default_output (ValentMixerAdapter *adapter,
126 : : ValentMixerStream *stream)
127 : : {
128 : : g_assert (VALENT_IS_MIXER_ADAPTER (adapter));
129 : : g_assert (VALENT_IS_MIXER_STREAM (stream));
130 : : }
131 : : /* LCOV_EXCL_STOP */
132 : :
133 : : /*
134 : : * ValentObject
135 : : */
136 : : static void
137 : 26 : valent_mixer_adapter_destroy (ValentObject *object)
138 : : {
139 : 26 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (object);
140 : 26 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
141 : :
142 [ + + ]: 26 : g_clear_pointer (&priv->streams, g_ptr_array_unref);
143 : :
144 : 26 : VALENT_OBJECT_CLASS (valent_mixer_adapter_parent_class)->destroy (object);
145 : 26 : }
146 : :
147 : : /*
148 : : * GObject
149 : : */
150 : : static void
151 : 4 : valent_mixer_adapter_get_property (GObject *object,
152 : : guint prop_id,
153 : : GValue *value,
154 : : GParamSpec *pspec)
155 : : {
156 : 4 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (object);
157 : :
158 [ + + - ]: 4 : switch ((ValentMixerAdapterProperty)prop_id)
159 : : {
160 : 2 : case PROP_DEFAULT_INPUT:
161 : 2 : g_value_set_object (value, valent_mixer_adapter_get_default_input (self));
162 : 2 : break;
163 : :
164 : 2 : case PROP_DEFAULT_OUTPUT:
165 : 2 : g_value_set_object (value, valent_mixer_adapter_get_default_output (self));
166 : 2 : break;
167 : :
168 : 0 : default:
169 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
170 : : }
171 : 4 : }
172 : :
173 : : static void
174 : 2 : valent_mixer_adapter_set_property (GObject *object,
175 : : guint prop_id,
176 : : const GValue *value,
177 : : GParamSpec *pspec)
178 : : {
179 : 2 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (object);
180 : :
181 [ + + - ]: 2 : switch ((ValentMixerAdapterProperty)prop_id)
182 : : {
183 : 1 : case PROP_DEFAULT_INPUT:
184 : 1 : valent_mixer_adapter_set_default_input (self, g_value_get_object (value));
185 : 1 : break;
186 : :
187 : 1 : case PROP_DEFAULT_OUTPUT:
188 : 1 : valent_mixer_adapter_set_default_output (self, g_value_get_object (value));
189 : 1 : break;
190 : :
191 : 0 : default:
192 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193 : : }
194 : 2 : }
195 : :
196 : : static void
197 : 53 : valent_mixer_adapter_class_init (ValentMixerAdapterClass *klass)
198 : : {
199 : 53 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
200 : 53 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
201 : :
202 : 53 : object_class->get_property = valent_mixer_adapter_get_property;
203 : 53 : object_class->set_property = valent_mixer_adapter_set_property;
204 : :
205 : 53 : vobject_class->destroy = valent_mixer_adapter_destroy;
206 : :
207 : 53 : klass->get_default_input = valent_mixer_adapter_real_get_default_input;
208 : 53 : klass->set_default_input = valent_mixer_adapter_real_set_default_input;
209 : 53 : klass->get_default_output = valent_mixer_adapter_real_get_default_output;
210 : 53 : klass->set_default_output = valent_mixer_adapter_real_set_default_output;
211 : :
212 : : /**
213 : : * ValentMixerAdapter:default-input: (getter get_default_input) (setter set_default_input)
214 : : *
215 : : * The active input stream.
216 : : *
217 : : * Implementations should emit [signal@GObject.Object::notify] for this
218 : : * property when the default stream changes.
219 : : *
220 : : * Since: 1.0
221 : : */
222 : 106 : properties [PROP_DEFAULT_INPUT] =
223 : 53 : g_param_spec_object ("default-input", NULL, NULL,
224 : : VALENT_TYPE_MIXER_STREAM,
225 : : (G_PARAM_READWRITE |
226 : : G_PARAM_EXPLICIT_NOTIFY |
227 : : G_PARAM_STATIC_STRINGS));
228 : :
229 : : /**
230 : : * ValentMixerAdapter:default-output: (getter get_default_output) (setter set_default_output)
231 : : *
232 : : * The active output stream.
233 : : *
234 : : * Implementations should emit [signal@GObject.Object::notify] for this
235 : : * property when the default stream changes.
236 : : *
237 : : * Since: 1.0
238 : : */
239 : 106 : properties [PROP_DEFAULT_OUTPUT] =
240 : 53 : g_param_spec_object ("default-output", NULL, NULL,
241 : : VALENT_TYPE_MIXER_STREAM,
242 : : (G_PARAM_READWRITE |
243 : : G_PARAM_EXPLICIT_NOTIFY |
244 : : G_PARAM_STATIC_STRINGS));
245 : :
246 : 53 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
247 : 53 : }
248 : :
249 : : static void
250 : 13 : valent_mixer_adapter_init (ValentMixerAdapter *self)
251 : : {
252 : 13 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
253 : :
254 : 13 : priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
255 : 13 : }
256 : :
257 : : /**
258 : : * valent_mixer_adapter_stream_added:
259 : : * @adapter: a `ValentMixerAdapter`
260 : : * @stream: a `ValentMixerStream`
261 : : *
262 : : * Called when @stream has been added to the mixer.
263 : : *
264 : : * This method should only be called by implementations of
265 : : * [class@Valent.MixerAdapter]. @adapter will hold a reference on @stream and
266 : : * emit [signal@Gio.ListModel::items-changed].
267 : : *
268 : : * Since: 1.0
269 : : */
270 : : void
271 : 30 : valent_mixer_adapter_stream_added (ValentMixerAdapter *adapter,
272 : : ValentMixerStream *stream)
273 : : {
274 : 30 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (adapter);
275 : 30 : unsigned int position = 0;
276 : :
277 [ - + ]: 30 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
278 [ + - ]: 30 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
279 : :
280 : 30 : position = priv->streams->len;
281 : 30 : g_ptr_array_add (priv->streams, g_object_ref (stream));
282 : 30 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 0, 1);
283 : : }
284 : :
285 : : /**
286 : : * valent_mixer_adapter_stream_removed:
287 : : * @adapter: a `ValentMixerAdapter`
288 : : * @stream: a `ValentMixerStream`
289 : : *
290 : : * Called when @stream has been removed from the mixer.
291 : : *
292 : : * This method should only be called by implementations of
293 : : * [class@Valent.MixerAdapter]. @adapter will drop its reference on @stream and
294 : : * emit [signal@Gio.ListModel::items-changed].
295 : : *
296 : : * Since: 1.0
297 : : */
298 : : void
299 : 5 : valent_mixer_adapter_stream_removed (ValentMixerAdapter *adapter,
300 : : ValentMixerStream *stream)
301 : : {
302 : 5 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (adapter);
303 : 5 : unsigned int position = 0;
304 : :
305 [ - + ]: 5 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
306 [ + - ]: 5 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
307 : :
308 [ + - ]: 5 : if (!g_ptr_array_find (priv->streams, stream, &position))
309 : : return;
310 : :
311 : 5 : g_ptr_array_remove_index (priv->streams, position);
312 : 5 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 1, 0);
313 : : }
314 : :
315 : : /**
316 : : * valent_mixer_adapter_get_default_input: (get-property default-input) (virtual get_default_input)
317 : : * @adapter: a `ValentMixerAdapter`
318 : : *
319 : : * Get the default input stream for @adapter.
320 : : *
321 : : * Returns: (transfer none): a `ValentMixerStream`
322 : : *
323 : : * Since: 1.0
324 : : */
325 : : ValentMixerStream *
326 : 12 : valent_mixer_adapter_get_default_input (ValentMixerAdapter *adapter)
327 : : {
328 : 12 : ValentMixerStream *ret;
329 : :
330 : 12 : VALENT_ENTRY;
331 : :
332 [ - + ]: 12 : g_return_val_if_fail (VALENT_IS_MIXER_ADAPTER (adapter), NULL);
333 : :
334 : 12 : ret = VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->get_default_input (adapter);
335 : :
336 : 12 : VALENT_RETURN (ret);
337 : : }
338 : :
339 : : /**
340 : : * valent_mixer_adapter_set_default_input: (set-property default-input) (virtual set_default_input)
341 : : * @adapter: a `ValentMixerAdapter`
342 : : * @stream: a `ValentMixerStream`
343 : : *
344 : : * Set the default input stream for @adapter to @stream.
345 : : *
346 : : * Since: 1.0
347 : : */
348 : : void
349 : 10 : valent_mixer_adapter_set_default_input (ValentMixerAdapter *adapter,
350 : : ValentMixerStream *stream)
351 : : {
352 : 10 : VALENT_ENTRY;
353 : :
354 [ - + ]: 10 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
355 [ + - ]: 10 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
356 : :
357 : 10 : VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->set_default_input (adapter, stream);
358 : :
359 : 10 : VALENT_EXIT;
360 : : }
361 : :
362 : : /**
363 : : * valent_mixer_adapter_get_default_output: (get-property default-output) (virtual get_default_output)
364 : : * @adapter: a `ValentMixerAdapter`
365 : : *
366 : : * Get the default output stream for @adapter.
367 : : *
368 : : * Returns: (transfer none): a `ValentMixerStream`
369 : : *
370 : : * Since: 1.0
371 : : */
372 : : ValentMixerStream *
373 : 28 : valent_mixer_adapter_get_default_output (ValentMixerAdapter *adapter)
374 : : {
375 : 28 : ValentMixerStream *ret;
376 : :
377 : 28 : VALENT_ENTRY;
378 : :
379 [ - + ]: 28 : g_return_val_if_fail (VALENT_IS_MIXER_ADAPTER (adapter), NULL);
380 : :
381 : 28 : ret = VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->get_default_output (adapter);
382 : :
383 : 28 : VALENT_RETURN (ret);
384 : : }
385 : :
386 : : /**
387 : : * valent_mixer_adapter_set_default_output: (set-property default-output) (virtual set_default_output)
388 : : * @adapter: a `ValentMixerAdapter`
389 : : * @stream: a `ValentMixerStream`
390 : : *
391 : : * Set the default output stream for @adapter to @stream.
392 : : *
393 : : * Since: 1.0
394 : : */
395 : : void
396 : 15 : valent_mixer_adapter_set_default_output (ValentMixerAdapter *adapter,
397 : : ValentMixerStream *stream)
398 : : {
399 : 15 : VALENT_ENTRY;
400 : :
401 [ - + ]: 15 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
402 [ + - ]: 15 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
403 : :
404 : 15 : VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->set_default_output (adapter, stream);
405 : :
406 : 15 : VALENT_EXIT;
407 : : }
408 : :
|