~drgeo-developers/drgeo/trunk

« back to all changes in this revision

Viewing changes to VMs/iPad/source/unix/vm-sound-ALSA/sqUnixSoundALSA.c

  • Committer: Hilaire Fernandes
  • Date: 2012-01-27 21:15:40 UTC
  • Revision ID: hilaire.fernandes@gmail.com-20120127211540-912spf97bhpx6mve
Initial additions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* sqUnixSoundALSA.c -- cheap and cheerful sound for Advanced Linux Sound Architecture
 
2
 *
 
3
 * Author: Ian.Piumarta@squeakland.org
 
4
 * 
 
5
 * Last edited: 2010-04-01 13:48:37 by piumarta on emilia-2.local
 
6
 *
 
7
 *   Copyright (C) 2006 by Ian Piumarta
 
8
 *   All rights reserved.
 
9
 *   
 
10
 *   This file is part of Unix Squeak.
 
11
 * 
 
12
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 
13
 *   of this software and associated documentation files (the "Software"), to deal
 
14
 *   in the Software without restriction, including without limitation the rights
 
15
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
16
 *   copies of the Software, and to permit persons to whom the Software is
 
17
 *   furnished to do so, subject to the following conditions:
 
18
 * 
 
19
 *   The above copyright notice and this permission notice shall be included in
 
20
 *   all copies or substantial portions of the Software.
 
21
 * 
 
22
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
23
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
24
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
25
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
26
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
27
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
28
 *   SOFTWARE.
 
29
 */
 
30
 
 
31
#include "sq.h"
 
32
#include <alsa/asoundlib.h>
 
33
#include <errno.h>
 
34
#include <signal.h>
 
35
 
 
36
 
 
37
#define DEVICE_NAME_LEN 128
 
38
 
 
39
static char sound_device[DEVICE_NAME_LEN];      /* = "default"; */
 
40
static char sound_playback[DEVICE_NAME_LEN];    /* = "Master"; */
 
41
static char sound_capture[DEVICE_NAME_LEN];     /* = "Capture"; */
 
42
 
 
43
 
 
44
#define FAIL(X)         \
 
45
{                       \
 
46
  success(false);       \
 
47
  return X;             \
 
48
}
 
49
 
 
50
#define snd(expr, what)                                         \
 
