1 /*
2 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <glib.h>
19 #include <glib-object.h>
20 #include <libmatemixer/matemixer.h>
21 #include <libmatemixer/matemixer-private.h>
22
23 #include <pulse/pulseaudio.h>
24
25 #include "pulse-connection.h"
26 #include "pulse-helpers.h"
27 #include "pulse-monitor.h"
28 #include "pulse-stream.h"
29 #include "pulse-stream-control.h"
30
31 struct _PulseStreamControlPrivate
32 {
33 guint32 index;
34 guint volume;
35 pa_cvolume cvolume;
36 pa_volume_t base_volume;
37 pa_channel_map channel_map;
38 PulseConnection *connection;
39 PulseMonitor *monitor;
40 MateMixerAppInfo *app_info;
41 };
42
43 enum {
44 PROP_0,
45 PROP_INDEX,
46 PROP_CONNECTION,
47 N_PROPERTIES
48 };
49
50 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
51
52 static void pulse_stream_control_get_property (GObject *object,
53 guint param_id,
54 GValue *value,
55 GParamSpec *pspec);
56 static void pulse_stream_control_set_property (GObject *object,
57 guint param_id,
58 const GValue *value,
59 GParamSpec *pspec);
60
61 static void pulse_stream_control_dispose (GObject *object);
62 static void pulse_stream_control_finalize (GObject *object);
63
64 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PulseStreamControl, pulse_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
65
66 static MateMixerAppInfo * pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc);
67
68 static gboolean pulse_stream_control_set_mute (MateMixerStreamControl *mmsc,
69 gboolean mute);
70
71 static guint pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
72
73 static guint pulse_stream_control_get_volume (MateMixerStreamControl *mmsc);
74 static gboolean pulse_stream_control_set_volume (MateMixerStreamControl *mmsc,
75 guint volume);
76
77 static gdouble pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc);
78 static gboolean pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc,
79 gdouble decibel);
80
81 static guint pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc,
82 guint channel);
83 static gboolean pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
84 guint channel,
85 guint volume);
86
87 static gdouble pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc,
88 guint channel);
89 static gboolean pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
90 guint channel,
91 gdouble decibel);
92
93 static MateMixerChannelPosition pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc,
94 guint channel);
95 static gboolean pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
96 MateMixerChannelPosition position);
97
98 static gboolean pulse_stream_control_set_balance (MateMixerStreamControl *mmsc,
99 gfloat balance);
100
101 static gboolean pulse_stream_control_set_fade (MateMixerStreamControl *mmsc,
102 gfloat fade);
103
104 static gboolean pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc);
105 static gboolean pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc,
106 gboolean enabled);
107
108 static guint pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc);
109 static guint pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc);
110 static guint pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
111 static guint pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
112
113 static void on_monitor_value (PulseMonitor *monitor,
114 gdouble value,
115 PulseStreamControl *control);
116
117 static void set_balance_fade (PulseStreamControl *control);
118
119 static gboolean set_cvolume (PulseStreamControl *control,
120 pa_cvolume *cvolume);
121
122 static void
pulse_stream_control_class_init(PulseStreamControlClass * klass)123 pulse_stream_control_class_init (PulseStreamControlClass *klass)
124 {
125 GObjectClass *object_class;
126 MateMixerStreamControlClass *control_class;
127
128 object_class = G_OBJECT_CLASS (klass);
129 object_class->dispose = pulse_stream_control_dispose;
130 object_class->finalize = pulse_stream_control_finalize;
131 object_class->get_property = pulse_stream_control_get_property;
132 object_class->set_property = pulse_stream_control_set_property;
133
134 control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
135 control_class->get_app_info = pulse_stream_control_get_app_info;
136 control_class->set_mute = pulse_stream_control_set_mute;
137 control_class->get_num_channels = pulse_stream_control_get_num_channels;
138 control_class->get_volume = pulse_stream_control_get_volume;
139 control_class->set_volume = pulse_stream_control_set_volume;
140 control_class->get_decibel = pulse_stream_control_get_decibel;
141 control_class->set_decibel = pulse_stream_control_set_decibel;
142 control_class->get_channel_volume = pulse_stream_control_get_channel_volume;
143 control_class->set_channel_volume = pulse_stream_control_set_channel_volume;
144 control_class->get_channel_decibel = pulse_stream_control_get_channel_decibel;
145 control_class->set_channel_decibel = pulse_stream_control_set_channel_decibel;
146 control_class->get_channel_position = pulse_stream_control_get_channel_position;
147 control_class->has_channel_position = pulse_stream_control_has_channel_position;
148 control_class->set_balance = pulse_stream_control_set_balance;
149 control_class->set_fade = pulse_stream_control_set_fade;
150 control_class->get_monitor_enabled = pulse_stream_control_get_monitor_enabled;
151 control_class->set_monitor_enabled = pulse_stream_control_set_monitor_enabled;
152 control_class->get_min_volume = pulse_stream_control_get_min_volume;
153 control_class->get_max_volume = pulse_stream_control_get_max_volume;
154 control_class->get_normal_volume = pulse_stream_control_get_normal_volume;
155 control_class->get_base_volume = pulse_stream_control_get_base_volume;
156
157 properties[PROP_INDEX] =
158 g_param_spec_uint ("index",
159 "Index",
160 "Index of the stream control",
161 0,
162 G_MAXUINT,
163 0,
164 G_PARAM_READWRITE |
165 G_PARAM_CONSTRUCT_ONLY |
166 G_PARAM_STATIC_STRINGS);
167
168 properties[PROP_CONNECTION] =
169 g_param_spec_object ("connection",
170 "Connection",
171 "PulseAudio connection",
172 PULSE_TYPE_CONNECTION,
173 G_PARAM_READWRITE |
174 G_PARAM_CONSTRUCT_ONLY |
175 G_PARAM_STATIC_STRINGS);
176
177 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
178 }
179
180 static void
pulse_stream_control_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)181 pulse_stream_control_get_property (GObject *object,
182 guint param_id,
183 GValue *value,
184 GParamSpec *pspec)
185 {
186 PulseStreamControl *control;
187
188 control = PULSE_STREAM_CONTROL (object);
189
190 switch (param_id) {
191 case PROP_INDEX:
192 g_value_set_uint (value, control->priv->index);
193 break;
194 case PROP_CONNECTION:
195 g_value_set_object (value, control->priv->connection);
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
199 break;
200 }
201 }
202
203 static void
pulse_stream_control_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)204 pulse_stream_control_set_property (GObject *object,
205 guint param_id,
206 const GValue *value,
207 GParamSpec *pspec)
208 {
209 PulseStreamControl *control;
210
211 control = PULSE_STREAM_CONTROL (object);
212
213 switch (param_id) {
214 case PROP_INDEX:
215 control->priv->index = g_value_get_uint (value);
216 break;
217 case PROP_CONNECTION:
218 control->priv->connection = g_value_dup_object (value);
219 break;
220 default:
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
222 break;
223 }
224 }
225
226 static void
pulse_stream_control_init(PulseStreamControl * control)227 pulse_stream_control_init (PulseStreamControl *control)
228 {
229 control->priv = pulse_stream_control_get_instance_private (control);
230
231 /* Initialize empty volume and channel map structures, they will be used
232 * if the stream does not support volume */
233 pa_cvolume_init (&control->priv->cvolume);
234
235 pa_channel_map_init (&control->priv->channel_map);
236 }
237
238 static void
pulse_stream_control_dispose(GObject * object)239 pulse_stream_control_dispose (GObject *object)
240 {
241 PulseStreamControl *control;
242
243 control = PULSE_STREAM_CONTROL (object);
244
245 g_clear_object (&control->priv->monitor);
246 g_clear_object (&control->priv->connection);
247
248 G_OBJECT_CLASS (pulse_stream_control_parent_class)->dispose (object);
249 }
250
251 static void
pulse_stream_control_finalize(GObject * object)252 pulse_stream_control_finalize (GObject *object)
253 {
254 PulseStreamControl *control;
255
256 control = PULSE_STREAM_CONTROL (object);
257
258 if (control->priv->app_info != NULL)
259 _mate_mixer_app_info_free (control->priv->app_info);
260
261 G_OBJECT_CLASS (pulse_stream_control_parent_class)->finalize (object);
262 }
263
264 guint32
pulse_stream_control_get_index(PulseStreamControl * control)265 pulse_stream_control_get_index (PulseStreamControl *control)
266 {
267 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), PA_INVALID_INDEX);
268
269 return control->priv->index;
270 }
271
272 guint32
pulse_stream_control_get_stream_index(PulseStreamControl * control)273 pulse_stream_control_get_stream_index (PulseStreamControl *control)
274 {
275 MateMixerStream *stream;
276
277 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), PA_INVALID_INDEX);
278
279 stream = mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (control));
280 if (G_UNLIKELY (stream == NULL))
281 return PA_INVALID_INDEX;
282
283 return pulse_stream_get_index (PULSE_STREAM (stream));
284 }
285
286 PulseConnection *
pulse_stream_control_get_connection(PulseStreamControl * control)287 pulse_stream_control_get_connection (PulseStreamControl *control)
288 {
289 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
290
291 return control->priv->connection;
292 }
293
294 PulseMonitor *
pulse_stream_control_get_monitor(PulseStreamControl * control)295 pulse_stream_control_get_monitor (PulseStreamControl *control)
296 {
297 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
298
299 return control->priv->monitor;
300 }
301
302 const pa_cvolume *
pulse_stream_control_get_cvolume(PulseStreamControl * control)303 pulse_stream_control_get_cvolume (PulseStreamControl *control)
304 {
305 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
306
307 return &control->priv->cvolume;
308 }
309
310 const pa_channel_map *
pulse_stream_control_get_channel_map(PulseStreamControl * control)311 pulse_stream_control_get_channel_map (PulseStreamControl *control)
312 {
313 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
314
315 return &control->priv->channel_map;
316 }
317
318 void
pulse_stream_control_set_app_info(PulseStreamControl * control,MateMixerAppInfo * info,gboolean take)319 pulse_stream_control_set_app_info (PulseStreamControl *control,
320 MateMixerAppInfo *info,
321 gboolean take)
322 {
323 g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
324
325 if (G_UNLIKELY (control->priv->app_info != NULL))
326 _mate_mixer_app_info_free (control->priv->app_info);
327
328 if (take == TRUE)
329 control->priv->app_info = info;
330 else
331 control->priv->app_info = _mate_mixer_app_info_copy (info);
332 }
333
334 void
pulse_stream_control_set_channel_map(PulseStreamControl * control,const pa_channel_map * map)335 pulse_stream_control_set_channel_map (PulseStreamControl *control, const pa_channel_map *map)
336 {
337 MateMixerStreamControlFlags flags;
338
339 g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
340
341 flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
342
343 if (map != NULL && pa_channel_map_valid (map)) {
344 if (pa_channel_map_can_balance (map))
345 flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
346 else
347 flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
348
349 if (pa_channel_map_can_fade (map))
350 flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
351 else
352 flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_FADE;
353
354 control->priv->channel_map = *map;
355 } else {
356 flags &= ~(MATE_MIXER_STREAM_CONTROL_CAN_BALANCE | MATE_MIXER_STREAM_CONTROL_CAN_FADE);
357
358 /* If the channel map is not valid, create an empty channel map, which
359 * also won't validate, but at least we know what it is */
360 pa_channel_map_init (&control->priv->channel_map);
361 }
362
363 _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
364 }
365
366 void
pulse_stream_control_set_cvolume(PulseStreamControl * control,const pa_cvolume * cvolume,pa_volume_t base_volume)367 pulse_stream_control_set_cvolume (PulseStreamControl *control,
368 const pa_cvolume *cvolume,
369 pa_volume_t base_volume)
370 {
371 MateMixerStreamControlFlags flags;
372
373 g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
374
375 /* The base volume is not a property */
376 control->priv->base_volume = base_volume;
377
378 flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
379
380 g_object_freeze_notify (G_OBJECT (control));
381
382 if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
383 /* Decibel volume and volume settability flags must be provided by
384 * the implementation */
385 flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE;
386
387 if (pa_cvolume_equal (&control->priv->cvolume, cvolume) == 0) {
388 control->priv->cvolume = *cvolume;
389 control->priv->volume = (guint) pa_cvolume_max (&control->priv->cvolume);
390
391 g_object_notify (G_OBJECT (control), "volume");
392 }
393 } else {
394 flags &= ~(MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
395 MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
396 MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL);
397
398 /* If the cvolume is not valid, create an empty cvolume, which also
399 * won't validate, but at least we know what it is */
400 pa_cvolume_init (&control->priv->cvolume);
401
402 if (control->priv->volume != (guint) PA_VOLUME_MUTED) {
403 control->priv->volume = (guint) PA_VOLUME_MUTED;
404
405 g_object_notify (G_OBJECT (control), "volume");
406 }
407 }
408
409 _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
410
411 /* Changing volume may change the balance and fade values as well */
412 set_balance_fade (control);
413
414 g_object_thaw_notify (G_OBJECT (control));
415 }
416
417 static MateMixerAppInfo *
pulse_stream_control_get_app_info(MateMixerStreamControl * mmsc)418 pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc)
419 {
420 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), NULL);
421
422 return PULSE_STREAM_CONTROL (mmsc)->priv->app_info;
423 }
424
425 static gboolean
pulse_stream_control_set_mute(MateMixerStreamControl * mmsc,gboolean mute)426 pulse_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
427 {
428 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
429
430 return PULSE_STREAM_CONTROL_GET_CLASS (mmsc)->set_mute (PULSE_STREAM_CONTROL (mmsc), mute);
431 }
432
433 static guint
pulse_stream_control_get_num_channels(MateMixerStreamControl * mmsc)434 pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc)
435 {
436 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), 0);
437
438 return PULSE_STREAM_CONTROL (mmsc)->priv->channel_map.channels;
439 }
440
441 static guint
pulse_stream_control_get_volume(MateMixerStreamControl * mmsc)442 pulse_stream_control_get_volume (MateMixerStreamControl *mmsc)
443 {
444 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
445
446 return PULSE_STREAM_CONTROL (mmsc)->priv->volume;
447 }
448
449 static gboolean
pulse_stream_control_set_volume(MateMixerStreamControl * mmsc,guint volume)450 pulse_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
451 {
452 PulseStreamControl *control;
453 pa_cvolume cvolume;
454
455 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
456
457 control = PULSE_STREAM_CONTROL (mmsc);
458 cvolume = control->priv->cvolume;
459
460 if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
461 return FALSE;
462
463 return set_cvolume (control, &cvolume);
464 }
465
466 static gdouble
pulse_stream_control_get_decibel(MateMixerStreamControl * mmsc)467 pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc)
468 {
469 gdouble value;
470
471 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
472
473 value = pa_sw_volume_to_dB (pulse_stream_control_get_volume (mmsc));
474
475 /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
476 return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
477 }
478
479 static gboolean
pulse_stream_control_set_decibel(MateMixerStreamControl * mmsc,gdouble decibel)480 pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc, gdouble decibel)
481 {
482 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
483
484 return pulse_stream_control_set_volume (mmsc,
485 pa_sw_volume_from_dB (decibel));
486 }
487
488 static guint
pulse_stream_control_get_channel_volume(MateMixerStreamControl * mmsc,guint channel)489 pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
490 {
491 PulseStreamControl *control;
492
493 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
494
495 control = PULSE_STREAM_CONTROL (mmsc);
496
497 if (channel >= control->priv->cvolume.channels)
498 return (guint) PA_VOLUME_MUTED;
499
500 return (guint) control->priv->cvolume.values[channel];
501 }
502
503 static gboolean
pulse_stream_control_set_channel_volume(MateMixerStreamControl * mmsc,guint channel,guint volume)504 pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume)
505 {
506 PulseStreamControl *control;
507 pa_cvolume cvolume;
508
509 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
510
511 control = PULSE_STREAM_CONTROL (mmsc);
512
513 if (channel >= control->priv->cvolume.channels)
514 return FALSE;
515
516 /* This is safe, because the cvolume is validated by set_cvolume() */
517 cvolume = control->priv->cvolume;
518 cvolume.values[channel] = (pa_volume_t) volume;
519
520 return set_cvolume (control, &cvolume);
521 }
522
523 static gdouble
pulse_stream_control_get_channel_decibel(MateMixerStreamControl * mmsc,guint channel)524 pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint channel)
525 {
526 PulseStreamControl *control;
527 gdouble value;
528
529 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
530
531 control = PULSE_STREAM_CONTROL (mmsc);
532
533 if (channel >= control->priv->cvolume.channels)
534 return -MATE_MIXER_INFINITY;
535
536 value = pa_sw_volume_to_dB (control->priv->cvolume.values[channel]);
537
538 return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
539 }
540
541 static gboolean
pulse_stream_control_set_channel_decibel(MateMixerStreamControl * mmsc,guint channel,gdouble decibel)542 pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
543 guint channel,
544 gdouble decibel)
545 {
546 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
547
548 return pulse_stream_control_set_channel_volume (mmsc,
549 channel,
550 pa_sw_volume_from_dB (decibel));
551 }
552
553 static MateMixerChannelPosition
pulse_stream_control_get_channel_position(MateMixerStreamControl * mmsc,guint channel)554 pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
555 {
556 PulseStreamControl *control;
557
558 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
559
560 control = PULSE_STREAM_CONTROL (mmsc);
561
562 if (channel >= control->priv->channel_map.channels)
563 return MATE_MIXER_CHANNEL_UNKNOWN;
564
565 if (control->priv->channel_map.map[channel] == PA_CHANNEL_POSITION_INVALID)
566 return MATE_MIXER_CHANNEL_UNKNOWN;
567
568 return pulse_channel_map_from[control->priv->channel_map.map[channel]];
569 }
570
571 static gboolean
pulse_stream_control_has_channel_position(MateMixerStreamControl * mmsc,MateMixerChannelPosition position)572 pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
573 MateMixerChannelPosition position)
574 {
575 PulseStreamControl *control;
576
577 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
578
579 control = PULSE_STREAM_CONTROL (mmsc);
580
581 /* Handle invalid position as a special case, otherwise this function would
582 * return TRUE for e.g. unknown index in a default channel map */
583 if (pulse_channel_map_to[position] == PA_CHANNEL_POSITION_INVALID)
584 return FALSE;
585
586 if (pa_channel_map_has_position (&control->priv->channel_map,
587 pulse_channel_map_to[position]) != 0)
588 return TRUE;
589 else
590 return FALSE;
591 }
592
593 static gboolean
pulse_stream_control_set_balance(MateMixerStreamControl * mmsc,gfloat balance)594 pulse_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
595 {
596 PulseStreamControl *control;
597 pa_cvolume cvolume;
598
599 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
600
601 control = PULSE_STREAM_CONTROL (mmsc);
602 cvolume = control->priv->cvolume;
603
604 if (pa_cvolume_set_balance (&cvolume, &control->priv->channel_map, balance) == NULL)
605 return FALSE;
606
607 return set_cvolume (control, &cvolume);
608 }
609
610 static gboolean
pulse_stream_control_set_fade(MateMixerStreamControl * mmsc,gfloat fade)611 pulse_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
612 {
613 PulseStreamControl *control;
614 pa_cvolume cvolume;
615
616 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
617
618 control = PULSE_STREAM_CONTROL (mmsc);
619 cvolume = control->priv->cvolume;
620
621 if (pa_cvolume_set_fade (&cvolume, &control->priv->channel_map, fade) == NULL)
622 return FALSE;
623
624 return set_cvolume (control, &cvolume);
625 }
626
627 static gboolean
pulse_stream_control_get_monitor_enabled(MateMixerStreamControl * mmsc)628 pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc)
629 {
630 PulseStreamControl *control;
631
632 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
633
634 control = PULSE_STREAM_CONTROL (mmsc);
635
636 if (control->priv->monitor != NULL)
637 return pulse_monitor_get_enabled (control->priv->monitor);
638
639 return FALSE;
640 }
641
642 static gboolean
pulse_stream_control_set_monitor_enabled(MateMixerStreamControl * mmsc,gboolean enabled)643 pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc, gboolean enabled)
644 {
645 PulseStreamControl *control;
646
647 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
648
649 control = PULSE_STREAM_CONTROL (mmsc);
650
651 if (enabled == TRUE) {
652 if (control->priv->monitor == NULL) {
653 control->priv->monitor =
654 PULSE_STREAM_CONTROL_GET_CLASS (control)->create_monitor (control);
655
656 if (G_UNLIKELY (control->priv->monitor == NULL))
657 return FALSE;
658
659 g_signal_connect (G_OBJECT (control->priv->monitor),
660 "value",
661 G_CALLBACK (on_monitor_value),
662 control);
663 }
664 } else {
665 if (control->priv->monitor == NULL)
666 return FALSE;
667 }
668 return pulse_monitor_set_enabled (control->priv->monitor, enabled);
669 }
670
671 static guint
pulse_stream_control_get_min_volume(MateMixerStreamControl * mmsc)672 pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc)
673 {
674 return (guint) PA_VOLUME_MUTED;
675 }
676
677 static guint
pulse_stream_control_get_max_volume(MateMixerStreamControl * mmsc)678 pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc)
679 {
680 MateMixerStreamControlFlags flags;
681
682 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
683
684 flags = mate_mixer_stream_control_get_flags (mmsc);
685
686 /*
687 * From PulseAudio wiki:
688 * For all volumes that are > PA_VOLUME_NORM (i.e. beyond the maximum volume
689 * setting of the hw) PA will do digital amplification. This works only for
690 * devices that have PA_SINK_DECIBEL_VOLUME/PA_SOURCE_DECIBEL_VOLUME set. For
691 * devices that lack this flag do not extend the volume slider like this, it
692 * will not have any effect.
693 */
694 if (flags & MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL)
695 return (guint) PA_VOLUME_UI_MAX;
696 else
697 return (guint) PA_VOLUME_NORM;
698 }
699
700 static guint
pulse_stream_control_get_normal_volume(MateMixerStreamControl * mmsc)701 pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)
702 {
703 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
704
705 return (guint) PA_VOLUME_NORM;
706 }
707
708 static guint
pulse_stream_control_get_base_volume(MateMixerStreamControl * mmsc)709 pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
710 {
711 PulseStreamControl *control;
712
713 g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
714
715 control = PULSE_STREAM_CONTROL (mmsc);
716
717 if (control->priv->base_volume > 0)
718 return (guint) control->priv->base_volume;
719 else
720 return (guint) PA_VOLUME_NORM;
721 }
722
723 static void
on_monitor_value(PulseMonitor * monitor,gdouble value,PulseStreamControl * control)724 on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStreamControl *control)
725 {
726 g_signal_emit_by_name (G_OBJECT (control),
727 "monitor-value",
728 value);
729 }
730
731 static void
set_balance_fade(PulseStreamControl * control)732 set_balance_fade (PulseStreamControl *control)
733 {
734 gfloat value;
735
736 /* PulseAudio returns the default 0.0f value on error, so skip checking validity
737 * of the channel map and cvolume */
738 value = pa_cvolume_get_balance (&control->priv->cvolume,
739 &control->priv->channel_map);
740
741 _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control), value);
742
743 value = pa_cvolume_get_fade (&control->priv->cvolume,
744 &control->priv->channel_map);
745
746 _mate_mixer_stream_control_set_fade (MATE_MIXER_STREAM_CONTROL (control), value);
747 }
748
749 static gboolean
set_cvolume(PulseStreamControl * control,pa_cvolume * cvolume)750 set_cvolume (PulseStreamControl *control, pa_cvolume *cvolume)
751 {
752 PulseStreamControlClass *klass;
753
754 if (pa_cvolume_valid (cvolume) == 0)
755 return FALSE;
756 if (pa_cvolume_equal (cvolume, &control->priv->cvolume) != 0)
757 return TRUE;
758
759 klass = PULSE_STREAM_CONTROL_GET_CLASS (control);
760
761 if (klass->set_volume (control, cvolume) == FALSE)
762 return FALSE;
763
764 control->priv->cvolume = *cvolume;
765 control->priv->volume = (guint) pa_cvolume_max (cvolume);
766
767 g_object_notify (G_OBJECT (control), "volume");
768
769 /* Changing volume may change the balance and fade values as well */
770 set_balance_fade (control);
771 return TRUE;
772 }
773