~ubuntu-branches/ubuntu/saucy/cairo-dock-plug-ins/saucy

« back to all changes in this revision

Viewing changes to alsaMixer/src/applet-mixer.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2009-08-26 21:07:39 UTC
  • Revision ID: james.westby@ubuntu.com-20090826210739-gyjuuqezrzuluao4
Tags: upstream-2.0.8.1
ImportĀ upstreamĀ versionĀ 2.0.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation; either version 3
 
10
* of the License, or (at your option) any later version.
 
11
*
 
12
* This program is distributed in the hope that it will be useful,
 
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
* GNU General Public License for more details.
 
16
* You should have received a copy of the GNU General Public License
 
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
/******************************************************************************
 
21
 
 
22
This file is a part of the cairo-dock program, 
 
23
released under the terms of the GNU General Public License.
 
24
 
 
25
Written by Fabrice Rey (for any bug report, please mail me to fabounet@users.berlios.de)
 
26
 
 
27
******************************************************************************/
 
28
 
 
29
#include <stdlib.h>
 
30
#include <math.h>
 
31
#include <string.h>
 
32
#include <glib/gi18n.h>
 
33
#include <alsa/asoundlib.h>
 
34
 
 
35
#include "applet-struct.h"
 
36
#include "applet-draw.h"
 
37
#include "applet-mixer.h"
 
38
 
 
39
 
 
40
static int       mixer_level = 0;
 
41
static struct snd_mixer_selem_regopt mixer_options;
 
42
 
 
43
 
 
44
static int
 
45
mixer_event (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
 
46
{
 
47
        cd_debug ("");
 
48
        return 0;
 
49
}
 
50
 
 
51
void mixer_init (gchar *cCardID)  // this function is taken from AlsaMixer.
 
52
{
 
53
        snd_ctl_card_info_t *hw_info = NULL;  // ne pas liberer.
 
54
        snd_ctl_t *ctl_handle = NULL;
 
55
        int err;
 
56
        snd_ctl_card_info_alloca (&hw_info);
 
57
        
 
58
        if ((err = snd_ctl_open (&ctl_handle, cCardID, 0)) < 0)
 
59
        {
 
60
                myData.cErrorMessage = g_strdup_printf (D_("I couldn't open card '%s'"), cCardID);
 
61
                return ;
 
62
        }
 
63
        if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0)
 
64
        {
 
65
                myData.cErrorMessage = g_strdup_printf (D_("Card '%s' opened but I couldn't get any info"), cCardID);
 
66
                return ;
 
67
        }
 
68
        snd_ctl_close (ctl_handle);
 
69
        
 
70
        // open mixer device
 
71
        if ((err = snd_mixer_open (&myData.mixer_handle, 0)) < 0)
 
72
        {
 
73
                myData.cErrorMessage = g_strdup (D_("I couldn't open the mixer"));
 
74
                return ;
 
75
        }
 
76
        if (mixer_level == 0 && (err = snd_mixer_attach (myData.mixer_handle, cCardID)) < 0)
 
77
        {
 
78
                snd_mixer_free (myData.mixer_handle);
 
79
                myData.mixer_handle = NULL;
 
80
                myData.cErrorMessage = g_strdup (D_("I couldn't attach the mixer to the card"));
 
81
                return ;
 
82
        }
 
83
        if ((err = snd_mixer_selem_register (myData.mixer_handle, mixer_level > 0 ? &mixer_options : NULL, NULL)) < 0)
 
84
        {
 
85
                snd_mixer_free (myData.mixer_handle);
 
86
                myData.mixer_handle = NULL;
 
87
                myData.cErrorMessage = g_strdup (D_("I couldn't register options"));
 
88
                return ;
 
89
        }
 
90
        ///snd_mixer_set_callback (myData.mixer_handle, mixer_event);
 
91
        if ((err = snd_mixer_load (myData.mixer_handle)) < 0)
 
92
        {
 
93
                snd_mixer_free (myData.mixer_handle);
 
94
                myData.mixer_handle = NULL;
 
95
                myData.cErrorMessage = g_strdup (D_("I couldn't load the mixer"));
 
96
                return ;
 
97
        }
 
98
        
 
99
        myData.mixer_card_name = g_strdup (snd_ctl_card_info_get_name(hw_info));
 
100
        myData.mixer_device_name= g_strdup (snd_ctl_card_info_get_mixername(hw_info));
 
101
        cd_debug ("myData.mixer_card_name : %s ; myData.mixer_device_name : %s", myData.mixer_card_name, myData.mixer_device_name);
 
102
}
 
