summaryrefslogtreecommitdiff
path: root/tutorials/sndkit/samples/mixext.c
blob: a70e638765ef02509a576ae2b45109d38f9eccf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
 * Purpose: A simple sample program for using the new mixer API
 * Copyright (C) 4Front Technologies, 2002-2004. Released under GPLv2/CDDL.
 *
 * Description:
 * This program is as simple as possible example for using the new mixer API
 * of OSS 4.0 (and later) from applications. It shows how to read or
 * change the settings. Please read the OSS API Developer's Manual for
 * more info about this API.
 *
 * This mixer interface is designed to ne "human readable". The idea is that
 * the mixer program just shows whatever controls are available and lets the
 * user to adjust them as he/she likes.
 *
 * Please note that the control names and numbers are fully dynamic. There are
 * some control names such as "spdif.enable" that are used by several different
 * drivers. It's relatively safe to assume that such controls have always
 * the same meaning. However there is no list of such control names
 * available at this moment. Even this kind of controls are supported just by 
 * some of the devices (some devices just don't have that feature).
 *
 * Most control names are 100% non-portable between devices. In addition some
 * settings may be available depending on the configuration.
 *
 * {!notice Applications using this mixer interface must not assume that
 * certain controls are always available or that they have exactly defined
 * meanings.}
 *
 * This program can be run without any command line arguments to 
 * list the available controls and their values. The mixer device number
 * (0 by default) can be given on the command line.
 *
 * Another way is to give the mixer number, control ame and value
 * on the command line ({!shell mixext 1 spdif.enable 1}).
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <soundcard.h>
#include <time.h>
#include <errno.h>

static int mixer_dev = 0;	/* Change this to access another mixer device */
static int mixerfd = -1;

typedef struct
{
  int num;
  char *name;
} name_ent;

#define TYPE_ENTRY(x) {x, #x}

name_ent type_names[] = {
  TYPE_ENTRY (MIXT_DEVROOT),
  TYPE_ENTRY (MIXT_GROUP),
  TYPE_ENTRY (MIXT_ONOFF),
  TYPE_ENTRY (MIXT_MUTE),
  TYPE_ENTRY (MIXT_ENUM),
  TYPE_ENTRY (MIXT_MONOSLIDER),
  TYPE_ENTRY (MIXT_STEREOSLIDER),
  TYPE_ENTRY (MIXT_MESSAGE),
  TYPE_ENTRY (MIXT_MONOVU),
  TYPE_ENTRY (MIXT_STEREOVU),
  TYPE_ENTRY (MIXT_MONOPEAK),
  TYPE_ENTRY (MIXT_STEREOPEAK),
  TYPE_ENTRY (MIXT_RADIOGROUP),
  TYPE_ENTRY (MIXT_MARKER),
  TYPE_ENTRY (MIXT_VALUE),
  TYPE_ENTRY (MIXT_HEXVALUE),
  TYPE_ENTRY (MIXT_MONODB),
  TYPE_ENTRY (MIXT_STEREODB),
  TYPE_ENTRY (MIXT_SLIDER),
  TYPE_ENTRY (MIXT_3D),
  TYPE_ENTRY (MIXT_MONOSLIDER16),
  TYPE_ENTRY (MIXT_STEREOSLIDER16),
  {-1, NULL}
};

static char *
mixt_name (int num)
{
  int i;

  i = 0;

  while (type_names[i].num != -1)
    {
      if (type_names[i].num == num)
	return type_names[i].name;
      i++;
    }
  return "Unknown type";
}

void
list_controls (int mixer_dev)
{
  int i, n, nn = 0;
  oss_mixext ext;
  int marker_seen = 0;

  n = mixer_dev;

  if (ioctl (mixerfd, SNDCTL_MIX_NREXT, &n) == -1)
    {
      perror ("SNDCTL_MIX_NREXT");
      if (errno == EINVAL)
	fprintf (stderr, "Error: OSS version 3.9 or later is required\n");
      return;
    }

  printf ("%d mixer controls available (including ordinary mixer controls)\n",
	  n);

  for (i = 0; i < n; i++)
    {
      oss_mixer_value val;

      ext.dev = mixer_dev;
      ext.ctrl = i;

      if (ioctl (mixerfd, SNDCTL_MIX_EXTINFO, &ext) == -1)
	{
	  if (errno == EINVAL)
	    {
	      fprintf (stderr, "SNDCTL_MIX_EXTINFO failed\n");
	      fprintf (stderr,
		       "This is almost certainly caused by a too old or new OSS version.\n");
	      return;
	    }

	  perror ("SNDCTL_MIX_EXTINFO");
	  return;
	}

      if (ext.type == MIXT_MARKER)
	{
	  marker_seen = 1;
	  continue;
	}
      else if (!marker_seen)
	continue;

      val.dev = mixer_dev;
      val.ctrl = i;
      val.timestamp = ext.timestamp;

      val.value = 0;

      if (ext.type != MIXT_DEVROOT && ext.type != MIXT_GROUP
	  && ext.type != MIXT_MARKER)
	if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
	  {
	    perror ("SNDCTL_MIX_READ");
	    val.value = 0xffffffff;
	  }

      printf ("%3d: \"%s\" (\"%s\"), parent %d\n", i, ext.extname, ext.id,
	      ext.parent);
      printf ("     Type %d (%s), value %d (0x%08x) (max %d)\n", ext.type,
	      mixt_name (ext.type), val.value, val.value, ext.maxvalue);
      printf ("     Update counter %d\n", ext.update_counter);
      nn++;
    }

  printf ("%d controls accessible by this program\n", nn);
}

int
set_control (int mixer_dev, char *name, int value)
{
  int i, n;
  oss_mixext ext;
  int marker_seen = 0;

  n = mixer_dev;

  if (ioctl (mixerfd, SNDCTL_MIX_NREXT, &n) == -1)
    {
      perror ("SNDCTL_MIX_NREXT");
      if (errno == EINVAL)
	fprintf (stderr, "Error: OSS version 3.9 or later is required\n");
      return -4;
    }

  for (i = 0; i < n; i++)
    {
      oss_mixer_value val;

      ext.dev = mixer_dev;
      ext.ctrl = i;

      if (ioctl (mixerfd, SNDCTL_MIX_EXTINFO, &ext) == -1)
	{
	  perror ("SNDCTL_MIX_EXTINFO");
	  return -1;
	}

      if (ext.type == MIXT_MARKER)
	{
	  marker_seen = 1;
	  continue;
	}
      else if (!marker_seen)
	continue;


      if (strcmp (ext.extname, name) != 0)	/* No match */
	continue;

      if (!(ext.flags & MIXF_WRITEABLE))
	return -2;

      val.dev = mixer_dev;
      val.ctrl = i;
      val.timestamp = ext.timestamp;
      val.value = value;

      if (ioctl (mixerfd, SNDCTL_MIX_WRITE, &val) == -1)
	{
	  perror ("SNDCTL_MIX_WRITE");
	  return -3;
	}

      return 1;
    }

  return 0;
}

int
main (int argc, char *argv[])
{
  char *devmixer;

  if ((devmixer=getenv("OSS_MIXERDEV"))==NULL)
     devmixer = "/dev/mixer";

  if (argc > 1)
    mixer_dev = atoi (argv[1]);

  if ((mixerfd = open (devmixer, O_RDWR, 0)) == -1)
    {
      perror (devmixer);
      exit (-1);
    }

  if (argc > 3)
    {
      int val;

      val = atoi (argv[3]);

      if (set_control (mixer_dev, argv[2], val) > 0)
	{
	  fprintf (stderr, "OK\n");
	}
      else
	{
	  fprintf (stderr, "Failed!!!\n");
	}
      exit (0);
    }

  list_controls (mixer_dev);

  exit (0);
}