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

« back to all changes in this revision

Viewing changes to cmd/ossmixd/ossmixd.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
 * OSS mixer service daemon (used by libossmix)
 
3
 */
 
4
 
 
5
#include <stdio.h>
 
6
#include <sys/types.h>
 
7
#include <sys/socket.h>
 
8
#include <netinet/in.h>
 
9
#include <stdlib.h>
 
10
#include <unistd.h>
 
11
#include <fcntl.h>
 
12
#include <string.h>
 
13
#include <errno.h>
 
14
#ifdef __SCO_VERSION__
 
15
#include <sys/time.h>
 
16
#else
 
17
#include <time.h>
 
18
#endif
 
19
#include <sched.h>
 
20
#include <soundcard.h>
 
21
 
 
22
#define OSSMIX_REMOTE
 
23
#include "libossmix.h"
 
24
 
 
25
static int connfd;
 
26
static int listenfd;
 
27
static int verbose = 0;
 
28
static int polling_started = 0;
 
29
static int num_mixers=0;
 
30
 
 
31
static unsigned char mixer_open_mask[MAX_TMP_MIXER/8] = {0};
 
32
 
 
33
static void
 
34
send_response (int cmd, int p1, int p2, int p3, int p4, int p5, int unsol)
 
35
{
 
36
  ossmix_commad_packet_t msg;
 
37
 
 
38
  memset (&msg, 0, sizeof (msg));
 
39
 
 
40
  if (verbose)
 
41
    printf ("Send %02d, p=0x%08x, %d, %d, %d, %d, unsol=%d\n",
 
42
            cmd, p1, p2, p3, p4, p5, unsol);
 
43
 
 
44
  msg.cmd = cmd;
 
45
  msg.unsolicited = unsol;
 
46
  msg.p1 = p1;
 
47
  msg.p2 = p2;
 
48
  msg.p3 = p3;
 
49
  msg.p4 = p4;
 
50
  msg.p5 = p5;
 
51
 
 
52
  if (write (connfd, &msg, sizeof (msg)) != sizeof (msg))
 
53
    {
 
54
      fprintf (stderr, "Write to socket failed\n");
 
55
    }
 
56
}
 
57
 
 
58
static void
 
59
send_response_long (int cmd, int p1, int p2, int p3, int p4, int p5,
 
60
                    const char *payload, int plsize, int unsol)
 
61
{
 
62
  ossmix_commad_packet_t msg;
 
63
 
 
64
  if (verbose)
 
65
    printf ("Send %02d, p=0x%08x, %d, %d, %d, %d, unsol=%d, pl=%d\n",
 
66
            cmd, p1, p2, p3, p4, p5, unsol, plsize);
 
67
 
 
68
  memset (&msg, 0, sizeof (msg));
 
69
 
 
70
  msg.cmd = cmd;
 
71
  msg.unsolicited = unsol;
 
72
  msg.p1 = p1;
 
73
  msg.p2 = p2;
 
74
  msg.p3 = p3;
 
75
  msg.p4 = p4;
 
76
  msg.p5 = p5;
 
77
  msg.payload_size = plsize;
 
78
 
 
79
  if (write (connfd, &msg, sizeof (msg)) != sizeof (msg))
 
80
    {
 
81
      fprintf (stderr, "Write to socket failed\n");
 
82
    }
 
83
 
 
84
  if (write (connfd, payload, msg.payload_size) != msg.payload_size)
 
85
    {
 
86
      fprintf (stderr, "Write to socket failed\n");
 
87
    }
 
88
}
 
89
 
 
90
static void
 
91
send_error (const char *msg)
 
92
{
 
93
  int l = strlen (msg) + 1;
 
94
 
 
95
  send_response_long (OSSMIX_CMD_ERROR, 0, 0, 0, 0, 0, msg, l, 0);
 
96
}
 
97
 
 
98
int
 
99
wait_connect (void)
 
100
{
 
101
  if (listen (listenfd, 1) == -1)
 
102
    {
 
103
      perror ("listen");
 
104
      exit (-1);
 
105
    }
 
106
 
 
107
  if ((connfd = accept (listenfd, NULL, NULL)) == -1)
 
108
    {
 
109
      perror ("accept");
 
110
      exit (-1);
 
111
    }
 
112
 
 
113
  return 1;
 
114
}
 
115
 
 
116
static void
 
117
send_ack (void)
 
118
{
 
119
  send_response (OSSMIX_CMD_OK, 0, 0, 0, 0, 0, 0);
 
120
}
 
