~ubuntu-branches/ubuntu/oneiric/oss4/oneiric-proposed

« back to all changes in this revision

Viewing changes to tutorials/sndkit/samples/mixer_applet.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Rivera
  • Date: 2011-06-16 20:37:48 UTC
  • mfrom: (5.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110616203748-jbrxik6ql33z54co
Tags: 4.2-build2004-1ubuntu1
* Merge from Debian unstable.
  - Supports our current kernel (LP: #746048)
  Remaining changes:
  - debian/oss4-dkms.dkms.in: s/source/build/ in Kernel headers paths.
* ld-as-needed.patch: Re-order CC arguments to enable building with ld
  --as-needed (LP: #770972)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: A sample program for developing a simple mixer applet.
 
3
 * Copyright (C) 4Front Technologies, 2007. Released under GPLv2/CDDL.
 
4
 *
 
5
 * This program is not usefull by itself. It just demonstrates techniques that
 
6
 * can be used when developing very simple mixer applets that control just
 
7
 * the key volumes in the system.
 
8
 *
 
9
 * The full OSS 4.0 mixer API is rather complex and designed for allmighty
 
10
 * master mixer applications. However there is a subset of the API that can be
 
11
 * used rather easily. This subset is limited to control of the main output volume,
 
12
 * audio/wave/pcm playback volume and/or recording input level. It cannot be
 
13
 * used for anything else.
 
14
 *
 
15
 * This program demonstrates three main techniques to be used by mixer applets:
 
16
 *
 
17
 * 1) How to find the default mixer device that controls the primary
 
18
 *    sound card/device in the system. This device is connected to the
 
19
 *    primary (desktop) speakers and the default system sounds/beep are
 
20
 *    directed to it. Normally this device is the audio chip installed on
 
21
 *    the motherboard of the computer.
 
22
 *
 
23
 * 2) How to find out the main, pcm and recording volume controls for
 
24
 *    the given device.
 
25
 *
 
26
 * 3) How to read the current volume and how to change it.
 
27
 *
 
28
 */
 
29
 
 
30
#include <stdio.h>
 
31
#include <unistd.h>
 
32
#include <stdlib.h>
 
33
#include <fcntl.h>
 
34
#include <soundcard.h>
 
35
#include <time.h>
 
36
#include <errno.h>
 
37
 
 
38
oss_sysinfo sysinfo;
 
39
 
 
40
#define MAX_CTL 50
 
41
 
 
42
static int mixer_dev = -1;      /* Use the default mixer */
 
43
 
 
44
int
 
45
find_default_mixer (int mixer_fd)
 
46
{
 
47
  int default_mix = -1;
 
48
  int best_pri = -2;
 
49
 
 
50
  oss_mixerinfo mi;
 
51
 
 
52
  int i;
 
53
 
 
54
/*
 
55
 * The default mixer device in the system can be found by checking the
 
56
 * priority parameter of all mixer devices in the system. The device with the
 
57
 * highest priority value is the winner. If there are multiple devices with the
 
58
 * same priority then the first one should be selected.
 
59
 *
 
60
 * Note that there should be some method for selecting the mixer device number.
 
61
 * In many cases the user actually wants to use some other mixer than the
 
62
 * motherboard one.
 
63
 */
 
64
 
 
65
  for (i = 0; i < sysinfo.nummixers; i++)
 
66
    {
 
67
      mi.dev = i;
 
68
 
 
69
      if (ioctl (mixer_fd, SNDCTL_MIXERINFO, &mi) == -1)
 
70
        {
 
71
          perror ("SNDCTL_MIXERINFO");
 
72
          continue;
 
73
        }
 
74
 
 
75
      if (mi.priority < -1)     /* Not suitable default mixer */
 
76
        continue;
 
77
 
 
78
      if (mi.priority > best_pri)
 
79
        {
 
80
          default_mix = i;
 
81
          best_pri = mi.priority;
 
82
        }
 
83
    }
 
84
 
 
85
  printf("Mixer device %d seems to be the most probable motherboard device\n",
 
86
         default_mix);
 
87
 
 
88
  return default_mix;
 
89
}
 
