~oah-dev/oah/gst-plugins-bad

« back to all changes in this revision

Viewing changes to sys/oss4/oss4-mixer-slider.c

  • Committer: Haakon Sporsheim
  • Date: 2009-03-12 13:52:03 UTC
  • Revision ID: haakon.sporsheim@tandberg.com-20090312135203-i5k294hgkushb0mt
Initial import of git repository: git://anongit.freedesktop.org/gstreamer/gst-plugins-bad (tag: RELEASE-0_10_10)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer OSS4 mixer slider control
 
2
 * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, 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
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 */
 
19
 
 
20
/* A 'slider' in gnome-volume-control / GstMixer is represented by a
 
21
 * GstMixerTrack with one or more channels.
 
22
 *
 
23
 * A slider should be either flagged as INPUT or OUTPUT (mostly because of
 
24
 * gnome-volume-control being littered with g_asserts for everything it doesn't
 
25
 * expect).
 
26
 *
 
27
 * From mixertrack.h:
 
28
 * "Input tracks can have 'recording' enabled, which means that any input will
 
29
 * be hearable into the speakers that are attached to the output. Mute is
 
30
 * obvious."
 
31
 */
 
32
 
 
33
#ifdef HAVE_CONFIG_H
 
34
#include "config.h"
 
35
#endif
 
36
 
 
37
#include <stdio.h>
 
38
#include <stdlib.h>
 
39
#include <fcntl.h>
 
40
#include <unistd.h>
 
41
#include <string.h>
 
42
#include <errno.h>
 
43
#include <sys/ioctl.h>
 
44
 
 
45
#include <gst/gst-i18n-plugin.h>
 
46
 
 
47
#define NO_LEGACY_MIXER
 
48
#include "oss4-mixer-slider.h"
 
49
 
 
50
GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug);
 
51
#define GST_CAT_DEFAULT oss4mixer_debug
 
52
 
 
53
/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */
 
54
G_DEFINE_TYPE (GstOss4MixerSlider, gst_oss4_mixer_slider, GST_TYPE_MIXER_TRACK);
 
55
 
 
56
static void
 
57
gst_oss4_mixer_slider_class_init (GstOss4MixerSliderClass * klass)
 
58
{
 
59
  /* nothing to do here */
 
60
}
 
61
 
 
62
static void
 
63
gst_oss4_mixer_slider_init (GstOss4MixerSlider * s)
 
64
{
 
65
  /* nothing to do here */
 
66
}
 
67
 
 
68
static int
 
69
gst_oss4_mixer_slider_pack_volume (GstOss4MixerSlider * s, const gint * volumes)
 
70
{
 
71
  int val = 0;
 
72
 
 
73
  switch (s->mc->mixext.type) {
 
74
    case MIXT_MONOSLIDER:
 
75
    case MIXT_MONOSLIDER16:
 
76
    case MIXT_SLIDER:
 
77
      val = volumes[0];
 
78
      break;
 
79
    case MIXT_STEREOSLIDER:
 
80
      val = ((volumes[1] & 0xff) << 8) | (volumes[0] & 0xff);
 
81
      break;
 
82
    case MIXT_STEREOSLIDER16:
 
83
      val = ((volumes[1] & 0xffff) << 16) | (volumes[0] & 0xffff);
 
84
      break;
 
85
    default:
 
86
      g_return_val_if_reached (0);
 
87
  }
 
88
  return val;
 
89
}
 
90
 
 
91
static void
 
92
gst_oss4_mixer_slider_unpack_volume (GstOss4MixerSlider * s, int v,
 
93
    gint * volumes)
 