121
 
 
122
static void
 
123
return_value (int val)
 
124
{
 
125
  send_response (val, 0, 0, 0, 0, 0, 0);
 
126
}
 
127
 
 
128
static void
 
129
send_multiple_nodes (ossmix_commad_packet_t * pack)
 
130
{
 
131
  int i, n;
 
132
  oss_mixext nodes[MAX_NODES];
 
133
 
 
134
  n = 0;
 
135
  for (i = pack->p2; i <= pack->p3; i++)
 
136
    {
 
137
      if (ossmix_get_nodeinfo (pack->p1, i, &nodes[n]) < 0)
 
138
        {
 
139
          send_error ("Cannot get mixer node info\n");
 
140
          return;
 
141
        }
 
142
 
 
143
      mixc_add_node (pack->p1, i, &nodes[n]);
 
144
 
 
145
      if (++n >= MAX_NODES)
 
146
        {
 
147
          send_response_long (OSSMIX_CMD_GET_NODEINFO, n, i, 0, 0, 0,
 
148
                              (void *) &nodes, n * sizeof (oss_mixext), 0);
 
149
          n = 0;
 
150
        }
 
151
    }
 
152
 
 
153
  if (n > 0)
 
154
    send_response_long (OSSMIX_CMD_GET_NODEINFO, n, pack->p3, 0, 0, 0,
 
155
                        (void *) &nodes, n * sizeof (oss_mixext), 0);
 
156
}
 
157
 
 
158
static void
 
159
update_values (int mixernum)
 
160
{
 
161
  oss_mixext *ext;
 
162
  int i;
 
163
  int nrext;
 
164
  int value, prev_value;
 
165
 
 
166
  nrext = ossmix_get_nrext (mixernum);
 
167
 
 
168
  for (i = 0; i < nrext; i++)
 
169
    {
 
170
      if ((ext = mixc_get_node (mixernum, i)) == NULL)
 
171
        continue;
 
172
 
 
173
      if (ext->type == MIXT_DEVROOT || ext->type == MIXT_GROUP
 
174
          || ext->type == MIXT_MARKER)
 
175
        continue;
 
176
 
 
177
      prev_value = mixc_get_value (mixernum, i);
 
178
 
 
179
      if ((value = ossmix_get_value (mixernum, i, ext->timestamp)) < 0)
 
180
        continue;
 
181
      // TODO check for EIDRM
 
182
 
 
183
      mixc_set_value (mixernum, i, value);
 
184
    }
 
185
}
 
186
 
 
187
static void
 
188
serve_command (ossmix_commad_packet_t * pack)
 
