~ubuntu-branches/ubuntu/wily/mate-settings-daemon/wily

« back to all changes in this revision

Viewing changes to plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.c

  • Committer: Package Import Robot
  • Author(s): John Paul Adrian Glaubitz, Martin Wimpress, John Paul Adrian Glaubitz
  • Date: 2015-08-16 16:35:32 UTC
  • mfrom: (10.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20150816163532-34zcev57w1c1bbv6
Tags: 1.10.1-1
[ Martin Wimpress ]
* debian/rules:
  + Remove obsolete build options.

[ John Paul Adrian Glaubitz ]
* Fix minor typo in debian/control (missing hyphen).
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
 
3
 
/* acme-volume.c
4
 
 
5
 
   Copyright (C) 2002, 2003 Bastien Nocera
6
 
   Copyright (C) 2004 Novell, Inc.
7
 
   Copyright (C) 2009 PERIER Romain <mrpouet@tuxfamily.org>
8
 
   Copyright (C) 2011 Stefano Karapetsas <stefano@karapetsas.com>
9
 
 
10
 
   The Mate Library is free software; you can redistribute it and/or
11
 
   modify it under the terms of the GNU Library General Public License as
12
 
   published by the Free Software Foundation; either version 2 of the
13
 
   License, or (at your option) any later version.
14
 
 
15
 
   The Mate Library is distributed in the hope that it will be useful,
16
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 
   Library General Public License for more details.
19
 
 
20
 
   You should have received a copy of the GNU Library General Public
21
 
   License along with the Mate Library; see the file COPYING.LIB.  If not,
22
 
   write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23
 
   Boston, MA 02110-1301, USA.
24
 
 
25
 
   Author: Bastien Nocera <hadess@hadess.net>
26
 
           Jon Trowbridge <trow@ximian.com>
27
 
*/
28
 
 
29
 
#include "config.h"
30
 
#include "gvc-gstreamer-acme-vol.h"
31
 
 
32
 
#include <gst/gst.h>
33
 
#include <gst/audio/mixerutils.h>
34
 
#include <gst/interfaces/mixer.h>
35
 
#include <gst/interfaces/propertyprobe.h>
36
 
 
37
 
#include <gio/gio.h>
38
 
 
39
 
#include <string.h>
40
 
 
41
 
#define TIMEOUT 4
42
 
 
43
 
#define MATE_SOUND_SCHEMA          "org.mate.sound"
44
 
#define DEFAULT_MIXER_DEVICE_KEY   "default-mixer-device"
45
 
#define DEFAULT_MIXER_TRACKS_KEY   "default-mixer-tracks"
46
 
 
47
 
#define ACME_VOLUME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACME_TYPE_VOLUME, AcmeVolumePrivate))
48
 
 
49
 
struct AcmeVolumePrivate {
50
 
        GstMixer     *mixer;
51
 
        GList        *mixer_tracks;
52
 
        guint         timer_id;
53
 
        gdouble       volume;
54
 
        gboolean      mute;
55
 
        GSettings    *settings;
56
 
};
57
 
 
58
 
G_DEFINE_TYPE (AcmeVolume, acme_volume, G_TYPE_OBJECT)
59
 
 
60
 
static gboolean acme_volume_open  (AcmeVolume *acme);
61
 
static void     acme_volume_close (AcmeVolume *acme);
62
 
static gboolean acme_volume_close_real (AcmeVolume *self);
63
 
 
64
 
static gpointer acme_volume_object = NULL;
65
 
 
66
 
static void
67
 
acme_volume_finalize (GObject *object)
68
 
{
69
 
        AcmeVolume *self;
70
 
 
71
 
        g_return_if_fail (object != NULL);
72
 
        g_return_if_fail (ACME_IS_VOLUME (object));
73
 
 
74
 
        self = ACME_VOLUME (object);
75
 
 
76
 
        if (self->_priv->timer_id != 0)
77
 
                g_source_remove (self->_priv->timer_id);
78
 
        acme_volume_close_real (self);
79
 
 
80
 
        if (self->_priv->settings != NULL) {
81
 
                g_object_unref (self->_priv->settings);
82
 
                self->_priv->settings = NULL;
83
 
        }
84
 
 
85
 
        G_OBJECT_CLASS (acme_volume_parent_class)->finalize (object);
86
 
}
87
 
 
88
 
void
89
 
acme_volume_set_mute (AcmeVolume *self, gboolean val)
90
 
{
91
 
        GList *t;
92
 
 
93
 
        g_return_if_fail(ACME_IS_VOLUME(self));
94
 
        g_return_if_fail(acme_volume_open(self));
95
 
 
96
 
        for (t = self->_priv->mixer_tracks; t != NULL; t = t->next) {
97
 
                GstMixerTrack *track = GST_MIXER_TRACK (t->data);
98
 
                gst_mixer_set_mute (self->_priv->mixer, track, val);
99
 
        }
100
 
        self->_priv->mute = val;
101
 
        acme_volume_close (self);
102
 
}
103
 
 
104
 
static void
105
 
update_state (AcmeVolume * self)
106
 
{
107
 
        gint *volumes, n;
108
 
        gdouble vol = 0;
109
 
        GstMixerTrack *track = GST_MIXER_TRACK (self->_priv->mixer_tracks->data);
110
 
 
111
 
        /* update mixer by getting volume */
112
 
        volumes = g_new0 (gint, track->num_channels);
113
 
        gst_mixer_get_volume (self->_priv->mixer, track, volumes);
114
 
        for (n = 0; n < track->num_channels; n++)
115
 
                vol += volumes[n];
116
 
        g_free (volumes);
117
 
        vol /= track->num_channels;
118
 
        vol = 100 * vol / (track->max_volume - track->min_volume);
119
 
 
120
 
        /* update mute flag, and volume if not muted */
121
 
        if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE))
