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 (550 loc) · 18.1 KB

SDL_alsa_audio.c

File metadata and controls

622 lines (550 loc) · 18.1 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
45
/* Audio driver functions */
Jul 10, 2006
Jul 10, 2006
46
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec);
Apr 15, 2002
Apr 15, 2002
47
48
49
50
51
static void ALSA_WaitAudio(_THIS);
static void ALSA_PlayAudio(_THIS);
static Uint8 *ALSA_GetAudioBuf(_THIS);
static void ALSA_CloseAudio(_THIS);
Oct 6, 2006
Oct 6, 2006
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
85
86
87
88
89
90
91
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
92
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
Mar 2, 2004
Mar 2, 2004
93
Feb 16, 2006
Feb 16, 2006
94
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
Mar 2, 2004
Mar 2, 2004
95
96
static void *alsa_handle = NULL;
Oct 6, 2006
Oct 6, 2006
97
98
static int
load_alsa_sym(const char *fn, void **addr)
Jul 10, 2006
Jul 10, 2006
99
{
Oct 6, 2006
Oct 6, 2006
100
101
102
103
#if HAVE_DLVSYM
*addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
if (*addr == NULL)
#endif
Jul 10, 2006
Jul 10, 2006
104
{
Oct 6, 2006
Oct 6, 2006
105
106
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
*addr = dlsym(alsa_handle, fn);
if (*addr == NULL) {
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;
}
Jul 10, 2006
Jul 10, 2006
150
151
152
153
static void
UnloadALSALibrary(void)
{
Oct 6, 2006
Oct 6, 2006
154
if (alsa_handle != NULL) {
Jul 10, 2006
Jul 10, 2006
155
156
157
dlclose(alsa_handle);
alsa_handle = NULL;
}
Mar 2, 2004
Mar 2, 2004
158
159
}
Jul 10, 2006
Jul 10, 2006
160
161
162
163
static int
LoadALSALibrary(void)
{
int i, retval = -1;
Mar 2, 2004
Mar 2, 2004
164
Jul 10, 2006
Jul 10, 2006
165
alsa_handle = dlopen(alsa_library, RTLD_NOW);
Oct 6, 2006
Oct 6, 2006
166
167
168
169
170
171
172
if (alsa_handle == NULL) {
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
173
174
175
}
}
return retval;
Mar 2, 2004
Mar 2, 2004
176
177
178
179
}
#else
Jul 10, 2006
Jul 10, 2006
180
181
182
183
static void
UnloadALSALibrary(void)
{
return;
Mar 2, 2004
Mar 2, 2004
184
185
}
Jul 10, 2006
Jul 10, 2006
186
187
188
static int
LoadALSALibrary(void)
{
Oct 6, 2006
Oct 6, 2006
189
load_alsa_syms();
Jul 10, 2006
Jul 10, 2006
190
return 0;
Mar 2, 2004
Mar 2, 2004
191
192
}
Feb 16, 2006
Feb 16, 2006
193
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
Mar 2, 2004
Mar 2, 2004
194
Jul 10, 2006
Jul 10, 2006
195
196
static const char *
get_audio_device(int channels)
Apr 26, 2001
Apr 26, 2001
197
{
Jul 10, 2006
Jul 10, 2006
198
199
200
201
202
203
204
205
206
207
208
209
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
210
211
212
213
}
/* Audio driver bootstrap functions */
Jul 10, 2006
Jul 10, 2006
214
215
static int
Audio_Available(void)
Apr 26, 2001
Apr 26, 2001
216
{
Jul 10, 2006
Jul 10, 2006
217
218
219
220
221
222
223
224
int available;
int status;
snd_pcm_t *handle;
available = 0;
if (LoadALSALibrary() < 0) {
return available;
}
Oct 6, 2006
Oct 6, 2006
225
226
status = ALSA_snd_pcm_open(&handle, get_audio_device(2),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Jul 10, 2006
Jul 10, 2006
227
228
if (status >= 0) {
available = 1;
Oct 6, 2006
Oct 6, 2006
229
ALSA_snd_pcm_close(handle);
Jul 10, 2006
Jul 10, 2006
230
231
232
}
UnloadALSALibrary();
return (available);
Apr 26, 2001
Apr 26, 2001
233
234
}
Jul 10, 2006
Jul 10, 2006
235
236
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
Apr 26, 2001
Apr 26, 2001
237
{
Jul 10, 2006
Jul 10, 2006
238
239
240
SDL_free(device->hidden);
SDL_free(device);
UnloadALSALibrary();
Apr 26, 2001
Apr 26, 2001
241
242
}
Jul 10, 2006
Jul 10, 2006
243
244
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
Apr 26, 2001
Apr 26, 2001
245
{
Jul 10, 2006
Jul 10, 2006
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadALSALibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
Apr 26, 2001
Apr 26, 2001
275
276
277
}
AudioBootStrap ALSA_bootstrap = {
Jul 10, 2006
Jul 10, 2006
278
DRIVER_NAME, "ALSA 0.9 PCM audio",
Oct 4, 2006
Oct 4, 2006
279
Audio_Available, Audio_CreateDevice, 0
Apr 26, 2001
Apr 26, 2001
280
281
282
};
/* This function waits until it is possible to write a full sound buffer */
Jul 10, 2006
Jul 10, 2006
283
284
static void
ALSA_WaitAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
285
{
Jul 10, 2006
Jul 10, 2006
286
287
288
289
290
291
292
293
294
295
296
297
/* 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.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
this->enabled = 0;
}
}
}
Apr 26, 2001
Apr 26, 2001
298
299
}
Jun 23, 2006
Jun 23, 2006
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/*
* 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) \
T *ptr = (T *) mixbuf; \
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
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
336
337
338
339
340
341
342
343
#undef SWIZ6
/*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
* from Windows/Mac order to the format alsalib will want.
*/
Jul 10, 2006
Jul 10, 2006
344
345
static __inline__ void
swizzle_alsa_channels(_THIS)
Jun 23, 2006
Jun 23, 2006
346
347
{
if (this->spec.channels == 6) {
Jul 10, 2006
Jul 10, 2006
348
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
Jun 23, 2006
Jun 23, 2006
349
350
351
352
353
354
355
356
357
358
359
360
361
362
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
363
364
static void
ALSA_PlayAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
365
{
Jul 10, 2006
Jul 10, 2006
366
367
368
369
370
371
372
373
374
375
int status;
int sample_len;
signed short *sample_buf;
swizzle_alsa_channels(this);
sample_len = this->spec.samples;
sample_buf = (signed short *) mixbuf;
while (sample_len > 0) {
Oct 6, 2006
Oct 6, 2006
376
status = ALSA_snd_pcm_writei(pcm_handle, sample_buf, sample_len);
Jul 10, 2006
Jul 10, 2006
377
378
379
380
381
382
383
384
if (status < 0) {
if (status == -EAGAIN) {
SDL_Delay(1);
continue;
}
if (status == -ESTRPIPE) {
do {
SDL_Delay(1);
Oct 6, 2006
Oct 6, 2006
385
status = ALSA_snd_pcm_resume(pcm_handle);
Jul 10, 2006
Jul 10, 2006
386
387
388
} while (status == -EAGAIN);
}
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
389
status = ALSA_snd_pcm_prepare(pcm_handle);
Jul 10, 2006
Jul 10, 2006
390
391
392
393
394
395
396
397
398
399
400
}
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
401
402
}
Jul 10, 2006
Jul 10, 2006
403
404
static Uint8 *
ALSA_GetAudioBuf(_THIS)
Apr 26, 2001
Apr 26, 2001
405
{
Jul 10, 2006
Jul 10, 2006
406
return (mixbuf);
Apr 26, 2001
Apr 26, 2001
407
408
}
Jul 10, 2006
Jul 10, 2006
409
410
static void
ALSA_CloseAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
411
{
Jul 10, 2006
Jul 10, 2006
412
413
414
415
416
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (pcm_handle) {
Oct 6, 2006
Oct 6, 2006
417
418
ALSA_snd_pcm_drain(pcm_handle);
ALSA_snd_pcm_close(pcm_handle);
Jul 10, 2006
Jul 10, 2006
419
420
pcm_handle = NULL;
}
Apr 26, 2001
Apr 26, 2001
421
422
}
Jul 10, 2006
Jul 10, 2006
423
424
static int
ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
Apr 26, 2001
Apr 26, 2001
425
{
Jul 10, 2006
Jul 10, 2006
426
427
428
429
430
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_format_t format;
snd_pcm_uframes_t frames;
Aug 24, 2006
Aug 24, 2006
431
SDL_AudioFormat test_format;
Jul 10, 2006
Jul 10, 2006
432
433
434
/* Open the audio device */
/* Name of device should depend on # channels in spec */
Oct 6, 2006
Oct 6, 2006
435
436
437
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(spec->channels),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Jul 10, 2006
Jul 10, 2006
438
439
440
if (status < 0) {
SDL_SetError("Couldn't open audio device: %s",
Oct 6, 2006
Oct 6, 2006
441
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
442
443
444
445
446
return (-1);
}
/* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams);
Oct 6, 2006
Oct 6, 2006
447
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
Jul 10, 2006
Jul 10, 2006
448
449
if (status < 0) {
SDL_SetError("Couldn't get hardware config: %s",
Oct 6, 2006
Oct 6, 2006
450
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
451
452
453
454
455
ALSA_CloseAudio(this);
return (-1);
}
/* SDL only uses interleaved sample output */
Oct 6, 2006
Oct 6, 2006
456
457
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
Jul 10, 2006
Jul 10, 2006
458
459
if (status < 0) {
SDL_SetError("Couldn't set interleaved access: %s",
Oct 6, 2006
Oct 6, 2006
460
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
461
462
463
464
465
466
467
468
ALSA_CloseAudio(this);
return (-1);
}
/* Try for a closest match on audio format */
status = -1;
for (test_format = SDL_FirstAudioFormat(spec->format);
test_format && (status < 0);) {
Sep 24, 2006
Sep 24, 2006
469
status = 0; /* if we can't support a format, it'll become -1. */
Jul 10, 2006
Jul 10, 2006
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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
489
case AUDIO_S32LSB:
Sep 1, 2006
Sep 1, 2006
490
format = SND_PCM_FORMAT_S32_LE;
Aug 31, 2006
Aug 31, 2006
491
492
break;
case AUDIO_S32MSB:
Sep 1, 2006
Sep 1, 2006
493
format = SND_PCM_FORMAT_S32_BE;
Aug 31, 2006
Aug 31, 2006
494
495
496
497
498
499
500
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
501
default:
Sep 1, 2006
Sep 1, 2006
502
status = -1;
Jul 10, 2006
Jul 10, 2006
503
504
break;
}
Sep 1, 2006
Sep 1, 2006
505
if (status >= 0) {
Oct 6, 2006
Oct 6, 2006
506
507
status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
hwparams, format);
Jul 10, 2006
Jul 10, 2006
508
509
510
511
512
513
514
515
516
517
518
519
520
}
if (status < 0) {
test_format = SDL_NextAudioFormat();
}
}
if (status < 0) {
SDL_SetError("Couldn't find any hardware audio formats");
ALSA_CloseAudio(this);
return (-1);
}
spec->format = test_format;
/* Set the number of channels */
Oct 6, 2006
Oct 6, 2006
521
522
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
spec->channels);
Jul 10, 2006
Jul 10, 2006
523
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
524
status = ALSA_snd_pcm_hw_params_get_channels(hwparams);
Jul 10, 2006
Jul 10, 2006
525
526
527
528
529
530
531
532
533
if ((status <= 0) || (status > 2)) {
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return (-1);
}
spec->channels = status;
}
/* Set the audio rate */
Oct 6, 2006
Oct 6, 2006
534
535
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
spec->freq, NULL);
Jul 10, 2006
Jul 10, 2006
536
537
if (status < 0) {
ALSA_CloseAudio(this);
Oct 6, 2006
Oct 6, 2006
538
539
SDL_SetError("Couldn't set audio frequency: %s",
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
540
541
542
543
544
545
return (-1);
}
spec->freq = status;
/* Set the buffer size, in samples */
frames = spec->samples;
Oct 6, 2006
Oct 6, 2006
546
547
frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
frames, NULL);
Jul 10, 2006
Jul 10, 2006
548
spec->samples = frames;
Oct 6, 2006
Oct 6, 2006
549
ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);
Jul 10, 2006
Jul 10, 2006
550
551
/* "set" the hardware with the desired parameters */
Oct 6, 2006
Oct 6, 2006
552
status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
Jul 10, 2006
Jul 10, 2006
553
554
if (status < 0) {
ALSA_CloseAudio(this);
Oct 6, 2006
Oct 6, 2006
555
556
SDL_SetError("Couldn't set hardware audio parameters: %s",
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
557
558
return (-1);
}
Mar 19, 2006
Mar 19, 2006
559
Mar 19, 2006
Mar 19, 2006
560
/* This is useful for debugging... */
Mar 19, 2006
Mar 19, 2006
561
/*
Mar 19, 2006
Mar 19, 2006
562
{ snd_pcm_sframes_t bufsize; int fragments;
Oct 6, 2006
Oct 6, 2006
563
564
bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams);
fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams);
Mar 19, 2006
Mar 19, 2006
565
566
567
568
569
fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
}
*/
Jul 10, 2006
Jul 10, 2006
570
571
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
Oct 6, 2006
Oct 6, 2006
572
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
Jul 10, 2006
Jul 10, 2006
573
574
if (status < 0) {
SDL_SetError("Couldn't get software config: %s",
Oct 6, 2006
Oct 6, 2006
575
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
576
577
578
ALSA_CloseAudio(this);
return (-1);
}
Oct 6, 2006
Oct 6, 2006
579
status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0);
Jul 10, 2006
Jul 10, 2006
580
581
if (status < 0) {
SDL_SetError("Couldn't set start threshold: %s",
Oct 6, 2006
Oct 6, 2006
582
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
583
584
585
ALSA_CloseAudio(this);
return (-1);
}
Oct 6, 2006
Oct 6, 2006
586
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
Jul 10, 2006
Jul 10, 2006
587
if (status < 0) {
Oct 6, 2006
Oct 6, 2006
588
SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
589
590
591
ALSA_CloseAudio(this);
return (-1);
}
Oct 6, 2006
Oct 6, 2006
592
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
Jul 10, 2006
Jul 10, 2006
593
594
if (status < 0) {
SDL_SetError("Couldn't set software audio parameters: %s",
Oct 6, 2006
Oct 6, 2006
595
ALSA_snd_strerror(status));
Jul 10, 2006
Jul 10, 2006
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
ALSA_CloseAudio(this);
return (-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
ALSA_CloseAudio(this);
return (-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* Switch to blocking mode for playback */
Oct 6, 2006
Oct 6, 2006
616
ALSA_snd_pcm_nonblock(pcm_handle, 0);
Jul 10, 2006
Jul 10, 2006
617
618
619
/* We're ready to rock and roll. :-) */
return (0);
Apr 26, 2001
Apr 26, 2001
620
}
Jul 10, 2006
Jul 10, 2006
621
622
/* vi: set ts=4 sw=4 expandtab: */