189
{
 
190
  switch (pack->cmd)
 
191
    {
 
192
    case OSSMIX_CMD_INIT:
 
193
      polling_started = 0;
 
194
      if (pack->ack_rq)
 
195
        send_ack ();
 
196
      break;
 
197
 
 
198
    case OSSMIX_CMD_EXIT:
 
199
      //fprintf(stderr, "Exit\n");
 
200
      polling_started = 0;
 
201
      memset(mixer_open_mask, 0, sizeof(mixer_open_mask));
 
202
      if (pack->ack_rq)
 
203
        send_ack ();
 
204
      break;
 
205
 
 
206
    case OSSMIX_CMD_START_EVENTS:
 
207
      polling_started = 1;
 
208
      break;
 
209
 
 
210
    case OSSMIX_CMD_GET_NMIXERS:
 
211
      return_value (num_mixers=ossmix_get_nmixers ());
 
212
      break;
 
213
 
 
214
    case OSSMIX_CMD_GET_MIXERINFO:
 
215
      {
 
216
        oss_mixerinfo mi;
 
217
 
 
218
        if (ossmix_get_mixerinfo (pack->p1, &mi) < 0)
 
219
          send_error ("Cannot get mixer info\n");
 
220
        else
 
221
          send_response_long (OSSMIX_CMD_OK, 0, 0, 0, 0, 0, (void *) &mi,
 
222
                              sizeof (mi), 0);
 
223
      }
 
224
      break;
 
225
 
 
226
    case OSSMIX_CMD_OPEN_MIXER:
 
227
      mixer_open_mask[pack->p1 / 8] |= (1<<(pack->p1 % 8)); // Open
 
228
      return_value (ossmix_open_mixer (pack->p1));
 
229
      break;
 
230
 
 
231
    case OSSMIX_CMD_CLOSE_MIXER:
 
232
      mixer_open_mask[pack->p1 / 8] &= ~(1<<(pack->p1 % 8)); // Closed
 
233
      ossmix_close_mixer (pack->p1);
 
234
      break;
 
235
 
 
236
    case OSSMIX_CMD_GET_NREXT:
 
237
      return_value (ossmix_get_nrext (pack->p1));
 
238
      break;
 
239
 
 
240
    case OSSMIX_CMD_GET_NODEINFO:
 
241
      {
 
242
        oss_mixext ext;
 
243
 
 
244
        if (pack->p3 > pack->p2)
 
245
          {
 
246
            send_multiple_nodes (pack);
 
247
            break;
 
248
          }
 
249
 
 
250
        if (ossmix_get_nodeinfo (pack->p1, pack->p2, &ext) < 0)
 
251
          send_error ("Cannot get mixer node info\n");
 
252
        else
 
253
          {
 
254
            mixc_add_node (pack->p1, pack->p2, &ext);
 
255
            send_response_long (OSSMIX_CMD_OK, 0, 0, 0, 0, 0, (void *) &ext,
 
256
                                sizeof (ext), 0);
 
257
          }
 
258
      }
 
259
      break;
 
260
 
 
261
    case OSSMIX_CMD_GET_ENUMINFO:
 
262
      {
 
263
        oss_mixer_enuminfo desc;
 
264
 
 
265
        if (ossmix_get_enuminfo (pack->p1, pack->p2, &desc) < 0)
 
266
          send_error ("Cannot get mixer enum strings\n");
 
267
        else
 
268
          send_response_long (OSSMIX_CMD_OK, 0, 0, 0, 0, 0, (void *) &desc,
 
269
                              sizeof (desc), 0);
 
270
      }
 
271
      break;
 
272
 
 
273
    case OSSMIX_CMD_GET_DESCRIPTION:
 
274
      {
 
275
        oss_mixer_enuminfo desc;
 
276
 
 
277
        if (ossmix_get_description (pack->p1, pack->p2, &desc) < 0)
 
278
          send_error ("Cannot get mixer description\n");
 
279
        else
 
280
          send_response_long (OSSMIX_CMD_OK, 0, 0, 0, 0, 0, (void *) &desc,
 
281
                              sizeof (desc), 0);
 
282
      }
 
283
      break;
 
284
 
 
285
    case OSSMIX_CMD_GET_VALUE:
 
286
      return_value (ossmix_get_value (pack->p1, pack->p2, pack->p3));
 
287
      break;
 
288
 
 
289
    case OSSMIX_CMD_GET_ALL_VALUES:
 
290
      {
 
291
        int n;
 
292
        value_packet_t value_packet;
 
293
 
 
294
        update_values (pack->p1);
 
295
        n = mixc_get_all_values (pack->p1, value_packet, 0);
 
296
 
 
297
        send_response_long (OSSMIX_CMD_GET_ALL_VALUES, n, pack->p1, 0, 0, 0,
 
298
                            (void *) &value_packet,
 
299
                            n * sizeof (value_record_t), 0);
 
300
        mixc_clear_changeflags (pack->p1);
 
301
      }
 
302
      break;
 
303
 
 
304
    case OSSMIX_CMD_SET_VALUE:
 
305
      ossmix_set_value (pack->p1, pack->p2, pack->p3, pack->p4);
 
306
      break;
 
307
 
 
308
    default:
 
309
 
 
310
      if (pack->ack_rq)
 
311
        send_error ("Unrecognized request");
 
312
    }
 
313
}
 
314
 
 
315
static void
 
316
poll_devices (void)
 
317
{
 
318
        int n;
 
319
        int mixernum;
 
320
        value_packet_t value_packet;
 
321
 
 
322
        for (mixernum=0;mixernum<num_mixers;mixernum++)
 
323
        if (mixer_open_mask[mixernum / 8] & 1<<(mixernum % 8))
 
324
        {
 
325
                update_values (mixernum);
 
326
                n = mixc_get_all_values (mixernum, value_packet, 1);
 
327
        
 
328
                if (n==0)       /* Nothing changed */
 
329
                   continue;
 
330
 
 
331
                send_response_long (OSSMIX_EVENT_VALUE, n, mixernum, 0, 0, 0,
 
332
                                    (void *) &value_packet,
 
333
                                    n * sizeof (value_record_t), 1);
 
334
                mixc_clear_changeflags (mixernum);
 
335
        }
 
336
 
 
337
        n=ossmix_get_nmixers();
 
338
        if (n>num_mixers)
 
339
        {
 
340
                num_mixers=n;
 
341
                send_response (OSSMIX_EVENT_NEWMIXER, n, 0, 0, 0, 0, 1);
 
342
        }
 
343
}
 
