1
//=========================================================
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
//=========================================================
12
#include <alsa/asoundlib.h>
14
#include <sys/asoundlib.h>
16
#if (SND_LIB_MAJOR==0) && (SND_LIB_MINOR==9)
22
#include <sys/ioctl.h>
28
//---------------------------------------------------------
30
//---------------------------------------------------------
32
class AlsaAudioDevice : public AudioDevice {
35
snd_pcm_t* playbackHandle;
36
snd_pcm_t* captureHandle;
39
AlsaAudioDevice(int c, int d, int f, const QString& s)
47
virtual QString open(int);
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;
57
static int buffer_time = -1;
58
static int avail_min = -1;
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;
65
//---------------------------------------------------------
67
// playback write error handler
68
//---------------------------------------------------------
70
void xrun(snd_pcm_t* handle)
72
snd_pcm_status_t *status;
75
snd_pcm_status_alloca(&status);
76
if ((res = snd_pcm_status(handle, status))<0) {
77
printf("status error: %s", snd_strerror(res));
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);
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));
92
return; // ok, data should be accepted again
95
printf("ALSA xrun: read/write error in state %d\n", state);
99
//---------------------------------------------------------
101
//---------------------------------------------------------
103
static void setParams(snd_pcm_t* handle)
105
//-----------------------------------------------
108
snd_pcm_hw_params_t* hwparams;
109
snd_pcm_hw_params_alloca(&hwparams);
110
int err = snd_pcm_hw_params_any(handle, hwparams);
112
printf("Broken configuration for this PCM: no configurations available");
116
err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
118
printf("ALSA: Access type not available");
122
err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
124
printf("ALSA: Sample format non available");
127
err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
129
printf("ALSA: Channels count non available");
133
snd_pcm_hw_params_set_rate_near(handle, hwparams, sampleRate, 0);
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);
142
err = snd_pcm_hw_params(handle, hwparams);
144
printf("Unable to install hw params:");
147
chunk_size = snd_pcm_hw_params_get_period_size(hwparams, 0);
148
int buffer_size = snd_pcm_hw_params_get_buffer_size(hwparams);
150
// printf("segment %d chunk %d, buffer %d\n", segmentSize, chunk_size, buffer_size);
152
if (chunk_size == int(buffer_size)) {
153
printf("Can't use period equal to buffer size (%u == %u)", chunk_size, buffer_size);
157
//-----------------------------------------------
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);
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:");
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;
181
// printf("bits/frame %d, real chunk_size = %i buffer %d, chunk %d\n",
182
// bits_per_frame, chunk_size, buffer_size, chunk_size);
185
//---------------------------------------------------------
187
//---------------------------------------------------------
189
QString AlsaAudioDevice::open(int rw)
191
int openFlags = SND_PCM_NONBLOCK;
193
//---------------------------------------------------
194
// setup playback stream
195
//---------------------------------------------------
198
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
199
int err = snd_pcm_open(&playbackHandle, "default", stream, openFlags);
201
return QString("Alsa open: ")+QString(snd_strerror(err));
202
setParams(playbackHandle);
203
int res = snd_pcm_prepare(playbackHandle);
205
printf("prepare error: %s", snd_strerror(res));
210
snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
211
int err = snd_pcm_open(&captureHandle, "default", stream, openFlags);
213
return QString("Alsa open: ")+QString(snd_strerror(err));
214
setParams(captureHandle);
216
return QString("OK");
219
//---------------------------------------------------------
221
//---------------------------------------------------------
223
int AlsaAudioDevice::read(unsigned char* buffer, int frames)
225
if (captureHandle == 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)
235
fprintf(stderr, "AlsaAudioDevice: read(0x%x, 0x%x, %d+%d) failed: %s\n",
236
unsigned(captureHandle), unsigned(buffer), frames, n, snd_strerror(rv));
242
buffer += rv * bits_per_frame / 8;
248
//---------------------------------------------------------
250
//---------------------------------------------------------
252
void AlsaAudioDevice::start() const
257
err = snd_pcm_start(captureHandle);
259
xrun(playbackHandle);
261
printf("Alsa capture go: %s\n", snd_strerror(err));
263
if (playbackHandle) {
264
int err = snd_pcm_start(playbackHandle);
266
xrun(playbackHandle);
268
printf("Alsa playback go: %s\n", snd_strerror(err));
274
//---------------------------------------------------------
276
//---------------------------------------------------------
278
void AlsaAudioDevice::stop() const
281
int err = snd_pcm_pause(captureHandle, 1);
283
printf("Alsa capture pause: %s\n", snd_strerror(err));
285
if (playbackHandle) {
286
int err = snd_pcm_pause(playbackHandle, 1);
288
printf("Alsa playback pause: %s\n", snd_strerror(err));
292
//---------------------------------------------------------
294
//---------------------------------------------------------
296
int AlsaAudioDevice::write(const unsigned char* buffer, int n)
298
if (playbackHandle == 0)
301
int framesize = bits_per_frame/8;
303
int r = snd_pcm_writei(playbackHandle, buffer, n);
305
snd_pcm_wait(playbackHandle, 1000);
308
else if (r == -EPIPE) {
309
xrun(playbackHandle);
313
fprintf(stderr, "AlsaAudioDevice: write(0x%x, 0x%x, %d) failed: %s\n",
314
unsigned(playbackHandle), unsigned(buffer), n, snd_strerror(r));
318
buffer += r * framesize;
321
snd_pcm_wait(playbackHandle, 1000);
326
//---------------------------------------------------------
328
//---------------------------------------------------------
330
int AlsaAudioDevice::selectwfd() const
332
if (playbackHandle) {
333
int n = snd_pcm_poll_descriptors_count(playbackHandle);
335
printf("AlsaAudioDevice:selectwfd: not supported\n");
339
snd_pcm_poll_descriptors(playbackHandle, fd, n);
345
//---------------------------------------------------------
347
//---------------------------------------------------------
349
int AlsaAudioDevice::selectrfd() const
352
int n = snd_pcm_poll_descriptors_count(captureHandle);
354
printf("AlsaAudioDevice:selectrfd: not supported\n");
358
snd_pcm_poll_descriptors(captureHandle, fd, n);
364
//---------------------------------------------------------
366
//---------------------------------------------------------
368
void AlsaAudioDevice::close()
371
int err = snd_pcm_close(captureHandle);
373
printf("Alsa close capture: %s\n", snd_strerror(err));
375
if (playbackHandle) {
376
int err = snd_pcm_close(playbackHandle);
378
printf("Alsa close playback: %s\n", snd_strerror(err));
384
//---------------------------------------------------------
386
// collect infos about audio devices
387
// return true if no soundcard found
388
//---------------------------------------------------------
394
if (snd_card_next(&card) < 0 || card < 0) {
395
fprintf(stderr, "ALSA: no soundcard found\n");
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);
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));
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);
420
if (snd_ctl_pcm_next_device(handle, &dev) < 0)
421
fprintf(stderr, "ALSA: pcm next device: %s\n",
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)
431
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
432
if (snd_ctl_pcm_info(handle, pcminfo) >= 0)
435
const char* name = snd_pcm_info_get_name(pcminfo);
436
AudioDevice* d = new AlsaAudioDevice (card, dev, flags, QString(name));
440
snd_ctl_close(handle);
441
if (snd_card_next(&card) < 0) {
442
fprintf(stderr, "ALSA: snd_card_next: %s\n",