~ubuntu-branches/ubuntu/oneiric/muse/oneiric

« back to all changes in this revision

Viewing changes to driver/alsa9audio.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2002-04-23 17:28:23 UTC
  • Revision ID: james.westby@ubuntu.com-20020423172823-w8yplzr81a759xa3
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=========================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//    $Id: alsa9audio.cpp,v 1.4 2002/02/27 11:52:58 muse Exp $
 
5
//  (C) Copyright 2000 Werner Schweer (ws@seh.de)
 
6
//=========================================================
 
7
 
 
8
#include "config.h"
 
9
 
 
10
#ifdef AUDIO
 
11
#ifdef ALSACVS
 
12
#include <alsa/asoundlib.h>
 
13
#else
 
14
#include <sys/asoundlib.h>
 
15
#endif
 
16
#if (SND_LIB_MAJOR==0) && (SND_LIB_MINOR==9)
 
17
#include <fcntl.h>
 
18
#include <stdio.h>
 
19
#include <unistd.h>
 
20
#include <errno.h>
 
21
#include <qstring.h>
 
22
#include <sys/ioctl.h>
 
23
#include <sys/time.h>
 
24
 
 
25
#include "globals.h"
 
26
#include "audiodev.h"
 
27
 
 
28
//---------------------------------------------------------
 
29
//   AlsaAudioDevice
 
30
//---------------------------------------------------------
 
31
 
 
32
class AlsaAudioDevice : public AudioDevice {
 
33
      int card;
 
34
      int dev;
 
35
      snd_pcm_t* playbackHandle;
 
36
      snd_pcm_t* captureHandle;
 
37
 
 
38
   public:
 
39
      AlsaAudioDevice(int c, int d, int f, const QString& s)
 
40
         : AudioDevice(s) {
 
41
            card = c;
 
42
            dev  = d;
 
43
            _rwFlags = f;
 
44
            playbackHandle = 0;
 
45
            captureHandle = 0;
 
46
            }
 
47
      virtual QString open(int);
 
48
      virtual void close();
 
49
      virtual int read(unsigned char* p, int n);
 
50
      virtual int write(const unsigned char* p, int n);
 
51
      virtual int selectrfd() const;
 
52
      virtual int selectwfd() const;
 
53
      virtual void start() const;
 
54
      virtual void stop () const;
 
55
      };
 
56
 
 
57
static int buffer_time = -1;
 
58
static int avail_min   = -1;
 
59
 
 
60
static size_t bits_per_sample;
 
61
static size_t bits_per_frame;
 
62
static size_t chunk_bytes;
 
63
static int chunk_size = -1;
 
64
 
 
65
//---------------------------------------------------------
 
66
//   xrun
 
67
//    playback write error handler
 
68
//---------------------------------------------------------
 
69
 
 
70
void xrun(snd_pcm_t* handle)
 
