Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
622 lines (547 loc) · 18.6 KB

SDL_alsa_audio.c

File metadata and controls

622 lines (547 loc) · 18.6 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Jan 4, 2004
Jan 4, 2004
3
Copyright (C) 1997-2004 Sam Lantinga
Apr 26, 2001
Apr 26, 2001
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Apr 26, 2001
Apr 26, 2001
21
*/
Feb 21, 2006
Feb 21, 2006
22
#include "SDL_config.h"
Apr 26, 2001
Apr 26, 2001
23
24
25
26
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
Jul 10, 2006
Jul 10, 2006
27
#include <signal.h> /* For kill() */
Oct 6, 2006
Oct 6, 2006
28
29
30
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
Apr 26, 2001
Apr 26, 2001
31
32
#include "SDL_timer.h"
Feb 16, 2006
Feb 16, 2006
33
34
35
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
Apr 26, 2001
Apr 26, 2001
36
37
#include "SDL_alsa_audio.h"
Mar 2, 2004
Mar 2, 2004
38
Apr 26, 2001
Apr 26, 2001
39
40
41
/* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa"
Apr 15, 2002
Apr 15, 2002
42
/* The default ALSA audio driver */
Jan 4, 2004
Jan 4, 2004
43
#define DEFAULT_DEVICE "default"
Apr 26, 2001
Apr 26, 2001
44
Oct 6, 2006
Oct 6, 2006
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
static int (*ALSA_snd_pcm_open)
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm);
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
(snd_pcm_t *,const void *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_resume)(snd_pcm_t *);
static int (*ALSA_snd_pcm_prepare)(snd_pcm_t *);
static int (*ALSA_snd_pcm_drain)(snd_pcm_t *);
static const char *(*ALSA_snd_strerror)(int);
static size_t(*ALSA_snd_pcm_hw_params_sizeof)(void);
static size_t(*ALSA_snd_pcm_sw_params_sizeof)(void);
static int (*ALSA_snd_pcm_hw_params_any)(snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params_set_access)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
static int (*ALSA_snd_pcm_hw_params_set_format)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
static int (*ALSA_snd_pcm_hw_params_set_channels)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
static int (*ALSA_snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *);
static unsigned int (*ALSA_snd_pcm_hw_params_set_rate_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *);
static snd_pcm_uframes_t (*ALSA_snd_pcm_hw_params_set_period_size_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t, int *);
static snd_pcm_sframes_t (*ALSA_snd_pcm_hw_params_get_period_size)
(const snd_pcm_hw_params_t *);
static unsigned int (*ALSA_snd_pcm_hw_params_set_periods_near)
(snd_pcm_t *,snd_pcm_hw_params_t *, unsigned int, int *);
static int (*ALSA_snd_pcm_hw_params_get_periods)(snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_sw_params_current)(snd_pcm_t*, snd_pcm_sw_params_t*);
static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_sw_params)(snd_pcm_t *, snd_pcm_sw_params_t *);
static int (*ALSA_snd_pcm_nonblock)(snd_pcm_t *, int);
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
#define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
Feb 16, 2006
Feb 16, 2006
85
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
Mar 2, 2004
Mar 2, 2004
86
Feb 16, 2006
Feb 16, 2006
87
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
Mar 2, 2004
Mar 2, 2004
88
89
static void *alsa_handle = NULL;
Oct 6, 2006
Oct 6, 2006
90
91
static int
load_alsa_sym(const char *fn, void **addr)
Jul 10, 2006
Jul 10, 2006
92
{
Oct 7, 2006
Oct 7, 2006
93
94
95
96
97
98
/*
* !!! FIXME:
* Eventually, this will deal with fallbacks, version changes, and
* missing symbols we can workaround. But for now, it doesn't.
*/
Oct 6, 2006
Oct 6, 2006
99
100
101
102
#if HAVE_DLVSYM
*addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
if (*addr == NULL)
#endif
Jul 10, 2006
Jul 10, 2006
103
{
Oct 6, 2006
Oct 6, 2006
104
105
*addr = dlsym(alsa_handle, fn);
if (*addr == NULL) {
Oct 7, 2006
Oct 7, 2006
106
SDL_SetError("dlsym('%s') failed: %s", fn, strerror(errno));
Oct 6, 2006
Oct 6, 2006
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
return 0;
}
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_ALSA_SYM(x) \
if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
#else
#define SDL_ALSA_SYM(x) ALSA_##x = x
#endif
static int load_alsa_syms(void)
{
SDL_ALSA_SYM(snd_pcm_open);
SDL_ALSA_SYM(snd_pcm_close);
SDL_ALSA_SYM(snd_pcm_writei);
SDL_ALSA_SYM(snd_pcm_resume);
SDL_ALSA_SYM(snd_pcm_prepare);
SDL_ALSA_SYM(snd_pcm_drain);
SDL_ALSA_SYM(snd_strerror);
SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_hw_params_any);
SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
SDL_ALSA_SYM(snd_pcm_hw_params);
SDL_ALSA_SYM(snd_pcm_sw_params_current);
SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
SDL_ALSA_SYM(snd_pcm_sw_params);
SDL_ALSA_SYM(snd_pcm_nonblock);
return 0;
}
Oct 7, 2006
Oct 7, 2006
150
#undef SDL_ALSA_SYM
Jul 10, 2006
Jul 10, 2006
151
Oct 6, 2006
Oct 6, 2006
152
153
154
155
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static int library_load_count = 0;
Jul 10, 2006
Jul 10, 2006
156
157
158
static void
UnloadALSALibrary(void)
{
Oct 6, 2006
Oct 6, 2006
159
if ((alsa_handle != NULL) && (--library_load_count == 0)) {
Jul 10, 2006
Jul 10, 2006
160
161
162
dlclose(alsa_handle);
alsa_handle = NULL;
}
Mar 2, 2004
Mar 2, 2004
163
164
}
Jul 10, 2006
Jul 10, 2006
165
166
167
static int
LoadALSALibrary(void)
{
Oct 6, 2006
Oct 6, 2006
168
169
170
171
172
173
174
175
176
177
178
179
180
int retval = 0;
if (library_load_count++ == 0) {
alsa_handle = dlopen(alsa_library, RTLD_NOW);
if (alsa_handle == NULL) {
library_load_count--;
retval = -1;
SDL_SetError("ALSA: dlopen('%s') failed: %s\n",
alsa_library, strerror(errno));
} else {
retval = load_alsa_syms();
if (retval < 0) {
UnloadALSALibrary();
}
Jul 10, 2006
Jul 10, 2006
181
182
183
}
}
return retval;
Mar 2, 2004
Mar 2, 2004
184
185
186
187
}
#else
Jul 10, 2006
Jul 10, 2006
188
189
190
static void
UnloadALSALibrary(void)
{
Mar 2, 2004
Mar 2, 2004
191
192
}
Jul 10, 2006
Jul 10, 2006
193
194
195
static int
LoadALSALibrary(void)
{
Oct 6, 2006
Oct 6, 2006
196
load_alsa_syms();
Jul 10, 2006
Jul 10, 2006
197
return 0;
Mar 2, 2004
Mar 2, 2004
198
199
}
Feb 16, 2006
Feb 16, 2006
200
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
Mar 2, 2004
Mar 2, 2004
201
Jul 10, 2006
Jul 10, 2006
202
203
static const char *
get_audio_device(int channels)
Apr 26, 2001
Apr 26, 2001
204
{
Jul 10, 2006
Jul 10, 2006
205
206
207
208
209
210
211
212
213
214
215
216
const char *device;
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if (device == NULL) {
if (channels == 6)
device = "surround51";
else if (channels == 4)
device = "surround40";
else
device = DEFAULT_DEVICE;
}
return device;
Apr 26, 2001
Apr 26, 2001
217
218
219
}
Jul 10, 2006
Jul 10, 2006
220
static int
Oct 6, 2006
Oct 6, 2006
221
ALSA_Available(void)
Apr 26, 2001
Apr 26, 2001
222
{
Oct 6, 2006
Oct 6, 2006
223
int available = 0;
Jul 10, 2006
Jul 10, 2006
224
Oct 6, 2006
Oct 6, 2006
225
if (LoadALSALibrary() >= 0) {
Oct 17, 2006
Oct 17, 2006
226
available = 1;
Oct 6, 2006
Oct 6, 2006
227
UnloadALSALibrary();
Jul 10, 2006
Jul 10, 2006
228
229
}
return (available);
Apr 26, 2001
Apr 26, 2001
230
231
}
Jul 10, 2006
Jul 10, 2006
232
Apr 26, 2001
Apr 26, 2001
233
234
/* This function waits until it is possible to write a full sound buffer */
Jul 10, 2006
Jul 10, 2006
235
static void
Oct 6, 2006
Oct 6, 2006
236
ALSA_WaitDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
237
{
Jul 10, 2006
Jul 10, 2006
238
239
240
241
242
243
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
Oct 6, 2006
Oct 6, 2006
244
245
246
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
Jul 10, 2006
Jul 10, 2006
247
248
249
250
this->enabled = 0;
}
}
}
Apr 26, 2001
Apr 26, 2001
251
252
}
Jun 23, 2006
Jun 23, 2006
253
Oct 6, 2006
Oct 6, 2006
254
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
Jun 23, 2006
Jun 23, 2006
255
256
257
258
259
260
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T) \
Oct 6, 2006
Oct 6, 2006
261
T *ptr = (T *) this->hidden->mixbuf; \
Jun 23, 2006
Jun 23, 2006
262
263
264
265
266
267
268
269
const Uint32 count = (this->spec.samples / 6); \
Uint32 i; \
for (i = 0; i < count; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
Jul 10, 2006
Jul 10, 2006
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
static __inline__ void
swizzle_alsa_channels_6_64bit(_THIS)
{
SWIZ6(Uint64);
}
static __inline__ void
swizzle_alsa_channels_6_32bit(_THIS)
{
SWIZ6(Uint32);
}
static __inline__ void
swizzle_alsa_channels_6_16bit(_THIS)
{
SWIZ6(Uint16);
}
static __inline__ void
swizzle_alsa_channels_6_8bit(_THIS)
{
SWIZ6(Uint8);
}
Jun 23, 2006
Jun 23, 2006
290
291
292
293
294
#undef SWIZ6
/*
Oct 6, 2006
Oct 6, 2006
295
296
* Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
* channels from Windows/Mac order to the format alsalib will want.
Jun 23, 2006
Jun 23, 2006
297
*/
Jul 10, 2006
Jul 10, 2006
298
299
static __inline__ void
swizzle_alsa_channels(_THIS)
Jun 23, 2006
Jun 23, 2006
300
301
{
if (this->spec.channels == 6) {
Jul 10, 2006
Jul 10, 2006
302
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
Jun 23, 2006
Jun 23, 2006
303
304
305
306
307
308
309
310
311
312
313
314
315
316
if (fmtsize == 16)
swizzle_alsa_channels_6_16bit(this);
else if (fmtsize == 8)
swizzle_alsa_channels_6_8bit(this);
else if (fmtsize == 32)
swizzle_alsa_channels_6_32bit(this);
else if (fmtsize == 64)
swizzle_alsa_channels_6_64bit(this);
}
/* !!! FIXME: update this for 7.1 if needed, later. */
}
Jul 10, 2006
Jul 10, 2006
317
static void
Oct 6, 2006
Oct 6, 2006
318
ALSA_PlayDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
319
{
Jul 10, 2006
Jul 10, 2006
320
321
322
323
324
325
326
int status;
int sample_len;
signed short *sample_buf;
swizzle_alsa_channels(this);
sample_len = this->spec.samples;
Oct 6, 2006
Oct 6, 2006
327
sample_buf = (signed short *) this->hidden->mixbuf;
Jul 10, 2006
Jul 10, 2006
328
329
while (sample_len > 0) {
Oct 6, 2006
Oct 6, 2006
330
331
332
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
sample_buf, sample_len);
Jul 10, 2006
Jul 10, 2006
333
334
335
336
337
338
339
340
if (status < 0) {
if (status == -EAGAIN) {
SDL_Delay(1);
continue;
}
if (status == -ESTRPIPE) {
do {
SDL_Delay(1);
Oct 6, 2006
Oct 6, 2006
341
status = ALSA_snd_pcm_resume(this->hidden->pcm_handle);
Jul 10, 2006
Jul 10, 2006
342
343
344
} while (status == -EAGAIN);
}
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
345
status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle);
Jul 10, 2006
Jul 10, 2006
346
347
348
349
350
351
352
353
354
355
356
}
if (status < 0) {
/* Hmm, not much we can do - abort */
this->enabled = 0;
return;
}
continue;
}
sample_buf += status * this->spec.channels;
sample_len -= status;
}
Apr 26, 2001
Apr 26, 2001
357
358
}
Jul 10, 2006
Jul 10, 2006
359
static Uint8 *
Oct 6, 2006
Oct 6, 2006
360
ALSA_GetDeviceBuf(_THIS)
Apr 26, 2001
Apr 26, 2001
361
{
Oct 6, 2006
Oct 6, 2006
362
return (this->hidden->mixbuf);
Apr 26, 2001
Apr 26, 2001
363
364
}
Jul 10, 2006
Jul 10, 2006
365
static void
Oct 6, 2006
Oct 6, 2006
366
ALSA_CloseDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
367
{
Oct 6, 2006
Oct 6, 2006
368
369
370
371
372
373
374
375
376
377
378
379
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->pcm_handle) {
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
ALSA_snd_pcm_close(this->hidden->pcm_handle);
this->hidden->pcm_handle = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
Oct 7, 2006
Oct 7, 2006
380
UnloadALSALibrary();
Jul 10, 2006
Jul 10, 2006
381
}
Apr 26, 2001
Apr 26, 2001
382
383
}
Jul 10, 2006
Jul 10, 2006
384
static int
Oct 6, 2006
Oct 6, 2006
385
ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
Apr 26, 2001
Apr 26, 2001
386
{
Oct 6, 2006
Oct 6, 2006
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
int status = 0;
snd_pcm_t *pcm_handle = NULL;
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_format_t format = 0;
snd_pcm_uframes_t frames = 0;
SDL_AudioFormat test_format = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
Jul 10, 2006
Jul 10, 2006
403
Oct 7, 2006
Oct 7, 2006
404
405
406
407
408
if (LoadALSALibrary() < 0) {
ALSA_CloseDevice(this);
return 0;
}
Jul 10, 2006
Jul 10, 2006
409
410
/* Open the audio device */
/* Name of device should depend on # channels in spec */
Oct 6, 2006
Oct 6, 2006
411
status = ALSA_snd_pcm_open(&pcm_handle,
Oct 6, 2006
Oct 6, 2006
412
get_audio_device(this->spec.channels),
Oct 6, 2006
Oct 6, 2006
413
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Jul 10, 2006
Jul 10, 2006
414
415
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
416
417
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't open audio device: %s",
Oct 6, 2006
Oct 6, 2006
418
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
419
return 0;
Jul 10, 2006
Jul 10, 2006
420
421
}
Oct 6, 2006
Oct 6, 2006
422
423
this->hidden->pcm_handle = pcm_handle;
Jul 10, 2006
Jul 10, 2006
424
425
/* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams);
Oct 6, 2006
Oct 6, 2006
426
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
Jul 10, 2006
Jul 10, 2006
427
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
428
429
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't get hardware config: %s",
Oct 6, 2006
Oct 6, 2006
430
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
431
return 0;
Jul 10, 2006
Jul 10, 2006
432
433
434
}
/* SDL only uses interleaved sample output */
Oct 6, 2006
Oct 6, 2006
435
436
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
Jul 10, 2006
Jul 10, 2006
437
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
438
439
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set interleaved access: %s",
Oct 6, 2006
Oct 6, 2006
440
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
441
return 0;
Jul 10, 2006
Jul 10, 2006
442
443
444
445
}
/* Try for a closest match on audio format */
status = -1;
Oct 6, 2006
Oct 6, 2006
446
for (test_format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
447
test_format && (status < 0);) {
Oct 6, 2006
Oct 6, 2006
448
status = 0; /* if we can't support a format, it'll become -1. */
Jul 10, 2006
Jul 10, 2006
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
switch (test_format) {
case AUDIO_U8:
format = SND_PCM_FORMAT_U8;
break;
case AUDIO_S8:
format = SND_PCM_FORMAT_S8;
break;
case AUDIO_S16LSB:
format = SND_PCM_FORMAT_S16_LE;
break;
case AUDIO_S16MSB:
format = SND_PCM_FORMAT_S16_BE;
break;
case AUDIO_U16LSB:
format = SND_PCM_FORMAT_U16_LE;
break;
case AUDIO_U16MSB:
format = SND_PCM_FORMAT_U16_BE;
break;
Aug 31, 2006
Aug 31, 2006
468
case AUDIO_S32LSB:
Sep 1, 2006
Sep 1, 2006
469
format = SND_PCM_FORMAT_S32_LE;
Aug 31, 2006
Aug 31, 2006
470
471
break;
case AUDIO_S32MSB:
Sep 1, 2006
Sep 1, 2006
472
format = SND_PCM_FORMAT_S32_BE;
Aug 31, 2006
Aug 31, 2006
473
474
475
476
477
478
479
break;
case AUDIO_F32LSB:
format = SND_PCM_FORMAT_FLOAT_LE;
break;
case AUDIO_F32MSB:
format = SND_PCM_FORMAT_FLOAT_BE;
break;
Jul 10, 2006
Jul 10, 2006
480
default:
Sep 1, 2006
Sep 1, 2006
481
status = -1;
Jul 10, 2006
Jul 10, 2006
482
483
break;
}
Sep 1, 2006
Sep 1, 2006
484
if (status >= 0) {
Oct 6, 2006
Oct 6, 2006
485
486
status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
hwparams, format);
Jul 10, 2006
Jul 10, 2006
487
488
489
490
491
492
}
if (status < 0) {
test_format = SDL_NextAudioFormat();
}
}
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
493
494
495
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't find any hardware audio formats");
return 0;
Jul 10, 2006
Jul 10, 2006
496
}
Oct 6, 2006
Oct 6, 2006
497
this->spec.format = test_format;
Jul 10, 2006
Jul 10, 2006
498
499
/* Set the number of channels */
Oct 6, 2006
Oct 6, 2006
500
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
Oct 6, 2006
Oct 6, 2006
501
this->spec.channels);
Jul 10, 2006
Jul 10, 2006
502
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
503
status = ALSA_snd_pcm_hw_params_get_channels(hwparams);
Jul 10, 2006
Jul 10, 2006
504
if ((status <= 0) || (status > 2)) {
Oct 6, 2006
Oct 6, 2006
505
506
507
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set audio channels");
return 0;
Jul 10, 2006
Jul 10, 2006
508
}
Oct 6, 2006
Oct 6, 2006
509
this->spec.channels = status;
Jul 10, 2006
Jul 10, 2006
510
511
512
}
/* Set the audio rate */
Oct 6, 2006
Oct 6, 2006
513
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
Oct 6, 2006
Oct 6, 2006
514
this->spec.freq, NULL);
Jul 10, 2006
Jul 10, 2006
515
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
516
517
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set audio frequency: %s",
Oct 6, 2006
Oct 6, 2006
518
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
519
return 0;
Jul 10, 2006
Jul 10, 2006
520
}
Oct 6, 2006
Oct 6, 2006
521
this->spec.freq = status;
Jul 10, 2006
Jul 10, 2006
522
523
/* Set the buffer size, in samples */
Oct 6, 2006
Oct 6, 2006
524
frames = this->spec.samples;
Oct 6, 2006
Oct 6, 2006
525
526
frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
frames, NULL);
Oct 6, 2006
Oct 6, 2006
527
this->spec.samples = frames;
Oct 6, 2006
Oct 6, 2006
528
ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);
Jul 10, 2006
Jul 10, 2006
529
530
/* "set" the hardware with the desired parameters */
Oct 6, 2006
Oct 6, 2006
531
status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
Jul 10, 2006
Jul 10, 2006
532
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
533
534
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s",
Oct 6, 2006
Oct 6, 2006
535
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
536
return 0;
Jul 10, 2006
Jul 10, 2006
537
}
Mar 19, 2006
Mar 19, 2006
538
Oct 6, 2006
Oct 6, 2006
539
540
541
542
543
544
545
#if AUDIO_DEBUG
{
snd_pcm_sframes_t bufsize;
int fragments;
bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams);
fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams);
fprintf(stderr,"ALSA: bufsize = %ld, fragments = %d\n",bufsize,fragments);
Mar 19, 2006
Mar 19, 2006
546
}
Oct 6, 2006
Oct 6, 2006
547
#endif
Mar 19, 2006
Mar 19, 2006
548
Jul 10, 2006
Jul 10, 2006
549
550
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
Oct 6, 2006
Oct 6, 2006
551
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
Jul 10, 2006
Jul 10, 2006
552
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
553
554
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't get software config: %s",
Oct 6, 2006
Oct 6, 2006
555
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
556
return 0;
Jul 10, 2006
Jul 10, 2006
557
}
Oct 6, 2006
Oct 6, 2006
558
status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0);
Jul 10, 2006
Jul 10, 2006
559
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
560
561
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set start threshold: %s",
Oct 6, 2006
Oct 6, 2006
562
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
563
return 0;
Jul 10, 2006
Jul 10, 2006
564
}
Oct 6, 2006
Oct 6, 2006
565
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
Jul 10, 2006
Jul 10, 2006
566
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
567
ALSA_CloseDevice(this);
Oct 6, 2006
Oct 6, 2006
568
SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
569
return 0;
Jul 10, 2006
Jul 10, 2006
570
}
Oct 6, 2006
Oct 6, 2006
571
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
Jul 10, 2006
Jul 10, 2006
572
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
573
ALSA_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
574
SDL_SetError("Couldn't set software audio parameters: %s",
Oct 6, 2006
Oct 6, 2006
575
ALSA_snd_strerror(status));
Oct 6, 2006
Oct 6, 2006
576
return 0;
Jul 10, 2006
Jul 10, 2006
577
578
579
}
/* Calculate the final parameters for this audio specification */
Oct 6, 2006
Oct 6, 2006
580
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
581
582
/* Allocate mixing buffer */
Oct 6, 2006
Oct 6, 2006
583
584
585
586
587
588
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ALSA_CloseDevice(this);
SDL_OutOfMemory();
return 0;
Jul 10, 2006
Jul 10, 2006
589
}
Oct 6, 2006
Oct 6, 2006
590
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Jul 10, 2006
Jul 10, 2006
591
592
/* Get the parent process id (we're the parent of the audio thread) */
Oct 6, 2006
Oct 6, 2006
593
this->hidden->parent = getpid();
Jul 10, 2006
Jul 10, 2006
594
595
/* Switch to blocking mode for playback */
Oct 6, 2006
Oct 6, 2006
596
ALSA_snd_pcm_nonblock(pcm_handle, 0);
Jul 10, 2006
Jul 10, 2006
597
598
/* We're ready to rock and roll. :-) */
Oct 6, 2006
Oct 6, 2006
599
return 1;
Apr 26, 2001
Apr 26, 2001
600
}
Jul 10, 2006
Jul 10, 2006
601
Oct 6, 2006
Oct 6, 2006
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
static int
ALSA_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
return 1;
}
AudioBootStrap ALSA_bootstrap = {
DRIVER_NAME, "ALSA 0.9 PCM audio",
ALSA_Available, ALSA_Init, 0
};
Jul 10, 2006
Jul 10, 2006
622
/* vi: set ts=4 sw=4 expandtab: */