94
{
 
95
  guint32 val;                  /* use uint so bitshifting the highest bit works right */
 
96
 
 
97
  val = (guint32) v;
 
98
  switch (s->mc->mixext.type) {
 
99
    case MIXT_SLIDER:
 
100
      volumes[0] = val;
 
101
      break;
 
102
    case MIXT_MONOSLIDER:
 
103
      /* oss repeats the value in the upper bits, as if it was stereo */
 
104
      volumes[0] = val & 0x00ff;
 
105
      break;
 
106
    case MIXT_MONOSLIDER16:
 
107
      /* oss repeats the value in the upper bits, as if it was stereo */
 
108
      volumes[0] = val & 0x0000ffff;
 
109
      break;
 
110
    case MIXT_STEREOSLIDER:
 
111
      volumes[0] = (val & 0x00ff);
 
112
      volumes[1] = (val & 0xff00) >> 8;
 
113
      break;
 
114
    case MIXT_STEREOSLIDER16:
 
115
      volumes[0] = (val & 0x0000ffff);
 
116
      volumes[1] = (val & 0xffff0000) >> 16;
 
117
      break;
 
118
    default:
 
119
      g_return_if_reached ();
 
120
  }
 
121
}
 
122
 
 
123
gboolean
 
124
gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes)
 
125
{
 
126
  GstMixerTrack *track = GST_MIXER_TRACK (s);
 
127
  int v = 0;
 
128
 
 
129
  /* if we're supposed to be muted, and don't have an actual mute control
 
130
   * (ie. 'simulate' the mute), then just return the volume as saved, not
 
131
   * the actually set volume which is most likely 0 */
 
132
  if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) {
 
133
    volumes[0] = s->volumes[0];
 
134
    if (track->num_channels == 2)
 
135
      volumes[1] = s->volumes[1];
 
136
    return TRUE;
 
137
  }
 
138
 
 
139
  if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &v))
 
140
    return FALSE;
 
141
 
 
142
  gst_oss4_mixer_slider_unpack_volume (s, v, volumes);
 
143
 
 
144
  if (track->num_channels > 1) {
 
145
    GST_LOG_OBJECT (s, "volume: left=%d, right=%d", volumes[0], volumes[1]);
 
146
  } else {
 
147
    GST_LOG_OBJECT (s, "volume: mono=%d", volumes[0]);
 
148
  }
 
149
 
 
150
  return TRUE;
 
151
}
 
152
 
 
153
gboolean
 
154
gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes)
 
155
{
 
156
  GstMixerTrack *track = GST_MIXER_TRACK (s);
 
157
  int val = 0;
 
158
 
 
159
  /* if we're supposed to be muted, and are 'simulating' the mute because
 
160
   * we don't have a mute control, don't actually change the volume, just
 
161
   * save it as the new desired volume for later when we get unmuted again */
 
162
  if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute)
 
163
    goto done;
 
164
 
 
165
  val = gst_oss4_mixer_slider_pack_volume (s, volumes);
 
166
 
 
167
  if (track->num_channels > 1) {
 
168
    GST_LOG_OBJECT (s, "left=%d, right=%d", volumes[0], volumes[1]);
 
169
  } else {
 
170
    GST_LOG_OBJECT (s, "mono=%d", volumes[0]);
 
171
  }
 
172
 
 
173
  if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, val))
 
174
    return FALSE;
 
175
 
 
176
done:
 
177
 
 
178
  s->volumes[0] = volumes[0];
 
179
  if (track->num_channels == 2)
 
180
    s->volumes[1] = volumes[1];
 
181
 
 
182
  return TRUE;
 
183
}
 
184
 
 
185
gboolean
 
186
gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record)
 
187
{
 
188
  /* There doesn't seem to be a way to do this using the OSS4 mixer API, so
 
189
   * just do nothing here for now. */
 
190
  return FALSE;
 
191
}
 
192
 
 
193
gboolean
 
194
gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute)
 
195
{
 
196
  GstMixerTrack *track = GST_MIXER_TRACK (s);
 
197
  gboolean ret;
 
198
 
 
199
  /* if we don't have a mute control, simulate mute (which is a bit broken,
 
200
   * since we can't differentiate between capture/playback volume etc., so
 
201
   * we just assume that setting the volume to 0 would be the same as muting
 
202
   * this control) */
 
203
  if (s->mc->mute == NULL) {
 
204
    int volume;
 
205
 
 
206
    if (mute) {
 
207
      volume = 0;
 
208
    } else {
 
209
      volume = gst_oss4_mixer_slider_pack_volume (s, s->volumes);
 
210
    }
 
211
    ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc, volume);
 
212
  } else {
 
213
    ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, !!mute);
 