71
      {
 
72
      snd_pcm_status_t *status;
 
73
      int res;
 
74
 
 
75
      snd_pcm_status_alloca(&status);
 
76
      if ((res = snd_pcm_status(handle, status))<0) {
 
77
            printf("status error: %s", snd_strerror(res));
 
78
            exit(EXIT_FAILURE);
 
79
            }
 
80
      int state = snd_pcm_status_get_state(status);
 
81
      if (state == SND_PCM_STATE_XRUN) {
 
82
            struct timeval now, diff, tstamp;
 
83
            gettimeofday(&now, 0);
 
84
            snd_pcm_status_get_trigger_tstamp(status, &tstamp);
 
85
            timersub(&now, &tstamp, &diff);
 
86
            if (debugMsg)
 
87
                  fprintf(stderr, "xrun >= %.3f ms\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
 
88
            if ((res = snd_pcm_prepare(handle))<0) {
 
89
                  printf("xrun: prepare error: %s", snd_strerror(res));
 
90
                  exit(EXIT_FAILURE);
 
91
                  }
 
92
            return;     // ok, data should be accepted again
 
93
            }
 
94
      else {
 
95
            printf("ALSA xrun: read/write error in state %d\n", state);
 
96
            }
 
97
      }
 
98
 
 
99
//---------------------------------------------------------
 
100
//   setParams
 
101
//---------------------------------------------------------
 
102
 
 
103
static void setParams(snd_pcm_t* handle)
 
104
      {
 
105
      //-----------------------------------------------
 
106
      //   HW parameters
 
107
 
 
108
      snd_pcm_hw_params_t* hwparams;
 
109
      snd_pcm_hw_params_alloca(&hwparams);
 
110
      int err = snd_pcm_hw_params_any(handle, hwparams);
 
111
      if (err < 0) {
 
112
            printf("Broken configuration for this PCM: no configurations available");
 
113
            exit(EXIT_FAILURE);
 
114
            }
 
115
 
 
116
      err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
 
117
      if (err < 0) {
 
118
            printf("ALSA: Access type not available");
 
119
            exit(EXIT_FAILURE);
 
120
            }
 
121
 
 
122
      err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
 
123
      if (err < 0) {
 
124
            printf("ALSA: Sample format non available");
 
125
            exit(EXIT_FAILURE);
 
126
            }
 
127
      err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
 
128
      if (err < 0) {
 
129
            printf("ALSA: Channels count non available");
 
130
            exit(EXIT_FAILURE);
 
131
            }
 
132
 
 
133
      snd_pcm_hw_params_set_rate_near(handle, hwparams, sampleRate, 0);
 
134
 
 
135
      //
 
136
      // buffer
 
137
      //
 
138
// war 4
 
139
      buffer_time = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, segmentSize*3);
 
140
      buffer_time = snd_pcm_hw_params_set_period_size_near(handle, hwparams, segmentSize, 0);
 
141
 
 
142
      err = snd_pcm_hw_params(handle, hwparams);
 
143
      if (err < 0) {
 
144
            printf("Unable to install hw params:");
 
145
            exit(EXIT_FAILURE);
 
146
            }
 
147
      chunk_size      = snd_pcm_hw_params_get_period_size(hwparams, 0);
 
148
      int buffer_size = snd_pcm_hw_params_get_buffer_size(hwparams);
 
149
 
 
150
// printf("segment %d chunk %d, buffer %d\n", segmentSize, chunk_size, buffer_size);
 
151
 
 
152
      if (chunk_size == int(buffer_size)) {
 
153
            printf("Can't use period equal to buffer size (%u == %u)", chunk_size, buffer_size);
 
154
            exit(EXIT_FAILURE);
 
155
            }
 
156
 
 
157
      //-----------------------------------------------
 
158
      //   SW parameters
 
159
 
 
160
      snd_pcm_sw_params_t *swparams;
 
161
      snd_pcm_sw_params_alloca(&swparams);
 
162
      snd_pcm_sw_params_current(handle, swparams);
 
163
      int xfer_align = snd_pcm_sw_params_get_xfer_align(swparams);
 
164
      err = snd_pcm_sw_params_set_sleep_min(handle, swparams, 0);
 
165
      size_t n;
 
166
      if (avail_min < 0)
 
167
            n = chunk_size;
 
168
      else
 
169
            n = int (snd_pcm_hw_params_get_rate(hwparams, 0) * (double) avail_min / 1000000);
 
170
      snd_pcm_sw_params_set_avail_min(handle, swparams, n);
 
171
      snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
 
172
      if (snd_pcm_sw_params(handle, swparams) < 0) {
 
173
            printf("unable to install sw params:");
 
174
            exit(EXIT_FAILURE);
 
175
            }
 
176
 
 
177
      bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
 
178
      bits_per_frame  = bits_per_sample * 2; // 2=channels
 
179
      chunk_bytes     = chunk_size * bits_per_frame / 8;
 
180
 
 
181
//      printf("bits/frame %d,  real chunk_size = %i buffer %d, chunk %d\n",
 
182
//         bits_per_frame, chunk_size, buffer_size, chunk_size);
 
183
      }
 
184
 
 
185
//---------------------------------------------------------
 
186
//   open
 
187
//---------------------------------------------------------
 
188
 
 
189
QString AlsaAudioDevice::open(int rw)
 
190
      {
 
191
      int openFlags = SND_PCM_NONBLOCK;
 
192
 
 
193
      //---------------------------------------------------
 
194
      //  setup playback stream
 
195
      //---------------------------------------------------
 
196
 
 
197
      if (rw & 1) {
 
198
            snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
 
199
            int err = snd_pcm_open(&playbackHandle, "default", stream, openFlags);
 
200
        if (err < 0)
 
201
                return QString("Alsa open: ")+QString(snd_strerror(err));
 
202
            setParams(playbackHandle);
 
203
            int res = snd_pcm_prepare(playbackHandle);
 
204
            if (res <0) {
 
205
                  printf("prepare error: %s", snd_strerror(res));
 
206
                  exit(EXIT_FAILURE);
 
207
                  }
 
208
            }
 
209
      if (rw & 2) {
 
210
            snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
 
211
            int err = snd_pcm_open(&captureHandle, "default", stream, openFlags);
 
212
        if (err < 0)
 
213
                return QString("Alsa open: ")+QString(snd_strerror(err));
 
214
            setParams(captureHandle);
 
215
            }
 
216
      return QString("OK");
 
217
      }
 
218
 
 
219
//---------------------------------------------------------
 
