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 [ + + + - ]: 673 : 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 : 35 : valent_mixer_adapter_get_n_items (GListModel *list)
82 : : {
83 : 35 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (list);
84 : 35 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
85 : :
86 [ + - ]: 35 : g_assert (VALENT_IS_MIXER_ADAPTER (self));
87 : :
88 : 35 : return priv->streams->len;
89 : : }
90 : :
91 : : static void
92 : 58 : g_list_model_iface_init (GListModelInterface *iface)
93 : : {
94 : 58 : iface->get_item = valent_mixer_adapter_get_item;
95 : 58 : iface->get_item_type = valent_mixer_adapter_get_item_type;
96 : 58 : iface->get_n_items = valent_mixer_adapter_get_n_items;
97 : 58 : }
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 : 24 : valent_mixer_adapter_destroy (ValentObject *object)
138 : : {
139 : 24 : ValentMixerAdapter *self = VALENT_MIXER_ADAPTER (object);
140 : 24 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (self);
141 : :
142 [ + + ]: 24 : g_clear_pointer (&priv->streams, g_ptr_array_unref);
143 : :
144 : 24 : VALENT_OBJECT_CLASS (valent_mixer_adapter_parent_class)->destroy (object);
145 : 24 : }
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 : 58 : valent_mixer_adapter_class_init (ValentMixerAdapterClass *klass)
198 : : {
199 : 58 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
200 : 58 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
201 : :
202 : 58 : object_class->get_property = valent_mixer_adapter_get_property;
203 : 58 : object_class->set_property = valent_mixer_adapter_set_property;
204 : :
205 : 58 : vobject_class->destroy = valent_mixer_adapter_destroy;
206 : :
207 : 58 : klass->get_default_input = valent_mixer_adapter_real_get_default_input;
208 : 58 : klass->set_default_input = valent_mixer_adapter_real_set_default_input;
209 : 58 : klass->get_default_output = valent_mixer_adapter_real_get_default_output;
210 : 58 : 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 : 116 : properties [PROP_DEFAULT_INPUT] =
223 : 58 : 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 : 116 : properties [PROP_DEFAULT_OUTPUT] =
240 : 58 : 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 : 58 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
247 : 58 : }
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 : 4 : valent_mixer_adapter_stream_removed (ValentMixerAdapter *adapter,
300 : : ValentMixerStream *stream)
301 : : {
302 : 4 : ValentMixerAdapterPrivate *priv = valent_mixer_adapter_get_instance_private (adapter);
303 : 4 : g_autoptr (ValentMixerStream) item = NULL;
304 : 4 : unsigned int position = 0;
305 : :
306 [ + - ]: 4 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
307 [ - + ]: 4 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
308 : :
309 [ + - ]: 4 : if (!g_ptr_array_find (priv->streams, stream, &position))
310 : : return;
311 : :
312 : 4 : item = g_ptr_array_steal_index (priv->streams, position);
313 [ + - ]: 4 : g_list_model_items_changed (G_LIST_MODEL (adapter), position, 1, 0);
314 : : }
315 : :
316 : : /**
317 : : * valent_mixer_adapter_get_default_input: (get-property default-input) (virtual get_default_input)
318 : : * @adapter: a `ValentMixerAdapter`
319 : : *
320 : : * Get the default input stream for @adapter.
321 : : *
322 : : * Returns: (transfer none): a `ValentMixerStream`
323 : : *
324 : : * Since: 1.0
325 : : */
326 : : ValentMixerStream *
327 : 12 : valent_mixer_adapter_get_default_input (ValentMixerAdapter *adapter)
328 : : {
329 : 12 : ValentMixerStream *ret;
330 : :
331 : 12 : VALENT_ENTRY;
332 : :
333 [ + - ]: 12 : g_return_val_if_fail (VALENT_IS_MIXER_ADAPTER (adapter), NULL);
334 : :
335 : 12 : ret = VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->get_default_input (adapter);
336 : :
337 : 12 : VALENT_RETURN (ret);
338 : : }
339 : :
340 : : /**
341 : : * valent_mixer_adapter_set_default_input: (set-property default-input) (virtual set_default_input)
342 : : * @adapter: a `ValentMixerAdapter`
343 : : * @stream: a `ValentMixerStream`
344 : : *
345 : : * Set the default input stream for @adapter to @stream.
346 : : *
347 : : * Since: 1.0
348 : : */
349 : : void
350 : 10 : valent_mixer_adapter_set_default_input (ValentMixerAdapter *adapter,
351 : : ValentMixerStream *stream)
352 : : {
353 : 10 : VALENT_ENTRY;
354 : :
355 [ + - ]: 10 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
356 [ - + ]: 10 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
357 : :
358 : 10 : VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->set_default_input (adapter, stream);
359 : :
360 : 10 : VALENT_EXIT;
361 : : }
362 : :
363 : : /**
364 : : * valent_mixer_adapter_get_default_output: (get-property default-output) (virtual get_default_output)
365 : : * @adapter: a `ValentMixerAdapter`
366 : : *
367 : : * Get the default output stream for @adapter.
368 : : *
369 : : * Returns: (transfer none): a `ValentMixerStream`
370 : : *
371 : : * Since: 1.0
372 : : */
373 : : ValentMixerStream *
374 : 28 : valent_mixer_adapter_get_default_output (ValentMixerAdapter *adapter)
375 : : {
376 : 28 : ValentMixerStream *ret;
377 : :
378 : 28 : VALENT_ENTRY;
379 : :
380 [ + - ]: 28 : g_return_val_if_fail (VALENT_IS_MIXER_ADAPTER (adapter), NULL);
381 : :
382 : 28 : ret = VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->get_default_output (adapter);
383 : :
384 : 28 : VALENT_RETURN (ret);
385 : : }
386 : :
387 : : /**
388 : : * valent_mixer_adapter_set_default_output: (set-property default-output) (virtual set_default_output)
389 : : * @adapter: a `ValentMixerAdapter`
390 : : * @stream: a `ValentMixerStream`
391 : : *
392 : : * Set the default output stream for @adapter to @stream.
393 : : *
394 : : * Since: 1.0
395 : : */
396 : : void
397 : 15 : valent_mixer_adapter_set_default_output (ValentMixerAdapter *adapter,
398 : : ValentMixerStream *stream)
399 : : {
400 : 15 : VALENT_ENTRY;
401 : :
402 [ + - ]: 15 : g_return_if_fail (VALENT_IS_MIXER_ADAPTER (adapter));
403 [ - + ]: 15 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
404 : :
405 : 15 : VALENT_MIXER_ADAPTER_GET_CLASS (adapter)->set_default_output (adapter, stream);
406 : :
407 : 15 : VALENT_EXIT;
408 : : }
409 : :
|