summaryrefslogtreecommitdiff
path: root/tutorials/sndkit/userdev_demo/udserver.c
blob: eafe8c964f19cd518a77174d7c3f56573c0854da (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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
 * Sample server program that uses the oss_userdev driver.
 *
 * Copyright (C) 4Front Technologies. Released under the BSD license.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>

/*
 * OSS specific includes. Use correct -I setting when compiling. Typically
 * -I/usr/lib/oss/include/sys or -I/usr/include/sys
 */
#include <soundcard.h>
#include <oss_userdev_exports.h>

#define SERVER_DEVNAME		"/dev/oss/oss_userdev0/server"

int server_fd = -1;	/* File descriptor for the server side device. */

static void
terminator(int sig)
{
	wait();
	exit(0);
}

static void
create_mixer_interface(int fd)
{
	userdev_mixctl_t ctl;
	userdev_mixgroup_t grp;
	userdev_mixvalues_t rec;
	int group;

/*
 * Create a slider on the top level
 */

	memset(&ctl, 0, sizeof(ctl));
	strcpy(ctl.name, "volumitaz");
	ctl.parent	=	0; /* Device root group */
	ctl.type	= 	MIXT_STEREOSLIDER16;
	ctl.flags	= 	MIXF_READABLE|MIXF_WRITEABLE;
	ctl.index	= 	0;	/* Use position 0 of the value array */
	ctl.maxvalue	= 	100;
	ctl.offset	= 	0;
	ctl.rgbcolor	=	OSS_RGB_RED;

	if (ioctl(fd, USERDEV_CREATE_MIXCTL, &ctl)==-1)
	{
		perror("USERDEV_CREATE_MIXCTL");
		return;
	}
	
/*
 * Create a mixer group under the device root
 */

	memset(&grp, 0, sizeof(grp));

	strcat(grp.name, "private");
	grp.parent	=	0;
	
	if (ioctl(fd, USERDEV_CREATE_MIXGROUP, &grp)==-1)
	{
		perror("USERDEV_CREATE_MIXGROUP");
		return;
	}

	group = grp.num;

/*
 * Create an enumerated control under the "private" group that was created above
 */
	memset(&ctl, 0, sizeof(ctl));
	strcpy(ctl.name, "mode");
	ctl.parent	=	group; /* See above */
	ctl.type	= 	MIXT_ENUM;
	ctl.flags	= 	MIXF_READABLE|MIXF_WRITEABLE;
	ctl.index	= 	1;	/* Use position 1 of the value array */
	ctl.maxvalue	= 	4;

	memset (&ctl.enum_present, 0xff, sizeof(ctl.enum_present)); /* Mark all choices active */

	strcpy(ctl.enum_choises, "stall crawl cruise warp");

	if (ioctl(fd, USERDEV_CREATE_MIXCTL, &ctl)==-1)
	{
		perror("USERDEV_CREATE_MIXCTL");
		return;
	}

/*
 * Finally set the initial values for all the controls
 */
	memset(&rec, 0, sizeof(rec)); /* Set all to zeroes */

	rec.values[0] = 100 | (100<<16);	// volumitaz = 100:100
	rec.values[1] = 2;			// private.mode = "cruise"

/*
 * Post the initial settings
 */
	if (ioctl(fd, USERDEV_SET_MIXERS, &rec)==-1)
	{
		perror("USERDEV_SET_MIXERS");
	}
}

static void
poll_mixer(int fd)
{
	static int prev_count=0;
	int count;

	if (ioctl(fd, USERDEV_GET_MIX_CHANGECOUNT, &count)==-1)
	{
		perror("USERDEV_GET_MIX_CHANGECOUNT");
		return;
	}

	if (count > prev_count) /* Something has changed */
	{
		userdev_mixvalues_t rec;
		int i;

		if (ioctl(fd, USERDEV_GET_MIXERS, &rec)==-1)
		{
			perror("USERDEV_GET_MIXERS");
			return;
		}

		printf("Mixer change %d\n", count);

		/*
		 * Print only the controls that were allocated in
		 * create_mixer_interface()
		 */
		for (i=0;i<2;i++)
		    printf("%2d: %08x\n", i, rec.values[i]);
		fflush(stdout);
	}

	prev_count = count;
}

int
main(int argc, char *argv[])
{
	userdev_create_t crea = {0};
	char cmd[512];

/*
 * Sample rate/format we would like to use on server side. The client side
 * can use whatever they want since OSS will automatically do the required 
 * conversions.
 */
	int rate = 48000;
	int fmt = AFMT_S16_LE;
	int channels = 2;



	int tmp;
	int fragsize=0;

	if (argc != 2)
	{
		fprintf(stderr, "Usage: %s <command>\n", argv[0]);
		exit(-1);
	}

/*
 * Open the server side device. A new userdev instance (client&server)
 * will automatically get created when the device is opened. However
 * creation of the client side will be delayed until USERDEV_CREATE_INSTANCE
 * gets called.
 */

	if ((server_fd = open(SERVER_DEVNAME, O_RDWR, 0))==-1)
	{
		perror(SERVER_DEVNAME);
		exit(-1);
	}

/*
 * Create the client side device.
 */
	sprintf(crea.name, "udserver device for %s", getenv("USER"));
	crea.flags = USERDEV_F_VMIX_ATTACH | USERDEV_F_VMIX_PRIVATENODE; /* Doesn't work at this moment */
	crea.match_method = UD_MATCH_UID;
	crea.match_key = geteuid();
	crea.poll_interval = 10; /* In milliseconds */

	if (ioctl(server_fd, USERDEV_CREATE_INSTANCE, &crea)==-1)
	{
		perror("USERDEV_CREATE_INSTANCE");
		exit(-1);
	}

/*
 * Set up the master side parameters such as sampling rate and sample format.
 * The server application can select whatever format is best for its
 * purposes. The client side can select different rate/format if necessary.
 */

	tmp=0;
	ioctl(server_fd, SNDCTL_DSP_COOKEDMODE, &tmp); /* Turn off conversions */

	if (ioctl(server_fd, SNDCTL_DSP_SETFMT, &fmt)==-1)
	   perror("SNDCTL_DSP_SETFMT");

	if (ioctl(server_fd, SNDCTL_DSP_CHANNELS, &channels)==-1)
	   perror("SNDCTL_DSP_CHANNELS");

	if (ioctl(server_fd, SNDCTL_DSP_SPEED, &rate)==-1)
	   perror("SNDCTL_DSP_SPEED");

	if (ioctl(server_fd, SNDCTL_DSP_GETBLKSIZE, &fragsize)==-1)
	   fragsize = 1024;

	create_mixer_interface(server_fd);

	if (fork())
	{
		/*
		 * Server side code. In this case we have just a simple echo loop
		 * that writes back everything everything received from the client side.
		 */
		int l;
		int poll_count=0;

		char *buffer;
		signal(SIGCHLD, terminator);

		buffer = malloc (fragsize);
		memset(buffer, 0, fragsize);

		write(server_fd, buffer, fragsize);
		write(server_fd, buffer, fragsize);

		while ((l=read(server_fd, buffer, fragsize))>0)
		{
			if (write(server_fd, buffer, l)!=l)
			{
				perror("write");
				exit(-1);
			}

			if (poll_count++ > 10)
			{
				poll_mixer(server_fd);
				poll_count = 0;
			}
		}

		exit(0);
	}

/*
 * Client side code. Simply execute the command that was given in
 * argv[1]. However replace all %s's by the client side device node name.
 */

	if (setenv("OSS_AUDIODEV", crea.devnode, 1) == -1)
	   perror("setenv OSS_AUDIODEV");

	if (setenv("OSS_MIXERDEV", crea.devnode, 1) == -1)
	   perror("setenv OSS_MIXERDEV");

	setenv("PS1", "udserver> ", 1);

	sprintf(cmd, argv[1], crea.devnode, crea.devnode, crea.devnode);
	printf("Running '%s'\n", cmd);

	system(cmd);
	exit(0);
}