103
 
 
104
void mixer_stop (void)
 
105
{
 
106
        if (myData.mixer_handle != NULL)
 
107
        {
 
108
                snd_mixer_detach (myData.mixer_handle, myConfig.card_id);
 
109
                snd_mixer_close (myData.mixer_handle);
 
110
                myData.mixer_handle = NULL;
 
111
                myData.pControledElement = NULL;
 
112
                myData.pControledElement2 = NULL;
 
113
        }
 
114
}
 
115
 
 
116
 
 
117
GList *mixer_get_elements_list (void)
 
118
{
 
119
        snd_mixer_elem_t *elem;
 
120
        if (myData.mixer_handle == NULL)
 
121
                return NULL;
 
122
        cd_message ("");
 
123
        
 
124
        GList *pList = NULL;
 
125
        for (elem = snd_mixer_first_elem(myData.mixer_handle); elem; elem = snd_mixer_elem_next(elem))
 
126
        {
 
127
                if (snd_mixer_selem_is_active (elem) && snd_mixer_selem_has_playback_volume (elem))
 
128
                        pList = g_list_prepend (pList, snd_mixer_selem_get_name (elem));
 
129
        }
 
130
        return pList;
 
131
}
 
132
 
 
133
 
 
134
static snd_mixer_elem_t *_mixer_get_element_by_name (gchar *cName)
 
135
{
 
136
        if (myData.mixer_handle == NULL)
 
137
                return NULL;
 
138
        g_return_val_if_fail (cName != NULL, NULL);
 
139
        
 
140
        snd_mixer_elem_t *elem;
 
141
        for (elem = snd_mixer_first_elem(myData.mixer_handle); elem; elem = snd_mixer_elem_next(elem))
 
142
        {
 
143
                if (strcmp (cName, snd_mixer_selem_get_name (elem)) == 0)
 
144
                        return elem;
 
145
        }
 
146
        myData.cErrorMessage = g_strdup_printf (D_("I couldn't find any audio channel named '%s'\nYou should try to open the configuration panel of the applet,\n and select the proper audio channel you want to control."), cName);
 
147
        return NULL;
 
148
}
 
149
 
 
150
void mixer_get_controlled_element (void)
 
151
{
 
152
        myData.pControledElement = _mixer_get_element_by_name (myConfig.cMixerElementName);
 
153
        if (myData.pControledElement != NULL)
 
154
        {
 
155
                myData.bHasMuteSwitch = snd_mixer_selem_has_playback_switch (myData.pControledElement);
 
156
                
 
157
                snd_mixer_selem_get_playback_volume_range (myData.pControledElement, &myData.iVolumeMin, &myData.iVolumeMax);
 
158
                cd_debug ("volume range : %d - %d", myData.iVolumeMin, myData.iVolumeMax);
 
159
                
 
160
                snd_mixer_elem_set_callback (myData.pControledElement, mixer_element_update_with_event);
 
161
        }
 
162
        if (myConfig.cMixerElementName2 != NULL)
 
163
        {
 
164
                myData.pControledElement2 = _mixer_get_element_by_name (myConfig.cMixerElementName2);
 
165
        }
 
166
}
 
167
 
 
168
int mixer_get_mean_volume (void)
 
