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-pipewire-stream"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <math.h>
9 : :
10 : : #include <pipewire/pipewire.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-pipewire-mixer.h"
14 : : #include "valent-pipewire-stream.h"
15 : :
16 : :
17 : : struct _ValentPipewireStream
18 : : {
19 : : ValentMixerStream parent_instance;
20 : :
21 : : ValentPipewireMixer *adapter;
22 : : uint32_t device_id;
23 : : uint32_t node_id;
24 : :
25 : : char *description;
26 : : unsigned int level;
27 : : gboolean muted;
28 : : };
29 : :
30 : 0 : G_DEFINE_FINAL_TYPE (ValentPipewireStream, valent_pipewire_stream, VALENT_TYPE_MIXER_STREAM)
31 : :
32 : : typedef enum {
33 : : PROP_ADAPTER = 1,
34 : : PROP_DEVICE_ID,
35 : : PROP_NODE_ID,
36 : : } ValentPipewireStreamProperty;
37 : :
38 : : static GParamSpec *properties[PROP_NODE_ID + 1] = { NULL, };
39 : :
40 : :
41 : : /*
42 : : * ValentMixerStream
43 : : */
44 : : static const char *
45 : 0 : valent_pipewire_stream_get_description (ValentMixerStream *stream)
46 : : {
47 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (stream);
48 : :
49 : 0 : g_assert (VALENT_IS_PIPEWIRE_STREAM (self));
50 : :
51 : 0 : return self->description;
52 : : }
53 : :
54 : : static unsigned int
55 : 0 : valent_pipewire_stream_get_level (ValentMixerStream *stream)
56 : : {
57 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (stream);
58 : :
59 : 0 : g_assert (VALENT_IS_PIPEWIRE_STREAM (self));
60 : :
61 : 0 : return self->level;
62 : : }
63 : :
64 : : static void
65 : 0 : valent_pipewire_stream_set_level (ValentMixerStream *stream,
66 : : unsigned int level)
67 : : {
68 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (stream);
69 : :
70 : 0 : g_assert (VALENT_IS_PIPEWIRE_STREAM (self));
71 : :
72 : 0 : if (self->level == level || self->adapter == NULL)
73 : : return;
74 : :
75 : : // TODO: fix property update listener instead
76 : 0 : self->level = level;
77 : 0 : g_object_notify (G_OBJECT (stream), "level");
78 : :
79 : 0 : valent_pipewire_mixer_set_stream_state (self->adapter,
80 : : self->device_id,
81 : : self->node_id,
82 : : level,
83 : : self->muted);
84 : : }
85 : :
86 : : static gboolean
87 : 0 : valent_pipewire_stream_get_muted (ValentMixerStream *stream)
88 : : {
89 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (stream);
90 : :
91 : 0 : g_assert (VALENT_IS_PIPEWIRE_STREAM (self));
92 : :
93 : 0 : return self->muted;
94 : : }
95 : :
96 : : static void
97 : 0 : valent_pipewire_stream_set_muted (ValentMixerStream *stream,
98 : : gboolean state)
99 : : {
100 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (stream);
101 : :
102 : 0 : g_assert (VALENT_IS_PIPEWIRE_STREAM (self));
103 : :
104 : 0 : if (self->muted == state || self->adapter == NULL)
105 : : return;
106 : :
107 : 0 : self->muted = state;
108 : 0 : g_object_notify (G_OBJECT (stream), "muted");
109 : :
110 : 0 : valent_pipewire_mixer_set_stream_state (self->adapter,
111 : : self->device_id,
112 : : self->node_id,
113 : : self->level,
114 : : state);
115 : : }
116 : :
117 : : /*
118 : : * GObject
119 : : */
120 : : static void
121 : 0 : valent_pipewire_stream_get_property (GObject *object,
122 : : guint prop_id,
123 : : GValue *value,
124 : : GParamSpec *pspec)
125 : : {
126 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (object);
127 : :
128 : 0 : switch ((ValentPipewireStreamProperty)prop_id)
129 : : {
130 : 0 : case PROP_ADAPTER:
131 : 0 : g_value_set_object (value, self->adapter);
132 : 0 : break;
133 : :
134 : 0 : case PROP_DEVICE_ID:
135 : 0 : g_value_set_uint (value, self->device_id);
136 : 0 : break;
137 : :
138 : 0 : case PROP_NODE_ID:
139 : 0 : g_value_set_uint (value, self->node_id);
140 : 0 : break;
141 : :
142 : 0 : default:
143 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144 : : }
145 : 0 : }
146 : :
147 : : static void
148 : 0 : valent_pipewire_stream_set_property (GObject *object,
149 : : guint prop_id,
150 : : const GValue *value,
151 : : GParamSpec *pspec)
152 : : {
153 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (object);
154 : :
155 : 0 : switch ((ValentPipewireStreamProperty)prop_id)
156 : : {
157 : 0 : case PROP_ADAPTER:
158 : 0 : self->adapter = g_value_get_object (value);
159 : 0 : g_object_add_weak_pointer (G_OBJECT (self->adapter),
160 : 0 : (gpointer *)&self->adapter);
161 : 0 : break;
162 : :
163 : 0 : case PROP_DEVICE_ID:
164 : 0 : self->device_id = g_value_get_uint (value);
165 : 0 : break;
166 : :
167 : 0 : case PROP_NODE_ID:
168 : 0 : self->node_id = g_value_get_uint (value);
169 : 0 : break;
170 : :
171 : 0 : default:
172 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173 : : }
174 : 0 : }
175 : :
176 : : static void
177 : 0 : valent_pipewire_stream_finalize (GObject *object)
178 : : {
179 : 0 : ValentPipewireStream *self = VALENT_PIPEWIRE_STREAM (object);
180 : :
181 : 0 : g_clear_weak_pointer (&self->adapter);
182 : 0 : g_clear_pointer (&self->description, g_free);
183 : :
184 : 0 : G_OBJECT_CLASS (valent_pipewire_stream_parent_class)->finalize (object);
185 : 0 : }
186 : :
187 : : static void
188 : 0 : valent_pipewire_stream_class_init (ValentPipewireStreamClass *klass)
189 : : {
190 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
191 : 0 : ValentMixerStreamClass *stream_class = VALENT_MIXER_STREAM_CLASS (klass);
192 : :
193 : 0 : object_class->finalize = valent_pipewire_stream_finalize;
194 : 0 : object_class->get_property = valent_pipewire_stream_get_property;
195 : 0 : object_class->set_property = valent_pipewire_stream_set_property;
196 : :
197 : 0 : stream_class->get_description = valent_pipewire_stream_get_description;
198 : 0 : stream_class->get_level = valent_pipewire_stream_get_level;
199 : 0 : stream_class->set_level = valent_pipewire_stream_set_level;
200 : 0 : stream_class->get_muted = valent_pipewire_stream_get_muted;
201 : 0 : stream_class->set_muted = valent_pipewire_stream_set_muted;
202 : :
203 : : /**
204 : : * ValentPaStream:adapter:
205 : : *
206 : : * The #GvcMixerStream this stream wraps.
207 : : */
208 : 0 : properties [PROP_ADAPTER] =
209 : 0 : g_param_spec_object ("adapter", NULL, NULL,
210 : : VALENT_TYPE_PIPEWIRE_MIXER,
211 : : (G_PARAM_READWRITE |
212 : : G_PARAM_CONSTRUCT_ONLY |
213 : : G_PARAM_EXPLICIT_NOTIFY |
214 : : G_PARAM_STATIC_STRINGS));
215 : :
216 : : /**
217 : : * ValentPaStream:device-id:
218 : : *
219 : : * The PipeWire device ID.
220 : : */
221 : 0 : properties [PROP_DEVICE_ID] =
222 : 0 : g_param_spec_uint ("device-id", NULL, NULL,
223 : : 0, G_MAXUINT32,
224 : : 0,
225 : : (G_PARAM_READWRITE |
226 : : G_PARAM_CONSTRUCT_ONLY |
227 : : G_PARAM_EXPLICIT_NOTIFY |
228 : : G_PARAM_STATIC_STRINGS));
229 : :
230 : : /**
231 : : * ValentPaStream:node-id:
232 : : *
233 : : * The PipeWire node ID.
234 : : */
235 : 0 : properties [PROP_NODE_ID] =
236 : 0 : g_param_spec_uint ("node-id", NULL, NULL,
237 : : 0, G_MAXUINT32,
238 : : 0,
239 : : (G_PARAM_READWRITE |
240 : : G_PARAM_CONSTRUCT_ONLY |
241 : : G_PARAM_EXPLICIT_NOTIFY |
242 : : G_PARAM_STATIC_STRINGS));
243 : :
244 : 0 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
245 : 0 : }
246 : :
247 : : static void
248 : 0 : valent_pipewire_stream_init (ValentPipewireStream *self)
249 : : {
250 : 0 : }
251 : :
252 : : /*< private >
253 : : * valent_pipewire_stream_update:
254 : : * @stream: `ValentPipewireStream`
255 : : * @description: the new description
256 : : * @level: the new volume level
257 : : * @state: the new mute state
258 : : *
259 : : * Update the stream state.
260 : : */
261 : : void
262 : 0 : valent_pipewire_stream_update (ValentPipewireStream *stream,
263 : : const char *description,
264 : : uint32_t level,
265 : : gboolean state)
266 : : {
267 : 0 : g_return_if_fail (VALENT_IS_MIXER_STREAM (stream));
268 : :
269 : 0 : if (g_set_str (&stream->description, description))
270 : 0 : g_object_notify (G_OBJECT (stream), "description");
271 : :
272 : 0 : if (stream->level != level)
273 : : {
274 : 0 : stream->level = level;
275 : 0 : g_object_notify (G_OBJECT (stream), "level");
276 : : }
277 : :
278 : 0 : if (stream->muted != state)
279 : : {
280 : 0 : stream->muted = state;
281 : 0 : g_object_notify (G_OBJECT (stream), "muted");
282 : : }
283 : : }
284 : :
|