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