51
  if ((err= snd_##expr) < 0)                                    \
 
52
    {                                                           \
 
53
      fprintf(stderr, "%s: %s\n", what, snd_strerror(err));     \
 
54
      success(false);                                           \
 
55
      return err;                                               \
 
56
    }
 
57
 
 
58
#define MIN(X, Y)       ((X) < (Y) ? (X) : (Y))
 
59
#define MAX(X, Y)       ((X) > (Y) ? (X) : (Y))
 
60
 
 
61
static void sigio_save(void);
 
62
static void sigio_restore(void);
 
63
 
 
64
 
 
65
/* output */
 
66
 
 
67
 
 
68
#define SQ_SND_PLAY_START_THRESHOLD     7/8
 
69
#define SQ_SND_PLAY_AVAIL_MIN           4/8
 
70
 
 
71
static snd_pcm_t                *output_handle= 0;
 
72
static snd_async_handler_t      *output_handler= 0;
 
73
static int                       output_semaphore= 0;
 
74
static int                       output_channels= 0;
 
75
static int                       output_buffer_frames_available= 0;
 
76
static snd_pcm_uframes_t         output_buffer_period_size= 0;
 
77
static snd_pcm_uframes_t         output_buffer_size= 0;
 
78
static double                    max_delay_frames= 0;
 
79
 
 
80
static void output_callback(snd_async_handler_t *handler)
 
81
{
 
82
  signalSemaphoreWithIndex(output_semaphore);
 
83
  output_buffer_frames_available= 1;
 
84
}
 
85
 
 
86
static sqInt sound_Stop(void)
 
87
{
 
88
  if (output_handle)
 
89
    {
 
90
      snd_pcm_close(output_handle);
 
91
      output_handle= 0;
 
92
      sigio_restore();
 
93
    }
 
94
  return 0;
 
95
}
 
96
 
 
97
static sqInt sound_Start(sqInt frameCount, sqInt samplesPerSec, sqInt stereo, sqInt semaIndex)
 
98
{
 
99
  int                    err;
 
100
  snd_pcm_hw_params_t   *hwparams;
 
101
  snd_pcm_sw_params_t   *swparams;
 
102
  unsigned int           uval;
 
103
  int                    dir;
 
104
 
 
105
  if (output_handle) sound_Stop();
 
106
 
 
107
  output_semaphore= semaIndex;
 
108
  output_channels= stereo ? 2 : 1;
 
109
  snd(pcm_open(&output_handle, sound_device, SND_PCM_STREAM_PLAYBACK, 0), "startSound: snd_pcm_open");
 
110
 
 
111
  snd_pcm_hw_params_alloca(&hwparams);
 
112
  snd_pcm_hw_params_any(output_handle, hwparams);
 
113
  snd_pcm_hw_params_set_access(output_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
 
114
  snd_pcm_hw_params_set_format(output_handle, hwparams, SND_PCM_FORMAT_S16_LE);
 
115
  snd_pcm_hw_params_set_channels(output_handle, hwparams, output_channels);
 
116
  uval= samplesPerSec;
 
117
  snd_pcm_hw_params_set_rate_near(output_handle, hwparams, &uval, &dir);
 
118
  output_buffer_period_size= frameCount;
 
119
  snd_pcm_hw_params_set_period_size_near(output_handle, hwparams, &output_buffer_period_size, &dir);
 
120
  snd(pcm_hw_params(output_handle, hwparams), "sound_Start: snd_pcm_hw_params");
 
121
 
 
122
  snd_pcm_sw_params_alloca(&swparams);
 
123
  snd(pcm_sw_params_current(output_handle, swparams), "sound_Start: snd_pcm_sw_params_current");
 
124
  snd(pcm_sw_params_set_start_threshold(output_handle, swparams, frameCount * SQ_SND_PLAY_START_THRESHOLD), "sound_Start: snd_pcm_sw_params_set_start_threshold");
 
125
  snd(pcm_sw_params_set_avail_min(output_handle, swparams, frameCount * SQ_SND_PLAY_AVAIL_MIN), "sound_Start: snd_pcm_sw_parama_set_avail_min");
 
126
  snd(pcm_sw_params_set_xfer_align(output_handle, swparams, 1), "sound_Start: snd_pcm_sw_params_set_xfer_align");
 
127
  snd(pcm_sw_params(output_handle, swparams), "sound_Start: snd_pcm_sw_params");
 
128
  snd(pcm_hw_params_get_buffer_size(hwparams, &output_buffer_size), "sound_Start: pcm_hw_params_get_buffer_size");
 
129
  output_buffer_frames_available= 1;
 
130
  max_delay_frames= output_buffer_period_size * 2;      /* set initial delay frames */
 
131
 
 
132
  snd(pcm_nonblock(output_handle, 1), "sound_Start: snd_pcm_nonblock");
 
133
  snd(async_add_pcm_handler(&output_handler, output_handle, output_callback, 0), "soundStart: snd_add_pcm_handler");
 
134
 
 
135
  if ((err= snd_pcm_start(output_handle)) < 0)
 
136
    {
 
137
      if (err != -EPIPE)
 
138
        {
 
139
          fprintf(stderr, "snd_pcm_start(1): %s\n", snd_strerror(err));
 
140
          success(false);
 
141
          return 0;
 
142
        }
 
143
    }
 
144
 
 
145
  if ((err= snd_pcm_prepare(output_handle)) < 0)
 
146
    fprintf(stderr, "snd_pcm_prepare: %s\n", snd_strerror(err));
 
147
 
 
148
  if ((err= snd_pcm_start(output_handle)) < 0)
 
149
    {
 
150
      if (err != -EPIPE)
 
151
        {
 
152
          fprintf(stderr, "snd_pcm_start(2): %s\n", snd_strerror(err));
 
153
          success(false);
 
154
          return 0;
 
155
        }
 
156
    }
 
157
 
 
158
  return 1;
 
159
}
 
160
 
 
161
static sqInt sound_AvailableSpace(void)
 
162
{
 
163
#if 1
 
164
  snd_pcm_sframes_t delay;    /* distance to playback point (in frames) */
 
165
  snd_pcm_state_t   state;    /* current state of the stream */
 
166
  sqInt             avail= 0; /* available space for the answer (in bytes) */
 
167
 
 
168
  if (!output_handle) return 0;
 
169
 
 
170
  snd_pcm_delay(output_handle, &delay);
 
171
  snd_pcm_avail_update(output_handle);
 
172
  state= snd_pcm_state(output_handle);
 
173
 
 
174
  /* if underrun causes, max delay is loosened */
 
175
  if (state == SND_PCM_STATE_XRUN)
 
176
    max_delay_frames=   MIN(max_delay_frames * 1.5, output_buffer_size - output_buffer_period_size);
 
177
 
 
178
  /* if the state is not running, new sound is needed because nobody can signal the semaphore */
 
179
  if (delay <= max_delay_frames || state != SND_PCM_STATE_RUNNING)
 
180
    {
 
181
      avail= output_buffer_period_size;
 
182
      max_delay_frames= MAX(max_delay_frames * 0.9995, output_buffer_period_size);
 
183
    }
 
184
  /*fprintf(stderr, "delay=%i, ans_avail=%i, state=%i, real_delay=%.1fms\n", (int) delay, avail, state, 1000 * max_delay_frames / 22050);*/
 
185
  return avail * output_channels * 2;   /* bytes */
 
186
#else
 
187
  if (output_handle)
 
188
    {
 
189
      int count= snd_pcm_avail_update(output_handle);
 
190
      if (count >= 0)
 
191
        return count;
 
192
      fprintf(stderr, "sound_AvailableSpace: snd_pcm_avail_update: %s\n", snd_strerror(count));
 
193
      snd_pcm_prepare(output_handle);
 
194
    }
 
195
  return 0;
 
196
#endif
 
197
}
 
198
 
 
199
static sqInt  sound_InsertSamplesFromLeadTime(sqInt frameCount, void *srcBufPtr, sqInt samplesOfLeadTime)       FAIL(frameCount)
 
200
 
 
201
static sqInt  sound_PlaySamplesFromAtLength(sqInt frameCount, void *srcBufPtr, sqInt startIndex)
 
202
{
 
203
  if (output_handle)
 
204
    {
 
205
      void *samples= srcBufPtr + startIndex * output_channels * 2;
 
206
      int   count=   snd_pcm_writei(output_handle, samples, frameCount);
 
207
      if (count < frameCount / 2)
 
208
        {
 
209
          output_buffer_frames_available= 0;
 
210
        }
 
211
      if (count < 0)
 
212
        {
 
213
          if (count == -EPIPE)    /* underrun */
 
214
            {
 
215
              int err;
 
216
              snd(pcm_prepare(output_handle), "sound_PlaySamples: snd_pcm_prepare");
 
217
              return 0;
 
218
            }
 
219
          fprintf(stderr, "snd_pcm_writei returned %i\n", count);
 
220
          return 0;
 
221
        }
 
222
      return count;
 
223
    }
 
224
  success(false);
 
225
  return 0;
 
226
}
 
227
 
 
228
static sqInt  sound_PlaySilence(void)                                                                           FAIL(8192)
 
229
 
 
230
 
 
231
/* input */
 
232
 
 
233
 
 
234
#define SQ_SND_REC_START_THRESHOLD      4/8
 
235
#define SQ_SND_REC_AVAIL_MIN            4/8
 
236
 
 
237
static snd_pcm_t                *input_handle= 0;
 
238
static snd_async_handler_t      *input_handler= 0;
 
239
static int                       input_semaphore= 0;
 
240
static int                       input_channels= 0;
 
241
static unsigned int              input_rate= 0;
 
242
 
 
243
static void input_callback(snd_async_handler_t *handler)
 
244
{
 
245
  signalSemaphoreWithIndex(input_semaphore);
 
246
}
 
247
 
 
248
static sqInt sound_StopRecording(void)
 
249
{
 
250
  if (input_handle)
 
251
    {
 
252
      snd_pcm_close(input_handle);
 
253
      input_handle= 0;
 
254
      sigio_restore();
 
255
    }
 
256
  return 0;
 
257
}
 
258
 
 
259
static sqInt sound_StartRecording(sqInt desiredSamplesPerSec, sqInt stereo, sqInt semaIndex)
 
260
{
 
261
  int                    err;
 
262
  snd_pcm_hw_params_t   *hwparams;
 
263
  snd_pcm_sw_params_t   *swparams;
 
264
  snd_pcm_uframes_t      frames;
 
265
  int                    dir;
 
266
 
 
267
  if (input_handle) sound_StopRecording();
 
268
 
 
269
  input_semaphore= semaIndex;
 
270
  input_channels= stereo ? 2 : 1;
 
271
  snd(pcm_open(&input_handle, sound_device, SND_PCM_STREAM_CAPTURE, 0), "start_SoundRecording: snd_pcm_open");
 
272
 
 
273
  snd_pcm_hw_params_alloca(&hwparams);
 
274
  snd_pcm_hw_params_any(input_handle, hwparams);
 
275
  snd_pcm_hw_params_set_access(input_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
 
276
  snd_pcm_hw_params_set_format(input_handle, hwparams, SND_PCM_FORMAT_S16_LE);
 
277
  snd_pcm_hw_params_set_channels(input_handle, hwparams, input_channels);
 
278
  input_rate= desiredSamplesPerSec;
 
279
  snd_pcm_hw_params_set_rate_near(input_handle, hwparams, &input_rate, &dir);
 
280
  frames= 4096;
 
281
  snd_pcm_hw_params_set_period_size_near(input_handle, hwparams, &frames, &dir);
 
282
  snd(pcm_hw_params(input_handle, hwparams), "sound_StartRecording: snd_pcm_hw_params");
 
283
 
 
284
  snd_pcm_sw_params_alloca(&swparams);
 
285
  snd(pcm_sw_params_current(input_handle, swparams), "sound_StartRecording: snd_pcm_sw_params_current");
 
286
  snd(pcm_sw_params_set_start_threshold(input_handle, swparams, frames * SQ_SND_REC_START_THRESHOLD), "sound_StartRecording: snd_pcm_sw_params_set_start_threshold");
 
287
  snd(pcm_sw_params_set_avail_min(input_handle, swparams, frames * SQ_SND_REC_AVAIL_MIN), "sound_StartRecording: snd_pcm_sw_parama_set_avail_min");
 
288
  snd(pcm_sw_params_set_xfer_align(input_handle, swparams, 1), "sound_StartRecording: snd_pcm_sw_params_set_xfer_align");
 
289
  snd(pcm_sw_params(input_handle, swparams), "sound_StartRecording: snd_pcm_sw_params");
 
290
 
 
291
  snd(pcm_nonblock(input_handle, 1), "sound_StartRecording: snd_pcm_nonblock");
 
292
  snd(async_add_pcm_handler(&input_handler, input_handle, input_callback, 0), "sound_StartRecording: snd_add_pcm_handler");
 
293
  snd(pcm_start(input_handle), "sound_StartRecording: snd_pcm_start");
 
294
  return 1;
 
295
}
 
296
 
 
297
static double sound_GetRecordingSampleRate(void)
 
298
{
 
299
  return (double)input_rate;
 
300
}
 
301
 
 
302
static sqInt sound_RecordSamplesIntoAtLength(void *buf, sqInt startSliceIndex, sqInt bufferSizeInBytes)
 
303
{
 
304
  if (input_handle)
 
305
    {
 
306
      void *samples=    buf + (startSliceIndex * 2);
 
307
      int   frameCount= ((bufferSizeInBytes / 2) - startSliceIndex) / input_channels;
 
308
      int   count=      snd_pcm_readi(input_handle, samples, frameCount);
 
309
      if (count < 0)
 
310
        {    
 
311
          if (count == -EPIPE)
 
312
            snd_pcm_prepare(input_handle);
 
313
          else if (count != -EAGAIN)
 
314
            fprintf(stderr, "snd_pcm_readi returned %i\n", count);
 
315
          return 0;
 
316
        }
 
317
      return count * input_channels;
 
318
    }
 
319
  success(false);
 
320
  return 0;
 
321
}
 
322
 
 
323
 
 
324
/* mixer */
 
325
 
 
326
 
 
327
static int               sound_nomixer  = 0;
 
328
static snd_mixer_t      *mixer_handle   = 0;
 
329
static snd_mixer_elem_t *mixer_element  = 0;
 
330
 
 
331
 
 
332
static int mixer_open(char *name)
 
333
{
 
334
  struct snd_mixer_selem_regopt  smixer_options;
 
335
  int                            err;
 
336
  snd_mixer_selem_id_t          *sid;
 
337
 
 
338
  if (sound_nomixer) return -EACCES;
 
339
 
 
340
  smixer_options.device= sound_device;
 
341
  snd_mixer_selem_id_alloca(&sid);
 
342
  snd_mixer_selem_id_set_name(sid, name);
 
343
  snd(mixer_open(&mixer_handle, 0),                     "snd_mixer_open");
 
344
  snd(mixer_attach(mixer_handle, sound_device),         "snd_mixer_attach");
 
345
  snd(mixer_selem_register(mixer_handle, NULL, NULL),   "snd_selem_register");
 
346
  snd(mixer_load(mixer_handle),                         "snd_mixer_load");
 
347
 
 
348
  mixer_element= snd_mixer_find_selem(mixer_handle, sid);
 
349
 
 
350
  if (!mixer_element)
 
351
    {
 
352
      fprintf(stderr, "unable to find control %s, %i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
 
353
      return -ENOENT;
 
354
    }
 
355
 
 
356
  return 0;
 
357
}
 
358
 
 
359
static void mixer_close(void)
 
360
{
 
361
  snd_mixer_close(mixer_handle);
 
362
  mixer_handle= 0;
 
363
}
 
364
 
 
365
 
 
366
static inline void mixer_getVolume(char *name, int captureFlag, double *leftLevel, double *rightLevel)
 
367
{
 
368
  if (mixer_open(name))
 
369
    {
 
370
      mixer_close();
 
371
      return;
 
372
    }
 
373
 
 
374
  if (!(captureFlag ? snd_mixer_selem_has_capture_volume : snd_mixer_selem_has_playback_volume)(mixer_element))
 
375
    fprintf(stderr, "%s: no %s volume\n", name, captureFlag ? "capture" : "playback");
 
376
  else
 
377
    {
 
378
      long vmin, vmax;
 
379
      int channel= -1;
 
380
      (captureFlag ? snd_mixer_selem_get_capture_volume_range : snd_mixer_selem_get_playback_volume_range)(mixer_element, &vmin, &vmax);
 
381
      fprintf(stderr, "%s range  %li - %li\n", captureFlag ? "capture" : "playback", vmin, vmax);
 
382
      while (++channel <= SND_MIXER_SCHN_LAST)
 
383
        if ((captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, channel))
 
384
          {
 
385
            long vol;
 
386
            (captureFlag ? snd_mixer_selem_get_capture_volume : snd_mixer_selem_get_playback_volume)(mixer_element, channel, &vol);
 
387
            *leftLevel= *rightLevel= (double)(vol - vmin) / (double)(vmax - vmin);
 
388
            break;
 
389
          }
 
390
      while (++channel <= SND_MIXER_SCHN_LAST)
 
391
        if ((captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, channel))
 
392
          {
 
393
            long vol;
 
394
            (captureFlag ? snd_mixer_selem_get_capture_volume : snd_mixer_selem_get_playback_volume)(mixer_element, channel, &vol);
 
395
            *rightLevel= (double)(vol - vmin) / (double)(vmax - vmin);
 
396
            break;
 
397
          }
 
398
    }
 
399
 
 
400
  mixer_close();
 
401
}
 
402
 
 
403
 
 
404
static inline void mixer_setVolume(char *name, int captureFlag, double leftLevel, double rightLevel)
 
405
{
 
406
  if (mixer_open(name))
 
407
    {
 
408
      mixer_close();
 
409
      return;
 
410
    }
 
411
 
 
412
  if (!(captureFlag ? snd_mixer_selem_has_capture_volume : snd_mixer_selem_has_playback_volume)(mixer_element))
 
413
    fprintf(stderr, "%s: no %s volume\n", name, captureFlag ? "capture" : "playback");
 
414
  else
 
415
    {
 
416
      long vmin, vmax;
 
417
      int channel= -1;
 
418
      (captureFlag ? snd_mixer_selem_get_capture_volume_range : snd_mixer_selem_get_playback_volume_range)(mixer_element, &vmin, &vmax);
 
419
      fprintf(stderr, "playback range  %li - %li\n", vmin, vmax);
 
420
      while (++channel <= SND_MIXER_SCHN_LAST)
 
421
        if ((captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, channel))
 
422
          {
 
423
            long vol= vmin + (double)(vmax - vmin) * leftLevel;
 
424
            (captureFlag ? snd_mixer_selem_set_capture_volume : snd_mixer_selem_set_playback_volume)(mixer_element, channel, vol);
 
425
            (captureFlag ? snd_mixer_selem_set_capture_switch : snd_mixer_selem_set_playback_switch)(mixer_element, channel, 1);
 
426
            break;
 
427
          }
 
428
      while (++channel <= SND_MIXER_SCHN_LAST)
 
429
        if ((captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, channel))
 
430
          {
 
431
            long vol= vmin + (double)(vmax - vmin) * rightLevel;
 
432
            (captureFlag ? snd_mixer_selem_set_capture_volume : snd_mixer_selem_set_playback_volume)(mixer_element, channel, vol);
 
433
            (captureFlag ? snd_mixer_selem_set_capture_switch : snd_mixer_selem_set_playback_switch)(mixer_element, channel, 1);
 
434
            break;
 
435
          }
 
436
    }
 
437
 
 
438
  mixer_close();
 
439
}
 
440
 
 
441
static int mixer_setSwitch(char *name, int captureFlag, int parameter)
 
442
{
 
443
  int chn;
 
444
  if (mixer_open(name))
 
445
    {
 
446
      mixer_close();
 
447
      return 0;
 
448
    }
 
449
 
 
450
  if (!(captureFlag ? snd_mixer_selem_has_capture_switch : snd_mixer_selem_has_playback_switch)(mixer_element))
 
451
    {
 
452
      mixer_close();
 
453
      return 0;
 
454
    }
 
455
 
 
456
  for (chn= 0;  chn <= SND_MIXER_SCHN_LAST;  ++chn)
 
457
    {
 
458
      if (!(captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, chn))
 
459
        continue;
 
460
 
 
461
      if ((captureFlag ? snd_mixer_selem_set_capture_switch : snd_mixer_selem_set_playback_switch)(mixer_element, chn, parameter) < 0)
 
462
        continue;
 
463
    }
 
464
 
 
465
  mixer_close();
 
466
  return 1;
 
467
}
 
468
 
 
469
static int mixer_getSwitch(char *name, int captureFlag, int channel)
 
470
{
 
471
  int ival;
 
472
  if (channel < 0 || channel > SND_MIXER_SCHN_LAST)
 
473
    {
 
474
      return -1;
 
475
    }
 
476
      
 
477
  if (mixer_open(name))
 
478
    {
 
479
      mixer_close();
 
480
      return -1;
 
481
    }
 
482
 
 
483
  if (!(captureFlag ? snd_mixer_selem_has_capture_switch : snd_mixer_selem_has_playback_switch)(mixer_element))
 
484
    {
 
485
      mixer_close();
 
486
      return -1;
 
487
    }
 
488
 
 
489
  if (!(captureFlag ? snd_mixer_selem_has_capture_channel : snd_mixer_selem_has_playback_channel)(mixer_element, channel))
 
490
    {
 
491
      mixer_close();
 
492
      return -1;
 
493
    }
 
494
 
 
495
  if ((captureFlag ? snd_mixer_selem_get_capture_switch : snd_mixer_selem_get_playback_switch)(mixer_element, channel, &ival) < 0)
 
496
    ival= -1;
 
497
 
 
498
  mixer_close();
 
499
  return ival;
 
500
}
 
501
 
 
502
static void sound_Volume(double *left, double *right)
 
503
{
 
504
  mixer_getVolume(sound_playback, 0, left, right);
 
505
}
 
506
 
 
507
static void sound_SetVolume(double left, double right)
 
508
{
 
509
  mixer_setVolume(sound_playback, 0, left, right);
 
510
  if (strcmp("Master", sound_playback))
 
511
    {
 
512
      /* unmute the master volume */
 
513
      mixer_getVolume("Master", 0, &left, &right);
 
514
      mixer_setVolume("Master", 0,  left,  right);
 
515
    }
 
516
}
 
517
 
 
518
static void sound_SetRecordLevel(sqInt level)
 
519
{
 
520
  mixer_setVolume(sound_capture, 1, (double)level / 100.0, (double)level / 100.0);
 
521
}
 
522
 
 
523
static sqInt sound_SetDevice(sqInt id, char *arg)
 
524
{
 
525
  char *dest= NULL; 
 
526
  if (id == 0)
 
527
    {
 
528
      if (arg == NULL)
 
529
        {
 
530
          arg= "default";
 
531
        }
 
532
      dest= sound_device;
 
533
    }
 
534
  else if (id == 1)
 
535
    {
 
536
      if (arg == NULL)
 
537
        {
 
538
          arg= "Master";
 
539
        }
 
540
      dest= sound_playback;
 
541
    }
 
542
  else if (id == 2)
 
543
    {
 
544
      if (arg == NULL)
 
545
        {
 
546
          arg= "Capture";
 
547
        }
 
548
      dest= sound_capture;
 
549
    }
 
550
  
 
551
  if (dest)
 
552
    {
 
553
      strncpy(dest, arg, DEVICE_NAME_LEN-1);
 
554
      return 1;
 
555
    }
 
556
  return -1;
 
557
}
 
558
 
 
559
static sqInt sound_GetSwitch(sqInt id, sqInt captureFlag, sqInt channel)
 
560
{
 
561
  if (id == 1)
 
562
    {
 
563
    return mixer_getSwitch(sound_playback, captureFlag, channel);
 
564
    }
 
565
  else if (id == 2)
 
566
    {
 
567
      return mixer_getSwitch(sound_capture, captureFlag, channel);
 
568
    }
 
569
  return -1;
 
570
}
 
571
 
 
572
static sqInt sound_SetSwitch(sqInt id, sqInt captureFlag, sqInt parameter)
 
573
{
 
574
  if (id == 1)
 
575
    {
 
576
      return mixer_setSwitch(sound_playback, captureFlag, parameter);
 
577
  }
 
578
  else if (id == 2)
 
579
    {
 
580
      return mixer_setSwitch(sound_capture, captureFlag, parameter);
 
581
    }
 
582
  return -1;
 
583
}
 
584
 
 
585
 
 
586
/* signal support */
 
587
 
 
588
 
 
589
static void *sigio_handler= 0;
 
590
 
 
591
static void sigio_save(void)
 
592
{
 
593
  if (!sigio_handler)
 
594
    {
 
595
      sigio_handler= signal(SIGIO, SIG_IGN);
 
596
      signal(SIGIO, sigio_handler);
 
597
    }
 
598
}
 
599
 
 
600
static void sigio_restore(void)
 
601
 
602
  if (sigio_handler && !output_handle && !input_handle)
 
603
    signal(SIGIO, sigio_handler);
 
604
}
 
605
 
 
606
 
 
607
/* module */
 
608
 
 
609
 
 
610
#include "SqSound.h"
 
611
 
 
612
SqSoundDefine(ALSA);
 
613
 
 
614
#include "SqModule.h"
 
615
 
 
616
static void sound_parseEnvironment(void)
 
617
{
 
618
  char *ev= 0;
 
619
 
 
620
  sound_SetDevice(0, NULL);
 
621
  sound_SetDevice(1, NULL);
 
622
  sound_SetDevice(2, NULL);
 
623
 
 
624
  if (     getenv("SQUEAK_NOMIXER"   )) sound_nomixer= 1;
 
625
  if ((ev= getenv("SQUEAK_SOUNDCARD"))) sound_SetDevice(0, ev);
 
626
  if ((ev= getenv("SQUEAK_PLAYBACK" ))) sound_SetDevice(1, ev);
 
627
  if ((ev= getenv("SQUEAK_CAPTURE"  ))) sound_SetDevice(2, ev);
 
628
}
 
629
 
 
630
static int  sound_parseArgument(int argc, char **argv)
 
631
{
 
632
  if     (!strcmp(argv[0], "-nomixer"  )) { sound_nomixer= 1;           return 1; }
 
633
  else if (argv[1])
 
634
    {
 
635
      if (!strcmp(argv[0], "-soundcard")) { sound_SetDevice(0, argv[1]);        return 2; }
 
636
      if (!strcmp(argv[0], "-playback" )) { sound_SetDevice(1, argv[1]);        return 2; }
 
637
      if (!strcmp(argv[0], "-capture"  )) { sound_SetDevice(2, argv[1]);        return 2; }
 
638
    }
 
639
  return 0;
 
640
}
 
641
 
 
642
static void  sound_printUsage(void)
 
643
{
 
644
  printf("\nALSA <option>s:\n");
 
645
  printf("  -nomixer              disable mixer (volume) adjustment\n");
 
646
  printf("  -soundcard <name>     open the named sound card (default: %s)\n", sound_device);
 
647
  printf("  -playback <name>      play to the named sound device (default: %s)\n", sound_playback);
 
648
  printf("  -capture <name>       record from the named sound device (default: %s)\n", sound_capture);
 
649
}
 
650
 
 
651
static void  sound_printUsageNotes(void) {}
 
652
 
 
653
static void *sound_makeInterface(void)
 
654
{
 
655
  sigio_save();
 
656
  return &sound_ALSA_itf;
 
657
}
 
658
 
 
659
SqModuleDefine(sound, ALSA);