122
 
                self->_priv->mute = TRUE;
123
 
        self->_priv->volume = vol;
124
 
}
125
 
 
126
 
gboolean
127
 
acme_volume_get_mute (AcmeVolume *self)
128
 
{
129
 
        g_return_val_if_fail(acme_volume_open(self), FALSE);
130
 
 
131
 
        update_state (self);
132
 
        acme_volume_close (self);
133
 
 
134
 
        return self->_priv->mute;
135
 
}
136
 
 
137
 
gint
138
 
acme_volume_get_volume (AcmeVolume *self)
139
 
{
140
 
 
141
 
        g_return_val_if_fail(acme_volume_open(self), 0);
142
 
 
143
 
        update_state (self);
144
 
 
145
 
        acme_volume_close (self);
146
 
        
147
 
        return (gint) (self->_priv->volume + 0.5);
148
 
}
149
 
 
150
 
void
151
 
acme_volume_set_volume (AcmeVolume *self, gint val)
152
 
{
153
 
        GList *t;
154
 
 
155
 
        g_return_if_fail(acme_volume_open(self));
156
 
 
157
 
        val = CLAMP (val, 0, 100);
158
 
 
159
 
        for (t = self->_priv->mixer_tracks; t != NULL; t = t->next) {
160
 
                GstMixerTrack *track = GST_MIXER_TRACK (t->data);
161
 
                gint *volumes, n;
162
 
                gdouble scale = (track->max_volume - track->min_volume) / 100.0;
163
 
                gint vol = (gint) (val * scale + track->min_volume + 0.5);
164
 
 
165
 
                volumes = g_new (gint, track->num_channels);
166
 
                for (n = 0; n < track->num_channels; n++)
167
 
                        volumes[n] = vol;
168
 
                gst_mixer_set_volume (self->_priv->mixer, track, volumes);
169
 
                g_free (volumes);
170
 
        }
171
 
 
172
 
        /* update state */
173
 
        self->_priv->volume = val;
174
 
 
175
 
        acme_volume_close (self);
176
 
}
177
 
 
178
 
void
179
 
acme_volume_mute_toggle (AcmeVolume *self)
180
 
{
181
 
        gboolean muted;
182
 
 
183
 
        g_return_if_fail (self != NULL);
184
 
        g_return_if_fail (ACME_IS_VOLUME(self));
185
 
 
186
 
        muted = acme_volume_get_mute(self);
187
 
        acme_volume_set_mute(self, !muted);
188
 
}
189
 
 
190
 
gint
191
 
acme_volume_get_threshold (AcmeVolume *self)
192
 
{
193
 
        GList *t;
194
 
        gint steps = 101;
195
 
 
196
 
        g_return_val_if_fail(acme_volume_open(self), 1);
197
 
 
198
 
        for (t = self->_priv->mixer_tracks; t != NULL; t = t->next) {
199
 
                GstMixerTrack *track = GST_MIXER_TRACK (t->data);
200
 
                gint track_steps = track->max_volume - track->min_volume;
201
 
                if (track_steps > 0 && track_steps < steps)
202
 
                        steps = track_steps;
203
 
        }
204
 
 
205
 
        acme_volume_close (self);
206
 
 
207
 
        return 100 / steps + 1;
208
 
}
209
 
 
210
 
