Skip to content

Latest commit

 

History

History
561 lines (490 loc) · 17.9 KB

SDL_alsa_audio.c

File metadata and controls

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