214
  }
 
215
 
 
216
  if (mute) {
 
217
    track->flags |= GST_MIXER_TRACK_MUTE;
 
218
  } else {
 
219
    track->flags &= ~GST_MIXER_TRACK_MUTE;
 
220
  }
 
221
 
 
222
  return FALSE;
 
223
}
 
224
 
 
225
GstMixerTrack *
 
226
gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc)
 
227
{
 
228
  GstOss4MixerSlider *s;
 
229
  GstMixerTrack *track;
 
230
  gint volumes[2] = { 0, };
 
231
 
 
232
  s = g_object_new (GST_TYPE_OSS4_MIXER_SLIDER, "untranslated-label",
 
233
      mc->mixext.extname, NULL);
 
234
 
 
235
  track = GST_MIXER_TRACK (s);
 
236
 
 
237
  /* caller will set track->label and track->flags */
 
238
 
 
239
  s->mc = mc;
 
240
  s->mixer = mixer;
 
241
 
 
242
  /* we don't do value scaling but just present a scale of 0-maxvalue */
 
243
  track->min_volume = 0;
 
244
  track->max_volume = mc->mixext.maxvalue;
 
245
 
 
246
  switch (mc->mixext.type) {
 
247
    case MIXT_MONOSLIDER:
 
248
    case MIXT_MONOSLIDER16:
 
249
    case MIXT_SLIDER:
 
250
      track->num_channels = 1;
 
251
      break;
 
252
    case MIXT_STEREOSLIDER:
 
253
    case MIXT_STEREOSLIDER16:
 
254
      track->num_channels = 2;
 
255
      break;
 
256
    default:
 
257
      g_return_val_if_reached (NULL);
 
258
  }
 
259
 
 
260
  GST_LOG_OBJECT (track, "min=%d, max=%d, channels=%d", track->min_volume,
 
261
      track->max_volume, track->num_channels);
 
262
 
 
263
  if (!gst_oss4_mixer_slider_get_volume (s, volumes)) {
 
264
    GST_WARNING_OBJECT (track, "failed to read volume, returning NULL");
 
265
    g_object_unref (track);
 
266
    track = NULL;
 
267
  }
 
268
 
 
269
  return track;
 
270
}
 
271
 
 
272
/* This is called from the watch thread */
 
273
void
 
274
gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track)
 
275
{
 
276
  GstOss4MixerSlider *s = GST_OSS4_MIXER_SLIDER_CAST (track);
 
277
 
 
278
  if (s->mc->mute != NULL && s->mc->mute->changed) {
 
279
    gst_mixer_mute_toggled (GST_MIXER (s->mixer), track,
 
280
        !!s->mc->mute->last_val);
 
281
  } else {
 
282
    /* nothing to do here, since we don't/can't easily implement the record
 
283
     * flag */
 
284
  }
 
285
 
 
286
  if (s->mc->changed) {
 
287
    gint volumes[2] = { 0, 0 };
 
288
 
 
289
    gst_oss4_mixer_slider_unpack_volume (s, s->mc->last_val, volumes);
 
290
 
 
291
    /* if we 'simulate' the mute, update flag when the volume changes */
 
292
    if (s->mc->mute == NULL) {
 
293
      if (volumes[0] == 0 && volumes[1] == 0) {
 
294
        track->flags |= GST_MIXER_TRACK_MUTE;
 
295
      } else {
 
296
        track->flags &= ~GST_MIXER_TRACK_MUTE;
 
297
      }
 
298
    }
 
299
 
 
300
    gst_mixer_volume_changed (GST_MIXER (s->mixer), track, volumes);
 
301
  }
 
302
}