static gboolean
211
 
acme_volume_close_real (AcmeVolume *self)
212
 
{
213
 
        if (self->_priv->mixer != NULL)
214
 
        {
215
 
                gst_element_set_state (GST_ELEMENT (self->_priv->mixer), GST_STATE_NULL);
216
 
                gst_object_unref (GST_OBJECT (self->_priv->mixer));
217
 
                g_list_foreach (self->_priv->mixer_tracks, (GFunc) g_object_unref, NULL);
218
 
                g_list_free (self->_priv->mixer_tracks);
219
 
                self->_priv->mixer = NULL;
220
 
                self->_priv->mixer_tracks = NULL;
221
 
        }
222
 
 
223
 
        self->_priv->timer_id = 0;
224
 
        return FALSE;
225
 
}
226
 
 
227
 
/*
228
 
 * _acme_set_mixer
229
 
 * @mixer  A pointer to mixer element
230
 
 * @data   A pointer to user data (AcmeVolume instance to be modified)
231
 
 * @return A gboolean indicating success if Master track was found, failed otherwises.
232
 
 */
233
 
static gboolean
234
 
_acme_set_mixer(GstMixer *mixer, gpointer user_data)
235
 
{
236
 
        const GList *tracks;
237
 
 
238
 
        for (tracks = gst_mixer_list_tracks (mixer); tracks != NULL; tracks = tracks->next) {
239
 
                GstMixerTrack *track = GST_MIXER_TRACK (tracks->data);
240
 
 
241
 
                if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER)) {
242
 
                        AcmeVolume *self;
243
 
 
244
 
                        self = ACME_VOLUME (user_data);
245
 
 
246
 
                        self->_priv->mixer = mixer;
247
 
                        self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
248
 
                        return TRUE;
249
 
                }
250
 
 
251
 
                continue;
252
 
        }
253
 
 
254
 
        return FALSE;
255
 
}
256
 
 
257
 
/* This is a modified version of code from gnome-media's gst-mixer */
258
 
static gboolean
259
 
acme_volume_open (AcmeVolume *self)
260
 
{
261
 
        gchar *mixer_device, **factory_and_device = NULL;
262
 
        GList *mixer_list;
263
 
 
264
 
        if (self->_priv->timer_id != 0) {
265
 
                g_source_remove (self->_priv->timer_id);
266
 
                self->_priv->timer_id = 0;
267
 
                return TRUE;
268
 
        }
269
 
 
270
 
        mixer_device = g_settings_get_string (self->_priv->settings, DEFAULT_MIXER_DEVICE_KEY);
271
 
        if (mixer_device != NULL)
272
 
                factory_and_device = g_strsplit (mixer_device, ":", 2);
273
 
 
274
 
        if (factory_and_device != NULL && factory_and_device[0] != NULL) {
275
 
                GstElement *element;
276
 
 
277
 
                element = gst_element_factory_make (factory_and_device[0], NULL);
278
 
 
279
 
                if (element != NULL) {
280
 
                        if (factory_and_device[1] != NULL &&
281
 
                            g_object_class_find_property (G_OBJECT_GET_CLASS (element), "device"))
282
 
                                g_object_set (G_OBJECT (element), "device", factory_and_device[1], NULL);
283
 
                        gst_element_set_state (element, GST_STATE_READY);
284
 
 
285
 
                        if (GST_IS_MIXER (element))
286
 
                                self->_priv->mixer = GST_MIXER (element);
287
 
                        else {
288
 
                                gst_element_set_state (element, GST_STATE_NULL);
289
 
                                gst_object_unref (element);
290
 
                        }
291
 
                }
292
 
        }
293
 
 
294
 
        g_free (mixer_device);
295
 
        g_strfreev (factory_and_device);
296
 
 
297
 
        if (self->_priv->mixer != NULL) {
298
 
                const GList *m;
299
 
                GSList *tracks, *t;
300
 
 
301
 
                /* Try to use tracks saved in GSettings 
302
 
                   Note: errors need to be treated , for example if the user set a non type list for this key
303
 
                   or if the elements type_list are not "matched" */
304
 
                gchar **settings_list;
305
 
                settings_list = g_settings_get_strv (self->_priv->settings, DEFAULT_MIXER_TRACKS_KEY);
306
 
                if (settings_list != NULL) {
307
 
                        gint i;
308
 
                        for (i = 0; i < G_N_ELEMENTS (settings_list); i++) {
309
 
                                if (settings_list[i] != NULL)
310
 
                                        tracks = g_slist_append (tracks, g_strdup (settings_list[i]));
311
 
                        }
312
 
                        g_strfreev (settings_list);
313
 
                }
314
 
                
315
 
                /* We use these tracks ONLY if they are supported on the system with the following mixer */
316
 
                for (m = gst_mixer_list_tracks (self->_priv->mixer); m != NULL; m = m->next) {
317
 
                        GstMixerTrack *track = GST_MIXER_TRACK (m->data);
318
 
 
319
 
                        for (t = tracks; t != NULL; t = t->next)
320
 
                                if (!strcmp (t->data, track->label))
321
 
                                        self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
322
 
 
323
 
                }
324
 
 
325
 
                g_slist_foreach (tracks, (GFunc)g_free, NULL);
326
 
                g_slist_free (tracks);
327
 
 
328
 
                /* If no track stored in GSettings is avaiable try to use Master track */
329
 
                if (self->_priv->mixer_tracks == NULL) {
330
 
                        for (m = gst_mixer_list_tracks (self->_priv->mixer); m != NULL; m = m->next) {
331
 
                                GstMixerTrack *track = GST_MIXER_TRACK (m->data);
332
 
 
333
 
                                if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER)) {
334
 
                                        self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
335
 
                                        break;
336
 
                                }
337
 
                        }
338
 
                }