169
{
 
170
        g_return_val_if_fail (myData.pControledElement != NULL, 0);
 
171
        long iVolumeLeft=0, iVolumeRight=0;
 
172
        gboolean bHasLeft = snd_mixer_selem_has_playback_channel (myData.pControledElement, SND_MIXER_SCHN_FRONT_LEFT);
 
173
        gboolean bHasRight = snd_mixer_selem_has_playback_channel (myData.pControledElement, SND_MIXER_SCHN_FRONT_RIGHT);
 
174
                
 
175
        if (bHasLeft)
 
176
                snd_mixer_selem_get_playback_volume (myData.pControledElement, SND_MIXER_SCHN_FRONT_LEFT, &iVolumeLeft);
 
177
        if (bHasRight)
 
178
                snd_mixer_selem_get_playback_volume (myData.pControledElement, SND_MIXER_SCHN_FRONT_RIGHT, &iVolumeRight);
 
179
        cd_debug ("volume : %d;%d", iVolumeLeft, iVolumeRight);
 
180
        
 
181
        g_return_val_if_fail (bHasLeft || bHasRight, 0);
 
182
        
 
183
        int iMeanVolume = (iVolumeLeft + iVolumeRight) / (bHasLeft + bHasRight);
 
184
        
 
185
        g_print ("myData.iVolumeMin : %d ; myData.iVolumeMax : %d ; iMeanVolume : %d\n", myData.iVolumeMin, myData.iVolumeMax, iMeanVolume);
 
186
        return (100. * (iMeanVolume - myData.iVolumeMin) / (myData.iVolumeMax - myData.iVolumeMin));
 
187
}
 
188
 
 
189
void mixer_set_volume (int iNewVolume)
 
190
{
 
191
        g_return_if_fail (myData.pControledElement != NULL);
 
192
        int iVolume = ceil (myData.iVolumeMin + (myData.iVolumeMax - myData.iVolumeMin) * iNewVolume / 100.);
 
193
        snd_mixer_selem_set_playback_volume_all (myData.pControledElement, iVolume);
 
194
        if (myData.pControledElement2 != NULL)
 
195
                snd_mixer_selem_set_playback_volume_all (myData.pControledElement2, iVolume);
 
196
        myData.iCurrentVolume = iNewVolume;
 
197
        mixer_element_update_with_event (myData.pControledElement, 0);  // on ne recoit pas d'evenements pour nos actions.
 
198
}
 
199
 
 
200
gboolean mixer_is_mute (void)
 
201
{
 
202
        cd_debug ("");
 
203
        g_return_val_if_fail (myData.pControledElement != NULL, FALSE);
 
204
        if (snd_mixer_selem_has_playback_switch (myData.pControledElement))
 
205
        {
 
206
                int iSwitchLeft, iSwitchRight;
 
207
                snd_mixer_selem_get_playback_switch (myData.pControledElement, SND_MIXER_SCHN_FRONT_LEFT, &iSwitchLeft);
 
208
                snd_mixer_selem_get_playback_switch (myData.pControledElement, SND_MIXER_SCHN_FRONT_RIGHT, &iSwitchRight);
 
209
                cd_debug ("%d;%d", iSwitchLeft, iSwitchRight);
 
210
                return (iSwitchLeft == 0 && iSwitchRight == 0);
 
211
        }
 
212
        else
 
213
                return FALSE;
 
214
}
 
215
 
 
216
void mixer_switch_mute (void)
 
217
{
 
218
        g_return_if_fail (myData.pControledElement != NULL);
 
219
        gboolean bIsMute = mixer_is_mute ();
 
220
        snd_mixer_selem_set_playback_switch_all (myData.pControledElement, bIsMute);
 
221
        if (myData.pControledElement2 != NULL)
 
222
                snd_mixer_selem_set_playback_switch_all (myData.pControledElement2, bIsMute);
 
223
        myData.bIsMute = ! bIsMute;
 
224
        mixer_element_update_with_event (myData.pControledElement, 0);  // on ne recoit pas d'evenements pour nos actions.
 
225
}
 
226
 
 
227
 
 
228
 
 
229
static void on_change_volume (GtkRange *range, gpointer data)
 