220
//   read
 
221
//---------------------------------------------------------
 
222
 
 
223
int AlsaAudioDevice::read(unsigned char* buffer, int frames)
 
224
      {
 
225
      if (captureHandle == 0)
 
226
            return 0;
 
227
      int n = 0;
 
228
      while (frames > 0) {
 
229
            int rv = snd_pcm_readi(captureHandle, buffer, frames);
 
230
            if (rv == -EAGAIN || (rv >= 0 && rv < frames))
 
231
                  snd_pcm_wait(captureHandle, 1000);
 
232
            else if (rv == -EPIPE)
 
233
                  xrun(captureHandle);
 
234
            else if (rv < 0) {
 
235
                  fprintf(stderr, "AlsaAudioDevice: read(0x%x, 0x%x, %d+%d) failed: %s\n",
 
236
                    unsigned(captureHandle), unsigned(buffer), frames, n, snd_strerror(rv));
 
237
                  return rv;
 
238
                  }
 
239
            else {
 
240
                  n      += rv;
 
241
                  frames -= rv;
 
242
                  buffer   += rv * bits_per_frame / 8;
 
243
                  }
 
244
            }
 
245
      return n;
 
246
      }
 
247
 
 
248
//---------------------------------------------------------
 
249
//   start
 
250
//---------------------------------------------------------
 
251
 
 
252
void AlsaAudioDevice::start() const
 
253
      {
 
254
#if 0
 
255
      int err;
 
256
      if (captureHandle) {
 
257
              err = snd_pcm_start(captureHandle);
 
258
            if (err == -EPIPE)
 
259
                  xrun(playbackHandle);
 
260
            else if (err < 0)
 
261
                    printf("Alsa capture go: %s\n", snd_strerror(err));
 
262
            }
 
263
      if (playbackHandle) {
 
264
              int err = snd_pcm_start(playbackHandle);
 
265
            if (err == -EPIPE)
 
266
                  xrun(playbackHandle);
 
267
            else if (err < 0) {
 
268
                    printf("Alsa playback go: %s\n", snd_strerror(err));
 
269
                  }
 
270
            }
 
271
#endif
 
272
      }
 
273
 
 
274
//---------------------------------------------------------
 
275
//   stop
 
276
//---------------------------------------------------------
 
277
 
 
278
void AlsaAudioDevice::stop() const
 
279
      {
 
280
      if (captureHandle) {
 
281
              int err = snd_pcm_pause(captureHandle, 1);
 
282
            if (err < 0)
 
283
                    printf("Alsa capture pause: %s\n", snd_strerror(err));
 
284
            }
 
285
      if (playbackHandle) {
 
286
              int err = snd_pcm_pause(playbackHandle, 1);
 
287
            if (err < 0)
 
288
                    printf("Alsa playback pause: %s\n", snd_strerror(err));
 
289
            }
 
290
      }
 
291
 
 
292
//---------------------------------------------------------
 
293
//   write
 
294
//---------------------------------------------------------
 
295
 
 
296
int AlsaAudioDevice::write(const unsigned char* buffer, int n)
 
297
      {
 
298
      if (playbackHandle == 0)
 
299
            return 0;
 
300
      int result    = 0;
 
301
      int framesize = bits_per_frame/8;
 
302
      while (n > 0) {
 
303
            int r = snd_pcm_writei(playbackHandle, buffer, n);
 
304
            if (r == -EAGAIN) {
 
305
                  snd_pcm_wait(playbackHandle, 1000);
 
306
                  continue;
 
307
                  }
 
308
            else if (r == -EPIPE) {
 
309
                  xrun(playbackHandle);
 
310
                  continue;
 
311
                  }
 
312
            else if (r < 0) {
 
313
                  fprintf(stderr, "AlsaAudioDevice: write(0x%x, 0x%x, %d) failed: %s\n",
 
314
                    unsigned(playbackHandle), unsigned(buffer), n, snd_strerror(r));
 
315
                  exit(1);
 
316
                  }
 
317
            result += r;
 
318
            buffer += r * framesize;
 
319
            n -= r;
 
320
            if (n)
 
321
                  snd_pcm_wait(playbackHandle, 1000);
 
322
            }
 
323
      return result;
 
324
      }
 
325
 
 
326
//---------------------------------------------------------
 
327
//   selectwfd
 
328
//---------------------------------------------------------
 
329
 
 
330
int AlsaAudioDevice::selectwfd() const
 