344
 
 
345
static void
 
346
handle_connection (int connfd)
 
347
{
 
348
  ossmix_commad_packet_t pack;
 
349
  struct timeval tmout;
 
350
 
 
351
  send_response (OSSMIX_CMD_HALOO, OSSMIX_P1_MAGIC, 0, 0, 0, 0, 0);
 
352
 
 
353
  tmout.tv_sec = 1;
 
354
  tmout.tv_usec = 0;
 
355
 
 
356
  while (1)
 
357
    {
 
358
      int ndevs;
 
359
      fd_set readfds, exfds;
 
360
      FD_ZERO (&readfds);
 
361
      FD_ZERO (&exfds);
 
362
 
 
363
      FD_SET (connfd, &readfds);
 
364
      FD_SET (connfd, &exfds);
 
365
 
 
366
      if ((ndevs = select (connfd + 1, &readfds, NULL, &exfds, &tmout)) == -1)
 
367
        {
 
368
          perror ("select");
 
369
          exit (-1);
 
370
        }
 
371
 
 
372
      if (ndevs == 0)
 
373
        {
 
374
          if (polling_started)
 
375
            {
 
376
              poll_devices ();
 
377
              tmout.tv_sec = 0;
 
378
              tmout.tv_usec = 100000;
 
379
            }
 
380
          else
 
381
            {
 
382
              tmout.tv_sec = 1;
 
383
              tmout.tv_usec = 0;
 
384
            }
 
385
        }
 
386
 
 
387
      if (FD_ISSET (connfd, &readfds) || FD_ISSET (connfd, &exfds))
 
388
        {
 
389
          if (read (connfd, &pack, sizeof (pack)) == sizeof (pack))
 
390
            {
 
391
              serve_command (&pack);
 
392
            }
 
393
          else
 
394
            return;
 
395
        }
 
396
    }
 
397
 
 
398
 
 
399
}
 
400
 
 
401
int
 
402
main (int argc, char *argv[])
 
403
{
 
404
  struct sockaddr_in servaddr;
 
405
  int port = 7777;
 
406
  int c;
 
407
  int err;
 
408
 
 
409
  if ((err = ossmix_init ()) < 0)
 
410
    {
 
411
      fprintf (stderr, "ossmix_init() failed, err=%d\n", err);
 
412
      exit (EXIT_FAILURE);
 
413
    }
 
414
 
 
415
  if ((err = ossmix_connect (NULL, 0)) < 0)     /* Force local connection */
 
416
    {
 
417
      fprintf (stderr, "ossmix_connect() failed, err=%d\n", err);
 
418
      exit (EXIT_FAILURE);
 
419
    }
 
420
 
 
421
  while ((c = getopt (argc, argv, "vp:")) != EOF)
 
422
    {
 
423
      switch (c)
 
424
        {
 
425
        case 'p':               /* TCP/IP port */
 
426
          port = atoi (optarg);
 
427
          if (port <= 0)
 
428
            port = 9876;
 
429
          break;
 
430
 
 
431
        case 'v':               /* Verbose */
 
432
          verbose++;
 
433
          break;
 
434
        }
 
435
    }
 
436
 
 
437
  printf ("Listening socket %d\n", port);
 
438
 
 
439
  if ((listenfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
 
440
    {
 
441
      perror ("socket");
 
442
      exit (-1);
 
443
    }
 
444
 
 
445
  memset (&servaddr, 0, sizeof (servaddr));
 
446
  servaddr.sin_family = AF_INET;
 
447
  servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
 
448
  servaddr.sin_port = htons (port);
 
449
 
 
450
  if (bind (listenfd, (struct sockaddr *) &servaddr, sizeof (servaddr)) == -1)
 
451
    {
 
452
      perror ("bind");
 
453
      exit (-1);
 
454
    }
 
455
 
 
456
  while (1)
 
457
    {
 
458
 
 
459
      if (!wait_connect ())
 
460
        exit (-1);
 
461
 
 
462
      handle_connection (connfd);
 
463
      close (connfd);
 
464
    }
 
465
 
 
466
  // close (listenfd); /* Not reached */
 
467
  exit (0);
 
468
}