230
{
 
231
        int iNewVolume = (int) gtk_range_get_value (GTK_RANGE (range));
 
232
        cd_debug ("%s (%d)", __func__, iNewVolume);
 
233
        mixer_set_volume (iNewVolume);
 
234
}
 
235
GtkWidget *mixer_build_widget (gboolean bHorizontal)
 
236
{
 
237
        g_return_val_if_fail (myData.pControledElement != NULL, NULL);
 
238
        GtkWidget *pScale = (bHorizontal ? gtk_hscale_new_with_range (0., 100., .5*myConfig.iScrollVariation) : gtk_vscale_new_with_range (0., 100., .5*myConfig.iScrollVariation));
 
239
        if (! bHorizontal)
 
240
                gtk_range_set_inverted (GTK_RANGE (pScale), TRUE);  // de bas en haut.
 
241
        
 
242
        myData.iCurrentVolume = mixer_get_mean_volume ();
 
243
        gtk_range_set_value (GTK_RANGE (pScale), myData.iCurrentVolume);
 
244
        
 
245
        g_signal_connect (G_OBJECT (pScale),
 
246
                "value-changed",
 
247
                G_CALLBACK (on_change_volume),
 
248
                NULL);
 
249
        
 
250
        return pScale;
 
251
}
 
252
 
 
253
 
 
254
void mixer_set_volume_with_no_callback (GtkWidget *pScale, int iVolume)
 
255
{
 
256
        g_signal_handlers_block_matched (GTK_WIDGET(pScale),
 
257
                G_SIGNAL_MATCH_FUNC,
 
258
                0, 0, NULL, (void*)on_change_volume, NULL);
 
259
        gtk_range_set_value (GTK_RANGE (pScale), (double) iVolume);
 
260
        g_signal_handlers_unblock_matched (GTK_WIDGET(pScale),
 
261
                G_SIGNAL_MATCH_FUNC,
 
262
                0, 0, NULL, (void*)on_change_volume, NULL);
 
263
}
 
264
 
 
265
 
 
266
static gboolean on_button_press_dialog (GtkWidget *widget,
 
267
        GdkEventButton *pButton,
 
268
        CairoDialog *pDialog)
 
269
{
 
270
        cairo_dock_dialog_unreference (pDialog);
 
271
        myData.pDialog = NULL;
 
272
        return FALSE;
 
273
}
 
274
 
 
275
void mixer_show_hide_dialog (void)
 
276
{
 
277
        if (myDesklet)
 
278
                return ;
 
279
        if (myData.pDialog == NULL)
 
280
        {
 
281
                const gchar *cMessage;
 
282
                GtkWidget *pScale = NULL;
 
283
                if (myData.cErrorMessage != NULL)
 
284
                        cMessage = myData.cErrorMessage;
 
285
                else
 
286
                {
 
287
                        cMessage = D_("Set up volume :");
 
288
                        pScale = mixer_build_widget (TRUE);
 
289
                }
 
290
                
 
291
                CairoDialogAttribute attr;
 
292
                memset (&attr, 0, sizeof (CairoDialogAttribute));
 
293
                attr.cText = cMessage;
 
294
                attr.pInteractiveWidget = pScale;
 
295
                myData.pDialog = cairo_dock_build_dialog (&attr, myIcon, myContainer);
 
296
                g_signal_connect (G_OBJECT (myData.pDialog->pWidget),
 
297
                        "button-press-event",
 
298
                        G_CALLBACK (on_button_press_dialog),
 
299
                        myData.pDialog);
 
300
        }
 
301
        else
 
302
        {
 
303
                cairo_dock_dialog_unreference (myData.pDialog);
 
304
                myData.pDialog = NULL;
 
305
        }
 
306
}
 
307
 
 
308
gboolean mixer_check_events (gpointer data)
 
309
{
 
310
        snd_mixer_handle_events (myData.mixer_handle);  // ne renvoie pas d'evenements pour nos actions !
 
311
        return TRUE;
 
312
}