331
      {
 
332
      if (playbackHandle) {
 
333
            int n = snd_pcm_poll_descriptors_count(playbackHandle);
 
334
            if (n != 1) {
 
335
                  printf("AlsaAudioDevice:selectwfd: not supported\n");
 
336
                  abort();
 
337
                  }
 
338
            struct pollfd fd[n];
 
339
            snd_pcm_poll_descriptors(playbackHandle, fd, n);
 
340
            return fd[0].fd;
 
341
            }
 
342
      return -1;
 
343
      }
 
344
 
 
345
//---------------------------------------------------------
 
346
//   selectrfd
 
347
//---------------------------------------------------------
 
348
 
 
349
int AlsaAudioDevice::selectrfd() const
 
350
      {
 
351
      if (captureHandle) {
 
352
            int n = snd_pcm_poll_descriptors_count(captureHandle);
 
353
            if (n != 1) {
 
354
                  printf("AlsaAudioDevice:selectrfd: not supported\n");
 
355
                  abort();
 
356
                  }
 
357
            struct pollfd fd[n];
 
358
            snd_pcm_poll_descriptors(captureHandle, fd, n);
 
359
            return fd[0].fd;
 
360
            }
 
361
      return -1;
 
362
      }
 
363
 
 
364
//---------------------------------------------------------
 
365
//   close
 
366
//---------------------------------------------------------
 
367
 
 
368
void AlsaAudioDevice::close()
 
369
      {
 
370
      if (captureHandle) {
 
371
              int err = snd_pcm_close(captureHandle);
 
372
            if (err < 0)
 
373
                    printf("Alsa close capture: %s\n", snd_strerror(err));
 
374
            }
 
375
      if (playbackHandle) {
 
376
              int err = snd_pcm_close(playbackHandle);
 
377
            if (err < 0)
 
378
                    printf("Alsa close playback: %s\n", snd_strerror(err));
 
379
            }
 
380
      captureHandle  = 0;
 
381
      playbackHandle = 0;
 
382
      }
 
383
 
 
384
//---------------------------------------------------------
 
385
//   initAlsaAudio
 
386
//    collect infos about audio devices
 
387
//    return true if no soundcard found
 
388
//---------------------------------------------------------
 
389
 
 
390
bool initAlsaAudio()
 
391
      {
 
392
      int card = -1;
 
393
      int err;
 
394
      if (snd_card_next(&card) < 0 || card < 0) {
 
395
            fprintf(stderr, "ALSA: no soundcard found\n");
 
396
            return true;
 
397
            }
 
398
      snd_ctl_card_info_t* info;
 
399
      snd_ctl_card_info_alloca(&info);
 
400
      snd_pcm_info_t* pcminfo;
 
401
      snd_pcm_info_alloca(&pcminfo);
 
402
      while (card >= 0) {
 
403
            snd_ctl_t* handle;
 
404
            char name[32];
 
405
            sprintf(name, "hw:%d", card);
 
406
/*??*/      if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0) {
 
407
                  fprintf(stderr, "ALSA: control open (%d): %s\n",
 
408
                     card, snd_strerror(err));
 
409
                  continue;
 
410
                  }
 
411
 
 
412
            if ((err = snd_ctl_card_info(handle, info)) < 0) {
 
413
                  fprintf(stderr, "ALSA: control hardware info %d: %s\n",
 
414
                     card, snd_strerror(err));
 
415
                  snd_ctl_close(handle);
 
416
                  continue;
 
417
                  }
 
418
            int dev = -1;
 
419
            for (;;) {
 
420
                  if (snd_ctl_pcm_next_device(handle, &dev) < 0)
 
421
                        fprintf(stderr, "ALSA: pcm next device: %s\n",
 
422
                           snd_strerror(err));
 
423
                  if (dev < 0)
 
424
                        break;
 
425
                  int flags = 0;
 
426
                  snd_pcm_info_set_device(pcminfo, dev);
 
427
                  snd_pcm_info_set_subdevice(pcminfo, 0);
 
428
                  snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
 
429
                  if (snd_ctl_pcm_info(handle, pcminfo) >= 0)
 
430
                        flags |= 1;
 
431
                  snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
 
432
                  if (snd_ctl_pcm_info(handle, pcminfo) >= 0)
 
433
                        flags |= 2;
 
434
                  if (flags) {
 
435
                        const char* name = snd_pcm_info_get_name(pcminfo);
 
436
                        AudioDevice* d = new AlsaAudioDevice (card, dev, flags, QString(name));
 
437
                        audioDevices.add(d);
 
438
                        }
 
439
                  }
 
440
            snd_ctl_close(handle);
 
441
            if (snd_card_next(&card) < 0) {
 
442
                  fprintf(stderr, "ALSA: snd_card_next: %s\n",
 
443
                     snd_strerror(err));
 
444
                  break;
 
445
                  }
 
446
            }
 
447
      return false;
 
448
      }
 
449
#endif
 
450
#endif