Skip to content

Latest commit

 

History

History
546 lines (475 loc) · 17.7 KB

SDL_alsa_audio.c

File metadata and controls

546 lines (475 loc) · 17.7 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Dec 8, 2008
Dec 8, 2008
3
Copyright (C) 1997-2009 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>
Feb 7, 2006
Feb 7, 2006
27
#include <signal.h> /* For kill() */
Apr 26, 2001
Apr 26, 2001
28
29
#include "SDL_timer.h"
Feb 16, 2006
Feb 16, 2006
30
31
32
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
Apr 26, 2001
Apr 26, 2001
33
34
#include "SDL_alsa_audio.h"
Feb 16, 2006
Feb 16, 2006
35
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
Mar 2, 2004
Mar 2, 2004
36
37
38
39
40
41
42
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
Apr 26, 2001
Apr 26, 2001
43
44
45
/* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa"
Apr 15, 2002
Apr 15, 2002
46
/* The default ALSA audio driver */
Jan 4, 2004
Jan 4, 2004
47
#define DEFAULT_DEVICE "default"
Apr 26, 2001
Apr 26, 2001
48
49
/* Audio driver functions */
Apr 15, 2002
Apr 15, 2002
50
51
52
53
54
55
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void ALSA_WaitAudio(_THIS);
static void ALSA_PlayAudio(_THIS);
static Uint8 *ALSA_GetAudioBuf(_THIS);
static void ALSA_CloseAudio(_THIS);
Feb 16, 2006
Feb 16, 2006
56
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
Mar 2, 2004
Mar 2, 2004
57
Feb 16, 2006
Feb 16, 2006
58
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
Mar 2, 2004
Mar 2, 2004
59
60
61
62
63
64
65
66
67
68
69
static void *alsa_handle = NULL;
static int alsa_loaded = 0;
static int (*SDL_NAME(snd_pcm_open))(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
static int (*SDL_NAME(snd_pcm_close))(snd_pcm_t *pcm);
static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_writei))(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
static int (*SDL_NAME(snd_pcm_resume))(snd_pcm_t *pcm);
static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm);
static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm);
static const char *(*SDL_NAME(snd_strerror))(int errnum);
static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
Mar 19, 2006
Mar 19, 2006
70
static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
Mar 2, 2004
Mar 2, 2004
71
72
73
74
static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
Oct 13, 2009
Oct 13, 2009
75
static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val);
Oct 10, 2009
Oct 10, 2009
76
77
static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
Oct 13, 2009
Oct 13, 2009
78
static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir);
Oct 10, 2009
Oct 10, 2009
79
static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
Oct 13, 2009
Oct 13, 2009
80
81
static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
Mar 2, 2004
Mar 2, 2004
82
static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
Mar 19, 2006
Mar 19, 2006
83
84
85
86
87
88
/*
*/
static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
Mar 19, 2006
Mar 19, 2006
89
static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
Mar 2, 2004
Mar 2, 2004
90
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
Mar 19, 2006
Mar 19, 2006
91
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
Mar 2, 2004
Mar 2, 2004
92
Oct 20, 2005
Oct 20, 2005
93
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
Mar 2, 2004
Mar 2, 2004
94
95
96
97
static struct {
const char *name;
void **func;
} alsa_functions[] = {
Oct 20, 2005
Oct 20, 2005
98
99
100
101
102
103
104
105
{ "snd_pcm_open", (void**)(char*)&SDL_NAME(snd_pcm_open) },
{ "snd_pcm_close", (void**)(char*)&SDL_NAME(snd_pcm_close) },
{ "snd_pcm_writei", (void**)(char*)&SDL_NAME(snd_pcm_writei) },
{ "snd_pcm_resume", (void**)(char*)&SDL_NAME(snd_pcm_resume) },
{ "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) },
{ "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) },
{ "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) },
{ "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) },
Mar 19, 2006
Mar 19, 2006
106
{ "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
Oct 20, 2005
Oct 20, 2005
107
108
109
110
111
112
113
{ "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) },
{ "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) },
{ "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) },
{ "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) },
{ "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) },
{ "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
{ "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
Mar 19, 2006
Mar 19, 2006
114
{ "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
Mar 19, 2006
Mar 19, 2006
115
{ "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
Mar 19, 2006
Mar 19, 2006
116
{ "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
Oct 13, 2009
Oct 13, 2009
117
{ "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
Mar 19, 2006
Mar 19, 2006
118
{ "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
Mar 19, 2006
Mar 19, 2006
119
120
121
122
{ "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
{ "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
{ "snd_pcm_sw_params_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) },
{ "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
Mar 19, 2006
Mar 19, 2006
123
{ "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
Mar 2, 2004
Mar 2, 2004
124
125
126
127
};
static void UnloadALSALibrary(void) {
if (alsa_loaded) {
Oct 10, 2009
Oct 10, 2009
128
SDL_UnloadObject(alsa_handle);
Mar 2, 2004
Mar 2, 2004
129
130
131
132
133
134
135
136
alsa_handle = NULL;
alsa_loaded = 0;
}
}
static int LoadALSALibrary(void) {
int i, retval = -1;
Oct 10, 2009
Oct 10, 2009
137
alsa_handle = SDL_LoadObject(alsa_library);
Mar 2, 2004
Mar 2, 2004
138
139
140
if (alsa_handle) {
alsa_loaded = 1;
retval = 0;
Feb 19, 2006
Feb 19, 2006
141
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
Oct 10, 2009
Oct 10, 2009
142
*alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);
Mar 2, 2004
Mar 2, 2004
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
if (!*alsa_functions[i].func) {
retval = -1;
UnloadALSALibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadALSALibrary(void) {
return;
}
static int LoadALSALibrary(void) {
return 0;
}
Feb 16, 2006
Feb 16, 2006
163
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
Mar 2, 2004
Mar 2, 2004
164
Aug 21, 2004
Aug 21, 2004
165
static const char *get_audio_device(int channels)
Apr 26, 2001
Apr 26, 2001
166
{
Apr 15, 2002
Apr 15, 2002
167
168
const char *device;
Feb 7, 2006
Feb 7, 2006
169
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
Apr 15, 2002
Apr 15, 2002
170
if ( device == NULL ) {
Aug 21, 2004
Aug 21, 2004
171
172
173
if (channels == 6) device = "surround51";
else if (channels == 4) device = "surround40";
else device = DEFAULT_DEVICE;
Apr 15, 2002
Apr 15, 2002
174
175
}
return device;
Apr 26, 2001
Apr 26, 2001
176
177
178
179
180
181
182
}
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int available;
Apr 15, 2002
Apr 15, 2002
183
int status;
Apr 26, 2001
Apr 26, 2001
184
185
186
snd_pcm_t *handle;
available = 0;
Mar 2, 2004
Mar 2, 2004
187
188
189
if (LoadALSALibrary() < 0) {
return available;
}
Aug 21, 2004
Aug 21, 2004
190
status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Apr 15, 2002
Apr 15, 2002
191
192
if ( status >= 0 ) {
available = 1;
Mar 2, 2004
Mar 2, 2004
193
SDL_NAME(snd_pcm_close)(handle);
Apr 26, 2001
Apr 26, 2001
194
}
Mar 2, 2004
Mar 2, 2004
195
UnloadALSALibrary();
Apr 26, 2001
Apr 26, 2001
196
197
198
199
200
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
Feb 7, 2006
Feb 7, 2006
201
202
SDL_free(device->hidden);
SDL_free(device);
Mar 2, 2004
Mar 2, 2004
203
UnloadALSALibrary();
Apr 26, 2001
Apr 26, 2001
204
205
206
207
208
209
210
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
Mar 2, 2004
Mar 2, 2004
211
LoadALSALibrary();
Feb 7, 2006
Feb 7, 2006
212
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
Apr 26, 2001
Apr 26, 2001
213
if ( this ) {
Feb 7, 2006
Feb 7, 2006
214
SDL_memset(this, 0, (sizeof *this));
Apr 26, 2001
Apr 26, 2001
215
this->hidden = (struct SDL_PrivateAudioData *)
Feb 7, 2006
Feb 7, 2006
216
SDL_malloc((sizeof *this->hidden));
Apr 26, 2001
Apr 26, 2001
217
218
219
220
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
Feb 7, 2006
Feb 7, 2006
221
SDL_free(this);
Apr 26, 2001
Apr 26, 2001
222
223
224
}
return(0);
}
Feb 7, 2006
Feb 7, 2006
225
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
Apr 26, 2001
Apr 26, 2001
226
227
/* Set the function pointers */
Apr 15, 2002
Apr 15, 2002
228
229
230
231
232
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
Apr 26, 2001
Apr 26, 2001
233
234
235
236
237
238
239
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ALSA_bootstrap = {
Apr 15, 2002
Apr 15, 2002
240
DRIVER_NAME, "ALSA 0.9 PCM audio",
Apr 26, 2001
Apr 26, 2001
241
242
243
244
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
Apr 15, 2002
Apr 15, 2002
245
static void ALSA_WaitAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
/* 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;
}
}
}
}
Jun 23, 2006
Jun 23, 2006
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/*
* 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; \
}
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); }
#undef SWIZ6
/*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
* from Windows/Mac order to the format alsalib will want.
*/
static __inline__ void swizzle_alsa_channels(_THIS)
{
if (this->spec.channels == 6) {
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
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. */
}
Apr 15, 2002
Apr 15, 2002
306
static void ALSA_PlayAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
307
{
Oct 12, 2009
Oct 12, 2009
308
int status;
Oct 13, 2009
Oct 13, 2009
309
snd_pcm_uframes_t samps_left;
Oct 12, 2009
Oct 12, 2009
310
const Uint8 *sample_buf = (const Uint8 *) mixbuf;
Oct 13, 2009
Oct 13, 2009
311
const int sample_size = ((int) (this->spec.format & 0xFF)) / 8;
Jan 4, 2004
Jan 4, 2004
312
Jun 23, 2006
Jun 23, 2006
313
314
swizzle_alsa_channels(this);
Oct 13, 2009
Oct 13, 2009
315
samps_left = ((snd_pcm_uframes_t) this->spec.samples);
Jun 23, 2006
Jun 23, 2006
316
Oct 13, 2009
Oct 13, 2009
317
318
while ( samps_left > 0 ) {
status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, samps_left);
Apr 15, 2002
Apr 15, 2002
319
320
if ( status < 0 ) {
if ( status == -EAGAIN ) {
Jan 4, 2004
Jan 4, 2004
321
SDL_Delay(1);
Apr 15, 2002
Apr 15, 2002
322
323
324
325
continue;
}
if ( status == -ESTRPIPE ) {
do {
Jan 4, 2004
Jan 4, 2004
326
SDL_Delay(1);
Mar 2, 2004
Mar 2, 2004
327
status = SDL_NAME(snd_pcm_resume)(pcm_handle);
Apr 15, 2002
Apr 15, 2002
328
329
330
} while ( status == -EAGAIN );
}
if ( status < 0 ) {
Mar 2, 2004
Mar 2, 2004
331
status = SDL_NAME(snd_pcm_prepare)(pcm_handle);
Apr 15, 2002
Apr 15, 2002
332
333
334
335
336
}
if ( status < 0 ) {
/* Hmm, not much we can do - abort */
this->enabled = 0;
return;
Apr 26, 2001
Apr 26, 2001
337
}
Apr 15, 2002
Apr 15, 2002
338
continue;
Apr 26, 2001
Apr 26, 2001
339
}
Oct 13, 2009
Oct 13, 2009
340
341
sample_buf += status * sample_size;
samps_left -= status;
Apr 26, 2001
Apr 26, 2001
342
343
344
}
}
Apr 15, 2002
Apr 15, 2002
345
static Uint8 *ALSA_GetAudioBuf(_THIS)
Apr 26, 2001
Apr 26, 2001
346
{
Apr 15, 2002
Apr 15, 2002
347
return(mixbuf);
Apr 26, 2001
Apr 26, 2001
348
349
}
Apr 15, 2002
Apr 15, 2002
350
static void ALSA_CloseAudio(_THIS)
Apr 26, 2001
Apr 26, 2001
351
{
Apr 15, 2002
Apr 15, 2002
352
353
354
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
Apr 26, 2001
Apr 26, 2001
355
}
Apr 15, 2002
Apr 15, 2002
356
if ( pcm_handle ) {
Mar 2, 2004
Mar 2, 2004
357
358
SDL_NAME(snd_pcm_drain)(pcm_handle);
SDL_NAME(snd_pcm_close)(pcm_handle);
Apr 15, 2002
Apr 15, 2002
359
pcm_handle = NULL;
Apr 26, 2001
Apr 26, 2001
360
361
362
}
}
Apr 15, 2002
Apr 15, 2002
363
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
Apr 26, 2001
Apr 26, 2001
364
{
Apr 15, 2002
Apr 15, 2002
365
int status;
Mar 19, 2006
Mar 19, 2006
366
367
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
Apr 15, 2002
Apr 15, 2002
368
369
snd_pcm_format_t format;
snd_pcm_uframes_t frames;
Oct 10, 2009
Oct 10, 2009
370
371
372
unsigned int rate;
unsigned int periods;
unsigned int channels;
Apr 15, 2002
Apr 15, 2002
373
Uint16 test_format;
Apr 26, 2001
Apr 26, 2001
374
375
/* Open the audio device */
Aug 21, 2004
Aug 21, 2004
376
377
378
/* Name of device should depend on # channels in spec */
status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Apr 15, 2002
Apr 15, 2002
379
if ( status < 0 ) {
Mar 2, 2004
Mar 2, 2004
380
SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
Apr 26, 2001
Apr 26, 2001
381
382
383
return(-1);
}
Apr 15, 2002
Apr 15, 2002
384
/* Figure out what the hardware is capable of */
Mar 19, 2006
Mar 19, 2006
385
386
snd_pcm_hw_params_alloca(&hwparams);
status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
Apr 15, 2002
Apr 15, 2002
387
if ( status < 0 ) {
Mar 2, 2004
Mar 2, 2004
388
SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
Apr 15, 2002
Apr 15, 2002
389
390
391
ALSA_CloseAudio(this);
return(-1);
}
Apr 26, 2001
Apr 26, 2001
392
Apr 15, 2002
Apr 15, 2002
393
/* SDL only uses interleaved sample output */
Mar 19, 2006
Mar 19, 2006
394
status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
Apr 15, 2002
Apr 15, 2002
395
if ( status < 0 ) {
Mar 2, 2004
Mar 2, 2004
396
SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
Apr 15, 2002
Apr 15, 2002
397
398
399
ALSA_CloseAudio(this);
return(-1);
}
Apr 26, 2001
Apr 26, 2001
400
401
/* Try for a closest match on audio format */
Apr 15, 2002
Apr 15, 2002
402
status = -1;
Apr 26, 2001
Apr 26, 2001
403
for ( test_format = SDL_FirstAudioFormat(spec->format);
Apr 15, 2002
Apr 15, 2002
404
405
test_format && (status < 0); ) {
switch ( test_format ) {
Apr 26, 2001
Apr 26, 2001
406
case AUDIO_U8:
Apr 15, 2002
Apr 15, 2002
407
format = SND_PCM_FORMAT_U8;
Apr 26, 2001
Apr 26, 2001
408
409
break;
case AUDIO_S8:
Apr 15, 2002
Apr 15, 2002
410
format = SND_PCM_FORMAT_S8;
Apr 26, 2001
Apr 26, 2001
411
412
break;
case AUDIO_S16LSB:
Apr 15, 2002
Apr 15, 2002
413
format = SND_PCM_FORMAT_S16_LE;
Apr 26, 2001
Apr 26, 2001
414
415
break;
case AUDIO_S16MSB:
Apr 15, 2002
Apr 15, 2002
416
format = SND_PCM_FORMAT_S16_BE;
Apr 26, 2001
Apr 26, 2001
417
418
break;
case AUDIO_U16LSB:
Apr 15, 2002
Apr 15, 2002
419
format = SND_PCM_FORMAT_U16_LE;
Apr 26, 2001
Apr 26, 2001
420
421
break;
case AUDIO_U16MSB:
Apr 15, 2002
Apr 15, 2002
422
format = SND_PCM_FORMAT_U16_BE;
Apr 26, 2001
Apr 26, 2001
423
424
break;
default:
Apr 15, 2002
Apr 15, 2002
425
format = 0;
Apr 26, 2001
Apr 26, 2001
426
427
break;
}
Apr 15, 2002
Apr 15, 2002
428
if ( format != 0 ) {
Mar 19, 2006
Mar 19, 2006
429
status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
Apr 15, 2002
Apr 15, 2002
430
431
}
if ( status < 0 ) {
Apr 26, 2001
Apr 26, 2001
432
433
434
test_format = SDL_NextAudioFormat();
}
}
Apr 15, 2002
Apr 15, 2002
435
if ( status < 0 ) {
Apr 26, 2001
Apr 26, 2001
436
SDL_SetError("Couldn't find any hardware audio formats");
Apr 15, 2002
Apr 15, 2002
437
ALSA_CloseAudio(this);
Apr 26, 2001
Apr 26, 2001
438
439
440
441
return(-1);
}
spec->format = test_format;
Apr 15, 2002
Apr 15, 2002
442
/* Set the number of channels */
Mar 19, 2006
Mar 19, 2006
443
status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
Oct 10, 2009
Oct 10, 2009
444
channels = spec->channels;
Apr 15, 2002
Apr 15, 2002
445
if ( status < 0 ) {
Oct 10, 2009
Oct 10, 2009
446
447
status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams, &channels);
if ( status < 0 ) {
Apr 15, 2002
Apr 15, 2002
448
449
450
451
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return(-1);
}
Oct 10, 2009
Oct 10, 2009
452
spec->channels = channels;
Apr 15, 2002
Apr 15, 2002
453
}
Apr 26, 2001
Apr 26, 2001
454
Apr 15, 2002
Apr 15, 2002
455
/* Set the audio rate */
Oct 10, 2009
Oct 10, 2009
456
457
458
rate = spec->freq;
status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, &rate, NULL);
Apr 15, 2002
Apr 15, 2002
459
if ( status < 0 ) {
Mar 2, 2004
Mar 2, 2004
460
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
Apr 15, 2002
Apr 15, 2002
461
462
463
ALSA_CloseAudio(this);
return(-1);
}
Oct 10, 2009
Oct 10, 2009
464
spec->freq = rate;
Apr 15, 2002
Apr 15, 2002
465
466
467
/* Set the buffer size, in samples */
frames = spec->samples;
Oct 10, 2009
Oct 10, 2009
468
469
470
471
472
473
474
status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
if ( status < 0 ) {
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
Apr 15, 2002
Apr 15, 2002
475
spec->samples = frames;
Oct 10, 2009
Oct 10, 2009
476
477
478
periods = 2;
SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
Apr 15, 2002
Apr 15, 2002
479
480
/* "set" the hardware with the desired parameters */
Mar 19, 2006
Mar 19, 2006
481
482
483
484
485
486
487
status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
if ( status < 0 ) {
SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
Mar 19, 2006
Mar 19, 2006
488
/* This is useful for debugging... */
Oct 13, 2009
Oct 13, 2009
489
490
491
492
493
#if 0
{ snd_pcm_uframes_t bufsize; snd_pcm_sframes_t persize; unsigned int periods; int dir;
SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir);
SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir);
Mar 19, 2006
Mar 19, 2006
494
Oct 13, 2009
Oct 13, 2009
495
fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
Mar 19, 2006
Mar 19, 2006
496
}
Oct 13, 2009
Oct 13, 2009
497
#endif
Mar 19, 2006
Mar 19, 2006
498
499
500
501
502
503
504
505
506
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams);
if ( status < 0 ) {
SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
Oct 13, 2009
Oct 13, 2009
507
status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 1);
Mar 19, 2006
Mar 19, 2006
508
509
510
511
512
513
514
515
516
517
518
519
if ( status < 0 ) {
SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, frames);
if ( status < 0 ) {
SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
Apr 15, 2002
Apr 15, 2002
520
if ( status < 0 ) {
Mar 19, 2006
Mar 19, 2006
521
SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
Apr 15, 2002
Apr 15, 2002
522
ALSA_CloseAudio(this);
Apr 26, 2001
Apr 26, 2001
523
524
525
return(-1);
}
Apr 15, 2002
Apr 15, 2002
526
527
528
529
530
531
532
533
534
/* 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);
Apr 26, 2001
Apr 26, 2001
535
}
Feb 7, 2006
Feb 7, 2006
536
SDL_memset(mixbuf, spec->silence, spec->size);
Apr 26, 2001
Apr 26, 2001
537
538
539
540
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
Jan 4, 2004
Jan 4, 2004
541
/* Switch to blocking mode for playback */
Mar 2, 2004
Mar 2, 2004
542
SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0);
Jan 4, 2004
Jan 4, 2004
543
Apr 26, 2001
Apr 26, 2001
544
545
546
/* We're ready to rock and roll. :-) */
return(0);
}