90
 
 
91
void
 
92
show_controls (int mixer_fd, char *heading, int mixer_dev, int ctls[], int count)
 
93
{
 
94
  oss_mixext ext;
 
95
  oss_mixer_value val;
 
96
  int ctl, i;
 
97
 
 
98
  printf("\n***** %s *****\n", heading);
 
99
 
 
100
  for (i=0;i<count;i++)
 
101
  {
 
102
          ctl = ctls[i];
 
103
/*
 
104
 * Obtain the mixer extension definition. It might be a good idea to cache
 
105
 * this info in global variables so that doesn't need to be reloaded
 
106
 * every time. 
 
107
 *
 
108
 * Reloading this info every time may cause serious troubles because in that
 
109
 * way the application cannot be noticed after the mixer interface has changed.
 
110
 */
 
111
 
 
112
  ext.dev = mixer_dev;
 
113
  ext.ctrl = ctl;
 
114
 
 
115
  if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, &ext) == -1)
 
116
    {
 
117
      perror ("SNDCTL_MIX_EXTINFO");
 
118
      exit (-1);
 
119
    }
 
120
 
 
121
/*
 
122
 * Have to initialize the dev, ctl and timestamp fields before reading the
 
123
 * actual value.
 
124
 */
 
125
 
 
126
  val.dev = mixer_dev;
 
127
  val.ctrl = ctl;
 
128
  val.timestamp = ext.timestamp;
 
129
 
 
130
  if (ioctl (mixer_fd, SNDCTL_MIX_READ, &val) == -1)
 
131
    {
 
132
      if (errno == EIDRM)
 
133
        {
 
134
/*
 
135
 * Getting errno=EIDRM tells that the mixer struicture has been changed. This
 
136
 * may happen for example if new firmware gets loaded to the device. In such 
 
137
 * case the application should start from the beginning and to load all
 
138
 * the information again.
 
139
 *
 
140
 */
 
141
          fprintf (stderr, "Mixer structure changed. Please try again\n");
 
142
          exit (-1);
 
143
        }
 
144
 
 
145
      perror ("SNDCTL_MIX_READ");
 
146
      exit (-1);
 
147
    }
 
148
 
 
149
  printf ("\t%3d: %s\t ", ctl, ext.extname);
 
150
 
 
151
  switch (ext.type)
 
152
    {
 
153
    case MIXT_MONOSLIDER:
 
154
      printf ("monoslider %d ", val.value & 0xff);
 
155
      break;
 
156
 
 
157
    case MIXT_STEREOSLIDER:
 
158
      printf ("stereoslider %d:%d ", val.value & 0xff,
 
159
              (val.value >> 8) & 0xff);
 
160
      break;
 
161
 
 
162
    case MIXT_SLIDER:
 
163
      printf ("slider %d ", val.value);
 
164
      break;
 
165
 
 
166
    case MIXT_MONOSLIDER16:
 
167
      printf ("monoslider %d ", val.value & 0xffff);
 
168
      break;
 
169
 
 
170
    case MIXT_STEREOSLIDER16:
 
171
      printf ("stereoslider %d:%d ", val.value & 0xffff,
 
172
              (val.value >> 16) & 0xffff);
 
173
      break;
 
174
 
 
175
/*
 
176
 * Sometimes there may be just a MUTE control instead of a slider. However
 
177
 * it's also possible that there is both mute and a slider.
 
178
 */
 
179
    case MIXT_ONOFF:
 
180
      printf ("ONOFF %d ", val.value);
 
181
      break;
 
182
 
 
183
    case MIXT_MUTE:
 
184
      printf ("mute %d ", val.value);
 
185
      break;
 
186
 
 
187
/*
 
188
 * Enumerated controls may be used for example for recording source
 
189
 * selection.
 
190
 */
 
191
    case MIXT_ENUM:
 
192
      printf ("Selection %d ", val.value);
 
193
      break;
 
194
 
 
195
 
 
196
    default:
 
197
      printf ("Unknown control type (%d), value=0x%08x ", ext.type,
 
198
              val.value);
 
199
    }
 