339
 
 
340
 
                if (self->_priv->mixer_tracks != NULL)
341
 
                        return TRUE;
342
 
                else {
343
 
                        gst_element_set_state (GST_ELEMENT (self->_priv->mixer), GST_STATE_NULL);
344
 
                        gst_object_unref (self->_priv->mixer);
345
 
                }
346
 
        }
347
 
 
348
 
        /* Go through all elements of a certain class and check whether
349
 
         * they implement a mixer. If so, walk through the tracks and look
350
 
         * for first one named "volume".
351
 
         *
352
 
         * We should probably do something intelligent if we don't find an
353
 
         * appropriate mixer/track.  But now we do something stupid...
354
 
         * everything just becomes a no-op.
355
 
         */
356
 
        mixer_list = gst_audio_default_registry_mixer_filter (_acme_set_mixer,
357
 
                        TRUE,
358
 
                        self);
359
 
 
360
 
        if (mixer_list == NULL)
361
 
                return FALSE;
362
 
 
363
 
        /* do not unref the mixer as we keep the ref for self->priv->mixer */
364
 
        g_list_free (mixer_list);
365
 
 
366
 
        return TRUE;
367
 
}
368
 
 
369
 
static void
370
 
acme_volume_close (AcmeVolume *self)
371
 
{
372
 
        self->_priv->timer_id = g_timeout_add_seconds (TIMEOUT,
373
 
                        (GSourceFunc) acme_volume_close_real, self);
374
 
}
375
 
 
376
 
static void
377
 
acme_volume_init (AcmeVolume *self)
378
 
{
379
 
        self->_priv = ACME_VOLUME_GET_PRIVATE (self);
380
 
        self->_priv->settings = g_settings_new (MATE_SOUND_SCHEMA);
381
 
}
382
 
 
383
 
static void
384
 
acme_volume_class_init (AcmeVolumeClass *klass)
385
 
{
386
 
        G_OBJECT_CLASS (klass)->finalize = acme_volume_finalize;
387
 
 
388
 
        gst_init (NULL, NULL);
389
 
 
390
 
        g_type_class_add_private (klass, sizeof (AcmeVolumePrivate));
391
 
}
392
 
 
393
 
/* acme_volume_new
394
 
 * @return A singleton instance of type AcmeVolume
395
 
 */
396
 
AcmeVolume *
397
 
acme_volume_new (void)
398
 
{
399
 
        if (acme_volume_object == NULL) {
400
 
                acme_volume_object = g_object_new (ACME_TYPE_VOLUME, NULL);
401
 
                return ACME_VOLUME(acme_volume_object);
402
 
        }
403
 
        g_object_ref(acme_volume_object);
404
 
        return ACME_VOLUME(acme_volume_object);
405
 
}