200
 
 
201
  printf ("\n");
 
202
  }
 
203
 
 
204
}
 
205
 
 
206
int
 
207
main (int argc, char *argv[])
 
208
{
 
209
  int mixer_fd = -1;
 
210
  int i, n;
 
211
 
 
212
  /*
 
213
   * Bins for the mixer controls.
 
214
   */
 
215
#define ADD_TO_BIN(bin, ctl) \
 
216
  if (n_##bin >= MAX_CTL) \
 
217
  { \
 
218
          fprintf(stderr, #bin " table is full\n"); exit(-1); \
 
219
  } \
 
220
  bin##_ctls[n_##bin++] = ctl
 
221
 
 
222
  int mainvol_ctls[MAX_CTL];
 
223
  int pcmvol_ctls[MAX_CTL];
 
224
  int recvol_ctls[MAX_CTL];
 
225
  int monvol_ctls[MAX_CTL];
 
226
  int n_mainvol=0, n_pcmvol=0, n_recvol=0, n_monvol=0;
 
227
  char *devmixer;
 
228
 
 
229
  if ((devmixer=getenv("OSS_MIXERDEV"))==NULL)
 
230
     devmixer = "/dev/mixer";
 
231
 
 
232
/*
 
233
 * Get the mixer device number from command line.
 
234
 */
 
235
  if (argc > 1)
 
236
    mixer_dev = atoi (argv[1]);
 
237
 
 
238
/*
 
239
 * Open /dev/mixer. This device file can be used regardless of the actual
 
240
 * mixer device number.
 
241
 */
 
242
 
 
243
  if ((mixer_fd = open (devmixer, O_RDWR, 0)) == -1)
 
244
    {
 
245
      perror (devmixer);
 
246
      exit (-1);
 
247
    }
 
248
 
 
249
/*
 
250
 * Get OSS system info to a global buffer.
 
251
 */
 
252
 
 
253
  if (ioctl (mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1)
 
254
    {
 
255
      perror ("SNDCTL_SYSINFO");
 
256
      exit (-1);
 
257
    }
 
258
 
 
259
/*
 
260
 * Check the mixer device number.
 
261
 */
 
262
 
 
263
  if (mixer_dev == -1)
 
264
    mixer_dev = find_default_mixer (mixer_fd);
 
265
 
 
266
  if (mixer_dev < 0 || mixer_dev >= sysinfo.nummixers)
 
267
    {
 
268
      fprintf (stderr, "Nonexistent mixer device %d\n", mixer_dev);
 
269
      exit (-1);
 
270
    }
 
271
 
 
272
  printf ("Using OSS mixer device %d\n", mixer_dev);
 
273
 
 
274
/*
 
275
 * The second step is to find the main volume, audio/pcm playback volume and
 
276
 * recording level controls.
 
277
 *
 
278
 * It's important to understand that many mixer devices don't have such
 
279
 * controls. This is perfectly normal and the mixer applet must be able to
 
280
 * handle this. Aborting or displaying loud error message should be avoided.
 
281
 *
 
282
 * It's also possible that some mixers have multiple main volume, pcm or
 
283
 * record level controls. In such case the application can support all of
 
284
 * of them or select just the first one. Having multiple controls means that
 
285
 * the device hase multiple sets of speakers or audio devices and each of
 
286
 * them has separate volume controls.
 
287
 */
 
288
 
 
289
  n = mixer_dev;
 
290
  if (ioctl (mixer_fd, SNDCTL_MIX_NREXT, &n) == -1)
 
291
    {
 
292
      perror ("SNDCTL_MIX_NREXT");
 
293
      exit (-1);
 
294
    }
 
295
 
 
296
  for (i = 0; i < n; i++)
 
297
    {
 
298
      oss_mixext ext;
 
299
 
 
300
      ext.dev = mixer_dev;
 
301
      ext.ctrl = i;
 
302
 
 
303
      if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, &ext) == -1)
 
304
        {
 
305
          perror ("SNDCTL_MIX_EXTINFO");
 
306
          exit (-1);
 
307
        }
 
308
 
 
309
/*
 
310
 * The MIXF_MAINVOL, MIXF_PCMVOL, MIXF_MONVOL and MIXF_RECVOL flags are used to mark
 
311
 * potential main volume, pcm and recording level controls. This makes it
 
312
 * possible to implement support for these common types of controls without
 
313
 * having to implement fully featured mixer program.
 
314
 *
 
315
 * Mixer applets using this simplified interface should ignore all mixer
 
316
 * controls that don't have any of these three flags. However
 
317
 *
 
318
 * Note that while mixer controls should have at most one of thse flags defined
 
319
 * it may happen that some devices violate this rule. It's up to 
 
320
 * application what it does with such controls. Preferably it gets added
 
321
 * to all of the bins.
 
322
 */
 
323
 
 
324
      if (ext.
 
325
          flags & (MIXF_MAINVOL | MIXF_PCMVOL | MIXF_RECVOL | MIXF_MONVOL))
 
326
        {
 
327
          printf ("Mixer control %d is ", i);
 
328
 
 
329
          if (ext.flags & MIXF_MAINVOL)
 
330
            {
 
331
              printf ("Mainvol ");
 
332
 
 
333
              ADD_TO_BIN(mainvol, i);
 
334
            }
 
335
 
 
336
          if (ext.flags & MIXF_PCMVOL)
 
337
            {
 
338
              printf ("PCMvol ");
 
339
 
 
340
              ADD_TO_BIN(pcmvol, i);
 
341
            }
 
342
 
 
343
          if (ext.flags & MIXF_RECVOL)
 
344
            {
 
345
              printf ("Recvol ");
 
346
 
 
347
              ADD_TO_BIN(recvol, i);
 
348
            }
 
349
 
 
350
          if (ext.flags & MIXF_MONVOL)
 
351
            {
 
352
              printf ("Monvol ");
 
353
 
 
354
              ADD_TO_BIN(monvol, i);
 
355
            }
 
356
/*
 
357
 * It is possible that many/most/all mixer controls don't have any of the above
 
358
 * flags set. This means that such controls are for expert use only. It is
 
359
 * recommended that mixer applets have an [Advanced options] button that is
 
360
 * enabled if such controls are found. This button can launch ossxmix (or
 
361
 * some configurable program).
 
362
 */
 
363
 
 
364
          printf ("%s\n", ext.extname);
 
365
        }
 
366
    }
 
367
 
 
368
/*
 
369
 * Now we have selected the mixer controls. Next show their values.
 
370
 * Since setting the value is pretty much identical to reading them we don't
 
371
 * demonstrate it in this program.
 
372
 */
 
373
  printf ("\n");
 
374
 
 
375
  if (n_mainvol > 0)
 
376
    show_controls (mixer_fd, "Main volume controls", mixer_dev, mainvol_ctls, n_mainvol);
 
377
  else
 
378
    printf ("No main volume control available\n");
 
379
 
 
380
  if (n_pcmvol > 0)
 
381
    show_controls (mixer_fd, "Pcm volume controls", mixer_dev, pcmvol_ctls, n_pcmvol);
 
382
  else
 
383
    printf ("No pcm volume control available\n");
 
384
 
 
385
  if (n_recvol > 0)
 
386
    show_controls (mixer_fd, "Rec volume controls", mixer_dev, recvol_ctls, n_recvol);
 
387
  else
 
388
    printf ("No rec volume control available\n");
 
389
 
 
390
  if (n_monvol > 0)
 
391
    show_controls (mixer_fd, "Monitor volume controls", mixer_dev, monvol_ctls, n_monvol);
 
392
  else
 
393
    printf ("No monitor volume control available\n");
 
394
 
 
395
  close (mixer_fd);
 
396
 
 
397
  if (n_mainvol + n_pcmvol + n_recvol + n_monvol == 0)
 
398
     {
 
399
             printf("\nNo 'simple' mixer controls available for this device\n");
 
400
             printf("It may be a good idea to start 'ossxmix -d %d' which can access advanced options.\n", mixer_dev);
 
401
     }
 
402
 
 
403
  exit (0);
 
404
}